Merge "Really fix excessive 'trun' box parsing" into qt-qpr1-dev am: 01102840bc
Change-Id: I1e99a0717491cd91c57d1afe51fc9571e4d18442
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
new file mode 100644
index 0000000..e63185d
--- /dev/null
+++ b/PREUPLOAD.cfg
@@ -0,0 +1,2 @@
+[Hook Scripts]
+mainline_hook = tools/mainline_hook.sh ${PREUPLOAD_COMMIT} "."
diff --git a/apex/Android.bp b/apex/Android.bp
index 42a620b..c1ef3d8 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -14,6 +14,7 @@
apex_defaults {
name: "com.android.media-defaults",
+ updatable: true,
java_libs: ["updatable-media"],
multilib: {
first: {
@@ -35,12 +36,23 @@
},
prebuilts: [
"mediaextractor.policy",
+ "code_coverage.policy",
+ "crash_dump.policy",
],
key: "com.android.media.key",
certificate: ":com.android.media.certificate",
// Use a custom AndroidManifest.xml used for API targeting.
androidManifest: ":com.android.media-androidManifest",
+
+ // IMPORTANT: For the APEX to be installed on Android 10 (API 29),
+ // min_sdk_version should be 29. This enables the build system to make
+ // sure the package compatible to Android 10 in two ways:
+ // - build the APEX package compatible to Android 10
+ // so that the package can be installed.
+ // - build artifacts (lib/javalib/bin) against Android 10 SDK
+ // so that the artifacts can run.
+ min_sdk_version: "29",
}
apex {
@@ -61,6 +73,7 @@
apex_defaults {
name: "com.android.media.swcodec-defaults",
+ updatable: true,
binaries: [
"mediaswcodec",
],
@@ -68,6 +81,8 @@
"com.android.media.swcodec-mediaswcodec.rc",
"com.android.media.swcodec-ld.config.txt",
"mediaswcodec.policy",
+ "code_coverage.policy",
+ "crash_dump.policy",
"mediaswcodec.xml",
],
use_vendor: true,
@@ -76,6 +91,15 @@
// Use a custom AndroidManifest.xml used for API targeting.
androidManifest: ":com.android.media.swcodec-androidManifest",
+
+ // IMPORTANT: For the APEX to be installed on Android 10 (API 29),
+ // min_sdk_version should be 29. This enables the build system to make
+ // sure the package compatible to Android 10 in two ways:
+ // - build the APEX package compatible to Android 10
+ // so that the package can be installed.
+ // - build artifacts (lib/javalib/bin) against Android 10 SDK
+ // so that the artifacts can run.
+ min_sdk_version: "29",
}
prebuilt_etc {
diff --git a/apex/AndroidManifest-media.xml b/apex/AndroidManifest-media.xml
index 1af4586..b020cba 100644
--- a/apex/AndroidManifest-media.xml
+++ b/apex/AndroidManifest-media.xml
@@ -19,8 +19,10 @@
<!-- APEX does not have classes.dex -->
<application android:hasCode="false" />
<!-- Setting maxSdk to lock the module to Q. minSdk is auto-set by build system -->
- <uses-sdk
+ <!-- TODO: Uncomment this when the R API level is fixed. b/148281152 -->
+ <!--uses-sdk
android:maxSdkVersion="29"
android:targetSdkVersion="29"
/>
+ -->
</manifest>
diff --git a/apex/AndroidManifest-swcodec.xml b/apex/AndroidManifest-swcodec.xml
index de50864..1a28d19 100644
--- a/apex/AndroidManifest-swcodec.xml
+++ b/apex/AndroidManifest-swcodec.xml
@@ -19,8 +19,10 @@
<!-- APEX does not have classes.dex -->
<application android:hasCode="false" />
<!-- Setting maxSdk to lock the module to Q. minSdk is auto-set by build system -->
- <uses-sdk
+ <!-- TODO: Uncomment this when the R API level is fixed. b/148281152 -->
+ <!--uses-sdk
android:maxSdkVersion="29"
android:targetSdkVersion="29"
/>
+ -->
</manifest>
diff --git a/apex/ld.config.txt b/apex/ld.config.txt
index af8ec06..713f0b7 100644
--- a/apex/ld.config.txt
+++ b/apex/ld.config.txt
@@ -22,12 +22,18 @@
namespace.default.search.paths = /apex/com.android.media.swcodec/${LIB}
namespace.default.asan.search.paths = /apex/com.android.media.swcodec/${LIB}
+# Below lines are required to be able to access libs in APEXes which are
+# actually symlinks to the files under /system/lib. The symlinks exist for
+# bundled APEXes to reduce space.
+namespace.default.permitted.paths = /system/${LIB}
+namespace.default.asan.permitted.paths = /system/${LIB}
+
namespace.default.links = platform
# TODO: replace the following when apex has a way to auto-generate this list
# namespace.default.link.platform.shared_libs = %LLNDK_LIBRARIES%
# namespace.default.link.platform.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-namespace.default.link.platform.shared_libs = libEGL.so:libGLESv1_CM.so:libGLESv2.so:libGLESv3.so:libRS.so:libandroid_net.so:libc.so:libcgrouprc.so:libclang_rt.asan-aarch64-android.so:libclang_rt.asan-arm-android.so:libclang_rt.hwasan-aarch64-android.so:libclang_rt.asan-i686-android.so:libclang_rt.asan-x86_64-android.so:libdl.so:libft2.so:liblog.so:libm.so:libmediandk.so:libnativewindow.so:libneuralnetworks.so:libsync.so:libvndksupport.so:libdl_android.so:libvulkan.so
+namespace.default.link.platform.shared_libs = libEGL.so:libGLESv1_CM.so:libGLESv2.so:libGLESv3.so:libRS.so:libandroid_net.so:libc.so:libcgrouprc.so:libclang_rt.asan-aarch64-android.so:libclang_rt.asan-arm-android.so:libclang_rt.hwasan-aarch64-android.so:libclang_rt.asan-i686-android.so:libclang_rt.asan-x86_64-android.so:libdl.so:libft2.so:liblog.so:libm.so:libmediandk.so:libnativewindow.so:libneuralnetworks.so:libsync.so:libvndksupport.so:libdl_android.so:libvulkan.so:libbinder_ndk.so
###############################################################################
# "platform" namespace
@@ -38,13 +44,18 @@
namespace.platform.isolated = true
namespace.platform.search.paths = /system/${LIB}
-namespace.platform.search.paths += /apex/com.android.runtime/${LIB}
namespace.platform.asan.search.paths = /data/asan/system/${LIB}
namespace.platform.asan.search.paths += /system/${LIB}
+
+# TODO(b/140790209): These directories are wrong in R and later because they
+# only contain Bionic internal libraries dependencies that should not be
+# accessed from the outside. However, they may be necessary for APEX builds that
+# are pushed to Q. Remove them as soon as Q compatibility is no longer required.
+namespace.platform.search.paths += /apex/com.android.runtime/${LIB}
namespace.platform.asan.search.paths += /apex/com.android.runtime/${LIB}
# /system/lib/libc.so, etc are symlinks to /apex/com.android.lib/lib/bionic/libc.so, etc.
-# Add /apex/... pat to the permitted paths because linker uses realpath(3)
+# Add /apex/... path to the permitted paths because linker uses realpath(3)
# to check the accessibility of the lib. We could add this to search.paths
# instead but that makes the resolution of bionic libs be dependent on
# the order of /system/lib and /apex/... in search.paths. If /apex/...
@@ -127,7 +138,13 @@
# TODO: replace the following when apex has a way to auto-generate this list
# namespace.sphal.link.platform.shared_libs = %LLNDK_LIBRARIES%
# namespace.sphal.link.platform.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-namespace.sphal.link.platform.shared_libs = libEGL.so:libGLESv1_CM.so:libGLESv2.so:libGLESv3.so:libRS.so:libandroid_net.so:libc.so:libcgrouprc.so:libclang_rt.asan-aarch64-android.so:libclang_rt.asan-arm-android.so:libclang_rt.hwasan-aarch64-android.so:libclang_rt.asan-i686-android.so:libclang_rt.asan-x86_64-android.so:libdl.so:libft2.so:liblog.so:libm.so:libmediandk.so:libnativewindow.so:libneuralnetworks.so:libsync.so:libvndksupport.so:libvulkan.so
+namespace.sphal.link.platform.shared_libs = libEGL.so:libGLESv1_CM.so:libGLESv2.so:libGLESv3.so:libRS.so:libandroid_net.so:libc.so:libcgrouprc.so:libclang_rt.asan-aarch64-android.so:libclang_rt.asan-arm-android.so:libclang_rt.hwasan-aarch64-android.so:libclang_rt.asan-i686-android.so:libclang_rt.asan-x86_64-android.so:libdl.so:libft2.so:liblog.so:libm.so:libmediandk.so:libnativewindow.so:libneuralnetworks.so:libsync.so:libvndksupport.so:libvulkan.so:libbinder_ndk.so
# Add a link for libz.so which is llndk on devices where VNDK is not enforced.
namespace.sphal.link.platform.shared_libs += libz.so
+
+# With VNDK APEX, /system/${LIB}/vndk-sp${VNDK_VER} is a symlink to the following.
+# Add /apex/... path to the permitted paths because linker uses realpath(3)
+# to check the accessibility of the lib.
+namespace.sphal.permitted.paths += /apex/com.android.vndk.${VNDK_APEX_VER}/${LIB}
+namespace.sphal.asan.permitted.paths += /apex/com.android.vndk.${VNDK_APEX_VER}/${LIB}
diff --git a/apex/manifest.json b/apex/manifest.json
index b11187d..ddd642e 100644
--- a/apex/manifest.json
+++ b/apex/manifest.json
@@ -1,4 +1,4 @@
{
"name": "com.android.media",
- "version": 299900000
+ "version": 300000000
}
diff --git a/apex/manifest_codec.json b/apex/manifest_codec.json
index 09c436d..2320fd7 100644
--- a/apex/manifest_codec.json
+++ b/apex/manifest_codec.json
@@ -1,4 +1,4 @@
{
"name": "com.android.media.swcodec",
- "version": 299900000
+ "version": 300000000
}
diff --git a/apex/testing/Android.bp b/apex/testing/Android.bp
index 701ced7..376d3e4 100644
--- a/apex/testing/Android.bp
+++ b/apex/testing/Android.bp
@@ -12,18 +12,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-apex {
+apex_test {
name: "test_com.android.media",
manifest: "test_manifest.json",
- file_contexts: "com.android.media",
+ file_contexts: ":com.android.media-file_contexts",
defaults: ["com.android.media-defaults"],
installable: false,
}
-apex {
+apex_test {
name: "test_com.android.media.swcodec",
manifest: "test_manifest_codec.json",
- file_contexts: "com.android.media.swcodec",
+ file_contexts: ":com.android.media.swcodec-file_contexts",
defaults: ["com.android.media.swcodec-defaults"],
installable: false,
}
diff --git a/camera/Android.bp b/camera/Android.bp
index 2800595..fa36bb3 100644
--- a/camera/Android.bp
+++ b/camera/Android.bp
@@ -40,6 +40,7 @@
"ICameraRecordingProxy.cpp",
"ICameraRecordingProxyListener.cpp",
"camera2/CaptureRequest.cpp",
+ "camera2/ConcurrentCamera.cpp",
"camera2/OutputConfiguration.cpp",
"camera2/SessionConfiguration.cpp",
"camera2/SubmitInfo.cpp",
@@ -66,7 +67,7 @@
"include",
"include/camera"
],
- export_shared_lib_headers: ["libcamera_metadata"],
+ export_shared_lib_headers: ["libcamera_metadata", "libnativewindow", "libgui"],
cflags: [
"-Werror",
@@ -85,7 +86,9 @@
"aidl/android/hardware/ICameraServiceProxy.aidl",
"aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl",
"aidl/android/hardware/camera2/ICameraDeviceUser.aidl",
+ "aidl/android/hardware/camera2/ICameraOfflineSession.aidl",
],
+ path: "aidl",
}
// Extra AIDL files that are used by framework.jar but not libcamera_client
@@ -96,4 +99,5 @@
"aidl/android/hardware/ICamera.aidl",
"aidl/android/hardware/ICameraClient.aidl",
],
+ path: "aidl",
}
diff --git a/camera/Camera.cpp b/camera/Camera.cpp
index c6c35ef..84d1d93 100644
--- a/camera/Camera.cpp
+++ b/camera/Camera.cpp
@@ -347,6 +347,20 @@
return c->setPreviewCallbackTarget(callbackProducer);
}
+status_t Camera::setAudioRestriction(int32_t mode)
+{
+ sp <::android::hardware::ICamera> c = mCamera;
+ if (c == 0) return NO_INIT;
+ return c->setAudioRestriction(mode);
+}
+
+int32_t Camera::getGlobalAudioRestriction()
+{
+ sp <::android::hardware::ICamera> c = mCamera;
+ if (c == 0) return NO_INIT;
+ return c->getGlobalAudioRestriction();
+}
+
// callback from camera service
void Camera::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2)
{
diff --git a/camera/CameraBase.cpp b/camera/CameraBase.cpp
index c53e6c3..aecb70a 100644
--- a/camera/CameraBase.cpp
+++ b/camera/CameraBase.cpp
@@ -60,6 +60,13 @@
if (res != OK) return res;
res = parcel->writeInt32(status);
+ if (res != OK) return res;
+
+ std::vector<String16> unavailablePhysicalIds16;
+ for (auto& id8 : unavailablePhysicalIds) {
+ unavailablePhysicalIds16.push_back(String16(id8));
+ }
+ res = parcel->writeString16Vector(unavailablePhysicalIds16);
return res;
}
@@ -70,6 +77,14 @@
cameraId = String8(tempCameraId);
res = parcel->readInt32(&status);
+ if (res != OK) return res;
+
+ std::vector<String16> unavailablePhysicalIds16;
+ res = parcel->readString16Vector(&unavailablePhysicalIds16);
+ if (res != OK) return res;
+ for (auto& id16 : unavailablePhysicalIds16) {
+ unavailablePhysicalIds.push_back(String8(id16));
+ }
return res;
}
diff --git a/camera/CameraMetadata.cpp b/camera/CameraMetadata.cpp
index 92fe84b..4745ee8 100644
--- a/camera/CameraMetadata.cpp
+++ b/camera/CameraMetadata.cpp
@@ -17,7 +17,9 @@
// #define LOG_NDEBUG 0
#define LOG_TAG "Camera2-Metadata"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
#include <utils/Log.h>
+#include <utils/Trace.h>
#include <utils/Errors.h>
#include <binder/Parcel.h>
@@ -38,14 +40,25 @@
CameraMetadata::CameraMetadata(size_t entryCapacity, size_t dataCapacity) :
mLocked(false)
{
+ ATRACE_CALL();
mBuffer = allocate_camera_metadata(entryCapacity, dataCapacity);
}
CameraMetadata::CameraMetadata(const CameraMetadata &other) :
mLocked(false) {
+ ATRACE_CALL();
mBuffer = clone_camera_metadata(other.mBuffer);
}
+CameraMetadata::CameraMetadata(CameraMetadata &&other) :mBuffer(NULL), mLocked(false) {
+ acquire(other);
+}
+
+CameraMetadata &CameraMetadata::operator=(CameraMetadata &&other) {
+ acquire(other);
+ return *this;
+}
+
CameraMetadata::CameraMetadata(camera_metadata_t *buffer) :
mBuffer(NULL), mLocked(false) {
acquire(buffer);
@@ -104,6 +117,7 @@
}
void CameraMetadata::clear() {
+ ATRACE_CALL();
if (mLocked) {
ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
return;
@@ -115,6 +129,7 @@
}
void CameraMetadata::acquire(camera_metadata_t *buffer) {
+ ATRACE_CALL();
if (mLocked) {
ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
return;
@@ -128,6 +143,7 @@
}
void CameraMetadata::acquire(CameraMetadata &other) {
+ ATRACE_CALL();
if (mLocked) {
ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
return;
@@ -136,10 +152,12 @@
}
status_t CameraMetadata::append(const CameraMetadata &other) {
+ ATRACE_CALL();
return append(other.mBuffer);
}
status_t CameraMetadata::append(const camera_metadata_t* other) {
+ ATRACE_CALL();
if (mLocked) {
ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
return INVALID_OPERATION;
@@ -161,6 +179,7 @@
}
status_t CameraMetadata::sort() {
+ ATRACE_CALL();
if (mLocked) {
ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
return INVALID_OPERATION;
@@ -291,6 +310,7 @@
status_t CameraMetadata::updateImpl(uint32_t tag, const void *data,
size_t data_count) {
+ ATRACE_CALL();
status_t res;
if (mLocked) {
ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
@@ -348,11 +368,13 @@
}
bool CameraMetadata::exists(uint32_t tag) const {
+ ATRACE_CALL();
camera_metadata_ro_entry entry;
return find_camera_metadata_ro_entry(mBuffer, tag, &entry) == 0;
}
camera_metadata_entry_t CameraMetadata::find(uint32_t tag) {
+ ATRACE_CALL();
status_t res;
camera_metadata_entry entry;
if (mLocked) {
@@ -369,6 +391,7 @@
}
camera_metadata_ro_entry_t CameraMetadata::find(uint32_t tag) const {
+ ATRACE_CALL();
status_t res;
camera_metadata_ro_entry entry;
res = find_camera_metadata_ro_entry(mBuffer, tag, &entry);
@@ -380,6 +403,7 @@
}
status_t CameraMetadata::erase(uint32_t tag) {
+ ATRACE_CALL();
camera_metadata_entry_t entry;
status_t res;
if (mLocked) {
@@ -410,6 +434,7 @@
status_t CameraMetadata::removePermissionEntries(metadata_vendor_id_t vendorId,
std::vector<int32_t> *tagsRemoved) {
+ ATRACE_CALL();
uint32_t tagCount = 0;
std::vector<uint32_t> tagsToRemove;
@@ -486,6 +511,7 @@
}
status_t CameraMetadata::resizeIfNeeded(size_t extraEntries, size_t extraData) {
+ ATRACE_CALL();
if (mBuffer == NULL) {
mBuffer = allocate_camera_metadata(extraEntries * 2, extraData * 2);
if (mBuffer == NULL) {
@@ -525,7 +551,7 @@
status_t CameraMetadata::readFromParcel(const Parcel& data,
camera_metadata_t** out) {
-
+ ATRACE_CALL();
status_t err = OK;
camera_metadata_t* metadata = NULL;
@@ -616,6 +642,7 @@
status_t CameraMetadata::writeToParcel(Parcel& data,
const camera_metadata_t* metadata) {
+ ATRACE_CALL();
status_t res = OK;
/**
@@ -710,7 +737,7 @@
}
status_t CameraMetadata::readFromParcel(const Parcel *parcel) {
-
+ ATRACE_CALL();
ALOGV("%s: parcel = %p", __FUNCTION__, parcel);
status_t res = OK;
@@ -742,7 +769,7 @@
}
status_t CameraMetadata::writeToParcel(Parcel *parcel) const {
-
+ ATRACE_CALL();
ALOGV("%s: parcel = %p", __FUNCTION__, parcel);
if (parcel == NULL) {
@@ -771,7 +798,7 @@
status_t CameraMetadata::getTagFromName(const char *name,
const VendorTagDescriptor* vTags, uint32_t *tag) {
-
+ ATRACE_CALL();
if (name == nullptr || tag == nullptr) return BAD_VALUE;
size_t nameLength = strlen(name);
diff --git a/camera/CaptureResult.cpp b/camera/CaptureResult.cpp
index 1d8e8c4..9cbfdb0 100644
--- a/camera/CaptureResult.cpp
+++ b/camera/CaptureResult.cpp
@@ -117,6 +117,12 @@
mMetadata(), mResultExtras() {
}
+CaptureResult::CaptureResult(CaptureResult &&otherResult) {
+ mMetadata = std::move(otherResult.mMetadata);
+ mResultExtras = otherResult.mResultExtras;
+ mPhysicalMetadatas = std::move(otherResult.mPhysicalMetadatas);
+}
+
CaptureResult::CaptureResult(const CaptureResult &otherResult) {
mResultExtras = otherResult.mResultExtras;
mMetadata = otherResult.mMetadata;
diff --git a/camera/ICamera.cpp b/camera/ICamera.cpp
index f0945c7..b83edf7 100644
--- a/camera/ICamera.cpp
+++ b/camera/ICamera.cpp
@@ -56,6 +56,8 @@
SET_VIDEO_BUFFER_TARGET,
RELEASE_RECORDING_FRAME_HANDLE,
RELEASE_RECORDING_FRAME_HANDLE_BATCH,
+ SET_AUDIO_RESTRICTION,
+ GET_GLOBAL_AUDIO_RESTRICTION,
};
class BpCamera: public BpInterface<ICamera>
@@ -191,6 +193,21 @@
}
}
+ status_t setAudioRestriction(int32_t mode) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+ data.writeInt32(mode);
+ remote()->transact(SET_AUDIO_RESTRICTION, data, &reply);
+ return reply.readInt32();
+ }
+
+ int32_t getGlobalAudioRestriction() {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+ remote()->transact(GET_GLOBAL_AUDIO_RESTRICTION, data, &reply);
+ return reply.readInt32();
+ }
+
status_t setVideoBufferMode(int32_t videoBufferMode)
{
ALOGV("setVideoBufferMode: %d", videoBufferMode);
@@ -494,6 +511,17 @@
reply->writeInt32(setVideoTarget(st));
return NO_ERROR;
} break;
+ case SET_AUDIO_RESTRICTION: {
+ CHECK_INTERFACE(ICamera, data, reply);
+ int32_t mode = data.readInt32();
+ reply->writeInt32(setAudioRestriction(mode));
+ return NO_ERROR;
+ } break;
+ case GET_GLOBAL_AUDIO_RESTRICTION: {
+ CHECK_INTERFACE(ICamera, data, reply);
+ reply->writeInt32(getGlobalAudioRestriction());
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/camera/aidl/android/hardware/ICameraService.aidl b/camera/aidl/android/hardware/ICameraService.aidl
index 3e8992a..ac7a35b 100644
--- a/camera/aidl/android/hardware/ICameraService.aidl
+++ b/camera/aidl/android/hardware/ICameraService.aidl
@@ -22,6 +22,8 @@
import android.hardware.camera2.ICameraDeviceCallbacks;
import android.hardware.camera2.params.VendorTagDescriptor;
import android.hardware.camera2.params.VendorTagDescriptorCache;
+import android.hardware.camera2.utils.ConcurrentCameraIdCombination;
+import android.hardware.camera2.utils.CameraIdAndSessionConfiguration;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.ICameraServiceListener;
import android.hardware.CameraInfo;
@@ -87,6 +89,7 @@
ICameraDeviceUser connectDevice(ICameraDeviceCallbacks callbacks,
String cameraId,
String opPackageName,
+ @nullable String featureId,
int clientUid);
/**
@@ -113,6 +116,25 @@
CameraStatus[] addListener(ICameraServiceListener listener);
/**
+ * Get a list of combinations of camera ids which support concurrent streaming.
+ *
+ */
+ ConcurrentCameraIdCombination[] getConcurrentCameraIds();
+
+ /**
+ * Check whether a particular set of session configurations are concurrently supported by the
+ * corresponding camera ids.
+ *
+ * @param sessions the set of camera id and session configuration pairs to be queried.
+ * @return true - the set of concurrent camera id and stream combinations is supported.
+ * false - the set of concurrent camera id and stream combinations is not supported
+ * OR the method was called with a set of camera ids not returned by
+ * getConcurrentCameraIds().
+ */
+ boolean isConcurrentSessionConfigurationSupported(
+ in CameraIdAndSessionConfiguration[] sessions);
+
+ /**
* Remove listener for changes to camera device and flashlight state.
*/
void removeListener(ICameraServiceListener listener);
diff --git a/camera/aidl/android/hardware/ICameraServiceListener.aidl b/camera/aidl/android/hardware/ICameraServiceListener.aidl
index 47580f8..c54813c 100644
--- a/camera/aidl/android/hardware/ICameraServiceListener.aidl
+++ b/camera/aidl/android/hardware/ICameraServiceListener.aidl
@@ -54,6 +54,12 @@
oneway void onStatusChanged(int status, String cameraId);
/**
+ * Notify registered client about status changes for a physical camera backing
+ * a logical camera.
+ */
+ oneway void onPhysicalCameraStatusChanged(int status, String cameraId, String physicalCameraId);
+
+ /**
* The torch mode status of a camera.
*
* Initial status will be transmitted with onTorchStatusChanged immediately
diff --git a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
index 49dfde8..b183ccc 100644
--- a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
+++ b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -17,6 +17,8 @@
package android.hardware.camera2;
import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.ICameraDeviceCallbacks;
+import android.hardware.camera2.ICameraOfflineSession;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.params.OutputConfiguration;
import android.hardware.camera2.params.SessionConfiguration;
@@ -81,8 +83,9 @@
* @param operatingMode The kind of session to create; either NORMAL_MODE or
* CONSTRAINED_HIGH_SPEED_MODE. Must be a non-negative value.
* @param sessionParams Session wide camera parameters
+ * @return a list of stream ids that can be used in offline mode via "switchToOffline"
*/
- void endConfigure(int operatingMode, in CameraMetadataNative sessionParams);
+ int[] endConfigure(int operatingMode, in CameraMetadataNative sessionParams);
/**
* Check whether a particular session configuration has camera device
@@ -155,4 +158,37 @@
void updateOutputConfiguration(int streamId, in OutputConfiguration outputConfiguration);
void finalizeOutputConfigurations(int streamId, in OutputConfiguration outputConfiguration);
+
+
+ // Keep in sync with public API in
+ // frameworks/base/core/java/android/hardware/camera2/CameraDevice.java
+ const int AUDIO_RESTRICTION_NONE = 0;
+ const int AUDIO_RESTRICTION_VIBRATION = 1;
+ const int AUDIO_RESTRICTION_VIBRATION_SOUND = 3;
+
+ /**
+ * Set audio restriction mode for this camera device.
+ *
+ * @param mode the audio restriction mode ID as above
+ *
+ */
+ void setCameraAudioRestriction(int mode);
+
+ /**
+ * Get global audio restriction mode for all camera clients.
+ *
+ * @return the currently applied system-wide audio restriction mode
+ */
+ int getGlobalAudioRestriction();
+
+ /**
+ * Offline processing main entry point
+ *
+ * @param callbacks Object that will receive callbacks from offline session
+ * @param offlineOutputIds The ID of streams that needs to be preserved in offline session
+ *
+ * @return Offline session object.
+ */
+ ICameraOfflineSession switchToOffline(in ICameraDeviceCallbacks callbacks,
+ in int[] offlineOutputIds);
}
diff --git a/camera/aidl/android/hardware/camera2/ICameraOfflineSession.aidl b/camera/aidl/android/hardware/camera2/ICameraOfflineSession.aidl
new file mode 100644
index 0000000..ab030ab
--- /dev/null
+++ b/camera/aidl/android/hardware/camera2/ICameraOfflineSession.aidl
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+package android.hardware.camera2;
+
+ /** @hide */
+interface ICameraOfflineSession
+{
+ void disconnect();
+}
diff --git a/camera/aidl/android/hardware/camera2/utils/CameraIdAndSessionConfiguration.aidl b/camera/aidl/android/hardware/camera2/utils/CameraIdAndSessionConfiguration.aidl
new file mode 100644
index 0000000..ca89ad8
--- /dev/null
+++ b/camera/aidl/android/hardware/camera2/utils/CameraIdAndSessionConfiguration.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.utils;
+
+/** @hide */
+parcelable CameraIdAndSessionConfiguration cpp_header "camera/camera2/ConcurrentCamera.h";
diff --git a/camera/aidl/android/hardware/camera2/utils/ConcurrentCameraIdCombination.aidl b/camera/aidl/android/hardware/camera2/utils/ConcurrentCameraIdCombination.aidl
new file mode 100644
index 0000000..4b35c31
--- /dev/null
+++ b/camera/aidl/android/hardware/camera2/utils/ConcurrentCameraIdCombination.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.utils;
+
+/** @hide */
+parcelable ConcurrentCameraIdCombination cpp_header "camera/camera2/ConcurrentCamera.h";
diff --git a/camera/camera2/ConcurrentCamera.cpp b/camera/camera2/ConcurrentCamera.cpp
new file mode 100644
index 0000000..01a695c
--- /dev/null
+++ b/camera/camera2/ConcurrentCamera.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "ConcurrentCamera"
+#include <utils/Log.h>
+#include <utils/String16.h>
+
+#include <camera/camera2/ConcurrentCamera.h>
+
+#include <binder/Parcel.h>
+
+namespace android {
+namespace hardware {
+namespace camera2 {
+namespace utils {
+
+ConcurrentCameraIdCombination::ConcurrentCameraIdCombination() = default;
+
+ConcurrentCameraIdCombination::ConcurrentCameraIdCombination(
+ std::vector<std::string> &&combination) : mConcurrentCameraIds(std::move(combination)) { }
+
+ConcurrentCameraIdCombination::~ConcurrentCameraIdCombination() = default;
+
+status_t ConcurrentCameraIdCombination::readFromParcel(const android::Parcel* parcel) {
+ if (parcel == nullptr) {
+ ALOGE("%s: Null parcel", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ status_t err = OK;
+ mConcurrentCameraIds.clear();
+ int32_t cameraIdCount = 0;
+ if ((err = parcel->readInt32(&cameraIdCount)) != OK) {
+ ALOGE("%s: Failed to read the camera id count from parcel: %d", __FUNCTION__, err);
+ return err;
+ }
+ for (int32_t i = 0; i < cameraIdCount; i++) {
+ String16 id;
+ if ((err = parcel->readString16(&id)) != OK) {
+ ALOGE("%s: Failed to read camera id!", __FUNCTION__);
+ return err;
+ }
+ mConcurrentCameraIds.push_back(std::string(String8(id).string()));
+ }
+ return OK;
+}
+
+status_t ConcurrentCameraIdCombination::writeToParcel(android::Parcel* parcel) const {
+
+ if (parcel == nullptr) {
+ ALOGE("%s: Null parcel", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ status_t err = OK;
+
+ if ((err = parcel->writeInt32(mConcurrentCameraIds.size())) != OK) {
+ ALOGE("%s: Failed to write the camera id count to parcel: %d", __FUNCTION__, err);
+ return err;
+ }
+
+ for (const auto &it : mConcurrentCameraIds) {
+ if ((err = parcel->writeString16(String16(it.c_str()))) != OK) {
+ ALOGE("%s: Failed to write the camera id string to parcel: %d", __FUNCTION__, err);
+ return err;
+ }
+ }
+ return OK;
+}
+
+CameraIdAndSessionConfiguration::CameraIdAndSessionConfiguration() = default;
+CameraIdAndSessionConfiguration::~CameraIdAndSessionConfiguration() = default;
+
+status_t CameraIdAndSessionConfiguration::readFromParcel(const android::Parcel* parcel) {
+ if (parcel == nullptr) {
+ ALOGE("%s: Null parcel", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ status_t err = OK;
+ String16 id;
+ if ((err = parcel->readString16(&id)) != OK) {
+ ALOGE("%s: Failed to read camera id!", __FUNCTION__);
+ return err;
+ }
+ if ((err = mSessionConfiguration.readFromParcel(parcel)) != OK) {
+ ALOGE("%s: Failed to read sessionConfiguration!", __FUNCTION__);
+ return err;
+ }
+ mCameraId = std::string(String8(id).string());
+ return OK;
+}
+
+status_t CameraIdAndSessionConfiguration::writeToParcel(android::Parcel* parcel) const {
+
+ if (parcel == nullptr) {
+ ALOGE("%s: Null parcel", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ status_t err = OK;
+ if ((err = parcel->writeString16(String16(mCameraId.c_str()))) != OK) {
+ ALOGE("%s: Failed to write camera id!", __FUNCTION__);
+ return err;
+ }
+
+ if ((err = mSessionConfiguration.writeToParcel(parcel) != OK)) {
+ ALOGE("%s: Failed to write session configuration!", __FUNCTION__);
+ return err;
+ }
+ return OK;
+}
+
+} // namespace utils
+} // namespace camera2
+} // namespace hardware
+} // namespace android
diff --git a/camera/cameraserver/Android.bp b/camera/cameraserver/Android.bp
index ecaba3a..dc7f88a 100644
--- a/camera/cameraserver/Android.bp
+++ b/camera/cameraserver/Android.bp
@@ -17,6 +17,10 @@
srcs: ["main_cameraserver.cpp"],
+ header_libs: [
+ "libmedia_headers",
+ ],
+
shared_libs: [
"libcameraservice",
"liblog",
@@ -25,10 +29,10 @@
"libgui",
"libbinder",
"libhidlbase",
- "libhidltransport",
"android.hardware.camera.common@1.0",
"android.hardware.camera.provider@2.4",
"android.hardware.camera.provider@2.5",
+ "android.hardware.camera.provider@2.6",
"android.hardware.camera.device@1.0",
"android.hardware.camera.device@3.2",
"android.hardware.camera.device@3.4",
@@ -44,6 +48,6 @@
init_rc: ["cameraserver.rc"],
vintf_fragments: [
- "manifest_android.frameworks.cameraservice.service@2.0.xml",
+ "manifest_android.frameworks.cameraservice.service@2.1.xml",
],
}
diff --git a/camera/cameraserver/manifest_android.frameworks.cameraservice.service@2.0.xml b/camera/cameraserver/manifest_android.frameworks.cameraservice.service@2.0.xml
deleted file mode 100644
index 601c717..0000000
--- a/camera/cameraserver/manifest_android.frameworks.cameraservice.service@2.0.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<manifest version="1.0" type="framework">
- <hal>
- <name>android.frameworks.cameraservice.service</name>
- <transport>hwbinder</transport>
- <version>2.0</version>
- <interface>
- <name>ICameraService</name>
- <instance>default</instance>
- </interface>
- </hal>
-</manifest>
diff --git a/camera/cameraserver/manifest_android.frameworks.cameraservice.service@2.1.xml b/camera/cameraserver/manifest_android.frameworks.cameraservice.service@2.1.xml
new file mode 100644
index 0000000..5a15b35
--- /dev/null
+++ b/camera/cameraserver/manifest_android.frameworks.cameraservice.service@2.1.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="framework">
+ <hal>
+ <name>android.frameworks.cameraservice.service</name>
+ <transport>hwbinder</transport>
+ <version>2.1</version>
+ <interface>
+ <name>ICameraService</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/camera/include/camera/Camera.h b/camera/include/camera/Camera.h
index 430aa1c..2cdb617 100644
--- a/camera/include/camera/Camera.h
+++ b/camera/include/camera/Camera.h
@@ -167,6 +167,9 @@
sp<ICameraRecordingProxy> getRecordingProxy();
+ status_t setAudioRestriction(int32_t mode);
+ int32_t getGlobalAudioRestriction();
+
// ICameraClient interface
virtual void notifyCallback(int32_t msgType, int32_t ext, int32_t ext2);
virtual void dataCallback(int32_t msgType, const sp<IMemory>& dataPtr,
diff --git a/camera/include/camera/CameraBase.h b/camera/include/camera/CameraBase.h
index 74a2dce..499b0e6 100644
--- a/camera/include/camera/CameraBase.h
+++ b/camera/include/camera/CameraBase.h
@@ -80,10 +80,16 @@
*/
int32_t status;
+ /**
+ * Unavailable physical camera names for a multi-camera device
+ */
+ std::vector<String8> unavailablePhysicalIds;
+
virtual status_t writeToParcel(android::Parcel* parcel) const;
virtual status_t readFromParcel(const android::Parcel* parcel);
- CameraStatus(String8 id, int32_t s) : cameraId(id), status(s) {}
+ CameraStatus(String8 id, int32_t s, const std::vector<String8>& unavailSubIds) :
+ cameraId(id), status(s), unavailablePhysicalIds(unavailSubIds) {}
CameraStatus() : status(ICameraServiceListener::STATUS_PRESENT) {}
};
diff --git a/camera/include/camera/CameraMetadata.h b/camera/include/camera/CameraMetadata.h
index 844bb80..9d1b5c7 100644
--- a/camera/include/camera/CameraMetadata.h
+++ b/camera/include/camera/CameraMetadata.h
@@ -40,6 +40,11 @@
* dataCapacity extra storage */
CameraMetadata(size_t entryCapacity, size_t dataCapacity = 10);
+ /**
+ * Move constructor, acquires other's metadata buffer
+ */
+ CameraMetadata(CameraMetadata &&other);
+
~CameraMetadata();
/** Takes ownership of passed-in buffer */
@@ -54,6 +59,11 @@
CameraMetadata &operator=(const camera_metadata_t *buffer);
/**
+ * Move assignment operator, acquires other's metadata buffer
+ */
+ CameraMetadata &operator=(CameraMetadata &&other);
+
+ /**
* Get reference to the underlying metadata buffer. Ownership remains with
* the CameraMetadata object, but non-const CameraMetadata methods will not
* work until unlock() is called. Note that the lock has nothing to do with
diff --git a/camera/include/camera/CaptureResult.h b/camera/include/camera/CaptureResult.h
index ef830b5..dc3d282 100644
--- a/camera/include/camera/CaptureResult.h
+++ b/camera/include/camera/CaptureResult.h
@@ -135,6 +135,8 @@
CaptureResult(const CaptureResult& otherResult);
+ CaptureResult(CaptureResult &&captureResult);
+
status_t readFromParcel(android::Parcel* parcel);
status_t writeToParcel(android::Parcel* parcel) const;
};
diff --git a/camera/include/camera/VendorTagDescriptor.h b/camera/include/camera/VendorTagDescriptor.h
index 6f55890..b2fbf3a 100644
--- a/camera/include/camera/VendorTagDescriptor.h
+++ b/camera/include/camera/VendorTagDescriptor.h
@@ -188,8 +188,8 @@
sp<android::VendorTagDescriptor> *desc /*out*/);
// Parcelable interface
- status_t writeToParcel(Parcel* parcel) const override;
- status_t readFromParcel(const Parcel* parcel) override;
+ status_t writeToParcel(android::Parcel* parcel) const override;
+ status_t readFromParcel(const android::Parcel* parcel) override;
// Returns the number of vendor tags defined.
int getTagCount(metadata_vendor_id_t id) const;
diff --git a/camera/include/camera/android/hardware/ICamera.h b/camera/include/camera/android/hardware/ICamera.h
index 80823d6..ec19e5d 100644
--- a/camera/include/camera/android/hardware/ICamera.h
+++ b/camera/include/camera/android/hardware/ICamera.h
@@ -140,6 +140,12 @@
// Set the video buffer producer for camera to use in VIDEO_BUFFER_MODE_BUFFER_QUEUE mode.
virtual status_t setVideoTarget(
const sp<IGraphicBufferProducer>& bufferProducer) = 0;
+
+ // Set the audio restriction mode
+ virtual status_t setAudioRestriction(int32_t mode) = 0;
+
+ // Get the global audio restriction mode
+ virtual int32_t getGlobalAudioRestriction() = 0;
};
// ----------------------------------------------------------------------------
diff --git a/camera/include/camera/camera2/ConcurrentCamera.h b/camera/include/camera/camera2/ConcurrentCamera.h
new file mode 100644
index 0000000..ac99fd5
--- /dev/null
+++ b/camera/include/camera/camera2/ConcurrentCamera.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA2_UTIL_CONCURRENTCAMERA_H
+#define ANDROID_HARDWARE_CAMERA2_UTIL_CONCURRENTCAMERA_H
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <camera2/OutputConfiguration.h>
+#include <camera2/SessionConfiguration.h>
+
+namespace android {
+namespace hardware {
+namespace camera2 {
+namespace utils {
+
+struct ConcurrentCameraIdCombination : public Parcelable {
+ std::vector<std::string> mConcurrentCameraIds;
+ ConcurrentCameraIdCombination();
+ ConcurrentCameraIdCombination(std::vector<std::string> &&combination);
+ virtual ~ConcurrentCameraIdCombination();
+
+ virtual status_t writeToParcel(android::Parcel *parcel) const override;
+ virtual status_t readFromParcel(const android::Parcel* parcel) override;
+};
+
+struct CameraIdAndSessionConfiguration : public Parcelable {
+ std::string mCameraId;
+ SessionConfiguration mSessionConfiguration;
+
+ CameraIdAndSessionConfiguration();
+ virtual ~CameraIdAndSessionConfiguration();
+
+ virtual status_t writeToParcel(android::Parcel *parcel) const override;
+ virtual status_t readFromParcel(const android::Parcel* parcel) override;
+};
+
+} // namespace utils
+} // namespace camera2
+} // namespace hardware
+} // namespace android
+
+#endif
diff --git a/camera/ndk/Android.bp b/camera/ndk/Android.bp
index a2ee65d..7ba82c1 100644
--- a/camera/ndk/Android.bp
+++ b/camera/ndk/Android.bp
@@ -57,6 +57,9 @@
"libmediandk",
"libnativewindow",
],
+ header_libs: [
+ "jni_headers",
+ ],
cflags: [
"-fvisibility=hidden",
"-DEXPORT=__attribute__ ((visibility (\"default\")))",
@@ -107,7 +110,6 @@
],
shared_libs: [
- "libhwbinder",
"libfmq",
"libhidlbase",
"libhardware",
@@ -121,8 +123,8 @@
"android.frameworks.cameraservice.device@2.0",
"android.frameworks.cameraservice.common@2.0",
"android.frameworks.cameraservice.service@2.0",
+ "android.frameworks.cameraservice.service@2.1",
],
-
static_libs: [
"android.hardware.camera.common@1.0-helper",
"libarect",
@@ -139,11 +141,13 @@
}
cc_test {
- name: "AImageReaderVendorTest",
+ name: "ACameraNdkVendorTest",
vendor: true,
- srcs: ["ndk_vendor/tests/AImageReaderVendorTest.cpp"],
+ srcs: [
+ "ndk_vendor/tests/AImageReaderVendorTest.cpp",
+ "ndk_vendor/tests/ACameraManagerTest.cpp",
+ ],
shared_libs: [
- "libhwbinder",
"libcamera2ndk_vendor",
"libcamera_metadata",
"libmediandk",
diff --git a/camera/ndk/NdkCameraMetadata.cpp b/camera/ndk/NdkCameraMetadata.cpp
index 9a39ed8..7d3a53e 100644
--- a/camera/ndk/NdkCameraMetadata.cpp
+++ b/camera/ndk/NdkCameraMetadata.cpp
@@ -26,6 +26,76 @@
using namespace android;
+#ifndef __ANDROID_VNDK__
+namespace {
+
+constexpr const char* android_hardware_camera2_CameraMetadata_jniClassName =
+ "android/hardware/camera2/CameraMetadata";
+constexpr const char* android_hardware_camera2_CameraCharacteristics_jniClassName =
+ "android/hardware/camera2/CameraCharacteristics";
+constexpr const char* android_hardware_camera2_CaptureResult_jniClassName =
+ "android/hardware/camera2/CaptureResult";
+
+jclass android_hardware_camera2_CameraCharacteristics_clazz = nullptr;
+jclass android_hardware_camera2_CaptureResult_clazz = nullptr;
+jmethodID android_hardware_camera2_CameraMetadata_getNativeMetadataPtr = nullptr;
+
+// Called at most once to initializes global variables used by JNI.
+bool InitJni(JNIEnv* env) {
+ // From C++11 onward, static initializers are guaranteed to be executed at most once,
+ // even if called from multiple threads.
+ static bool ok = [env]() -> bool {
+ const jclass cameraMetadataClazz = env->FindClass(
+ android_hardware_camera2_CameraMetadata_jniClassName);
+ if (cameraMetadataClazz == nullptr) {
+ return false;
+ }
+ const jmethodID cameraMetadata_getNativeMetadataPtr =
+ env->GetMethodID(cameraMetadataClazz, "getNativeMetadataPtr", "()J");
+ if (cameraMetadata_getNativeMetadataPtr == nullptr) {
+ return false;
+ }
+
+ const jclass cameraCharacteristics_clazz = env->FindClass(
+ android_hardware_camera2_CameraCharacteristics_jniClassName);
+ if (cameraCharacteristics_clazz == nullptr) {
+ return false;
+ }
+
+ const jclass captureResult_clazz = env->FindClass(
+ android_hardware_camera2_CaptureResult_jniClassName);
+ if (captureResult_clazz == nullptr) {
+ return false;
+ }
+
+ android_hardware_camera2_CameraMetadata_getNativeMetadataPtr =
+ cameraMetadata_getNativeMetadataPtr;
+ android_hardware_camera2_CameraCharacteristics_clazz =
+ static_cast<jclass>(env->NewGlobalRef(cameraCharacteristics_clazz));
+ android_hardware_camera2_CaptureResult_clazz =
+ static_cast<jclass>(env->NewGlobalRef(captureResult_clazz));
+
+ return true;
+ }();
+ return ok;
+}
+
+// Given cameraMetadata, an instance of android.hardware.camera2.CameraMetadata, invokes
+// cameraMetadata.getNativeMetadataPtr() and returns it as a std::shared_ptr<CameraMetadata>*.
+std::shared_ptr<CameraMetadata>* CameraMetadata_getNativeMetadataPtr(JNIEnv* env,
+ jobject cameraMetadata) {
+ if (cameraMetadata == nullptr) {
+ ALOGE("%s: Invalid Java CameraMetadata object.", __FUNCTION__);
+ return nullptr;
+ }
+ jlong ret = env->CallLongMethod(cameraMetadata,
+ android_hardware_camera2_CameraMetadata_getNativeMetadataPtr);
+ return reinterpret_cast<std::shared_ptr<CameraMetadata>* >(ret);
+}
+
+} // namespace
+#endif /* __ANDROID_VNDK__ */
+
EXPORT
camera_status_t ACameraMetadata_getConstEntry(
const ACameraMetadata* acm, uint32_t tag, ACameraMetadata_const_entry* entry) {
@@ -58,7 +128,7 @@
return nullptr;
}
ACameraMetadata* copy = new ACameraMetadata(*src);
- copy->incStrong((void*) ACameraMetadata_copy);
+ copy->incStrong(/*id=*/(void*) ACameraMetadata_copy);
return copy;
}
@@ -86,3 +156,33 @@
return staticMetadata->isLogicalMultiCamera(numPhysicalCameras, physicalCameraIds);
}
+
+#ifndef __ANDROID_VNDK__
+EXPORT
+ACameraMetadata* ACameraMetadata_fromCameraMetadata(JNIEnv* env, jobject cameraMetadata) {
+ ATRACE_CALL();
+
+ const bool ok = InitJni(env);
+ LOG_ALWAYS_FATAL_IF(!ok, "Failed to find CameraMetadata Java classes.");
+
+ if (cameraMetadata == nullptr) {
+ return nullptr;
+ }
+
+ ACameraMetadata::ACAMERA_METADATA_TYPE type;
+ if (env->IsInstanceOf(cameraMetadata,
+ android_hardware_camera2_CameraCharacteristics_clazz)) {
+ type = ACameraMetadata::ACM_CHARACTERISTICS;
+ } else if (env->IsInstanceOf(cameraMetadata,
+ android_hardware_camera2_CaptureResult_clazz)) {
+ type = ACameraMetadata::ACM_RESULT;
+ } else {
+ return nullptr;
+ }
+
+ auto sharedData = CameraMetadata_getNativeMetadataPtr(env, cameraMetadata);
+ ACameraMetadata* output = new ACameraMetadata(*sharedData, type);
+ output->incStrong(/*id=*/(void*) ACameraMetadata_fromCameraMetadata);
+ return output;
+}
+#endif /* __ANDROID_VNDK__ */
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index 46a8dae..0d7180a 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -710,7 +710,8 @@
if ((sessionParameters != nullptr) && (sessionParameters->settings != nullptr)) {
params.append(sessionParameters->settings->getInternalData());
}
- remoteRet = mRemote->endConfigure(/*isConstrainedHighSpeed*/ false, params);
+ std::vector<int> offlineStreamIds;
+ remoteRet = mRemote->endConfigure(/*isConstrainedHighSpeed*/ false, params, &offlineStreamIds);
if (remoteRet.serviceSpecificErrorCode() == hardware::ICameraService::ERROR_ILLEGAL_ARGUMENT) {
ALOGE("Camera device %s cannnot support app output configuration: %s", getId(),
remoteRet.toString8().string());
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
index 9d40fd7..f408b6a 100644
--- a/camera/ndk/impl/ACameraManager.cpp
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -32,6 +32,7 @@
namespace acam {
// Static member definitions
const char* CameraManagerGlobal::kCameraIdKey = "CameraId";
+const char* CameraManagerGlobal::kPhysicalCameraIdKey = "PhysicalCameraId";
const char* CameraManagerGlobal::kCallbackFpKey = "CallbackFp";
const char* CameraManagerGlobal::kContextKey = "CallbackContext";
Mutex CameraManagerGlobal::sLock;
@@ -76,6 +77,10 @@
sp<hardware::ICameraService> CameraManagerGlobal::getCameraService() {
Mutex::Autolock _l(mLock);
+ return getCameraServiceLocked();
+}
+
+sp<hardware::ICameraService> CameraManagerGlobal::getCameraServiceLocked() {
if (mCameraService.get() == nullptr) {
if (isCameraServiceDisabled()) {
return mCameraService;
@@ -125,6 +130,11 @@
mCameraService->addListener(mCameraServiceListener, &cameraStatuses);
for (auto& c : cameraStatuses) {
onStatusChangedLocked(c.status, c.cameraId);
+
+ for (auto& unavailablePhysicalId : c.unavailablePhysicalIds) {
+ onStatusChangedLocked(hardware::ICameraServiceListener::STATUS_NOT_PRESENT,
+ c.cameraId, unavailablePhysicalId);
+ }
}
// setup vendor tags
@@ -195,9 +205,7 @@
void CameraManagerGlobal::registerExtendedAvailabilityCallback(
const ACameraManager_ExtendedAvailabilityCallbacks *callback) {
- Mutex::Autolock _l(mLock);
- Callback cb(callback);
- mCallbacks.insert(cb);
+ return registerAvailCallback<ACameraManager_ExtendedAvailabilityCallbacks>(callback);
}
void CameraManagerGlobal::unregisterExtendedAvailabilityCallback(
@@ -209,24 +217,7 @@
void CameraManagerGlobal::registerAvailabilityCallback(
const ACameraManager_AvailabilityCallbacks *callback) {
- Mutex::Autolock _l(mLock);
- Callback cb(callback);
- auto pair = mCallbacks.insert(cb);
- // Send initial callbacks if callback is newly registered
- if (pair.second) {
- for (auto& pair : mDeviceStatusMap) {
- const String8& cameraId = pair.first;
- int32_t status = pair.second;
-
- sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
- ACameraManager_AvailabilityCallback cb = isStatusAvailable(status) ?
- callback->onCameraAvailable : callback->onCameraUnavailable;
- msg->setPointer(kCallbackFpKey, (void *) cb);
- msg->setPointer(kContextKey, callback->context);
- msg->setString(kCameraIdKey, AString(cameraId));
- msg->post();
- }
- }
+ return registerAvailCallback<ACameraManager_AvailabilityCallbacks>(callback);
}
void CameraManagerGlobal::unregisterAvailabilityCallback(
@@ -236,20 +227,74 @@
mCallbacks.erase(cb);
}
+template<class T>
+void CameraManagerGlobal::registerAvailCallback(const T *callback) {
+ Mutex::Autolock _l(mLock);
+ Callback cb(callback);
+ auto pair = mCallbacks.insert(cb);
+ // Send initial callbacks if callback is newly registered
+ if (pair.second) {
+ for (auto& pair : mDeviceStatusMap) {
+ const String8& cameraId = pair.first;
+ int32_t status = pair.second.getStatus();
+ // Don't send initial callbacks for camera ids which don't support
+ // camera2
+ if (!pair.second.supportsHAL3) {
+ continue;
+ }
+
+ // Camera available/unavailable callback
+ sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
+ ACameraManager_AvailabilityCallback cbFunc = isStatusAvailable(status) ?
+ cb.mAvailable : cb.mUnavailable;
+ msg->setPointer(kCallbackFpKey, (void *) cbFunc);
+ msg->setPointer(kContextKey, cb.mContext);
+ msg->setString(kCameraIdKey, AString(cameraId));
+ msg->post();
+
+ // Physical camera unavailable callback
+ std::set<String8> unavailablePhysicalCameras =
+ pair.second.getUnavailablePhysicalIds();
+ for (const auto& physicalCameraId : unavailablePhysicalCameras) {
+ sp<AMessage> msg = new AMessage(kWhatSendSinglePhysicalCameraCallback, mHandler);
+ ACameraManager_PhysicalCameraAvailabilityCallback cbFunc =
+ cb.mPhysicalCamUnavailable;
+ msg->setPointer(kCallbackFpKey, (void *) cbFunc);
+ msg->setPointer(kContextKey, cb.mContext);
+ msg->setString(kCameraIdKey, AString(cameraId));
+ msg->setString(kPhysicalCameraIdKey, AString(physicalCameraId));
+ msg->post();
+ }
+ }
+ }
+}
+
+bool CameraManagerGlobal::supportsCamera2ApiLocked(const String8 &cameraId) {
+ bool camera2Support = false;
+ auto cs = getCameraServiceLocked();
+ binder::Status serviceRet =
+ cs->supportsCameraApi(String16(cameraId),
+ hardware::ICameraService::API_VERSION_2, &camera2Support);
+ if (!serviceRet.isOk()) {
+ ALOGE("%s: supportsCameraApi2Locked() call failed for cameraId %s",
+ __FUNCTION__, cameraId.c_str());
+ return false;
+ }
+ return camera2Support;
+}
+
void CameraManagerGlobal::getCameraIdList(std::vector<String8>* cameraIds) {
// Ensure that we have initialized/refreshed the list of available devices
- auto cs = getCameraService();
Mutex::Autolock _l(mLock);
-
+ // Needed to make sure we're connected to cameraservice
+ getCameraServiceLocked();
for(auto& deviceStatus : mDeviceStatusMap) {
- if (deviceStatus.second == hardware::ICameraServiceListener::STATUS_NOT_PRESENT ||
- deviceStatus.second == hardware::ICameraServiceListener::STATUS_ENUMERATING) {
+ int32_t status = deviceStatus.second.getStatus();
+ if (status == hardware::ICameraServiceListener::STATUS_NOT_PRESENT ||
+ status == hardware::ICameraServiceListener::STATUS_ENUMERATING) {
continue;
}
- bool camera2Support = false;
- binder::Status serviceRet = cs->supportsCameraApi(String16(deviceStatus.first),
- hardware::ICameraService::API_VERSION_2, &camera2Support);
- if (!serviceRet.isOk() || !camera2Support) {
+ if (!deviceStatus.second.supportsHAL3) {
continue;
}
cameraIds->push_back(deviceStatus.first);
@@ -321,6 +366,39 @@
(*cb)(context);
break;
}
+ case kWhatSendSinglePhysicalCameraCallback:
+ {
+ ACameraManager_PhysicalCameraAvailabilityCallback cb;
+ void* context;
+ AString cameraId;
+ AString physicalCameraId;
+ bool found = msg->findPointer(kCallbackFpKey, (void**) &cb);
+ if (!found) {
+ ALOGE("%s: Cannot find camera callback fp!", __FUNCTION__);
+ return;
+ }
+ if (cb == nullptr) {
+ // Physical camera callback is null
+ return;
+ }
+ found = msg->findPointer(kContextKey, &context);
+ if (!found) {
+ ALOGE("%s: Cannot find callback context!", __FUNCTION__);
+ return;
+ }
+ found = msg->findString(kCameraIdKey, &cameraId);
+ if (!found) {
+ ALOGE("%s: Cannot find camera ID!", __FUNCTION__);
+ return;
+ }
+ found = msg->findString(kPhysicalCameraIdKey, &physicalCameraId);
+ if (!found) {
+ ALOGE("%s: Cannot find physical camera ID!", __FUNCTION__);
+ return;
+ }
+ (*cb)(context, cameraId.c_str(), physicalCameraId.c_str());
+ break;
+ }
default:
ALOGE("%s: unknown message type %d", __FUNCTION__, msg->what());
break;
@@ -348,6 +426,17 @@
return binder::Status::ok();
}
+binder::Status CameraManagerGlobal::CameraServiceListener::onPhysicalCameraStatusChanged(
+ int32_t status, const String16& cameraId, const String16& physicalCameraId) {
+ sp<CameraManagerGlobal> cm = mCameraManager.promote();
+ if (cm != nullptr) {
+ cm->onStatusChanged(status, String8(cameraId), String8(physicalCameraId));
+ } else {
+ ALOGE("Cannot deliver physical camera status change. Global camera manager died");
+ }
+ return binder::Status::ok();
+}
+
void CameraManagerGlobal::onCameraAccessPrioritiesChanged() {
Mutex::Autolock _l(mLock);
for (auto cb : mCallbacks) {
@@ -377,7 +466,7 @@
bool firstStatus = (mDeviceStatusMap.count(cameraId) == 0);
int32_t oldStatus = firstStatus ?
status : // first status
- mDeviceStatusMap[cameraId];
+ mDeviceStatusMap[cameraId].getStatus();
if (!firstStatus &&
isStatusAvailable(status) == isStatusAvailable(oldStatus)) {
@@ -385,22 +474,111 @@
return;
}
+ bool supportsHAL3 = supportsCamera2ApiLocked(cameraId);
+ if (firstStatus) {
+ mDeviceStatusMap.emplace(std::piecewise_construct,
+ std::forward_as_tuple(cameraId),
+ std::forward_as_tuple(status, supportsHAL3));
+ } else {
+ mDeviceStatusMap[cameraId].updateStatus(status);
+ }
// Iterate through all registered callbacks
- mDeviceStatusMap[cameraId] = status;
- for (auto cb : mCallbacks) {
- sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
- ACameraManager_AvailabilityCallback cbFp = isStatusAvailable(status) ?
- cb.mAvailable : cb.mUnavailable;
- msg->setPointer(kCallbackFpKey, (void *) cbFp);
- msg->setPointer(kContextKey, cb.mContext);
- msg->setString(kCameraIdKey, AString(cameraId));
- msg->post();
+ if (supportsHAL3) {
+ for (auto cb : mCallbacks) {
+ sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
+ ACameraManager_AvailabilityCallback cbFp = isStatusAvailable(status) ?
+ cb.mAvailable : cb.mUnavailable;
+ msg->setPointer(kCallbackFpKey, (void *) cbFp);
+ msg->setPointer(kContextKey, cb.mContext);
+ msg->setString(kCameraIdKey, AString(cameraId));
+ msg->post();
+ }
}
if (status == hardware::ICameraServiceListener::STATUS_NOT_PRESENT) {
mDeviceStatusMap.erase(cameraId);
}
}
+void CameraManagerGlobal::onStatusChanged(
+ int32_t status, const String8& cameraId, const String8& physicalCameraId) {
+ Mutex::Autolock _l(mLock);
+ onStatusChangedLocked(status, cameraId, physicalCameraId);
+}
+
+void CameraManagerGlobal::onStatusChangedLocked(
+ int32_t status, const String8& cameraId, const String8& physicalCameraId) {
+ if (!validStatus(status)) {
+ ALOGE("%s: Invalid status %d", __FUNCTION__, status);
+ return;
+ }
+
+ auto logicalStatus = mDeviceStatusMap.find(cameraId);
+ if (logicalStatus == mDeviceStatusMap.end()) {
+ ALOGE("%s: Physical camera id %s status change on a non-present id %s",
+ __FUNCTION__, physicalCameraId.c_str(), cameraId.c_str());
+ return;
+ }
+ int32_t logicalCamStatus = mDeviceStatusMap[cameraId].getStatus();
+ if (logicalCamStatus != hardware::ICameraServiceListener::STATUS_PRESENT &&
+ logicalCamStatus != hardware::ICameraServiceListener::STATUS_NOT_AVAILABLE) {
+ ALOGE("%s: Physical camera id %s status %d change for an invalid logical camera state %d",
+ __FUNCTION__, physicalCameraId.string(), status, logicalCamStatus);
+ return;
+ }
+
+ bool supportsHAL3 = supportsCamera2ApiLocked(cameraId);
+
+ bool updated = false;
+ if (status == hardware::ICameraServiceListener::STATUS_PRESENT) {
+ updated = mDeviceStatusMap[cameraId].removeUnavailablePhysicalId(physicalCameraId);
+ } else {
+ updated = mDeviceStatusMap[cameraId].addUnavailablePhysicalId(physicalCameraId);
+ }
+
+ // Iterate through all registered callbacks
+ if (supportsHAL3 && updated) {
+ for (auto cb : mCallbacks) {
+ sp<AMessage> msg = new AMessage(kWhatSendSinglePhysicalCameraCallback, mHandler);
+ ACameraManager_PhysicalCameraAvailabilityCallback cbFp = isStatusAvailable(status) ?
+ cb.mPhysicalCamAvailable : cb.mPhysicalCamUnavailable;
+ msg->setPointer(kCallbackFpKey, (void *) cbFp);
+ msg->setPointer(kContextKey, cb.mContext);
+ msg->setString(kCameraIdKey, AString(cameraId));
+ msg->setString(kPhysicalCameraIdKey, AString(physicalCameraId));
+ msg->post();
+ }
+ }
+}
+
+int32_t CameraManagerGlobal::StatusAndHAL3Support::getStatus() {
+ std::lock_guard<std::mutex> lock(mLock);
+ return status;
+}
+
+void CameraManagerGlobal::StatusAndHAL3Support::updateStatus(int32_t newStatus) {
+ std::lock_guard<std::mutex> lock(mLock);
+ status = newStatus;
+}
+
+bool CameraManagerGlobal::StatusAndHAL3Support::addUnavailablePhysicalId(
+ const String8& physicalCameraId) {
+ std::lock_guard<std::mutex> lock(mLock);
+ auto result = unavailablePhysicalIds.insert(physicalCameraId);
+ return result.second;
+}
+
+bool CameraManagerGlobal::StatusAndHAL3Support::removeUnavailablePhysicalId(
+ const String8& physicalCameraId) {
+ std::lock_guard<std::mutex> lock(mLock);
+ auto count = unavailablePhysicalIds.erase(physicalCameraId);
+ return count > 0;
+}
+
+std::set<String8> CameraManagerGlobal::StatusAndHAL3Support::getUnavailablePhysicalIds() {
+ std::lock_guard<std::mutex> lock(mLock);
+ return unavailablePhysicalIds;
+}
+
} // namespace acam
} // namespace android
@@ -517,7 +695,7 @@
// No way to get package name from native.
// Send a zero length package name and let camera service figure it out from UID
binder::Status serviceRet = cs->connectDevice(
- callbacks, String16(cameraId), String16(""),
+ callbacks, String16(cameraId), String16(""), std::unique_ptr<String16>(),
hardware::ICameraService::USE_CALLING_UID, /*out*/&deviceRemote);
if (!serviceRet.isOk()) {
diff --git a/camera/ndk/impl/ACameraManager.h b/camera/ndk/impl/ACameraManager.h
index 28fec82..7fba188 100644
--- a/camera/ndk/impl/ACameraManager.h
+++ b/camera/ndk/impl/ACameraManager.h
@@ -66,9 +66,12 @@
private:
sp<hardware::ICameraService> mCameraService;
- const int kCameraServicePollDelay = 500000; // 0.5s
- const char* kCameraServiceName = "media.camera";
- Mutex mLock;
+ const int kCameraServicePollDelay = 500000; // 0.5s
+ const char* kCameraServiceName = "media.camera";
+ Mutex mLock;
+
+ template<class T>
+ void registerAvailCallback(const T *callback);
class DeathNotifier : public IBinder::DeathRecipient {
public:
@@ -85,6 +88,8 @@
public:
explicit CameraServiceListener(CameraManagerGlobal* cm) : mCameraManager(cm) {}
virtual binder::Status onStatusChanged(int32_t status, const String16& cameraId);
+ virtual binder::Status onPhysicalCameraStatusChanged(int32_t status,
+ const String16& cameraId, const String16& physicalCameraId);
// Torch API not implemented yet
virtual binder::Status onTorchStatusChanged(int32_t, const String16&) {
@@ -110,18 +115,24 @@
mAvailable(callback->onCameraAvailable),
mUnavailable(callback->onCameraUnavailable),
mAccessPriorityChanged(nullptr),
+ mPhysicalCamAvailable(nullptr),
+ mPhysicalCamUnavailable(nullptr),
mContext(callback->context) {}
explicit Callback(const ACameraManager_ExtendedAvailabilityCallbacks *callback) :
mAvailable(callback->availabilityCallbacks.onCameraAvailable),
mUnavailable(callback->availabilityCallbacks.onCameraUnavailable),
mAccessPriorityChanged(callback->onCameraAccessPrioritiesChanged),
+ mPhysicalCamAvailable(callback->onPhysicalCameraAvailable),
+ mPhysicalCamUnavailable(callback->onPhysicalCameraUnavailable),
mContext(callback->availabilityCallbacks.context) {}
bool operator == (const Callback& other) const {
return (mAvailable == other.mAvailable &&
mUnavailable == other.mUnavailable &&
mAccessPriorityChanged == other.mAccessPriorityChanged &&
+ mPhysicalCamAvailable == other.mPhysicalCamAvailable &&
+ mPhysicalCamUnavailable == other.mPhysicalCamUnavailable &&
mContext == other.mContext);
}
bool operator != (const Callback& other) const {
@@ -130,6 +141,12 @@
bool operator < (const Callback& other) const {
if (*this == other) return false;
if (mContext != other.mContext) return mContext < other.mContext;
+ if (mPhysicalCamAvailable != other.mPhysicalCamAvailable) {
+ return mPhysicalCamAvailable < other.mPhysicalCamAvailable;
+ }
+ if (mPhysicalCamUnavailable != other.mPhysicalCamUnavailable) {
+ return mPhysicalCamUnavailable < other.mPhysicalCamUnavailable;
+ }
if (mAccessPriorityChanged != other.mAccessPriorityChanged) {
return mAccessPriorityChanged < other.mAccessPriorityChanged;
}
@@ -142,6 +159,8 @@
ACameraManager_AvailabilityCallback mAvailable;
ACameraManager_AvailabilityCallback mUnavailable;
ACameraManager_AccessPrioritiesChangedCallback mAccessPriorityChanged;
+ ACameraManager_PhysicalCameraAvailabilityCallback mPhysicalCamAvailable;
+ ACameraManager_PhysicalCameraAvailabilityCallback mPhysicalCamUnavailable;
void* mContext;
};
std::set<Callback> mCallbacks;
@@ -150,8 +169,10 @@
enum {
kWhatSendSingleCallback,
kWhatSendSingleAccessCallback,
+ kWhatSendSinglePhysicalCameraCallback,
};
static const char* kCameraIdKey;
+ static const char* kPhysicalCameraIdKey;
static const char* kCallbackFpKey;
static const char* kContextKey;
class CallbackHandler : public AHandler {
@@ -162,12 +183,17 @@
sp<CallbackHandler> mHandler;
sp<ALooper> mCbLooper; // Looper thread where callbacks actually happen on
+ sp<hardware::ICameraService> getCameraServiceLocked();
void onCameraAccessPrioritiesChanged();
void onStatusChanged(int32_t status, const String8& cameraId);
void onStatusChangedLocked(int32_t status, const String8& cameraId);
+ void onStatusChanged(int32_t status, const String8& cameraId, const String8& physicalCameraId);
+ void onStatusChangedLocked(int32_t status, const String8& cameraId,
+ const String8& physicalCameraId);
// Utils for status
static bool validStatus(int32_t status);
static bool isStatusAvailable(int32_t status);
+ bool supportsCamera2ApiLocked(const String8 &cameraId);
// The sort logic must match the logic in
// libcameraservice/common/CameraProviderManager.cpp::getAPI1CompatibleCameraDeviceIds
@@ -190,8 +216,26 @@
}
};
+ struct StatusAndHAL3Support {
+ private:
+ int32_t status = hardware::ICameraServiceListener::STATUS_NOT_PRESENT;
+ mutable std::mutex mLock;
+ std::set<String8> unavailablePhysicalIds;
+ public:
+ const bool supportsHAL3 = false;
+ StatusAndHAL3Support(int32_t st, bool HAL3support):
+ status(st), supportsHAL3(HAL3support) { };
+ StatusAndHAL3Support() = default;
+
+ bool addUnavailablePhysicalId(const String8& physicalCameraId);
+ bool removeUnavailablePhysicalId(const String8& physicalCameraId);
+ int32_t getStatus();
+ void updateStatus(int32_t newStatus);
+ std::set<String8> getUnavailablePhysicalIds();
+ };
+
// Map camera_id -> status
- std::map<String8, int32_t, CameraIdComparator> mDeviceStatusMap;
+ std::map<String8, StatusAndHAL3Support, CameraIdComparator> mDeviceStatusMap;
// For the singleton instance
static Mutex sLock;
diff --git a/camera/ndk/impl/ACameraMetadata.cpp b/camera/ndk/impl/ACameraMetadata.cpp
index 77dcd48..2aeffa2 100644
--- a/camera/ndk/impl/ACameraMetadata.cpp
+++ b/camera/ndk/impl/ACameraMetadata.cpp
@@ -28,7 +28,28 @@
* ACameraMetadata Implementation
*/
ACameraMetadata::ACameraMetadata(camera_metadata_t* buffer, ACAMERA_METADATA_TYPE type) :
- mData(buffer), mType(type) {
+ mData(std::make_shared<CameraMetadata>(buffer)),
+ mType(type) {
+ init();
+}
+
+ACameraMetadata::ACameraMetadata(const std::shared_ptr<CameraMetadata>& cameraMetadata,
+ ACAMERA_METADATA_TYPE type) :
+ mData(cameraMetadata),
+ mType(type) {
+ init();
+}
+
+ACameraMetadata::ACameraMetadata(const ACameraMetadata& other) :
+ mData(std::make_shared<CameraMetadata>(*(other.mData))),
+ mType(other.mType) {
+}
+
+ACameraMetadata::~ACameraMetadata() {
+}
+
+void
+ACameraMetadata::init() {
if (mType == ACM_CHARACTERISTICS) {
filterUnsupportedFeatures();
filterStreamConfigurations();
@@ -61,7 +82,7 @@
void
ACameraMetadata::filterUnsupportedFeatures() {
// Hide unsupported capabilities (reprocessing)
- camera_metadata_entry entry = mData.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+ camera_metadata_entry entry = mData->find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
if (entry.count == 0 || entry.type != TYPE_BYTE) {
ALOGE("%s: malformed available capability key! count %zu, type %d",
__FUNCTION__, entry.count, entry.type);
@@ -80,7 +101,7 @@
}
}
}
- mData.update(ANDROID_REQUEST_AVAILABLE_CAPABILITIES, capabilities);
+ mData->update(ANDROID_REQUEST_AVAILABLE_CAPABILITIES, capabilities);
}
void
@@ -118,12 +139,20 @@
const int STREAM_WIDTH_OFFSET = 1;
const int STREAM_HEIGHT_OFFSET = 2;
const int STREAM_DURATION_OFFSET = 3;
- camera_metadata_entry entry = mData.find(tag);
- if (entry.count == 0 || entry.count % 4 || entry.type != TYPE_INT64) {
+
+ camera_metadata_entry entry = mData->find(tag);
+
+ if (entry.count == 0) {
+ // Duration keys can be missing when corresponding capture feature is not supported
+ return;
+ }
+
+ if (entry.count % 4 || entry.type != TYPE_INT64) {
ALOGE("%s: malformed duration key %d! count %zu, type %d",
__FUNCTION__, tag, entry.count, entry.type);
return;
}
+
Vector<int64_t> filteredDurations;
filteredDurations.setCapacity(entry.count * 2);
@@ -194,7 +223,7 @@
}
}
- mData.update(tag, filteredDurations);
+ mData->update(tag, filteredDurations);
}
void
@@ -204,7 +233,7 @@
const int STREAM_WIDTH_OFFSET = 1;
const int STREAM_HEIGHT_OFFSET = 2;
const int STREAM_IS_INPUT_OFFSET = 3;
- camera_metadata_entry entry = mData.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
+ camera_metadata_entry entry = mData->find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
if (entry.count > 0 && (entry.count % 4 || entry.type != TYPE_INT32)) {
ALOGE("%s: malformed available stream configuration key! count %zu, type %d",
__FUNCTION__, entry.count, entry.type);
@@ -234,10 +263,10 @@
}
if (filteredStreamConfigs.size() > 0) {
- mData.update(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, filteredStreamConfigs);
+ mData->update(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, filteredStreamConfigs);
}
- entry = mData.find(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS);
+ entry = mData->find(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS);
if (entry.count > 0 && (entry.count % 4 || entry.type != TYPE_INT32)) {
ALOGE("%s: malformed available depth stream configuration key! count %zu, type %d",
__FUNCTION__, entry.count, entry.type);
@@ -270,11 +299,11 @@
}
if (filteredDepthStreamConfigs.size() > 0) {
- mData.update(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS,
+ mData->update(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS,
filteredDepthStreamConfigs);
}
- entry = mData.find(ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS);
+ entry = mData->find(ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS);
Vector<int32_t> filteredHeicStreamConfigs;
filteredHeicStreamConfigs.setCapacity(entry.count);
@@ -297,9 +326,9 @@
filteredHeicStreamConfigs.push_back(height);
filteredHeicStreamConfigs.push_back(isInput);
}
- mData.update(ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS, filteredHeicStreamConfigs);
+ mData->update(ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS, filteredHeicStreamConfigs);
- entry = mData.find(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS);
+ entry = mData->find(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS);
Vector<int32_t> filteredDynamicDepthStreamConfigs;
filteredDynamicDepthStreamConfigs.setCapacity(entry.count);
@@ -322,7 +351,7 @@
filteredDynamicDepthStreamConfigs.push_back(height);
filteredDynamicDepthStreamConfigs.push_back(isInput);
}
- mData.update(ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS,
+ mData->update(ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS,
filteredDynamicDepthStreamConfigs);
}
@@ -343,7 +372,7 @@
Mutex::Autolock _l(mLock);
- camera_metadata_ro_entry rawEntry = mData.find(tag);
+ camera_metadata_ro_entry rawEntry = static_cast<const CameraMetadata*>(mData.get())->find(tag);
if (rawEntry.count == 0) {
ALOGE("%s: cannot find metadata tag %d", __FUNCTION__, tag);
return ACAMERA_ERROR_METADATA_NOT_FOUND;
@@ -390,9 +419,9 @@
/*out*/const uint32_t** tags) const {
Mutex::Autolock _l(mLock);
if (mTags.size() == 0) {
- size_t entry_count = mData.entryCount();
+ size_t entry_count = mData->entryCount();
mTags.setCapacity(entry_count);
- const camera_metadata_t* rawMetadata = mData.getAndLock();
+ const camera_metadata_t* rawMetadata = mData->getAndLock();
for (size_t i = 0; i < entry_count; i++) {
camera_metadata_ro_entry_t entry;
int ret = get_camera_metadata_ro_entry(rawMetadata, i, &entry);
@@ -405,7 +434,7 @@
mTags.push_back(entry.tag);
}
}
- mData.unlock(rawMetadata);
+ mData->unlock(rawMetadata);
}
*numTags = mTags.size();
@@ -415,7 +444,7 @@
const CameraMetadata&
ACameraMetadata::getInternalData() const {
- return mData;
+ return (*mData);
}
bool
@@ -479,6 +508,8 @@
case ACAMERA_CONTROL_VIDEO_STABILIZATION_MODE:
case ACAMERA_CONTROL_POST_RAW_SENSITIVITY_BOOST:
case ACAMERA_CONTROL_ENABLE_ZSL:
+ case ACAMERA_CONTROL_BOKEH_MODE:
+ case ACAMERA_CONTROL_ZOOM_RATIO:
case ACAMERA_EDGE_MODE:
case ACAMERA_FLASH_MODE:
case ACAMERA_HOT_PIXEL_MODE:
diff --git a/camera/ndk/impl/ACameraMetadata.h b/camera/ndk/impl/ACameraMetadata.h
index 97f7f48..084a60b 100644
--- a/camera/ndk/impl/ACameraMetadata.h
+++ b/camera/ndk/impl/ACameraMetadata.h
@@ -18,6 +18,7 @@
#include <unordered_set>
#include <vector>
+#include <memory>
#include <sys/types.h>
#include <utils/Mutex.h>
@@ -36,8 +37,8 @@
using namespace android;
/**
- * ACameraMetadata opaque struct definition
- * Leave outside of android namespace because it's NDK struct
+ * ACameraMetadata is an opaque struct definition.
+ * It is intentionally left outside of the android namespace because it's NDK struct.
*/
struct ACameraMetadata : public RefBase {
public:
@@ -47,11 +48,19 @@
ACM_RESULT, // Read only
} ACAMERA_METADATA_TYPE;
- // Takes ownership of pass-in buffer
- ACameraMetadata(camera_metadata_t *buffer, ACAMERA_METADATA_TYPE type);
- // Clone
- ACameraMetadata(const ACameraMetadata& other) :
- mData(other.mData), mType(other.mType) {};
+ // Constructs a ACameraMetadata that takes ownership of `buffer`.
+ ACameraMetadata(camera_metadata_t* buffer, ACAMERA_METADATA_TYPE type);
+
+ // Constructs a ACameraMetadata that shares its data with something else, like a Java object
+ ACameraMetadata(const std::shared_ptr<CameraMetadata>& cameraMetadata,
+ ACAMERA_METADATA_TYPE type);
+
+ // Copy constructor.
+ //
+ // Always makes a deep copy.
+ ACameraMetadata(const ACameraMetadata& other);
+
+ ~ACameraMetadata();
camera_status_t getConstEntry(uint32_t tag, ACameraMetadata_const_entry* entry) const;
@@ -70,6 +79,9 @@
private:
+ // Common code called by constructors.
+ void init();
+
// This function does not check whether the capability passed to it is valid.
// The caller must make sure that it is.
bool isNdkSupportedCapability(const int32_t capability);
@@ -95,11 +107,11 @@
status_t ret = OK;
if (count == 0 && data == nullptr) {
- ret = mData.erase(tag);
+ ret = mData->erase(tag);
} else {
// Here we have to use reinterpret_cast because the NDK data type is
// exact copy of internal data type but they do not inherit from each other
- ret = mData.update(tag, reinterpret_cast<const INTERNAL_T*>(data), count);
+ ret = mData->update(tag, reinterpret_cast<const INTERNAL_T*>(data), count);
}
if (ret == OK) {
@@ -110,10 +122,12 @@
}
}
- // guard access of public APIs: get/update/getTags
- mutable Mutex mLock;
- CameraMetadata mData;
- mutable Vector<uint32_t> mTags; // updated in getTags, cleared by update
+ // Guard access of public APIs: get/update/getTags.
+ mutable Mutex mLock;
+
+ std::shared_ptr<CameraMetadata> mData;
+
+ mutable Vector<uint32_t> mTags; // Updated by `getTags()`, cleared by `update()`.
const ACAMERA_METADATA_TYPE mType;
static std::unordered_set<uint32_t> sSystemTags;
diff --git a/camera/ndk/include/camera/NdkCameraManager.h b/camera/ndk/include/camera/NdkCameraManager.h
index 2cc8a97..e2b71bf 100644
--- a/camera/ndk/include/camera/NdkCameraManager.h
+++ b/camera/ndk/include/camera/NdkCameraManager.h
@@ -123,6 +123,21 @@
const char* cameraId);
/**
+ * Definition of physical camera availability callbacks.
+ *
+ * @param context The optional application context provided by user in
+ * {@link ACameraManager_AvailabilityCallbacks}.
+ * @param cameraId The ID of the logical multi-camera device whose physical camera status is
+ * changing. The memory of this argument is owned by camera framework and will
+ * become invalid immediately after this callback returns.
+ * @param physicalCameraId The ID of the physical camera device whose status is changing. The
+ * memory of this argument is owned by camera framework and will become invalid
+ * immediately after this callback returns.
+ */
+typedef void (*ACameraManager_PhysicalCameraAvailabilityCallback)(void* context,
+ const char* cameraId, const char* physicalCameraId);
+
+/**
* A listener for camera devices becoming available or unavailable to open.
*
* <p>Cameras become available when they are no longer in use, or when a new
@@ -320,8 +335,15 @@
/// Called when there is camera access permission change
ACameraManager_AccessPrioritiesChangedCallback onCameraAccessPrioritiesChanged;
+ /// Called when a physical camera becomes available
+ ACameraManager_PhysicalCameraAvailabilityCallback onPhysicalCameraAvailable __INTRODUCED_IN(30);
+
+ /// Called when a physical camera becomes unavailable
+ ACameraManager_PhysicalCameraAvailabilityCallback onPhysicalCameraUnavailable
+ __INTRODUCED_IN(30);
+
/// Reserved for future use, please ensure that all entries are set to NULL
- void *reserved[6];
+ void *reserved[4];
} ACameraManager_ExtendedAvailabilityCallbacks;
/**
diff --git a/camera/ndk/include/camera/NdkCameraMetadata.h b/camera/ndk/include/camera/NdkCameraMetadata.h
index 9bbfb83..072bb02 100644
--- a/camera/ndk/include/camera/NdkCameraMetadata.h
+++ b/camera/ndk/include/camera/NdkCameraMetadata.h
@@ -39,6 +39,12 @@
#include <stdint.h>
#include <sys/cdefs.h>
+#ifndef __ANDROID_VNDK__
+#if __ANDROID_API__ >= 30
+#include "jni.h"
+#endif /* __ANDROID_API__ >= 30 */
+#endif /* __ANDROID_VNDK__ */
+
#include "NdkCameraError.h"
#include "NdkCameraMetadataTags.h"
@@ -255,6 +261,37 @@
#endif /* __ANDROID_API__ >= 29 */
+#ifndef __ANDROID_VNDK__
+#if __ANDROID_API__ >= 30
+
+/**
+ * Return a {@link ACameraMetadata} that references the same data as
+ * {@link cameraMetadata}, which is an instance of
+ * {@link android.hardware.camera2.CameraMetadata} (e.g., a
+ * {@link android.hardware.camera2.CameraCharacteristics} or
+ * {@link android.hardware.camera2.CaptureResult}).
+ *
+ * <p>The returned ACameraMetadata must be freed by the application by {@link ACameraMetadata_free}
+ * after application is done using it.</p>
+ *
+ * <p>The ACameraMetadata maintains a reference count to the underlying data, so
+ * it can be used independently of the Java object, and it remains valid even if
+ * the Java metadata is garbage collected.
+ *
+ * @param env the JNI environment.
+ * @param cameraMetadata the source {@link android.hardware.camera2.CameraMetadata} from which the
+ * returned {@link ACameraMetadata} is a view.
+ *
+ * @return a valid ACameraMetadata pointer or NULL if {@link cameraMetadata} is null or not a valid
+ * instance of {@link android.hardware.camera2.CameraMetadata}.
+ *
+ */
+ACameraMetadata* ACameraMetadata_fromCameraMetadata(JNIEnv* env, jobject cameraMetadata)
+ __INTRODUCED_IN(30);
+
+#endif /* __ANDROID_API__ >= 30 */
+#endif /* __ANDROID_VNDK__ */
+
__END_DECLS
#endif /* _NDK_CAMERA_METADATA_H */
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 8dd6e00..8b371db 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -140,7 +140,7 @@
* application controls how the color mapping is performed.</p>
* <p>We define the expected processing pipeline below. For consistency
* across devices, this is always the case with TRANSFORM_MATRIX.</p>
- * <p>When either FULL or HIGH_QUALITY is used, the camera device may
+ * <p>When either FAST or HIGH_QUALITY is used, the camera device may
* do additional processing but ACAMERA_COLOR_CORRECTION_GAINS and
* ACAMERA_COLOR_CORRECTION_TRANSFORM will still be provided by the
* camera device (in the results) and be roughly correct.</p>
@@ -518,11 +518,22 @@
* region and output only the intersection rectangle as the metering region in the result
* metadata. If the region is entirely outside the crop region, it will be ignored and
* not reported in the result metadata.</p>
+ * <p>Starting from API level 30, the coordinate system of activeArraySize or
+ * preCorrectionActiveArraySize is used to represent post-zoomRatio field of view, not
+ * pre-zoom field of view. This means that the same aeRegions values at different
+ * ACAMERA_CONTROL_ZOOM_RATIO represent different parts of the scene. The aeRegions
+ * coordinates are relative to the activeArray/preCorrectionActiveArray representing the
+ * zoomed field of view. If ACAMERA_CONTROL_ZOOM_RATIO is set to 1.0 (default), the same
+ * aeRegions at different ACAMERA_SCALER_CROP_REGION still represent the same parts of the
+ * scene as they do before. See ACAMERA_CONTROL_ZOOM_RATIO for details. Whether to use
+ * activeArraySize or preCorrectionActiveArraySize still depends on distortion correction
+ * mode.</p>
* <p>The data representation is <code>int[5 * area_count]</code>.
* Every five elements represent a metering region of <code>(xmin, ymin, xmax, ymax, weight)</code>.
* The rectangle is defined to be inclusive on xmin and ymin, but exclusive on xmax and
* ymax.</p>
*
+ * @see ACAMERA_CONTROL_ZOOM_RATIO
* @see ACAMERA_DISTORTION_CORRECTION_MODE
* @see ACAMERA_SCALER_CROP_REGION
* @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE
@@ -698,11 +709,22 @@
* region and output only the intersection rectangle as the metering region in the result
* metadata. If the region is entirely outside the crop region, it will be ignored and
* not reported in the result metadata.</p>
+ * <p>Starting from API level 30, the coordinate system of activeArraySize or
+ * preCorrectionActiveArraySize is used to represent post-zoomRatio field of view, not
+ * pre-zoom field of view. This means that the same afRegions values at different
+ * ACAMERA_CONTROL_ZOOM_RATIO represent different parts of the scene. The afRegions
+ * coordinates are relative to the activeArray/preCorrectionActiveArray representing the
+ * zoomed field of view. If ACAMERA_CONTROL_ZOOM_RATIO is set to 1.0 (default), the same
+ * afRegions at different ACAMERA_SCALER_CROP_REGION still represent the same parts of the
+ * scene as they do before. See ACAMERA_CONTROL_ZOOM_RATIO for details. Whether to use
+ * activeArraySize or preCorrectionActiveArraySize still depends on distortion correction
+ * mode.</p>
* <p>The data representation is <code>int[5 * area_count]</code>.
* Every five elements represent a metering region of <code>(xmin, ymin, xmax, ymax, weight)</code>.
* The rectangle is defined to be inclusive on xmin and ymin, but exclusive on xmax and
* ymax.</p>
*
+ * @see ACAMERA_CONTROL_ZOOM_RATIO
* @see ACAMERA_DISTORTION_CORRECTION_MODE
* @see ACAMERA_SCALER_CROP_REGION
* @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE
@@ -873,11 +895,22 @@
* region and output only the intersection rectangle as the metering region in the result
* metadata. If the region is entirely outside the crop region, it will be ignored and
* not reported in the result metadata.</p>
+ * <p>Starting from API level 30, the coordinate system of activeArraySize or
+ * preCorrectionActiveArraySize is used to represent post-zoomRatio field of view, not
+ * pre-zoom field of view. This means that the same awbRegions values at different
+ * ACAMERA_CONTROL_ZOOM_RATIO represent different parts of the scene. The awbRegions
+ * coordinates are relative to the activeArray/preCorrectionActiveArray representing the
+ * zoomed field of view. If ACAMERA_CONTROL_ZOOM_RATIO is set to 1.0 (default), the same
+ * awbRegions at different ACAMERA_SCALER_CROP_REGION still represent the same parts of
+ * the scene as they do before. See ACAMERA_CONTROL_ZOOM_RATIO for details. Whether to use
+ * activeArraySize or preCorrectionActiveArraySize still depends on distortion correction
+ * mode.</p>
* <p>The data representation is <code>int[5 * area_count]</code>.
* Every five elements represent a metering region of <code>(xmin, ymin, xmax, ymax, weight)</code>.
* The rectangle is defined to be inclusive on xmin and ymin, but exclusive on xmax and
* ymax.</p>
*
+ * @see ACAMERA_CONTROL_ZOOM_RATIO
* @see ACAMERA_DISTORTION_CORRECTION_MODE
* @see ACAMERA_SCALER_CROP_REGION
* @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE
@@ -1126,10 +1159,17 @@
* </ul>
* <p>For devices at the LIMITED level or above:</p>
* <ul>
- * <li>For YUV_420_888 burst capture use case, this list will always include (<code>min</code>, <code>max</code>)
- * and (<code>max</code>, <code>max</code>) where <code>min</code> <= 15 and <code>max</code> = the maximum output frame rate of the
+ * <li>For devices that advertise NIR color filter arrangement in
+ * ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT, this list will always include
+ * (<code>max</code>, <code>max</code>) where <code>max</code> = the maximum output frame rate of the maximum YUV_420_888
+ * output size.</li>
+ * <li>For devices advertising any color filter arrangement other than NIR, or devices not
+ * advertising color filter arrangement, this list will always include (<code>min</code>, <code>max</code>) and
+ * (<code>max</code>, <code>max</code>) where <code>min</code> <= 15 and <code>max</code> = the maximum output frame rate of the
* maximum YUV_420_888 output size.</li>
* </ul>
+ *
+ * @see ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT
*/
ACAMERA_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES = // int32[2*n]
ACAMERA_CONTROL_START + 20,
@@ -1304,7 +1344,7 @@
/**
* <p>List of the maximum number of regions that can be used for metering in
* auto-exposure (AE), auto-white balance (AWB), and auto-focus (AF);
- * this corresponds to the the maximum number of elements in
+ * this corresponds to the maximum number of elements in
* ACAMERA_CONTROL_AE_REGIONS, ACAMERA_CONTROL_AWB_REGIONS,
* and ACAMERA_CONTROL_AF_REGIONS.</p>
*
@@ -1727,6 +1767,169 @@
*/
ACAMERA_CONTROL_AF_SCENE_CHANGE = // byte (acamera_metadata_enum_android_control_af_scene_change_t)
ACAMERA_CONTROL_START + 42,
+ /**
+ * <p>The list of bokeh modes for ACAMERA_CONTROL_BOKEH_MODE that are supported by this camera
+ * device, and each bokeh mode's maximum streaming (non-stall) size with bokeh effect.</p>
+ *
+ * @see ACAMERA_CONTROL_BOKEH_MODE
+ *
+ * <p>Type: int32[3*n]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>For OFF mode, the camera behaves normally with no bokeh effect.</p>
+ * <p>For STILL_CAPTURE mode, the maximum streaming dimension specifies the limit under which
+ * bokeh is effective when capture intent is PREVIEW. Note that when capture intent is
+ * PREVIEW, the bokeh effect may not be as high quality compared to STILL_CAPTURE intent
+ * in order to maintain reasonable frame rate. The maximum streaming dimension must be one
+ * of the YUV_420_888 or PRIVATE resolutions in availableStreamConfigurations, or (0, 0)
+ * if preview bokeh is not supported. If the application configures a stream larger than
+ * the maximum streaming dimension, bokeh effect may not be applied for this stream for
+ * PREVIEW intent.</p>
+ * <p>For CONTINUOUS mode, the maximum streaming dimension specifies the limit under which
+ * bokeh is effective. This dimension must be one of the YUV_420_888 or PRIVATE resolutions
+ * in availableStreamConfigurations, and if the sensor maximum resolution is larger than or
+ * equal to 1080p, the maximum streaming dimension must be at least 1080p. If the
+ * application configures a stream with larger dimension, the stream may not have bokeh
+ * effect applied.</p>
+ */
+ ACAMERA_CONTROL_AVAILABLE_BOKEH_MAX_SIZES = // int32[3*n]
+ ACAMERA_CONTROL_START + 43,
+ /**
+ * <p>The ranges of supported zoom ratio for non-OFF ACAMERA_CONTROL_BOKEH_MODE.</p>
+ *
+ * @see ACAMERA_CONTROL_BOKEH_MODE
+ *
+ * <p>Type: float[2*n]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>When bokeh mode is enabled, the camera device may have limited range of zoom ratios
+ * compared to when bokeh mode is disabled. This tag lists the zoom ratio ranges for all
+ * supported non-OFF bokeh modes, in the same order as in
+ * ACAMERA_CONTROL_AVAILABLE_BOKEH_CAPABILITIES.</p>
+ * <p>Range [1.0, 1.0] means that no zoom (optical or digital) is supported.</p>
+ *
+ * @see ACAMERA_CONTROL_AVAILABLE_BOKEH_CAPABILITIES
+ */
+ ACAMERA_CONTROL_AVAILABLE_BOKEH_ZOOM_RATIO_RANGES = // float[2*n]
+ ACAMERA_CONTROL_START + 44,
+ /**
+ * <p>Whether bokeh mode is enabled for a particular capture request.</p>
+ *
+ * <p>Type: byte (acamera_metadata_enum_android_control_bokeh_mode_t)</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraCaptureSession_captureCallback_result callbacks</li>
+ * <li>ACaptureRequest</li>
+ * </ul></p>
+ *
+ * <p>With bokeh mode, the camera device may blur out the parts of scene that are not in
+ * focus, creating a bokeh (or shallow depth of field) effect for people or objects.</p>
+ * <p>When set to STILL_CAPTURE bokeh mode with STILL_CAPTURE capture intent, due to the extra
+ * processing needed for high quality bokeh effect, the stall may be longer than when
+ * capture intent is not STILL_CAPTURE.</p>
+ * <p>When set to STILL_CAPTURE bokeh mode with PREVIEW capture intent,</p>
+ * <ul>
+ * <li>If the camera device has BURST_CAPTURE capability, the frame rate requirement of
+ * BURST_CAPTURE must still be met.</li>
+ * <li>All streams not larger than the maximum streaming dimension for STILL_CAPTURE mode
+ * (queried via {@link ACAMERA_CONTROL_AVAILABLE_BOKEH_CAPABILITIES })
+ * will have preview bokeh effect applied.</li>
+ * </ul>
+ * <p>When set to CONTINUOUS mode, configured streams dimension should not exceed this mode's
+ * maximum streaming dimension in order to have bokeh effect applied. Bokeh effect may not
+ * be available for streams larger than the maximum streaming dimension.</p>
+ * <p>Switching between different bokeh modes may involve reconfiguration of the camera
+ * pipeline, resulting in long latency. The application should check this key against the
+ * available session keys queried via
+ * {@link ACameraManager_getCameraCharacteristics }.</p>
+ * <p>When bokeh mode is on, the camera device may override certain control parameters, such as
+ * reduce frame rate or use face priority scene mode, to achieve best power and quality
+ * tradeoffs. When turned on, AE, AWB, and AF run in auto modes, and only the mandatory
+ * stream combinations of LIMITED hardware level are guaranteed.</p>
+ * <p>For a logical multi-camera, bokeh may be implemented by stereo vision from sub-cameras
+ * with different field of view. As a result, when bokeh mode is enabled, the camera device
+ * may override ACAMERA_SCALER_CROP_REGION, and the field of view will be smaller than when
+ * bokeh mode is off.</p>
+ *
+ * @see ACAMERA_SCALER_CROP_REGION
+ */
+ ACAMERA_CONTROL_BOKEH_MODE = // byte (acamera_metadata_enum_android_control_bokeh_mode_t)
+ ACAMERA_CONTROL_START + 45,
+ /**
+ * <p>Minimum and maximum zoom ratios supported by this camera device.</p>
+ *
+ * <p>Type: float[2]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>If the camera device supports zoom-out from 1x zoom, minZoom will be less than 1.0, and
+ * setting ACAMERA_CONTROL_ZOOM_RATIO to values less than 1.0 increases the camera's field
+ * of view.</p>
+ *
+ * @see ACAMERA_CONTROL_ZOOM_RATIO
+ */
+ ACAMERA_CONTROL_ZOOM_RATIO_RANGE = // float[2]
+ ACAMERA_CONTROL_START + 46,
+ /**
+ * <p>The desired zoom ratio</p>
+ *
+ * <p>Type: float</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraCaptureSession_captureCallback_result callbacks</li>
+ * <li>ACaptureRequest</li>
+ * </ul></p>
+ *
+ * <p>Instead of using ACAMERA_SCALER_CROP_REGION with dual purposes of crop and zoom, the
+ * application can now choose to use this tag to specify the desired zoom level. The
+ * ACAMERA_SCALER_CROP_REGION can still be used to specify the horizontal or vertical
+ * crop to achieve aspect ratios different than the native camera sensor.</p>
+ * <p>By using this control, the application gains a simpler way to control zoom, which can
+ * be a combination of optical and digital zoom. More specifically, for a logical
+ * multi-camera with more than one focal length, using a floating point zoom ratio offers
+ * more zoom precision when a telephoto lens is used, as well as allowing zoom ratio of
+ * less than 1.0 to zoom out to a wide field of view.</p>
+ * <p>Note that the coordinate system of cropRegion, AE/AWB/AF regions, and faces now changes
+ * to the effective after-zoom field-of-view represented by rectangle of (0, 0,
+ * activeArrayWidth, activeArrayHeight).</p>
+ * <p>For example, if ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE is 4032*3024, and the preview stream
+ * is configured to the same 4:3 aspect ratio, the application can achieve 2.0x zoom in
+ * one of two ways:</p>
+ * <ul>
+ * <li>zoomRatio = 2.0, scaler.cropRegion = (0, 0, 4032, 3024)</li>
+ * <li>zoomRatio = 1.0 (default), scaler.cropRegion = (1008, 756, 3024, 2268)</li>
+ * </ul>
+ * <p>If the application intends to set aeRegions to be top-left quarter of the preview
+ * field-of-view, the ACAMERA_CONTROL_AE_REGIONS should be set to (0, 0, 2016, 1512) with
+ * zoomRatio set to 2.0. Alternatively, the application can set aeRegions to the equivalent
+ * region of (1008, 756, 2016, 1512) for zoomRatio of 1.0. If the application doesn't
+ * explicitly set ACAMERA_CONTROL_ZOOM_RATIO, its value defaults to 1.0.</p>
+ * <p>This coordinate system change isn't applicable to RAW capture and its related metadata
+ * such as intrinsicCalibration and lensShadingMap.</p>
+ * <p>One limitation of controlling zoom using zoomRatio is that the ACAMERA_SCALER_CROP_REGION
+ * must only be used for letterboxing or pillarboxing of the sensor active array, and no
+ * FREEFORM cropping can be used with ACAMERA_CONTROL_ZOOM_RATIO other than 1.0.</p>
+ *
+ * @see ACAMERA_CONTROL_AE_REGIONS
+ * @see ACAMERA_CONTROL_ZOOM_RATIO
+ * @see ACAMERA_SCALER_CROP_REGION
+ * @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ */
+ ACAMERA_CONTROL_ZOOM_RATIO = // float
+ ACAMERA_CONTROL_START + 47,
ACAMERA_CONTROL_END,
/**
@@ -2306,6 +2509,11 @@
* <p><code>p' = Rp</code></p>
* <p>where <code>p</code> is in the device sensor coordinate system, and
* <code>p'</code> is in the camera-oriented coordinate system.</p>
+ * <p>If ACAMERA_LENS_POSE_REFERENCE is UNDEFINED, the quaternion rotation cannot
+ * be accurately represented by the camera device, and will be represented by
+ * default values matching its default facing.</p>
+ *
+ * @see ACAMERA_LENS_POSE_REFERENCE
*/
ACAMERA_LENS_POSE_ROTATION = // float[4]
ACAMERA_LENS_START + 6,
@@ -2346,6 +2554,8 @@
* <p>When ACAMERA_LENS_POSE_REFERENCE is GYROSCOPE, then this position is relative to
* the center of the primary gyroscope on the device. The axis definitions are the same as
* with PRIMARY_CAMERA.</p>
+ * <p>When ACAMERA_LENS_POSE_REFERENCE is UNDEFINED, this position cannot be accurately
+ * represented by the camera device, and will be represented as <code>(0, 0, 0)</code>.</p>
*
* @see ACAMERA_LENS_DISTORTION
* @see ACAMERA_LENS_INTRINSIC_CALIBRATION
@@ -2488,8 +2698,10 @@
ACAMERA_LENS_RADIAL_DISTORTION = // Deprecated! DO NOT USE
ACAMERA_LENS_START + 11,
/**
- * <p>The origin for ACAMERA_LENS_POSE_TRANSLATION.</p>
+ * <p>The origin for ACAMERA_LENS_POSE_TRANSLATION, and the accuracy of
+ * ACAMERA_LENS_POSE_TRANSLATION and ACAMERA_LENS_POSE_ROTATION.</p>
*
+ * @see ACAMERA_LENS_POSE_ROTATION
* @see ACAMERA_LENS_POSE_TRANSLATION
*
* <p>Type: byte (acamera_metadata_enum_android_lens_pose_reference_t)</p>
@@ -3085,32 +3297,70 @@
* <p>For devices not supporting ACAMERA_DISTORTION_CORRECTION_MODE control, the coordinate
* system always follows that of ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE, with <code>(0, 0)</code> being
* the top-left pixel of the active array.</p>
- * <p>For devices supporting ACAMERA_DISTORTION_CORRECTION_MODE control, the coordinate
- * system depends on the mode being set.
- * When the distortion correction mode is OFF, the coordinate system follows
- * ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE, with
- * <code>(0, 0)</code> being the top-left pixel of the pre-correction active array.
- * When the distortion correction mode is not OFF, the coordinate system follows
- * ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE, with
- * <code>(0, 0)</code> being the top-left pixel of the active array.</p>
- * <p>Output streams use this rectangle to produce their output,
- * cropping to a smaller region if necessary to maintain the
- * stream's aspect ratio, then scaling the sensor input to
+ * <p>For devices supporting ACAMERA_DISTORTION_CORRECTION_MODE control, the coordinate system
+ * depends on the mode being set. When the distortion correction mode is OFF, the
+ * coordinate system follows ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE, with <code>(0,
+ * 0)</code> being the top-left pixel of the pre-correction active array. When the distortion
+ * correction mode is not OFF, the coordinate system follows
+ * ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE, with <code>(0, 0)</code> being the top-left pixel of the
+ * active array.</p>
+ * <p>Output streams use this rectangle to produce their output, cropping to a smaller region
+ * if necessary to maintain the stream's aspect ratio, then scaling the sensor input to
* match the output's configured resolution.</p>
- * <p>The crop region is applied after the RAW to other color
- * space (e.g. YUV) conversion. Since raw streams
- * (e.g. RAW16) don't have the conversion stage, they are not
+ * <p>The crop region is applied after the RAW to other color space (e.g. YUV)
+ * conversion. Since raw streams (e.g. RAW16) don't have the conversion stage, they are not
* croppable. The crop region will be ignored by raw streams.</p>
- * <p>For non-raw streams, any additional per-stream cropping will
- * be done to maximize the final pixel area of the stream.</p>
- * <p>For example, if the crop region is set to a 4:3 aspect
- * ratio, then 4:3 streams will use the exact crop
- * region. 16:9 streams will further crop vertically
- * (letterbox).</p>
- * <p>Conversely, if the crop region is set to a 16:9, then 4:3
- * outputs will crop horizontally (pillarbox), and 16:9
- * streams will match exactly. These additional crops will
- * be centered within the crop region.</p>
+ * <p>For non-raw streams, any additional per-stream cropping will be done to maximize the
+ * final pixel area of the stream.</p>
+ * <p>For example, if the crop region is set to a 4:3 aspect ratio, then 4:3 streams will use
+ * the exact crop region. 16:9 streams will further crop vertically (letterbox).</p>
+ * <p>Conversely, if the crop region is set to a 16:9, then 4:3 outputs will crop horizontally
+ * (pillarbox), and 16:9 streams will match exactly. These additional crops will be
+ * centered within the crop region.</p>
+ * <p>To illustrate, here are several scenarios of different crop regions and output streams,
+ * for a hypothetical camera device with an active array of size <code>(2000,1500)</code>. Note that
+ * several of these examples use non-centered crop regions for ease of illustration; such
+ * regions are only supported on devices with FREEFORM capability
+ * (ACAMERA_SCALER_CROPPING_TYPE <code>== FREEFORM</code>), but this does not affect the way the crop
+ * rules work otherwise.</p>
+ * <ul>
+ * <li>Camera Configuration:<ul>
+ * <li>Active array size: <code>2000x1500</code> (3 MP, 4:3 aspect ratio)</li>
+ * <li>Output stream #1: <code>640x480</code> (VGA, 4:3 aspect ratio)</li>
+ * <li>Output stream #2: <code>1280x720</code> (720p, 16:9 aspect ratio)</li>
+ * </ul>
+ * </li>
+ * <li>Case #1: 4:3 crop region with 2x digital zoom<ul>
+ * <li>Crop region: <code>Rect(500, 375, 1500, 1125) // (left, top, right, bottom)</code></li>
+ * <li><img alt="4:3 aspect ratio crop diagram" src="../images/camera2/metadata/android.scaler.cropRegion/crop-region-43-ratio.png" /></li>
+ * <li><code>640x480</code> stream source area: <code>(500, 375, 1500, 1125)</code> (equal to crop region)</li>
+ * <li><code>1280x720</code> stream source area: <code>(500, 469, 1500, 1031)</code> (letterboxed)</li>
+ * </ul>
+ * </li>
+ * <li>Case #2: 16:9 crop region with ~1.5x digital zoom.<ul>
+ * <li>Crop region: <code>Rect(500, 375, 1833, 1125)</code></li>
+ * <li><img alt="16:9 aspect ratio crop diagram" src="../images/camera2/metadata/android.scaler.cropRegion/crop-region-169-ratio.png" /></li>
+ * <li><code>640x480</code> stream source area: <code>(666, 375, 1666, 1125)</code> (pillarboxed)</li>
+ * <li><code>1280x720</code> stream source area: <code>(500, 375, 1833, 1125)</code> (equal to crop region)</li>
+ * </ul>
+ * </li>
+ * <li>Case #3: 1:1 crop region with ~2.6x digital zoom.<ul>
+ * <li>Crop region: <code>Rect(500, 375, 1250, 1125)</code></li>
+ * <li><img alt="1:1 aspect ratio crop diagram" src="../images/camera2/metadata/android.scaler.cropRegion/crop-region-11-ratio.png" /></li>
+ * <li><code>640x480</code> stream source area: <code>(500, 469, 1250, 1031)</code> (letterboxed)</li>
+ * <li><code>1280x720</code> stream source area: <code>(500, 543, 1250, 957)</code> (letterboxed)</li>
+ * </ul>
+ * </li>
+ * <li>Case #4: Replace <code>640x480</code> stream with <code>1024x1024</code> stream, with 4:3 crop region:<ul>
+ * <li>Crop region: <code>Rect(500, 375, 1500, 1125)</code></li>
+ * <li><img alt="Square output, 4:3 aspect ratio crop diagram" src="../images/camera2/metadata/android.scaler.cropRegion/crop-region-43-square-ratio.png" /></li>
+ * <li><code>1024x1024</code> stream source area: <code>(625, 375, 1375, 1125)</code> (pillarboxed)</li>
+ * <li><code>1280x720</code> stream source area: <code>(500, 469, 1500, 1031)</code> (letterboxed)</li>
+ * <li>Note that in this case, neither of the two outputs is a subset of the other, with
+ * each containing image data the other doesn't have.</li>
+ * </ul>
+ * </li>
+ * </ul>
* <p>If the coordinate system is ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE, the width and height
* of the crop region cannot be set to be smaller than
* <code>floor( activeArraySize.width / ACAMERA_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM )</code> and
@@ -3121,14 +3371,22 @@
* and
* <code>floor( preCorrectionActiveArraySize.height / ACAMERA_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM )</code>,
* respectively.</p>
- * <p>The camera device may adjust the crop region to account
- * for rounding and other hardware requirements; the final
- * crop region used will be included in the output capture
- * result.</p>
+ * <p>The camera device may adjust the crop region to account for rounding and other hardware
+ * requirements; the final crop region used will be included in the output capture result.</p>
+ * <p>Starting from API level 30, it's strongly recommended to use ACAMERA_CONTROL_ZOOM_RATIO
+ * to take advantage of better support for zoom with logical multi-camera. The benefits
+ * include better precision with optical-digital zoom combination, and ability to do
+ * zoom-out from 1.0x. When using ACAMERA_CONTROL_ZOOM_RATIO for zoom, the crop region in
+ * the capture request must be either letterboxing or pillarboxing (but not both). The
+ * coordinate system is post-zoom, meaning that the activeArraySize or
+ * preCorrectionActiveArraySize covers the camera device's field of view "after" zoom. See
+ * ACAMERA_CONTROL_ZOOM_RATIO for details.</p>
* <p>The data representation is int[4], which maps to (left, top, width, height).</p>
*
+ * @see ACAMERA_CONTROL_ZOOM_RATIO
* @see ACAMERA_DISTORTION_CORRECTION_MODE
* @see ACAMERA_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM
+ * @see ACAMERA_SCALER_CROPPING_TYPE
* @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE
* @see ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
*/
@@ -3154,6 +3412,12 @@
* <p>Crop regions that have a width or height that is smaller
* than this ratio allows will be rounded up to the minimum
* allowed size by the camera device.</p>
+ * <p>Starting from API level 30, when using ACAMERA_CONTROL_ZOOM_RATIO to zoom in or out,
+ * the application must use ACAMERA_CONTROL_ZOOM_RATIO_RANGE to query both the minimum and
+ * maximum zoom ratio.</p>
+ *
+ * @see ACAMERA_CONTROL_ZOOM_RATIO
+ * @see ACAMERA_CONTROL_ZOOM_RATIO_RANGE
*/
ACAMERA_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM = // float
ACAMERA_SCALER_START + 4,
@@ -3328,8 +3592,24 @@
* <p>Camera devices that support FREEFORM cropping will support any crop region that
* is inside of the active array. The camera device will apply the same crop region and
* return the final used crop region in capture result metadata ACAMERA_SCALER_CROP_REGION.</p>
+ * <p>Starting from API level 30,</p>
+ * <ul>
+ * <li>If the camera device supports FREEFORM cropping, in order to do FREEFORM cropping, the
+ * application must set ACAMERA_CONTROL_ZOOM_RATIO to 1.0, and use ACAMERA_SCALER_CROP_REGION
+ * for zoom.</li>
+ * <li>To do CENTER_ONLY zoom, the application has below 2 options:<ol>
+ * <li>Set ACAMERA_CONTROL_ZOOM_RATIO to 1.0; adjust zoom by ACAMERA_SCALER_CROP_REGION.</li>
+ * <li>Adjust zoom by ACAMERA_CONTROL_ZOOM_RATIO; use ACAMERA_SCALER_CROP_REGION to crop
+ * the field of view vertically (letterboxing) or horizontally (pillarboxing), but not
+ * windowboxing.</li>
+ * </ol>
+ * </li>
+ * <li>Setting ACAMERA_CONTROL_ZOOM_RATIO to values different than 1.0 and
+ * ACAMERA_SCALER_CROP_REGION to be windowboxing at the same time is undefined behavior.</li>
+ * </ul>
* <p>LEGACY capability devices will only support CENTER_ONLY cropping.</p>
*
+ * @see ACAMERA_CONTROL_ZOOM_RATIO
* @see ACAMERA_SCALER_CROP_REGION
* @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE
*/
@@ -3536,11 +3816,19 @@
* output capture result.</p>
* <p>This control is only effective if ACAMERA_CONTROL_AE_MODE or ACAMERA_CONTROL_MODE is set to
* OFF; otherwise the auto-exposure algorithm will override this value.</p>
+ * <p>Note that for devices supporting postRawSensitivityBoost, the total sensitivity applied
+ * to the final processed image is the combination of ACAMERA_SENSOR_SENSITIVITY and
+ * ACAMERA_CONTROL_POST_RAW_SENSITIVITY_BOOST. In case the application uses the sensor
+ * sensitivity from last capture result of an auto request for a manual request, in order
+ * to achieve the same brightness in the output image, the application should also
+ * set postRawSensitivityBoost.</p>
*
* @see ACAMERA_CONTROL_AE_MODE
* @see ACAMERA_CONTROL_MODE
+ * @see ACAMERA_CONTROL_POST_RAW_SENSITIVITY_BOOST
* @see ACAMERA_SENSOR_INFO_SENSITIVITY_RANGE
* @see ACAMERA_SENSOR_MAX_ANALOG_SENSITIVITY
+ * @see ACAMERA_SENSOR_SENSITIVITY
*/
ACAMERA_SENSOR_SENSITIVITY = // int32
ACAMERA_SENSOR_START + 2,
@@ -4621,9 +4909,20 @@
* When the distortion correction mode is not OFF, the coordinate system follows
* ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE, with
* <code>(0, 0)</code> being the top-left pixel of the active array.</p>
- * <p>Only available if ACAMERA_STATISTICS_FACE_DETECT_MODE == FULL</p>
+ * <p>Only available if ACAMERA_STATISTICS_FACE_DETECT_MODE == FULL.</p>
+ * <p>Starting from API level 30, the coordinate system of activeArraySize or
+ * preCorrectionActiveArraySize is used to represent post-zoomRatio field of view, not
+ * pre-zoomRatio field of view. This means that if the relative position of faces and
+ * the camera device doesn't change, when zooming in by increasing
+ * ACAMERA_CONTROL_ZOOM_RATIO, the face landmarks move farther away from the center of the
+ * activeArray or preCorrectionActiveArray. If ACAMERA_CONTROL_ZOOM_RATIO is set to 1.0
+ * (default), the face landmarks coordinates won't change as ACAMERA_SCALER_CROP_REGION
+ * changes. See ACAMERA_CONTROL_ZOOM_RATIO for details. Whether to use activeArraySize or
+ * preCorrectionActiveArraySize still depends on distortion correction mode.</p>
*
+ * @see ACAMERA_CONTROL_ZOOM_RATIO
* @see ACAMERA_DISTORTION_CORRECTION_MODE
+ * @see ACAMERA_SCALER_CROP_REGION
* @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE
* @see ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
* @see ACAMERA_STATISTICS_FACE_DETECT_MODE
@@ -4652,10 +4951,21 @@
* When the distortion correction mode is not OFF, the coordinate system follows
* ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE, with
* <code>(0, 0)</code> being the top-left pixel of the active array.</p>
- * <p>Only available if ACAMERA_STATISTICS_FACE_DETECT_MODE != OFF
- * The data representation is <code>int[4]</code>, which maps to <code>(left, top, right, bottom)</code>.</p>
+ * <p>Only available if ACAMERA_STATISTICS_FACE_DETECT_MODE != OFF.</p>
+ * <p>Starting from API level 30, the coordinate system of activeArraySize or
+ * preCorrectionActiveArraySize is used to represent post-zoomRatio field of view, not
+ * pre-zoomRatio field of view. This means that if the relative position of faces and
+ * the camera device doesn't change, when zooming in by increasing
+ * ACAMERA_CONTROL_ZOOM_RATIO, the face rectangles grow larger and move farther away from
+ * the center of the activeArray or preCorrectionActiveArray. If ACAMERA_CONTROL_ZOOM_RATIO
+ * is set to 1.0 (default), the face rectangles won't change as ACAMERA_SCALER_CROP_REGION
+ * changes. See ACAMERA_CONTROL_ZOOM_RATIO for details. Whether to use activeArraySize or
+ * preCorrectionActiveArraySize still depends on distortion correction mode.</p>
+ * <p>The data representation is <code>int[4]</code>, which maps to <code>(left, top, right, bottom)</code>.</p>
*
+ * @see ACAMERA_CONTROL_ZOOM_RATIO
* @see ACAMERA_DISTORTION_CORRECTION_MODE
+ * @see ACAMERA_SCALER_CROP_REGION
* @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE
* @see ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
* @see ACAMERA_STATISTICS_FACE_DETECT_MODE
@@ -6987,6 +7297,31 @@
} acamera_metadata_enum_android_control_af_scene_change_t;
+// ACAMERA_CONTROL_BOKEH_MODE
+typedef enum acamera_metadata_enum_acamera_control_bokeh_mode {
+ /**
+ * <p>Bokeh mode is disabled.</p>
+ */
+ ACAMERA_CONTROL_BOKEH_MODE_OFF = 0,
+
+ /**
+ * <p>High quality bokeh mode is enabled for all non-raw streams (including YUV,
+ * JPEG, and IMPLEMENTATION_DEFINED) when capture intent is STILL_CAPTURE. Due to the
+ * extra image processing, this mode may introduce additional stall to non-raw streams.
+ * This mode should be used in high quality still capture use case.</p>
+ */
+ ACAMERA_CONTROL_BOKEH_MODE_STILL_CAPTURE = 1,
+
+ /**
+ * <p>Bokeh effect must not slow down capture rate relative to sensor raw output,
+ * and the effect is applied to all processed streams no larger than the maximum
+ * streaming dimension. This mode should be used if performance and power are a
+ * priority, such as video recording.</p>
+ */
+ ACAMERA_CONTROL_BOKEH_MODE_CONTINUOUS = 2,
+
+} acamera_metadata_enum_android_control_bokeh_mode_t;
+
// ACAMERA_EDGE_MODE
@@ -7213,6 +7548,19 @@
*/
ACAMERA_LENS_POSE_REFERENCE_GYROSCOPE = 1,
+ /**
+ * <p>The camera device cannot represent the values of ACAMERA_LENS_POSE_TRANSLATION
+ * and ACAMERA_LENS_POSE_ROTATION accurately enough. One such example is a camera device
+ * on the cover of a foldable phone: in order to measure the pose translation and rotation,
+ * some kind of hinge position sensor would be needed.</p>
+ * <p>The value of ACAMERA_LENS_POSE_TRANSLATION must be all zeros, and
+ * ACAMERA_LENS_POSE_ROTATION must be values matching its default facing.</p>
+ *
+ * @see ACAMERA_LENS_POSE_ROTATION
+ * @see ACAMERA_LENS_POSE_TRANSLATION
+ */
+ ACAMERA_LENS_POSE_REFERENCE_UNDEFINED = 2,
+
} acamera_metadata_enum_android_lens_pose_reference_t;
@@ -7593,14 +7941,20 @@
* <p>The camera device is a logical camera backed by two or more physical cameras.</p>
* <p>In API level 28, the physical cameras must also be exposed to the application via
* <a href="https://developer.android.com/reference/android/hardware/camera2/CameraManager.html#getCameraIdList">CameraManager#getCameraIdList</a>.</p>
- * <p>Starting from API level 29, some or all physical cameras may not be independently
- * exposed to the application, in which case the physical camera IDs will not be
- * available in <a href="https://developer.android.com/reference/android/hardware/camera2/CameraManager.html#getCameraIdList">CameraManager#getCameraIdList</a>. But the
+ * <p>Starting from API level 29:</p>
+ * <ul>
+ * <li>Some or all physical cameras may not be independently exposed to the application,
+ * in which case the physical camera IDs will not be available in
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraManager.html#getCameraIdList">CameraManager#getCameraIdList</a>. But the
* application can still query the physical cameras' characteristics by calling
- * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraManager.html#getCameraCharacteristics">CameraManager#getCameraCharacteristics</a>. Additionally,
- * if a physical camera is hidden from camera ID list, the mandatory stream combinations
- * for that physical camera must be supported through the logical camera using physical
- * streams.</p>
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraManager.html#getCameraCharacteristics">CameraManager#getCameraCharacteristics</a>.</li>
+ * <li>If a physical camera is hidden from camera ID list, the mandatory stream
+ * combinations for that physical camera must be supported through the logical camera
+ * using physical streams. One exception is that in API level 30, a physical camera
+ * may become unavailable via
+ * {@link ACameraManager_PhysicalCameraAvailabilityCallback }
+ * callback.</li>
+ * </ul>
* <p>Combinations of logical and physical streams, or physical streams from different
* physical cameras are not guaranteed. However, if the camera device supports
* {@link ACameraDevice_isSessionConfigurationSupported },
@@ -7751,6 +8105,13 @@
*/
ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA = 13,
+ /**
+ * <p>The camera device is only accessible by Android's system components and privileged
+ * applications. Processes need to have the android.permission.SYSTEM_CAMERA in
+ * addition to android.permission.CAMERA in order to connect to this camera device.</p>
+ */
+ ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA = 14,
+
} acamera_metadata_enum_android_request_available_capabilities_t;
@@ -8047,12 +8408,16 @@
// ACAMERA_SENSOR_INFO_TIMESTAMP_SOURCE
typedef enum acamera_metadata_enum_acamera_sensor_info_timestamp_source {
/**
- * <p>Timestamps from ACAMERA_SENSOR_TIMESTAMP are in nanoseconds and monotonic,
- * but can not be compared to timestamps from other subsystems
- * (e.g. accelerometer, gyro etc.), or other instances of the same or different
- * camera devices in the same system. Timestamps between streams and results for
- * a single camera instance are comparable, and the timestamps for all buffers
- * and the result metadata generated by a single capture are identical.</p>
+ * <p>Timestamps from ACAMERA_SENSOR_TIMESTAMP are in nanoseconds and monotonic, but can
+ * not be compared to timestamps from other subsystems (e.g. accelerometer, gyro etc.),
+ * or other instances of the same or different camera devices in the same system with
+ * accuracy. However, the timestamps are roughly in the same timebase as
+ * <a href="https://developer.android.com/reference/android/os/SystemClock.html#uptimeMillis">SystemClock#uptimeMillis</a>. The accuracy is sufficient for tasks
+ * like A/V synchronization for video recording, at least, and the timestamps can be
+ * directly used together with timestamps from the audio subsystem for that task.</p>
+ * <p>Timestamps between streams and results for a single camera instance are comparable,
+ * and the timestamps for all buffers and the result metadata generated by a single
+ * capture are identical.</p>
*
* @see ACAMERA_SENSOR_TIMESTAMP
*/
@@ -8062,6 +8427,14 @@
* <p>Timestamps from ACAMERA_SENSOR_TIMESTAMP are in the same timebase as
* <a href="https://developer.android.com/reference/android/os/SystemClock.html#elapsedRealtimeNanos">SystemClock#elapsedRealtimeNanos</a>,
* and they can be compared to other timestamps using that base.</p>
+ * <p>When buffers from a REALTIME device are passed directly to a video encoder from the
+ * camera, automatic compensation is done to account for differing timebases of the
+ * audio and camera subsystems. If the application is receiving buffers and then later
+ * sending them to a video encoder or other application where they are compared with
+ * audio subsystem timestamps or similar, this compensation is not present. In those
+ * cases, applications need to adjust the timestamps themselves. Since <a href="https://developer.android.com/reference/android/os/SystemClock.html#elapsedRealtimeNanos">SystemClock#elapsedRealtimeNanos</a> and <a href="https://developer.android.com/reference/android/os/SystemClock.html#uptimeMillis">SystemClock#uptimeMillis</a> only diverge while the device is asleep, an
+ * offset between the two sources can be measured once per active session and applied
+ * to timestamps for sufficient accuracy for A/V sync.</p>
*
* @see ACAMERA_SENSOR_TIMESTAMP
*/
diff --git a/camera/ndk/libcamera2ndk.map.txt b/camera/ndk/libcamera2ndk.map.txt
index b6f1553..2b630db 100644
--- a/camera/ndk/libcamera2ndk.map.txt
+++ b/camera/ndk/libcamera2ndk.map.txt
@@ -31,6 +31,7 @@
ACameraMetadata_getAllTags;
ACameraMetadata_getConstEntry;
ACameraMetadata_isLogicalMultiCamera; # introduced=29
+ ACameraMetadata_fromCameraMetadata; # introduced=30
ACameraOutputTarget_create;
ACameraOutputTarget_free;
ACaptureRequest_addTarget;
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
index 70c887a..e2097b5 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
@@ -36,13 +36,13 @@
namespace android {
namespace acam {
-using frameworks::cameraservice::service::V2_0::CameraStatusAndId;
using frameworks::cameraservice::common::V2_0::ProviderIdAndVendorTagSections;
using android::hardware::camera::common::V1_0::helper::VendorTagDescriptor;
using android::hardware::camera::common::V1_0::helper::VendorTagDescriptorCache;
// Static member definitions
const char* CameraManagerGlobal::kCameraIdKey = "CameraId";
+const char* CameraManagerGlobal::kPhysicalCameraIdKey = "PhysicalCameraId";
const char* CameraManagerGlobal::kCallbackFpKey = "CallbackFp";
const char* CameraManagerGlobal::kContextKey = "CallbackContext";
Mutex CameraManagerGlobal::sLock;
@@ -258,9 +258,9 @@
if (mCameraServiceListener == nullptr) {
mCameraServiceListener = new CameraServiceListener(this);
}
- hidl_vec<CameraStatusAndId> cameraStatuses{};
+ hidl_vec<frameworks::cameraservice::service::V2_1::CameraStatusAndId> cameraStatuses{};
Status status = Status::NO_ERROR;
- auto remoteRet = mCameraService->addListener(mCameraServiceListener,
+ auto remoteRet = mCameraService->addListener_2_1(mCameraServiceListener,
[&status, &cameraStatuses](Status s,
auto &retStatuses) {
status = s;
@@ -277,7 +277,15 @@
}
for (auto& c : cameraStatuses) {
- onStatusChangedLocked(c);
+ onStatusChangedLocked(c.v2_0);
+
+ for (auto& unavailablePhysicalId : c.unavailPhysicalCameraIds) {
+ PhysicalCameraStatusAndId statusAndId;
+ statusAndId.deviceStatus = CameraDeviceStatus::STATUS_NOT_PRESENT;
+ statusAndId.cameraId = c.v2_0.cameraId;
+ statusAndId.physicalCameraId = unavailablePhysicalId;
+ onStatusChangedLocked(statusAndId);
+ }
}
}
return mCameraService;
@@ -293,7 +301,7 @@
for (auto& pair : cm->mDeviceStatusMap) {
CameraStatusAndId cameraStatusAndId;
cameraStatusAndId.cameraId = pair.first;
- cameraStatusAndId.deviceStatus = pair.second;
+ cameraStatusAndId.deviceStatus = pair.second.getStatus();
cm->onStatusChangedLocked(cameraStatusAndId);
}
cm->mCameraService.clear();
@@ -303,24 +311,7 @@
void CameraManagerGlobal::registerAvailabilityCallback(
const ACameraManager_AvailabilityCallbacks *callback) {
- Mutex::Autolock _l(mLock);
- Callback cb(callback);
- auto pair = mCallbacks.insert(cb);
- // Send initial callbacks if callback is newly registered
- if (pair.second) {
- for (auto& pair : mDeviceStatusMap) {
- const hidl_string& cameraId = pair.first;
- CameraDeviceStatus status = pair.second;
-
- sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
- ACameraManager_AvailabilityCallback cb = isStatusAvailable(status) ?
- callback->onCameraAvailable : callback->onCameraUnavailable;
- msg->setPointer(kCallbackFpKey, (void *) cb);
- msg->setPointer(kContextKey, callback->context);
- msg->setString(kCameraIdKey, AString(cameraId.c_str()));
- msg->post();
- }
- }
+ return registerAvailCallback<ACameraManager_AvailabilityCallbacks>(callback);
}
void CameraManagerGlobal::unregisterAvailabilityCallback(
@@ -330,14 +321,63 @@
mCallbacks.erase(cb);
}
+void CameraManagerGlobal::registerExtendedAvailabilityCallback(
+ const ACameraManager_ExtendedAvailabilityCallbacks *callback) {
+ return registerAvailCallback<ACameraManager_ExtendedAvailabilityCallbacks>(callback);
+}
+
+void CameraManagerGlobal::unregisterExtendedAvailabilityCallback(
+ const ACameraManager_ExtendedAvailabilityCallbacks *callback) {
+ Mutex::Autolock _l(mLock);
+ Callback cb(callback);
+ mCallbacks.erase(cb);
+}
+
+template <class T>
+void CameraManagerGlobal::registerAvailCallback(const T *callback) {
+ Mutex::Autolock _l(mLock);
+ Callback cb(callback);
+ auto pair = mCallbacks.insert(cb);
+ // Send initial callbacks if callback is newly registered
+ if (pair.second) {
+ for (auto& pair : mDeviceStatusMap) {
+ const hidl_string& cameraId = pair.first;
+ CameraDeviceStatus status = pair.second.getStatus();
+
+ // Camera available/unavailable callback
+ sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
+ ACameraManager_AvailabilityCallback cbFunc = isStatusAvailable(status) ?
+ cb.mAvailable : cb.mUnavailable;
+ msg->setPointer(kCallbackFpKey, (void *) cbFunc);
+ msg->setPointer(kContextKey, cb.mContext);
+ msg->setString(kCameraIdKey, AString(cameraId.c_str()));
+ msg->post();
+
+ // Physical camera unavailable callback
+ std::set<hidl_string> unavailPhysicalIds = pair.second.getUnavailablePhysicalIds();
+ for (const auto& physicalCameraId : unavailPhysicalIds) {
+ sp<AMessage> msg = new AMessage(kWhatSendSinglePhysicalCameraCallback, mHandler);
+ ACameraManager_PhysicalCameraAvailabilityCallback cbFunc =
+ cb.mPhysicalCamUnavailable;
+ msg->setPointer(kCallbackFpKey, (void *) cbFunc);
+ msg->setPointer(kContextKey, cb.mContext);
+ msg->setString(kCameraIdKey, AString(cameraId.c_str()));
+ msg->setString(kPhysicalCameraIdKey, AString(physicalCameraId.c_str()));
+ msg->post();
+ }
+ }
+ }
+}
+
void CameraManagerGlobal::getCameraIdList(std::vector<hidl_string>* cameraIds) {
// Ensure that we have initialized/refreshed the list of available devices
auto cs = getCameraService();
Mutex::Autolock _l(mLock);
for(auto& deviceStatus : mDeviceStatusMap) {
- if (deviceStatus.second == CameraDeviceStatus::STATUS_NOT_PRESENT ||
- deviceStatus.second == CameraDeviceStatus::STATUS_ENUMERATING) {
+ CameraDeviceStatus status = deviceStatus.second.getStatus();
+ if (status == CameraDeviceStatus::STATUS_NOT_PRESENT ||
+ status == CameraDeviceStatus::STATUS_ENUMERATING) {
continue;
}
cameraIds->push_back(deviceStatus.first);
@@ -391,6 +431,35 @@
(*cb)(context, cameraId.c_str());
break;
}
+ case kWhatSendSinglePhysicalCameraCallback:
+ {
+ ACameraManager_PhysicalCameraAvailabilityCallback cb;
+ void* context;
+ AString cameraId;
+ AString physicalCameraId;
+ bool found = msg->findPointer(kCallbackFpKey, (void**) &cb);
+ if (!found) {
+ ALOGE("%s: Cannot find camera callback fp!", __FUNCTION__);
+ return;
+ }
+ found = msg->findPointer(kContextKey, &context);
+ if (!found) {
+ ALOGE("%s: Cannot find callback context!", __FUNCTION__);
+ return;
+ }
+ found = msg->findString(kCameraIdKey, &cameraId);
+ if (!found) {
+ ALOGE("%s: Cannot find camera ID!", __FUNCTION__);
+ return;
+ }
+ found = msg->findString(kPhysicalCameraIdKey, &physicalCameraId);
+ if (!found) {
+ ALOGE("%s: Cannot find physical camera ID!", __FUNCTION__);
+ return;
+ }
+ (*cb)(context, cameraId.c_str(), physicalCameraId.c_str());
+ break;
+ }
default:
ALOGE("%s: unknown message type %d", __FUNCTION__, msg->what());
break;
@@ -426,7 +495,7 @@
bool firstStatus = (mDeviceStatusMap.count(cameraId) == 0);
CameraDeviceStatus oldStatus = firstStatus ?
status : // first status
- mDeviceStatusMap[cameraId];
+ mDeviceStatusMap[cameraId].getStatus();
if (!firstStatus &&
isStatusAvailable(status) == isStatusAvailable(oldStatus)) {
@@ -435,7 +504,7 @@
}
// Iterate through all registered callbacks
- mDeviceStatusMap[cameraId] = status;
+ mDeviceStatusMap[cameraId].updateStatus(status);
for (auto cb : mCallbacks) {
sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
ACameraManager_AvailabilityCallback cbFp = isStatusAvailable(status) ?
@@ -450,6 +519,98 @@
}
}
+hardware::Return<void> CameraManagerGlobal::CameraServiceListener::onPhysicalCameraStatusChanged(
+ const PhysicalCameraStatusAndId &statusAndId) {
+ sp<CameraManagerGlobal> cm = mCameraManager.promote();
+ if (cm != nullptr) {
+ cm->onStatusChanged(statusAndId);
+ } else {
+ ALOGE("Cannot deliver status change. Global camera manager died");
+ }
+ return Void();
+}
+
+void CameraManagerGlobal::onStatusChanged(
+ const PhysicalCameraStatusAndId &statusAndId) {
+ Mutex::Autolock _l(mLock);
+ onStatusChangedLocked(statusAndId);
+}
+
+void CameraManagerGlobal::onStatusChangedLocked(
+ const PhysicalCameraStatusAndId &statusAndId) {
+ hidl_string cameraId = statusAndId.cameraId;
+ hidl_string physicalCameraId = statusAndId.physicalCameraId;
+ CameraDeviceStatus status = statusAndId.deviceStatus;
+ if (!validStatus(status)) {
+ ALOGE("%s: Invalid status %d", __FUNCTION__, status);
+ return;
+ }
+
+ auto logicalStatus = mDeviceStatusMap.find(cameraId);
+ if (logicalStatus == mDeviceStatusMap.end()) {
+ ALOGE("%s: Physical camera id %s status change on a non-present id %s",
+ __FUNCTION__, physicalCameraId.c_str(), cameraId.c_str());
+ return;
+ }
+ CameraDeviceStatus logicalCamStatus = mDeviceStatusMap[cameraId].getStatus();
+ if (logicalCamStatus != CameraDeviceStatus::STATUS_PRESENT &&
+ logicalCamStatus != CameraDeviceStatus::STATUS_NOT_AVAILABLE) {
+ ALOGE("%s: Physical camera id %s status %d change for an invalid logical camera state %d",
+ __FUNCTION__, physicalCameraId.c_str(), status, logicalCamStatus);
+ return;
+ }
+
+ bool updated = false;
+ if (status == CameraDeviceStatus::STATUS_PRESENT) {
+ updated = mDeviceStatusMap[cameraId].removeUnavailablePhysicalId(physicalCameraId);
+ } else {
+ updated = mDeviceStatusMap[cameraId].addUnavailablePhysicalId(physicalCameraId);
+ }
+
+ // Iterate through all registered callbacks
+ if (updated) {
+ for (auto cb : mCallbacks) {
+ sp<AMessage> msg = new AMessage(kWhatSendSinglePhysicalCameraCallback, mHandler);
+ ACameraManager_PhysicalCameraAvailabilityCallback cbFp = isStatusAvailable(status) ?
+ cb.mPhysicalCamAvailable : cb.mPhysicalCamUnavailable;
+ msg->setPointer(kCallbackFpKey, (void *) cbFp);
+ msg->setPointer(kContextKey, cb.mContext);
+ msg->setString(kCameraIdKey, AString(cameraId.c_str()));
+ msg->setString(kPhysicalCameraIdKey, AString(physicalCameraId.c_str()));
+ msg->post();
+ }
+ }
+}
+
+CameraDeviceStatus CameraManagerGlobal::CameraStatus::getStatus() {
+ std::lock_guard<std::mutex> lock(mLock);
+ return status;
+}
+
+void CameraManagerGlobal::CameraStatus::updateStatus(CameraDeviceStatus newStatus) {
+ std::lock_guard<std::mutex> lock(mLock);
+ status = newStatus;
+}
+
+bool CameraManagerGlobal::CameraStatus::addUnavailablePhysicalId(
+ const hidl_string& physicalCameraId) {
+ std::lock_guard<std::mutex> lock(mLock);
+ auto result = unavailablePhysicalIds.insert(physicalCameraId);
+ return result.second;
+}
+
+bool CameraManagerGlobal::CameraStatus::removeUnavailablePhysicalId(
+ const hidl_string& physicalCameraId) {
+ std::lock_guard<std::mutex> lock(mLock);
+ auto count = unavailablePhysicalIds.erase(physicalCameraId);
+ return count > 0;
+}
+
+std::set<hidl_string> CameraManagerGlobal::CameraStatus::getUnavailablePhysicalIds() {
+ std::lock_guard<std::mutex> lock(mLock);
+ return unavailablePhysicalIds;
+}
+
} // namespace acam
} // namespace android
@@ -574,9 +735,8 @@
if (!serviceRet.isOk() || status != Status::NO_ERROR) {
ALOGE("%s: connect camera device failed", __FUNCTION__);
- // TODO: Convert serviceRet to camera_status_t
delete device;
- return ACAMERA_ERROR_UNKNOWN;
+ return utils::convertFromHidl(status);
}
if (deviceRemote == nullptr) {
ALOGE("%s: connect camera device failed! remote device is null", __FUNCTION__);
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.h b/camera/ndk/ndk_vendor/impl/ACameraManager.h
index 2c62d44..36c8e2b 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraManager.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.h
@@ -21,6 +21,8 @@
#include <android-base/parseint.h>
#include <android/frameworks/cameraservice/service/2.0/ICameraService.h>
+#include <android/frameworks/cameraservice/service/2.1/ICameraService.h>
+#include <android/frameworks/cameraservice/service/2.1/ICameraServiceListener.h>
#include <CameraMetadata.h>
#include <utils/StrongPointer.h>
@@ -36,9 +38,10 @@
namespace android {
namespace acam {
-using ICameraService = frameworks::cameraservice::service::V2_0::ICameraService;
+using ICameraService = frameworks::cameraservice::service::V2_1::ICameraService;
using CameraDeviceStatus = frameworks::cameraservice::service::V2_0::CameraDeviceStatus;
-using ICameraServiceListener = frameworks::cameraservice::service::V2_0::ICameraServiceListener;
+using ICameraServiceListener = frameworks::cameraservice::service::V2_1::ICameraServiceListener;
+using PhysicalCameraStatusAndId = frameworks::cameraservice::service::V2_1::PhysicalCameraStatusAndId;
using CameraStatusAndId = frameworks::cameraservice::service::V2_0::CameraStatusAndId;
using Status = frameworks::cameraservice::common::V2_0::Status;
using VendorTagSection = frameworks::cameraservice::common::V2_0::VendorTagSection;
@@ -65,9 +68,9 @@
const ACameraManager_AvailabilityCallbacks *callback);
void registerExtendedAvailabilityCallback(
- const ACameraManager_ExtendedAvailabilityCallbacks* /*callback*/) {}
+ const ACameraManager_ExtendedAvailabilityCallbacks* callback);
void unregisterExtendedAvailabilityCallback(
- const ACameraManager_ExtendedAvailabilityCallbacks* /*callback*/) {}
+ const ACameraManager_ExtendedAvailabilityCallbacks* callback);
/**
* Return camera IDs that support camera2
@@ -94,6 +97,8 @@
explicit CameraServiceListener(CameraManagerGlobal* cm) : mCameraManager(cm) {}
android::hardware::Return<void> onStatusChanged(
const CameraStatusAndId &statusAndId) override;
+ android::hardware::Return<void> onPhysicalCameraStatusChanged(
+ const PhysicalCameraStatusAndId &statusAndId) override;
private:
const wp<CameraManagerGlobal> mCameraManager;
@@ -105,11 +110,25 @@
explicit Callback(const ACameraManager_AvailabilityCallbacks *callback) :
mAvailable(callback->onCameraAvailable),
mUnavailable(callback->onCameraUnavailable),
+ mAccessPriorityChanged(nullptr),
+ mPhysicalCamAvailable(nullptr),
+ mPhysicalCamUnavailable(nullptr),
mContext(callback->context) {}
+ explicit Callback(const ACameraManager_ExtendedAvailabilityCallbacks *callback) :
+ mAvailable(callback->availabilityCallbacks.onCameraAvailable),
+ mUnavailable(callback->availabilityCallbacks.onCameraUnavailable),
+ mAccessPriorityChanged(callback->onCameraAccessPrioritiesChanged),
+ mPhysicalCamAvailable(callback->onPhysicalCameraAvailable),
+ mPhysicalCamUnavailable(callback->onPhysicalCameraUnavailable),
+ mContext(callback->availabilityCallbacks.context) {}
+
bool operator == (const Callback& other) const {
return (mAvailable == other.mAvailable &&
mUnavailable == other.mUnavailable &&
+ mAccessPriorityChanged == other.mAccessPriorityChanged &&
+ mPhysicalCamAvailable == other.mPhysicalCamAvailable &&
+ mPhysicalCamUnavailable == other.mPhysicalCamUnavailable &&
mContext == other.mContext);
}
bool operator != (const Callback& other) const {
@@ -119,6 +138,12 @@
if (*this == other) return false;
if (mContext != other.mContext) return mContext < other.mContext;
if (mAvailable != other.mAvailable) return mAvailable < other.mAvailable;
+ if (mAccessPriorityChanged != other.mAccessPriorityChanged)
+ return mAccessPriorityChanged < other.mAccessPriorityChanged;
+ if (mPhysicalCamAvailable != other.mPhysicalCamAvailable)
+ return mPhysicalCamAvailable < other.mPhysicalCamAvailable;
+ if (mPhysicalCamUnavailable != other.mPhysicalCamUnavailable)
+ return mPhysicalCamUnavailable < other.mPhysicalCamUnavailable;
return mUnavailable < other.mUnavailable;
}
bool operator > (const Callback& other) const {
@@ -126,15 +151,20 @@
}
ACameraManager_AvailabilityCallback mAvailable;
ACameraManager_AvailabilityCallback mUnavailable;
+ ACameraManager_AccessPrioritiesChangedCallback mAccessPriorityChanged;
+ ACameraManager_PhysicalCameraAvailabilityCallback mPhysicalCamAvailable;
+ ACameraManager_PhysicalCameraAvailabilityCallback mPhysicalCamUnavailable;
void* mContext;
};
std::set<Callback> mCallbacks;
// definition of handler and message
enum {
- kWhatSendSingleCallback
+ kWhatSendSingleCallback,
+ kWhatSendSinglePhysicalCameraCallback,
};
static const char* kCameraIdKey;
+ static const char* kPhysicalCameraIdKey;
static const char* kCallbackFpKey;
static const char* kContextKey;
class CallbackHandler : public AHandler {
@@ -147,6 +177,8 @@
void onStatusChanged(const CameraStatusAndId &statusAndId);
void onStatusChangedLocked(const CameraStatusAndId &statusAndId);
+ void onStatusChanged(const PhysicalCameraStatusAndId &statusAndId);
+ void onStatusChangedLocked(const PhysicalCameraStatusAndId &statusAndId);
bool setupVendorTags();
// Utils for status
@@ -174,8 +206,27 @@
}
};
+ struct CameraStatus {
+ private:
+ CameraDeviceStatus status = CameraDeviceStatus::STATUS_NOT_PRESENT;
+ mutable std::mutex mLock;
+ std::set<hidl_string> unavailablePhysicalIds;
+ public:
+ CameraStatus(CameraDeviceStatus st): status(st) { };
+ CameraStatus() = default;
+
+ bool addUnavailablePhysicalId(const hidl_string& physicalCameraId);
+ bool removeUnavailablePhysicalId(const hidl_string& physicalCameraId);
+ CameraDeviceStatus getStatus();
+ void updateStatus(CameraDeviceStatus newStatus);
+ std::set<hidl_string> getUnavailablePhysicalIds();
+ };
+
+ template <class T>
+ void registerAvailCallback(const T *callback);
+
// Map camera_id -> status
- std::map<hidl_string, CameraDeviceStatus, CameraIdComparator> mDeviceStatusMap;
+ std::map<hidl_string, CameraStatus, CameraIdComparator> mDeviceStatusMap;
// For the singleton instance
static Mutex sLock;
diff --git a/camera/ndk/ndk_vendor/tests/ACameraManagerTest.cpp b/camera/ndk/ndk_vendor/tests/ACameraManagerTest.cpp
new file mode 100644
index 0000000..a20a290
--- /dev/null
+++ b/camera/ndk/ndk_vendor/tests/ACameraManagerTest.cpp
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ACameraManagerTest"
+//#define LOG_NDEBUG 0
+
+#include <gtest/gtest.h>
+
+#include <mutex>
+#include <set>
+#include <string>
+
+#include <utils/Log.h>
+#include <camera/NdkCameraError.h>
+#include <camera/NdkCameraManager.h>
+
+namespace {
+
+class CameraServiceListener {
+ public:
+ typedef std::set<std::pair<std::string, std::string>> StringPairSet;
+
+ static void onAvailable(void* obj, const char* cameraId) {
+ ALOGV("Camera %s onAvailable", cameraId);
+ if (obj == nullptr) {
+ return;
+ }
+ CameraServiceListener* thiz = reinterpret_cast<CameraServiceListener*>(obj);
+ std::lock_guard<std::mutex> lock(thiz->mMutex);
+ thiz->mOnAvailableCount++;
+ thiz->mAvailableMap[cameraId] = true;
+ return;
+ }
+
+ static void onUnavailable(void* obj, const char* cameraId) {
+ ALOGV("Camera %s onUnavailable", cameraId);
+ if (obj == nullptr) {
+ return;
+ }
+ CameraServiceListener* thiz = reinterpret_cast<CameraServiceListener*>(obj);
+ std::lock_guard<std::mutex> lock(thiz->mMutex);
+ thiz->mOnUnavailableCount++;
+ thiz->mAvailableMap[cameraId] = false;
+ return;
+ }
+
+ static void onCameraAccessPrioritiesChanged(void* /*obj*/) {
+ return;
+ }
+
+ static void onPhysicalCameraAvailable(void* obj, const char* cameraId,
+ const char* physicalCameraId) {
+ ALOGV("Camera %s : %s onAvailable", cameraId, physicalCameraId);
+ if (obj == nullptr) {
+ return;
+ }
+ CameraServiceListener* thiz = reinterpret_cast<CameraServiceListener*>(obj);
+ std::lock_guard<std::mutex> lock(thiz->mMutex);
+ thiz->mOnPhysicalCameraAvailableCount++;
+ return;
+ }
+
+ static void onPhysicalCameraUnavailable(void* obj, const char* cameraId,
+ const char* physicalCameraId) {
+ ALOGV("Camera %s : %s onUnavailable", cameraId, physicalCameraId);
+ if (obj == nullptr) {
+ return;
+ }
+ CameraServiceListener* thiz = reinterpret_cast<CameraServiceListener*>(obj);
+ std::lock_guard<std::mutex> lock(thiz->mMutex);
+ thiz->mUnavailablePhysicalCameras.emplace(cameraId, physicalCameraId);
+ return;
+ }
+
+ void resetCount() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mOnAvailableCount = 0;
+ mOnUnavailableCount = 0;
+ mOnPhysicalCameraAvailableCount = 0;
+ mUnavailablePhysicalCameras.clear();
+ return;
+ }
+
+ int getAvailableCount() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mOnAvailableCount;
+ }
+
+ int getUnavailableCount() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mOnUnavailableCount;
+ }
+
+ int getPhysicalCameraAvailableCount() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mOnPhysicalCameraAvailableCount;
+ }
+
+ StringPairSet getUnavailablePhysicalCameras() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mUnavailablePhysicalCameras;
+ }
+
+ bool isAvailable(const char* cameraId) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mAvailableMap.count(cameraId) == 0) {
+ return false;
+ }
+ return mAvailableMap[cameraId];
+ }
+
+ private:
+ std::mutex mMutex;
+ int mOnAvailableCount = 0;
+ int mOnUnavailableCount = 0;
+ int mOnPhysicalCameraAvailableCount = 0;
+ std::map<std::string, bool> mAvailableMap;
+ StringPairSet mUnavailablePhysicalCameras;
+};
+
+class ACameraManagerTest : public ::testing::Test {
+ public:
+ void SetUp() override {
+ mCameraManager = ACameraManager_create();
+ if (mCameraManager == nullptr) {
+ ALOGE("Failed to create ACameraManager.");
+ return;
+ }
+
+ camera_status_t ret = ACameraManager_getCameraIdList(mCameraManager, &mCameraIdList);
+ if (ret != ACAMERA_OK) {
+ ALOGE("Failed to get cameraIdList: ret=%d", ret);
+ return;
+ }
+ if (mCameraIdList->numCameras < 1) {
+ ALOGW("Device has no camera on board.");
+ return;
+ }
+ }
+ void TearDown() override {
+ // Destroy camera manager
+ if (mCameraIdList) {
+ ACameraManager_deleteCameraIdList(mCameraIdList);
+ mCameraIdList = nullptr;
+ }
+ if (mCameraManager) {
+ ACameraManager_delete(mCameraManager);
+ mCameraManager = nullptr;
+ }
+ }
+
+ // Camera manager
+ ACameraManager* mCameraManager = nullptr;
+ ACameraIdList* mCameraIdList = nullptr;
+ CameraServiceListener mAvailabilityListener;
+ ACameraManager_ExtendedAvailabilityCallbacks mCbs = {
+ {
+ &mAvailabilityListener,
+ CameraServiceListener::onAvailable,
+ CameraServiceListener::onUnavailable
+ },
+ CameraServiceListener::onCameraAccessPrioritiesChanged,
+ CameraServiceListener::onPhysicalCameraAvailable,
+ CameraServiceListener::onPhysicalCameraUnavailable,
+ {}
+ };
+};
+
+TEST_F(ACameraManagerTest, testCameraManagerExtendedAvailabilityCallbacks) {
+ camera_status_t ret = ACameraManager_registerExtendedAvailabilityCallback(mCameraManager,
+ &mCbs);
+ ASSERT_EQ(ret, ACAMERA_OK);
+
+ sleep(1);
+
+ // Should at least get onAvailable for each camera once
+ ASSERT_EQ(mAvailabilityListener.getAvailableCount(), mCameraIdList->numCameras);
+
+ // Expect no available callbacks for physical cameras
+ int availablePhysicalCamera = mAvailabilityListener.getPhysicalCameraAvailableCount();
+ ASSERT_EQ(availablePhysicalCamera, 0);
+
+ CameraServiceListener::StringPairSet unavailablePhysicalCameras;
+ CameraServiceListener::StringPairSet physicalCameraIdPairs;
+
+ unavailablePhysicalCameras = mAvailabilityListener.getUnavailablePhysicalCameras();
+ for (int i = 0; i < mCameraIdList->numCameras; i++) {
+ const char* cameraId = mCameraIdList->cameraIds[i];
+ ASSERT_NE(cameraId, nullptr);
+ ASSERT_TRUE(mAvailabilityListener.isAvailable(cameraId));
+
+ ACameraMetadata* chars = nullptr;
+ ret = ACameraManager_getCameraCharacteristics(mCameraManager, cameraId, &chars);
+ ASSERT_EQ(ret, ACAMERA_OK);
+ ASSERT_NE(chars, nullptr);
+
+ size_t physicalCameraCnt = 0;
+ const char *const* physicalCameraIds = nullptr;
+ if (!ACameraMetadata_isLogicalMultiCamera(
+ chars, &physicalCameraCnt, &physicalCameraIds)) {
+ ACameraMetadata_free(chars);
+ continue;
+ }
+ for (size_t j = 0; j < physicalCameraCnt; j++) {
+ physicalCameraIdPairs.emplace(cameraId, physicalCameraIds[j]);
+ }
+ ACameraMetadata_free(chars);
+ }
+ for (const auto& unavailIdPair : unavailablePhysicalCameras) {
+ bool validPair = false;
+ for (const auto& idPair : physicalCameraIdPairs) {
+ if (idPair.first == unavailIdPair.first && idPair.second == unavailIdPair.second) {
+ validPair = true;
+ break;
+ }
+ }
+ // Expect valid unavailable physical cameras
+ ASSERT_TRUE(validPair);
+ }
+
+ ret = ACameraManager_unregisterExtendedAvailabilityCallback(mCameraManager, &mCbs);
+ ASSERT_EQ(ret, ACAMERA_OK);
+}
+
+} // namespace
diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp
index dc5afc5..8ccded2 100644
--- a/camera/tests/CameraBinderTests.cpp
+++ b/camera/tests/CameraBinderTests.cpp
@@ -57,7 +57,7 @@
#include <algorithm>
using namespace android;
-using ::android::hardware::ICameraServiceDefault;
+using ::android::hardware::ICameraService;
using ::android::hardware::camera2::ICameraDeviceUser;
#define ASSERT_NOT_NULL(x) \
@@ -83,6 +83,12 @@
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) {
Mutex::Autolock l(mLock);
mCameraTorchStatuses[cameraId] = status;
@@ -372,7 +378,8 @@
sp<TestCameraDeviceCallbacks> callbacks(new TestCameraDeviceCallbacks());
sp<hardware::camera2::ICameraDeviceUser> device;
res = service->connectDevice(callbacks, cameraId, String16("meeeeeeeee!"),
- hardware::ICameraService::USE_CALLING_UID, /*out*/&device);
+ std::unique_ptr<String16>(), hardware::ICameraService::USE_CALLING_UID,
+ /*out*/&device);
EXPECT_TRUE(res.isOk()) << res;
ASSERT_NE(nullptr, device.get());
device->disconnect();
@@ -414,7 +421,8 @@
{
SCOPED_TRACE("openNewDevice");
binder::Status res = service->connectDevice(callbacks, deviceId, String16("meeeeeeeee!"),
- hardware::ICameraService::USE_CALLING_UID, /*out*/&device);
+ std::unique_ptr<String16>(), hardware::ICameraService::USE_CALLING_UID,
+ /*out*/&device);
EXPECT_TRUE(res.isOk()) << res;
}
auto p = std::make_pair(callbacks, device);
@@ -507,7 +515,9 @@
EXPECT_TRUE(res.isOk()) << res;
EXPECT_LE(0, streamId);
CameraMetadata sessionParams;
- res = device->endConfigure(/*isConstrainedHighSpeed*/ false, sessionParams);
+ std::vector<int> offlineStreamIds;
+ res = device->endConfigure(/*isConstrainedHighSpeed*/ false, sessionParams,
+ &offlineStreamIds);
EXPECT_TRUE(res.isOk()) << res;
EXPECT_FALSE(callbacks->hadError());
@@ -518,7 +528,7 @@
bool queryStatus;
res = device->isSessionConfigurationSupported(sessionConfiguration, &queryStatus);
EXPECT_TRUE(res.isOk() ||
- (res.serviceSpecificErrorCode() == ICameraServiceDefault::ERROR_INVALID_OPERATION))
+ (res.serviceSpecificErrorCode() == ICameraService::ERROR_INVALID_OPERATION))
<< res;
if (res.isOk()) {
EXPECT_TRUE(queryStatus);
@@ -618,7 +628,8 @@
EXPECT_TRUE(res.isOk()) << res;
res = device->deleteStream(streamId);
EXPECT_TRUE(res.isOk()) << res;
- res = device->endConfigure(/*isConstrainedHighSpeed*/ false, sessionParams);
+ res = device->endConfigure(/*isConstrainedHighSpeed*/ false, sessionParams,
+ &offlineStreamIds);
EXPECT_TRUE(res.isOk()) << res;
sleep(/*second*/1); // allow some time for errors to show up, if any
diff --git a/cmds/screenrecord/Android.bp b/cmds/screenrecord/Android.bp
index 86476cd..d7d905f 100644
--- a/cmds/screenrecord/Android.bp
+++ b/cmds/screenrecord/Android.bp
@@ -24,9 +24,15 @@
"Program.cpp",
],
+ header_libs: [
+ "libmediadrm_headers",
+ "libmediametrics_headers",
+ ],
+
shared_libs: [
"libstagefright",
"libmedia",
+ "libmediandk",
"libmedia_omx",
"libutils",
"libbinder",
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index 7aa655f..f4fb626 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -37,23 +37,28 @@
#include <binder/IPCThreadState.h>
#include <utils/Errors.h>
+#include <utils/SystemClock.h>
#include <utils/Timers.h>
#include <utils/Trace.h>
+#include <gui/ISurfaceComposer.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/ISurfaceComposer.h>
-#include <ui/DisplayInfo.h>
+#include <media/MediaCodecBuffer.h>
+#include <media/NdkMediaCodec.h>
+#include <media/NdkMediaFormatPriv.h>
+#include <media/NdkMediaMuxer.h>
#include <media/openmax/OMX_IVCommon.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaCodec.h>
#include <media/stagefright/MediaCodecConstants.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaMuxer.h>
#include <media/stagefright/PersistentSurface.h>
-#include <media/ICrypto.h>
-#include <media/MediaCodecBuffer.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <mediadrm/ICrypto.h>
+#include <ui/DisplayConfig.h>
+#include <ui/DisplayState.h>
#include "screenrecord.h"
#include "Overlay.h"
@@ -63,16 +68,16 @@
using android::ALooper;
using android::AMessage;
using android::AString;
-using android::DisplayInfo;
+using android::DisplayConfig;
using android::FrameOutput;
using android::IBinder;
using android::IGraphicBufferProducer;
using android::ISurfaceComposer;
using android::MediaCodec;
using android::MediaCodecBuffer;
-using android::MediaMuxer;
using android::Overlay;
using android::PersistentSurface;
+using android::PhysicalDisplayId;
using android::ProcessState;
using android::Rect;
using android::String8;
@@ -81,20 +86,21 @@
using android::sp;
using android::status_t;
-using android::DISPLAY_ORIENTATION_0;
-using android::DISPLAY_ORIENTATION_180;
-using android::DISPLAY_ORIENTATION_90;
using android::INVALID_OPERATION;
using android::NAME_NOT_FOUND;
using android::NO_ERROR;
using android::UNKNOWN_ERROR;
+namespace ui = android::ui;
+
static const uint32_t kMinBitRate = 100000; // 0.1Mbps
static const uint32_t kMaxBitRate = 200 * 1000000; // 200Mbps
static const uint32_t kMaxTimeLimitSec = 180; // 3 minutes
static const uint32_t kFallbackWidth = 1280; // 720p
static const uint32_t kFallbackHeight = 720;
static const char* kMimeTypeAvc = "video/avc";
+static const char* kMimeTypeApplicationOctetstream = "application/octet-stream";
+static const char* kWinscopeMagicString = "#VV1NSC0PET1ME!#";
// Command-line parameters.
static bool gVerbose = false; // chatty on stdout
@@ -113,7 +119,7 @@
static uint32_t gBitRate = 20000000; // 20Mbps
static uint32_t gTimeLimitSec = kMaxTimeLimitSec;
static uint32_t gBframes = 0;
-
+static PhysicalDisplayId gPhysicalDisplayId;
// Set by signal handler to stop recording.
static volatile bool gStopRequested = false;
@@ -266,14 +272,15 @@
static status_t setDisplayProjection(
SurfaceComposerClient::Transaction& t,
const sp<IBinder>& dpy,
- const DisplayInfo& mainDpyInfo) {
+ const ui::DisplayState& displayState) {
+ const ui::Size& viewport = displayState.viewport;
// Set the region of the layer stack we're interested in, which in our
// case is "all of it".
- Rect layerStackRect(mainDpyInfo.viewportW, mainDpyInfo.viewportH);
+ Rect layerStackRect(viewport);
// We need to preserve the aspect ratio of the display.
- float displayAspect = (float) mainDpyInfo.viewportH / (float) mainDpyInfo.viewportW;
+ float displayAspect = viewport.getHeight() / static_cast<float>(viewport.getWidth());
// Set the way we map the output onto the display surface (which will
@@ -323,7 +330,7 @@
}
t.setDisplayProjection(dpy,
- gRotate ? DISPLAY_ORIENTATION_90 : DISPLAY_ORIENTATION_0,
+ gRotate ? ui::ROTATION_90 : ui::ROTATION_0,
layerStackRect, displayRect);
return NO_ERROR;
}
@@ -332,16 +339,16 @@
* Configures the virtual display. When this completes, virtual display
* frames will start arriving from the buffer producer.
*/
-static status_t prepareVirtualDisplay(const DisplayInfo& mainDpyInfo,
+static status_t prepareVirtualDisplay(
+ const ui::DisplayState& displayState,
const sp<IGraphicBufferProducer>& bufferProducer,
sp<IBinder>* pDisplayHandle) {
sp<IBinder> dpy = SurfaceComposerClient::createDisplay(
String8("ScreenRecorder"), false /*secure*/);
-
SurfaceComposerClient::Transaction t;
t.setDisplaySurface(dpy, bufferProducer);
- setDisplayProjection(t, dpy, mainDpyInfo);
- t.setDisplayLayerStack(dpy, 0); // default stack
+ setDisplayProjection(t, dpy, displayState);
+ t.setDisplayLayerStack(dpy, displayState.layerStack);
t.apply();
*pDisplayHandle = dpy;
@@ -350,6 +357,56 @@
}
/*
+ * Writes an unsigned integer byte-by-byte in little endian order regardless
+ * of the platform endianness.
+ */
+template <typename UINT>
+static void writeValueLE(UINT value, uint8_t* buffer) {
+ for (int i = 0; i < sizeof(UINT); ++i) {
+ buffer[i] = static_cast<uint8_t>(value);
+ value >>= 8;
+ }
+}
+
+/*
+ * Saves frames presentation time relative to the elapsed realtime clock in microseconds
+ * preceded by a Winscope magic string and frame count to a metadata track.
+ * This metadata is used by the Winscope tool to sync video with SurfaceFlinger
+ * and WindowManager traces.
+ *
+ * The metadata is written as a binary array as follows:
+ * - winscope magic string (kWinscopeMagicString constant), without trailing null char,
+ * - the number of recorded frames (as little endian uint32),
+ * - for every frame its presentation time relative to the elapsed realtime clock in microseconds
+ * (as little endian uint64).
+ */
+static status_t writeWinscopeMetadata(const Vector<int64_t>& timestamps,
+ const ssize_t metaTrackIdx, AMediaMuxer *muxer) {
+ ALOGV("Writing metadata");
+ int64_t systemTimeToElapsedTimeOffsetMicros = (android::elapsedRealtimeNano()
+ - systemTime(SYSTEM_TIME_MONOTONIC)) / 1000;
+ sp<ABuffer> buffer = new ABuffer(timestamps.size() * sizeof(int64_t)
+ + sizeof(uint32_t) + strlen(kWinscopeMagicString));
+ uint8_t* pos = buffer->data();
+ strcpy(reinterpret_cast<char*>(pos), kWinscopeMagicString);
+ pos += strlen(kWinscopeMagicString);
+ writeValueLE<uint32_t>(timestamps.size(), pos);
+ pos += sizeof(uint32_t);
+ for (size_t idx = 0; idx < timestamps.size(); ++idx) {
+ writeValueLE<uint64_t>(static_cast<uint64_t>(timestamps[idx]
+ + systemTimeToElapsedTimeOffsetMicros), pos);
+ pos += sizeof(uint64_t);
+ }
+ AMediaCodecBufferInfo bufferInfo = {
+ 0,
+ static_cast<int32_t>(buffer->size()),
+ timestamps[0],
+ 0
+ };
+ return AMediaMuxer_writeSampleData(muxer, metaTrackIdx, buffer->data(), &bufferInfo);
+}
+
+/*
* Runs the MediaCodec encoder, sending the output to the MediaMuxer. The
* input frames are coming from the virtual display as fast as SurfaceFlinger
* wants to send them.
@@ -359,15 +416,17 @@
* The muxer must *not* have been started before calling.
*/
static status_t runEncoder(const sp<MediaCodec>& encoder,
- const sp<MediaMuxer>& muxer, FILE* rawFp, const sp<IBinder>& mainDpy,
- const sp<IBinder>& virtualDpy, uint8_t orientation) {
+ AMediaMuxer *muxer, FILE* rawFp, const sp<IBinder>& display,
+ const sp<IBinder>& virtualDpy, ui::Rotation orientation) {
static int kTimeout = 250000; // be responsive on signal
status_t err;
ssize_t trackIdx = -1;
+ ssize_t metaTrackIdx = -1;
uint32_t debugNumFrames = 0;
int64_t startWhenNsec = systemTime(CLOCK_MONOTONIC);
int64_t endWhenNsec = startWhenNsec + seconds_to_nanoseconds(gTimeLimitSec);
- DisplayInfo mainDpyInfo;
+ Vector<int64_t> timestamps;
+ bool firstFrame = true;
assert((rawFp == NULL && muxer != NULL) || (rawFp != NULL && muxer == NULL));
@@ -384,6 +443,11 @@
int64_t ptsUsec;
uint32_t flags;
+ if (firstFrame) {
+ ATRACE_NAME("first_frame");
+ firstFrame = false;
+ }
+
if (systemTime(CLOCK_MONOTONIC) > endWhenNsec) {
if (gVerbose) {
printf("Time limit reached\n");
@@ -417,16 +481,16 @@
//
// Polling for changes is inefficient and wrong, but the
// useful stuff is hard to get at without a Dalvik VM.
- err = SurfaceComposerClient::getDisplayInfo(mainDpy,
- &mainDpyInfo);
+ ui::DisplayState displayState;
+ err = SurfaceComposerClient::getDisplayState(display, &displayState);
if (err != NO_ERROR) {
- ALOGW("getDisplayInfo(main) failed: %d", err);
- } else if (orientation != mainDpyInfo.orientation) {
- ALOGD("orientation changed, now %d", mainDpyInfo.orientation);
+ ALOGW("getDisplayState() failed: %d", err);
+ } else if (orientation != displayState.orientation) {
+ ALOGD("orientation changed, now %s", toCString(displayState.orientation));
SurfaceComposerClient::Transaction t;
- setDisplayProjection(t, virtualDpy, mainDpyInfo);
+ setDisplayProjection(t, virtualDpy, displayState);
t.apply();
- orientation = mainDpyInfo.orientation;
+ orientation = displayState.orientation;
}
}
@@ -458,13 +522,21 @@
// TODO
sp<ABuffer> buffer = new ABuffer(
buffers[bufIndex]->data(), buffers[bufIndex]->size());
- err = muxer->writeSampleData(buffer, trackIdx,
- ptsUsec, flags);
+ AMediaCodecBufferInfo bufferInfo = {
+ 0,
+ static_cast<int32_t>(buffer->size()),
+ ptsUsec,
+ flags
+ };
+ err = AMediaMuxer_writeSampleData(muxer, trackIdx, buffer->data(), &bufferInfo);
if (err != NO_ERROR) {
fprintf(stderr,
"Failed writing data to muxer (err=%d)\n", err);
return err;
}
+ if (gOutputFormat == FORMAT_MP4) {
+ timestamps.add(ptsUsec);
+ }
}
debugNumFrames++;
}
@@ -489,10 +561,18 @@
ALOGV("Encoder format changed");
sp<AMessage> newFormat;
encoder->getOutputFormat(&newFormat);
+ // TODO remove when MediaCodec has been replaced with AMediaCodec
+ AMediaFormat *ndkFormat = AMediaFormat_fromMsg(&newFormat);
if (muxer != NULL) {
- trackIdx = muxer->addTrack(newFormat);
+ trackIdx = AMediaMuxer_addTrack(muxer, ndkFormat);
+ if (gOutputFormat == FORMAT_MP4) {
+ AMediaFormat *metaFormat = AMediaFormat_new();
+ AMediaFormat_setString(metaFormat, AMEDIAFORMAT_KEY_MIME, kMimeTypeApplicationOctetstream);
+ metaTrackIdx = AMediaMuxer_addTrack(muxer, metaFormat);
+ AMediaFormat_delete(metaFormat);
+ }
ALOGV("Starting muxer");
- err = muxer->start();
+ err = AMediaMuxer_start(muxer);
if (err != NO_ERROR) {
fprintf(stderr, "Unable to start muxer (err=%d)\n", err);
return err;
@@ -527,6 +607,13 @@
systemTime(CLOCK_MONOTONIC) - startWhenNsec));
fflush(stdout);
}
+ if (metaTrackIdx >= 0 && !timestamps.isEmpty()) {
+ err = writeWinscopeMetadata(timestamps, metaTrackIdx, muxer);
+ if (err != NO_ERROR) {
+ fprintf(stderr, "Failed writing metadata to muxer (err=%d)\n", err);
+ return err;
+ }
+ }
return NO_ERROR;
}
@@ -591,32 +678,41 @@
self->startThreadPool();
// Get main display parameters.
- const sp<IBinder> mainDpy = SurfaceComposerClient::getInternalDisplayToken();
- if (mainDpy == nullptr) {
+ sp<IBinder> display = SurfaceComposerClient::getPhysicalDisplayToken(
+ gPhysicalDisplayId);
+ if (display == nullptr) {
fprintf(stderr, "ERROR: no display\n");
return NAME_NOT_FOUND;
}
- DisplayInfo mainDpyInfo;
- err = SurfaceComposerClient::getDisplayInfo(mainDpy, &mainDpyInfo);
+ ui::DisplayState displayState;
+ err = SurfaceComposerClient::getDisplayState(display, &displayState);
if (err != NO_ERROR) {
- fprintf(stderr, "ERROR: unable to get display characteristics\n");
+ fprintf(stderr, "ERROR: unable to get display state\n");
return err;
}
+ DisplayConfig displayConfig;
+ err = SurfaceComposerClient::getActiveDisplayConfig(display, &displayConfig);
+ if (err != NO_ERROR) {
+ fprintf(stderr, "ERROR: unable to get display config\n");
+ return err;
+ }
+
+ const ui::Size& viewport = displayState.viewport;
if (gVerbose) {
- printf("Main display is %dx%d @%.2ffps (orientation=%u)\n",
- mainDpyInfo.viewportW, mainDpyInfo.viewportH, mainDpyInfo.fps,
- mainDpyInfo.orientation);
+ printf("Display is %dx%d @%.2ffps (orientation=%s), layerStack=%u\n",
+ viewport.getWidth(), viewport.getHeight(), displayConfig.refreshRate,
+ toCString(displayState.orientation), displayState.layerStack);
fflush(stdout);
}
// Encoder can't take odd number as config
if (gVideoWidth == 0) {
- gVideoWidth = floorToEven(mainDpyInfo.viewportW);
+ gVideoWidth = floorToEven(viewport.getWidth());
}
if (gVideoHeight == 0) {
- gVideoHeight = floorToEven(mainDpyInfo.viewportH);
+ gVideoHeight = floorToEven(viewport.getHeight());
}
// Configure and start the encoder.
@@ -624,7 +720,7 @@
sp<FrameOutput> frameOutput;
sp<IGraphicBufferProducer> encoderInputSurface;
if (gOutputFormat != FORMAT_FRAMES && gOutputFormat != FORMAT_RAW_FRAMES) {
- err = prepareEncoder(mainDpyInfo.fps, &encoder, &encoderInputSurface);
+ err = prepareEncoder(displayConfig.refreshRate, &encoder, &encoderInputSurface);
if (err != NO_ERROR && !gSizeSpecified) {
// fallback is defined for landscape; swap if we're in portrait
@@ -637,8 +733,7 @@
gVideoWidth, gVideoHeight, newWidth, newHeight);
gVideoWidth = newWidth;
gVideoHeight = newHeight;
- err = prepareEncoder(mainDpyInfo.fps, &encoder,
- &encoderInputSurface);
+ err = prepareEncoder(displayConfig.refreshRate, &encoder, &encoderInputSurface);
}
}
if (err != NO_ERROR) return err;
@@ -685,13 +780,13 @@
// Configure virtual display.
sp<IBinder> dpy;
- err = prepareVirtualDisplay(mainDpyInfo, bufferProducer, &dpy);
+ err = prepareVirtualDisplay(displayState, bufferProducer, &dpy);
if (err != NO_ERROR) {
if (encoder != NULL) encoder->release();
return err;
}
- sp<MediaMuxer> muxer = NULL;
+ AMediaMuxer *muxer = nullptr;
FILE* rawFp = NULL;
switch (gOutputFormat) {
case FORMAT_MP4:
@@ -710,15 +805,15 @@
abort();
}
if (gOutputFormat == FORMAT_MP4) {
- muxer = new MediaMuxer(fd, MediaMuxer::OUTPUT_FORMAT_MPEG_4);
+ muxer = AMediaMuxer_new(fd, AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4);
} else if (gOutputFormat == FORMAT_WEBM) {
- muxer = new MediaMuxer(fd, MediaMuxer::OUTPUT_FORMAT_WEBM);
+ muxer = AMediaMuxer_new(fd, AMEDIAMUXER_OUTPUT_FORMAT_WEBM);
} else {
- muxer = new MediaMuxer(fd, MediaMuxer::OUTPUT_FORMAT_THREE_GPP);
+ muxer = AMediaMuxer_new(fd, AMEDIAMUXER_OUTPUT_FORMAT_THREE_GPP);
}
close(fd);
if (gRotate) {
- muxer->setOrientationHint(90); // TODO: does this do anything?
+ AMediaMuxer_setOrientationHint(muxer, 90); // TODO: does this do anything?
}
break;
}
@@ -768,8 +863,7 @@
}
} else {
// Main encoder loop.
- err = runEncoder(encoder, muxer, rawFp, mainDpy, dpy,
- mainDpyInfo.orientation);
+ err = runEncoder(encoder, muxer, rawFp, display, dpy, displayState.orientation);
if (err != NO_ERROR) {
fprintf(stderr, "Encoder failed (err=%d)\n", err);
// fall through to cleanup
@@ -789,7 +883,7 @@
if (muxer != NULL) {
// If we don't stop muxer explicitly, i.e. let the destructor run,
// it may hang (b/11050628).
- err = muxer->stop();
+ err = AMediaMuxer_stop(muxer);
} else if (rawFp != stdout) {
fclose(rawFp);
}
@@ -935,6 +1029,9 @@
" in videos captured to illustrate bugs.\n"
"--time-limit TIME\n"
" Set the maximum recording time, in seconds. Default / maximum is %d.\n"
+ "--display-id ID\n"
+ " specify the physical display ID to record. Default is the primary display.\n"
+ " see \"dumpsys SurfaceFlinger --display-id\" for valid display IDs.\n"
"--verbose\n"
" Display interesting information on stdout.\n"
"--help\n"
@@ -966,9 +1063,18 @@
{ "monotonic-time", no_argument, NULL, 'm' },
{ "persistent-surface", no_argument, NULL, 'p' },
{ "bframes", required_argument, NULL, 'B' },
+ { "display-id", required_argument, NULL, 'd' },
{ NULL, 0, NULL, 0 }
};
+ std::optional<PhysicalDisplayId> displayId = SurfaceComposerClient::getInternalDisplayId();
+ if (!displayId) {
+ fprintf(stderr, "Failed to get token for internal display\n");
+ return 1;
+ }
+
+ gPhysicalDisplayId = *displayId;
+
while (true) {
int optionIndex = 0;
int ic = getopt_long(argc, argv, "", longOptions, &optionIndex);
@@ -1063,6 +1169,18 @@
return 2;
}
break;
+ case 'd':
+ gPhysicalDisplayId = atoll(optarg);
+ if (gPhysicalDisplayId == 0) {
+ fprintf(stderr, "Please specify a valid physical display id\n");
+ return 2;
+ } else if (SurfaceComposerClient::
+ getPhysicalDisplayToken(gPhysicalDisplayId) == nullptr) {
+ fprintf(stderr, "Invalid physical display id: %"
+ ANDROID_PHYSICAL_DISPLAY_ID_FORMAT "\n", gPhysicalDisplayId);
+ return 2;
+ }
+ break;
default:
if (ic != '?') {
fprintf(stderr, "getopt_long returned unexpected value 0x%x\n", ic);
diff --git a/cmds/screenrecord/screenrecord.h b/cmds/screenrecord/screenrecord.h
index 9b058c2..cec7c13 100644
--- a/cmds/screenrecord/screenrecord.h
+++ b/cmds/screenrecord/screenrecord.h
@@ -18,6 +18,6 @@
#define SCREENRECORD_SCREENRECORD_H
#define kVersionMajor 1
-#define kVersionMinor 2
+#define kVersionMinor 3
#endif /*SCREENRECORD_SCREENRECORD_H*/
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 6eb2e9f..6470fb1 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -3,26 +3,30 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ AudioPlayer.cpp \
stagefright.cpp \
jpeg.cpp \
SineSource.cpp
+LOCAL_HEADER_LIBRARIES := \
+ libmediametrics_headers \
+
LOCAL_SHARED_LIBRARIES := \
- libstagefright libmedia libmedia_omx libutils libbinder \
+ libstagefright libmedia libmedia_codeclist libutils libbinder \
libstagefright_foundation libjpeg libui libgui libcutils liblog \
- libhidlbase \
+ libhidlbase libdatasource libaudioclient \
android.hardware.media.omx@1.0 \
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
frameworks/av/media/libstagefright/include \
frameworks/native/include/media/openmax \
- external/jpeg \
LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
LOCAL_MODULE_TAGS := optional
+LOCAL_SYSTEM_EXT_MODULE:= true
LOCAL_MODULE:= stagefright
include $(BUILD_EXECUTABLE)
@@ -32,14 +36,19 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ AudioPlayer.cpp \
SineSource.cpp \
record.cpp
+LOCAL_HEADER_LIBRARIES := \
+ libmediametrics_headers \
+
LOCAL_SHARED_LIBRARIES := \
libstagefright libmedia liblog libutils libbinder \
- libstagefright_foundation
+ libstagefright_foundation libdatasource libaudioclient
LOCAL_C_INCLUDES:= \
+ frameworks/av/camera/include \
frameworks/av/media/libstagefright \
frameworks/native/include/media/openmax \
frameworks/native/include/media/hardware
@@ -57,12 +66,15 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- SineSource.cpp \
+ AudioPlayer.cpp \
recordvideo.cpp
+LOCAL_HEADER_LIBRARIES := \
+ libmediametrics_headers \
+
LOCAL_SHARED_LIBRARIES := \
libstagefright libmedia liblog libutils libbinder \
- libstagefright_foundation
+ libstagefright_foundation libaudioclient
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
@@ -83,12 +95,16 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ AudioPlayer.cpp \
SineSource.cpp \
audioloop.cpp
+LOCAL_HEADER_LIBRARIES := \
+ libmediametrics_headers \
+
LOCAL_SHARED_LIBRARIES := \
libstagefright libmedia liblog libutils libbinder \
- libstagefright_foundation
+ libstagefright_foundation libaudioclient
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
@@ -109,9 +125,12 @@
LOCAL_SRC_FILES:= \
stream.cpp \
+LOCAL_HEADER_LIBRARIES := \
+ libmediametrics_headers \
+
LOCAL_SHARED_LIBRARIES := \
libstagefright liblog libutils libbinder libui libgui \
- libstagefright_foundation libmedia libcutils
+ libstagefright_foundation libmedia libcutils libdatasource
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
@@ -133,6 +152,10 @@
codec.cpp \
SimplePlayer.cpp \
+LOCAL_HEADER_LIBRARIES := \
+ libmediadrm_headers \
+ libmediametrics_headers \
+
LOCAL_SHARED_LIBRARIES := \
libstagefright liblog libutils libbinder libstagefright_foundation \
libmedia libmedia_omx libaudioclient libui libgui libcutils
@@ -154,22 +177,24 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- filters/argbtorgba.rs \
- filters/nightvision.rs \
- filters/saturation.rs \
+ filters/argbtorgba.rscript \
+ filters/nightvision.rscript \
+ filters/saturation.rscript \
mediafilter.cpp \
+LOCAL_HEADER_LIBRARIES := \
+ libmediadrm_headers \
+ libmediametrics_headers \
+
LOCAL_SHARED_LIBRARIES := \
libstagefright \
liblog \
libutils \
libbinder \
libstagefright_foundation \
- libmedia \
libmedia_omx \
libui \
libgui \
- libcutils \
libRScpp \
LOCAL_C_INCLUDES:= \
@@ -201,6 +226,9 @@
LOCAL_SRC_FILES:= \
muxer.cpp \
+LOCAL_HEADER_LIBRARIES := \
+ libmediametrics_headers \
+
LOCAL_SHARED_LIBRARIES := \
libstagefright liblog libutils libbinder libstagefright_foundation \
libcutils libc
diff --git a/cmds/stagefright/AudioPlayer.cpp b/cmds/stagefright/AudioPlayer.cpp
new file mode 100644
index 0000000..eb76953
--- /dev/null
+++ b/cmds/stagefright/AudioPlayer.cpp
@@ -0,0 +1,689 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <inttypes.h>
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AudioPlayer"
+#include <utils/Log.h>
+#include <cutils/compiler.h>
+
+#include <binder/IPCThreadState.h>
+#include <media/AudioTrack.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/openmax/OMX_Audio.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALookup.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+
+#include "AudioPlayer.h"
+
+namespace android {
+
+AudioPlayer::AudioPlayer(
+ const sp<MediaPlayerBase::AudioSink> &audioSink,
+ uint32_t flags)
+ : mInputBuffer(NULL),
+ mSampleRate(0),
+ mLatencyUs(0),
+ mFrameSize(0),
+ mNumFramesPlayed(0),
+ mNumFramesPlayedSysTimeUs(ALooper::GetNowUs()),
+ mPositionTimeMediaUs(-1),
+ mPositionTimeRealUs(-1),
+ mSeeking(false),
+ mReachedEOS(false),
+ mFinalStatus(OK),
+ mSeekTimeUs(0),
+ mStarted(false),
+ mIsFirstBuffer(false),
+ mFirstBufferResult(OK),
+ mFirstBuffer(NULL),
+ mAudioSink(audioSink),
+ mPlaying(false),
+ mStartPosUs(0),
+ mCreateFlags(flags) {
+}
+
+AudioPlayer::~AudioPlayer() {
+ if (mStarted) {
+ reset();
+ }
+}
+
+void AudioPlayer::setSource(const sp<MediaSource> &source) {
+ CHECK(mSource == NULL);
+ mSource = source;
+}
+
+ALookup<audio_format_t, int32_t> sAudioFormatToPcmEncoding {
+ {
+ { AUDIO_FORMAT_PCM_16_BIT, kAudioEncodingPcm16bit },
+ { AUDIO_FORMAT_PCM_8_BIT, kAudioEncodingPcm8bit },
+ { AUDIO_FORMAT_PCM_FLOAT, kAudioEncodingPcmFloat },
+ }
+};
+
+status_t AudioPlayer::start(bool sourceAlreadyStarted) {
+ CHECK(!mStarted);
+ CHECK(mSource != NULL);
+
+ status_t err;
+ if (!sourceAlreadyStarted) {
+ err = mSource->start();
+
+ if (err != OK) {
+ return err;
+ }
+ }
+
+ // We allow an optional INFO_FORMAT_CHANGED at the very beginning
+ // of playback, if there is one, getFormat below will retrieve the
+ // updated format, if there isn't, we'll stash away the valid buffer
+ // of data to be used on the first audio callback.
+
+ CHECK(mFirstBuffer == NULL);
+
+ MediaSource::ReadOptions options;
+ if (mSeeking) {
+ options.setSeekTo(mSeekTimeUs);
+ mSeeking = false;
+ }
+
+ mFirstBufferResult = mSource->read(&mFirstBuffer, &options);
+ if (mFirstBufferResult == INFO_FORMAT_CHANGED) {
+ ALOGV("INFO_FORMAT_CHANGED!!!");
+
+ CHECK(mFirstBuffer == NULL);
+ mFirstBufferResult = OK;
+ mIsFirstBuffer = false;
+ } else {
+ mIsFirstBuffer = true;
+ }
+
+ sp<MetaData> format = mSource->getFormat();
+
+ if (format == NULL) {
+ ALOGE("No metadata b/118620871");
+ android_errorWriteLog(0x534e4554, "118620871");
+ return BAD_VALUE;
+ }
+
+ const char *mime;
+ bool success = format->findCString(kKeyMIMEType, &mime);
+ CHECK(success);
+ CHECK(useOffload() || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW));
+
+ success = format->findInt32(kKeySampleRate, &mSampleRate);
+ CHECK(success);
+
+ int32_t numChannels, channelMask;
+ success = format->findInt32(kKeyChannelCount, &numChannels);
+ CHECK(success);
+
+ if(!format->findInt32(kKeyChannelMask, &channelMask)) {
+ // log only when there's a risk of ambiguity of channel mask selection
+ ALOGI_IF(numChannels > 2,
+ "source format didn't specify channel mask, using (%d) channel order", numChannels);
+ channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER;
+ }
+
+ audio_format_t audioFormat = AUDIO_FORMAT_PCM_16_BIT;
+ int32_t pcmEncoding;
+ if (format->findInt32(kKeyPcmEncoding, &pcmEncoding)) {
+ sAudioFormatToPcmEncoding.map(pcmEncoding, &audioFormat);
+ }
+
+ if (useOffload()) {
+ if (mapMimeToAudioFormat(audioFormat, mime) != OK) {
+ ALOGE("Couldn't map mime type \"%s\" to a valid AudioSystem::audio_format", mime);
+ audioFormat = AUDIO_FORMAT_INVALID;
+ } else {
+ ALOGV("Mime type \"%s\" mapped to audio_format 0x%x", mime, audioFormat);
+ }
+
+ int32_t aacaot = -1;
+ if ((audioFormat == AUDIO_FORMAT_AAC) && format->findInt32(kKeyAACAOT, &aacaot)) {
+ // Redefine AAC format corrosponding to aac profile
+ mapAACProfileToAudioFormat(audioFormat,(OMX_AUDIO_AACPROFILETYPE) aacaot);
+ }
+ }
+
+ int avgBitRate = -1;
+ format->findInt32(kKeyBitRate, &avgBitRate);
+
+ if (mAudioSink.get() != NULL) {
+
+ uint32_t flags = AUDIO_OUTPUT_FLAG_NONE;
+ audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER;
+
+ if (allowDeepBuffering()) {
+ flags |= AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
+ }
+ if (useOffload()) {
+ flags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
+
+ int64_t durationUs;
+ if (format->findInt64(kKeyDuration, &durationUs)) {
+ offloadInfo.duration_us = durationUs;
+ } else {
+ offloadInfo.duration_us = -1;
+ }
+
+ offloadInfo.sample_rate = mSampleRate;
+ offloadInfo.channel_mask = channelMask;
+ offloadInfo.format = audioFormat;
+ offloadInfo.stream_type = AUDIO_STREAM_MUSIC;
+ offloadInfo.bit_rate = avgBitRate;
+ offloadInfo.has_video = ((mCreateFlags & HAS_VIDEO) != 0);
+ offloadInfo.is_streaming = ((mCreateFlags & IS_STREAMING) != 0);
+ }
+
+ status_t err = mAudioSink->open(
+ mSampleRate, numChannels, channelMask, audioFormat,
+ DEFAULT_AUDIOSINK_BUFFERCOUNT,
+ &AudioPlayer::AudioSinkCallback,
+ this,
+ (audio_output_flags_t)flags,
+ useOffload() ? &offloadInfo : NULL);
+
+ if (err == OK) {
+ mLatencyUs = (int64_t)mAudioSink->latency() * 1000;
+ mFrameSize = mAudioSink->frameSize();
+
+ if (useOffload()) {
+ // If the playback is offloaded to h/w we pass the
+ // HAL some metadata information
+ // We don't want to do this for PCM because it will be going
+ // through the AudioFlinger mixer before reaching the hardware
+ sendMetaDataToHal(mAudioSink, format);
+ }
+
+ err = mAudioSink->start();
+ // do not alter behavior for non offloaded tracks: ignore start status.
+ if (!useOffload()) {
+ err = OK;
+ }
+ }
+
+ if (err != OK) {
+ if (mFirstBuffer != NULL) {
+ mFirstBuffer->release();
+ mFirstBuffer = NULL;
+ }
+
+ if (!sourceAlreadyStarted) {
+ mSource->stop();
+ }
+
+ return err;
+ }
+
+ } else {
+ // playing to an AudioTrack, set up mask if necessary
+ audio_channel_mask_t audioMask = channelMask == CHANNEL_MASK_USE_CHANNEL_ORDER ?
+ audio_channel_out_mask_from_count(numChannels) : channelMask;
+ if (0 == audioMask) {
+ return BAD_VALUE;
+ }
+
+ mAudioTrack = new AudioTrack(
+ AUDIO_STREAM_MUSIC, mSampleRate, AUDIO_FORMAT_PCM_16_BIT, audioMask,
+ 0 /*frameCount*/, AUDIO_OUTPUT_FLAG_NONE, &AudioCallback, this,
+ 0 /*notificationFrames*/);
+
+ if ((err = mAudioTrack->initCheck()) != OK) {
+ mAudioTrack.clear();
+
+ if (mFirstBuffer != NULL) {
+ mFirstBuffer->release();
+ mFirstBuffer = NULL;
+ }
+
+ if (!sourceAlreadyStarted) {
+ mSource->stop();
+ }
+
+ return err;
+ }
+
+ mLatencyUs = (int64_t)mAudioTrack->latency() * 1000;
+ mFrameSize = mAudioTrack->frameSize();
+
+ mAudioTrack->start();
+ }
+
+ mStarted = true;
+ mPlaying = true;
+
+ return OK;
+}
+
+void AudioPlayer::pause(bool playPendingSamples) {
+ CHECK(mStarted);
+
+ if (playPendingSamples) {
+ if (mAudioSink.get() != NULL) {
+ mAudioSink->stop();
+ } else {
+ mAudioTrack->stop();
+ }
+
+ mNumFramesPlayed = 0;
+ mNumFramesPlayedSysTimeUs = ALooper::GetNowUs();
+ } else {
+ if (mAudioSink.get() != NULL) {
+ mAudioSink->pause();
+ } else {
+ mAudioTrack->pause();
+ }
+ }
+
+ mPlaying = false;
+}
+
+status_t AudioPlayer::resume() {
+ CHECK(mStarted);
+ status_t err;
+
+ if (mAudioSink.get() != NULL) {
+ err = mAudioSink->start();
+ } else {
+ err = mAudioTrack->start();
+ }
+
+ if (err == OK) {
+ mPlaying = true;
+ }
+
+ return err;
+}
+
+void AudioPlayer::reset() {
+ CHECK(mStarted);
+
+ ALOGV("reset: mPlaying=%d mReachedEOS=%d useOffload=%d",
+ mPlaying, mReachedEOS, useOffload() );
+
+ if (mAudioSink.get() != NULL) {
+ mAudioSink->stop();
+ // If we're closing and have reached EOS, we don't want to flush
+ // the track because if it is offloaded there could be a small
+ // amount of residual data in the hardware buffer which we must
+ // play to give gapless playback.
+ // But if we're resetting when paused or before we've reached EOS
+ // we can't be doing a gapless playback and there could be a large
+ // amount of data queued in the hardware if the track is offloaded,
+ // so we must flush to prevent a track switch being delayed playing
+ // the buffered data that we don't want now
+ if (!mPlaying || !mReachedEOS) {
+ mAudioSink->flush();
+ }
+
+ mAudioSink->close();
+ } else {
+ mAudioTrack->stop();
+
+ if (!mPlaying || !mReachedEOS) {
+ mAudioTrack->flush();
+ }
+
+ mAudioTrack.clear();
+ }
+
+ // Make sure to release any buffer we hold onto so that the
+ // source is able to stop().
+
+ if (mFirstBuffer != NULL) {
+ mFirstBuffer->release();
+ mFirstBuffer = NULL;
+ }
+
+ if (mInputBuffer != NULL) {
+ ALOGV("AudioPlayer releasing input buffer.");
+
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+ }
+
+ mSource->stop();
+
+ // The following hack is necessary to ensure that the OMX
+ // component is completely released by the time we may try
+ // to instantiate it again.
+ // When offloading, the OMX component is not used so this hack
+ // is not needed
+ if (!useOffload()) {
+ wp<MediaSource> tmp = mSource;
+ mSource.clear();
+ while (tmp.promote() != NULL) {
+ usleep(1000);
+ }
+ } else {
+ mSource.clear();
+ }
+ IPCThreadState::self()->flushCommands();
+
+ mNumFramesPlayed = 0;
+ mNumFramesPlayedSysTimeUs = ALooper::GetNowUs();
+ mPositionTimeMediaUs = -1;
+ mPositionTimeRealUs = -1;
+ mSeeking = false;
+ mSeekTimeUs = 0;
+ mReachedEOS = false;
+ mFinalStatus = OK;
+ mStarted = false;
+ mPlaying = false;
+ mStartPosUs = 0;
+}
+
+// static
+void AudioPlayer::AudioCallback(int event, void *user, void *info) {
+ static_cast<AudioPlayer *>(user)->AudioCallback(event, info);
+}
+
+bool AudioPlayer::reachedEOS(status_t *finalStatus) {
+ *finalStatus = OK;
+
+ Mutex::Autolock autoLock(mLock);
+ *finalStatus = mFinalStatus;
+ return mReachedEOS;
+}
+
+status_t AudioPlayer::setPlaybackRate(const AudioPlaybackRate &rate) {
+ if (mAudioSink.get() != NULL) {
+ return mAudioSink->setPlaybackRate(rate);
+ } else if (mAudioTrack != 0){
+ return mAudioTrack->setPlaybackRate(rate);
+ } else {
+ return NO_INIT;
+ }
+}
+
+status_t AudioPlayer::getPlaybackRate(AudioPlaybackRate *rate /* nonnull */) {
+ if (mAudioSink.get() != NULL) {
+ return mAudioSink->getPlaybackRate(rate);
+ } else if (mAudioTrack != 0) {
+ *rate = mAudioTrack->getPlaybackRate();
+ return OK;
+ } else {
+ return NO_INIT;
+ }
+}
+
+// static
+size_t AudioPlayer::AudioSinkCallback(
+ MediaPlayerBase::AudioSink * /* audioSink */,
+ void *buffer, size_t size, void *cookie,
+ MediaPlayerBase::AudioSink::cb_event_t event) {
+ AudioPlayer *me = (AudioPlayer *)cookie;
+
+ switch(event) {
+ case MediaPlayerBase::AudioSink::CB_EVENT_FILL_BUFFER:
+ return me->fillBuffer(buffer, size);
+
+ case MediaPlayerBase::AudioSink::CB_EVENT_STREAM_END:
+ ALOGV("AudioSinkCallback: stream end");
+ me->mReachedEOS = true;
+ break;
+
+ case MediaPlayerBase::AudioSink::CB_EVENT_TEAR_DOWN:
+ ALOGV("AudioSinkCallback: Tear down event");
+ break;
+ }
+
+ return 0;
+}
+
+void AudioPlayer::AudioCallback(int event, void *info) {
+ switch (event) {
+ case AudioTrack::EVENT_MORE_DATA:
+ {
+ AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
+ size_t numBytesWritten = fillBuffer(buffer->raw, buffer->size);
+ buffer->size = numBytesWritten;
+ }
+ break;
+
+ case AudioTrack::EVENT_STREAM_END:
+ mReachedEOS = true;
+ break;
+ }
+}
+
+size_t AudioPlayer::fillBuffer(void *data, size_t size) {
+ if (mNumFramesPlayed == 0) {
+ ALOGV("AudioCallback");
+ }
+
+ if (mReachedEOS) {
+ return 0;
+ }
+
+ size_t size_done = 0;
+ size_t size_remaining = size;
+ while (size_remaining > 0) {
+ MediaSource::ReadOptions options;
+ bool refreshSeekTime = false;
+
+ {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mSeeking) {
+ if (mIsFirstBuffer) {
+ if (mFirstBuffer != NULL) {
+ mFirstBuffer->release();
+ mFirstBuffer = NULL;
+ }
+ mIsFirstBuffer = false;
+ }
+
+ options.setSeekTo(mSeekTimeUs);
+ refreshSeekTime = true;
+
+ if (mInputBuffer != NULL) {
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+ }
+
+ mSeeking = false;
+ }
+ }
+
+ if (mInputBuffer == NULL) {
+ status_t err;
+
+ if (mIsFirstBuffer) {
+ mInputBuffer = mFirstBuffer;
+ mFirstBuffer = NULL;
+ err = mFirstBufferResult;
+
+ mIsFirstBuffer = false;
+ } else {
+ err = mSource->read(&mInputBuffer, &options);
+ }
+
+ CHECK((err == OK && mInputBuffer != NULL)
+ || (err != OK && mInputBuffer == NULL));
+
+ Mutex::Autolock autoLock(mLock);
+
+ if (err != OK) {
+ if (!mReachedEOS) {
+ if (useOffload()) {
+ // no more buffers to push - stop() and wait for STREAM_END
+ // don't set mReachedEOS until stream end received
+ if (mAudioSink != NULL) {
+ mAudioSink->stop();
+ } else {
+ mAudioTrack->stop();
+ }
+ } else {
+ mReachedEOS = true;
+ }
+ }
+
+ mFinalStatus = err;
+ break;
+ }
+
+ if (mAudioSink != NULL) {
+ mLatencyUs = (int64_t)mAudioSink->latency() * 1000;
+ } else {
+ mLatencyUs = (int64_t)mAudioTrack->latency() * 1000;
+ }
+
+ if(mInputBuffer->range_length() != 0) {
+ CHECK(mInputBuffer->meta_data().findInt64(
+ kKeyTime, &mPositionTimeMediaUs));
+ }
+
+ // need to adjust the mStartPosUs for offload decoding since parser
+ // might not be able to get the exact seek time requested.
+ if (refreshSeekTime) {
+ if (useOffload()) {
+ mStartPosUs = mPositionTimeMediaUs;
+ ALOGV("adjust seek time to: %.2f", mStartPosUs/ 1E6);
+ }
+ // clear seek time with mLock locked and once we have valid mPositionTimeMediaUs
+ // and mPositionTimeRealUs
+ // before clearing mSeekTimeUs check if a new seek request has been received while
+ // we were reading from the source with mLock released.
+ if (!mSeeking) {
+ mSeekTimeUs = 0;
+ }
+ }
+
+ if (!useOffload()) {
+ mPositionTimeRealUs =
+ ((mNumFramesPlayed + size_done / mFrameSize) * 1000000)
+ / mSampleRate;
+ ALOGV("buffer->size() = %zu, "
+ "mPositionTimeMediaUs=%.2f mPositionTimeRealUs=%.2f",
+ mInputBuffer->range_length(),
+ mPositionTimeMediaUs / 1E6, mPositionTimeRealUs / 1E6);
+ }
+
+ }
+
+ if (mInputBuffer->range_length() == 0) {
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+
+ continue;
+ }
+
+ size_t copy = size_remaining;
+ if (copy > mInputBuffer->range_length()) {
+ copy = mInputBuffer->range_length();
+ }
+
+ memcpy((char *)data + size_done,
+ (const char *)mInputBuffer->data() + mInputBuffer->range_offset(),
+ copy);
+
+ mInputBuffer->set_range(mInputBuffer->range_offset() + copy,
+ mInputBuffer->range_length() - copy);
+
+ size_done += copy;
+ size_remaining -= copy;
+ }
+
+ if (useOffload()) {
+ // We must ask the hardware what it has played
+ mPositionTimeRealUs = getOutputPlayPositionUs_l();
+ ALOGV("mPositionTimeMediaUs=%.2f mPositionTimeRealUs=%.2f",
+ mPositionTimeMediaUs / 1E6, mPositionTimeRealUs / 1E6);
+ }
+
+ {
+ Mutex::Autolock autoLock(mLock);
+ mNumFramesPlayed += size_done / mFrameSize;
+ mNumFramesPlayedSysTimeUs = ALooper::GetNowUs();
+ }
+
+ return size_done;
+}
+
+int64_t AudioPlayer::getOutputPlayPositionUs_l()
+{
+ uint32_t playedSamples = 0;
+ uint32_t sampleRate;
+ if (mAudioSink != NULL) {
+ mAudioSink->getPosition(&playedSamples);
+ sampleRate = mAudioSink->getSampleRate();
+ } else {
+ mAudioTrack->getPosition(&playedSamples);
+ sampleRate = mAudioTrack->getSampleRate();
+ }
+ if (sampleRate != 0) {
+ mSampleRate = sampleRate;
+ }
+
+ int64_t playedUs;
+ if (mSampleRate != 0) {
+ playedUs = (static_cast<int64_t>(playedSamples) * 1000000 ) / mSampleRate;
+ } else {
+ playedUs = 0;
+ }
+
+ // HAL position is relative to the first buffer we sent at mStartPosUs
+ const int64_t renderedDuration = mStartPosUs + playedUs;
+ ALOGV("getOutputPlayPositionUs_l %" PRId64, renderedDuration);
+ return renderedDuration;
+}
+
+status_t AudioPlayer::seekTo(int64_t time_us) {
+ Mutex::Autolock autoLock(mLock);
+
+ ALOGV("seekTo( %" PRId64 " )", time_us);
+
+ mSeeking = true;
+ mPositionTimeRealUs = mPositionTimeMediaUs = -1;
+ mReachedEOS = false;
+ mSeekTimeUs = time_us;
+ mStartPosUs = time_us;
+
+ // Flush resets the number of played frames
+ mNumFramesPlayed = 0;
+ mNumFramesPlayedSysTimeUs = ALooper::GetNowUs();
+
+ if (mAudioSink != NULL) {
+ if (mPlaying) {
+ mAudioSink->pause();
+ }
+ mAudioSink->flush();
+ if (mPlaying) {
+ mAudioSink->start();
+ }
+ } else {
+ if (mPlaying) {
+ mAudioTrack->pause();
+ }
+ mAudioTrack->flush();
+ if (mPlaying) {
+ mAudioTrack->start();
+ }
+ }
+
+ return OK;
+}
+
+}
diff --git a/cmds/stagefright/AudioPlayer.h b/cmds/stagefright/AudioPlayer.h
new file mode 100644
index 0000000..43550ea
--- /dev/null
+++ b/cmds/stagefright/AudioPlayer.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AUDIO_PLAYER_H_
+
+#define AUDIO_PLAYER_H_
+
+#include <media/AudioResamplerPublic.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/MediaPlayerInterface.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class AudioTrack;
+struct AwesomePlayer;
+
+class AudioPlayer {
+public:
+ enum {
+ REACHED_EOS,
+ SEEK_COMPLETE
+ };
+
+ enum {
+ ALLOW_DEEP_BUFFERING = 0x01,
+ USE_OFFLOAD = 0x02,
+ HAS_VIDEO = 0x1000,
+ IS_STREAMING = 0x2000
+
+ };
+
+ AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink,
+ uint32_t flags = 0);
+
+ virtual ~AudioPlayer();
+
+ // Caller retains ownership of "source".
+ void setSource(const sp<MediaSource> &source);
+
+ status_t start(bool sourceAlreadyStarted = false);
+
+ void pause(bool playPendingSamples = false);
+ status_t resume();
+
+ status_t seekTo(int64_t time_us);
+
+ bool isSeeking();
+ bool reachedEOS(status_t *finalStatus);
+
+ status_t setPlaybackRate(const AudioPlaybackRate &rate);
+ status_t getPlaybackRate(AudioPlaybackRate *rate /* nonnull */);
+
+private:
+ sp<MediaSource> mSource;
+ sp<AudioTrack> mAudioTrack;
+
+ MediaBufferBase *mInputBuffer;
+
+ int mSampleRate;
+ int64_t mLatencyUs;
+ size_t mFrameSize;
+
+ Mutex mLock;
+ int64_t mNumFramesPlayed;
+ int64_t mNumFramesPlayedSysTimeUs;
+
+ int64_t mPositionTimeMediaUs;
+ int64_t mPositionTimeRealUs;
+
+ bool mSeeking;
+ bool mReachedEOS;
+ status_t mFinalStatus;
+ int64_t mSeekTimeUs;
+
+ bool mStarted;
+
+ bool mIsFirstBuffer;
+ status_t mFirstBufferResult;
+ MediaBufferBase *mFirstBuffer;
+
+ sp<MediaPlayerBase::AudioSink> mAudioSink;
+
+ bool mPlaying;
+ int64_t mStartPosUs;
+ const uint32_t mCreateFlags;
+
+ static void AudioCallback(int event, void *user, void *info);
+ void AudioCallback(int event, void *info);
+
+ static size_t AudioSinkCallback(
+ MediaPlayerBase::AudioSink *audioSink,
+ void *data, size_t size, void *me,
+ MediaPlayerBase::AudioSink::cb_event_t event);
+
+ size_t fillBuffer(void *data, size_t size);
+
+ void reset();
+
+ int64_t getOutputPlayPositionUs_l();
+
+ bool allowDeepBuffering() const { return (mCreateFlags & ALLOW_DEEP_BUFFERING) != 0; }
+ bool useOffload() const { return (mCreateFlags & USE_OFFLOAD) != 0; }
+
+ AudioPlayer(const AudioPlayer &);
+ AudioPlayer &operator=(const AudioPlayer &);
+};
+
+} // namespace android
+
+#endif // AUDIO_PLAYER_H_
diff --git a/cmds/stagefright/SimplePlayer.cpp b/cmds/stagefright/SimplePlayer.cpp
index afb7db3..f4b8164 100644
--- a/cmds/stagefright/SimplePlayer.cpp
+++ b/cmds/stagefright/SimplePlayer.cpp
@@ -23,7 +23,7 @@
#include <gui/Surface.h>
#include <media/AudioTrack.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/IMediaHTTPService.h>
#include <media/MediaCodecBuffer.h>
#include <media/stagefright/foundation/ABuffer.h>
diff --git a/cmds/stagefright/SineSource.h b/cmds/stagefright/SineSource.h
index 1817291..6f1d98c 100644
--- a/cmds/stagefright/SineSource.h
+++ b/cmds/stagefright/SineSource.h
@@ -2,7 +2,7 @@
#define SINE_SOURCE_H_
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <utils/Compat.h>
namespace android {
diff --git a/cmds/stagefright/audioloop.cpp b/cmds/stagefright/audioloop.cpp
index d4f2e8d..84a6d6b 100644
--- a/cmds/stagefright/audioloop.cpp
+++ b/cmds/stagefright/audioloop.cpp
@@ -29,11 +29,11 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/AMRWriter.h>
-#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/AudioSource.h>
#include <media/stagefright/MediaCodecSource.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/SimpleDecodingSource.h>
+#include "AudioPlayer.h"
#include "SineSource.h"
using namespace android;
@@ -107,8 +107,11 @@
if (useMic) {
// talk into the appropriate microphone for the duration
+ audio_attributes_t attr = AUDIO_ATTRIBUTES_INITIALIZER;
+ attr.source = AUDIO_SOURCE_MIC;
+
source = new AudioSource(
- AUDIO_SOURCE_MIC,
+ &attr,
String16(),
sampleRate,
channels);
diff --git a/cmds/stagefright/codec.cpp b/cmds/stagefright/codec.cpp
index e5a4337..c26e0b9 100644
--- a/cmds/stagefright/codec.cpp
+++ b/cmds/stagefright/codec.cpp
@@ -23,7 +23,7 @@
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/IMediaHTTPService.h>
#include <media/IMediaPlayerService.h>
#include <media/MediaCodecBuffer.h>
@@ -39,7 +39,7 @@
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/Surface.h>
-#include <ui/DisplayInfo.h>
+#include <ui/DisplayConfig.h>
static void usage(const char *me) {
fprintf(stderr, "usage: %s [-a] use audio\n"
@@ -414,11 +414,12 @@
const sp<IBinder> display = SurfaceComposerClient::getInternalDisplayToken();
CHECK(display != nullptr);
- DisplayInfo info;
- CHECK_EQ(SurfaceComposerClient::getDisplayInfo(display, &info), NO_ERROR);
+ DisplayConfig config;
+ CHECK_EQ(SurfaceComposerClient::getActiveDisplayConfig(display, &config), NO_ERROR);
- ssize_t displayWidth = info.w;
- ssize_t displayHeight = info.h;
+ const ui::Size& resolution = config.resolution;
+ const ssize_t displayWidth = resolution.getWidth();
+ const ssize_t displayHeight = resolution.getHeight();
ALOGV("display is %zd x %zd\n", displayWidth, displayHeight);
diff --git a/cmds/stagefright/filters/argbtorgba.rs b/cmds/stagefright/filters/argbtorgba.rscript
similarity index 100%
rename from cmds/stagefright/filters/argbtorgba.rs
rename to cmds/stagefright/filters/argbtorgba.rscript
diff --git a/cmds/stagefright/filters/nightvision.rs b/cmds/stagefright/filters/nightvision.rscript
similarity index 100%
rename from cmds/stagefright/filters/nightvision.rs
rename to cmds/stagefright/filters/nightvision.rscript
diff --git a/cmds/stagefright/filters/saturation.rs b/cmds/stagefright/filters/saturation.rscript
similarity index 100%
rename from cmds/stagefright/filters/saturation.rs
rename to cmds/stagefright/filters/saturation.rscript
diff --git a/cmds/stagefright/mediafilter.cpp b/cmds/stagefright/mediafilter.cpp
index 2cf6955..b894545 100644
--- a/cmds/stagefright/mediafilter.cpp
+++ b/cmds/stagefright/mediafilter.cpp
@@ -24,9 +24,9 @@
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/Surface.h>
-#include <media/ICrypto.h>
#include <media/IMediaHTTPService.h>
#include <media/MediaCodecBuffer.h>
+#include <mediadrm/ICrypto.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
@@ -34,7 +34,7 @@
#include <media/stagefright/NuMediaExtractor.h>
#include <media/stagefright/RenderScriptWrapper.h>
#include <OMX_IVCommon.h>
-#include <ui/DisplayInfo.h>
+#include <ui/DisplayConfig.h>
#include "RenderScript.h"
#include "ScriptC_argbtorgba.h"
@@ -751,11 +751,12 @@
const android::sp<IBinder> display = SurfaceComposerClient::getInternalDisplayToken();
CHECK(display != nullptr);
- DisplayInfo info;
- CHECK_EQ(SurfaceComposerClient::getDisplayInfo(display, &info), NO_ERROR);
+ DisplayConfig config;
+ CHECK_EQ(SurfaceComposerClient::getActiveDisplayConfig(display, &config), NO_ERROR);
- ssize_t displayWidth = info.w;
- ssize_t displayHeight = info.h;
+ const ui::Size& resolution = config.resolution;
+ const ssize_t displayWidth = resolution.getWidth();
+ const ssize_t displayHeight = resolution.getHeight();
ALOGV("display is %zd x %zd", displayWidth, displayHeight);
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 95a16f3..37091c4 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -17,12 +17,11 @@
#include "SineSource.h"
#include <binder/ProcessState.h>
+#include <datasource/FileSource.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/CameraSource.h>
-#include <media/stagefright/FileSource.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaCodecSource.h>
@@ -33,6 +32,8 @@
#include <media/stagefright/SimpleDecodingSource.h>
#include <media/MediaPlayerInterface.h>
+#include "AudioPlayer.h"
+
using namespace android;
static const int32_t kAudioBitRate = 12200;
diff --git a/cmds/stagefright/recordvideo.cpp b/cmds/stagefright/recordvideo.cpp
index a63b9b9..01a178e 100644
--- a/cmds/stagefright/recordvideo.cpp
+++ b/cmds/stagefright/recordvideo.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#include "SineSource.h"
-
#include <inttypes.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -25,8 +23,8 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaCodecSource.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index bf36be0..c430f05 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -31,18 +31,15 @@
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
+#include <datasource/DataSourceFactory.h>
#include <media/DataSource.h>
-#include <media/MediaSource.h>
-#include <media/ICrypto.h>
+#include <media/stagefright/MediaSource.h>
#include <media/IMediaHTTPService.h>
#include <media/IMediaPlayerService.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AUtils.h>
-#include "include/NuCachedSource2.h"
-#include <media/stagefright/AudioPlayer.h>
-#include <media/stagefright/DataSourceFactory.h>
#include <media/stagefright/JPEGSource.h>
#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MediaCodec.h>
@@ -69,6 +66,8 @@
#include <android/hardware/media/omx/1.0/IOmx.h>
+#include "AudioPlayer.h"
+
using namespace android;
static long gNumRepetitions;
@@ -305,7 +304,7 @@
seekTimeUs = -1;
if (shouldSeek) {
- seekTimeUs = (rand() * (float)durationUs) / RAND_MAX;
+ seekTimeUs = (rand() * (float)durationUs) / (float)RAND_MAX;
options.setSeekTo(seekTimeUs);
printf("seeking to %" PRId64 " us (%.2f secs)\n",
@@ -989,7 +988,7 @@
failed = false;
printf("getFrameAtTime(%s) => OK\n", filename);
- VideoFrame *frame = (VideoFrame *)mem->pointer();
+ VideoFrame *frame = (VideoFrame *)mem->unsecurePointer();
CHECK_EQ(writeJpegFile("/sdcard/out.jpg",
frame->getFlattenedData(),
@@ -1086,7 +1085,7 @@
const char *filename = argv[k];
sp<DataSource> dataSource =
- DataSourceFactory::CreateFromURI(NULL /* httpService */, filename);
+ DataSourceFactory::getInstance()->CreateFromURI(NULL /* httpService */, filename);
if (strncasecmp(filename, "sine:", 5) && dataSource == NULL) {
fprintf(stderr, "Unable to create data source.\n");
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
index 35bdbc0..250d26b 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -21,14 +21,14 @@
#include <binder/ProcessState.h>
#include <cutils/properties.h> // for property_get
+#include <datasource/DataSourceFactory.h>
#include <media/DataSource.h>
#include <media/IMediaHTTPService.h>
#include <media/IStreamSource.h>
#include <media/mediaplayer.h>
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSourceFactory.h>
#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MPEG2TSWriter.h>
#include <media/stagefright/MediaExtractor.h>
@@ -42,7 +42,7 @@
#include <gui/Surface.h>
#include <fcntl.h>
-#include <ui/DisplayInfo.h>
+#include <ui/DisplayConfig.h>
using namespace android;
@@ -116,7 +116,7 @@
sp<IMemory> mem = mBuffers.itemAt(index);
- ssize_t n = read(mFd, mem->pointer(), mem->size());
+ ssize_t n = read(mFd, mem->unsecurePointer(), mem->size());
if (n <= 0) {
mListener->issueCommand(IStreamListener::EOS, false /* synchronous */);
} else {
@@ -164,7 +164,7 @@
: mCurrentBufferIndex(-1),
mCurrentBufferOffset(0) {
sp<DataSource> dataSource =
- DataSourceFactory::CreateFromURI(NULL /* httpService */, filename);
+ DataSourceFactory::getInstance()->CreateFromURI(NULL /* httpService */, filename);
CHECK(dataSource != NULL);
@@ -238,7 +238,7 @@
copy = mem->size() - mCurrentBufferOffset;
}
- memcpy((uint8_t *)mem->pointer() + mCurrentBufferOffset, data, copy);
+ memcpy((uint8_t *)mem->unsecurePointer() + mCurrentBufferOffset, data, copy);
mCurrentBufferOffset += copy;
if (mCurrentBufferOffset == mem->size()) {
@@ -321,11 +321,12 @@
const sp<IBinder> display = SurfaceComposerClient::getInternalDisplayToken();
CHECK(display != nullptr);
- DisplayInfo info;
- CHECK_EQ(SurfaceComposerClient::getDisplayInfo(display, &info), NO_ERROR);
+ DisplayConfig config;
+ CHECK_EQ(SurfaceComposerClient::getActiveDisplayConfig(display, &config), NO_ERROR);
- ssize_t displayWidth = info.w;
- ssize_t displayHeight = info.h;
+ const ui::Size& resolution = config.resolution;
+ const ssize_t displayWidth = resolution.getWidth();
+ const ssize_t displayHeight = resolution.getHeight();
ALOGV("display is %zd x %zd\n", displayWidth, displayHeight);
diff --git a/drm/drmserver/Android.bp b/drm/drmserver/Android.bp
index c25a0a1..f427834 100644
--- a/drm/drmserver/Android.bp
+++ b/drm/drmserver/Android.bp
@@ -25,11 +25,14 @@
shared_libs: [
"libmedia",
+ "libmediametrics",
+ "libcutils",
"libutils",
"liblog",
"libbinder",
"libdl",
"libselinux",
+ "libstagefright_foundation",
],
static_libs: ["libdrmframeworkcommon"],
diff --git a/drm/drmserver/DrmManager.cpp b/drm/drmserver/DrmManager.cpp
index afbcb39..9a32cc5 100644
--- a/drm/drmserver/DrmManager.cpp
+++ b/drm/drmserver/DrmManager.cpp
@@ -16,10 +16,14 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "DrmManager(Native)"
-#include "utils/Log.h"
+#include <cutils/properties.h>
#include <utils/String8.h>
+#include <utils/Log.h>
+
+#include <binder/IPCThreadState.h>
#include <drm/DrmInfo.h>
+
#include <drm/DrmInfoEvent.h>
#include <drm/DrmRights.h>
#include <drm/DrmConstraints.h>
@@ -28,17 +32,36 @@
#include <drm/DrmInfoRequest.h>
#include <drm/DrmSupportInfo.h>
#include <drm/DrmConvertedStatus.h>
+#include <media/MediaMetricsItem.h>
#include <IDrmEngine.h>
#include "DrmManager.h"
#include "ReadWriteUtils.h"
+#include <algorithm>
+
#define DECRYPT_FILE_ERROR (-1)
using namespace android;
const String8 DrmManager::EMPTY_STRING("");
+const std::map<const char*, size_t> DrmManager::kMethodIdMap {
+ {"getConstraints" , DrmManagerMethodId::GET_CONSTRAINTS },
+ {"getMetadata" , DrmManagerMethodId::GET_METADATA },
+ {"canHandle" , DrmManagerMethodId::CAN_HANDLE },
+ {"processDrmInfo" , DrmManagerMethodId::PROCESS_DRM_INFO },
+ {"acquireDrmInfo" , DrmManagerMethodId::ACQUIRE_DRM_INFO },
+ {"saveRights" , DrmManagerMethodId::SAVE_RIGHTS },
+ {"getOriginalMimeType", DrmManagerMethodId::GET_ORIGINAL_MIME_TYPE},
+ {"getDrmObjectType" , DrmManagerMethodId::GET_DRM_OBJECT_TYPE },
+ {"checkRightsStatus" , DrmManagerMethodId::CHECK_RIGHTS_STATUS },
+ {"removeRights" , DrmManagerMethodId::REMOVE_RIGHTS },
+ {"removeAllRights" , DrmManagerMethodId::REMOVE_ALL_RIGHTS },
+ {"openConvertSession" , DrmManagerMethodId::OPEN_CONVERT_SESSION },
+ {"openDecryptSession" , DrmManagerMethodId::OPEN_DECRYPT_SESSION }
+};
+
DrmManager::DrmManager() :
mDecryptSessionId(0),
mConvertId(0) {
@@ -47,7 +70,104 @@
}
DrmManager::~DrmManager() {
+ if (mMetricsLooper != NULL) {
+ mMetricsLooper->stop();
+ }
+ flushEngineMetrics();
+}
+void DrmManager::initMetricsLooper() {
+ if (mMetricsLooper != NULL) {
+ return;
+ }
+ mMetricsLooper = new ALooper;
+ mMetricsLooper->setName("DrmManagerMetricsLooper");
+ mMetricsLooper->start();
+ mMetricsLooper->registerHandler(this);
+
+ sp<AMessage> msg = new AMessage(kWhatFlushMetrics, this);
+ msg->post(getMetricsFlushPeriodUs());
+}
+
+void DrmManager::onMessageReceived(const sp<AMessage> &msg) {
+ switch (msg->what()) {
+ case kWhatFlushMetrics:
+ {
+ flushEngineMetrics();
+ msg->post(getMetricsFlushPeriodUs());
+ break;
+ }
+ default:
+ {
+ ALOGW("Unrecognized message type: %zd", msg->what());
+ }
+ }
+}
+
+int64_t DrmManager::getMetricsFlushPeriodUs() {
+ return 1000 * 1000 * std::max(1ll, property_get_int64("drmmanager.metrics.period", 86400));
+}
+
+void DrmManager::recordEngineMetrics(
+ const char func[], const String8& plugInId8, const String8& mimeType) {
+ IDrmEngine& engine = mPlugInManager.getPlugIn(plugInId8);
+ std::unique_ptr<DrmSupportInfo> info(engine.getSupportInfo(0));
+
+ uid_t callingUid = IPCThreadState::self()->getCallingUid();
+ std::string plugInId(plugInId8.getPathLeaf().getBasePath().c_str());
+ ALOGV("%d calling %s %s", callingUid, plugInId.c_str(), func);
+
+ Mutex::Autolock _l(mMetricsLock);
+ auto& metrics = mPluginMetrics[std::make_pair(callingUid, plugInId)];
+ if (metrics.mPluginId.empty()) {
+ metrics.mPluginId = plugInId;
+ metrics.mCallingUid = callingUid;
+ if (NULL != info) {
+ metrics.mDescription = info->getDescription().c_str();
+ }
+ }
+
+ if (!mimeType.isEmpty()) {
+ metrics.mMimeTypes.insert(mimeType.c_str());
+ } else if (NULL != info) {
+ DrmSupportInfo::MimeTypeIterator mimeIter = info->getMimeTypeIterator();
+ while (mimeIter.hasNext()) {
+ metrics.mMimeTypes.insert(mimeIter.next().c_str());
+ }
+ }
+
+ size_t methodId = kMethodIdMap.at(func);
+ if (methodId < metrics.mMethodCounts.size()) {
+ metrics.mMethodCounts[methodId]++;
+ }
+}
+
+void DrmManager::flushEngineMetrics() {
+ using namespace std::string_literals;
+ Mutex::Autolock _l(mMetricsLock);
+ for (auto kv : mPluginMetrics) {
+ DrmManagerMetrics& metrics = kv.second;
+ std::unique_ptr<mediametrics::Item> item(mediametrics::Item::create("drmmanager"));
+ item->setUid(metrics.mCallingUid);
+ item->setCString("plugin_id", metrics.mPluginId.c_str());
+ item->setCString("description", metrics.mDescription.c_str());
+
+ std::vector<std::string> mimeTypes(metrics.mMimeTypes.begin(), metrics.mMimeTypes.end());
+ std::string mimeTypesStr(mimeTypes.empty() ? "" : mimeTypes[0]);
+ for (size_t i = 1; i < mimeTypes.size() ; i++) {
+ mimeTypesStr.append(",").append(mimeTypes[i]);
+ }
+ item->setCString("mime_types", mimeTypesStr.c_str());
+
+ for (size_t i = 0; i < metrics.mMethodCounts.size() ; i++) {
+ item->setInt64(("method"s + std::to_string(i)).c_str(), metrics.mMethodCounts[i]);
+ }
+
+ if (!item->selfrecord()) {
+ ALOGE("Failed to record metrics");
+ }
+ }
+ mPluginMetrics.clear();
}
int DrmManager::addUniqueId(bool isNative) {
@@ -152,22 +272,30 @@
DrmConstraints* DrmManager::getConstraints(int uniqueId, const String8* path, const int action) {
Mutex::Autolock _l(mLock);
+ DrmConstraints *constraints = NULL;
const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, *path);
if (EMPTY_STRING != plugInId) {
IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
- return rDrmEngine.getConstraints(uniqueId, path, action);
+ constraints = rDrmEngine.getConstraints(uniqueId, path, action);
}
- return NULL;
+ if (NULL != constraints) {
+ recordEngineMetrics(__func__, plugInId);
+ }
+ return constraints;
}
DrmMetadata* DrmManager::getMetadata(int uniqueId, const String8* path) {
Mutex::Autolock _l(mLock);
+ DrmMetadata *meta = NULL;
const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, *path);
if (EMPTY_STRING != plugInId) {
IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
- return rDrmEngine.getMetadata(uniqueId, path);
+ meta = rDrmEngine.getMetadata(uniqueId, path);
}
- return NULL;
+ if (NULL != meta) {
+ recordEngineMetrics(__func__, plugInId);
+ }
+ return meta;
}
bool DrmManager::canHandle(int uniqueId, const String8& path, const String8& mimeType) {
@@ -175,6 +303,10 @@
const String8 plugInId = getSupportedPlugInId(mimeType);
bool result = (EMPTY_STRING != plugInId) ? true : false;
+ if (result) {
+ recordEngineMetrics(__func__, plugInId, mimeType);
+ }
+
if (0 < path.length()) {
if (result) {
IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
@@ -191,12 +323,17 @@
DrmInfoStatus* DrmManager::processDrmInfo(int uniqueId, const DrmInfo* drmInfo) {
Mutex::Autolock _l(mLock);
- const String8 plugInId = getSupportedPlugInId(drmInfo->getMimeType());
+ DrmInfoStatus *infoStatus = NULL;
+ const String8 mimeType = drmInfo->getMimeType();
+ const String8 plugInId = getSupportedPlugInId(mimeType);
if (EMPTY_STRING != plugInId) {
IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
- return rDrmEngine.processDrmInfo(uniqueId, drmInfo);
+ infoStatus = rDrmEngine.processDrmInfo(uniqueId, drmInfo);
}
- return NULL;
+ if (NULL != infoStatus) {
+ recordEngineMetrics(__func__, plugInId, mimeType);
+ }
+ return infoStatus;
}
bool DrmManager::canHandle(int uniqueId, const String8& path) {
@@ -208,6 +345,7 @@
result = rDrmEngine.canHandle(uniqueId, path);
if (result) {
+ recordEngineMetrics(__func__, plugInPathList[i]);
break;
}
}
@@ -216,54 +354,75 @@
DrmInfo* DrmManager::acquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest) {
Mutex::Autolock _l(mLock);
- const String8 plugInId = getSupportedPlugInId(drmInfoRequest->getMimeType());
+ DrmInfo *info = NULL;
+ const String8 mimeType = drmInfoRequest->getMimeType();
+ const String8 plugInId = getSupportedPlugInId(mimeType);
if (EMPTY_STRING != plugInId) {
IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
- return rDrmEngine.acquireDrmInfo(uniqueId, drmInfoRequest);
+ info = rDrmEngine.acquireDrmInfo(uniqueId, drmInfoRequest);
}
- return NULL;
+ if (NULL != info) {
+ recordEngineMetrics(__func__, plugInId, mimeType);
+ }
+ return info;
}
status_t DrmManager::saveRights(int uniqueId, const DrmRights& drmRights,
const String8& rightsPath, const String8& contentPath) {
Mutex::Autolock _l(mLock);
- const String8 plugInId = getSupportedPlugInId(drmRights.getMimeType());
+ const String8 mimeType = drmRights.getMimeType();
+ const String8 plugInId = getSupportedPlugInId(mimeType);
status_t result = DRM_ERROR_UNKNOWN;
if (EMPTY_STRING != plugInId) {
IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
result = rDrmEngine.saveRights(uniqueId, drmRights, rightsPath, contentPath);
}
+ if (DRM_NO_ERROR == result) {
+ recordEngineMetrics(__func__, plugInId, mimeType);
+ }
return result;
}
String8 DrmManager::getOriginalMimeType(int uniqueId, const String8& path, int fd) {
Mutex::Autolock _l(mLock);
+ String8 mimeType(EMPTY_STRING);
const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, path);
if (EMPTY_STRING != plugInId) {
IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
- return rDrmEngine.getOriginalMimeType(uniqueId, path, fd);
+ mimeType = rDrmEngine.getOriginalMimeType(uniqueId, path, fd);
}
- return EMPTY_STRING;
+ if (!mimeType.isEmpty()) {
+ recordEngineMetrics(__func__, plugInId, mimeType);
+ }
+ return mimeType;
}
int DrmManager::getDrmObjectType(int uniqueId, const String8& path, const String8& mimeType) {
Mutex::Autolock _l(mLock);
+ int type = DrmObjectType::UNKNOWN;
const String8 plugInId = getSupportedPlugInId(uniqueId, path, mimeType);
if (EMPTY_STRING != plugInId) {
IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
- return rDrmEngine.getDrmObjectType(uniqueId, path, mimeType);
+ type = rDrmEngine.getDrmObjectType(uniqueId, path, mimeType);
}
- return DrmObjectType::UNKNOWN;
+ if (DrmObjectType::UNKNOWN != type) {
+ recordEngineMetrics(__func__, plugInId, mimeType);
+ }
+ return type;
}
int DrmManager::checkRightsStatus(int uniqueId, const String8& path, int action) {
Mutex::Autolock _l(mLock);
+ int rightsStatus = RightsStatus::RIGHTS_INVALID;
const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, path);
if (EMPTY_STRING != plugInId) {
IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
- return rDrmEngine.checkRightsStatus(uniqueId, path, action);
+ rightsStatus = rDrmEngine.checkRightsStatus(uniqueId, path, action);
}
- return RightsStatus::RIGHTS_INVALID;
+ if (RightsStatus::RIGHTS_INVALID != rightsStatus) {
+ recordEngineMetrics(__func__, plugInId);
+ }
+ return rightsStatus;
}
status_t DrmManager::consumeRights(
@@ -307,6 +466,9 @@
IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
result = rDrmEngine.removeRights(uniqueId, path);
}
+ if (DRM_NO_ERROR == result) {
+ recordEngineMetrics(__func__, plugInId);
+ }
return result;
}
@@ -319,6 +481,7 @@
if (DRM_NO_ERROR != result) {
break;
}
+ recordEngineMetrics(__func__, plugInIdList[index]);
}
return result;
}
@@ -335,6 +498,7 @@
++mConvertId;
convertId = mConvertId;
mConvertSessionMap.add(convertId, &rDrmEngine);
+ recordEngineMetrics(__func__, plugInId, mimeType);
}
}
return convertId;
@@ -415,6 +579,7 @@
if (DRM_NO_ERROR == result) {
++mDecryptSessionId;
mDecryptSessionMap.add(mDecryptSessionId, &rDrmEngine);
+ recordEngineMetrics(__func__, plugInId, String8(mime));
break;
}
}
@@ -443,6 +608,7 @@
if (DRM_NO_ERROR == result) {
++mDecryptSessionId;
mDecryptSessionMap.add(mDecryptSessionId, &rDrmEngine);
+ recordEngineMetrics(__func__, plugInId, String8(mime));
break;
}
}
@@ -472,6 +638,7 @@
if (DRM_NO_ERROR == result) {
++mDecryptSessionId;
mDecryptSessionMap.add(mDecryptSessionId, &rDrmEngine);
+ recordEngineMetrics(__func__, plugInId, mimeType);
break;
}
}
diff --git a/drm/drmserver/DrmManager.h b/drm/drmserver/DrmManager.h
index 26222bc..350fcf4 100644
--- a/drm/drmserver/DrmManager.h
+++ b/drm/drmserver/DrmManager.h
@@ -17,13 +17,26 @@
#ifndef __DRM_MANAGER_H__
#define __DRM_MANAGER_H__
+#include <drm/drm_framework_common.h>
+#include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <sys/types.h>
#include <utils/Errors.h>
#include <utils/threads.h>
-#include <drm/drm_framework_common.h>
+
#include "IDrmEngine.h"
#include "PlugInManager.h"
#include "IDrmServiceListener.h"
+#include <array>
+#include <cstddef>
+#include <map>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
namespace android {
class IDrmManager;
@@ -40,6 +53,31 @@
class DrmSupportInfo;
class ActionDescription;
+enum DrmManagerMethodId {
+ GET_CONSTRAINTS,
+ GET_METADATA,
+ CAN_HANDLE,
+ PROCESS_DRM_INFO,
+ ACQUIRE_DRM_INFO,
+ SAVE_RIGHTS,
+ GET_ORIGINAL_MIME_TYPE,
+ GET_DRM_OBJECT_TYPE,
+ CHECK_RIGHTS_STATUS,
+ REMOVE_RIGHTS,
+ REMOVE_ALL_RIGHTS,
+ OPEN_CONVERT_SESSION,
+ OPEN_DECRYPT_SESSION,
+ NUM_METHODS,
+};
+
+struct DrmManagerMetrics {
+ std::string mPluginId;
+ std::string mDescription;
+ std::set<std::string> mMimeTypes;
+ std::array<int64_t, DrmManagerMethodId::NUM_METHODS> mMethodCounts{};
+ uid_t mCallingUid;
+};
+
/**
* This is implementation class for DRM Manager. This class delegates the
* functionality to corresponding DRM Engine.
@@ -47,7 +85,7 @@
* The DrmManagerService class creates an instance of this class.
*
*/
-class DrmManager : public IDrmEngine::OnInfoListener {
+class DrmManager : public AHandler, public IDrmEngine::OnInfoListener {
public:
DrmManager();
virtual ~DrmManager();
@@ -134,6 +172,8 @@
void onInfo(const DrmInfoEvent& event);
+ void initMetricsLooper();
+
private:
String8 getSupportedPlugInId(int uniqueId, const String8& path, const String8& mimeType);
@@ -143,13 +183,24 @@
bool canHandle(int uniqueId, const String8& path);
+ void onMessageReceived(const sp<AMessage> &msg);
+
+ int64_t getMetricsFlushPeriodUs();
+
+ void recordEngineMetrics(const char func[],
+ const String8& plugInId, const String8& mimeType = String8(""));
+
+ void flushEngineMetrics();
+
private:
enum {
kMaxNumUniqueIds = 0x1000,
+ kWhatFlushMetrics = 'metr',
};
bool mUniqueIdArray[kMaxNumUniqueIds];
static const String8 EMPTY_STRING;
+ static const std::map<const char*, size_t> kMethodIdMap;
int mDecryptSessionId;
int mConvertId;
@@ -157,11 +208,15 @@
Mutex mListenerLock;
Mutex mDecryptLock;
Mutex mConvertLock;
+ Mutex mMetricsLock;
TPlugInManager<IDrmEngine> mPlugInManager;
KeyedVector< DrmSupportInfo, String8 > mSupportInfoToPlugInIdMap;
KeyedVector< int, IDrmEngine*> mConvertSessionMap;
KeyedVector< int, sp<IDrmServiceListener> > mServiceListeners;
KeyedVector< int, IDrmEngine*> mDecryptSessionMap;
+
+ std::map<std::pair<uid_t, std::string>, DrmManagerMetrics> mPluginMetrics;
+ sp<ALooper> mMetricsLooper;
};
};
diff --git a/drm/drmserver/DrmManagerService.cpp b/drm/drmserver/DrmManagerService.cpp
index 2600a2c..4b8b3f6 100644
--- a/drm/drmserver/DrmManagerService.cpp
+++ b/drm/drmserver/DrmManagerService.cpp
@@ -130,13 +130,14 @@
mDrmManager(NULL) {
ALOGV("created");
mDrmManager = new DrmManager();
+ mDrmManager->initMetricsLooper();
mDrmManager->loadPlugIns();
}
DrmManagerService::~DrmManagerService() {
ALOGV("Destroyed");
mDrmManager->unloadPlugIns();
- delete mDrmManager; mDrmManager = NULL;
+ mDrmManager = NULL;
}
int DrmManagerService::addUniqueId(bool isNative) {
diff --git a/drm/drmserver/DrmManagerService.h b/drm/drmserver/DrmManagerService.h
index 2e27a3c..f9b8bef 100644
--- a/drm/drmserver/DrmManagerService.h
+++ b/drm/drmserver/DrmManagerService.h
@@ -142,7 +142,7 @@
virtual status_t dump(int fd, const Vector<String16>& args);
private:
- DrmManager* mDrmManager;
+ sp<DrmManager> mDrmManager;
};
};
diff --git a/drm/libmediadrm/Android.bp b/drm/libmediadrm/Android.bp
index d6db1d4..1700a95 100644
--- a/drm/libmediadrm/Android.bp
+++ b/drm/libmediadrm/Android.bp
@@ -2,39 +2,67 @@
// libmediadrm
//
-// TODO: change it back to cc_library_shared when MediaPlayer2 switches to
-// using NdkMediaDrm, instead of MediaDrm.java.
-cc_library {
+cc_library_headers {
+ name: "libmediadrm_headers",
+
+ export_include_dirs: [
+ "interface"
+ ],
+
+}
+
+cc_library_shared {
name: "libmediadrm",
srcs: [
"DrmPluginPath.cpp",
"DrmSessionManager.cpp",
- "ICrypto.cpp",
- "IDrm.cpp",
- "IDrmClient.cpp",
- "IMediaDrmService.cpp",
"SharedLibrary.cpp",
"DrmHal.cpp",
"CryptoHal.cpp",
+ "DrmUtils.cpp",
+ ],
+
+ local_include_dirs: [
+ "include",
+ "interface"
+ ],
+
+ export_include_dirs: [
+ "include"
+ ],
+
+ header_libs: [
+ "libmedia_headers",
],
shared_libs: [
- "libbinder",
+ "libbinder_ndk",
"libcutils",
"libdl",
"liblog",
+ "libmedia",
"libmediadrmmetrics_lite",
- "libmediametrics",
+ "libmediametrics#1",
"libmediautils",
"libstagefright_foundation",
"libutils",
"android.hardware.drm@1.0",
"android.hardware.drm@1.1",
"android.hardware.drm@1.2",
+ "android.hardware.drm@1.3",
"libhidlallocatorutils",
"libhidlbase",
- "libhidltransport",
+ ],
+
+ static_libs: [
+ "resourcemanager_aidl_interface-ndk_platform",
+ ],
+
+ export_shared_lib_headers: [
+ "android.hardware.drm@1.0",
+ "android.hardware.drm@1.1",
+ "android.hardware.drm@1.2",
],
cflags: [
@@ -52,16 +80,21 @@
"protos/metrics.proto",
],
+ local_include_dirs: [
+ "include"
+ ],
+
proto: {
export_proto_headers: true,
type: "lite",
},
+ header_libs: [
+ "libmedia_headers",
+ ],
shared_libs: [
"android.hardware.drm@1.0",
"android.hardware.drm@1.1",
"android.hardware.drm@1.2",
- "libbinder",
- "libhidlbase",
"liblog",
"libmediametrics",
"libprotobuf-cpp-lite",
@@ -83,17 +116,22 @@
"protos/metrics.proto",
],
+ local_include_dirs: [
+ "include"
+ ],
+
proto: {
export_proto_headers: true,
type: "full",
},
+ header_libs: [
+ "libmedia_headers",
+ ],
shared_libs: [
"android.hardware.drm@1.0",
"android.hardware.drm@1.1",
"android.hardware.drm@1.2",
"libbase",
- "libbinder",
- "libhidlbase",
"liblog",
"libmediametrics",
"libprotobuf-cpp-full",
@@ -107,3 +145,30 @@
],
}
+cc_library_shared {
+ name: "libmediadrmmetrics_consumer",
+ srcs: [
+ "DrmMetricsConsumer.cpp",
+ ],
+
+ include_dirs: [
+ "frameworks/av/media/libmedia/include"
+ ],
+
+ shared_libs: [
+ "android.hardware.drm@1.0",
+ "android.hardware.drm@1.1",
+ "android.hardware.drm@1.2",
+ "libbinder",
+ "libhidlbase",
+ "liblog",
+ "libmediadrm",
+ "libmediadrmmetrics_full",
+ "libutils",
+ ],
+
+ header_libs: [
+ "libmediametrics_headers",
+ "libstagefright_foundation_headers",
+ ],
+}
diff --git a/drm/libmediadrm/CryptoHal.cpp b/drm/libmediadrm/CryptoHal.cpp
index d62ccd6..18772e0 100644
--- a/drm/libmediadrm/CryptoHal.cpp
+++ b/drm/libmediadrm/CryptoHal.cpp
@@ -19,9 +19,8 @@
#include <utils/Log.h>
#include <android/hardware/drm/1.0/types.h>
-#include <android/hidl/manager/1.0/IServiceManager.h>
-
-#include <binder/IMemory.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <hidl/ServiceManagement.h>
#include <hidlmemory/FrameworkUtils.h>
#include <media/hardware/CryptoAPI.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -45,9 +44,9 @@
using ::android::hardware::hidl_memory;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
+using ::android::hardware::HidlMemory;
using ::android::hardware::Return;
using ::android::hardware::Void;
-using ::android::hidl::manager::V1_0::IServiceManager;
using ::android::sp;
typedef drm::V1_2::Status Status_V1_2;
@@ -119,7 +118,6 @@
CryptoHal::CryptoHal()
: mFactories(makeCryptoFactories()),
mInitCheck((mFactories.size() == 0) ? ERROR_UNSUPPORTED : NO_INIT),
- mNextBufferId(0),
mHeapSeqNum(0) {
}
@@ -129,9 +127,9 @@
Vector<sp<ICryptoFactory>> CryptoHal::makeCryptoFactories() {
Vector<sp<ICryptoFactory>> factories;
- auto manager = ::IServiceManager::getService();
+ auto manager = hardware::defaultServiceManager1_2();
if (manager != NULL) {
- manager->listByInterface(drm::V1_0::ICryptoFactory::descriptor,
+ manager->listManifestByInterface(drm::V1_0::ICryptoFactory::descriptor,
[&factories](const hidl_vec<hidl_string> ®istered) {
for (const auto &instance : registered) {
auto factory = drm::V1_0::ICryptoFactory::getService(instance);
@@ -142,7 +140,7 @@
}
}
);
- manager->listByInterface(drm::V1_1::ICryptoFactory::descriptor,
+ manager->listManifestByInterface(drm::V1_1::ICryptoFactory::descriptor,
[&factories](const hidl_vec<hidl_string> ®istered) {
for (const auto &instance : registered) {
auto factory = drm::V1_1::ICryptoFactory::getService(instance);
@@ -252,26 +250,23 @@
/**
- * If the heap base isn't set, get the heap base from the IMemory
+ * If the heap base isn't set, get the heap base from the HidlMemory
* and send it to the HAL so it can map a remote heap of the same
* size. Once the heap base is established, shared memory buffers
* are sent by providing an offset into the heap and a buffer size.
*/
-int32_t CryptoHal::setHeapBase(const sp<IMemoryHeap>& heap) {
- using ::android::hardware::fromHeap;
- using ::android::hardware::HidlMemory;
-
- if (heap == NULL) {
- ALOGE("setHeapBase(): heap is NULL");
+int32_t CryptoHal::setHeapBase(const sp<HidlMemory>& heap) {
+ if (heap == NULL || mHeapSeqNum < 0) {
+ ALOGE("setHeapBase(): heap %p mHeapSeqNum %d", heap.get(), mHeapSeqNum);
return -1;
}
Mutex::Autolock autoLock(mLock);
int32_t seqNum = mHeapSeqNum++;
- sp<HidlMemory> hidlMemory = fromHeap(heap);
- mHeapBases.add(seqNum, HeapBase(mNextBufferId, heap->getSize()));
- Return<void> hResult = mPlugin->setSharedBufferBase(*hidlMemory, mNextBufferId++);
+ uint32_t bufferId = static_cast<uint32_t>(seqNum);
+ mHeapSizes.add(seqNum, heap->size());
+ Return<void> hResult = mPlugin->setSharedBufferBase(*heap, bufferId);
ALOGE_IF(!hResult.isOk(), "setSharedBufferBase(): remote call failed");
return seqNum;
}
@@ -286,60 +281,40 @@
* TODO: Add a releaseSharedBuffer method in a future DRM HAL
* API version to make this explicit.
*/
- ssize_t index = mHeapBases.indexOfKey(seqNum);
+ ssize_t index = mHeapSizes.indexOfKey(seqNum);
if (index >= 0) {
if (mPlugin != NULL) {
- uint32_t bufferId = mHeapBases[index].getBufferId();
+ uint32_t bufferId = static_cast<uint32_t>(seqNum);
Return<void> hResult = mPlugin->setSharedBufferBase(hidl_memory(), bufferId);
ALOGE_IF(!hResult.isOk(), "setSharedBufferBase(): remote call failed");
}
- mHeapBases.removeItem(seqNum);
+ mHeapSizes.removeItem(seqNum);
}
}
-status_t CryptoHal::toSharedBuffer(const sp<IMemory>& memory, int32_t seqNum, ::SharedBuffer* buffer) {
- ssize_t offset;
- size_t size;
-
- if (memory == NULL || buffer == NULL) {
- return UNEXPECTED_NULL;
- }
-
- sp<IMemoryHeap> heap = memory->getMemory(&offset, &size);
- if (heap == NULL) {
- return UNEXPECTED_NULL;
- }
-
+status_t CryptoHal::checkSharedBuffer(const ::SharedBuffer &buffer) {
+ int32_t seqNum = static_cast<int32_t>(buffer.bufferId);
// memory must be in one of the heaps that have been set
- if (mHeapBases.indexOfKey(seqNum) < 0) {
+ if (mHeapSizes.indexOfKey(seqNum) < 0) {
return UNKNOWN_ERROR;
}
- // heap must be the same size as the one that was set in setHeapBase
- if (mHeapBases.valueFor(seqNum).getSize() != heap->getSize()) {
- android_errorWriteLog(0x534e4554, "76221123");
- return UNKNOWN_ERROR;
- }
-
// memory must be within the address space of the heap
- if (memory->pointer() != static_cast<uint8_t *>(heap->getBase()) + memory->offset() ||
- heap->getSize() < memory->offset() + memory->size() ||
- SIZE_MAX - memory->offset() < memory->size()) {
+ size_t heapSize = mHeapSizes.valueFor(seqNum);
+ if (heapSize < buffer.offset + buffer.size ||
+ SIZE_MAX - buffer.offset < buffer.size) {
android_errorWriteLog(0x534e4554, "76221123");
return UNKNOWN_ERROR;
}
- buffer->bufferId = mHeapBases.valueFor(seqNum).getBufferId();
- buffer->offset = offset >= 0 ? offset : 0;
- buffer->size = size;
return OK;
}
ssize_t CryptoHal::decrypt(const uint8_t keyId[16], const uint8_t iv[16],
CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
- const ICrypto::SourceBuffer &source, size_t offset,
+ const ::SharedBuffer &hSource, size_t offset,
const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
- const ICrypto::DestinationBuffer &destination, AString *errorDetailMsg) {
+ const ::DestinationBuffer &hDestination, AString *errorDetailMsg) {
Mutex::Autolock autoLock(mLock);
if (mInitCheck != OK) {
@@ -377,28 +352,21 @@
}
auto hSubSamples = hidl_vec<SubSample>(stdSubSamples);
- int32_t heapSeqNum = source.mHeapSeqNum;
bool secure;
- ::DestinationBuffer hDestination;
- if (destination.mType == kDestinationTypeSharedMemory) {
- hDestination.type = BufferType::SHARED_MEMORY;
- status_t status = toSharedBuffer(destination.mSharedMemory, heapSeqNum,
- &hDestination.nonsecureMemory);
+ if (hDestination.type == BufferType::SHARED_MEMORY) {
+ status_t status = checkSharedBuffer(hDestination.nonsecureMemory);
if (status != OK) {
return status;
}
secure = false;
- } else if (destination.mType == kDestinationTypeNativeHandle) {
- hDestination.type = BufferType::NATIVE_HANDLE;
- hDestination.secureMemory = hidl_handle(destination.mHandle);
+ } else if (hDestination.type == BufferType::NATIVE_HANDLE) {
secure = true;
} else {
android_errorWriteLog(0x534e4554, "70526702");
return UNKNOWN_ERROR;
}
- ::SharedBuffer hSource;
- status_t status = toSharedBuffer(source.mSharedMemory, heapSeqNum, &hSource);
+ status_t status = checkSharedBuffer(hSource);
if (status != OK) {
return status;
}
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index 919f4ee..f218041 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -20,14 +20,14 @@
#include <utils/Log.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
+#include <android/binder_manager.h>
+#include <aidl/android/media/BnResourceManagerClient.h>
#include <android/hardware/drm/1.2/types.h>
#include <android/hidl/manager/1.2/IServiceManager.h>
#include <hidl/ServiceManagement.h>
-
#include <media/EventMetric.h>
+#include <media/MediaMetrics.h>
#include <media/PluginMetricsReporting.h>
#include <media/drm/DrmAPI.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -38,6 +38,10 @@
#include <mediadrm/DrmHal.h>
#include <mediadrm/DrmSessionClientInterface.h>
#include <mediadrm/DrmSessionManager.h>
+#include <mediadrm/IDrmMetricsConsumer.h>
+#include <mediadrm/DrmUtils.h>
+
+#include <vector>
using drm::V1_0::KeyedVector;
using drm::V1_0::KeyRequestType;
@@ -57,7 +61,6 @@
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
-using ::android::hidl::manager::V1_0::IServiceManager;
using ::android::os::PersistableBundle;
using ::android::sp;
@@ -97,17 +100,6 @@
#define INIT_CHECK() {if (mInitCheck != OK) return mInitCheck;}
-static inline int getCallingPid() {
- return IPCThreadState::self()->getCallingPid();
-}
-
-static bool checkPermission(const char* permissionString) {
- if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
- bool ok = checkCallingPermission(String16(permissionString));
- if (!ok) ALOGE("Request requires %s", permissionString);
- return ok;
-}
-
static const Vector<uint8_t> toVector(const hidl_vec<uint8_t> &vec) {
Vector<uint8_t> vector;
vector.appendArray(vec.data(), vec.size());
@@ -295,28 +287,19 @@
}
}
-
Mutex DrmHal::mLock;
-struct DrmSessionClient : public DrmSessionClientInterface {
- explicit DrmSessionClient(DrmHal* drm) : mDrm(drm) {}
+struct DrmHal::DrmSessionClient : public aidl::android::media::BnResourceManagerClient {
+ explicit DrmSessionClient(DrmHal* drm, const Vector<uint8_t>& sessionId)
+ : mSessionId(sessionId),
+ mDrm(drm) {}
- virtual bool reclaimSession(const Vector<uint8_t>& sessionId) {
- sp<DrmHal> drm = mDrm.promote();
- if (drm == NULL) {
- return true;
- }
- status_t err = drm->closeSession(sessionId);
- if (err != OK) {
- return false;
- }
- drm->sendEvent(EventType::SESSION_RECLAIMED,
- toHidlVec(sessionId), hidl_vec<uint8_t>());
- return true;
- }
+ ::ndk::ScopedAStatus reclaimResource(bool* _aidl_return) override;
+ ::ndk::ScopedAStatus getName(::std::string* _aidl_return) override;
-protected:
- virtual ~DrmSessionClient() {}
+ const Vector<uint8_t> mSessionId;
+
+ virtual ~DrmSessionClient();
private:
wp<DrmHal> mDrm;
@@ -324,9 +307,48 @@
DISALLOW_EVIL_CONSTRUCTORS(DrmSessionClient);
};
+::ndk::ScopedAStatus DrmHal::DrmSessionClient::reclaimResource(bool* _aidl_return) {
+ auto sessionId = mSessionId;
+ sp<DrmHal> drm = mDrm.promote();
+ if (drm == NULL) {
+ *_aidl_return = true;
+ return ::ndk::ScopedAStatus::ok();
+ }
+ status_t err = drm->closeSession(sessionId);
+ if (err != OK) {
+ *_aidl_return = false;
+ return ::ndk::ScopedAStatus::ok();
+ }
+ drm->sendEvent(EventType::SESSION_RECLAIMED,
+ toHidlVec(sessionId), hidl_vec<uint8_t>());
+ *_aidl_return = true;
+ return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus DrmHal::DrmSessionClient::getName(::std::string* _aidl_return) {
+ String8 name;
+ sp<DrmHal> drm = mDrm.promote();
+ if (drm == NULL) {
+ name.append("<deleted>");
+ } else if (drm->getPropertyStringInternal(String8("vendor"), name) != OK
+ || name.isEmpty()) {
+ name.append("<Get vendor failed or is empty>");
+ }
+ name.append("[");
+ for (size_t i = 0; i < mSessionId.size(); ++i) {
+ name.appendFormat("%02x", mSessionId[i]);
+ }
+ name.append("]");
+ *_aidl_return = name;
+ return ::ndk::ScopedAStatus::ok();
+}
+
+DrmHal::DrmSessionClient::~DrmSessionClient() {
+ DrmSessionManager::Instance()->removeSession(mSessionId);
+}
+
DrmHal::DrmHal()
- : mDrmSessionClient(new DrmSessionClient(this)),
- mFactories(makeDrmFactories()),
+ : mFactories(makeDrmFactories()),
mInitCheck((mFactories.size() == 0) ? ERROR_UNSUPPORTED : NO_INIT) {
}
@@ -335,14 +357,13 @@
auto openSessions = mOpenSessions;
for (size_t i = 0; i < openSessions.size(); i++) {
mLock.unlock();
- closeSession(openSessions[i]);
+ closeSession(openSessions[i]->mSessionId);
mLock.lock();
}
mOpenSessions.clear();
}
DrmHal::~DrmHal() {
- DrmSessionManager::Instance()->removeDrm(mDrmSessionClient);
}
void DrmHal::cleanup() {
@@ -368,44 +389,8 @@
mPluginV1_2.clear();
}
-Vector<sp<IDrmFactory>> DrmHal::makeDrmFactories() {
- Vector<sp<IDrmFactory>> factories;
-
- auto manager = hardware::defaultServiceManager1_2();
-
- if (manager != NULL) {
- manager->listManifestByInterface(drm::V1_0::IDrmFactory::descriptor,
- [&factories](const hidl_vec<hidl_string> ®istered) {
- for (const auto &instance : registered) {
- auto factory = drm::V1_0::IDrmFactory::getService(instance);
- if (factory != NULL) {
- factories.push_back(factory);
- }
- }
- }
- );
- manager->listManifestByInterface(drm::V1_1::IDrmFactory::descriptor,
- [&factories](const hidl_vec<hidl_string> ®istered) {
- for (const auto &instance : registered) {
- auto factory = drm::V1_1::IDrmFactory::getService(instance);
- if (factory != NULL) {
- factories.push_back(factory);
- }
- }
- }
- );
- manager->listByInterface(drm::V1_2::IDrmFactory::descriptor,
- [&factories](const hidl_vec<hidl_string> ®istered) {
- for (const auto &instance : registered) {
- auto factory = drm::V1_2::IDrmFactory::getService(instance);
- if (factory != NULL) {
- factories.push_back(factory);
- }
- }
- }
- );
- }
-
+std::vector<sp<IDrmFactory>> DrmHal::makeDrmFactories() {
+ std::vector<sp<IDrmFactory>> factories(DrmUtils::MakeDrmFactories());
if (factories.size() == 0) {
// must be in passthrough mode, load the default passthrough service
auto passthrough = IDrmFactory::getService();
@@ -423,6 +408,7 @@
const uint8_t uuid[16], const String8& appPackageName) {
mAppPackageName = appPackageName;
mMetrics.SetAppPackageName(appPackageName);
+ mMetrics.SetAppUid(AIBinder_getCallingUid());
sp<IDrmPlugin> plugin;
Return<void> hResult = factory->createPlugin(uuid, appPackageName.string(),
@@ -449,12 +435,6 @@
status_t DrmHal::setListener(const sp<IDrmClient>& listener)
{
Mutex::Autolock lock(mEventLock);
- if (mListener != NULL){
- IInterface::asBinder(mListener)->unlinkToDeath(this);
- }
- if (listener != NULL) {
- IInterface::asBinder(listener)->linkToDeath(this);
- }
mListener = listener;
return NO_ERROR;
}
@@ -468,10 +448,6 @@
mEventLock.unlock();
if (listener != NULL) {
- Parcel obj;
- writeByteArray(obj, sessionId);
- writeByteArray(obj, data);
-
Mutex::Autolock lock(mNotifyLock);
DrmPlugin::EventType eventType;
switch(hEventType) {
@@ -493,7 +469,7 @@
default:
return Void();
}
- listener->notify(eventType, 0, &obj);
+ listener->sendEvent(eventType, sessionId, data);
}
return Void();
}
@@ -506,12 +482,8 @@
mEventLock.unlock();
if (listener != NULL) {
- Parcel obj;
- writeByteArray(obj, sessionId);
- obj.writeInt64(expiryTimeInMS);
-
Mutex::Autolock lock(mNotifyLock);
- listener->notify(DrmPlugin::kDrmPluginEventExpirationUpdate, 0, &obj);
+ listener->sendExpirationUpdate(sessionId, expiryTimeInMS);
}
return Void();
}
@@ -528,21 +500,17 @@
}
Return<void> DrmHal::sendKeysChange_1_2(const hidl_vec<uint8_t>& sessionId,
- const hidl_vec<KeyStatus>& keyStatusList, bool hasNewUsableKey) {
+ const hidl_vec<KeyStatus>& hKeyStatusList, bool hasNewUsableKey) {
mEventLock.lock();
sp<IDrmClient> listener = mListener;
mEventLock.unlock();
if (listener != NULL) {
- Parcel obj;
- writeByteArray(obj, sessionId);
-
- size_t nKeys = keyStatusList.size();
- obj.writeInt32(nKeys);
+ std::vector<DrmKeyStatus> keyStatusList;
+ size_t nKeys = hKeyStatusList.size();
for (size_t i = 0; i < nKeys; ++i) {
- const KeyStatus &keyStatus = keyStatusList[i];
- writeByteArray(obj, keyStatus.keyId);
+ const KeyStatus &keyStatus = hKeyStatusList[i];
uint32_t type;
switch(keyStatus.type) {
case KeyStatusType::USABLE:
@@ -565,19 +533,18 @@
type = DrmPlugin::kKeyStatusType_InternalError;
break;
}
- obj.writeInt32(type);
+ keyStatusList.push_back({type, keyStatus.keyId});
mMetrics.mKeyStatusChangeCounter.Increment(keyStatus.type);
}
- obj.writeInt32(hasNewUsableKey);
Mutex::Autolock lock(mNotifyLock);
- listener->notify(DrmPlugin::kDrmPluginEventKeysChange, 0, &obj);
+ listener->sendKeysChange(sessionId, keyStatusList, hasNewUsableKey);
} else {
// There's no listener. But we still want to count the key change
// events.
- size_t nKeys = keyStatusList.size();
+ size_t nKeys = hKeyStatusList.size();
for (size_t i = 0; i < nKeys; i++) {
- mMetrics.mKeyStatusChangeCounter.Increment(keyStatusList[i].type);
+ mMetrics.mKeyStatusChangeCounter.Increment(hKeyStatusList[i].type);
}
}
@@ -592,10 +559,8 @@
mEventLock.unlock();
if (listener != NULL) {
- Parcel obj;
- writeByteArray(obj, sessionId);
Mutex::Autolock lock(mNotifyLock);
- listener->notify(DrmPlugin::kDrmPluginEventSessionLostState, 0, &obj);
+ listener->sendSessionLostState(sessionId);
}
return Void();
}
@@ -740,7 +705,7 @@
// reclaimSession may call back to closeSession, since mLock is
// shared between Drm instances, we should unlock here to avoid
// deadlock.
- retry = DrmSessionManager::Instance()->reclaimSession(getCallingPid());
+ retry = DrmSessionManager::Instance()->reclaimSession(AIBinder_getCallingPid());
mLock.lock();
} else {
retry = false;
@@ -748,9 +713,11 @@
} while (retry);
if (err == OK) {
- DrmSessionManager::Instance()->addSession(getCallingPid(),
- mDrmSessionClient, sessionId);
- mOpenSessions.push(sessionId);
+ std::shared_ptr<DrmSessionClient> client =
+ ndk::SharedRefBase::make<DrmSessionClient>(this, sessionId);
+ DrmSessionManager::Instance()->addSession(AIBinder_getCallingPid(),
+ std::static_pointer_cast<IResourceManagerClient>(client), sessionId);
+ mOpenSessions.push_back(client);
mMetrics.SetSessionStart(sessionId);
}
@@ -766,9 +733,9 @@
if (status.isOk()) {
if (status == Status::OK) {
DrmSessionManager::Instance()->removeSession(sessionId);
- for (size_t i = 0; i < mOpenSessions.size(); i++) {
- if (mOpenSessions[i] == sessionId) {
- mOpenSessions.removeAt(i);
+ for (auto i = mOpenSessions.begin(); i != mOpenSessions.end(); i++) {
+ if (isEqualSessionId((*i)->mSessionId, sessionId)) {
+ mOpenSessions.erase(i);
break;
}
}
@@ -895,9 +862,8 @@
status_t DrmHal::provideKeyResponse(Vector<uint8_t> const &sessionId,
Vector<uint8_t> const &response, Vector<uint8_t> &keySetId) {
Mutex::Autolock autoLock(mLock);
- EventTimer<status_t> keyResponseTimer(&mMetrics.mProvideKeyResponseTimeUs);
-
INIT_CHECK();
+ EventTimer<status_t> keyResponseTimer(&mMetrics.mProvideKeyResponseTimeUs);
DrmSessionManager::Instance()->useSession(sessionId);
@@ -1363,11 +1329,11 @@
return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
}
-status_t DrmHal::getMetrics(PersistableBundle* metrics) {
- if (metrics == nullptr) {
+status_t DrmHal::getMetrics(const sp<IDrmMetricsConsumer> &consumer) {
+ if (consumer == nullptr) {
return UNEXPECTED_NULL;
}
- mMetrics.Export(metrics);
+ consumer->consumeFrameworkMetrics(mMetrics);
// Append vendor metrics if they are supported.
if (mPluginV1_1 != NULL) {
@@ -1394,11 +1360,7 @@
if (status != Status::OK) {
ALOGV("Error getting plugin metrics: %d", status);
} else {
- PersistableBundle pluginBundle;
- if (MediaDrmMetrics::HidlMetricsToBundle(
- pluginMetrics, &pluginBundle) == OK) {
- metrics->putPersistableBundle(String16(vendor), pluginBundle);
- }
+ consumer->consumeHidlMetrics(vendor, pluginMetrics);
}
err = toStatusT(status);
});
@@ -1532,10 +1494,6 @@
Mutex::Autolock autoLock(mLock);
INIT_CHECK();
- if (!checkPermission("android.permission.ACCESS_DRM_CERTIFICATES")) {
- return -EPERM;
- }
-
DrmSessionManager::Instance()->useSession(sessionId);
status_t err = UNKNOWN_ERROR;
@@ -1553,39 +1511,23 @@
return hResult.isOk() ? err : DEAD_OBJECT;
}
-void DrmHal::binderDied(const wp<IBinder> &the_late_who __unused)
-{
- cleanup();
-}
-
-void DrmHal::writeByteArray(Parcel &obj, hidl_vec<uint8_t> const &vec)
-{
- if (vec.size()) {
- obj.writeInt32(vec.size());
- obj.write(vec.data(), vec.size());
- } else {
- obj.writeInt32(0);
- }
-}
-
void DrmHal::reportFrameworkMetrics() const
{
- std::unique_ptr<MediaAnalyticsItem> item(MediaAnalyticsItem::create("mediadrm"));
- item->generateSessionID();
- item->setPkgName(mMetrics.GetAppPackageName().c_str());
+ mediametrics_handle_t item(mediametrics_create("mediadrm"));
+ mediametrics_setUid(item, mMetrics.GetAppUid());
String8 vendor;
String8 description;
status_t result = getPropertyStringInternal(String8("vendor"), vendor);
if (result != OK) {
ALOGE("Failed to get vendor from drm plugin: %d", result);
} else {
- item->setCString("vendor", vendor.c_str());
+ mediametrics_setCString(item, "vendor", vendor.c_str());
}
result = getPropertyStringInternal(String8("description"), description);
if (result != OK) {
ALOGE("Failed to get description from drm plugin: %d", result);
} else {
- item->setCString("description", description.c_str());
+ mediametrics_setCString(item, "description", description.c_str());
}
std::string serializedMetrics;
@@ -1596,11 +1538,12 @@
std::string b64EncodedMetrics = toBase64StringNoPad(serializedMetrics.data(),
serializedMetrics.size());
if (!b64EncodedMetrics.empty()) {
- item->setCString("serialized_metrics", b64EncodedMetrics.c_str());
+ mediametrics_setCString(item, "serialized_metrics", b64EncodedMetrics.c_str());
}
- if (!item->selfrecord()) {
+ if (!mediametrics_selfRecord(item)) {
ALOGE("Failed to self record framework metrics");
}
+ mediametrics_delete(item);
}
void DrmHal::reportPluginMetrics() const
@@ -1614,7 +1557,7 @@
std::string metricsString = toBase64StringNoPad(metricsVector.array(),
metricsVector.size());
status_t res = android::reportDrmPluginMetrics(metricsString, vendor,
- description, mAppPackageName);
+ description, mMetrics.GetAppUid());
if (res != OK) {
ALOGE("Metrics were retrieved but could not be reported: %d", res);
}
diff --git a/drm/libmediadrm/DrmMetrics.cpp b/drm/libmediadrm/DrmMetrics.cpp
index 3080802..996fd19 100644
--- a/drm/libmediadrm/DrmMetrics.cpp
+++ b/drm/libmediadrm/DrmMetrics.cpp
@@ -29,143 +29,12 @@
using ::android::String16;
using ::android::String8;
using ::android::drm_metrics::DrmFrameworkMetrics;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
using ::android::hardware::drm::V1_0::EventType;
using ::android::hardware::drm::V1_2::KeyStatusType;
using ::android::hardware::drm::V1_1::DrmMetricGroup;
-using ::android::os::PersistableBundle;
namespace {
-template <typename T> std::string GetAttributeName(T type);
-
-template <> std::string GetAttributeName<KeyStatusType>(KeyStatusType type) {
- static const char *type_names[] = {"USABLE", "EXPIRED",
- "OUTPUT_NOT_ALLOWED", "STATUS_PENDING",
- "INTERNAL_ERROR"};
- if (((size_t)type) > arraysize(type_names)) {
- return "UNKNOWN_TYPE";
- }
- return type_names[(size_t)type];
-}
-
-template <> std::string GetAttributeName<EventType>(EventType type) {
- static const char *type_names[] = {"PROVISION_REQUIRED", "KEY_NEEDED",
- "KEY_EXPIRED", "VENDOR_DEFINED",
- "SESSION_RECLAIMED"};
- if (((size_t)type) > arraysize(type_names)) {
- return "UNKNOWN_TYPE";
- }
- return type_names[(size_t)type];
-}
-
-template <typename T>
-void ExportCounterMetric(const android::CounterMetric<T> &counter,
- PersistableBundle *metrics) {
- if (!metrics) {
- ALOGE("metrics was unexpectedly null.");
- return;
- }
- std::string success_count_name = counter.metric_name() + ".ok.count";
- std::string error_count_name = counter.metric_name() + ".error.count";
- std::vector<int64_t> status_values;
- counter.ExportValues(
- [&](const android::status_t status, const int64_t value) {
- if (status == android::OK) {
- metrics->putLong(android::String16(success_count_name.c_str()),
- value);
- } else {
- int64_t total_errors(0);
- metrics->getLong(android::String16(error_count_name.c_str()),
- &total_errors);
- metrics->putLong(android::String16(error_count_name.c_str()),
- total_errors + value);
- status_values.push_back(status);
- }
- });
- if (!status_values.empty()) {
- std::string error_list_name = counter.metric_name() + ".error.list";
- metrics->putLongVector(android::String16(error_list_name.c_str()),
- status_values);
- }
-}
-
-template <typename T>
-void ExportCounterMetricWithAttributeNames(
- const android::CounterMetric<T> &counter, PersistableBundle *metrics) {
- if (!metrics) {
- ALOGE("metrics was unexpectedly null.");
- return;
- }
- counter.ExportValues([&](const T &attribute, const int64_t value) {
- std::string name = counter.metric_name() + "." +
- GetAttributeName(attribute) + ".count";
- metrics->putLong(android::String16(name.c_str()), value);
- });
-}
-
-template <typename T>
-void ExportEventMetric(const android::EventMetric<T> &event,
- PersistableBundle *metrics) {
- if (!metrics) {
- ALOGE("metrics was unexpectedly null.");
- return;
- }
- std::string success_count_name = event.metric_name() + ".ok.count";
- std::string error_count_name = event.metric_name() + ".error.count";
- std::string timing_name = event.metric_name() + ".ok.average_time_micros";
- std::vector<int64_t> status_values;
- event.ExportValues([&](const android::status_t &status,
- const android::EventStatistics &value) {
- if (status == android::OK) {
- metrics->putLong(android::String16(success_count_name.c_str()),
- value.count);
- metrics->putLong(android::String16(timing_name.c_str()),
- value.mean);
- } else {
- int64_t total_errors(0);
- metrics->getLong(android::String16(error_count_name.c_str()),
- &total_errors);
- metrics->putLong(android::String16(error_count_name.c_str()),
- total_errors + value.count);
- status_values.push_back(status);
- }
- });
- if (!status_values.empty()) {
- std::string error_list_name = event.metric_name() + ".error.list";
- metrics->putLongVector(android::String16(error_list_name.c_str()),
- status_values);
- }
-}
-
-void ExportSessionLifespans(
- const std::map<std::string, std::pair<int64_t, int64_t>> &mSessionLifespans,
- PersistableBundle *metrics) {
- if (!metrics) {
- ALOGE("metrics was unexpectedly null.");
- return;
- }
-
- if (mSessionLifespans.empty()) {
- return;
- }
-
- PersistableBundle startTimesBundle;
- PersistableBundle endTimesBundle;
- for (auto it = mSessionLifespans.begin(); it != mSessionLifespans.end();
- it++) {
- String16 key(it->first.c_str(), it->first.size());
- startTimesBundle.putLong(key, it->second.first);
- endTimesBundle.putLong(key, it->second.second);
- }
- metrics->putPersistableBundle(
- android::String16("drm.mediadrm.session_start_times_ms"),
- startTimesBundle);
- metrics->putPersistableBundle(
- android::String16("drm.mediadrm.session_end_times_ms"), endTimesBundle);
-}
-
std::string ToHexString(const android::Vector<uint8_t> &sessionId) {
std::ostringstream out;
out << std::hex << std::setfill('0');
@@ -175,31 +44,6 @@
return out.str();
}
-template <typename CT>
-void SetValue(const String16 &name, DrmMetricGroup::ValueType type,
- const CT &value, PersistableBundle *bundle) {
- switch (type) {
- case DrmMetricGroup::ValueType::INT64_TYPE:
- bundle->putLong(name, value.int64Value);
- break;
- case DrmMetricGroup::ValueType::DOUBLE_TYPE:
- bundle->putDouble(name, value.doubleValue);
- break;
- case DrmMetricGroup::ValueType::STRING_TYPE:
- bundle->putString(name, String16(value.stringValue.c_str()));
- break;
- default:
- ALOGE("Unexpected value type: %hhu", type);
- }
-}
-
-inline String16 MakeIndexString(unsigned int index) {
- std::string str("[");
- str.append(std::to_string(index));
- str.append("]");
- return String16(str.c_str());
-}
-
} // namespace
namespace android {
@@ -237,23 +81,6 @@
}
}
-void MediaDrmMetrics::Export(PersistableBundle *metrics) {
- if (!metrics) {
- ALOGE("metrics was unexpectedly null.");
- return;
- }
- ExportCounterMetric(mOpenSessionCounter, metrics);
- ExportCounterMetric(mCloseSessionCounter, metrics);
- ExportEventMetric(mGetKeyRequestTimeUs, metrics);
- ExportEventMetric(mProvideKeyResponseTimeUs, metrics);
- ExportCounterMetric(mGetProvisionRequestCounter, metrics);
- ExportCounterMetric(mProvideProvisionResponseCounter, metrics);
- ExportCounterMetricWithAttributeNames(mKeyStatusChangeCounter, metrics);
- ExportCounterMetricWithAttributeNames(mEventCounter, metrics);
- ExportCounterMetric(mGetDeviceUniqueIdCounter, metrics);
- ExportSessionLifespans(mSessionLifespans, metrics);
-}
-
status_t MediaDrmMetrics::GetSerializedMetrics(std::string *serializedMetrics) {
if (!serializedMetrics) {
@@ -361,62 +188,14 @@
return OK;
}
+std::map<std::string, std::pair<int64_t, int64_t>> MediaDrmMetrics::GetSessionLifespans() const {
+ return mSessionLifespans;
+}
+
int64_t MediaDrmMetrics::GetCurrentTimeMs() {
struct timeval tv;
gettimeofday(&tv, NULL);
return ((int64_t)tv.tv_sec * 1000) + ((int64_t)tv.tv_usec / 1000);
}
-status_t MediaDrmMetrics::HidlMetricsToBundle(
- const hidl_vec<DrmMetricGroup> &hidlMetricGroups,
- PersistableBundle *bundleMetricGroups) {
- if (bundleMetricGroups == nullptr) {
- return UNEXPECTED_NULL;
- }
- if (hidlMetricGroups.size() == 0) {
- return OK;
- }
-
- int groupIndex = 0;
- std::map<String16, int> indexMap;
- for (const auto &hidlMetricGroup : hidlMetricGroups) {
- PersistableBundle bundleMetricGroup;
- for (const auto &hidlMetric : hidlMetricGroup.metrics) {
- String16 metricName(hidlMetric.name.c_str());
- PersistableBundle bundleMetric;
- // Add metric component values.
- for (const auto &value : hidlMetric.values) {
- SetValue(String16(value.componentName.c_str()), value.type,
- value, &bundleMetric);
- }
- // Set metric attributes.
- PersistableBundle bundleMetricAttributes;
- for (const auto &attribute : hidlMetric.attributes) {
- SetValue(String16(attribute.name.c_str()), attribute.type,
- attribute, &bundleMetricAttributes);
- }
- // Add attributes to the bundle metric.
- bundleMetric.putPersistableBundle(String16("attributes"),
- bundleMetricAttributes);
- // Add one layer of indirection, allowing for repeated metric names.
- PersistableBundle repeatedMetrics;
- bundleMetricGroup.getPersistableBundle(metricName,
- &repeatedMetrics);
- int index = indexMap[metricName];
- repeatedMetrics.putPersistableBundle(MakeIndexString(index),
- bundleMetric);
- indexMap[metricName] = ++index;
-
- // Add the bundle metric to the group of metrics.
- bundleMetricGroup.putPersistableBundle(metricName,
- repeatedMetrics);
- }
- // Add the bundle metric group to the collection of groups.
- bundleMetricGroups->putPersistableBundle(MakeIndexString(groupIndex++),
- bundleMetricGroup);
- }
-
- return OK;
-}
-
} // namespace android
diff --git a/drm/libmediadrm/DrmMetricsConsumer.cpp b/drm/libmediadrm/DrmMetricsConsumer.cpp
new file mode 100644
index 0000000..b47b4ff
--- /dev/null
+++ b/drm/libmediadrm/DrmMetricsConsumer.cpp
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "DrmMetricsConsumer"
+
+#include <android-base/macros.h>
+#include <mediadrm/DrmMetricsConsumer.h>
+#include <mediadrm/DrmMetrics.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+
+using ::android::String16;
+using ::android::String8;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::drm::V1_0::EventType;
+using ::android::hardware::drm::V1_2::KeyStatusType;
+using ::android::hardware::drm::V1_1::DrmMetricGroup;
+using ::android::os::PersistableBundle;
+
+namespace {
+
+template <typename T> std::string GetAttributeName(T type);
+
+template <> std::string GetAttributeName<KeyStatusType>(KeyStatusType type) {
+ static const char *type_names[] = {"USABLE", "EXPIRED",
+ "OUTPUT_NOT_ALLOWED", "STATUS_PENDING",
+ "INTERNAL_ERROR"};
+ if (((size_t)type) > arraysize(type_names)) {
+ return "UNKNOWN_TYPE";
+ }
+ return type_names[(size_t)type];
+}
+
+template <> std::string GetAttributeName<EventType>(EventType type) {
+ static const char *type_names[] = {"PROVISION_REQUIRED", "KEY_NEEDED",
+ "KEY_EXPIRED", "VENDOR_DEFINED",
+ "SESSION_RECLAIMED"};
+ if (((size_t)type) > arraysize(type_names)) {
+ return "UNKNOWN_TYPE";
+ }
+ return type_names[(size_t)type];
+}
+
+template <typename T>
+void ExportCounterMetric(const android::CounterMetric<T> &counter,
+ PersistableBundle *metrics) {
+ if (!metrics) {
+ ALOGE("metrics was unexpectedly null.");
+ return;
+ }
+ std::string success_count_name = counter.metric_name() + ".ok.count";
+ std::string error_count_name = counter.metric_name() + ".error.count";
+ std::vector<int64_t> status_values;
+ counter.ExportValues(
+ [&](const android::status_t status, const int64_t value) {
+ if (status == android::OK) {
+ metrics->putLong(android::String16(success_count_name.c_str()),
+ value);
+ } else {
+ int64_t total_errors(0);
+ metrics->getLong(android::String16(error_count_name.c_str()),
+ &total_errors);
+ metrics->putLong(android::String16(error_count_name.c_str()),
+ total_errors + value);
+ status_values.push_back(status);
+ }
+ });
+ if (!status_values.empty()) {
+ std::string error_list_name = counter.metric_name() + ".error.list";
+ metrics->putLongVector(android::String16(error_list_name.c_str()),
+ status_values);
+ }
+}
+
+template <typename T>
+void ExportCounterMetricWithAttributeNames(
+ const android::CounterMetric<T> &counter, PersistableBundle *metrics) {
+ if (!metrics) {
+ ALOGE("metrics was unexpectedly null.");
+ return;
+ }
+ counter.ExportValues([&](const T &attribute, const int64_t value) {
+ std::string name = counter.metric_name() + "." +
+ GetAttributeName(attribute) + ".count";
+ metrics->putLong(android::String16(name.c_str()), value);
+ });
+}
+
+template <typename T>
+void ExportEventMetric(const android::EventMetric<T> &event,
+ PersistableBundle *metrics) {
+ if (!metrics) {
+ ALOGE("metrics was unexpectedly null.");
+ return;
+ }
+ std::string success_count_name = event.metric_name() + ".ok.count";
+ std::string error_count_name = event.metric_name() + ".error.count";
+ std::string timing_name = event.metric_name() + ".ok.average_time_micros";
+ std::vector<int64_t> status_values;
+ event.ExportValues([&](const android::status_t &status,
+ const android::EventStatistics &value) {
+ if (status == android::OK) {
+ metrics->putLong(android::String16(success_count_name.c_str()),
+ value.count);
+ metrics->putLong(android::String16(timing_name.c_str()),
+ value.mean);
+ } else {
+ int64_t total_errors(0);
+ metrics->getLong(android::String16(error_count_name.c_str()),
+ &total_errors);
+ metrics->putLong(android::String16(error_count_name.c_str()),
+ total_errors + value.count);
+ status_values.push_back(status);
+ }
+ });
+ if (!status_values.empty()) {
+ std::string error_list_name = event.metric_name() + ".error.list";
+ metrics->putLongVector(android::String16(error_list_name.c_str()),
+ status_values);
+ }
+}
+
+void ExportSessionLifespans(
+ const std::map<std::string, std::pair<int64_t, int64_t>> &sessionLifespans,
+ PersistableBundle *metrics) {
+ if (!metrics) {
+ ALOGE("metrics was unexpectedly null.");
+ return;
+ }
+
+ if (sessionLifespans.empty()) {
+ return;
+ }
+
+ PersistableBundle startTimesBundle;
+ PersistableBundle endTimesBundle;
+ for (auto it = sessionLifespans.begin(); it != sessionLifespans.end();
+ it++) {
+ String16 key(it->first.c_str(), it->first.size());
+ startTimesBundle.putLong(key, it->second.first);
+ endTimesBundle.putLong(key, it->second.second);
+ }
+ metrics->putPersistableBundle(
+ android::String16("drm.mediadrm.session_start_times_ms"),
+ startTimesBundle);
+ metrics->putPersistableBundle(
+ android::String16("drm.mediadrm.session_end_times_ms"), endTimesBundle);
+}
+
+template <typename CT>
+void SetValue(const String16 &name, DrmMetricGroup::ValueType type,
+ const CT &value, PersistableBundle *bundle) {
+ switch (type) {
+ case DrmMetricGroup::ValueType::INT64_TYPE:
+ bundle->putLong(name, value.int64Value);
+ break;
+ case DrmMetricGroup::ValueType::DOUBLE_TYPE:
+ bundle->putDouble(name, value.doubleValue);
+ break;
+ case DrmMetricGroup::ValueType::STRING_TYPE:
+ bundle->putString(name, String16(value.stringValue.c_str()));
+ break;
+ default:
+ ALOGE("Unexpected value type: %hhu", type);
+ }
+}
+
+inline String16 MakeIndexString(unsigned int index) {
+ std::string str("[");
+ str.append(std::to_string(index));
+ str.append("]");
+ return String16(str.c_str());
+}
+
+} // namespace
+
+namespace android {
+
+status_t DrmMetricsConsumer::consumeFrameworkMetrics(const MediaDrmMetrics &metrics) {
+ ExportCounterMetric(metrics.mOpenSessionCounter, mBundle);
+ ExportCounterMetric(metrics.mCloseSessionCounter, mBundle);
+ ExportEventMetric(metrics.mGetKeyRequestTimeUs, mBundle);
+ ExportEventMetric(metrics.mProvideKeyResponseTimeUs, mBundle);
+ ExportCounterMetric(metrics.mGetProvisionRequestCounter, mBundle);
+ ExportCounterMetric(metrics.mProvideProvisionResponseCounter, mBundle);
+ ExportCounterMetricWithAttributeNames(metrics.mKeyStatusChangeCounter, mBundle);
+ ExportCounterMetricWithAttributeNames(metrics.mEventCounter, mBundle);
+ ExportCounterMetric(metrics.mGetDeviceUniqueIdCounter, mBundle);
+ ExportSessionLifespans(metrics.GetSessionLifespans(), mBundle);
+ return android::OK;
+}
+
+status_t DrmMetricsConsumer::consumeHidlMetrics(
+ const String8 &vendor,
+ const hidl_vec<DrmMetricGroup> &pluginMetrics) {
+ PersistableBundle pluginBundle;
+ if (DrmMetricsConsumer::HidlMetricsToBundle(
+ pluginMetrics, &pluginBundle) == OK) {
+ mBundle->putPersistableBundle(String16(vendor), pluginBundle);
+ }
+ return android::OK;
+}
+
+status_t DrmMetricsConsumer::HidlMetricsToBundle(
+ const hidl_vec<DrmMetricGroup> &hidlMetricGroups,
+ PersistableBundle *bundleMetricGroups) {
+ if (bundleMetricGroups == nullptr) {
+ return UNEXPECTED_NULL;
+ }
+ if (hidlMetricGroups.size() == 0) {
+ return OK;
+ }
+
+ int groupIndex = 0;
+ std::map<String16, int> indexMap;
+ for (const auto &hidlMetricGroup : hidlMetricGroups) {
+ PersistableBundle bundleMetricGroup;
+ for (const auto &hidlMetric : hidlMetricGroup.metrics) {
+ String16 metricName(hidlMetric.name.c_str());
+ PersistableBundle bundleMetric;
+ // Add metric component values.
+ for (const auto &value : hidlMetric.values) {
+ SetValue(String16(value.componentName.c_str()), value.type,
+ value, &bundleMetric);
+ }
+ // Set metric attributes.
+ PersistableBundle bundleMetricAttributes;
+ for (const auto &attribute : hidlMetric.attributes) {
+ SetValue(String16(attribute.name.c_str()), attribute.type,
+ attribute, &bundleMetricAttributes);
+ }
+ // Add attributes to the bundle metric.
+ bundleMetric.putPersistableBundle(String16("attributes"),
+ bundleMetricAttributes);
+ // Add one layer of indirection, allowing for repeated metric names.
+ PersistableBundle repeatedMetrics;
+ bundleMetricGroup.getPersistableBundle(metricName,
+ &repeatedMetrics);
+ int index = indexMap[metricName];
+ repeatedMetrics.putPersistableBundle(MakeIndexString(index),
+ bundleMetric);
+ indexMap[metricName] = ++index;
+
+ // Add the bundle metric to the group of metrics.
+ bundleMetricGroup.putPersistableBundle(metricName,
+ repeatedMetrics);
+ }
+ // Add the bundle metric group to the collection of groups.
+ bundleMetricGroups->putPersistableBundle(MakeIndexString(groupIndex++),
+ bundleMetricGroup);
+ }
+
+ return OK;
+}
+
+} // namespace android
+
diff --git a/drm/libmediadrm/DrmSessionManager.cpp b/drm/libmediadrm/DrmSessionManager.cpp
index 375644c..5292705 100644
--- a/drm/libmediadrm/DrmSessionManager.cpp
+++ b/drm/libmediadrm/DrmSessionManager.cpp
@@ -18,17 +18,32 @@
#define LOG_TAG "DrmSessionManager"
#include <utils/Log.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IProcessInfoService.h>
-#include <binder/IServiceManager.h>
-#include <media/stagefright/ProcessInfo.h>
-#include <mediadrm/DrmSessionClientInterface.h>
+#include <aidl/android/media/IResourceManagerClient.h>
+#include <aidl/android/media/IResourceManagerService.h>
+#include <aidl/android/media/MediaResourceParcel.h>
+#include <android/binder_ibinder.h>
+#include <android/binder_manager.h>
+#include <cutils/properties.h>
+#include <mediadrm/DrmUtils.h>
#include <mediadrm/DrmSessionManager.h>
#include <unistd.h>
#include <utils/String8.h>
+#include <vector>
+
namespace android {
+using aidl::android::media::MediaResourceParcel;
+
+namespace {
+void ResourceManagerServiceDied(void* cookie) {
+ auto thiz = static_cast<DrmSessionManager*>(cookie);
+ thiz->binderDied();
+}
+}
+
+using ::ndk::ScopedAStatus;
+
static String8 GetSessionIdString(const Vector<uint8_t> &sessionId) {
String8 sessionIdStr;
for (size_t i = 0; i < sessionId.size(); ++i) {
@@ -37,6 +52,30 @@
return sessionIdStr;
}
+template <typename Byte = uint8_t>
+static std::vector<Byte> toStdVec(const Vector<uint8_t> &vector) {
+ auto v = reinterpret_cast<const Byte *>(vector.array());
+ std::vector<Byte> vec(v, v + vector.size());
+ return vec;
+}
+
+static std::vector<MediaResourceParcel> toResourceVec(
+ const Vector<uint8_t> &sessionId, int64_t value) {
+ using Type = aidl::android::media::MediaResourceType;
+ using SubType = aidl::android::media::MediaResourceSubType;
+ std::vector<MediaResourceParcel> resources;
+ MediaResourceParcel resource{
+ Type::kDrmSession, SubType::kUnspecifiedSubType,
+ toStdVec<int8_t>(sessionId), value};
+ resources.push_back(resource);
+ return resources;
+}
+
+static std::shared_ptr<IResourceManagerService> getResourceManagerService() {
+ ::ndk::SpAIBinder binder(AServiceManager_getService("media.resource_manager"));
+ return IResourceManagerService::fromBinder(binder);
+}
+
bool isEqualSessionId(const Vector<uint8_t> &sessionId1, const Vector<uint8_t> &sessionId2) {
if (sessionId1.size() != sessionId2.size()) {
return false;
@@ -51,189 +90,118 @@
sp<DrmSessionManager> DrmSessionManager::Instance() {
static sp<DrmSessionManager> drmSessionManager = new DrmSessionManager();
+ drmSessionManager->init();
return drmSessionManager;
}
DrmSessionManager::DrmSessionManager()
- : mProcessInfo(new ProcessInfo()),
- mTime(0) {}
+ : DrmSessionManager(getResourceManagerService()) {
+}
-DrmSessionManager::DrmSessionManager(sp<ProcessInfoInterface> processInfo)
- : mProcessInfo(processInfo),
- mTime(0) {}
+DrmSessionManager::DrmSessionManager(const std::shared_ptr<IResourceManagerService> &service)
+ : mService(service),
+ mInitialized(false),
+ mDeathRecipient(AIBinder_DeathRecipient_new(ResourceManagerServiceDied)) {
+ if (mService == NULL) {
+ ALOGE("Failed to init ResourceManagerService");
+ }
+}
-DrmSessionManager::~DrmSessionManager() {}
+DrmSessionManager::~DrmSessionManager() {
+ if (mService != NULL) {
+ AIBinder_unlinkToDeath(mService->asBinder().get(), mDeathRecipient.get(), this);
+ }
+}
-void DrmSessionManager::addSession(
- int pid, const sp<DrmSessionClientInterface>& drm, const Vector<uint8_t> &sessionId) {
- ALOGV("addSession(pid %d, drm %p, sessionId %s)", pid, drm.get(),
+void DrmSessionManager::init() {
+ Mutex::Autolock lock(mLock);
+ if (mInitialized) {
+ return;
+ }
+ mInitialized = true;
+ if (mService != NULL) {
+ AIBinder_linkToDeath(mService->asBinder().get(), mDeathRecipient.get(), this);
+ }
+}
+
+void DrmSessionManager::addSession(int pid,
+ const std::shared_ptr<IResourceManagerClient>& drm, const Vector<uint8_t> &sessionId) {
+ uid_t uid = AIBinder_getCallingUid();
+ ALOGV("addSession(pid %d, uid %d, drm %p, sessionId %s)", pid, uid, drm.get(),
GetSessionIdString(sessionId).string());
Mutex::Autolock lock(mLock);
- SessionInfo info;
- info.drm = drm;
- info.sessionId = sessionId;
- info.timeStamp = getTime_l();
- ssize_t index = mSessionMap.indexOfKey(pid);
- if (index < 0) {
- // new pid
- SessionInfos infosForPid;
- infosForPid.push_back(info);
- mSessionMap.add(pid, infosForPid);
- } else {
- mSessionMap.editValueAt(index).push_back(info);
+ if (mService == NULL) {
+ return;
}
+
+ static int64_t clientId = 0;
+ mSessionMap[toStdVec(sessionId)] = (SessionInfo){pid, uid, clientId};
+ mService->addResource(pid, uid, clientId++, drm, toResourceVec(sessionId, INT64_MAX));
}
void DrmSessionManager::useSession(const Vector<uint8_t> &sessionId) {
ALOGV("useSession(%s)", GetSessionIdString(sessionId).string());
Mutex::Autolock lock(mLock);
- for (size_t i = 0; i < mSessionMap.size(); ++i) {
- SessionInfos& infos = mSessionMap.editValueAt(i);
- for (size_t j = 0; j < infos.size(); ++j) {
- SessionInfo& info = infos.editItemAt(j);
- if (isEqualSessionId(sessionId, info.sessionId)) {
- info.timeStamp = getTime_l();
- return;
- }
- }
+ auto it = mSessionMap.find(toStdVec(sessionId));
+ if (mService == NULL || it == mSessionMap.end()) {
+ return;
}
+
+ auto info = it->second;
+ mService->addResource(info.pid, info.uid, info.clientId, NULL, toResourceVec(sessionId, -1));
}
void DrmSessionManager::removeSession(const Vector<uint8_t> &sessionId) {
ALOGV("removeSession(%s)", GetSessionIdString(sessionId).string());
Mutex::Autolock lock(mLock);
- for (size_t i = 0; i < mSessionMap.size(); ++i) {
- SessionInfos& infos = mSessionMap.editValueAt(i);
- for (size_t j = 0; j < infos.size(); ++j) {
- if (isEqualSessionId(sessionId, infos[j].sessionId)) {
- infos.removeAt(j);
- return;
- }
- }
+ auto it = mSessionMap.find(toStdVec(sessionId));
+ if (mService == NULL || it == mSessionMap.end()) {
+ return;
}
-}
-void DrmSessionManager::removeDrm(const sp<DrmSessionClientInterface>& drm) {
- ALOGV("removeDrm(%p)", drm.get());
-
- Mutex::Autolock lock(mLock);
- bool found = false;
- for (size_t i = 0; i < mSessionMap.size(); ++i) {
- SessionInfos& infos = mSessionMap.editValueAt(i);
- for (size_t j = 0; j < infos.size();) {
- if (infos[j].drm == drm) {
- ALOGV("removed session (%s)", GetSessionIdString(infos[j].sessionId).string());
- j = infos.removeAt(j);
- found = true;
- } else {
- ++j;
- }
- }
- if (found) {
- break;
- }
- }
+ auto info = it->second;
+ // removeClient instead of removeSession because each client has only one session
+ mService->removeClient(info.pid, info.clientId);
+ mSessionMap.erase(it);
}
bool DrmSessionManager::reclaimSession(int callingPid) {
ALOGV("reclaimSession(%d)", callingPid);
- sp<DrmSessionClientInterface> drm;
- Vector<uint8_t> sessionId;
- int lowestPriorityPid;
- int lowestPriority;
- {
- Mutex::Autolock lock(mLock);
- int callingPriority;
- if (!mProcessInfo->getPriority(callingPid, &callingPriority)) {
- return false;
- }
- if (!getLowestPriority_l(&lowestPriorityPid, &lowestPriority)) {
- return false;
- }
- if (lowestPriority <= callingPriority) {
- return false;
- }
+ // unlock early because reclaimResource might callback into removeSession
+ mLock.lock();
+ std::shared_ptr<IResourceManagerService> service(mService);
+ mLock.unlock();
- if (!getLeastUsedSession_l(lowestPriorityPid, &drm, &sessionId)) {
- return false;
- }
- }
-
- if (drm == NULL) {
+ if (service == NULL) {
return false;
}
- ALOGV("reclaim session(%s) opened by pid %d",
- GetSessionIdString(sessionId).string(), lowestPriorityPid);
-
- return drm->reclaimSession(sessionId);
+ // cannot update mSessionMap because we do not know which sessionId is reclaimed;
+ // we rely on IResourceManagerClient to removeSession in reclaimResource
+ Vector<uint8_t> dummy;
+ bool success;
+ ScopedAStatus status = service->reclaimResource(callingPid, toResourceVec(dummy, INT64_MAX), &success);
+ return status.isOk() && success;
}
-int64_t DrmSessionManager::getTime_l() {
- return mTime++;
+size_t DrmSessionManager::getSessionCount() const {
+ Mutex::Autolock lock(mLock);
+ return mSessionMap.size();
}
-bool DrmSessionManager::getLowestPriority_l(int* lowestPriorityPid, int* lowestPriority) {
- int pid = -1;
- int priority = -1;
- for (size_t i = 0; i < mSessionMap.size(); ++i) {
- if (mSessionMap.valueAt(i).size() == 0) {
- // no opened session by this process.
- continue;
- }
- int tempPid = mSessionMap.keyAt(i);
- int tempPriority;
- if (!mProcessInfo->getPriority(tempPid, &tempPriority)) {
- // shouldn't happen.
- return false;
- }
- if (pid == -1) {
- pid = tempPid;
- priority = tempPriority;
- } else {
- if (tempPriority > priority) {
- pid = tempPid;
- priority = tempPriority;
- }
- }
- }
- if (pid != -1) {
- *lowestPriorityPid = pid;
- *lowestPriority = priority;
- }
- return (pid != -1);
+bool DrmSessionManager::containsSession(const Vector<uint8_t>& sessionId) const {
+ Mutex::Autolock lock(mLock);
+ return mSessionMap.count(toStdVec(sessionId));
}
-bool DrmSessionManager::getLeastUsedSession_l(
- int pid, sp<DrmSessionClientInterface>* drm, Vector<uint8_t>* sessionId) {
- ssize_t index = mSessionMap.indexOfKey(pid);
- if (index < 0) {
- return false;
- }
-
- int leastUsedIndex = -1;
- int64_t minTs = LLONG_MAX;
- const SessionInfos& infos = mSessionMap.valueAt(index);
- for (size_t j = 0; j < infos.size(); ++j) {
- if (leastUsedIndex == -1) {
- leastUsedIndex = j;
- minTs = infos[j].timeStamp;
- } else {
- if (infos[j].timeStamp < minTs) {
- leastUsedIndex = j;
- minTs = infos[j].timeStamp;
- }
- }
- }
- if (leastUsedIndex != -1) {
- *drm = infos[leastUsedIndex].drm;
- *sessionId = infos[leastUsedIndex].sessionId;
- }
- return (leastUsedIndex != -1);
+void DrmSessionManager::binderDied() {
+ ALOGW("ResourceManagerService died.");
+ Mutex::Autolock lock(mLock);
+ mService.reset();
}
} // namespace android
diff --git a/drm/libmediadrm/DrmUtils.cpp b/drm/libmediadrm/DrmUtils.cpp
new file mode 100644
index 0000000..51c2e24
--- /dev/null
+++ b/drm/libmediadrm/DrmUtils.cpp
@@ -0,0 +1,181 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "DrmUtils"
+
+#include <android/hardware/drm/1.0/ICryptoFactory.h>
+#include <android/hardware/drm/1.0/ICryptoPlugin.h>
+#include <android/hardware/drm/1.0/IDrmFactory.h>
+#include <android/hardware/drm/1.0/IDrmPlugin.h>
+#include <android/hardware/drm/1.1/ICryptoFactory.h>
+#include <android/hardware/drm/1.1/IDrmFactory.h>
+#include <android/hardware/drm/1.2/ICryptoFactory.h>
+#include <android/hardware/drm/1.2/IDrmFactory.h>
+#include <android/hardware/drm/1.3/ICryptoFactory.h>
+#include <android/hardware/drm/1.3/IDrmFactory.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <hidl/HidlSupport.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/String16.h>
+#include <cutils/properties.h>
+
+#include <mediadrm/CryptoHal.h>
+#include <mediadrm/DrmHal.h>
+#include <mediadrm/DrmUtils.h>
+#include <mediadrm/ICrypto.h>
+#include <mediadrm/IDrm.h>
+
+using HServiceManager = ::android::hidl::manager::V1_0::IServiceManager;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using namespace ::android::hardware::drm;
+
+namespace android {
+namespace DrmUtils {
+
+namespace {
+
+template<typename Hal>
+Hal *MakeObject(status_t *pstatus) {
+ status_t err = OK;
+ status_t &status = pstatus ? *pstatus : err;
+ auto obj = new Hal();
+ status = obj->initCheck();
+ if (status != OK && status != NO_INIT) {
+ return NULL;
+ }
+ return obj;
+}
+
+template <typename Hal, typename V>
+void MakeHidlFactories(const uint8_t uuid[16], V &factories) {
+ sp<HServiceManager> serviceManager = HServiceManager::getService();
+ if (serviceManager == nullptr) {
+ ALOGE("Failed to get service manager");
+ exit(-1);
+ }
+
+ serviceManager->listByInterface(Hal::descriptor, [&](const hidl_vec<hidl_string> ®istered) {
+ for (const auto &instance : registered) {
+ auto factory = Hal::getService(instance);
+ if (factory != nullptr) {
+ ALOGI("found %s %s", Hal::descriptor, instance.c_str());
+ if (!uuid || factory->isCryptoSchemeSupported(uuid)) {
+ factories.push_back(factory);
+ }
+ }
+ }
+ });
+}
+
+hidl_vec<uint8_t> toHidlVec(const void *ptr, size_t size) {
+ hidl_vec<uint8_t> vec(size);
+ if (ptr != nullptr) {
+ memcpy(vec.data(), ptr, size);
+ }
+ return vec;
+}
+
+hidl_array<uint8_t, 16> toHidlArray16(const uint8_t *ptr) {
+ if (ptr == nullptr) {
+ return hidl_array<uint8_t, 16>();
+ }
+ return hidl_array<uint8_t, 16>(ptr);
+}
+
+sp<::V1_0::IDrmPlugin> MakeDrmPlugin(const sp<::V1_0::IDrmFactory> &factory,
+ const uint8_t uuid[16], const char *appPackageName) {
+ sp<::V1_0::IDrmPlugin> plugin;
+ factory->createPlugin(toHidlArray16(uuid), hidl_string(appPackageName),
+ [&](::V1_0::Status status, const sp<::V1_0::IDrmPlugin> &hPlugin) {
+ if (status != ::V1_0::Status::OK) {
+ return;
+ }
+ plugin = hPlugin;
+ });
+ return plugin;
+}
+
+sp<::V1_0::ICryptoPlugin> MakeCryptoPlugin(const sp<::V1_0::ICryptoFactory> &factory,
+ const uint8_t uuid[16], const void *initData,
+ size_t initDataSize) {
+ sp<::V1_0::ICryptoPlugin> plugin;
+ factory->createPlugin(toHidlArray16(uuid), toHidlVec(initData, initDataSize),
+ [&](::V1_0::Status status, const sp<::V1_0::ICryptoPlugin> &hPlugin) {
+ if (status != ::V1_0::Status::OK) {
+ return;
+ }
+ plugin = hPlugin;
+ });
+ return plugin;
+}
+
+} // namespace
+
+bool UseDrmService() {
+ return property_get_bool("mediadrm.use_mediadrmserver", true);
+}
+
+sp<IDrm> MakeDrm(status_t *pstatus) {
+ return MakeObject<DrmHal>(pstatus);
+}
+
+sp<ICrypto> MakeCrypto(status_t *pstatus) {
+ return MakeObject<CryptoHal>(pstatus);
+}
+
+std::vector<sp<::V1_0::IDrmFactory>> MakeDrmFactories(const uint8_t uuid[16]) {
+ std::vector<sp<::V1_0::IDrmFactory>> drmFactories;
+ MakeHidlFactories<::V1_0::IDrmFactory>(uuid, drmFactories);
+ MakeHidlFactories<::V1_1::IDrmFactory>(uuid, drmFactories);
+ MakeHidlFactories<::V1_2::IDrmFactory>(uuid, drmFactories);
+ MakeHidlFactories<::V1_3::IDrmFactory>(uuid, drmFactories);
+ return drmFactories;
+}
+
+std::vector<sp<::V1_0::IDrmPlugin>> MakeDrmPlugins(const uint8_t uuid[16],
+ const char *appPackageName) {
+ std::vector<sp<::V1_0::IDrmPlugin>> plugins;
+ for (const auto &factory : MakeDrmFactories(uuid)) {
+ plugins.push_back(MakeDrmPlugin(factory, uuid, appPackageName));
+ }
+ return plugins;
+}
+
+std::vector<sp<::V1_0::ICryptoFactory>> MakeCryptoFactories(const uint8_t uuid[16]) {
+ std::vector<sp<::V1_0::ICryptoFactory>> cryptoFactories;
+ MakeHidlFactories<::V1_0::ICryptoFactory>(uuid, cryptoFactories);
+ MakeHidlFactories<::V1_1::ICryptoFactory>(uuid, cryptoFactories);
+ MakeHidlFactories<::V1_2::ICryptoFactory>(uuid, cryptoFactories);
+ MakeHidlFactories<::V1_3::ICryptoFactory>(uuid, cryptoFactories);
+ return cryptoFactories;
+}
+
+std::vector<sp<ICryptoPlugin>> MakeCryptoPlugins(const uint8_t uuid[16], const void *initData,
+ size_t initDataSize) {
+ std::vector<sp<ICryptoPlugin>> plugins;
+ for (const auto &factory : MakeCryptoFactories(uuid)) {
+ plugins.push_back(MakeCryptoPlugin(factory, uuid, initData, initDataSize));
+ }
+ return plugins;
+}
+
+} // namespace DrmUtils
+} // namespace android
diff --git a/drm/libmediadrm/ICrypto.cpp b/drm/libmediadrm/ICrypto.cpp
deleted file mode 100644
index 8d8d088..0000000
--- a/drm/libmediadrm/ICrypto.cpp
+++ /dev/null
@@ -1,483 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "ICrypto"
-#include <binder/Parcel.h>
-#include <binder/IMemory.h>
-#include <cutils/log.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AString.h>
-#include <mediadrm/ICrypto.h>
-#include <utils/Log.h>
-
-namespace android {
-
-enum {
- INIT_CHECK = IBinder::FIRST_CALL_TRANSACTION,
- IS_CRYPTO_SUPPORTED,
- CREATE_PLUGIN,
- DESTROY_PLUGIN,
- REQUIRES_SECURE_COMPONENT,
- DECRYPT,
- NOTIFY_RESOLUTION,
- SET_MEDIADRM_SESSION,
- SET_HEAP,
- UNSET_HEAP,
-};
-
-struct BpCrypto : public BpInterface<ICrypto> {
- explicit BpCrypto(const sp<IBinder> &impl)
- : BpInterface<ICrypto>(impl) {
- }
-
- virtual status_t initCheck() const {
- Parcel data, reply;
- data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
- remote()->transact(INIT_CHECK, data, &reply);
-
- return reply.readInt32();
- }
-
- virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) {
- Parcel data, reply;
- data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
- data.write(uuid, 16);
- remote()->transact(IS_CRYPTO_SUPPORTED, data, &reply);
-
- return reply.readInt32() != 0;
- }
-
- virtual status_t createPlugin(
- const uint8_t uuid[16], const void *opaqueData, size_t opaqueSize) {
- Parcel data, reply;
- data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
- data.write(uuid, 16);
- data.writeInt32(opaqueSize);
-
- if (opaqueSize > 0) {
- data.write(opaqueData, opaqueSize);
- }
-
- remote()->transact(CREATE_PLUGIN, data, &reply);
-
- return reply.readInt32();
- }
-
- virtual status_t destroyPlugin() {
- Parcel data, reply;
- data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
- remote()->transact(DESTROY_PLUGIN, data, &reply);
-
- return reply.readInt32();
- }
-
- virtual bool requiresSecureDecoderComponent(
- const char *mime) const {
- Parcel data, reply;
- data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
- data.writeCString(mime);
- remote()->transact(REQUIRES_SECURE_COMPONENT, data, &reply);
-
- return reply.readInt32() != 0;
- }
-
- virtual ssize_t decrypt(const uint8_t key[16], const uint8_t iv[16],
- CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
- const SourceBuffer &source, size_t offset,
- const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
- const DestinationBuffer &destination, AString *errorDetailMsg) {
- Parcel data, reply;
- data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
- data.writeInt32(mode);
- data.writeInt32(pattern.mEncryptBlocks);
- data.writeInt32(pattern.mSkipBlocks);
-
- static const uint8_t kDummy[16] = { 0 };
-
- if (key == NULL) {
- key = kDummy;
- }
-
- if (iv == NULL) {
- iv = kDummy;
- }
-
- data.write(key, 16);
- data.write(iv, 16);
-
- size_t totalSize = 0;
- for (size_t i = 0; i < numSubSamples; ++i) {
- totalSize += subSamples[i].mNumBytesOfEncryptedData;
- totalSize += subSamples[i].mNumBytesOfClearData;
- }
-
- data.writeInt32(totalSize);
- data.writeStrongBinder(IInterface::asBinder(source.mSharedMemory));
- data.writeInt32(source.mHeapSeqNum);
- data.writeInt32(offset);
-
- data.writeInt32(numSubSamples);
- data.write(subSamples, sizeof(CryptoPlugin::SubSample) * numSubSamples);
-
- data.writeInt32((int32_t)destination.mType);
- if (destination.mType == kDestinationTypeNativeHandle) {
- if (destination.mHandle == NULL) {
- return BAD_VALUE;
- }
- data.writeNativeHandle(destination.mHandle);
- } else {
- if (destination.mSharedMemory == NULL) {
- return BAD_VALUE;
- }
- data.writeStrongBinder(IInterface::asBinder(destination.mSharedMemory));
- }
-
- remote()->transact(DECRYPT, data, &reply);
-
- ssize_t result = reply.readInt32();
-
- if (isCryptoError(result)) {
- AString msg = reply.readCString();
- if (errorDetailMsg) {
- *errorDetailMsg = msg;
- }
- }
-
- return result;
- }
-
- virtual void notifyResolution(
- uint32_t width, uint32_t height) {
- Parcel data, reply;
- data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
- data.writeInt32(width);
- data.writeInt32(height);
- remote()->transact(NOTIFY_RESOLUTION, data, &reply);
- }
-
- virtual status_t setMediaDrmSession(const Vector<uint8_t> &sessionId) {
- Parcel data, reply;
- data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
-
- writeVector(data, sessionId);
- remote()->transact(SET_MEDIADRM_SESSION, data, &reply);
-
- return reply.readInt32();
- }
-
- virtual int32_t setHeap(const sp<IMemoryHeap> &heap) {
- Parcel data, reply;
- data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
- data.writeStrongBinder(IInterface::asBinder(heap));
- status_t err = remote()->transact(SET_HEAP, data, &reply);
- if (err != NO_ERROR) {
- return -1;
- }
- int32_t seqNum;
- if (reply.readInt32(&seqNum) != NO_ERROR) {
- return -1;
- }
- return seqNum;
- }
-
- virtual void unsetHeap(int32_t seqNum) {
- Parcel data, reply;
- data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
- data.writeInt32(seqNum);
- remote()->transact(UNSET_HEAP, data, &reply);
- return;
- }
-
-
-private:
- void readVector(Parcel &reply, Vector<uint8_t> &vector) const {
- uint32_t size = reply.readInt32();
- vector.insertAt((size_t)0, size);
- reply.read(vector.editArray(), size);
- }
-
- void writeVector(Parcel &data, Vector<uint8_t> const &vector) const {
- data.writeInt32(vector.size());
- data.write(vector.array(), vector.size());
- }
-
- DISALLOW_EVIL_CONSTRUCTORS(BpCrypto);
-};
-
-IMPLEMENT_META_INTERFACE(Crypto, "android.hardware.ICrypto");
-
-////////////////////////////////////////////////////////////////////////////////
-
-void BnCrypto::readVector(const Parcel &data, Vector<uint8_t> &vector) const {
- uint32_t size = data.readInt32();
- if (vector.insertAt((size_t)0, size) < 0) {
- vector.clear();
- }
- if (data.read(vector.editArray(), size) != NO_ERROR) {
- vector.clear();
- android_errorWriteWithInfoLog(0x534e4554, "62872384", -1, NULL, 0);
- }
-}
-
-void BnCrypto::writeVector(Parcel *reply, Vector<uint8_t> const &vector) const {
- reply->writeInt32(vector.size());
- reply->write(vector.array(), vector.size());
-}
-
-status_t BnCrypto::onTransact(
- uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
- switch (code) {
- case INIT_CHECK:
- {
- CHECK_INTERFACE(ICrypto, data, reply);
- reply->writeInt32(initCheck());
-
- return OK;
- }
-
- case IS_CRYPTO_SUPPORTED:
- {
- CHECK_INTERFACE(ICrypto, data, reply);
- uint8_t uuid[16];
- data.read(uuid, sizeof(uuid));
- reply->writeInt32(isCryptoSchemeSupported(uuid));
-
- return OK;
- }
-
- case CREATE_PLUGIN:
- {
- CHECK_INTERFACE(ICrypto, data, reply);
-
- uint8_t uuid[16] = {0};
- if (data.read(uuid, sizeof(uuid)) != NO_ERROR) {
- android_errorWriteLog(0x534e4554, "144767096");
- reply->writeInt32(BAD_VALUE);
- return OK;
- }
-
- size_t opaqueSize = data.readInt32();
- void *opaqueData = NULL;
-
- const size_t kMaxOpaqueSize = 100 * 1024;
- if (opaqueSize > kMaxOpaqueSize) {
- return BAD_VALUE;
- }
-
- opaqueData = malloc(opaqueSize);
- if (NULL == opaqueData) {
- return NO_MEMORY;
- }
-
- if (data.read(opaqueData, opaqueSize) != NO_ERROR) {
- android_errorWriteLog(0x534e4554, "144767096");
- reply->writeInt32(BAD_VALUE);
- return OK;
- }
- reply->writeInt32(createPlugin(uuid, opaqueData, opaqueSize));
-
- free(opaqueData);
- opaqueData = NULL;
-
- return OK;
- }
-
- case DESTROY_PLUGIN:
- {
- CHECK_INTERFACE(ICrypto, data, reply);
- reply->writeInt32(destroyPlugin());
-
- return OK;
- }
-
- case REQUIRES_SECURE_COMPONENT:
- {
- CHECK_INTERFACE(ICrypto, data, reply);
-
- const char *mime = data.readCString();
- if (mime == NULL) {
- reply->writeInt32(BAD_VALUE);
- } else {
- reply->writeInt32(requiresSecureDecoderComponent(mime));
- }
-
- return OK;
- }
-
- case DECRYPT:
- {
- CHECK_INTERFACE(ICrypto, data, reply);
-
- CryptoPlugin::Mode mode = (CryptoPlugin::Mode)data.readInt32();
- CryptoPlugin::Pattern pattern;
- pattern.mEncryptBlocks = data.readInt32();
- pattern.mSkipBlocks = data.readInt32();
-
- uint8_t key[16];
- data.read(key, sizeof(key));
-
- uint8_t iv[16];
- data.read(iv, sizeof(iv));
-
- size_t totalSize = data.readInt32();
-
- SourceBuffer source;
-
- source.mSharedMemory =
- interface_cast<IMemory>(data.readStrongBinder());
- if (source.mSharedMemory == NULL) {
- reply->writeInt32(BAD_VALUE);
- return OK;
- }
- source.mHeapSeqNum = data.readInt32();
-
- int32_t offset = data.readInt32();
-
- int32_t numSubSamples = data.readInt32();
- if (numSubSamples < 0 || numSubSamples > 0xffff) {
- reply->writeInt32(BAD_VALUE);
- return OK;
- }
-
- std::unique_ptr<CryptoPlugin::SubSample[]> subSamples =
- std::make_unique<CryptoPlugin::SubSample[]>(numSubSamples);
-
- data.read(subSamples.get(),
- sizeof(CryptoPlugin::SubSample) * numSubSamples);
-
- DestinationBuffer destination;
- destination.mType = (DestinationType)data.readInt32();
- if (destination.mType == kDestinationTypeNativeHandle) {
- destination.mHandle = data.readNativeHandle();
- if (destination.mHandle == NULL) {
- reply->writeInt32(BAD_VALUE);
- return OK;
- }
- } else if (destination.mType == kDestinationTypeSharedMemory) {
- destination.mSharedMemory =
- interface_cast<IMemory>(data.readStrongBinder());
- if (destination.mSharedMemory == NULL) {
- reply->writeInt32(BAD_VALUE);
- return OK;
- }
- sp<IMemory> dest = destination.mSharedMemory;
- if (totalSize > dest->size() ||
- (size_t)dest->offset() > dest->size() - totalSize) {
- reply->writeInt32(BAD_VALUE);
- android_errorWriteLog(0x534e4554, "71389378");
- return OK;
- }
- } else {
- reply->writeInt32(BAD_VALUE);
- android_errorWriteLog(0x534e4554, "70526702");
- return OK;
- }
-
- AString errorDetailMsg;
- ssize_t result;
-
- size_t sumSubsampleSizes = 0;
- bool overflow = false;
- for (int32_t i = 0; i < numSubSamples; ++i) {
- CryptoPlugin::SubSample &ss = subSamples[i];
- if (sumSubsampleSizes <= SIZE_MAX - ss.mNumBytesOfEncryptedData) {
- sumSubsampleSizes += ss.mNumBytesOfEncryptedData;
- } else {
- overflow = true;
- }
- if (sumSubsampleSizes <= SIZE_MAX - ss.mNumBytesOfClearData) {
- sumSubsampleSizes += ss.mNumBytesOfClearData;
- } else {
- overflow = true;
- }
- }
-
- if (overflow || sumSubsampleSizes != totalSize) {
- result = -EINVAL;
- } else if (totalSize > source.mSharedMemory->size()) {
- result = -EINVAL;
- } else if ((size_t)offset > source.mSharedMemory->size() - totalSize) {
- result = -EINVAL;
- } else {
- result = decrypt(key, iv, mode, pattern, source, offset,
- subSamples.get(), numSubSamples, destination, &errorDetailMsg);
- }
-
- reply->writeInt32(result);
-
- if (isCryptoError(result)) {
- reply->writeCString(errorDetailMsg.c_str());
- }
-
- if (destination.mType == kDestinationTypeNativeHandle) {
- int err;
- if ((err = native_handle_close(destination.mHandle)) < 0) {
- ALOGW("secure buffer native_handle_close failed: %d", err);
- }
- if ((err = native_handle_delete(destination.mHandle)) < 0) {
- ALOGW("secure buffer native_handle_delete failed: %d", err);
- }
- }
-
- subSamples.reset();
- return OK;
- }
-
- case NOTIFY_RESOLUTION:
- {
- CHECK_INTERFACE(ICrypto, data, reply);
-
- int32_t width = data.readInt32();
- int32_t height = data.readInt32();
- notifyResolution(width, height);
-
- return OK;
- }
-
- case SET_MEDIADRM_SESSION:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- Vector<uint8_t> sessionId;
- readVector(data, sessionId);
- reply->writeInt32(setMediaDrmSession(sessionId));
- return OK;
- }
-
- case SET_HEAP:
- {
- CHECK_INTERFACE(ICrypto, data, reply);
- sp<IMemoryHeap> heap =
- interface_cast<IMemoryHeap>(data.readStrongBinder());
- reply->writeInt32(setHeap(heap));
- return OK;
- }
-
- case UNSET_HEAP:
- {
- CHECK_INTERFACE(ICrypto, data, reply);
- int32_t seqNum = data.readInt32();
- unsetHeap(seqNum);
- return OK;
- }
-
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-} // namespace android
diff --git a/drm/libmediadrm/IDrm.cpp b/drm/libmediadrm/IDrm.cpp
deleted file mode 100644
index 51274d1..0000000
--- a/drm/libmediadrm/IDrm.cpp
+++ /dev/null
@@ -1,1242 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "IDrm"
-#include <utils/Log.h>
-
-#include <binder/Parcel.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AString.h>
-#include <mediadrm/IDrm.h>
-
-namespace android {
-
-enum {
- INIT_CHECK = IBinder::FIRST_CALL_TRANSACTION,
- IS_CRYPTO_SUPPORTED,
- CREATE_PLUGIN,
- DESTROY_PLUGIN,
- OPEN_SESSION,
- CLOSE_SESSION,
- GET_KEY_REQUEST,
- PROVIDE_KEY_RESPONSE,
- REMOVE_KEYS,
- RESTORE_KEYS,
- QUERY_KEY_STATUS,
- GET_PROVISION_REQUEST,
- PROVIDE_PROVISION_RESPONSE,
- GET_SECURE_STOPS,
- RELEASE_SECURE_STOPS,
- GET_PROPERTY_STRING,
- GET_PROPERTY_BYTE_ARRAY,
- SET_PROPERTY_STRING,
- SET_PROPERTY_BYTE_ARRAY,
- GET_METRICS,
- SET_CIPHER_ALGORITHM,
- SET_MAC_ALGORITHM,
- ENCRYPT,
- DECRYPT,
- SIGN,
- SIGN_RSA,
- VERIFY,
- SET_LISTENER,
- GET_SECURE_STOP,
- REMOVE_ALL_SECURE_STOPS,
- GET_HDCP_LEVELS,
- GET_NUMBER_OF_SESSIONS,
- GET_SECURITY_LEVEL,
- REMOVE_SECURE_STOP,
- GET_SECURE_STOP_IDS,
- GET_OFFLINE_LICENSE_KEYSET_IDS,
- REMOVE_OFFLINE_LICENSE,
- GET_OFFLINE_LICENSE_STATE
-};
-
-struct BpDrm : public BpInterface<IDrm> {
- explicit BpDrm(const sp<IBinder> &impl)
- : BpInterface<IDrm>(impl) {
- }
-
- virtual status_t initCheck() const {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
- status_t status = remote()->transact(INIT_CHECK, data, &reply);
- if (status != OK) {
- return status;
- }
-
- return reply.readInt32();
- }
-
- virtual status_t isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType,
- DrmPlugin::SecurityLevel level, bool *isSupported) {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
- data.write(uuid, 16);
- data.writeString8(mimeType);
- data.writeInt32(level);
-
- status_t status = remote()->transact(IS_CRYPTO_SUPPORTED, data, &reply);
- if (status != OK) {
- ALOGE("isCryptoSchemeSupported: binder call failed: %d", status);
- return status;
- }
- *isSupported = static_cast<bool>(reply.readInt32());
-
- return reply.readInt32();
- }
-
- virtual status_t createPlugin(const uint8_t uuid[16],
- const String8& appPackageName) {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
- data.write(uuid, 16);
- data.writeString8(appPackageName);
- status_t status = remote()->transact(CREATE_PLUGIN, data, &reply);
- if (status != OK) {
- ALOGE("createPlugin: binder call failed: %d", status);
- return status;
- }
-
- return reply.readInt32();
- }
-
- virtual status_t destroyPlugin() {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
- status_t status = remote()->transact(DESTROY_PLUGIN, data, &reply);
- if (status != OK) {
- return status;
- }
-
- return reply.readInt32();
- }
-
- virtual status_t openSession(DrmPlugin::SecurityLevel level,
- Vector<uint8_t> &sessionId) {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
- data.writeInt32(level);
-
- status_t status = remote()->transact(OPEN_SESSION, data, &reply);
- if (status != OK) {
- return status;
- }
- readVector(reply, sessionId);
-
- return reply.readInt32();
- }
-
- virtual status_t closeSession(Vector<uint8_t> const &sessionId) {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- writeVector(data, sessionId);
- status_t status = remote()->transact(CLOSE_SESSION, data, &reply);
- if (status != OK) {
- return status;
- }
-
- return reply.readInt32();
- }
-
- virtual status_t
- getKeyRequest(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &initData,
- String8 const &mimeType, DrmPlugin::KeyType keyType,
- KeyedVector<String8, String8> const &optionalParameters,
- Vector<uint8_t> &request, String8 &defaultUrl,
- DrmPlugin::KeyRequestType *keyRequestType) {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- writeVector(data, sessionId);
- writeVector(data, initData);
- data.writeString8(mimeType);
- data.writeInt32((uint32_t)keyType);
-
- data.writeInt32(optionalParameters.size());
- for (size_t i = 0; i < optionalParameters.size(); ++i) {
- data.writeString8(optionalParameters.keyAt(i));
- data.writeString8(optionalParameters.valueAt(i));
- }
-
- status_t status = remote()->transact(GET_KEY_REQUEST, data, &reply);
- if (status != OK) {
- return status;
- }
-
- readVector(reply, request);
- defaultUrl = reply.readString8();
- *keyRequestType = static_cast<DrmPlugin::KeyRequestType>(reply.readInt32());
-
- return reply.readInt32();
- }
-
- virtual status_t provideKeyResponse(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &response,
- Vector<uint8_t> &keySetId) {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
- writeVector(data, sessionId);
- writeVector(data, response);
-
- status_t status = remote()->transact(PROVIDE_KEY_RESPONSE, data, &reply);
- if (status != OK) {
- return status;
- }
-
- readVector(reply, keySetId);
-
- return reply.readInt32();
- }
-
- virtual status_t removeKeys(Vector<uint8_t> const &keySetId) {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- writeVector(data, keySetId);
- status_t status = remote()->transact(REMOVE_KEYS, data, &reply);
- if (status != OK) {
- return status;
- }
-
- return reply.readInt32();
- }
-
- virtual status_t restoreKeys(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keySetId) {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- writeVector(data, sessionId);
- writeVector(data, keySetId);
- status_t status = remote()->transact(RESTORE_KEYS, data, &reply);
- if (status != OK) {
- return status;
- }
-
- return reply.readInt32();
- }
-
- virtual status_t queryKeyStatus(Vector<uint8_t> const &sessionId,
- KeyedVector<String8, String8> &infoMap) const {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- writeVector(data, sessionId);
- status_t status = remote()->transact(QUERY_KEY_STATUS, data, &reply);
- if (status != OK) {
- return status;
- }
-
- infoMap.clear();
- size_t count = reply.readInt32();
- for (size_t i = 0; i < count; i++) {
- String8 key = reply.readString8();
- String8 value = reply.readString8();
- infoMap.add(key, value);
- }
- return reply.readInt32();
- }
-
- virtual status_t getProvisionRequest(String8 const &certType,
- String8 const &certAuthority,
- Vector<uint8_t> &request,
- String8 &defaultUrl) {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- data.writeString8(certType);
- data.writeString8(certAuthority);
- status_t status = remote()->transact(GET_PROVISION_REQUEST, data, &reply);
- if (status != OK) {
- return status;
- }
-
- readVector(reply, request);
- defaultUrl = reply.readString8();
-
- return reply.readInt32();
- }
-
- virtual status_t provideProvisionResponse(Vector<uint8_t> const &response,
- Vector<uint8_t> &certificate,
- Vector<uint8_t> &wrappedKey) {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- writeVector(data, response);
- status_t status = remote()->transact(PROVIDE_PROVISION_RESPONSE, data, &reply);
- if (status != OK) {
- return status;
- }
-
- readVector(reply, certificate);
- readVector(reply, wrappedKey);
-
- return reply.readInt32();
- }
-
- virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops) {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- status_t status = remote()->transact(GET_SECURE_STOPS, data, &reply);
- if (status != OK) {
- return status;
- }
-
- secureStops.clear();
- uint32_t count = reply.readInt32();
- for (size_t i = 0; i < count; i++) {
- Vector<uint8_t> secureStop;
- readVector(reply, secureStop);
- secureStops.push_back(secureStop);
- }
- return reply.readInt32();
- }
-
- virtual status_t getSecureStopIds(List<Vector<uint8_t> > &secureStopIds) {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- status_t status = remote()->transact(GET_SECURE_STOP_IDS, data, &reply);
- if (status != OK) {
- return status;
- }
-
- secureStopIds.clear();
- uint32_t count = reply.readInt32();
- for (size_t i = 0; i < count; i++) {
- Vector<uint8_t> secureStopId;
- readVector(reply, secureStopId);
- secureStopIds.push_back(secureStopId);
- }
- return reply.readInt32();
- }
-
- virtual status_t getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop) {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- writeVector(data, ssid);
- status_t status = remote()->transact(GET_SECURE_STOP, data, &reply);
- if (status != OK) {
- return status;
- }
-
- readVector(reply, secureStop);
- return reply.readInt32();
- }
-
- virtual status_t releaseSecureStops(Vector<uint8_t> const &ssRelease) {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- writeVector(data, ssRelease);
- status_t status = remote()->transact(RELEASE_SECURE_STOPS, data, &reply);
- if (status != OK) {
- return status;
- }
-
- return reply.readInt32();
- }
-
- virtual status_t removeSecureStop(Vector<uint8_t> const &ssid) {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- writeVector(data, ssid);
- status_t status = remote()->transact(REMOVE_SECURE_STOP, data, &reply);
- if (status != OK) {
- return status;
- }
-
- return reply.readInt32();
- }
-
- virtual status_t removeAllSecureStops() {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- status_t status = remote()->transact(REMOVE_ALL_SECURE_STOPS, data, &reply);
- if (status != OK) {
- return status;
- }
-
- return reply.readInt32();
- }
-
- virtual status_t getOfflineLicenseKeySetIds(List<Vector<uint8_t> > &keySetIds) const {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- status_t status = remote()->transact(GET_OFFLINE_LICENSE_KEYSET_IDS, data, &reply);
- if (status != OK) {
- return status;
- }
-
- keySetIds.clear();
- uint32_t count = reply.readInt32();
- for (size_t i = 0; i < count; i++) {
- Vector<uint8_t> keySetId;
- readVector(reply, keySetId);
- keySetIds.push_back(keySetId);
- }
- return reply.readInt32();
- }
-
- virtual status_t removeOfflineLicense(Vector<uint8_t> const &keySetId) {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- writeVector(data, keySetId);
- status_t status = remote()->transact(REMOVE_OFFLINE_LICENSE, data, &reply);
- if (status != OK) {
- return status;
- }
- return reply.readInt32();
- }
-
- virtual status_t getOfflineLicenseState(Vector<uint8_t> const &keySetId,
- DrmPlugin::OfflineLicenseState *licenseState) const {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- writeVector(data, keySetId);
- status_t status = remote()->transact(GET_OFFLINE_LICENSE_STATE, data, &reply);
- if (status != OK) {
- *licenseState = DrmPlugin::OfflineLicenseState::kOfflineLicenseStateUnknown;
- return status;
- }
- *licenseState = static_cast<DrmPlugin::OfflineLicenseState>(reply.readInt32());
- return reply.readInt32();
- }
-
- virtual status_t getPropertyString(String8 const &name, String8 &value) const {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- data.writeString8(name);
- status_t status = remote()->transact(GET_PROPERTY_STRING, data, &reply);
- if (status != OK) {
- return status;
- }
-
- value = reply.readString8();
- return reply.readInt32();
- }
-
- virtual status_t getHdcpLevels(DrmPlugin::HdcpLevel *connected,
- DrmPlugin::HdcpLevel *max) const {
- Parcel data, reply;
-
- if (connected == NULL || max == NULL) {
- return BAD_VALUE;
- }
-
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- status_t status = remote()->transact(GET_HDCP_LEVELS, data, &reply);
- if (status != OK) {
- return status;
- }
-
- *connected = static_cast<DrmPlugin::HdcpLevel>(reply.readInt32());
- *max = static_cast<DrmPlugin::HdcpLevel>(reply.readInt32());
- return reply.readInt32();
- }
-
- virtual status_t getNumberOfSessions(uint32_t *open, uint32_t *max) const {
- Parcel data, reply;
-
- if (open == NULL || max == NULL) {
- return BAD_VALUE;
- }
-
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- status_t status = remote()->transact(GET_NUMBER_OF_SESSIONS, data, &reply);
- if (status != OK) {
- return status;
- }
-
- *open = reply.readInt32();
- *max = reply.readInt32();
- return reply.readInt32();
- }
-
- virtual status_t getSecurityLevel(Vector<uint8_t> const &sessionId,
- DrmPlugin::SecurityLevel *level) const {
- Parcel data, reply;
-
- if (level == NULL) {
- return BAD_VALUE;
- }
-
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- writeVector(data, sessionId);
- status_t status = remote()->transact(GET_SECURITY_LEVEL, data, &reply);
- if (status != OK) {
- return status;
- }
-
- *level = static_cast<DrmPlugin::SecurityLevel>(reply.readInt32());
- return reply.readInt32();
- }
-
- virtual status_t getPropertyByteArray(String8 const &name, Vector<uint8_t> &value) const {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- data.writeString8(name);
- status_t status = remote()->transact(GET_PROPERTY_BYTE_ARRAY, data, &reply);
- if (status != OK) {
- return status;
- }
-
- readVector(reply, value);
- return reply.readInt32();
- }
-
- virtual status_t setPropertyString(String8 const &name, String8 const &value) const {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- data.writeString8(name);
- data.writeString8(value);
- status_t status = remote()->transact(SET_PROPERTY_STRING, data, &reply);
- if (status != OK) {
- return status;
- }
-
- return reply.readInt32();
- }
-
- virtual status_t setPropertyByteArray(String8 const &name,
- Vector<uint8_t> const &value) const {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- data.writeString8(name);
- writeVector(data, value);
- status_t status = remote()->transact(SET_PROPERTY_BYTE_ARRAY, data, &reply);
- if (status != OK) {
- return status;
- }
-
- return reply.readInt32();
- }
-
- virtual status_t getMetrics(os::PersistableBundle *metrics) {
- if (metrics == NULL) {
- return BAD_VALUE;
- }
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- status_t status = remote()->transact(GET_METRICS, data, &reply);
- if (status != OK) {
- return status;
- }
- // The reply data is ordered as
- // 1) 32 bit integer reply followed by
- // 2) Serialized PersistableBundle containing metrics.
- status_t reply_status;
- if (reply.readInt32(&reply_status) != OK
- || reply_status != OK) {
- ALOGE("Failed to read getMetrics response code from parcel. %d",
- reply_status);
- return reply_status;
- }
-
- status = metrics->readFromParcel(&reply);
- if (status != OK) {
- ALOGE("Failed to read metrics from parcel. %d", status);
- return status;
- }
- return reply_status;
- }
-
- virtual status_t setCipherAlgorithm(Vector<uint8_t> const &sessionId,
- String8 const &algorithm) {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- writeVector(data, sessionId);
- data.writeString8(algorithm);
- status_t status = remote()->transact(SET_CIPHER_ALGORITHM, data, &reply);
- if (status != OK) {
- return status;
- }
- return reply.readInt32();
- }
-
- virtual status_t setMacAlgorithm(Vector<uint8_t> const &sessionId,
- String8 const &algorithm) {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- writeVector(data, sessionId);
- data.writeString8(algorithm);
- status_t status = remote()->transact(SET_MAC_ALGORITHM, data, &reply);
- if (status != OK) {
- return status;
- }
- return reply.readInt32();
- }
-
- virtual status_t encrypt(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId,
- Vector<uint8_t> const &input,
- Vector<uint8_t> const &iv,
- Vector<uint8_t> &output) {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- writeVector(data, sessionId);
- writeVector(data, keyId);
- writeVector(data, input);
- writeVector(data, iv);
-
- status_t status = remote()->transact(ENCRYPT, data, &reply);
- if (status != OK) {
- return status;
- }
- readVector(reply, output);
-
- return reply.readInt32();
- }
-
- virtual status_t decrypt(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId,
- Vector<uint8_t> const &input,
- Vector<uint8_t> const &iv,
- Vector<uint8_t> &output) {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- writeVector(data, sessionId);
- writeVector(data, keyId);
- writeVector(data, input);
- writeVector(data, iv);
-
- status_t status = remote()->transact(DECRYPT, data, &reply);
- if (status != OK) {
- return status;
- }
- readVector(reply, output);
-
- return reply.readInt32();
- }
-
- virtual status_t sign(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId,
- Vector<uint8_t> const &message,
- Vector<uint8_t> &signature) {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- writeVector(data, sessionId);
- writeVector(data, keyId);
- writeVector(data, message);
-
- status_t status = remote()->transact(SIGN, data, &reply);
- if (status != OK) {
- return status;
- }
- readVector(reply, signature);
-
- return reply.readInt32();
- }
-
- virtual status_t verify(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId,
- Vector<uint8_t> const &message,
- Vector<uint8_t> const &signature,
- bool &match) {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- writeVector(data, sessionId);
- writeVector(data, keyId);
- writeVector(data, message);
- writeVector(data, signature);
-
- status_t status = remote()->transact(VERIFY, data, &reply);
- if (status != OK) {
- return status;
- }
- match = (bool)reply.readInt32();
- return reply.readInt32();
- }
-
- virtual status_t signRSA(Vector<uint8_t> const &sessionId,
- String8 const &algorithm,
- Vector<uint8_t> const &message,
- Vector<uint8_t> const &wrappedKey,
- Vector<uint8_t> &signature) {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- writeVector(data, sessionId);
- data.writeString8(algorithm);
- writeVector(data, message);
- writeVector(data, wrappedKey);
-
- status_t status = remote()->transact(SIGN_RSA, data, &reply);
- if (status != OK) {
- return status;
- }
- readVector(reply, signature);
-
- return reply.readInt32();
- }
-
- virtual status_t setListener(const sp<IDrmClient>& listener) {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
- data.writeStrongBinder(IInterface::asBinder(listener));
- status_t status = remote()->transact(SET_LISTENER, data, &reply);
- if (status != OK) {
- return status;
- }
- return reply.readInt32();
- }
-
-private:
- void readVector(Parcel &reply, Vector<uint8_t> &vector) const {
- uint32_t size = reply.readInt32();
- vector.insertAt((size_t)0, size);
- reply.read(vector.editArray(), size);
- }
-
- void writeVector(Parcel &data, Vector<uint8_t> const &vector) const {
- data.writeInt32(vector.size());
- data.write(vector.array(), vector.size());
- }
-
- DISALLOW_EVIL_CONSTRUCTORS(BpDrm);
-};
-
-IMPLEMENT_META_INTERFACE(Drm, "android.drm.IDrm");
-
-////////////////////////////////////////////////////////////////////////////////
-
-void BnDrm::readVector(const Parcel &data, Vector<uint8_t> &vector) const {
- uint32_t size = data.readInt32();
- if (vector.insertAt((size_t)0, size) < 0) {
- vector.clear();
- }
- if (data.read(vector.editArray(), size) != NO_ERROR) {
- vector.clear();
- android_errorWriteWithInfoLog(0x534e4554, "62872384", -1, NULL, 0);
- }
-}
-
-void BnDrm::writeVector(Parcel *reply, Vector<uint8_t> const &vector) const {
- reply->writeInt32(vector.size());
- reply->write(vector.array(), vector.size());
-}
-
-status_t BnDrm::onTransact(
- uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
- switch (code) {
- case INIT_CHECK:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- reply->writeInt32(initCheck());
- return OK;
- }
-
- case IS_CRYPTO_SUPPORTED:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- uint8_t uuid[16];
- data.read(uuid, sizeof(uuid));
- String8 mimeType = data.readString8();
- DrmPlugin::SecurityLevel level =
- static_cast<DrmPlugin::SecurityLevel>(data.readInt32());
- bool isSupported = false;
- status_t result = isCryptoSchemeSupported(uuid, mimeType, level, &isSupported);
- reply->writeInt32(isSupported);
- reply->writeInt32(result);
- return OK;
- }
-
- case CREATE_PLUGIN:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- uint8_t uuid[16];
- data.read(uuid, sizeof(uuid));
- String8 appPackageName = data.readString8();
- reply->writeInt32(createPlugin(uuid, appPackageName));
- return OK;
- }
-
- case DESTROY_PLUGIN:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- reply->writeInt32(destroyPlugin());
- return OK;
- }
-
- case OPEN_SESSION:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- DrmPlugin::SecurityLevel level =
- static_cast<DrmPlugin::SecurityLevel>(data.readInt32());
- Vector<uint8_t> sessionId;
- status_t result = openSession(level, sessionId);
- writeVector(reply, sessionId);
- reply->writeInt32(result);
- return OK;
- }
-
- case CLOSE_SESSION:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- Vector<uint8_t> sessionId;
- readVector(data, sessionId);
- reply->writeInt32(closeSession(sessionId));
- return OK;
- }
-
- case GET_KEY_REQUEST:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- Vector<uint8_t> sessionId, initData;
-
- readVector(data, sessionId);
- readVector(data, initData);
- String8 mimeType = data.readString8();
- DrmPlugin::KeyType keyType = (DrmPlugin::KeyType)data.readInt32();
-
- KeyedVector<String8, String8> optionalParameters;
- uint32_t count = data.readInt32();
- for (size_t i = 0; i < count; ++i) {
- String8 key, value;
- key = data.readString8();
- value = data.readString8();
- optionalParameters.add(key, value);
- }
-
- Vector<uint8_t> request;
- String8 defaultUrl;
- DrmPlugin::KeyRequestType keyRequestType = DrmPlugin::kKeyRequestType_Unknown;
-
- status_t result = getKeyRequest(sessionId, initData, mimeType,
- keyType, optionalParameters, request, defaultUrl,
- &keyRequestType);
-
- writeVector(reply, request);
- reply->writeString8(defaultUrl);
- reply->writeInt32(static_cast<int32_t>(keyRequestType));
- reply->writeInt32(result);
- return OK;
- }
-
- case PROVIDE_KEY_RESPONSE:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- Vector<uint8_t> sessionId, response, keySetId;
- readVector(data, sessionId);
- readVector(data, response);
- uint32_t result = provideKeyResponse(sessionId, response, keySetId);
- writeVector(reply, keySetId);
- reply->writeInt32(result);
- return OK;
- }
-
- case REMOVE_KEYS:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- Vector<uint8_t> keySetId;
- readVector(data, keySetId);
- reply->writeInt32(removeKeys(keySetId));
- return OK;
- }
-
- case RESTORE_KEYS:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- Vector<uint8_t> sessionId, keySetId;
- readVector(data, sessionId);
- readVector(data, keySetId);
- reply->writeInt32(restoreKeys(sessionId, keySetId));
- return OK;
- }
-
- case QUERY_KEY_STATUS:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- Vector<uint8_t> sessionId;
- readVector(data, sessionId);
- KeyedVector<String8, String8> infoMap;
- status_t result = queryKeyStatus(sessionId, infoMap);
- size_t count = infoMap.size();
- reply->writeInt32(count);
- for (size_t i = 0; i < count; ++i) {
- reply->writeString8(infoMap.keyAt(i));
- reply->writeString8(infoMap.valueAt(i));
- }
- reply->writeInt32(result);
- return OK;
- }
-
- case GET_PROVISION_REQUEST:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- String8 certType = data.readString8();
- String8 certAuthority = data.readString8();
-
- Vector<uint8_t> request;
- String8 defaultUrl;
- status_t result = getProvisionRequest(certType, certAuthority,
- request, defaultUrl);
- writeVector(reply, request);
- reply->writeString8(defaultUrl);
- reply->writeInt32(result);
- return OK;
- }
-
- case PROVIDE_PROVISION_RESPONSE:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- Vector<uint8_t> response;
- Vector<uint8_t> certificate;
- Vector<uint8_t> wrappedKey;
- readVector(data, response);
- status_t result = provideProvisionResponse(response, certificate, wrappedKey);
- writeVector(reply, certificate);
- writeVector(reply, wrappedKey);
- reply->writeInt32(result);
- return OK;
- }
-
- case GET_SECURE_STOPS:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- List<Vector<uint8_t> > secureStops;
- status_t result = getSecureStops(secureStops);
- size_t count = secureStops.size();
- reply->writeInt32(count);
- List<Vector<uint8_t> >::iterator iter = secureStops.begin();
- while(iter != secureStops.end()) {
- size_t size = iter->size();
- reply->writeInt32(size);
- reply->write(iter->array(), iter->size());
- iter++;
- }
- reply->writeInt32(result);
- return OK;
- }
-
- case GET_SECURE_STOP_IDS:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- List<Vector<uint8_t> > secureStopIds;
- status_t result = getSecureStopIds(secureStopIds);
- size_t count = secureStopIds.size();
- reply->writeInt32(count);
- List<Vector<uint8_t> >::iterator iter = secureStopIds.begin();
- while(iter != secureStopIds.end()) {
- size_t size = iter->size();
- reply->writeInt32(size);
- reply->write(iter->array(), iter->size());
- iter++;
- }
- reply->writeInt32(result);
- return OK;
- }
-
- case GET_SECURE_STOP:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- Vector<uint8_t> ssid, secureStop;
- readVector(data, ssid);
- status_t result = getSecureStop(ssid, secureStop);
- writeVector(reply, secureStop);
- reply->writeInt32(result);
- return OK;
- }
-
- case RELEASE_SECURE_STOPS:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- Vector<uint8_t> ssRelease;
- readVector(data, ssRelease);
- reply->writeInt32(releaseSecureStops(ssRelease));
- return OK;
- }
-
- case REMOVE_SECURE_STOP:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- Vector<uint8_t> ssid;
- readVector(data, ssid);
- reply->writeInt32(removeSecureStop(ssid));
- return OK;
- }
-
- case REMOVE_ALL_SECURE_STOPS:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- reply->writeInt32(removeAllSecureStops());
- return OK;
- }
-
- case GET_HDCP_LEVELS:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpLevelUnknown;
- DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpLevelUnknown;
- status_t result = getHdcpLevels(&connected, &max);
- reply->writeInt32(connected);
- reply->writeInt32(max);
- reply->writeInt32(result);
- return OK;
- }
-
- case GET_NUMBER_OF_SESSIONS:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- uint32_t open = 0, max = 0;
- status_t result = getNumberOfSessions(&open, &max);
- reply->writeInt32(open);
- reply->writeInt32(max);
- reply->writeInt32(result);
- return OK;
- }
-
- case GET_SECURITY_LEVEL:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- Vector<uint8_t> sessionId;
- readVector(data, sessionId);
- DrmPlugin::SecurityLevel level = DrmPlugin::kSecurityLevelUnknown;
- status_t result = getSecurityLevel(sessionId, &level);
- reply->writeInt32(level);
- reply->writeInt32(result);
- return OK;
- }
-
- case GET_OFFLINE_LICENSE_KEYSET_IDS:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- List<Vector<uint8_t> > keySetIds;
- status_t result = getOfflineLicenseKeySetIds(keySetIds);
- size_t count = keySetIds.size();
- reply->writeInt32(count);
- List<Vector<uint8_t> >::iterator iter = keySetIds.begin();
- while(iter != keySetIds.end()) {
- size_t size = iter->size();
- reply->writeInt32(size);
- reply->write(iter->array(), iter->size());
- iter++;
- }
- reply->writeInt32(result);
- return OK;
- }
-
- case REMOVE_OFFLINE_LICENSE:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- Vector<uint8_t> keySetId;
- readVector(data, keySetId);
- reply->writeInt32(removeOfflineLicense(keySetId));
- return OK;
- }
-
- case GET_OFFLINE_LICENSE_STATE:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- Vector<uint8_t> keySetId;
- readVector(data, keySetId);
- DrmPlugin::OfflineLicenseState state;
- status_t result = getOfflineLicenseState(keySetId, &state);
- reply->writeInt32(static_cast<DrmPlugin::OfflineLicenseState>(state));
- reply->writeInt32(result);
- return OK;
- }
-
- case GET_PROPERTY_STRING:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- String8 name = data.readString8();
- String8 value;
- status_t result = getPropertyString(name, value);
- reply->writeString8(value);
- reply->writeInt32(result);
- return OK;
- }
-
- case GET_PROPERTY_BYTE_ARRAY:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- String8 name = data.readString8();
- Vector<uint8_t> value;
- status_t result = getPropertyByteArray(name, value);
- writeVector(reply, value);
- reply->writeInt32(result);
- return OK;
- }
-
- case SET_PROPERTY_STRING:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- String8 name = data.readString8();
- String8 value = data.readString8();
- reply->writeInt32(setPropertyString(name, value));
- return OK;
- }
-
- case SET_PROPERTY_BYTE_ARRAY:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- String8 name = data.readString8();
- Vector<uint8_t> value;
- readVector(data, value);
- reply->writeInt32(setPropertyByteArray(name, value));
- return OK;
- }
-
- case GET_METRICS:
- {
- CHECK_INTERFACE(IDrm, data, reply);
-
- os::PersistableBundle metrics;
- status_t result = getMetrics(&metrics);
- // The reply data is ordered as
- // 1) 32 bit integer reply followed by
- // 2) Serialized PersistableBundle containing metrics.
- // Only write the metrics if the getMetrics result was
- // OK and we successfully added the status to reply.
- status_t parcel_result = reply->writeInt32(result);
- if (result == OK && parcel_result == OK) {
- parcel_result = metrics.writeToParcel(reply);
- }
- return parcel_result;
- }
-
- case SET_CIPHER_ALGORITHM:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- Vector<uint8_t> sessionId;
- readVector(data, sessionId);
- String8 algorithm = data.readString8();
- reply->writeInt32(setCipherAlgorithm(sessionId, algorithm));
- return OK;
- }
-
- case SET_MAC_ALGORITHM:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- Vector<uint8_t> sessionId;
- readVector(data, sessionId);
- String8 algorithm = data.readString8();
- reply->writeInt32(setMacAlgorithm(sessionId, algorithm));
- return OK;
- }
-
- case ENCRYPT:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- Vector<uint8_t> sessionId, keyId, input, iv, output;
- readVector(data, sessionId);
- readVector(data, keyId);
- readVector(data, input);
- readVector(data, iv);
- uint32_t result = encrypt(sessionId, keyId, input, iv, output);
- writeVector(reply, output);
- reply->writeInt32(result);
- return OK;
- }
-
- case DECRYPT:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- Vector<uint8_t> sessionId, keyId, input, iv, output;
- readVector(data, sessionId);
- readVector(data, keyId);
- readVector(data, input);
- readVector(data, iv);
- uint32_t result = decrypt(sessionId, keyId, input, iv, output);
- writeVector(reply, output);
- reply->writeInt32(result);
- return OK;
- }
-
- case SIGN:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- Vector<uint8_t> sessionId, keyId, message, signature;
- readVector(data, sessionId);
- readVector(data, keyId);
- readVector(data, message);
- uint32_t result = sign(sessionId, keyId, message, signature);
- writeVector(reply, signature);
- reply->writeInt32(result);
- return OK;
- }
-
- case VERIFY:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- Vector<uint8_t> sessionId, keyId, message, signature;
- readVector(data, sessionId);
- readVector(data, keyId);
- readVector(data, message);
- readVector(data, signature);
- bool match = false;
- uint32_t result = verify(sessionId, keyId, message, signature, match);
- reply->writeInt32(match);
- reply->writeInt32(result);
- return OK;
- }
-
- case SIGN_RSA:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- Vector<uint8_t> sessionId, message, wrappedKey, signature;
- readVector(data, sessionId);
- String8 algorithm = data.readString8();
- readVector(data, message);
- readVector(data, wrappedKey);
- uint32_t result = signRSA(sessionId, algorithm, message, wrappedKey, signature);
- writeVector(reply, signature);
- reply->writeInt32(result);
- return OK;
- }
-
- case SET_LISTENER: {
- CHECK_INTERFACE(IDrm, data, reply);
- sp<IDrmClient> listener =
- interface_cast<IDrmClient>(data.readStrongBinder());
- reply->writeInt32(setListener(listener));
- return NO_ERROR;
- } break;
-
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-} // namespace android
diff --git a/drm/libmediadrm/IDrmClient.cpp b/drm/libmediadrm/IDrmClient.cpp
deleted file mode 100644
index 357de9d..0000000
--- a/drm/libmediadrm/IDrmClient.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
-**
-** Copyright 2013, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "IDrmClient"
-#include <utils/Log.h>
-
-#include <utils/RefBase.h>
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-
-#include <media/IMediaPlayerClient.h>
-#include <mediadrm/IDrmClient.h>
-
-namespace android {
-
-enum {
- NOTIFY = IBinder::FIRST_CALL_TRANSACTION,
-};
-
-class BpDrmClient: public BpInterface<IDrmClient>
-{
-public:
- explicit BpDrmClient(const sp<IBinder>& impl)
- : BpInterface<IDrmClient>(impl)
- {
- }
-
- virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IDrmClient::getInterfaceDescriptor());
- data.writeInt32((int)eventType);
- data.writeInt32(extra);
- if (obj && obj->dataSize() > 0) {
- data.appendFrom(const_cast<Parcel *>(obj), 0, obj->dataSize());
- }
- remote()->transact(NOTIFY, data, &reply, IBinder::FLAG_ONEWAY);
- }
-};
-
-IMPLEMENT_META_INTERFACE(DrmClient, "android.media.IDrmClient");
-
-// ----------------------------------------------------------------------
-
-status_t BnDrmClient::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch (code) {
- case NOTIFY: {
- CHECK_INTERFACE(IDrmClient, data, reply);
- int eventType = data.readInt32();
- int extra = data.readInt32();
- Parcel obj;
- if (data.dataAvail() > 0) {
- obj.appendFrom(const_cast<Parcel *>(&data), data.dataPosition(), data.dataAvail());
- }
-
- notify((DrmPlugin::EventType)eventType, extra, &obj);
- return NO_ERROR;
- } break;
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-} // namespace android
diff --git a/drm/libmediadrm/IMediaDrmService.cpp b/drm/libmediadrm/IMediaDrmService.cpp
deleted file mode 100644
index f320d0b..0000000
--- a/drm/libmediadrm/IMediaDrmService.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
-**
-** Copyright 2015, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <binder/Parcel.h>
-#include <binder/IMemory.h>
-#include <mediadrm/ICrypto.h>
-#include <mediadrm/IDrm.h>
-#include <mediadrm/IMediaDrmService.h>
-
-#include <utils/Errors.h> // for status_t
-#include <utils/String8.h>
-
-namespace android {
-
-enum {
- MAKE_CRYPTO = IBinder::FIRST_CALL_TRANSACTION,
- MAKE_DRM,
-};
-
-class BpMediaDrmService: public BpInterface<IMediaDrmService>
-{
-public:
- explicit BpMediaDrmService(const sp<IBinder>& impl)
- : BpInterface<IMediaDrmService>(impl)
- {
- }
-
- virtual sp<ICrypto> makeCrypto() {
- Parcel data, reply;
- data.writeInterfaceToken(IMediaDrmService::getInterfaceDescriptor());
- remote()->transact(MAKE_CRYPTO, data, &reply);
- return interface_cast<ICrypto>(reply.readStrongBinder());
- }
-
- virtual sp<IDrm> makeDrm() {
- Parcel data, reply;
- data.writeInterfaceToken(IMediaDrmService::getInterfaceDescriptor());
- remote()->transact(MAKE_DRM, data, &reply);
- return interface_cast<IDrm>(reply.readStrongBinder());
- }
-
-};
-
-IMPLEMENT_META_INTERFACE(MediaDrmService, "android.media.IMediaDrmService");
-
-// ----------------------------------------------------------------------
-
-status_t BnMediaDrmService::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch (code) {
- case MAKE_CRYPTO: {
- CHECK_INTERFACE(IMediaDrmService, data, reply);
- sp<ICrypto> crypto = makeCrypto();
- reply->writeStrongBinder(IInterface::asBinder(crypto));
- return NO_ERROR;
- } break;
- case MAKE_DRM: {
- CHECK_INTERFACE(IMediaDrmService, data, reply);
- sp<IDrm> drm = makeDrm();
- reply->writeStrongBinder(IInterface::asBinder(drm));
- return NO_ERROR;
- } break;
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-// ----------------------------------------------------------------------------
-
-} // namespace android
diff --git a/drm/libmediadrm/PluginMetricsReporting.cpp b/drm/libmediadrm/PluginMetricsReporting.cpp
index 8cd6f96..b0abf83 100644
--- a/drm/libmediadrm/PluginMetricsReporting.cpp
+++ b/drm/libmediadrm/PluginMetricsReporting.cpp
@@ -21,7 +21,7 @@
#include <inttypes.h>
-#include <media/MediaAnalyticsItem.h>
+#include <media/MediaMetrics.h>
#include <utils/Log.h>
@@ -33,20 +33,18 @@
status_t reportVendorMetrics(const std::string& metrics,
const String8& name,
- const String8& appPackageName) {
- std::unique_ptr<MediaAnalyticsItem> analyticsItem(MediaAnalyticsItem::create(name.c_str()));
- analyticsItem->generateSessionID();
-
- std::string app_package_name(appPackageName.c_str(), appPackageName.size());
- analyticsItem->setPkgName(app_package_name);
+ uid_t appUid) {
+ mediametrics_handle_t analyticsItem(mediametrics_create(name.c_str()));
+ mediametrics_setUid(analyticsItem, appUid);
if (metrics.size() > 0) {
- analyticsItem->setCString(kSerializedMetricsField, metrics.c_str());
+ mediametrics_setCString(analyticsItem, kSerializedMetricsField, metrics.c_str());
}
- if (!analyticsItem->selfrecord()) {
- ALOGE("selfrecord() returned false. sessioId %" PRId64, analyticsItem->getSessionID());
+ if (!mediametrics_selfRecord(analyticsItem)) {
+ ALOGE("%s: selfrecord() returned false", __func__);
}
+ mediametrics_delete(analyticsItem);
return OK;
}
@@ -69,13 +67,13 @@
status_t reportDrmPluginMetrics(const std::string& b64EncodedMetrics,
const String8& vendor,
const String8& description,
- const String8& appPackageName) {
+ uid_t appUid) {
String8 name = String8::format("drm.vendor.%s.%s",
sanitize(vendor).c_str(),
sanitize(description).c_str());
- return reportVendorMetrics(b64EncodedMetrics, name, appPackageName);
+ return reportVendorMetrics(b64EncodedMetrics, name, appUid);
}
} // namespace android
diff --git a/drm/libmediadrm/TEST_MAPPING b/drm/libmediadrm/TEST_MAPPING
new file mode 100644
index 0000000..bc15879
--- /dev/null
+++ b/drm/libmediadrm/TEST_MAPPING
@@ -0,0 +1,26 @@
+{
+ "presubmit": [
+ {
+ "name": "GtsMediaTestCases",
+ "options" : [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "include-filter": "com.google.android.media.gts.WidevineGenericOpsTests"
+ },
+ {
+ "include-filter": "com.google.android.media.gts.MediaDrmTest"
+ },
+ {
+ "include-filter": "com.google.android.media.gts.WidevineDashPolicyTests"
+ }
+ ]
+ }
+ ],
+ "imports": [
+ {
+ "path": "frameworks/av/drm/mediadrm/plugins"
+ }
+ ]
+}
diff --git a/drm/libmediadrm/include/mediadrm/CryptoHal.h b/drm/libmediadrm/include/mediadrm/CryptoHal.h
new file mode 100644
index 0000000..c9fda67
--- /dev/null
+++ b/drm/libmediadrm/include/mediadrm/CryptoHal.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CRYPTO_HAL_H_
+
+#define CRYPTO_HAL_H_
+
+#include <android/hardware/drm/1.0/ICryptoFactory.h>
+#include <android/hardware/drm/1.0/ICryptoPlugin.h>
+#include <android/hardware/drm/1.1/ICryptoFactory.h>
+#include <android/hardware/drm/1.2/ICryptoPlugin.h>
+
+#include <mediadrm/ICrypto.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+
+namespace drm = ::android::hardware::drm;
+using drm::V1_0::ICryptoFactory;
+using drm::V1_0::ICryptoPlugin;
+using drm::V1_0::SharedBuffer;
+using drm::V1_0::DestinationBuffer;
+
+using ::android::hardware::HidlMemory;
+
+class IMemoryHeap;
+
+namespace android {
+
+struct CryptoHal : public ICrypto {
+ CryptoHal();
+ virtual ~CryptoHal();
+
+ virtual status_t initCheck() const;
+
+ virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]);
+
+ virtual status_t createPlugin(
+ const uint8_t uuid[16], const void *data, size_t size);
+
+ virtual status_t destroyPlugin();
+
+ virtual bool requiresSecureDecoderComponent(
+ const char *mime) const;
+
+ virtual void notifyResolution(uint32_t width, uint32_t height);
+
+ virtual status_t setMediaDrmSession(const Vector<uint8_t> &sessionId);
+
+ virtual ssize_t decrypt(const uint8_t key[16], const uint8_t iv[16],
+ CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
+ const ::SharedBuffer &source, size_t offset,
+ const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
+ const ::DestinationBuffer &destination,
+ AString *errorDetailMsg);
+
+ virtual int32_t setHeap(const sp<HidlMemory>& heap) {
+ return setHeapBase(heap);
+ }
+ virtual void unsetHeap(int32_t seqNum) { clearHeapBase(seqNum); }
+
+private:
+ mutable Mutex mLock;
+
+ const Vector<sp<ICryptoFactory>> mFactories;
+ sp<ICryptoPlugin> mPlugin;
+ sp<drm::V1_2::ICryptoPlugin> mPluginV1_2;
+
+ /**
+ * mInitCheck is:
+ * NO_INIT if a plugin hasn't been created yet
+ * ERROR_UNSUPPORTED if a plugin can't be created for the uuid
+ * OK after a plugin has been created and mPlugin is valid
+ */
+ status_t mInitCheck;
+
+ KeyedVector<int32_t, size_t> mHeapSizes;
+ int32_t mHeapSeqNum;
+
+ Vector<sp<ICryptoFactory>> makeCryptoFactories();
+ sp<ICryptoPlugin> makeCryptoPlugin(const sp<ICryptoFactory>& factory,
+ const uint8_t uuid[16], const void *initData, size_t size);
+
+ int32_t setHeapBase(const sp<HidlMemory>& heap);
+ void clearHeapBase(int32_t seqNum);
+
+ status_t checkSharedBuffer(const ::SharedBuffer& buffer);
+
+ DISALLOW_EVIL_CONSTRUCTORS(CryptoHal);
+};
+
+} // namespace android
+
+#endif // CRYPTO_HAL_H_
diff --git a/drm/libmediadrm/include/mediadrm/DrmHal.h b/drm/libmediadrm/include/mediadrm/DrmHal.h
new file mode 100644
index 0000000..3b4639b
--- /dev/null
+++ b/drm/libmediadrm/include/mediadrm/DrmHal.h
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DRM_HAL_H_
+
+#define DRM_HAL_H_
+
+#include <android/hardware/drm/1.0/IDrmFactory.h>
+#include <android/hardware/drm/1.0/IDrmPlugin.h>
+#include <android/hardware/drm/1.1/IDrmFactory.h>
+#include <android/hardware/drm/1.1/IDrmPlugin.h>
+#include <android/hardware/drm/1.2/IDrmFactory.h>
+#include <android/hardware/drm/1.2/IDrmPlugin.h>
+#include <android/hardware/drm/1.2/IDrmPluginListener.h>
+
+#include <mediadrm/DrmMetrics.h>
+#include <mediadrm/DrmSessionManager.h>
+#include <mediadrm/IDrm.h>
+#include <mediadrm/IDrmClient.h>
+#include <mediadrm/IDrmMetricsConsumer.h>
+#include <utils/threads.h>
+
+namespace drm = ::android::hardware::drm;
+using drm::V1_0::EventType;
+using drm::V1_0::IDrmFactory;
+using drm::V1_0::IDrmPlugin;
+using drm::V1_0::IDrmPluginListener;
+using drm::V1_1::SecurityLevel;
+using drm::V1_2::KeyStatus;
+using drm::V1_2::OfflineLicenseState;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+typedef drm::V1_2::IDrmPluginListener IDrmPluginListener_V1_2;
+typedef drm::V1_0::KeyStatus KeyStatus_V1_0;
+
+namespace android {
+
+struct DrmSessionClientInterface;
+
+inline bool operator==(const Vector<uint8_t> &l, const Vector<uint8_t> &r) {
+ if (l.size() != r.size()) return false;
+ return memcmp(l.array(), r.array(), l.size()) == 0;
+}
+
+struct DrmHal : public IDrm,
+ public IDrmPluginListener_V1_2 {
+
+ struct DrmSessionClient;
+
+ DrmHal();
+ virtual ~DrmHal();
+
+ virtual status_t initCheck() const;
+
+ virtual status_t isCryptoSchemeSupported(const uint8_t uuid[16],
+ const String8& mimeType,
+ DrmPlugin::SecurityLevel level,
+ bool *isSupported);
+
+ virtual status_t createPlugin(const uint8_t uuid[16],
+ const String8 &appPackageName);
+
+ virtual status_t destroyPlugin();
+
+ virtual status_t openSession(DrmPlugin::SecurityLevel level,
+ Vector<uint8_t> &sessionId);
+
+ virtual status_t closeSession(Vector<uint8_t> const &sessionId);
+
+ virtual status_t
+ getKeyRequest(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &initData,
+ String8 const &mimeType, DrmPlugin::KeyType keyType,
+ KeyedVector<String8, String8> const &optionalParameters,
+ Vector<uint8_t> &request, String8 &defaultUrl,
+ DrmPlugin::KeyRequestType *keyRequestType);
+
+ virtual status_t provideKeyResponse(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &response,
+ Vector<uint8_t> &keySetId);
+
+ virtual status_t removeKeys(Vector<uint8_t> const &keySetId);
+
+ virtual status_t restoreKeys(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keySetId);
+
+ virtual status_t queryKeyStatus(Vector<uint8_t> const &sessionId,
+ KeyedVector<String8, String8> &infoMap) const;
+
+ virtual status_t getProvisionRequest(String8 const &certType,
+ String8 const &certAuthority,
+ Vector<uint8_t> &request,
+ String8 &defaulUrl);
+
+ virtual status_t provideProvisionResponse(Vector<uint8_t> const &response,
+ Vector<uint8_t> &certificate,
+ Vector<uint8_t> &wrappedKey);
+
+ virtual status_t getSecureStops(List<Vector<uint8_t>> &secureStops);
+ virtual status_t getSecureStopIds(List<Vector<uint8_t>> &secureStopIds);
+ virtual status_t getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop);
+
+ virtual status_t releaseSecureStops(Vector<uint8_t> const &ssRelease);
+ virtual status_t removeSecureStop(Vector<uint8_t> const &ssid);
+ virtual status_t removeAllSecureStops();
+
+ virtual status_t getHdcpLevels(DrmPlugin::HdcpLevel *connectedLevel,
+ DrmPlugin::HdcpLevel *maxLevel) const;
+ virtual status_t getNumberOfSessions(uint32_t *currentSessions,
+ uint32_t *maxSessions) const;
+ virtual status_t getSecurityLevel(Vector<uint8_t> const &sessionId,
+ DrmPlugin::SecurityLevel *level) const;
+
+ virtual status_t getOfflineLicenseKeySetIds(List<Vector<uint8_t>> &keySetIds) const;
+ virtual status_t removeOfflineLicense(Vector<uint8_t> const &keySetId);
+ virtual status_t getOfflineLicenseState(Vector<uint8_t> const &keySetId,
+ DrmPlugin::OfflineLicenseState *licenseState) const;
+
+ virtual status_t getPropertyString(String8 const &name, String8 &value ) const;
+ virtual status_t getPropertyByteArray(String8 const &name,
+ Vector<uint8_t> &value ) const;
+ virtual status_t setPropertyString(String8 const &name, String8 const &value ) const;
+ virtual status_t setPropertyByteArray(String8 const &name,
+ Vector<uint8_t> const &value ) const;
+ virtual status_t getMetrics(const sp<IDrmMetricsConsumer> &consumer);
+
+ virtual status_t setCipherAlgorithm(Vector<uint8_t> const &sessionId,
+ String8 const &algorithm);
+
+ virtual status_t setMacAlgorithm(Vector<uint8_t> const &sessionId,
+ String8 const &algorithm);
+
+ virtual status_t encrypt(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &input,
+ Vector<uint8_t> const &iv,
+ Vector<uint8_t> &output);
+
+ virtual status_t decrypt(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &input,
+ Vector<uint8_t> const &iv,
+ Vector<uint8_t> &output);
+
+ virtual status_t sign(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &message,
+ Vector<uint8_t> &signature);
+
+ virtual status_t verify(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &message,
+ Vector<uint8_t> const &signature,
+ bool &match);
+
+ virtual status_t signRSA(Vector<uint8_t> const &sessionId,
+ String8 const &algorithm,
+ Vector<uint8_t> const &message,
+ Vector<uint8_t> const &wrappedKey,
+ Vector<uint8_t> &signature);
+
+ virtual status_t setListener(const sp<IDrmClient>& listener);
+
+ // Methods of IDrmPluginListener
+ Return<void> sendEvent(EventType eventType,
+ const hidl_vec<uint8_t>& sessionId, const hidl_vec<uint8_t>& data);
+
+ Return<void> sendExpirationUpdate(const hidl_vec<uint8_t>& sessionId,
+ int64_t expiryTimeInMS);
+
+ Return<void> sendKeysChange(const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<KeyStatus_V1_0>& keyStatusList, bool hasNewUsableKey);
+
+ Return<void> sendKeysChange_1_2(const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<KeyStatus>& keyStatusList, bool hasNewUsableKey);
+
+ Return<void> sendSessionLostState(const hidl_vec<uint8_t>& sessionId);
+
+private:
+ static Mutex mLock;
+
+ sp<IDrmClient> mListener;
+ mutable Mutex mEventLock;
+ mutable Mutex mNotifyLock;
+
+ const std::vector<sp<IDrmFactory>> mFactories;
+ sp<IDrmPlugin> mPlugin;
+ sp<drm::V1_1::IDrmPlugin> mPluginV1_1;
+ sp<drm::V1_2::IDrmPlugin> mPluginV1_2;
+ String8 mAppPackageName;
+
+ // Mutable to allow modification within GetPropertyByteArray.
+ mutable MediaDrmMetrics mMetrics;
+
+ std::vector<std::shared_ptr<DrmSessionClient>> mOpenSessions;
+ void closeOpenSessions();
+ void cleanup();
+
+ /**
+ * mInitCheck is:
+ * NO_INIT if a plugin hasn't been created yet
+ * ERROR_UNSUPPORTED if a plugin can't be created for the uuid
+ * OK after a plugin has been created and mPlugin is valid
+ */
+ status_t mInitCheck;
+
+ std::vector<sp<IDrmFactory>> makeDrmFactories();
+ sp<IDrmPlugin> makeDrmPlugin(const sp<IDrmFactory>& factory,
+ const uint8_t uuid[16], const String8& appPackageName);
+
+ void writeByteArray(Parcel &obj, const hidl_vec<uint8_t>& array);
+
+ void reportPluginMetrics() const;
+ void reportFrameworkMetrics() const;
+ status_t getPropertyStringInternal(String8 const &name, String8 &value) const;
+ status_t getPropertyByteArrayInternal(String8 const &name,
+ Vector<uint8_t> &value) const;
+ status_t matchMimeTypeAndSecurityLevel(const sp<IDrmFactory> &factory,
+ const uint8_t uuid[16],
+ const String8 &mimeType,
+ DrmPlugin::SecurityLevel level,
+ bool *isSupported);
+
+ DISALLOW_EVIL_CONSTRUCTORS(DrmHal);
+};
+
+} // namespace android
+
+#endif // DRM_HAL_H_
diff --git a/drm/libmediadrm/include/mediadrm/DrmMetrics.h b/drm/libmediadrm/include/mediadrm/DrmMetrics.h
new file mode 100644
index 0000000..100b8f7
--- /dev/null
+++ b/drm/libmediadrm/include/mediadrm/DrmMetrics.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DRM_METRICS_H_
+#define DRM_METRICS_H_
+
+#include <map>
+
+#include <android/hardware/drm/1.0/types.h>
+#include <android/hardware/drm/1.1/types.h>
+#include <android/hardware/drm/1.2/types.h>
+#include <binder/PersistableBundle.h>
+#include <media/CounterMetric.h>
+#include <media/EventMetric.h>
+#include <sys/types.h>
+
+namespace android {
+
+/**
+ * This class contains the definition of metrics captured within MediaDrm.
+ * It also contains a method for exporting all of the metrics to a
+ * PersistableBundle.
+ */
+class MediaDrmMetrics {
+ public:
+ explicit MediaDrmMetrics();
+ virtual ~MediaDrmMetrics() {};
+ // Count of openSession calls.
+ CounterMetric<status_t> mOpenSessionCounter;
+ // Count of closeSession calls.
+ CounterMetric<status_t> mCloseSessionCounter;
+ // Count and timing of getKeyRequest calls.
+ EventMetric<status_t> mGetKeyRequestTimeUs;
+ // Count and timing of provideKeyResponse calls.
+ EventMetric<status_t> mProvideKeyResponseTimeUs;
+ // Count of getProvisionRequest calls.
+ CounterMetric<status_t> mGetProvisionRequestCounter;
+ // Count of provideProvisionResponse calls.
+ CounterMetric<status_t> mProvideProvisionResponseCounter;
+
+ // Count of key status events broken out by status type.
+ CounterMetric<::android::hardware::drm::V1_2::KeyStatusType>
+ mKeyStatusChangeCounter;
+ // Count of events broken out by event type
+ CounterMetric<::android::hardware::drm::V1_0::EventType> mEventCounter;
+
+ // Count getPropertyByteArray calls to retrieve the device unique id.
+ CounterMetric<status_t> mGetDeviceUniqueIdCounter;
+
+ // Adds a session start time record.
+ void SetSessionStart(const Vector<uint8_t>& sessionId);
+
+ // Adds a session end time record.
+ void SetSessionEnd(const Vector<uint8_t>& sessionId);
+
+ // The app package name is the application package name that is using the
+ // instance. The app package name is held here for convenience. It is not
+ // serialized or exported with the metrics.
+ void SetAppPackageName(const String8& appPackageName) { mAppPackageName = appPackageName; }
+ const String8& GetAppPackageName() { return mAppPackageName; }
+
+ void SetAppUid(uid_t appUid) { mAppUid = appUid; }
+ uid_t GetAppUid() const { return mAppUid; }
+
+ // Get the serialized metrics. Metrics are formatted as a serialized
+ // DrmFrameworkMetrics proto. If there is a failure serializing the metrics,
+ // this returns an error. The parameter |serlializedMetrics| is owned by the
+ // caller and must not be null.
+ status_t GetSerializedMetrics(std::string* serializedMetrics);
+
+ // Get copy of session lifetimes.
+ std::map<std::string, std::pair<int64_t, int64_t>> GetSessionLifespans() const;
+
+ protected:
+ // This is visible for testing only.
+ virtual int64_t GetCurrentTimeMs();
+
+ private:
+ // Session lifetimes. A pair of values representing the milliseconds since
+ // epoch, UTC. The first value is the start time, the second is the end time.
+ std::map<std::string, std::pair<int64_t, int64_t>> mSessionLifespans;
+
+ String8 mAppPackageName;
+ uid_t mAppUid{~0u};
+};
+
+} // namespace android
+
+#endif // DRM_METRICS_H_
diff --git a/drm/libmediadrm/include/mediadrm/DrmMetricsConsumer.h b/drm/libmediadrm/include/mediadrm/DrmMetricsConsumer.h
new file mode 100644
index 0000000..bbbf4b5
--- /dev/null
+++ b/drm/libmediadrm/include/mediadrm/DrmMetricsConsumer.h
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+#include <binder/PersistableBundle.h>
+#include <mediadrm/IDrmMetricsConsumer.h>
+#include <utils/Errors.h>
+
+#ifndef ANDROID_METRICSCONSUMER_H_
+
+#define ANDROID_METRICSCONSUMER_H_
+
+namespace android {
+
+/**
+ * IDrmMetricsConsumer which saves IDrm/ICrypto metrics into a PersistableBundle.
+ *
+ * Example usage:
+ *
+ * PersistableBundle bundle;
+ * DrmMetricsConsumer consumer(&bundle);
+ * drm->exportMetrics(&consumer);
+ * crypto->exportMetrics(&consumer);
+ * // bundle now contains metrics from drm/crypto.
+ *
+ */
+struct DrmMetricsConsumer : public IDrmMetricsConsumer {
+ DrmMetricsConsumer(os::PersistableBundle *bundle) : mBundle(bundle) {}
+
+ status_t consumeFrameworkMetrics(const MediaDrmMetrics &) override;
+
+ status_t consumeHidlMetrics(
+ const String8 &/*vendor*/,
+ const hidl_vec<DrmMetricGroup> &/*pluginMetrics*/) override;
+
+ // Converts the DRM plugin metrics to a PersistableBundle. All of the metrics
+ // found in |pluginMetrics| are added to the |metricsBundle| parameter.
+ // |pluginBundle| is owned by the caller and must not be null.
+ //
+ // Each item in the pluginMetrics vector is added as a new PersistableBundle. E.g.
+ // DrmMetricGroup {
+ // metrics[0] {
+ // name: "buf_copy"
+ // attributes[0] {
+ // name: "size"
+ // type: INT64_TYPE
+ // int64Value: 1024
+ // }
+ // values[0] {
+ // componentName: "operation_count"
+ // type: INT64_TYPE
+ // int64Value: 75
+ // }
+ // values[1] {
+ // component_name: "average_time_seconds"
+ // type: DOUBLE_TYPE
+ // doubleValue: 0.00000042
+ // }
+ // }
+ // }
+ //
+ // becomes
+ //
+ // metricsBundle {
+ // "0": (PersistableBundle) {
+ // "attributes" : (PersistableBundle) {
+ // "size" : (int64) 1024
+ // }
+ // "operation_count" : (int64) 75
+ // "average_time_seconds" : (double) 0.00000042
+ // }
+ //
+ static status_t HidlMetricsToBundle(
+ const hardware::hidl_vec<hardware::drm::V1_1::DrmMetricGroup>& pluginMetrics,
+ os::PersistableBundle* metricsBundle);
+
+private:
+ os::PersistableBundle *mBundle;
+ DISALLOW_EVIL_CONSTRUCTORS(DrmMetricsConsumer);
+};
+
+} // namespace android
+
+#endif // ANDROID_METRICSCONSUMER_H_
diff --git a/media/libmedia/include/media/DrmPluginPath.h b/drm/libmediadrm/include/mediadrm/DrmPluginPath.h
similarity index 100%
rename from media/libmedia/include/media/DrmPluginPath.h
rename to drm/libmediadrm/include/mediadrm/DrmPluginPath.h
diff --git a/media/libmedia/include/media/DrmSessionClientInterface.h b/drm/libmediadrm/include/mediadrm/DrmSessionClientInterface.h
similarity index 100%
rename from media/libmedia/include/media/DrmSessionClientInterface.h
rename to drm/libmediadrm/include/mediadrm/DrmSessionClientInterface.h
diff --git a/drm/libmediadrm/include/mediadrm/DrmSessionManager.h b/drm/libmediadrm/include/mediadrm/DrmSessionManager.h
new file mode 100644
index 0000000..9e43504
--- /dev/null
+++ b/drm/libmediadrm/include/mediadrm/DrmSessionManager.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DRM_SESSION_MANAGER_H_
+
+#define DRM_SESSION_MANAGER_H_
+
+#include <aidl/android/media/IResourceManagerClient.h>
+#include <aidl/android/media/IResourceManagerService.h>
+#include <android/binder_auto_utils.h>
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/RefBase.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+#include <utils/Vector.h>
+
+#include <map>
+#include <memory>
+#include <utility>
+#include <vector>
+
+namespace android {
+
+class DrmSessionManagerTest;
+
+using aidl::android::media::IResourceManagerClient;
+using aidl::android::media::IResourceManagerService;
+
+bool isEqualSessionId(const Vector<uint8_t> &sessionId1, const Vector<uint8_t> &sessionId2);
+
+struct SessionInfo {
+ pid_t pid;
+ uid_t uid;
+ int64_t clientId;
+};
+
+typedef std::map<std::vector<uint8_t>, SessionInfo> SessionInfoMap;
+
+struct DrmSessionManager : public RefBase {
+ static sp<DrmSessionManager> Instance();
+
+ DrmSessionManager();
+ explicit DrmSessionManager(const std::shared_ptr<IResourceManagerService> &service);
+
+ void addSession(int pid,
+ const std::shared_ptr<IResourceManagerClient>& drm,
+ const Vector<uint8_t>& sessionId);
+ void useSession(const Vector<uint8_t>& sessionId);
+ void removeSession(const Vector<uint8_t>& sessionId);
+ bool reclaimSession(int callingPid);
+
+ // sanity check APIs
+ size_t getSessionCount() const;
+ bool containsSession(const Vector<uint8_t>& sessionId) const;
+
+ // implements DeathRecipient
+ void binderDied();
+
+protected:
+ virtual ~DrmSessionManager();
+
+private:
+ void init();
+
+ std::shared_ptr<IResourceManagerService> mService;
+ mutable Mutex mLock;
+ SessionInfoMap mSessionMap;
+ bool mInitialized;
+ ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+
+ DISALLOW_EVIL_CONSTRUCTORS(DrmSessionManager);
+};
+
+} // namespace android
+
+#endif // DRM_SESSION_MANAGER_H_
diff --git a/drm/libmediadrm/include/mediadrm/IDrm.h b/drm/libmediadrm/include/mediadrm/IDrm.h
new file mode 100644
index 0000000..0177c24
--- /dev/null
+++ b/drm/libmediadrm/include/mediadrm/IDrm.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <media/stagefright/foundation/ABase.h>
+#include <media/drm/DrmAPI.h>
+#include <mediadrm/IDrmClient.h>
+#include <mediadrm/IDrmMetricsConsumer.h>
+
+#ifndef ANDROID_IDRM_H_
+
+#define ANDROID_IDRM_H_
+
+namespace android {
+
+struct AString;
+
+struct IDrm : public virtual RefBase {
+
+ virtual ~IDrm() {}
+
+ virtual status_t initCheck() const = 0;
+
+ virtual status_t isCryptoSchemeSupported(const uint8_t uuid[16],
+ const String8 &mimeType,
+ DrmPlugin::SecurityLevel securityLevel,
+ bool *result) = 0;
+
+ virtual status_t createPlugin(const uint8_t uuid[16],
+ const String8 &appPackageName) = 0;
+
+ virtual status_t destroyPlugin() = 0;
+
+ virtual status_t openSession(DrmPlugin::SecurityLevel securityLevel,
+ Vector<uint8_t> &sessionId) = 0;
+
+ virtual status_t closeSession(Vector<uint8_t> const &sessionId) = 0;
+
+ virtual status_t
+ getKeyRequest(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &initData,
+ String8 const &mimeType, DrmPlugin::KeyType keyType,
+ KeyedVector<String8, String8> const &optionalParameters,
+ Vector<uint8_t> &request, String8 &defaultUrl,
+ DrmPlugin::KeyRequestType *keyRequestType) = 0;
+
+ virtual status_t provideKeyResponse(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &response,
+ Vector<uint8_t> &keySetId) = 0;
+
+ virtual status_t removeKeys(Vector<uint8_t> const &keySetId) = 0;
+
+ virtual status_t restoreKeys(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keySetId) = 0;
+
+ virtual status_t queryKeyStatus(Vector<uint8_t> const &sessionId,
+ KeyedVector<String8, String8> &infoMap) const = 0;
+
+ virtual status_t getProvisionRequest(String8 const &certType,
+ String8 const &certAuthority,
+ Vector<uint8_t> &request,
+ String8 &defaulUrl) = 0;
+
+ virtual status_t provideProvisionResponse(Vector<uint8_t> const &response,
+ Vector<uint8_t> &certificate,
+ Vector<uint8_t> &wrappedKey) = 0;
+
+ virtual status_t getSecureStops(List<Vector<uint8_t>> &secureStops) = 0;
+ virtual status_t getSecureStopIds(List<Vector<uint8_t>> &secureStopIds) = 0;
+ virtual status_t getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop) = 0;
+
+ virtual status_t releaseSecureStops(Vector<uint8_t> const &ssRelease) = 0;
+ virtual status_t removeSecureStop(Vector<uint8_t> const &ssid) = 0;
+ virtual status_t removeAllSecureStops() = 0;
+
+ virtual status_t getHdcpLevels(DrmPlugin::HdcpLevel *connectedLevel,
+ DrmPlugin::HdcpLevel *maxLevel)
+ const = 0;
+ virtual status_t getNumberOfSessions(uint32_t *currentSessions,
+ uint32_t *maxSessions) const = 0;
+ virtual status_t getSecurityLevel(Vector<uint8_t> const &sessionId,
+ DrmPlugin::SecurityLevel *level) const = 0;
+
+ virtual status_t getOfflineLicenseKeySetIds(List<Vector<uint8_t>> &keySetIds) const = 0;
+ virtual status_t removeOfflineLicense(Vector<uint8_t> const &keySetId) = 0;
+ virtual status_t getOfflineLicenseState(Vector<uint8_t> const &keySetId,
+ DrmPlugin::OfflineLicenseState *licenseState) const = 0;
+
+ virtual status_t getPropertyString(String8 const &name, String8 &value) const = 0;
+ virtual status_t getPropertyByteArray(String8 const &name,
+ Vector<uint8_t> &value) const = 0;
+ virtual status_t setPropertyString(String8 const &name,
+ String8 const &value ) const = 0;
+ virtual status_t setPropertyByteArray(String8 const &name,
+ Vector<uint8_t> const &value) const = 0;
+
+ virtual status_t getMetrics(const sp<IDrmMetricsConsumer> &consumer) = 0;
+
+ virtual status_t setCipherAlgorithm(Vector<uint8_t> const &sessionId,
+ String8 const &algorithm) = 0;
+
+ virtual status_t setMacAlgorithm(Vector<uint8_t> const &sessionId,
+ String8 const &algorithm) = 0;
+
+ virtual status_t encrypt(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &input,
+ Vector<uint8_t> const &iv,
+ Vector<uint8_t> &output) = 0;
+
+ virtual status_t decrypt(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &input,
+ Vector<uint8_t> const &iv,
+ Vector<uint8_t> &output) = 0;
+
+ virtual status_t sign(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &message,
+ Vector<uint8_t> &signature) = 0;
+
+ virtual status_t verify(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &message,
+ Vector<uint8_t> const &signature,
+ bool &match) = 0;
+
+ virtual status_t signRSA(Vector<uint8_t> const &sessionId,
+ String8 const &algorithm,
+ Vector<uint8_t> const &message,
+ Vector<uint8_t> const &wrappedKey,
+ Vector<uint8_t> &signature) = 0;
+
+ virtual status_t setListener(const sp<IDrmClient>& listener) = 0;
+
+protected:
+ IDrm() {}
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(IDrm);
+};
+
+} // namespace android
+
+#endif // ANDROID_IDRM_H_
diff --git a/drm/libmediadrm/include/mediadrm/IDrmClient.h b/drm/libmediadrm/include/mediadrm/IDrmClient.h
new file mode 100644
index 0000000..fe25ae1
--- /dev/null
+++ b/drm/libmediadrm/include/mediadrm/IDrmClient.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_IDRMCLIENT_H
+#define ANDROID_IDRMCLIENT_H
+
+#include <utils/RefBase.h>
+#include <hidl/HidlSupport.h>
+#include <media/drm/DrmAPI.h>
+
+#include <cstdint>
+#include <vector>
+
+namespace android {
+
+struct DrmKeyStatus {
+ const uint32_t type;
+ const hardware::hidl_vec<uint8_t> keyId;
+};
+
+class IDrmClient: public virtual RefBase
+{
+public:
+ ~IDrmClient() {}
+
+ virtual void sendEvent(
+ DrmPlugin::EventType eventType,
+ const hardware::hidl_vec<uint8_t> &sessionId,
+ const hardware::hidl_vec<uint8_t> &data) = 0;
+
+ virtual void sendExpirationUpdate(
+ const hardware::hidl_vec<uint8_t> &sessionId,
+ int64_t expiryTimeInMS) = 0;
+
+ virtual void sendKeysChange(
+ const hardware::hidl_vec<uint8_t> &sessionId,
+ const std::vector<DrmKeyStatus> &keyStatusList,
+ bool hasNewUsableKey) = 0;
+
+ virtual void sendSessionLostState(
+ const hardware::hidl_vec<uint8_t> &sessionId) = 0;
+
+protected:
+ IDrmClient() {}
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(IDrmClient);
+};
+
+}; // namespace android
+
+#endif // ANDROID_IDRMCLIENT_H
diff --git a/drm/libmediadrm/include/mediadrm/IDrmMetricsConsumer.h b/drm/libmediadrm/include/mediadrm/IDrmMetricsConsumer.h
new file mode 100644
index 0000000..aef35c3
--- /dev/null
+++ b/drm/libmediadrm/include/mediadrm/IDrmMetricsConsumer.h
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+#include <android/hardware/drm/1.1/types.h>
+#include <hidl/HidlSupport.h>
+#include <media/stagefright/foundation/ABase.h>
+
+#ifndef ANDROID_IDRMMETRICSCONSUMER_H_
+
+#define ANDROID_IDRMMETRICSCONSUMER_H_
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::drm::V1_1::DrmMetricGroup;
+
+namespace android {
+
+class MediaDrmMetrics;
+class String8;
+
+/**
+ * Interface to consume metrics produced by the IDrm/ICrypto
+ *
+ * To use with IDrm:
+ * drm->exportMetrics(&consumer);
+ *
+ * IDrmMetricsConsumer::consumeFrameworkMetrics &
+ * IDrmMetricsConsumer::consumeHidlMetrics implementations
+ * would each be invoked once per call to IDrm::exportMetrics.
+ * |consumeFrameworkMetrics| would be called for plugin-agnostic
+ * framework metrics; |consumeHidlMetrics| would be called for
+ * plugin specific metrics.
+ *
+ * ----------------------------------------
+ *
+ * To use with ICrypto:
+ * crypto->exportMetrics(&consumer);
+ *
+ * IDrmMetricsConsumer::consumeHidlMetrics implementation
+ * would each be invoked once per call to ICrypto::exportMetrics.
+ * ICrypto metrics are plugin agnostic.
+ *
+ * ----------------------------------------
+ *
+ * For an example implementation of IDrmMetricsConsumer, please
+ * see DrmMetricsConsumer. DrmMetricsConsumer consumes IDrm/ICrypto
+ * metrics and saves the metrics to a PersistableBundle.
+ *
+ */
+struct IDrmMetricsConsumer : public RefBase {
+
+ virtual ~IDrmMetricsConsumer() {}
+
+ /**
+ * Consume framework (plugin agnostic) MediaDrmMetrics
+ */
+ virtual status_t consumeFrameworkMetrics(const MediaDrmMetrics &) = 0;
+
+ /**
+ * Consume list of DrmMetricGroup with optional Drm vendor name
+ */
+ virtual status_t consumeHidlMetrics(
+ const String8 &vendor,
+ const hidl_vec<DrmMetricGroup> &pluginMetrics) = 0;
+
+protected:
+ IDrmMetricsConsumer() {}
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(IDrmMetricsConsumer);
+};
+
+} // namespace android
+
+#endif // ANDROID_IDRMMETRICSCONSUMER_H_
diff --git a/media/libmedia/include/media/SharedLibrary.h b/drm/libmediadrm/include/mediadrm/SharedLibrary.h
similarity index 100%
rename from media/libmedia/include/media/SharedLibrary.h
rename to drm/libmediadrm/include/mediadrm/SharedLibrary.h
diff --git a/drm/libmediadrm/interface/mediadrm/DrmUtils.h b/drm/libmediadrm/interface/mediadrm/DrmUtils.h
new file mode 100644
index 0000000..20b3fe9
--- /dev/null
+++ b/drm/libmediadrm/interface/mediadrm/DrmUtils.h
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_DRMUTILS_H
+#define ANDROID_DRMUTILS_H
+
+#include <android/hardware/drm/1.0/ICryptoFactory.h>
+#include <android/hardware/drm/1.0/IDrmFactory.h>
+#include <utils/Errors.h> // for status_t
+#include <utils/StrongPointer.h>
+#include <vector>
+
+using namespace ::android::hardware::drm;
+
+namespace android {
+
+struct ICrypto;
+struct IDrm;
+
+namespace DrmUtils {
+
+bool UseDrmService();
+
+sp<IDrm> MakeDrm(status_t *pstatus = nullptr);
+
+sp<ICrypto> MakeCrypto(status_t *pstatus = nullptr);
+
+template<typename BA, typename PARCEL>
+void WriteByteArray(PARCEL &obj, const BA &vec) {
+ obj.writeInt32(vec.size());
+ if (vec.size()) {
+ obj.write(vec.data(), vec.size());
+ }
+}
+
+template<typename ET, typename BA, typename PARCEL>
+void WriteEventToParcel(
+ PARCEL &obj,
+ ET eventType,
+ const BA &sessionId,
+ const BA &data) {
+ WriteByteArray(obj, sessionId);
+ WriteByteArray(obj, data);
+ obj.writeInt32(eventType);
+}
+
+template<typename BA, typename PARCEL>
+void WriteExpirationUpdateToParcel(
+ PARCEL &obj,
+ const BA &sessionId,
+ int64_t expiryTimeInMS) {
+ WriteByteArray(obj, sessionId);
+ obj.writeInt64(expiryTimeInMS);
+}
+
+template<typename BA, typename KSL, typename PARCEL>
+void WriteKeysChange(
+ PARCEL &obj,
+ const BA &sessionId,
+ const KSL &keyStatusList,
+ bool hasNewUsableKey) {
+ WriteByteArray(obj, sessionId);
+ obj.writeInt32(keyStatusList.size());
+ for (const auto &keyStatus : keyStatusList) {
+ WriteByteArray(obj, keyStatus.keyId);
+ obj.writeInt32(keyStatus.type);
+ }
+ obj.writeInt32(hasNewUsableKey);
+}
+
+std::vector<sp<::V1_0::IDrmFactory>> MakeDrmFactories(const uint8_t uuid[16] = nullptr);
+
+std::vector<sp<::V1_0::IDrmPlugin>> MakeDrmPlugins(const uint8_t uuid[16],
+ const char *appPackageName);
+
+std::vector<sp<::V1_0::ICryptoFactory>> MakeCryptoFactories(const uint8_t uuid[16]);
+
+std::vector<sp<::V1_0::ICryptoPlugin>> MakeCryptoPlugins(const uint8_t uuid[16],
+ const void *initData, size_t initDataSize);
+
+} // namespace DrmUtils
+
+} // namespace android
+
+#endif // ANDROID_DRMUTILS_H
diff --git a/drm/libmediadrm/interface/mediadrm/ICrypto.h b/drm/libmediadrm/interface/mediadrm/ICrypto.h
new file mode 100644
index 0000000..df980ae
--- /dev/null
+++ b/drm/libmediadrm/interface/mediadrm/ICrypto.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cutils/native_handle.h>
+#include <media/hardware/CryptoAPI.h>
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/RefBase.h>
+#include <utils/StrongPointer.h>
+
+#ifndef ANDROID_ICRYPTO_H_
+
+#define ANDROID_ICRYPTO_H_
+
+namespace android {
+namespace hardware {
+class HidlMemory;
+namespace drm {
+namespace V1_0 {
+struct SharedBuffer;
+struct DestinationBuffer;
+} // namespace V1_0
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
+namespace drm = ::android::hardware::drm;
+using drm::V1_0::SharedBuffer;
+
+namespace android {
+
+struct AString;
+
+struct ICrypto : public RefBase {
+
+ virtual ~ICrypto() {}
+
+ virtual status_t initCheck() const = 0;
+
+ virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) = 0;
+
+ virtual status_t createPlugin(
+ const uint8_t uuid[16], const void *data, size_t size) = 0;
+
+ virtual status_t destroyPlugin() = 0;
+
+ virtual bool requiresSecureDecoderComponent(
+ const char *mime) const = 0;
+
+ virtual void notifyResolution(uint32_t width, uint32_t height) = 0;
+
+ virtual status_t setMediaDrmSession(const Vector<uint8_t> &sessionId) = 0;
+
+ enum DestinationType {
+ kDestinationTypeSharedMemory, // non-secure
+ kDestinationTypeNativeHandle // secure
+ };
+
+ virtual ssize_t decrypt(const uint8_t /*key*/[16], const uint8_t /*iv*/[16],
+ CryptoPlugin::Mode /*mode*/, const CryptoPlugin::Pattern &/*pattern*/,
+ const drm::V1_0::SharedBuffer &/*source*/, size_t /*offset*/,
+ const CryptoPlugin::SubSample * /*subSamples*/, size_t /*numSubSamples*/,
+ const drm::V1_0::DestinationBuffer &/*destination*/, AString * /*errorDetailMsg*/) = 0;
+
+ /**
+ * Declare the heap that the shared memory source buffers passed
+ * to decrypt will be allocated from. Returns a sequence number
+ * that subsequent decrypt calls can use to refer to the heap,
+ * with -1 indicating failure.
+ */
+ virtual int32_t setHeap(const sp<hardware::HidlMemory>& heap) = 0;
+ virtual void unsetHeap(int32_t seqNum) = 0;
+
+protected:
+ ICrypto() {}
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(ICrypto);
+};
+
+} // namespace android
+
+#endif // ANDROID_ICRYPTO_H_
diff --git a/drm/libmediadrm/tests/Android.bp b/drm/libmediadrm/tests/Android.bp
index 9e0115e..6529387 100644
--- a/drm/libmediadrm/tests/Android.bp
+++ b/drm/libmediadrm/tests/Android.bp
@@ -3,8 +3,11 @@
cc_test {
name: "CounterMetric_test",
srcs: ["CounterMetric_test.cpp"],
+ header_libs: [
+ "libmedia_headers",
+ "libmediametrics_headers",
+ ],
shared_libs: ["libmediadrm"],
- include_dirs: ["frameworks/av/include/media"],
cflags: [
"-Werror",
"-Wall",
@@ -14,6 +17,9 @@
cc_test {
name: "DrmMetrics_test",
srcs: ["DrmMetrics_test.cpp"],
+ header_libs: [
+ "libmedia_headers"
+ ],
shared_libs: [
"android.hardware.drm@1.0",
"android.hardware.drm@1.1",
@@ -21,6 +27,8 @@
"libbinder",
"libhidlbase",
"liblog",
+ "libmediadrm",
+ "libmediadrmmetrics_consumer",
"libmediadrmmetrics_full",
"libmediametrics",
"libprotobuf-cpp-full",
@@ -28,7 +36,7 @@
],
static_libs: ["libgmock"],
include_dirs: [
- "frameworks/av/include/media",
+ "frameworks/av/drm/libmediadrm/include",
],
cflags: [
// Suppress unused parameter and no error options. These cause problems
@@ -40,12 +48,15 @@
cc_test {
name: "EventMetric_test",
srcs: ["EventMetric_test.cpp"],
+ header_libs: [
+ "libmedia_headers",
+ "libmediametrics_headers",
+ ],
shared_libs: [
"liblog",
"libmediadrm",
"libutils",
],
- include_dirs: ["frameworks/av/include/media"],
cflags: [
"-Werror",
"-Wall",
diff --git a/drm/libmediadrm/tests/CounterMetric_test.cpp b/drm/libmediadrm/tests/CounterMetric_test.cpp
index 6bca0da..c2becb4 100644
--- a/drm/libmediadrm/tests/CounterMetric_test.cpp
+++ b/drm/libmediadrm/tests/CounterMetric_test.cpp
@@ -16,7 +16,7 @@
#include <gtest/gtest.h>
-#include "CounterMetric.h"
+#include <media/CounterMetric.h>
namespace android {
diff --git a/drm/libmediadrm/tests/DrmMetrics_test.cpp b/drm/libmediadrm/tests/DrmMetrics_test.cpp
index 5c8a1b0..f362d60 100644
--- a/drm/libmediadrm/tests/DrmMetrics_test.cpp
+++ b/drm/libmediadrm/tests/DrmMetrics_test.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "DrmMetricsTest"
#include "mediadrm/DrmMetrics.h"
+#include "mediadrm/DrmMetricsConsumer.h"
#include <android/hardware/drm/1.0/types.h>
#include <android/hardware/drm/1.1/types.h>
@@ -58,8 +59,9 @@
TEST_F(MediaDrmMetricsTest, EmptySuccess) {
MediaDrmMetrics metrics;
PersistableBundle bundle;
+ DrmMetricsConsumer consumer(&bundle);
- metrics.Export(&bundle);
+ consumer.consumeFrameworkMetrics(metrics);
EXPECT_TRUE(bundle.empty());
}
@@ -85,8 +87,9 @@
metrics.mEventCounter.Increment(EventType::PROVISION_REQUIRED);
PersistableBundle bundle;
+ DrmMetricsConsumer consumer(&bundle);
- metrics.Export(&bundle);
+ consumer.consumeFrameworkMetrics(metrics);
EXPECT_EQ(11U, bundle.size());
// Verify the list of pairs of int64 metrics.
@@ -174,7 +177,8 @@
metrics.SetSessionEnd(sessionId1);
PersistableBundle bundle;
- metrics.Export(&bundle);
+ DrmMetricsConsumer consumer(&bundle);
+ consumer.consumeFrameworkMetrics(metrics);
EXPECT_EQ(35U, bundle.size());
// Verify the list of pairs of int64 metrics.
@@ -421,7 +425,7 @@
hidl_vec<DrmMetricGroup> hidlMetricGroups;
PersistableBundle bundleMetricGroups;
- ASSERT_EQ(OK, MediaDrmMetrics::HidlMetricsToBundle(hidlMetricGroups, &bundleMetricGroups));
+ ASSERT_EQ(OK, DrmMetricsConsumer::HidlMetricsToBundle(hidlMetricGroups, &bundleMetricGroups));
ASSERT_EQ(0U, bundleMetricGroups.size());
}
@@ -441,7 +445,7 @@
} } };
PersistableBundle bundleMetricGroups;
- ASSERT_EQ(OK, MediaDrmMetrics::HidlMetricsToBundle(hidl_vec<DrmMetricGroup>({hidlMetricGroup}),
+ ASSERT_EQ(OK, DrmMetricsConsumer::HidlMetricsToBundle(hidl_vec<DrmMetricGroup>({hidlMetricGroup}),
&bundleMetricGroups));
ASSERT_EQ(1U, bundleMetricGroups.size());
PersistableBundle bundleMetricGroup;
diff --git a/drm/libmediadrm/tests/EventMetric_test.cpp b/drm/libmediadrm/tests/EventMetric_test.cpp
index eb6c4f6..b3c3f62 100644
--- a/drm/libmediadrm/tests/EventMetric_test.cpp
+++ b/drm/libmediadrm/tests/EventMetric_test.cpp
@@ -16,7 +16,7 @@
#include <gtest/gtest.h>
-#include "EventMetric.h"
+#include <media/EventMetric.h>
namespace android {
diff --git a/drm/mediacas/plugins/clearkey/Android.bp b/drm/mediacas/plugins/clearkey/Android.bp
new file mode 100644
index 0000000..0113cb8
--- /dev/null
+++ b/drm/mediacas/plugins/clearkey/Android.bp
@@ -0,0 +1,55 @@
+//
+// Copyright (C) 2017 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.
+//
+
+cc_library_shared {
+ name: "libclearkeycasplugin",
+
+ srcs: [
+ "ClearKeyCasPlugin.cpp",
+ "ClearKeyFetcher.cpp",
+ "ClearKeyLicenseFetcher.cpp",
+ "ClearKeySessionLibrary.cpp",
+ "ecm.cpp",
+ "ecm_generator.cpp",
+ "JsonAssetLoader.cpp",
+ "protos/license_protos.proto",
+ ],
+
+ proprietary: true,
+ relative_install_path: "mediacas",
+
+ shared_libs: [
+ "libutils",
+ "liblog",
+ "libcrypto",
+ "libstagefright_foundation",
+ "libprotobuf-cpp-lite",
+ ],
+
+ header_libs: ["media_plugin_headers"],
+
+ static_libs: ["libjsmn"],
+
+ proto: {
+ type: "full",
+ export_proto_headers: true,
+ },
+
+ include_dirs: [
+ "frameworks/av/include",
+ "frameworks/native/include/media",
+ ],
+}
diff --git a/drm/mediacas/plugins/clearkey/Android.mk b/drm/mediacas/plugins/clearkey/Android.mk
deleted file mode 100644
index 4b139a8..0000000
--- a/drm/mediacas/plugins/clearkey/Android.mk
+++ /dev/null
@@ -1,71 +0,0 @@
-#
-# Copyright (C) 2017 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.
-#
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- ClearKeyCasPlugin.cpp \
- ClearKeyFetcher.cpp \
- ClearKeyLicenseFetcher.cpp \
- ClearKeySessionLibrary.cpp \
- ecm.cpp \
- ecm_generator.cpp \
- JsonAssetLoader.cpp \
- protos/license_protos.proto \
-
-LOCAL_MODULE := libclearkeycasplugin
-
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := mediacas
-
-LOCAL_SHARED_LIBRARIES := \
- libutils \
- liblog \
- libcrypto \
- libstagefright_foundation \
- libprotobuf-cpp-lite \
-
-LOCAL_HEADER_LIBRARIES := \
- media_plugin_headers
-
-LOCAL_STATIC_LIBRARIES := \
- libjsmn \
-
-LOCAL_MODULE_CLASS := SHARED_LIBRARIES
-
-LOCAL_PROTOC_OPTIMIZE_TYPE := full
-
-define proto_includes
-$(call local-generated-sources-dir)/proto/$(LOCAL_PATH)
-endef
-
-LOCAL_C_INCLUDES += \
- external/jsmn \
- frameworks/av/include \
- frameworks/native/include/media \
- $(call proto_includes)
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := \
- $(call proto_includes)
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-#########################################################################
-# Build unit tests
-
-include $(LOCAL_PATH)/tests/Android.mk
diff --git a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
index bf35224..af7c367 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
+++ b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
@@ -97,7 +97,8 @@
///////////////////////////////////////////////////////////////////////////////
ClearKeyCasPlugin::ClearKeyCasPlugin(
void *appData, CasPluginCallback callback)
- : mCallback(callback), mCallbackExt(NULL), mAppData(appData) {
+ : mCallback(callback), mCallbackExt(NULL), mStatusCallback(NULL),
+ mAppData(appData) {
ALOGV("CTOR");
}
@@ -112,6 +113,13 @@
ClearKeySessionLibrary::get()->destroyPlugin(this);
}
+status_t ClearKeyCasPlugin::setStatusCallback(
+ CasPluginStatusCallback callback) {
+ ALOGV("setStatusCallback");
+ mStatusCallback = callback;
+ return OK;
+}
+
status_t ClearKeyCasPlugin::setPrivateData(const CasData &/*data*/) {
ALOGV("setPrivateData");
@@ -135,6 +143,19 @@
return ClearKeySessionLibrary::get()->addSession(this, sessionId);
}
+status_t ClearKeyCasPlugin::openSession(uint32_t intent, uint32_t mode,
+ CasSessionId* sessionId) {
+ ALOGV("openSession with intent=%d, mode=%d", intent, mode);
+ // Echo the received information to the callback.
+ // Clear key plugin doesn't use any event, echo'ing for testing only.
+ if (mStatusCallback != NULL) {
+ mStatusCallback((void*)mAppData, intent, mode);
+ }
+
+ // Clear key plugin doesn't use intent and mode.
+ return ClearKeySessionLibrary::get()->addSession(this, sessionId);
+}
+
status_t ClearKeyCasPlugin::closeSession(const CasSessionId &sessionId) {
ALOGV("closeSession: sessionId=%s", sessionIdToString(sessionId).string());
std::shared_ptr<ClearKeyCasSession> session =
diff --git a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h
index f48d5b1..c6938e6 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h
+++ b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h
@@ -71,11 +71,17 @@
ClearKeyCasPlugin(void *appData, CasPluginCallbackExt callback);
virtual ~ClearKeyCasPlugin();
+ virtual status_t setStatusCallback(
+ CasPluginStatusCallback callback) override;
+
virtual status_t setPrivateData(
const CasData &data) override;
virtual status_t openSession(CasSessionId *sessionId) override;
+ virtual status_t openSession(uint32_t intent, uint32_t mode,
+ CasSessionId *sessionId) override;
+
virtual status_t closeSession(
const CasSessionId &sessionId) override;
@@ -105,6 +111,7 @@
std::unique_ptr<KeyFetcher> mKeyFetcher;
CasPluginCallback mCallback;
CasPluginCallbackExt mCallbackExt;
+ CasPluginStatusCallback mStatusCallback;
void* mAppData;
};
diff --git a/drm/mediacas/plugins/clearkey/ClearKeyFetcher.cpp b/drm/mediacas/plugins/clearkey/ClearKeyFetcher.cpp
index eaa3390..cb69f91 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeyFetcher.cpp
+++ b/drm/mediacas/plugins/clearkey/ClearKeyFetcher.cpp
@@ -89,7 +89,7 @@
// asset_id change. If it sends an EcmContainer with 2 Ecms with different
// asset_ids (old and new) then it might be best to prefetch the Emm.
if ((asset_.id() != 0) && (*asset_id != asset_.id())) {
- ALOGW("Asset_id change from %llu to %" PRIu64, asset_.id(), *asset_id);
+ ALOGW("Asset_id change from %" PRIu64 " to %" PRIu64, asset_.id(), *asset_id);
asset_.Clear();
}
diff --git a/drm/mediacas/plugins/clearkey/ecm.cpp b/drm/mediacas/plugins/clearkey/ecm.cpp
index 9fde13a..b3b5218 100644
--- a/drm/mediacas/plugins/clearkey/ecm.cpp
+++ b/drm/mediacas/plugins/clearkey/ecm.cpp
@@ -17,6 +17,8 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "ecm"
+#include <inttypes.h>
+
#include "ecm.h"
#include "ecm_generator.h"
#include "protos/license_protos.pb.h"
@@ -76,7 +78,7 @@
return status;
}
if (asset.id() != asset_from_emm.id()) {
- ALOGE("Asset_id from Emm (%llu) does not match asset_id from Ecm (%llu).",
+ ALOGE("Asset_id from Emm (%" PRIu64 ") does not match asset_id from Ecm (%" PRIu64 ").",
asset_from_emm.id(), asset.id());
return CLEARKEY_STATUS_INVALID_PARAMETER;
}
diff --git a/drm/mediacas/plugins/clearkey/tests/Android.bp b/drm/mediacas/plugins/clearkey/tests/Android.bp
new file mode 100644
index 0000000..575863c
--- /dev/null
+++ b/drm/mediacas/plugins/clearkey/tests/Android.bp
@@ -0,0 +1,45 @@
+//
+// Copyright (C) 2017 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.
+//
+
+cc_test {
+ name: "ClearKeyFetcherTest",
+
+ srcs: ["ClearKeyFetcherTest.cpp"],
+
+ vendor: true,
+
+ // LOCAL_LDFLAGS is needed here for the test to use the plugin, because
+ // the plugin is not in standard library search path. Without this .so
+ // loading fails at run-time (linking is okay).
+ ldflags: [
+ "-Wl,--rpath,${ORIGIN}/../../../system/vendor/lib/mediacas",
+ "-Wl,--enable-new-dtags",
+ ],
+
+ shared_libs: [
+ "libutils",
+ "libclearkeycasplugin",
+ "libstagefright_foundation",
+ "libprotobuf-cpp-lite",
+ "liblog",
+ ],
+
+ include_dirs: [
+ "frameworks/av/drm/mediacas/plugins/clearkey",
+ "frameworks/av/include",
+ "frameworks/native/include/media",
+ ],
+}
diff --git a/drm/mediacas/plugins/clearkey/tests/Android.mk b/drm/mediacas/plugins/clearkey/tests/Android.mk
deleted file mode 100644
index e1545af..0000000
--- a/drm/mediacas/plugins/clearkey/tests/Android.mk
+++ /dev/null
@@ -1,45 +0,0 @@
-#
-# Copyright (C) 2017 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.
-#
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
- ClearKeyFetcherTest.cpp
-
-LOCAL_MODULE := ClearKeyFetcherTest
-LOCAL_VENDOR_MODULE := true
-
-# LOCAL_LDFLAGS is needed here for the test to use the plugin, because
-# the plugin is not in standard library search path. Without this .so
-# loading fails at run-time (linking is okay).
-LOCAL_LDFLAGS := \
- -Wl,--rpath,\$${ORIGIN}/../../../system/vendor/lib/mediacas -Wl,--enable-new-dtags
-
-LOCAL_SHARED_LIBRARIES := \
- libutils libclearkeycasplugin libstagefright_foundation libprotobuf-cpp-lite liblog
-
-LOCAL_C_INCLUDES += \
- $(TOP)/frameworks/av/drm/mediacas/plugins/clearkey \
- $(TOP)/frameworks/av/include \
- $(TOP)/frameworks/native/include/media \
-
-LOCAL_MODULE_TAGS := tests
-
-include $(BUILD_NATIVE_TEST)
-
-
-
diff --git a/drm/mediacas/plugins/mock/Android.bp b/drm/mediacas/plugins/mock/Android.bp
new file mode 100644
index 0000000..e8a3c6f
--- /dev/null
+++ b/drm/mediacas/plugins/mock/Android.bp
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2017 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.
+//
+
+cc_library_shared {
+ name: "libmockcasplugin",
+
+ srcs: [
+ "MockCasPlugin.cpp",
+ "MockSessionLibrary.cpp",
+ ],
+
+ proprietary: true,
+ relative_install_path: "mediacas",
+
+ shared_libs: [
+ "libutils",
+ "liblog",
+ ],
+
+ header_libs: ["media_plugin_headers"],
+
+ include_dirs: [
+ "frameworks/av/include",
+ "frameworks/native/include/media",
+ ],
+}
diff --git a/drm/mediacas/plugins/mock/Android.mk b/drm/mediacas/plugins/mock/Android.mk
deleted file mode 100644
index a1d61da..0000000
--- a/drm/mediacas/plugins/mock/Android.mk
+++ /dev/null
@@ -1,39 +0,0 @@
-#
-# Copyright (C) 2017 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.
-#
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- MockCasPlugin.cpp \
- MockSessionLibrary.cpp \
-
-LOCAL_MODULE := libmockcasplugin
-
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := mediacas
-
-LOCAL_SHARED_LIBRARIES := \
- libutils liblog
-
-LOCAL_HEADER_LIBRARIES := media_plugin_headers
-
-LOCAL_C_INCLUDES += \
- $(TOP)/frameworks/av/include \
- $(TOP)/frameworks/native/include/media \
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/drm/mediacas/plugins/mock/MockCasPlugin.cpp b/drm/mediacas/plugins/mock/MockCasPlugin.cpp
index 2964791..f8bab0a 100644
--- a/drm/mediacas/plugins/mock/MockCasPlugin.cpp
+++ b/drm/mediacas/plugins/mock/MockCasPlugin.cpp
@@ -111,6 +111,12 @@
MockSessionLibrary::get()->destroyPlugin(this);
}
+status_t MockCasPlugin::setStatusCallback(
+ CasPluginStatusCallback /*callback*/) {
+ ALOGV("setStatusCallback");
+ return OK;
+}
+
status_t MockCasPlugin::setPrivateData(const CasData& /*data*/) {
ALOGV("setPrivateData");
return OK;
@@ -121,6 +127,13 @@
return MockSessionLibrary::get()->addSession(this, sessionId);
}
+status_t MockCasPlugin::openSession(uint32_t intent, uint32_t mode,
+ CasSessionId* sessionId) {
+ ALOGV("openSession with intent=%d, mode=%d", intent, mode);
+ // Clear key plugin doesn't use intent and mode.
+ return MockSessionLibrary::get()->addSession(this, sessionId);
+}
+
status_t MockCasPlugin::closeSession(const CasSessionId &sessionId) {
ALOGV("closeSession: sessionId=%s", arrayToString(sessionId).string());
Mutex::Autolock lock(mLock);
diff --git a/drm/mediacas/plugins/mock/MockCasPlugin.h b/drm/mediacas/plugins/mock/MockCasPlugin.h
index 74b540c..660fd44 100644
--- a/drm/mediacas/plugins/mock/MockCasPlugin.h
+++ b/drm/mediacas/plugins/mock/MockCasPlugin.h
@@ -65,11 +65,17 @@
MockCasPlugin();
virtual ~MockCasPlugin();
+ virtual status_t setStatusCallback(
+ CasPluginStatusCallback callback) override;
+
virtual status_t setPrivateData(
const CasData &data) override;
virtual status_t openSession(CasSessionId *sessionId) override;
+ virtual status_t openSession(uint32_t intent, uint32_t mode,
+ CasSessionId *sessionId) override;
+
virtual status_t closeSession(
const CasSessionId &sessionId) override;
diff --git a/drm/mediadrm/plugins/TEST_MAPPING b/drm/mediadrm/plugins/TEST_MAPPING
new file mode 100644
index 0000000..7bd1568
--- /dev/null
+++ b/drm/mediadrm/plugins/TEST_MAPPING
@@ -0,0 +1,18 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsMediaTestCases",
+ "options" : [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "include-filter": "android.media.cts.MediaDrmClearkeyTest"
+ },
+ {
+ "include-filter": "android.media.cts.MediaDrmMetricsTest"
+ }
+ ]
+ }
+ ]
+}
diff --git a/drm/mediadrm/plugins/clearkey/common/ClearKeyUUID.cpp b/drm/mediadrm/plugins/clearkey/common/ClearKeyUUID.cpp
index 0259a42..4e7daec 100644
--- a/drm/mediadrm/plugins/clearkey/common/ClearKeyUUID.cpp
+++ b/drm/mediadrm/plugins/clearkey/common/ClearKeyUUID.cpp
@@ -20,20 +20,28 @@
namespace clearkeydrm {
+namespace {
+
+const std::array<uint8_t, 16> kCommonPsshBoxUUID{
+ 0x10,0x77,0xEF,0xEC,0xC0,0xB2,0x4D,0x02,
+ 0xAC,0xE3,0x3C,0x1E,0x52,0xE2,0xFB,0x4B
+};
+
+// To be used in mpd to specify drm scheme for players
+const std::array<uint8_t, 16> kClearKeyUUID{
+ 0xE2,0x71,0x9D,0x58,0xA9,0x85,0xB3,0xC9,
+ 0x78,0x1A,0xB0,0x30,0xAF,0x78,0xD3,0x0E
+};
+
+}
+
bool isClearKeyUUID(const uint8_t uuid[16]) {
- static const uint8_t kCommonPsshBoxUUID[16] = {
- 0x10,0x77,0xEF,0xEC,0xC0,0xB2,0x4D,0x02,
- 0xAC,0xE3,0x3C,0x1E,0x52,0xE2,0xFB,0x4B
- };
+ return !memcmp(uuid, kCommonPsshBoxUUID.data(), kCommonPsshBoxUUID.size()) ||
+ !memcmp(uuid, kClearKeyUUID.data(), kClearKeyUUID.size());
+}
- // To be used in mpd to specify drm scheme for players
- static const uint8_t kClearKeyUUID[16] = {
- 0xE2,0x71,0x9D,0x58,0xA9,0x85,0xB3,0xC9,
- 0x78,0x1A,0xB0,0x30,0xAF,0x78,0xD3,0x0E
- };
-
- return !memcmp(uuid, kCommonPsshBoxUUID, sizeof(kCommonPsshBoxUUID)) ||
- !memcmp(uuid, kClearKeyUUID, sizeof(kClearKeyUUID));
+std::vector<std::array<uint8_t, 16>> getSupportedCryptoSchemes() {
+ return {kCommonPsshBoxUUID, kClearKeyUUID};
}
} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/include/ClearKeyUUID.h b/drm/mediadrm/plugins/clearkey/common/include/ClearKeyUUID.h
index ac99418..fe10fba 100644
--- a/drm/mediadrm/plugins/clearkey/common/include/ClearKeyUUID.h
+++ b/drm/mediadrm/plugins/clearkey/common/include/ClearKeyUUID.h
@@ -17,12 +17,16 @@
#ifndef CLEARKEY_UUID_H_
#define CLEARKEY_UUID_H_
-#include <stdint.h>
+#include <array>
+#include <cstdint>
+#include <vector>
namespace clearkeydrm {
bool isClearKeyUUID(const uint8_t uuid[16]);
+std::vector<std::array<uint8_t, 16>> getSupportedCryptoSchemes();
+
} // namespace clearkeydrm
#endif // CLEARKEY_UUID_H_
diff --git a/drm/mediadrm/plugins/clearkey/hidl/Android.bp b/drm/mediadrm/plugins/clearkey/hidl/Android.bp
index e91e918..a194416 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/Android.bp
+++ b/drm/mediadrm/plugins/clearkey/hidl/Android.bp
@@ -43,12 +43,12 @@
"android.hardware.drm@1.0",
"android.hardware.drm@1.1",
"android.hardware.drm@1.2",
+ "android.hardware.drm@1.3",
"libbase",
"libbinder",
"libcrypto",
"libhidlbase",
"libhidlmemory",
- "libhidltransport",
"liblog",
"libprotobuf-cpp-lite",
"libutils",
@@ -78,16 +78,37 @@
},
srcs: ["protos/DeviceFiles.proto"],
}
+
cc_binary {
name: "android.hardware.drm@1.2-service.clearkey",
defaults: ["clearkey_service_defaults"],
srcs: ["service.cpp"],
init_rc: ["android.hardware.drm@1.2-service.clearkey.rc"],
+ vintf_fragments: ["manifest_android.hardware.drm@1.2-service.clearkey.xml"],
}
+
cc_binary {
name: "android.hardware.drm@1.2-service-lazy.clearkey",
overrides: ["android.hardware.drm@1.2-service.clearkey"],
defaults: ["clearkey_service_defaults"],
srcs: ["serviceLazy.cpp"],
init_rc: ["android.hardware.drm@1.2-service-lazy.clearkey.rc"],
+ vintf_fragments: ["manifest_android.hardware.drm@1.2-service.clearkey.xml"],
+}
+
+cc_binary {
+ name: "android.hardware.drm@1.3-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"],
+}
+
+cc_binary {
+ name: "android.hardware.drm@1.3-service-lazy.clearkey",
+ overrides: ["android.hardware.drm@1.3-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"],
}
diff --git a/drm/mediadrm/plugins/clearkey/hidl/CreatePluginFactories.cpp b/drm/mediadrm/plugins/clearkey/hidl/CreatePluginFactories.cpp
index 1410d77..bfb0e05 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_2 {
+namespace V1_3 {
namespace clearkey {
extern "C" {
@@ -38,7 +38,7 @@
} // extern "C"
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_3
} // 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 2a48db6..a6ed3bd 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/CryptoFactory.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/CryptoFactory.cpp
@@ -27,9 +27,12 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_3 {
namespace clearkey {
+using ::android::hardware::drm::V1_0::Status;
+using ::android::hardware::drm::V1_2::clearkey::CryptoPlugin;
+
Return<bool> CryptoFactory::isCryptoSchemeSupported(
const hidl_array<uint8_t, 16> &uuid)
{
@@ -60,7 +63,7 @@
}
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_3
} // 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 9fb5bbe..ccc73b6 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DrmFactory.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmFactory.cpp
@@ -15,6 +15,7 @@
*/
//#define LOG_NDEBUG 0
+#include <vector>
#define LOG_TAG "hidl_ClearKeyDrmFactory"
#include <utils/Log.h>
@@ -30,11 +31,13 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_3 {
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::Void;
Return<bool> DrmFactory::isCryptoSchemeSupported(
@@ -78,8 +81,18 @@
return Void();
}
+Return<void> DrmFactory::getSupportedCryptoSchemes(
+ getSupportedCryptoSchemes_cb _hidl_cb) {
+ std::vector<hidl_array<uint8_t, 16>> schemes;
+ for (const auto &scheme : clearkeydrm::getSupportedCryptoSchemes()) {
+ schemes.push_back(scheme);
+ }
+ _hidl_cb(schemes);
+ return Void();
+}
+
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_3
} // 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 aab475e..546eb3e 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
@@ -111,6 +111,8 @@
// The content in this secure stop is implementation dependent, the clearkey
// secureStop does not serve as a reference implementation.
void DrmPlugin::installSecureStop(const hidl_vec<uint8_t>& sessionId) {
+ Mutex::Autolock lock(mSecureStopLock);
+
ClearkeySecureStop clearkeySecureStop;
clearkeySecureStop.id = uint32ToVector(++mNextSecureStopId);
clearkeySecureStop.data.assign(sessionId.begin(), sessionId.end());
@@ -744,6 +746,7 @@
}
Return<void> DrmPlugin::getSecureStops(getSecureStops_cb _hidl_cb) {
+ mSecureStopLock.lock();
std::vector<SecureStop> stops;
for (auto itr = mSecureStops.begin(); itr != mSecureStops.end(); ++itr) {
ClearkeySecureStop clearkeyStop = itr->second;
@@ -755,26 +758,32 @@
stop.opaqueData = toHidlVec(stopVec);
stops.push_back(stop);
}
+ mSecureStopLock.unlock();
+
_hidl_cb(Status::OK, stops);
return Void();
}
Return<void> DrmPlugin::getSecureStop(const hidl_vec<uint8_t>& secureStopId,
getSecureStop_cb _hidl_cb) {
- SecureStop stop;
+ std::vector<uint8_t> stopVec;
+
+ mSecureStopLock.lock();
auto itr = mSecureStops.find(toVector(secureStopId));
if (itr != mSecureStops.end()) {
ClearkeySecureStop clearkeyStop = itr->second;
- std::vector<uint8_t> stopVec;
stopVec.insert(stopVec.end(), clearkeyStop.id.begin(), clearkeyStop.id.end());
stopVec.insert(stopVec.end(), clearkeyStop.data.begin(), clearkeyStop.data.end());
+ }
+ mSecureStopLock.unlock();
+ SecureStop stop;
+ if (!stopVec.empty()) {
stop.opaqueData = toHidlVec(stopVec);
_hidl_cb(Status::OK, stop);
} else {
_hidl_cb(Status::BAD_VALUE, stop);
}
-
return Void();
}
@@ -787,10 +796,12 @@
}
Return<void> DrmPlugin::getSecureStopIds(getSecureStopIds_cb _hidl_cb) {
+ mSecureStopLock.lock();
std::vector<SecureStopId> ids;
for (auto itr = mSecureStops.begin(); itr != mSecureStops.end(); ++itr) {
ids.push_back(itr->first);
}
+ mSecureStopLock.unlock();
_hidl_cb(Status::OK, toHidlVec(ids));
return Void();
@@ -856,6 +867,8 @@
}
Return<Status> DrmPlugin::removeSecureStop(const hidl_vec<uint8_t>& secureStopId) {
+ Mutex::Autolock lock(mSecureStopLock);
+
if (1 != mSecureStops.erase(toVector(secureStopId))) {
return Status::BAD_VALUE;
}
@@ -863,6 +876,8 @@
}
Return<Status> DrmPlugin::removeAllSecureStops() {
+ Mutex::Autolock lock(mSecureStopLock);
+
mSecureStops.clear();
mNextSecureStopId = kSecureStopIdStart;
return Status::OK;
diff --git a/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp b/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp
index b988ce0..8513434 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp
@@ -85,10 +85,21 @@
Status InitDataParser::parsePssh(const std::vector<uint8_t>& initData,
std::vector<const uint8_t*>* keyIds) {
+ // Description of PSSH format:
+ // https://w3c.github.io/encrypted-media/format-registry/initdata/cenc.html
size_t readPosition = 0;
- // Validate size field
uint32_t expectedSize = initData.size();
+ const char psshIdentifier[4] = {'p', 's', 's', 'h'};
+ const uint8_t psshVersion1[4] = {1, 0, 0, 0};
+ uint32_t keyIdCount = 0;
+ size_t headerSize = sizeof(expectedSize) + sizeof(psshIdentifier) +
+ sizeof(psshVersion1) + kSystemIdSize + sizeof(keyIdCount);
+ if (initData.size() < headerSize) {
+ return Status::ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ // Validate size field
expectedSize = htonl(expectedSize);
if (memcmp(&initData[readPosition], &expectedSize,
sizeof(expectedSize)) != 0) {
@@ -97,7 +108,6 @@
readPosition += sizeof(expectedSize);
// Validate PSSH box identifier
- const char psshIdentifier[4] = {'p', 's', 's', 'h'};
if (memcmp(&initData[readPosition], psshIdentifier,
sizeof(psshIdentifier)) != 0) {
return Status::ERROR_DRM_CANNOT_HANDLE;
@@ -105,7 +115,6 @@
readPosition += sizeof(psshIdentifier);
// Validate EME version number
- const uint8_t psshVersion1[4] = {1, 0, 0, 0};
if (memcmp(&initData[readPosition], psshVersion1,
sizeof(psshVersion1)) != 0) {
return Status::ERROR_DRM_CANNOT_HANDLE;
@@ -119,12 +128,14 @@
readPosition += kSystemIdSize;
// Read key ID count
- uint32_t keyIdCount;
memcpy(&keyIdCount, &initData[readPosition], sizeof(keyIdCount));
keyIdCount = ntohl(keyIdCount);
readPosition += sizeof(keyIdCount);
- if (readPosition + ((uint64_t)keyIdCount * kKeyIdSize) !=
- initData.size() - sizeof(uint32_t)) {
+
+ uint64_t psshSize = 0;
+ if (__builtin_mul_overflow(keyIdCount, kKeyIdSize, &psshSize) ||
+ __builtin_add_overflow(readPosition, psshSize, &psshSize) ||
+ psshSize != initData.size() - sizeof(uint32_t) /* DataSize(0) */) {
return Status::ERROR_DRM_CANNOT_HANDLE;
}
diff --git a/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service.clearkey.rc b/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service.clearkey.rc
index 5ba669d..c1abe7f 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service.clearkey.rc
+++ b/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service.clearkey.rc
@@ -5,6 +5,7 @@
interface android.hardware.drm@1.1::IDrmFactory clearkey
interface android.hardware.drm@1.2::ICryptoFactory clearkey
interface android.hardware.drm@1.2::IDrmFactory clearkey
+ disabled
class hal
user media
group media mediadrm
diff --git a/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.3-service-lazy.clearkey.rc b/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.3-service-lazy.clearkey.rc
new file mode 100644
index 0000000..1e0d431
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.3-service-lazy.clearkey.rc
@@ -0,0 +1,16 @@
+service vendor.drm-clearkey-hal-1-3 /vendor/bin/hw/android.hardware.drm@1.3-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
+ 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.3-service.clearkey.rc b/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.3-service.clearkey.rc
new file mode 100644
index 0000000..8130511
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.3-service.clearkey.rc
@@ -0,0 +1,14 @@
+service vendor.drm-clearkey-hal-1-3 /vendor/bin/hw/android.hardware.drm@1.3-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
+ class hal
+ user media
+ group media mediadrm
+ ioprio rt 4
+ writepid /dev/cpuset/foreground/tasks
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/CreatePluginFactories.h b/drm/mediadrm/plugins/clearkey/hidl/include/CreatePluginFactories.h
index 6368f3d..c1c188e 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.2/ICryptoFactory.h>
-#include <android/hardware/drm/1.2/IDrmFactory.h>
+#include <android/hardware/drm/1.3/ICryptoFactory.h>
+#include <android/hardware/drm/1.3/IDrmFactory.h>
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_3 {
namespace clearkey {
-using ::android::hardware::drm::V1_2::ICryptoFactory;
-using ::android::hardware::drm::V1_2::IDrmFactory;
+using ::android::hardware::drm::V1_3::ICryptoFactory;
+using ::android::hardware::drm::V1_3::IDrmFactory;
extern "C" {
IDrmFactory* createDrmFactory();
@@ -35,7 +35,7 @@
}
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_3
} // 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 203bb2d..cb4811b 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.2/ICryptoFactory.h>
+#include <android/hardware/drm/1.3/ICryptoFactory.h>
#include "ClearKeyTypes.h"
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_3 {
namespace clearkey {
-using ::android::hardware::drm::V1_2::ICryptoFactory;
+using ::android::hardware::drm::V1_3::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_2
+} // namespace V1_3
} // 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 4ca856d..403a8ec 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/DrmFactory.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/DrmFactory.h
@@ -18,16 +18,17 @@
#define CLEARKEY_DRM_FACTORY_H_
#include <android/hardware/drm/1.2/IDrmPlugin.h>
-#include <android/hardware/drm/1.2/IDrmFactory.h>
+#include <android/hardware/drm/1.3/IDrmFactory.h>
#include "ClearKeyTypes.h"
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_3 {
namespace clearkey {
+using ::android::hardware::drm::V1_1::SecurityLevel;
using ::android::hardware::hidl_array;
using ::android::hardware::hidl_string;
using ::android::hardware::Return;
@@ -51,12 +52,15 @@
const hidl_string& appPackageName,
createPlugin_cb _hidl_cb) override;
+ Return<void> getSupportedCryptoSchemes(
+ getSupportedCryptoSchemes_cb _hidl_cb) override;
+
private:
CLEARKEY_DISALLOW_COPY_AND_ASSIGN(DrmFactory);
};
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_3
} // 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 f294d4d..3de7589 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
@@ -416,6 +416,7 @@
}
DeviceFiles mFileHandle;
+ Mutex mSecureStopLock;
CLEARKEY_DISALLOW_COPY_AND_ASSIGN_AND_NEW(DrmPlugin);
};
diff --git a/drm/mediadrm/plugins/clearkey/hidl/manifest_android.hardware.drm@1.2-service.clearkey.xml b/drm/mediadrm/plugins/clearkey/hidl/manifest_android.hardware.drm@1.2-service.clearkey.xml
new file mode 100644
index 0000000..16cba11
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/manifest_android.hardware.drm@1.2-service.clearkey.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.drm</name>
+ <transport>hwbinder</transport>
+ <fqname>@1.2::ICryptoFactory/clearkey</fqname>
+ <fqname>@1.2::IDrmFactory/clearkey</fqname>
+ </hal>
+</manifest>
diff --git a/drm/mediadrm/plugins/clearkey/hidl/manifest_android.hardware.drm@1.3-service.clearkey.xml b/drm/mediadrm/plugins/clearkey/hidl/manifest_android.hardware.drm@1.3-service.clearkey.xml
new file mode 100644
index 0000000..229ee96
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/manifest_android.hardware.drm@1.3-service.clearkey.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.drm</name>
+ <transport>hwbinder</transport>
+ <fqname>@1.3::ICryptoFactory/clearkey</fqname>
+ <fqname>@1.3::IDrmFactory/clearkey</fqname>
+ </hal>
+</manifest>
diff --git a/drm/mediadrm/plugins/clearkey/hidl/service.cpp b/drm/mediadrm/plugins/clearkey/hidl/service.cpp
index b39ea01..b62baae 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_2::ICryptoFactory;
-using android::hardware::drm::V1_2::IDrmFactory;
-using android::hardware::drm::V1_2::clearkey::CryptoFactory;
-using android::hardware::drm::V1_2::clearkey::DrmFactory;
+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;
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 99fd883..b3e0179 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_2::ICryptoFactory;
-using android::hardware::drm::V1_2::IDrmFactory;
-using android::hardware::drm::V1_2::clearkey::CryptoFactory;
-using android::hardware::drm::V1_2::clearkey::DrmFactory;
+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::LazyServiceRegistrar;
int main(int /* argc */, char** /* argv */) {
@@ -38,7 +38,7 @@
configureRpcThreadpool(8, true /* callerWillJoin */);
// Setup hwbinder service
- LazyServiceRegistrar serviceRegistrar;
+ auto serviceRegistrar = LazyServiceRegistrar::getInstance();
// Setup hwbinder service
CHECK_EQ(serviceRegistrar.registerService(drmFactory, "clearkey"), android::NO_ERROR)
diff --git a/include/camera b/include/camera
deleted file mode 120000
index 00848e3..0000000
--- a/include/camera
+++ /dev/null
@@ -1 +0,0 @@
-../camera/include/camera/
\ No newline at end of file
diff --git a/include/cpustats b/include/cpustats
deleted file mode 120000
index 4a02d41..0000000
--- a/include/cpustats
+++ /dev/null
@@ -1 +0,0 @@
-../media/libcpustats/include/cpustats/
\ No newline at end of file
diff --git a/include/drm/drm_framework_common.h b/include/drm/drm_framework_common.h
index d75f71c..d5f3ba2 100644
--- a/include/drm/drm_framework_common.h
+++ b/include/drm/drm_framework_common.h
@@ -317,14 +317,6 @@
~DecryptHandle() {
delete decryptInfo; decryptInfo = NULL;
}
-
- bool operator<(const DecryptHandle& handle) const {
- return (decryptId < handle.decryptId);
- }
-
- bool operator==(const DecryptHandle& handle) const {
- return (decryptId == handle.decryptId);
- }
};
};
diff --git a/include/media/AVSyncSettings.h b/include/media/AVSyncSettings.h
deleted file mode 120000
index bbe211f..0000000
--- a/include/media/AVSyncSettings.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/AVSyncSettings.h
\ No newline at end of file
diff --git a/include/media/AudioAttributes.h b/include/media/AudioAttributes.h
deleted file mode 120000
index 27ba471..0000000
--- a/include/media/AudioAttributes.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioAttributes.h
\ No newline at end of file
diff --git a/include/media/AudioBufferProvider.h b/include/media/AudioBufferProvider.h
deleted file mode 120000
index c4d6e79..0000000
--- a/include/media/AudioBufferProvider.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioBufferProvider.h
\ No newline at end of file
diff --git a/include/media/AudioClient.h b/include/media/AudioClient.h
deleted file mode 120000
index a0530e4..0000000
--- a/include/media/AudioClient.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioClient.h
\ No newline at end of file
diff --git a/include/media/AudioCommonTypes.h b/include/media/AudioCommonTypes.h
deleted file mode 120000
index ae7c99a..0000000
--- a/include/media/AudioCommonTypes.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioCommonTypes.h
\ No newline at end of file
diff --git a/include/media/AudioEffect.h b/include/media/AudioEffect.h
deleted file mode 120000
index bf52955..0000000
--- a/include/media/AudioEffect.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioEffect.h
\ No newline at end of file
diff --git a/include/media/AudioIoDescriptor.h b/include/media/AudioIoDescriptor.h
deleted file mode 120000
index 68f54c9..0000000
--- a/include/media/AudioIoDescriptor.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioIoDescriptor.h
\ No newline at end of file
diff --git a/include/media/AudioMixer.h b/include/media/AudioMixer.h
deleted file mode 120000
index de839c6..0000000
--- a/include/media/AudioMixer.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioMixer.h
\ No newline at end of file
diff --git a/include/media/AudioParameter.h b/include/media/AudioParameter.h
deleted file mode 120000
index a5889e5..0000000
--- a/include/media/AudioParameter.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioParameter.h
\ No newline at end of file
diff --git a/include/media/AudioPolicy.h b/include/media/AudioPolicy.h
deleted file mode 120000
index dd4cd53..0000000
--- a/include/media/AudioPolicy.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioPolicy.h
\ No newline at end of file
diff --git a/include/media/AudioProductStrategy.h b/include/media/AudioProductStrategy.h
deleted file mode 120000
index 6bfaf11..0000000
--- a/include/media/AudioProductStrategy.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioProductStrategy.h
\ No newline at end of file
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
deleted file mode 120000
index 7939dd3..0000000
--- a/include/media/AudioRecord.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioRecord.h
\ No newline at end of file
diff --git a/include/media/AudioResampler.h b/include/media/AudioResampler.h
deleted file mode 120000
index 771f1b8..0000000
--- a/include/media/AudioResampler.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioprocessing/include/media/AudioResampler.h
\ No newline at end of file
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
deleted file mode 120000
index 9fad2b7..0000000
--- a/include/media/AudioSystem.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioSystem.h
\ No newline at end of file
diff --git a/include/media/AudioTimestamp.h b/include/media/AudioTimestamp.h
deleted file mode 120000
index b6b9278..0000000
--- a/include/media/AudioTimestamp.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioTimestamp.h
\ No newline at end of file
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
deleted file mode 120000
index 303bfcd..0000000
--- a/include/media/AudioTrack.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioTrack.h
\ No newline at end of file
diff --git a/include/media/AudioVolumeGroup.h b/include/media/AudioVolumeGroup.h
deleted file mode 120000
index d6f1c99..0000000
--- a/include/media/AudioVolumeGroup.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioVolumeGroup.h
\ No newline at end of file
diff --git a/include/media/BufferProviders.h b/include/media/BufferProviders.h
deleted file mode 120000
index 779bb15..0000000
--- a/include/media/BufferProviders.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/BufferProviders.h
\ No newline at end of file
diff --git a/include/media/BufferingSettings.h b/include/media/BufferingSettings.h
deleted file mode 120000
index 409203f..0000000
--- a/include/media/BufferingSettings.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/BufferingSettings.h
\ No newline at end of file
diff --git a/include/media/CharacterEncodingDetector.h b/include/media/CharacterEncodingDetector.h
deleted file mode 120000
index 2b28387..0000000
--- a/include/media/CharacterEncodingDetector.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/CharacterEncodingDetector.h
\ No newline at end of file
diff --git a/include/media/CounterMetric.h b/include/media/CounterMetric.h
deleted file mode 120000
index baba043..0000000
--- a/include/media/CounterMetric.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/CounterMetric.h
\ No newline at end of file
diff --git a/include/media/DataSource.h b/include/media/DataSource.h
deleted file mode 120000
index 198b27e..0000000
--- a/include/media/DataSource.h
+++ /dev/null
@@ -1 +0,0 @@
-stagefright/DataSource.h
\ No newline at end of file
diff --git a/include/media/DataSource.h b/include/media/DataSource.h
new file mode 100644
index 0000000..2abd5f5
--- /dev/null
+++ b/include/media/DataSource.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DATA_SOURCE_H_
+
+#define DATA_SOURCE_H_
+
+#include <sys/types.h>
+
+#include <android/IDataSource.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/DataSourceBase.h>
+#include <media/MediaExtractorPluginApi.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+
+namespace android {
+
+class String8;
+
+class DataSource : public DataSourceBase, public virtual RefBase {
+public:
+ DataSource() : mWrapper(NULL) {}
+
+ // returns a pointer to IDataSource if it is wrapped.
+ virtual sp<IDataSource> getIDataSource() const {
+ return nullptr;
+ }
+
+ virtual String8 toString() {
+ return String8("<unspecified>");
+ }
+
+ virtual status_t reconnectAtOffset(off64_t /*offset*/) {
+ return ERROR_UNSUPPORTED;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ virtual String8 getUri() {
+ return String8();
+ }
+
+ virtual bool getUri(char *uriString, size_t bufferSize) final {
+ int ret = snprintf(uriString, bufferSize, "%s", getUri().c_str());
+ return ret >= 0 && static_cast<size_t>(ret) < bufferSize;
+ }
+
+ virtual String8 getMIMEType() const {
+ return String8("application/octet-stream");
+ }
+
+ CDataSource *wrap() {
+ if (mWrapper) {
+ return mWrapper;
+ }
+ mWrapper = new CDataSource();
+ mWrapper->handle = this;
+
+ mWrapper->readAt = [](void *handle, off64_t offset, void *data, size_t size) -> ssize_t {
+ return ((DataSource*)handle)->readAt(offset, data, size);
+ };
+ mWrapper->getSize = [](void *handle, off64_t *size) -> status_t {
+ return ((DataSource*)handle)->getSize(size);
+ };
+ mWrapper->flags = [](void *handle) -> uint32_t {
+ return ((DataSource*)handle)->flags();
+ };
+ mWrapper->getUri = [](void *handle, char *uriString, size_t bufferSize) -> bool {
+ return ((DataSource*)handle)->getUri(uriString, bufferSize);
+ };
+ return mWrapper;
+ }
+
+protected:
+ virtual ~DataSource() {
+ delete mWrapper;
+ }
+
+private:
+ CDataSource *mWrapper;
+ DataSource(const DataSource &);
+ DataSource &operator=(const DataSource &);
+};
+
+} // namespace android
+
+#endif // DATA_SOURCE_H_
diff --git a/include/media/DataSourceBase.h b/include/media/DataSourceBase.h
deleted file mode 120000
index d2ab2f1..0000000
--- a/include/media/DataSourceBase.h
+++ /dev/null
@@ -1 +0,0 @@
-stagefright/DataSourceBase.h
\ No newline at end of file
diff --git a/include/media/EventLog.h b/include/media/EventLog.h
deleted file mode 120000
index 9b2c4bf..0000000
--- a/include/media/EventLog.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/utils/include/mediautils/EventLog.h
\ No newline at end of file
diff --git a/include/media/EventMetric.h b/include/media/EventMetric.h
deleted file mode 120000
index 5707d9a..0000000
--- a/include/media/EventMetric.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/EventMetric.h
\ No newline at end of file
diff --git a/include/media/ExtendedAudioBufferProvider.h b/include/media/ExtendedAudioBufferProvider.h
deleted file mode 120000
index d653cc3..0000000
--- a/include/media/ExtendedAudioBufferProvider.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/ExtendedAudioBufferProvider.h
\ No newline at end of file
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
deleted file mode 120000
index ef6f5be..0000000
--- a/include/media/IAudioFlinger.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/IAudioFlinger.h
\ No newline at end of file
diff --git a/include/media/IAudioFlingerClient.h b/include/media/IAudioFlingerClient.h
deleted file mode 120000
index dc481e8..0000000
--- a/include/media/IAudioFlingerClient.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/IAudioFlingerClient.h
\ No newline at end of file
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
deleted file mode 120000
index 08101fc..0000000
--- a/include/media/IAudioPolicyService.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/IAudioPolicyService.h
\ No newline at end of file
diff --git a/include/media/IAudioPolicyServiceClient.h b/include/media/IAudioPolicyServiceClient.h
deleted file mode 120000
index 0d4b3e7..0000000
--- a/include/media/IAudioPolicyServiceClient.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/IAudioPolicyServiceClient.h
\ No newline at end of file
diff --git a/include/media/IAudioTrack.h b/include/media/IAudioTrack.h
deleted file mode 120000
index 7bab1fd..0000000
--- a/include/media/IAudioTrack.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/IAudioTrack.h
\ No newline at end of file
diff --git a/include/media/IDataSource.h b/include/media/IDataSource.h
deleted file mode 120000
index 41cdd8b..0000000
--- a/include/media/IDataSource.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IDataSource.h
\ No newline at end of file
diff --git a/include/media/IEffect.h b/include/media/IEffect.h
deleted file mode 120000
index 2fb8bfb..0000000
--- a/include/media/IEffect.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/IEffect.h
\ No newline at end of file
diff --git a/include/media/IEffectClient.h b/include/media/IEffectClient.h
deleted file mode 120000
index b4e39cf..0000000
--- a/include/media/IEffectClient.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/IEffectClient.h
\ No newline at end of file
diff --git a/include/media/IMediaAnalyticsService.h b/include/media/IMediaAnalyticsService.h
deleted file mode 120000
index a596d60..0000000
--- a/include/media/IMediaAnalyticsService.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmediametrics/include/IMediaAnalyticsService.h
\ No newline at end of file
diff --git a/include/media/IMediaCodecList.h b/include/media/IMediaCodecList.h
deleted file mode 120000
index 2186312..0000000
--- a/include/media/IMediaCodecList.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaCodecList.h
\ No newline at end of file
diff --git a/include/media/IMediaDeathNotifier.h b/include/media/IMediaDeathNotifier.h
deleted file mode 120000
index ce3b8f0..0000000
--- a/include/media/IMediaDeathNotifier.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaDeathNotifier.h
\ No newline at end of file
diff --git a/include/media/IMediaExtractor.h b/include/media/IMediaExtractor.h
deleted file mode 120000
index 8708c8c..0000000
--- a/include/media/IMediaExtractor.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaExtractor.h
\ No newline at end of file
diff --git a/include/media/IMediaExtractorService.h b/include/media/IMediaExtractorService.h
deleted file mode 120000
index 3ee9f1e..0000000
--- a/include/media/IMediaExtractorService.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaExtractorService.h
\ No newline at end of file
diff --git a/include/media/IMediaHTTPConnection.h b/include/media/IMediaHTTPConnection.h
deleted file mode 120000
index 0970c15..0000000
--- a/include/media/IMediaHTTPConnection.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaHTTPConnection.h
\ No newline at end of file
diff --git a/include/media/IMediaHTTPService.h b/include/media/IMediaHTTPService.h
deleted file mode 120000
index b90c34f..0000000
--- a/include/media/IMediaHTTPService.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaHTTPService.h
\ No newline at end of file
diff --git a/include/media/IMediaLogService.h b/include/media/IMediaLogService.h
deleted file mode 120000
index 245a29d..0000000
--- a/include/media/IMediaLogService.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaLogService.h
\ No newline at end of file
diff --git a/include/media/IMediaMetadataRetriever.h b/include/media/IMediaMetadataRetriever.h
deleted file mode 120000
index 959df1a..0000000
--- a/include/media/IMediaMetadataRetriever.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaMetadataRetriever.h
\ No newline at end of file
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
deleted file mode 120000
index 9414d37..0000000
--- a/include/media/IMediaPlayer.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaPlayer.h
\ No newline at end of file
diff --git a/include/media/IMediaPlayerClient.h b/include/media/IMediaPlayerClient.h
deleted file mode 120000
index b6547ce..0000000
--- a/include/media/IMediaPlayerClient.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaPlayerClient.h
\ No newline at end of file
diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h
deleted file mode 120000
index 89c96cd..0000000
--- a/include/media/IMediaPlayerService.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaPlayerService.h
\ No newline at end of file
diff --git a/include/media/IMediaRecorder.h b/include/media/IMediaRecorder.h
deleted file mode 120000
index 57d192c..0000000
--- a/include/media/IMediaRecorder.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaRecorder.h
\ No newline at end of file
diff --git a/include/media/IMediaRecorderClient.h b/include/media/IMediaRecorderClient.h
deleted file mode 120000
index 89f4359..0000000
--- a/include/media/IMediaRecorderClient.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaRecorderClient.h
\ No newline at end of file
diff --git a/include/media/IMediaSource.h b/include/media/IMediaSource.h
deleted file mode 120000
index 1330ad3..0000000
--- a/include/media/IMediaSource.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaSource.h
\ No newline at end of file
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
deleted file mode 120000
index 6d5b375..0000000
--- a/include/media/IOMX.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IOMX.h
\ No newline at end of file
diff --git a/include/media/IRemoteDisplay.h b/include/media/IRemoteDisplay.h
deleted file mode 120000
index 4b0cf10..0000000
--- a/include/media/IRemoteDisplay.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IRemoteDisplay.h
\ No newline at end of file
diff --git a/include/media/IRemoteDisplayClient.h b/include/media/IRemoteDisplayClient.h
deleted file mode 120000
index f29a2ee..0000000
--- a/include/media/IRemoteDisplayClient.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IRemoteDisplayClient.h
\ No newline at end of file
diff --git a/include/media/IResourceManagerClient.h b/include/media/IResourceManagerClient.h
deleted file mode 120000
index 100af9b..0000000
--- a/include/media/IResourceManagerClient.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IResourceManagerClient.h
\ No newline at end of file
diff --git a/include/media/IResourceManagerService.h b/include/media/IResourceManagerService.h
deleted file mode 120000
index 9b389c6..0000000
--- a/include/media/IResourceManagerService.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IResourceManagerService.h
\ No newline at end of file
diff --git a/include/media/IStreamSource.h b/include/media/IStreamSource.h
deleted file mode 120000
index 4943af9..0000000
--- a/include/media/IStreamSource.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IStreamSource.h
\ No newline at end of file
diff --git a/include/media/JetPlayer.h b/include/media/JetPlayer.h
deleted file mode 120000
index 5483fda..0000000
--- a/include/media/JetPlayer.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/JetPlayer.h
\ No newline at end of file
diff --git a/include/media/LinearMap.h b/include/media/LinearMap.h
deleted file mode 120000
index 30d4ca8..0000000
--- a/include/media/LinearMap.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/LinearMap.h
\ No newline at end of file
diff --git a/include/media/MediaAnalyticsItem.h b/include/media/MediaAnalyticsItem.h
deleted file mode 120000
index e8124e0..0000000
--- a/include/media/MediaAnalyticsItem.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmediametrics/include/MediaAnalyticsItem.h
\ No newline at end of file
diff --git a/include/media/MediaCodecBuffer.h b/include/media/MediaCodecBuffer.h
deleted file mode 120000
index 8c9aa76..0000000
--- a/include/media/MediaCodecBuffer.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/MediaCodecBuffer.h
\ No newline at end of file
diff --git a/include/media/MediaCodecInfo.h b/include/media/MediaCodecInfo.h
deleted file mode 120000
index ff44ce4..0000000
--- a/include/media/MediaCodecInfo.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/MediaCodecInfo.h
\ No newline at end of file
diff --git a/include/media/MediaMetadataRetrieverInterface.h b/include/media/MediaMetadataRetrieverInterface.h
deleted file mode 120000
index 1c53511..0000000
--- a/include/media/MediaMetadataRetrieverInterface.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/MediaMetadataRetrieverInterface.h
\ No newline at end of file
diff --git a/include/media/MediaMetrics.h b/include/media/MediaMetrics.h
deleted file mode 120000
index 5f757e4..0000000
--- a/include/media/MediaMetrics.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmediametrics/include/MediaMetrics.h
\ No newline at end of file
diff --git a/include/media/MediaProfiles.h b/include/media/MediaProfiles.h
deleted file mode 120000
index 651c6e6..0000000
--- a/include/media/MediaProfiles.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/MediaProfiles.h
\ No newline at end of file
diff --git a/include/media/MediaRecorderBase.h b/include/media/MediaRecorderBase.h
deleted file mode 120000
index e40f992..0000000
--- a/include/media/MediaRecorderBase.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/MediaRecorderBase.h
\ No newline at end of file
diff --git a/include/media/MediaResource.h b/include/media/MediaResource.h
deleted file mode 120000
index 91346aa..0000000
--- a/include/media/MediaResource.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/MediaResource.h
\ No newline at end of file
diff --git a/include/media/MediaResourcePolicy.h b/include/media/MediaResourcePolicy.h
deleted file mode 120000
index 5d165ee..0000000
--- a/include/media/MediaResourcePolicy.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/MediaResourcePolicy.h
\ No newline at end of file
diff --git a/include/media/MediaSource.h b/include/media/MediaSource.h
deleted file mode 120000
index 34bf65d..0000000
--- a/include/media/MediaSource.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libstagefright/include/media/stagefright/MediaSource.h
\ No newline at end of file
diff --git a/include/media/MemoryLeakTrackUtil.h b/include/media/MemoryLeakTrackUtil.h
deleted file mode 120000
index 504173e..0000000
--- a/include/media/MemoryLeakTrackUtil.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/MemoryLeakTrackUtil.h
\ No newline at end of file
diff --git a/include/media/Metadata.h b/include/media/Metadata.h
deleted file mode 120000
index e421168..0000000
--- a/include/media/Metadata.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/Metadata.h
\ No newline at end of file
diff --git a/include/media/MidiDeviceInfo.h b/include/media/MidiDeviceInfo.h
deleted file mode 120000
index 95da7cf..0000000
--- a/include/media/MidiDeviceInfo.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/MidiDeviceInfo.h
\ No newline at end of file
diff --git a/include/media/MidiIoWrapper.h b/include/media/MidiIoWrapper.h
deleted file mode 120000
index 786ec3d..0000000
--- a/include/media/MidiIoWrapper.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/MidiIoWrapper.h
\ No newline at end of file
diff --git a/include/media/Modulo.h b/include/media/Modulo.h
deleted file mode 120000
index 989c4cb..0000000
--- a/include/media/Modulo.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/Modulo.h
\ No newline at end of file
diff --git a/include/media/OMXBuffer.h b/include/media/OMXBuffer.h
deleted file mode 120000
index 00db207..0000000
--- a/include/media/OMXBuffer.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/OMXBuffer.h
\ No newline at end of file
diff --git a/include/media/OMXFenceParcelable.h b/include/media/OMXFenceParcelable.h
deleted file mode 120000
index c4c1b0a..0000000
--- a/include/media/OMXFenceParcelable.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/OMXFenceParcelable.h
\ No newline at end of file
diff --git a/include/media/PluginLoader.h b/include/media/PluginLoader.h
deleted file mode 120000
index 9101735..0000000
--- a/include/media/PluginLoader.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/PluginLoader.h
\ No newline at end of file
diff --git a/include/media/PluginMetricsReporting.h b/include/media/PluginMetricsReporting.h
deleted file mode 120000
index 7d9a7a0..0000000
--- a/include/media/PluginMetricsReporting.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/PluginMetricsReporting.h
\ No newline at end of file
diff --git a/include/media/RecordBufferConverter.h b/include/media/RecordBufferConverter.h
deleted file mode 120000
index 2d7bc0c..0000000
--- a/include/media/RecordBufferConverter.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/RecordBufferConverter.h
\ No newline at end of file
diff --git a/include/media/RingBuffer.h b/include/media/RingBuffer.h
deleted file mode 120000
index 9af28d5..0000000
--- a/include/media/RingBuffer.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/RingBuffer.h
\ No newline at end of file
diff --git a/include/media/SingleStateQueue.h b/include/media/SingleStateQueue.h
deleted file mode 120000
index 619f6ee..0000000
--- a/include/media/SingleStateQueue.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/SingleStateQueue.h
\ No newline at end of file
diff --git a/include/media/StringArray.h b/include/media/StringArray.h
deleted file mode 120000
index 616ce6c..0000000
--- a/include/media/StringArray.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/StringArray.h
\ No newline at end of file
diff --git a/include/media/TimeCheck.h b/include/media/TimeCheck.h
deleted file mode 120000
index 85e17f9..0000000
--- a/include/media/TimeCheck.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/utils/include/mediautils/TimeCheck.h
\ No newline at end of file
diff --git a/include/media/ToneGenerator.h b/include/media/ToneGenerator.h
deleted file mode 120000
index 33df0e3..0000000
--- a/include/media/ToneGenerator.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/ToneGenerator.h
\ No newline at end of file
diff --git a/include/media/TypeConverter.h b/include/media/TypeConverter.h
deleted file mode 120000
index 837af44..0000000
--- a/include/media/TypeConverter.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/TypeConverter.h
\ No newline at end of file
diff --git a/include/media/Visualizer.h b/include/media/Visualizer.h
deleted file mode 120000
index ed2ec15..0000000
--- a/include/media/Visualizer.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/Visualizer.h
\ No newline at end of file
diff --git a/include/media/audiohal b/include/media/audiohal
deleted file mode 120000
index f400582..0000000
--- a/include/media/audiohal
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudiohal/include/media/audiohal/
\ No newline at end of file
diff --git a/include/media/convert.h b/include/media/convert.h
deleted file mode 120000
index cb0d00d..0000000
--- a/include/media/convert.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/convert.h
\ No newline at end of file
diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h
deleted file mode 120000
index b401bab..0000000
--- a/include/media/mediametadataretriever.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/mediametadataretriever.h
\ No newline at end of file
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
deleted file mode 120000
index 06d537b..0000000
--- a/include/media/mediaplayer.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/mediaplayer.h
\ No newline at end of file
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
deleted file mode 120000
index a24deb3..0000000
--- a/include/media/mediarecorder.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/mediarecorder.h
\ No newline at end of file
diff --git a/include/media/mediascanner.h b/include/media/mediascanner.h
deleted file mode 120000
index 91479e0..0000000
--- a/include/media/mediascanner.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/mediascanner.h
\ No newline at end of file
diff --git a/include/media/nbaio/AudioBufferProviderSource.h b/include/media/nbaio/AudioBufferProviderSource.h
deleted file mode 120000
index 55841e7..0000000
--- a/include/media/nbaio/AudioBufferProviderSource.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../media/libnbaio/include/media/nbaio/AudioBufferProviderSource.h
\ No newline at end of file
diff --git a/include/media/nbaio/AudioStreamInSource.h b/include/media/nbaio/AudioStreamInSource.h
deleted file mode 120000
index f5bcc76..0000000
--- a/include/media/nbaio/AudioStreamInSource.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../media/libnbaio/include/media/nbaio/AudioStreamInSource.h
\ No newline at end of file
diff --git a/include/media/nbaio/AudioStreamOutSink.h b/include/media/nbaio/AudioStreamOutSink.h
deleted file mode 120000
index 43bfac5..0000000
--- a/include/media/nbaio/AudioStreamOutSink.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../media/libnbaio/include/media/nbaio/AudioStreamOutSink.h
\ No newline at end of file
diff --git a/include/media/nbaio/LibsndfileSink.h b/include/media/nbaio/LibsndfileSink.h
deleted file mode 120000
index 8a13b6c..0000000
--- a/include/media/nbaio/LibsndfileSink.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../media/libnbaio/include/media/nbaio/LibsndfileSink.h
\ No newline at end of file
diff --git a/include/media/nbaio/LibsndfileSource.h b/include/media/nbaio/LibsndfileSource.h
deleted file mode 120000
index 2750fde..0000000
--- a/include/media/nbaio/LibsndfileSource.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../media/libnbaio/include/media/nbaio/LibsndfileSource.h
\ No newline at end of file
diff --git a/include/media/nbaio/MonoPipe.h b/include/media/nbaio/MonoPipe.h
deleted file mode 120000
index 4ea43be..0000000
--- a/include/media/nbaio/MonoPipe.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../media/libnbaio/include_mono/media/nbaio/MonoPipe.h
\ No newline at end of file
diff --git a/include/media/nbaio/MonoPipeReader.h b/include/media/nbaio/MonoPipeReader.h
deleted file mode 120000
index 30f426c..0000000
--- a/include/media/nbaio/MonoPipeReader.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../media/libnbaio/include_mono/media/nbaio/MonoPipeReader.h
\ No newline at end of file
diff --git a/include/media/nbaio/NBAIO.h b/include/media/nbaio/NBAIO.h
deleted file mode 120000
index ff6a151..0000000
--- a/include/media/nbaio/NBAIO.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../media/libnbaio/include_mono/media/nbaio/NBAIO.h
\ No newline at end of file
diff --git a/include/media/nbaio/Pipe.h b/include/media/nbaio/Pipe.h
deleted file mode 120000
index a4bbbc9..0000000
--- a/include/media/nbaio/Pipe.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../media/libnbaio/include/media/nbaio/Pipe.h
\ No newline at end of file
diff --git a/include/media/nbaio/PipeReader.h b/include/media/nbaio/PipeReader.h
deleted file mode 120000
index 64b21cf..0000000
--- a/include/media/nbaio/PipeReader.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../media/libnbaio/include/media/nbaio/PipeReader.h
\ No newline at end of file
diff --git a/include/media/nbaio/SourceAudioBufferProvider.h b/include/media/nbaio/SourceAudioBufferProvider.h
deleted file mode 120000
index 74a3b06..0000000
--- a/include/media/nbaio/SourceAudioBufferProvider.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../media/libnbaio/include/media/nbaio/SourceAudioBufferProvider.h
\ No newline at end of file
diff --git a/include/media/nblog/NBLog.h b/include/media/nblog/NBLog.h
deleted file mode 120000
index 3cc366c..0000000
--- a/include/media/nblog/NBLog.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../media/libnblog/include/media/nblog/NBLog.h
\ No newline at end of file
diff --git a/include/media/nblog/PerformanceAnalysis.h b/include/media/nblog/PerformanceAnalysis.h
deleted file mode 120000
index 6ead3bc..0000000
--- a/include/media/nblog/PerformanceAnalysis.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../media/libnblog/include/media/nblog/PerformanceAnalysis.h
\ No newline at end of file
diff --git a/include/media/nblog/ReportPerformance.h b/include/media/nblog/ReportPerformance.h
deleted file mode 120000
index e9b8e80..0000000
--- a/include/media/nblog/ReportPerformance.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../media/libnblog/include/media/nblog/ReportPerformance.h
\ No newline at end of file
diff --git a/include/media/stagefright b/include/media/stagefright
deleted file mode 120000
index 5393f68..0000000
--- a/include/media/stagefright
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libstagefright/include/media/stagefright/
\ No newline at end of file
diff --git a/include/mediadrm/CryptoHal.h b/include/mediadrm/CryptoHal.h
deleted file mode 120000
index 92f3137..0000000
--- a/include/mediadrm/CryptoHal.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/CryptoHal.h
\ No newline at end of file
diff --git a/include/mediadrm/DrmHal.h b/include/mediadrm/DrmHal.h
deleted file mode 120000
index 17bb667..0000000
--- a/include/mediadrm/DrmHal.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/DrmHal.h
\ No newline at end of file
diff --git a/include/mediadrm/DrmMetrics.h b/include/mediadrm/DrmMetrics.h
deleted file mode 120000
index abc966b..0000000
--- a/include/mediadrm/DrmMetrics.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/DrmMetrics.h
\ No newline at end of file
diff --git a/include/mediadrm/DrmPluginPath.h b/include/mediadrm/DrmPluginPath.h
deleted file mode 120000
index 9e05194..0000000
--- a/include/mediadrm/DrmPluginPath.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/DrmPluginPath.h
\ No newline at end of file
diff --git a/include/mediadrm/DrmSessionClientInterface.h b/include/mediadrm/DrmSessionClientInterface.h
deleted file mode 120000
index f4e3211..0000000
--- a/include/mediadrm/DrmSessionClientInterface.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/DrmSessionClientInterface.h
\ No newline at end of file
diff --git a/include/mediadrm/DrmSessionManager.h b/include/mediadrm/DrmSessionManager.h
deleted file mode 120000
index f0a47bf..0000000
--- a/include/mediadrm/DrmSessionManager.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/DrmSessionManager.h
\ No newline at end of file
diff --git a/include/mediadrm/ICrypto.h b/include/mediadrm/ICrypto.h
deleted file mode 120000
index b250e07..0000000
--- a/include/mediadrm/ICrypto.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/ICrypto.h
\ No newline at end of file
diff --git a/include/mediadrm/IDrm.h b/include/mediadrm/IDrm.h
deleted file mode 120000
index 841bb1b..0000000
--- a/include/mediadrm/IDrm.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IDrm.h
\ No newline at end of file
diff --git a/include/mediadrm/IDrmClient.h b/include/mediadrm/IDrmClient.h
deleted file mode 120000
index 10aa5c0..0000000
--- a/include/mediadrm/IDrmClient.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IDrmClient.h
\ No newline at end of file
diff --git a/include/mediadrm/IMediaDrmService.h b/include/mediadrm/IMediaDrmService.h
deleted file mode 120000
index f3c260f..0000000
--- a/include/mediadrm/IMediaDrmService.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaDrmService.h
\ No newline at end of file
diff --git a/include/mediadrm/SharedLibrary.h b/include/mediadrm/SharedLibrary.h
deleted file mode 120000
index 9f8f5a4..0000000
--- a/include/mediadrm/SharedLibrary.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/SharedLibrary.h
\ No newline at end of file
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 5f19f74..8aec80d 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -28,7 +28,7 @@
#include <media/AudioResamplerPublic.h>
#include <media/AudioTimestamp.h>
#include <media/Modulo.h>
-#include <media/SingleStateQueue.h>
+#include <media/nbaio/SingleStateQueue.h>
namespace android {
@@ -575,7 +575,7 @@
class AudioTrackServerProxy : public ServerProxy {
public:
AudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
- size_t frameSize, bool clientInServer = false, uint32_t sampleRate = 0)
+ size_t frameSize, bool clientInServer, uint32_t sampleRate)
: ServerProxy(cblk, buffers, frameCount, frameSize, true /*isOut*/, clientInServer),
mPlaybackRateObserver(&cblk->mPlaybackRateQueue),
mUnderrunCount(0), mUnderrunning(false), mDrained(true) {
@@ -651,7 +651,7 @@
class StaticAudioTrackServerProxy : public AudioTrackServerProxy {
public:
StaticAudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
- size_t frameSize);
+ size_t frameSize, uint32_t sampleRate);
protected:
virtual ~StaticAudioTrackServerProxy() { }
diff --git a/include/private/media/VideoFrame.h b/include/private/media/VideoFrame.h
index 712f118..16e794a 100644
--- a/include/private/media/VideoFrame.h
+++ b/include/private/media/VideoFrame.h
@@ -41,7 +41,7 @@
uint32_t angle, uint32_t bpp, bool hasData, size_t iccSize):
mWidth(width), mHeight(height),
mDisplayWidth(displayWidth), mDisplayHeight(displayHeight),
- mTileWidth(tileWidth), mTileHeight(tileHeight),
+ mTileWidth(tileWidth), mTileHeight(tileHeight), mDurationUs(0),
mRotationAngle(angle), mBytesPerPixel(bpp), mRowBytes(bpp * width),
mSize(hasData ? (bpp * width * height) : 0),
mIccSize(iccSize), mReserved(0) {
@@ -78,6 +78,7 @@
uint32_t mDisplayHeight; // Display height before rotation
uint32_t mTileWidth; // Tile width (0 if image doesn't have grid)
uint32_t mTileHeight; // Tile height (0 if image doesn't have grid)
+ int64_t mDurationUs; // Frame duration in microseconds
int32_t mRotationAngle; // Rotation angle, clockwise, should be multiple of 90
uint32_t mBytesPerPixel; // Number of bytes per pixel
uint32_t mRowBytes; // Number of bytes per row before rotation
diff --git a/include/soundtrigger/ISoundTrigger.h b/include/soundtrigger/ISoundTrigger.h
deleted file mode 100644
index c357caa..0000000
--- a/include/soundtrigger/ISoundTrigger.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_ISOUNDTRIGGER_H
-#define ANDROID_HARDWARE_ISOUNDTRIGGER_H
-
-#include <utils/RefBase.h>
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-#include <binder/IMemory.h>
-#include <system/sound_trigger.h>
-
-namespace android {
-
-class ISoundTrigger : public IInterface
-{
-public:
- DECLARE_META_INTERFACE(SoundTrigger);
-
- virtual void detach() = 0;
-
- virtual status_t loadSoundModel(const sp<IMemory>& modelMemory,
- sound_model_handle_t *handle) = 0;
-
- virtual status_t unloadSoundModel(sound_model_handle_t handle) = 0;
-
- virtual status_t startRecognition(sound_model_handle_t handle,
- const sp<IMemory>& dataMemory) = 0;
- virtual status_t stopRecognition(sound_model_handle_t handle) = 0;
- virtual status_t getModelState(sound_model_handle_t handle) = 0;
-
-};
-
-// ----------------------------------------------------------------------------
-
-class BnSoundTrigger: public BnInterface<ISoundTrigger>
-{
-public:
- virtual status_t onTransact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-};
-
-}; // namespace android
-
-#endif //ANDROID_HARDWARE_ISOUNDTRIGGER_H
diff --git a/include/soundtrigger/ISoundTriggerClient.h b/include/soundtrigger/ISoundTriggerClient.h
deleted file mode 100644
index 480429a..0000000
--- a/include/soundtrigger/ISoundTriggerClient.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_ISOUNDTRIGGER_CLIENT_H
-#define ANDROID_HARDWARE_ISOUNDTRIGGER_CLIENT_H
-
-#include <utils/RefBase.h>
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-
-namespace android {
-
-class ISoundTriggerClient : public IInterface
-{
-public:
-
- DECLARE_META_INTERFACE(SoundTriggerClient);
-
- virtual void onRecognitionEvent(const sp<IMemory>& eventMemory) = 0;
-
- virtual void onSoundModelEvent(const sp<IMemory>& eventMemory) = 0;
-
- virtual void onServiceStateChange(const sp<IMemory>& eventMemory) = 0;
-
-};
-
-// ----------------------------------------------------------------------------
-
-class BnSoundTriggerClient : public BnInterface<ISoundTriggerClient>
-{
-public:
- virtual status_t onTransact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-};
-
-}; // namespace android
-
-#endif //ANDROID_HARDWARE_ISOUNDTRIGGER_CLIENT_H
diff --git a/include/soundtrigger/ISoundTriggerHwService.h b/include/soundtrigger/ISoundTriggerHwService.h
deleted file mode 100644
index 1faeb0f..0000000
--- a/include/soundtrigger/ISoundTriggerHwService.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_ISOUNDTRIGGER_SERVICE_H
-#define ANDROID_HARDWARE_ISOUNDTRIGGER_SERVICE_H
-
-#include <utils/RefBase.h>
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-#include <system/sound_trigger.h>
-
-namespace android {
-
-class ISoundTrigger;
-class ISoundTriggerClient;
-
-class ISoundTriggerHwService : public IInterface
-{
-public:
-
- DECLARE_META_INTERFACE(SoundTriggerHwService);
-
- virtual status_t listModules(const String16& opPackageName,
- struct sound_trigger_module_descriptor *modules,
- uint32_t *numModules) = 0;
-
- virtual status_t attach(const String16& opPackageName,
- const sound_trigger_module_handle_t handle,
- const sp<ISoundTriggerClient>& client,
- sp<ISoundTrigger>& module) = 0;
-
- virtual status_t setCaptureState(bool active) = 0;
-};
-
-// ----------------------------------------------------------------------------
-
-class BnSoundTriggerHwService: public BnInterface<ISoundTriggerHwService>
-{
-public:
- virtual status_t onTransact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-};
-
-}; // namespace android
-
-#endif //ANDROID_HARDWARE_ISOUNDTRIGGER_SERVICE_H
diff --git a/include/soundtrigger/OWNERS b/include/soundtrigger/OWNERS
deleted file mode 100644
index e83f6b9..0000000
--- a/include/soundtrigger/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-elaurent@google.com
-thorntonc@google.com
diff --git a/include/soundtrigger/SoundTrigger.h b/include/soundtrigger/SoundTrigger.h
deleted file mode 100644
index ccc61dc..0000000
--- a/include/soundtrigger/SoundTrigger.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_SOUNDTRIGGER_H
-#define ANDROID_HARDWARE_SOUNDTRIGGER_H
-
-#include <binder/IBinder.h>
-#include <utils/threads.h>
-#include <soundtrigger/SoundTriggerCallback.h>
-#include <soundtrigger/ISoundTrigger.h>
-#include <soundtrigger/ISoundTriggerHwService.h>
-#include <soundtrigger/ISoundTriggerClient.h>
-#include <system/sound_trigger.h>
-
-namespace android {
-
-class MemoryDealer;
-
-class SoundTrigger : public BnSoundTriggerClient,
- public IBinder::DeathRecipient
-{
-public:
-
- virtual ~SoundTrigger();
-
- static status_t listModules(const String16& opPackageName,
- struct sound_trigger_module_descriptor *modules,
- uint32_t *numModules);
- static sp<SoundTrigger> attach(const String16& opPackageName,
- const sound_trigger_module_handle_t module,
- const sp<SoundTriggerCallback>& callback);
-
- static status_t setCaptureState(bool active);
-
- void detach();
-
- status_t loadSoundModel(const sp<IMemory>& modelMemory,
- sound_model_handle_t *handle);
-
- status_t unloadSoundModel(sound_model_handle_t handle);
-
- status_t startRecognition(sound_model_handle_t handle, const sp<IMemory>& dataMemory);
- status_t stopRecognition(sound_model_handle_t handle);
- status_t getModelState(sound_model_handle_t handle);
-
- // BpSoundTriggerClient
- virtual void onRecognitionEvent(const sp<IMemory>& eventMemory);
- virtual void onSoundModelEvent(const sp<IMemory>& eventMemory);
- virtual void onServiceStateChange(const sp<IMemory>& eventMemory);
-
- //IBinder::DeathRecipient
- virtual void binderDied(const wp<IBinder>& who);
-
- static status_t stringToGuid(const char *str, sound_trigger_uuid_t *guid);
- static status_t guidToString(const sound_trigger_uuid_t *guid,
- char *str, size_t maxLen);
-
-private:
- SoundTrigger(sound_trigger_module_handle_t module,
- const sp<SoundTriggerCallback>&);
- static const sp<ISoundTriggerHwService> getSoundTriggerHwService();
-
- Mutex mLock;
- sp<ISoundTrigger> mISoundTrigger;
- sp<SoundTriggerCallback> mCallback;
-};
-
-}; // namespace android
-
-#endif //ANDROID_HARDWARE_SOUNDTRIGGER_H
diff --git a/include/soundtrigger/SoundTriggerCallback.h b/include/soundtrigger/SoundTriggerCallback.h
deleted file mode 100644
index b5277f2..0000000
--- a/include/soundtrigger/SoundTriggerCallback.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_SOUNDTRIGGER_CALLBACK_H
-#define ANDROID_HARDWARE_SOUNDTRIGGER_CALLBACK_H
-
-#include <utils/RefBase.h>
-#include <system/sound_trigger.h>
-
-namespace android {
-
-class SoundTriggerCallback : public RefBase
-{
-public:
-
- SoundTriggerCallback() {}
- virtual ~SoundTriggerCallback() {}
-
- virtual void onRecognitionEvent(struct sound_trigger_recognition_event *event) = 0;
-
- virtual void onSoundModelEvent(struct sound_trigger_model_event *event) = 0;
-
- virtual void onServiceStateChange(sound_trigger_service_state_t state) = 0;
-
- virtual void onServiceDied() = 0;
-
-};
-
-}; // namespace android
-
-#endif //ANDROID_HARDWARE_SOUNDTRIGGER_CALLBACK_H
diff --git a/media/audioserver/Android.mk b/media/audioserver/Android.mk
index 33b36b8..f44f0d5 100644
--- a/media/audioserver/Android.mk
+++ b/media/audioserver/Android.mk
@@ -9,21 +9,23 @@
libaaudioservice \
libaudioflinger \
libaudiopolicyservice \
+ libaudioprocessing \
libbinder \
libcutils \
liblog \
libhidlbase \
- libhidltransport \
- libhwbinder \
libmedia \
libmedialogservice \
libmediautils \
libnbaio \
libnblog \
- libsoundtriggerservice \
libutils \
libvibrator
+LOCAL_HEADER_LIBRARIES := \
+ libaudiohal_headers \
+ libmediametrics_headers \
+
# TODO oboeservice is the old folder name for aaudioservice. It will be changed.
LOCAL_C_INCLUDES := \
frameworks/av/services/audioflinger \
@@ -34,30 +36,12 @@
frameworks/av/services/audiopolicy/service \
frameworks/av/services/medialog \
frameworks/av/services/oboeservice \
- frameworks/av/services/radio \
- frameworks/av/services/soundtrigger \
frameworks/av/media/libaaudio/include \
frameworks/av/media/libaaudio/src \
frameworks/av/media/libaaudio/src/binding \
frameworks/av/media/libmedia \
- $(call include-path-for, audio-utils) \
external/sonic \
-# If AUDIOSERVER_MULTILIB in device.mk is non-empty then it is used to control
-# the LOCAL_MULTILIB for all audioserver exclusive libraries.
-# This is relevant for 64 bit architectures where either or both
-# 32 and 64 bit libraries may be built.
-#
-# AUDIOSERVER_MULTILIB may be set as follows:
-# 32 to build 32 bit audioserver libraries and 32 bit audioserver.
-# 64 to build 64 bit audioserver libraries and 64 bit audioserver.
-# both to build both 32 bit and 64 bit libraries,
-# and use primary target architecture (32 or 64) for audioserver.
-# first to build libraries and audioserver for the primary target architecture only.
-# <empty> to build both 32 and 64 bit libraries and primary target audioserver.
-
-LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-
LOCAL_MODULE := audioserver
LOCAL_INIT_RC := audioserver.rc
diff --git a/media/audioserver/audioserver.rc b/media/audioserver/audioserver.rc
index dfb1a3f..5484613 100644
--- a/media/audioserver/audioserver.rc
+++ b/media/audioserver/audioserver.rc
@@ -2,14 +2,14 @@
class core
user audioserver
# media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
- group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct wakelock
+ group audio camera drmrpc media mediadrm net_bt net_bt_admin net_bw_acct wakelock
capabilities BLOCK_SUSPEND
ioprio rt 4
writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
- onrestart restart vendor.audio-hal-2-0
+ onrestart restart vendor.audio-hal
onrestart restart vendor.audio-hal-4-0-msd
- # Keep the original service name for backward compatibility when upgrading
- # O-MR1 devices with framework-only.
+ # Keep the original service names for backward compatibility
+ onrestart restart vendor.audio-hal-2-0
onrestart restart audio-hal-2-0
on property:vts.native_server.on=1
diff --git a/media/audioserver/main_audioserver.cpp b/media/audioserver/main_audioserver.cpp
index db57248..4a2ac1d 100644
--- a/media/audioserver/main_audioserver.cpp
+++ b/media/audioserver/main_audioserver.cpp
@@ -36,7 +36,6 @@
#include "utility/AAudioUtilities.h"
#include "MediaLogService.h"
#include "MediaUtils.h"
-#include "SoundTriggerHwService.h"
using namespace android;
@@ -148,7 +147,6 @@
AAudioService::instantiate();
}
- SoundTriggerHwService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
diff --git a/media/bufferpool/1.0/AccessorImpl.cpp b/media/bufferpool/1.0/AccessorImpl.cpp
index a5366f6..0d7e92f 100644
--- a/media/bufferpool/1.0/AccessorImpl.cpp
+++ b/media/bufferpool/1.0/AccessorImpl.cpp
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-#define LOG_TAG "BufferPoolAccessor"
+#define LOG_TAG "BufferPoolAccessor1.0"
//#define LOG_NDEBUG 0
#include <sys/types.h>
+#include <stdint.h>
#include <time.h>
#include <unistd.h>
#include <utils/Log.h>
@@ -127,7 +128,6 @@
return false;
}
-int32_t Accessor::Impl::sPid = getpid();
uint32_t Accessor::Impl::sSeqId = time(nullptr);
Accessor::Impl::Impl(
@@ -145,14 +145,19 @@
{
std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
if (newConnection) {
- ConnectionId id = (int64_t)sPid << 32 | sSeqId;
+ int32_t pid = getpid();
+ ConnectionId id = (int64_t)pid << 32 | sSeqId;
status = mBufferPool.mObserver.open(id, fmqDescPtr);
if (status == ResultStatus::OK) {
newConnection->initialize(accessor, id);
*connection = newConnection;
*pConnectionId = id;
mBufferPool.mConnectionIds.insert(id);
- ++sSeqId;
+ if (sSeqId == UINT32_MAX) {
+ sSeqId = 0;
+ } else {
+ ++sSeqId;
+ }
}
}
mBufferPool.processStatusMessages();
@@ -248,7 +253,7 @@
ALOGD("Destruction - bufferpool %p "
"cached: %zu/%zuM, %zu/%d%% in use; "
"allocs: %zu, %d%% recycled; "
- "transfers: %zu, %d%% unfetced",
+ "transfers: %zu, %d%% unfetched",
this, mStats.mBuffersCached, mStats.mSizeCached >> 20,
mStats.mBuffersInUse, percentage(mStats.mBuffersInUse, mStats.mBuffersCached),
mStats.mTotalAllocations, percentage(mStats.mTotalRecycles, mStats.mTotalAllocations),
diff --git a/media/bufferpool/1.0/AccessorImpl.h b/media/bufferpool/1.0/AccessorImpl.h
index 84cb685..a09cbe2 100644
--- a/media/bufferpool/1.0/AccessorImpl.h
+++ b/media/bufferpool/1.0/AccessorImpl.h
@@ -61,7 +61,6 @@
// ConnectionId = pid : (timestamp_created + seqId)
// in order to guarantee uniqueness for each connection
static uint32_t sSeqId;
- static int32_t sPid;
const std::shared_ptr<BufferPoolAllocator> mAllocator;
diff --git a/media/bufferpool/1.0/Android.bp b/media/bufferpool/1.0/Android.bp
index c7ea70f..f817c76 100644
--- a/media/bufferpool/1.0/Android.bp
+++ b/media/bufferpool/1.0/Android.bp
@@ -16,8 +16,6 @@
"libcutils",
"libfmq",
"libhidlbase",
- "libhwbinder",
- "libhidltransport",
"liblog",
"libutils",
"android.hardware.media.bufferpool@1.0",
diff --git a/media/bufferpool/2.0/AccessorImpl.cpp b/media/bufferpool/2.0/AccessorImpl.cpp
index 0d591d7..1947656 100644
--- a/media/bufferpool/2.0/AccessorImpl.cpp
+++ b/media/bufferpool/2.0/AccessorImpl.cpp
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-#define LOG_TAG "BufferPoolAccessor"
+#define LOG_TAG "BufferPoolAccessor2.0"
//#define LOG_NDEBUG 0
#include <sys/types.h>
+#include <stdint.h>
#include <time.h>
#include <unistd.h>
#include <utils/Log.h>
@@ -134,7 +135,6 @@
return false;
}
-int32_t Accessor::Impl::sPid = getpid();
uint32_t Accessor::Impl::sSeqId = time(nullptr);
Accessor::Impl::Impl(
@@ -156,7 +156,8 @@
{
std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
if (newConnection) {
- ConnectionId id = (int64_t)sPid << 32 | sSeqId;
+ int32_t pid = getpid();
+ ConnectionId id = (int64_t)pid << 32 | sSeqId;
status = mBufferPool.mObserver.open(id, statusDescPtr);
if (status == ResultStatus::OK) {
newConnection->initialize(accessor, id);
@@ -166,7 +167,11 @@
mBufferPool.mConnectionIds.insert(id);
mBufferPool.mInvalidationChannel.getDesc(invDescPtr);
mBufferPool.mInvalidation.onConnect(id, observer);
- ++sSeqId;
+ if (sSeqId == UINT32_MAX) {
+ sSeqId = 0;
+ } else {
+ ++sSeqId;
+ }
}
}
@@ -304,7 +309,7 @@
ALOGD("Destruction - bufferpool2 %p "
"cached: %zu/%zuM, %zu/%d%% in use; "
"allocs: %zu, %d%% recycled; "
- "transfers: %zu, %d%% unfetced",
+ "transfers: %zu, %d%% unfetched",
this, mStats.mBuffersCached, mStats.mSizeCached >> 20,
mStats.mBuffersInUse, percentage(mStats.mBuffersInUse, mStats.mBuffersCached),
mStats.mTotalAllocations, percentage(mStats.mTotalRecycles, mStats.mTotalAllocations),
diff --git a/media/bufferpool/2.0/AccessorImpl.h b/media/bufferpool/2.0/AccessorImpl.h
index 807e0f1..9888be5 100644
--- a/media/bufferpool/2.0/AccessorImpl.h
+++ b/media/bufferpool/2.0/AccessorImpl.h
@@ -75,7 +75,6 @@
// ConnectionId = pid : (timestamp_created + seqId)
// in order to guarantee uniqueness for each connection
static uint32_t sSeqId;
- static int32_t sPid;
const std::shared_ptr<BufferPoolAllocator> mAllocator;
diff --git a/media/bufferpool/2.0/Android.bp b/media/bufferpool/2.0/Android.bp
index e8a69c9..557b7ef 100644
--- a/media/bufferpool/2.0/Android.bp
+++ b/media/bufferpool/2.0/Android.bp
@@ -16,8 +16,6 @@
"libcutils",
"libfmq",
"libhidlbase",
- "libhwbinder",
- "libhidltransport",
"liblog",
"libutils",
"android.hardware.media.bufferpool@2.0",
@@ -32,6 +30,8 @@
name: "libstagefright_bufferpool@2.0.1",
defaults: ["libstagefright_bufferpool@2.0-default"],
vendor_available: true,
+ // TODO: b/147147992
+ double_loadable: true,
cflags: [
"-DBUFFERPOOL_CLONE_HANDLES",
],
@@ -42,6 +42,8 @@
name: "libstagefright_bufferpool@2.0",
defaults: ["libstagefright_bufferpool@2.0-default"],
vendor_available: true,
+ // TODO: b/147147992
+ double_loadable: true,
vndk: {
enabled: true,
},
diff --git a/media/codec2/OWNERS b/media/codec2/OWNERS
new file mode 100644
index 0000000..46a9fca
--- /dev/null
+++ b/media/codec2/OWNERS
@@ -0,0 +1,5 @@
+set noparent
+wonsik@google.com
+lajos@google.com
+pawin@google.com
+taklee@google.com
diff --git a/media/codec2/TEST_MAPPING b/media/codec2/TEST_MAPPING
new file mode 100644
index 0000000..8afa1a8
--- /dev/null
+++ b/media/codec2/TEST_MAPPING
@@ -0,0 +1,22 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsMediaTestCases",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.RequiresDevice"
+ },
+ // TODO: b/149314419
+ {
+ "exclude-filter": "android.media.cts.AudioPlaybackCaptureTest"
+ },
+ {
+ "exclude-filter": "android.media.cts.AudioRecordTest"
+ }
+ ]
+ }
+ ]
+}
diff --git a/media/codec2/components/aac/C2SoftAacDec.cpp b/media/codec2/components/aac/C2SoftAacDec.cpp
index 2d4e126..f39620e 100644
--- a/media/codec2/components/aac/C2SoftAacDec.cpp
+++ b/media/codec2/components/aac/C2SoftAacDec.cpp
@@ -40,6 +40,8 @@
#define DRC_DEFAULT_MOBILE_DRC_BOOST 1.0 /* maximum compression of dynamic range for mobile conf */
#define DRC_DEFAULT_MOBILE_DRC_HEAVY C2Config::DRC_COMPRESSION_HEAVY /* switch for heavy compression for mobile conf */
#define DRC_DEFAULT_MOBILE_DRC_EFFECT 3 /* MPEG-D DRC effect type; 3 => Limited playback range */
+#define DRC_DEFAULT_MOBILE_DRC_ALBUM 0 /* MPEG-D DRC album mode; 0 => album mode is disabled, 1 => album mode is enabled */
+#define DRC_DEFAULT_MOBILE_OUTPUT_LOUDNESS (0.25) /* decoder output loudness; -1 => the value is unknown, otherwise dB step value (e.g. 64 for -16 dB) */
#define DRC_DEFAULT_MOBILE_ENC_LEVEL (0.25) /* encoder target level; -1 => the value is unknown, otherwise dB step value (e.g. 64 for -16 dB) */
#define MAX_CHANNEL_COUNT 8 /* maximum number of audio channels that can be decoded */
// names of properties that can be used to override the default DRC settings
@@ -78,7 +80,8 @@
DefineParam(mSampleRate, C2_PARAMKEY_SAMPLE_RATE)
.withDefault(new C2StreamSampleRateInfo::output(0u, 44100))
.withFields({C2F(mSampleRate, value).oneOf({
- 7350, 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+ 7350, 8000, 11025, 12000, 16000, 22050, 24000, 32000,
+ 44100, 48000, 64000, 88200, 96000
})})
.withSetter(Setter<decltype(*mSampleRate)>::NonStrictValueWithNoDeps)
.build());
@@ -189,6 +192,24 @@
})
.withSetter(Setter<decltype(*mDrcEffectType)>::StrictValueWithNoDeps)
.build());
+
+ addParameter(
+ DefineParam(mDrcAlbumMode, C2_PARAMKEY_DRC_ALBUM_MODE)
+ .withDefault(new C2StreamDrcAlbumModeTuning::input(0u, C2Config::DRC_ALBUM_MODE_OFF))
+ .withFields({
+ C2F(mDrcAlbumMode, value).oneOf({
+ C2Config::DRC_ALBUM_MODE_OFF,
+ C2Config::DRC_ALBUM_MODE_ON})
+ })
+ .withSetter(Setter<decltype(*mDrcAlbumMode)>::StrictValueWithNoDeps)
+ .build());
+
+ addParameter(
+ DefineParam(mDrcOutputLoudness, C2_PARAMKEY_DRC_OUTPUT_LOUDNESS)
+ .withDefault(new C2StreamDrcOutputLoudnessTuning::output(0u, DRC_DEFAULT_MOBILE_OUTPUT_LOUDNESS))
+ .withFields({C2F(mDrcOutputLoudness, value).inRange(-57.75, 0.25)})
+ .withSetter(Setter<decltype(*mDrcOutputLoudness)>::StrictValueWithNoDeps)
+ .build());
}
bool isAdts() const { return mAacFormat->value == C2Config::AAC_PACKAGING_ADTS; }
@@ -203,6 +224,8 @@
int32_t getDrcBoostFactor() const { return mDrcBoostFactor->value * 127. + 0.5; }
int32_t getDrcAttenuationFactor() const { return mDrcAttenuationFactor->value * 127. + 0.5; }
int32_t getDrcEffectType() const { return mDrcEffectType->value; }
+ int32_t getDrcAlbumMode() const { return mDrcAlbumMode->value; }
+ int32_t getDrcOutputLoudness() const { return (mDrcOutputLoudness->value <= 0 ? -mDrcOutputLoudness->value * 4. + 0.5 : -1); }
private:
std::shared_ptr<C2StreamSampleRateInfo::output> mSampleRate;
@@ -217,6 +240,8 @@
std::shared_ptr<C2StreamDrcBoostFactorTuning::input> mDrcBoostFactor;
std::shared_ptr<C2StreamDrcAttenuationFactorTuning::input> mDrcAttenuationFactor;
std::shared_ptr<C2StreamDrcEffectTypeTuning::input> mDrcEffectType;
+ std::shared_ptr<C2StreamDrcAlbumModeTuning::input> mDrcAlbumMode;
+ std::shared_ptr<C2StreamDrcOutputLoudnessTuning::output> mDrcOutputLoudness;
// TODO Add : C2StreamAacSbrModeTuning
};
@@ -323,7 +348,7 @@
// DRC_PRES_MODE_WRAP_DESIRED_HEAVY
int32_t compressMode = mIntf->getDrcCompressMode();
- ALOGV("AAC decoder using desried DRC heavy compression switch of %d", compressMode);
+ ALOGV("AAC decoder using desired DRC heavy compression switch of %d", compressMode);
mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_HEAVY, (unsigned)compressMode);
// DRC_PRES_MODE_WRAP_ENCODER_TARGET
@@ -336,6 +361,11 @@
ALOGV("AAC decoder using MPEG-D DRC effect type %d", effectType);
aacDecoder_SetParam(mAACDecoder, AAC_UNIDRC_SET_EFFECT, effectType);
+ // AAC_UNIDRC_ALBUM_MODE
+ int32_t albumMode = mIntf->getDrcAlbumMode();
+ ALOGV("AAC decoder using MPEG-D DRC album mode %d", albumMode);
+ aacDecoder_SetParam(mAACDecoder, AAC_UNIDRC_ALBUM_MODE, albumMode);
+
// By default, the decoder creates a 5.1 channel downmix signal.
// For seven and eight channel input streams, enable 6.1 and 7.1 channel output
aacDecoder_SetParam(mAACDecoder, AAC_PCM_MAX_OUTPUT_CHANNELS, -1);
@@ -631,6 +661,7 @@
INT prevSampleRate = mStreamInfo->sampleRate;
INT prevNumChannels = mStreamInfo->numChannels;
+ INT prevOutLoudness = mStreamInfo->outputLoudness;
aacDecoder_Fill(mAACDecoder,
inBuffer,
@@ -639,6 +670,43 @@
// run DRC check
mDrcWrap.submitStreamData(mStreamInfo);
+
+ // apply runtime updates
+ // DRC_PRES_MODE_WRAP_DESIRED_TARGET
+ int32_t targetRefLevel = mIntf->getDrcTargetRefLevel();
+ ALOGV("AAC decoder using desired DRC target reference level of %d", targetRefLevel);
+ mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_TARGET, (unsigned)targetRefLevel);
+
+ // DRC_PRES_MODE_WRAP_DESIRED_ATT_FACTOR
+ int32_t attenuationFactor = mIntf->getDrcAttenuationFactor();
+ ALOGV("AAC decoder using desired DRC attenuation factor of %d", attenuationFactor);
+ mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_ATT_FACTOR, (unsigned)attenuationFactor);
+
+ // DRC_PRES_MODE_WRAP_DESIRED_BOOST_FACTOR
+ int32_t boostFactor = mIntf->getDrcBoostFactor();
+ ALOGV("AAC decoder using desired DRC boost factor of %d", boostFactor);
+ mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_BOOST_FACTOR, (unsigned)boostFactor);
+
+ // DRC_PRES_MODE_WRAP_DESIRED_HEAVY
+ int32_t compressMode = mIntf->getDrcCompressMode();
+ ALOGV("AAC decoder using desried DRC heavy compression switch of %d", compressMode);
+ mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_HEAVY, (unsigned)compressMode);
+
+ // DRC_PRES_MODE_WRAP_ENCODER_TARGET
+ int32_t encTargetLevel = mIntf->getDrcEncTargetLevel();
+ ALOGV("AAC decoder using encoder-side DRC reference level of %d", encTargetLevel);
+ mDrcWrap.setParam(DRC_PRES_MODE_WRAP_ENCODER_TARGET, (unsigned)encTargetLevel);
+
+ // AAC_UNIDRC_SET_EFFECT
+ int32_t effectType = mIntf->getDrcEffectType();
+ ALOGV("AAC decoder using MPEG-D DRC effect type %d", effectType);
+ aacDecoder_SetParam(mAACDecoder, AAC_UNIDRC_SET_EFFECT, effectType);
+
+ // AAC_UNIDRC_ALBUM_MODE
+ int32_t albumMode = mIntf->getDrcAlbumMode();
+ ALOGV("AAC decoder using MPEG-D DRC album mode %d", albumMode);
+ aacDecoder_SetParam(mAACDecoder, AAC_UNIDRC_ALBUM_MODE, albumMode);
+
mDrcWrap.update();
UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0];
@@ -762,6 +830,23 @@
}
}
ALOGV("size = %zu", size);
+
+ if (mStreamInfo->outputLoudness != prevOutLoudness) {
+ C2StreamDrcOutputLoudnessTuning::output
+ drcOutLoudness(0u, (float) (mStreamInfo->outputLoudness*-0.25));
+
+ std::vector<std::unique_ptr<C2SettingResult>> failures;
+ c2_status_t err = mIntf->config(
+ { &drcOutLoudness },
+ C2_MAY_BLOCK,
+ &failures);
+ if (err == OK) {
+ work->worklets.front()->output.configUpdate.push_back(
+ C2Param::Copy(drcOutLoudness));
+ } else {
+ ALOGE("Getting output loudness failed");
+ }
+ }
} while (decoderErr == AAC_DEC_OK);
}
diff --git a/media/codec2/components/aac/C2SoftAacEnc.cpp b/media/codec2/components/aac/C2SoftAacEnc.cpp
index be52a1d..4db94f5 100644
--- a/media/codec2/components/aac/C2SoftAacEnc.cpp
+++ b/media/codec2/components/aac/C2SoftAacEnc.cpp
@@ -155,9 +155,7 @@
mNumBytesPerInputFrame(0u),
mOutBufferSize(0u),
mSentCodecSpecificData(false),
- mInputTimeSet(false),
mInputSize(0),
- mNextFrameTimestampUs(0),
mSignalledError(false),
mOutIndex(0u),
mRemainderLen(0u) {
@@ -182,9 +180,9 @@
c2_status_t C2SoftAacEnc::onStop() {
mSentCodecSpecificData = false;
- mInputTimeSet = false;
mInputSize = 0u;
- mNextFrameTimestampUs = 0;
+ mNextFrameTimestampUs.reset();
+ mLastFrameEndTimestampUs.reset();
mSignalledError = false;
mRemainderLen = 0;
return C2_OK;
@@ -201,9 +199,9 @@
c2_status_t C2SoftAacEnc::onFlush_sm() {
mSentCodecSpecificData = false;
- mInputTimeSet = false;
mInputSize = 0u;
- mNextFrameTimestampUs = 0;
+ mNextFrameTimestampUs.reset();
+ mLastFrameEndTimestampUs.reset();
return C2_OK;
}
@@ -366,9 +364,19 @@
data = view.data();
capacity = view.capacity();
}
- if (!mInputTimeSet && capacity > 0) {
- mNextFrameTimestampUs = work->input.ordinal.timestamp;
- mInputTimeSet = true;
+ c2_cntr64_t inputTimestampUs = work->input.ordinal.timestamp;
+ if (inputTimestampUs < mLastFrameEndTimestampUs.value_or(inputTimestampUs)) {
+ ALOGW("Correcting overlapping timestamp: last frame ended at %lldus but "
+ "current frame is starting at %lldus. Using the last frame's end timestamp",
+ mLastFrameEndTimestampUs->peekll(), inputTimestampUs.peekll());
+ inputTimestampUs = *mLastFrameEndTimestampUs;
+ }
+ if (capacity > 0) {
+ if (!mNextFrameTimestampUs) {
+ mNextFrameTimestampUs = work->input.ordinal.timestamp;
+ }
+ mLastFrameEndTimestampUs = inputTimestampUs
+ + (capacity / sizeof(int16_t) * 1000000ll / channelCount / sampleRate);
}
size_t numFrames =
@@ -376,8 +384,7 @@
/ mNumBytesPerInputFrame;
ALOGV("capacity = %zu; mInputSize = %zu; numFrames = %zu "
"mNumBytesPerInputFrame = %u inputTS = %lld remaining = %zu",
- capacity, mInputSize, numFrames,
- mNumBytesPerInputFrame, work->input.ordinal.timestamp.peekll(),
+ capacity, mInputSize, numFrames, mNumBytesPerInputFrame, inputTimestampUs.peekll(),
mRemainderLen);
std::shared_ptr<C2LinearBlock> block;
@@ -505,8 +512,10 @@
mInputSize = 0;
int consumed = (capacity / sizeof(int16_t)) - inargs.numInSamples
+ outargs.numInSamples;
- c2_cntr64_t currentFrameTimestampUs = mNextFrameTimestampUs;
- mNextFrameTimestampUs = work->input.ordinal.timestamp
+ ALOGV("consumed = %d, capacity = %zu, inSamples = %d, outSamples = %d",
+ consumed, capacity, inargs.numInSamples, outargs.numInSamples);
+ c2_cntr64_t currentFrameTimestampUs = *mNextFrameTimestampUs;
+ mNextFrameTimestampUs = inputTimestampUs
+ (consumed * 1000000ll / channelCount / sampleRate);
std::shared_ptr<C2Buffer> buffer = createLinearBuffer(block, 0, outargs.numOutBytes);
#if 0
@@ -533,7 +542,7 @@
}
ALOGV("encoderErr = %d mInputSize = %zu "
"inargs.numInSamples = %d, mNextFrameTimestampUs = %lld",
- encoderErr, mInputSize, inargs.numInSamples, mNextFrameTimestampUs.peekll());
+ encoderErr, mInputSize, inargs.numInSamples, mNextFrameTimestampUs->peekll());
}
if (eos && inBufferSize[0] > 0) {
if (numFrames && !block) {
@@ -617,9 +626,9 @@
(void)pool;
mSentCodecSpecificData = false;
- mInputTimeSet = false;
mInputSize = 0u;
- mNextFrameTimestampUs = 0;
+ mNextFrameTimestampUs.reset();
+ mLastFrameEndTimestampUs.reset();
// TODO: we don't have any pending work at this time to drain.
return C2_OK;
diff --git a/media/codec2/components/aac/C2SoftAacEnc.h b/media/codec2/components/aac/C2SoftAacEnc.h
index 6ecfbdd..9a28280 100644
--- a/media/codec2/components/aac/C2SoftAacEnc.h
+++ b/media/codec2/components/aac/C2SoftAacEnc.h
@@ -18,6 +18,7 @@
#define ANDROID_C2_SOFT_AAC_ENC_H_
#include <atomic>
+#include <optional>
#include <SimpleC2Component.h>
@@ -54,9 +55,9 @@
UINT mOutBufferSize;
bool mSentCodecSpecificData;
- bool mInputTimeSet;
size_t mInputSize;
- c2_cntr64_t mNextFrameTimestampUs;
+ std::optional<c2_cntr64_t> mNextFrameTimestampUs;
+ std::optional<c2_cntr64_t> mLastFrameEndTimestampUs;
bool mSignalledError;
std::atomic_uint64_t mOutIndex;
diff --git a/media/codec2/components/aac/DrcPresModeWrap.cpp b/media/codec2/components/aac/DrcPresModeWrap.cpp
index 5b9aebc..bee969b 100644
--- a/media/codec2/components/aac/DrcPresModeWrap.cpp
+++ b/media/codec2/components/aac/DrcPresModeWrap.cpp
@@ -47,10 +47,9 @@
mEncoderTarget = -1;
/* Values from last time. */
- /* Initialized to the same values as the desired values */
- mLastTarget = -1;
- mLastAttFactor = 0;
- mLastBoostFactor = 0;
+ mLastTarget = -2;
+ mLastAttFactor = -1;
+ mLastBoostFactor = -1;
mLastHeavy = 0;
}
@@ -163,7 +162,7 @@
if (mDataUpdate) {
// sanity check
- if (mDesTarget < MAX_TARGET_LEVEL){
+ if ((mDesTarget < MAX_TARGET_LEVEL) && (mDesTarget != -1)){
mDesTarget = MAX_TARGET_LEVEL; // limit target level to -10 dB or below
newTarget = MAX_TARGET_LEVEL;
}
diff --git a/media/codec2/components/aom/C2SoftAomDec.cpp b/media/codec2/components/aom/C2SoftAomDec.cpp
index 36137e6..c7046cb 100644
--- a/media/codec2/components/aom/C2SoftAomDec.cpp
+++ b/media/codec2/components/aom/C2SoftAomDec.cpp
@@ -29,6 +29,8 @@
namespace android {
+constexpr size_t kMinInputBufferSize = 2 * 1024 * 1024;
+
// codecname set and passed in as a compile flag from Android.bp
constexpr char COMPONENT_NAME[] = CODECNAME;
@@ -112,7 +114,7 @@
addParameter(
DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
.withDefault(
- new C2StreamMaxBufferSizeInfo::input(0u, 320 * 240 * 3 / 4))
+ new C2StreamMaxBufferSizeInfo::input(0u, kMinInputBufferSize))
.withFields({
C2F(mMaxInputSize, value).any(),
})
@@ -192,8 +194,8 @@
const C2P<C2StreamMaxPictureSizeTuning::output>& maxSize) {
(void)mayBlock;
// assume compression ratio of 2
- me.set().value = (((maxSize.v.width + 63) / 64) *
- ((maxSize.v.height + 63) / 64) * 3072);
+ me.set().value = c2_max((((maxSize.v.width + 63) / 64)
+ * ((maxSize.v.height + 63) / 64) * 3072), kMinInputBufferSize);
return C2R::Ok();
}
static C2R DefaultColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsTuning::output> &me) {
diff --git a/media/codec2/components/avc/C2SoftAvcDec.cpp b/media/codec2/components/avc/C2SoftAvcDec.cpp
index fa98178..56813c4 100644
--- a/media/codec2/components/avc/C2SoftAvcDec.cpp
+++ b/media/codec2/components/avc/C2SoftAvcDec.cpp
@@ -31,7 +31,7 @@
namespace android {
namespace {
-
+constexpr size_t kMinInputBufferSize = 2 * 1024 * 1024;
constexpr char COMPONENT_NAME[] = "c2.android.avc.decoder";
constexpr uint32_t kDefaultOutputDelay = 8;
constexpr uint32_t kMaxOutputDelay = 16;
@@ -114,7 +114,7 @@
addParameter(
DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
- .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, 320 * 240 * 3 / 4))
+ .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, kMinInputBufferSize))
.withFields({
C2F(mMaxInputSize, value).any(),
})
@@ -227,7 +227,8 @@
const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) {
(void)mayBlock;
// assume compression ratio of 2
- me.set().value = (((maxSize.v.width + 15) / 16) * ((maxSize.v.height + 15) / 16) * 192);
+ me.set().value = c2_max((((maxSize.v.width + 15) / 16)
+ * ((maxSize.v.height + 15) / 16) * 192), kMinInputBufferSize);
return C2R::Ok();
}
@@ -500,7 +501,7 @@
status_t C2SoftAvcDec::initDecoder() {
if (OK != createDecoder()) return UNKNOWN_ERROR;
mNumCores = MIN(getCpuCoreCount(), MAX_NUM_CORES);
- mStride = ALIGN64(mWidth);
+ mStride = ALIGN128(mWidth);
mSignalledError = false;
resetPlugin();
(void) setNumCores();
@@ -755,8 +756,8 @@
ALOGE("not supposed to be here, invalid decoder context");
return C2_CORRUPTED;
}
- if (mStride != ALIGN64(mWidth)) {
- mStride = ALIGN64(mWidth);
+ if (mStride != ALIGN128(mWidth)) {
+ mStride = ALIGN128(mWidth);
if (OK != setParams(mStride, IVD_DECODE_FRAME)) return C2_CORRUPTED;
}
if (mOutBlock &&
@@ -908,7 +909,7 @@
if (0 < s_decode_op.u4_pic_wd && 0 < s_decode_op.u4_pic_ht) {
if (mHeaderDecoded == false) {
mHeaderDecoded = true;
- setParams(ALIGN64(s_decode_op.u4_pic_wd), IVD_DECODE_FRAME);
+ setParams(ALIGN128(s_decode_op.u4_pic_wd), IVD_DECODE_FRAME);
}
if (s_decode_op.u4_pic_wd != mWidth || s_decode_op.u4_pic_ht != mHeight) {
mWidth = s_decode_op.u4_pic_wd;
diff --git a/media/codec2/components/avc/C2SoftAvcDec.h b/media/codec2/components/avc/C2SoftAvcDec.h
index 4414a26..ed27493 100644
--- a/media/codec2/components/avc/C2SoftAvcDec.h
+++ b/media/codec2/components/avc/C2SoftAvcDec.h
@@ -40,6 +40,7 @@
#define ivdext_ctl_get_vui_params_ip_t ih264d_ctl_get_vui_params_ip_t
#define ivdext_ctl_get_vui_params_op_t ih264d_ctl_get_vui_params_op_t
#define ALIGN64(x) ((((x) + 63) >> 6) << 6)
+#define ALIGN128(x) ((((x) + 127) >> 7) << 7)
#define MAX_NUM_CORES 4
#define IVDEXT_CMD_CTL_SET_NUM_CORES \
(IVD_CONTROL_API_COMMAND_TYPE_T)IH264D_CMD_CTL_SET_NUM_CORES
diff --git a/media/codec2/components/avc/C2SoftAvcEnc.cpp b/media/codec2/components/avc/C2SoftAvcEnc.cpp
index b41c271..e3d419c 100644
--- a/media/codec2/components/avc/C2SoftAvcEnc.cpp
+++ b/media/codec2/components/avc/C2SoftAvcEnc.cpp
@@ -40,7 +40,7 @@
namespace {
constexpr char COMPONENT_NAME[] = "c2.android.avc.encoder";
-
+constexpr uint32_t kMinOutBufferSize = 524288;
void ParseGop(
const C2StreamGopTuning::output &gop,
uint32_t *syncInterval, uint32_t *iInterval, uint32_t *maxBframes) {
@@ -440,8 +440,7 @@
mSignalledError(false),
mCodecCtx(nullptr),
mOutBlock(nullptr),
- // TODO: output buffer size
- mOutBufferSize(524288) {
+ mOutBufferSize(kMinOutBufferSize) {
// If dump is enabled, then open create an empty file
GENERATE_FILE_NAMES();
@@ -951,6 +950,9 @@
mStride = width;
+ // Assume worst case output buffer size to be equal to number of bytes in input
+ mOutBufferSize = std::max(width * height * 3 / 2, kMinOutBufferSize);
+
// TODO
mIvVideoColorFormat = IV_YUV_420P;
diff --git a/media/codec2/components/cmds/Android.bp b/media/codec2/components/cmds/Android.bp
index 35f689e..a081e28 100644
--- a/media/codec2/components/cmds/Android.bp
+++ b/media/codec2/components/cmds/Android.bp
@@ -9,10 +9,15 @@
include_dirs: [
],
+ header_libs: [
+ "libmediadrm_headers",
+ ],
+
shared_libs: [
"libbase",
"libbinder",
"libcutils",
+ "libdatasource",
"libgui",
"liblog",
"libstagefright",
diff --git a/media/codec2/components/cmds/codec2.cpp b/media/codec2/components/cmds/codec2.cpp
index f2cf545..d6025de 100644
--- a/media/codec2/components/cmds/codec2.cpp
+++ b/media/codec2/components/cmds/codec2.cpp
@@ -30,15 +30,15 @@
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
+#include <datasource/DataSourceFactory.h>
#include <media/DataSource.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/IMediaHTTPService.h>
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AUtils.h>
-#include <media/stagefright/DataSourceFactory.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaExtractorFactory.h>
@@ -418,7 +418,7 @@
const char *filename = argv[k];
sp<DataSource> dataSource =
- DataSourceFactory::CreateFromURI(nullptr /* httpService */, filename);
+ DataSourceFactory::getInstance()->CreateFromURI(nullptr /* httpService */, filename);
if (strncasecmp(filename, "sine:", 5) && dataSource == nullptr) {
fprintf(stderr, "Unable to create data source.\n");
diff --git a/media/codec2/components/flac/Android.bp b/media/codec2/components/flac/Android.bp
index e5eb51d..48cc51b 100644
--- a/media/codec2/components/flac/Android.bp
+++ b/media/codec2/components/flac/Android.bp
@@ -23,8 +23,11 @@
srcs: ["C2SoftFlacEnc.cpp"],
- static_libs: [
+ shared_libs: [
"libaudioutils",
+ ],
+
+ static_libs: [
"libFLAC",
],
}
diff --git a/media/codec2/components/hevc/C2SoftHevcDec.cpp b/media/codec2/components/hevc/C2SoftHevcDec.cpp
index df677c2..6db4387 100644
--- a/media/codec2/components/hevc/C2SoftHevcDec.cpp
+++ b/media/codec2/components/hevc/C2SoftHevcDec.cpp
@@ -497,7 +497,7 @@
status_t C2SoftHevcDec::initDecoder() {
if (OK != createDecoder()) return UNKNOWN_ERROR;
mNumCores = MIN(getCpuCoreCount(), MAX_NUM_CORES);
- mStride = ALIGN64(mWidth);
+ mStride = ALIGN128(mWidth);
mSignalledError = false;
resetPlugin();
(void) setNumCores();
@@ -752,8 +752,8 @@
ALOGE("not supposed to be here, invalid decoder context");
return C2_CORRUPTED;
}
- if (mStride != ALIGN64(mWidth)) {
- mStride = ALIGN64(mWidth);
+ if (mStride != ALIGN128(mWidth)) {
+ mStride = ALIGN128(mWidth);
if (OK != setParams(mStride, IVD_DECODE_FRAME)) return C2_CORRUPTED;
}
if (mOutBlock &&
@@ -904,7 +904,7 @@
if (0 < s_decode_op.u4_pic_wd && 0 < s_decode_op.u4_pic_ht) {
if (mHeaderDecoded == false) {
mHeaderDecoded = true;
- setParams(ALIGN64(s_decode_op.u4_pic_wd), IVD_DECODE_FRAME);
+ setParams(ALIGN128(s_decode_op.u4_pic_wd), IVD_DECODE_FRAME);
}
if (s_decode_op.u4_pic_wd != mWidth || s_decode_op.u4_pic_ht != mHeight) {
mWidth = s_decode_op.u4_pic_wd;
diff --git a/media/codec2/components/hevc/C2SoftHevcDec.h b/media/codec2/components/hevc/C2SoftHevcDec.h
index ce63a6c..aecd101 100644
--- a/media/codec2/components/hevc/C2SoftHevcDec.h
+++ b/media/codec2/components/hevc/C2SoftHevcDec.h
@@ -38,6 +38,7 @@
#define ivdext_ctl_get_vui_params_ip_t ihevcd_cxa_ctl_get_vui_params_ip_t
#define ivdext_ctl_get_vui_params_op_t ihevcd_cxa_ctl_get_vui_params_op_t
#define ALIGN64(x) ((((x) + 63) >> 6) << 6)
+#define ALIGN128(x) ((((x) + 127) >> 7) << 7)
#define MAX_NUM_CORES 4
#define IVDEXT_CMD_CTL_SET_NUM_CORES \
(IVD_CONTROL_API_COMMAND_TYPE_T)IHEVCD_CXA_CMD_CTL_SET_NUM_CORES
diff --git a/media/codec2/components/hevc/C2SoftHevcEnc.cpp b/media/codec2/components/hevc/C2SoftHevcEnc.cpp
index b129b1b..19ccbf9 100644
--- a/media/codec2/components/hevc/C2SoftHevcEnc.cpp
+++ b/media/codec2/components/hevc/C2SoftHevcEnc.cpp
@@ -42,6 +42,36 @@
constexpr char COMPONENT_NAME[] = "c2.android.hevc.encoder";
+void ParseGop(
+ const C2StreamGopTuning::output &gop,
+ uint32_t *syncInterval, uint32_t *iInterval, uint32_t *maxBframes) {
+ uint32_t syncInt = 1;
+ uint32_t iInt = 1;
+ for (size_t i = 0; i < gop.flexCount(); ++i) {
+ const C2GopLayerStruct &layer = gop.m.values[i];
+ if (layer.count == UINT32_MAX) {
+ syncInt = 0;
+ } else if (syncInt <= UINT32_MAX / (layer.count + 1)) {
+ syncInt *= (layer.count + 1);
+ }
+ if ((layer.type_ & I_FRAME) == 0) {
+ if (layer.count == UINT32_MAX) {
+ iInt = 0;
+ } else if (iInt <= UINT32_MAX / (layer.count + 1)) {
+ iInt *= (layer.count + 1);
+ }
+ }
+ if (layer.type_ == C2Config::picture_type_t(P_FRAME | B_FRAME) && maxBframes) {
+ *maxBframes = layer.count;
+ }
+ }
+ if (syncInterval) {
+ *syncInterval = syncInt;
+ }
+ if (iInterval) {
+ *iInterval = iInt;
+ }
+}
} // namepsace
class C2SoftHevcEnc::IntfImpl : public SimpleInterface<void>::BaseParams {
@@ -60,13 +90,21 @@
setDerivedInstance(this);
addParameter(
+ DefineParam(mGop, C2_PARAMKEY_GOP)
+ .withDefault(C2StreamGopTuning::output::AllocShared(
+ 0 /* flexCount */, 0u /* stream */))
+ .withFields({C2F(mGop, m.values[0].type_).any(),
+ C2F(mGop, m.values[0].count).any()})
+ .withSetter(GopSetter)
+ .build());
+
+ addParameter(
DefineParam(mActualInputDelay, C2_PARAMKEY_INPUT_DELAY)
.withDefault(new C2PortActualDelayTuning::input(
DEFAULT_B_FRAMES + DEFAULT_RC_LOOKAHEAD))
.withFields({C2F(mActualInputDelay, value).inRange(
0, MAX_B_FRAMES + MAX_RC_LOOKAHEAD)})
- .withSetter(
- Setter<decltype(*mActualInputDelay)>::StrictValueWithNoDeps)
+ .calculatedAs(InputDelaySetter, mGop)
.build());
addParameter(
@@ -172,6 +210,17 @@
.build());
}
+ static C2R InputDelaySetter(
+ bool mayBlock,
+ C2P<C2PortActualDelayTuning::input> &me,
+ const C2P<C2StreamGopTuning::output> &gop) {
+ (void)mayBlock;
+ uint32_t maxBframes = 0;
+ ParseGop(gop.v, nullptr, nullptr, &maxBframes);
+ me.set().value = maxBframes + DEFAULT_RC_LOOKAHEAD;
+ return C2R::Ok();
+ }
+
static C2R BitrateSetter(bool mayBlock,
C2P<C2StreamBitrateInfo::output>& me) {
(void)mayBlock;
@@ -270,6 +319,18 @@
return C2R::Ok();
}
+ static C2R GopSetter(bool mayBlock, C2P<C2StreamGopTuning::output> &me) {
+ (void)mayBlock;
+ for (size_t i = 0; i < me.v.flexCount(); ++i) {
+ const C2GopLayerStruct &layer = me.v.m.values[0];
+ if (layer.type_ == C2Config::picture_type_t(P_FRAME | B_FRAME)
+ && layer.count > MAX_B_FRAMES) {
+ me.set().m.values[i].count = MAX_B_FRAMES;
+ }
+ }
+ return C2R::Ok();
+ }
+
UWORD32 getProfile_l() const {
switch (mProfileLevel->profile) {
case PROFILE_HEVC_MAIN: [[fallthrough]];
@@ -338,6 +399,9 @@
std::shared_ptr<C2StreamQualityTuning::output> getQuality_l() const {
return mQuality;
}
+ std::shared_ptr<C2StreamGopTuning::output> getGop_l() const {
+ return mGop;
+ }
private:
std::shared_ptr<C2StreamUsageTuning::input> mUsage;
@@ -350,6 +414,7 @@
std::shared_ptr<C2StreamQualityTuning::output> mQuality;
std::shared_ptr<C2StreamProfileLevelInfo::output> mProfileLevel;
std::shared_ptr<C2StreamSyncFrameIntervalTuning::output> mSyncFramePeriod;
+ std::shared_ptr<C2StreamGopTuning::output> mGop;
};
static size_t GetCPUCoreCount() {
@@ -449,7 +514,25 @@
ALOGE("HEVC default init failed : 0x%x", err);
return C2_CORRUPTED;
}
-
+ mBframes = 0;
+ if (mGop && mGop->flexCount() > 0) {
+ uint32_t syncInterval = 1;
+ uint32_t iInterval = 1;
+ uint32_t maxBframes = 0;
+ ParseGop(*mGop, &syncInterval, &iInterval, &maxBframes);
+ if (syncInterval > 0) {
+ ALOGD("Updating IDR interval from GOP: old %u new %u", mIDRInterval, syncInterval);
+ mIDRInterval = syncInterval;
+ }
+ if (iInterval > 0) {
+ ALOGD("Updating I interval from GOP: old %u new %u", mIInterval, iInterval);
+ mIInterval = iInterval;
+ }
+ if (mBframes != maxBframes) {
+ ALOGD("Updating max B frames from GOP: old %u new %u", mBframes, maxBframes);
+ mBframes = maxBframes;
+ }
+ }
// update configuration
mEncParams.s_src_prms.i4_width = mSize->width;
mEncParams.s_src_prms.i4_height = mSize->height;
@@ -463,12 +546,20 @@
mBitrate->value << 1;
mEncParams.s_tgt_lyr_prms.as_tgt_params[0].i4_codec_level = mHevcEncLevel;
mEncParams.s_coding_tools_prms.i4_max_i_open_gop_period = mIDRInterval;
- mEncParams.s_coding_tools_prms.i4_max_cra_open_gop_period = mIDRInterval;
+ mEncParams.s_coding_tools_prms.i4_max_cra_open_gop_period = mIInterval;
mIvVideoColorFormat = IV_YUV_420P;
mEncParams.s_multi_thrd_prms.i4_max_num_cores = mNumCores;
mEncParams.s_out_strm_prms.i4_codec_profile = mHevcEncProfile;
mEncParams.s_lap_prms.i4_rc_look_ahead_pics = DEFAULT_RC_LOOKAHEAD;
- mEncParams.s_coding_tools_prms.i4_max_temporal_layers = DEFAULT_B_FRAMES;
+ if (mBframes == 0) {
+ mEncParams.s_coding_tools_prms.i4_max_temporal_layers = 0;
+ } else if (mBframes <= 2) {
+ mEncParams.s_coding_tools_prms.i4_max_temporal_layers = 1;
+ } else if (mBframes <= 6) {
+ mEncParams.s_coding_tools_prms.i4_max_temporal_layers = 2;
+ } else {
+ mEncParams.s_coding_tools_prms.i4_max_temporal_layers = 3;
+ }
switch (mBitrateMode->value) {
case C2Config::BITRATE_IGNORE:
@@ -523,6 +614,7 @@
c2_status_t C2SoftHevcEnc::initEncoder() {
CHECK(!mCodecCtx);
+
{
IntfImpl::Lock lock = mIntf->lock();
mSize = mIntf->getSize_l();
@@ -532,8 +624,10 @@
mHevcEncProfile = mIntf->getProfile_l();
mHevcEncLevel = mIntf->getLevel_l();
mIDRInterval = mIntf->getSyncFramePeriod_l();
+ mIInterval = mIntf->getSyncFramePeriod_l();
mComplexity = mIntf->getComplexity_l();
mQuality = mIntf->getQuality_l();
+ mGop = mIntf->getGop_l();
}
c2_status_t status = initEncParams();
diff --git a/media/codec2/components/hevc/C2SoftHevcEnc.h b/media/codec2/components/hevc/C2SoftHevcEnc.h
index f2c7642..140b4a9 100644
--- a/media/codec2/components/hevc/C2SoftHevcEnc.h
+++ b/media/codec2/components/hevc/C2SoftHevcEnc.h
@@ -67,6 +67,8 @@
ihevce_static_cfg_params_t mEncParams;
size_t mNumCores;
UWORD32 mIDRInterval;
+ UWORD32 mIInterval;
+ UWORD32 mBframes;
IV_COLOR_FORMAT_T mIvVideoColorFormat;
UWORD32 mHevcEncProfile;
UWORD32 mHevcEncLevel;
@@ -85,7 +87,7 @@
std::shared_ptr<C2StreamBitrateModeTuning::output> mBitrateMode;
std::shared_ptr<C2StreamComplexityTuning::output> mComplexity;
std::shared_ptr<C2StreamQualityTuning::output> mQuality;
-
+ std::shared_ptr<C2StreamGopTuning::output> mGop;
#ifdef FILE_DUMP_ENABLE
char mInFile[200];
char mOutFile[200];
diff --git a/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp b/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp
index df7b403..e0365fc 100644
--- a/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp
+++ b/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp
@@ -29,7 +29,7 @@
#include "impeg2d.h"
namespace android {
-
+constexpr size_t kMinInputBufferSize = 2 * 1024 * 1024;
constexpr char COMPONENT_NAME[] = "c2.android.mpeg2.decoder";
class C2SoftMpeg2Dec::IntfImpl : public SimpleInterface<void>::BaseParams {
@@ -47,6 +47,12 @@
noInputLatency();
noTimeStretch();
+ // TODO: Proper support for reorder depth.
+ addParameter(
+ DefineParam(mActualOutputDelay, C2_PARAMKEY_OUTPUT_DELAY)
+ .withConstValue(new C2PortActualDelayTuning::output(3u))
+ .build());
+
// TODO: output latency and reordering
addParameter(
@@ -93,7 +99,7 @@
addParameter(
DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
- .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, 320 * 240 * 3 / 2))
+ .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, kMinInputBufferSize))
.withFields({
C2F(mMaxInputSize, value).any(),
})
@@ -207,7 +213,8 @@
const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) {
(void)mayBlock;
// assume compression ratio of 1
- me.set().value = (((maxSize.v.width + 15) / 16) * ((maxSize.v.height + 15) / 16) * 384);
+ me.set().value = c2_max((((maxSize.v.width + 15) / 16)
+ * ((maxSize.v.height + 15) / 16) * 384), kMinInputBufferSize);
return C2R::Ok();
}
diff --git a/media/codec2/components/mpeg4_h263/C2SoftMpeg4Dec.cpp b/media/codec2/components/mpeg4_h263/C2SoftMpeg4Dec.cpp
index 7e6685e..61b286c 100644
--- a/media/codec2/components/mpeg4_h263/C2SoftMpeg4Dec.cpp
+++ b/media/codec2/components/mpeg4_h263/C2SoftMpeg4Dec.cpp
@@ -33,7 +33,7 @@
#include "mp4dec_api.h"
namespace android {
-
+constexpr size_t kMinInputBufferSize = 2 * 1024 * 1024;
#ifdef MPEG4
constexpr char COMPONENT_NAME[] = "c2.android.mpeg4.decoder";
#else
@@ -149,11 +149,7 @@
addParameter(
DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
-#ifdef MPEG4
- .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, 1920 * 1088 * 3 / 2))
-#else
- .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, 352 * 288 * 3 / 2))
-#endif
+ .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, kMinInputBufferSize))
.withFields({
C2F(mMaxInputSize, value).any(),
})
@@ -218,7 +214,8 @@
const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) {
(void)mayBlock;
// assume compression ratio of 1
- me.set().value = (((maxSize.v.width + 15) / 16) * ((maxSize.v.height + 15) / 16) * 384);
+ me.set().value = c2_max((((maxSize.v.width + 15) / 16)
+ * ((maxSize.v.height + 15) / 16) * 384), kMinInputBufferSize);
return C2R::Ok();
}
diff --git a/media/codec2/components/opus/C2SoftOpusDec.cpp b/media/codec2/components/opus/C2SoftOpusDec.cpp
index 6b6974f..b7c1556 100644
--- a/media/codec2/components/opus/C2SoftOpusDec.cpp
+++ b/media/codec2/components/opus/C2SoftOpusDec.cpp
@@ -62,7 +62,7 @@
addParameter(
DefineParam(mSampleRate, C2_PARAMKEY_SAMPLE_RATE)
.withDefault(new C2StreamSampleRateInfo::output(0u, 48000))
- .withFields({C2F(mSampleRate, value).equalTo(48000)})
+ .withFields({C2F(mSampleRate, value).inRange(8000, 48000)})
.withSetter((Setter<decltype(*mSampleRate)>::StrictValueWithNoDeps))
.build());
diff --git a/media/codec2/components/vorbis/Android.bp b/media/codec2/components/vorbis/Android.bp
index a5f485d..bc1c380 100644
--- a/media/codec2/components/vorbis/Android.bp
+++ b/media/codec2/components/vorbis/Android.bp
@@ -7,5 +7,5 @@
srcs: ["C2SoftVorbisDec.cpp"],
- shared_libs: ["libvorbisidec"],
+ static_libs: ["libvorbisidec"],
}
diff --git a/media/codec2/components/vorbis/C2SoftVorbisDec.cpp b/media/codec2/components/vorbis/C2SoftVorbisDec.cpp
index 18e6db2..15564d9 100644
--- a/media/codec2/components/vorbis/C2SoftVorbisDec.cpp
+++ b/media/codec2/components/vorbis/C2SoftVorbisDec.cpp
@@ -66,7 +66,7 @@
addParameter(
DefineParam(mSampleRate, C2_PARAMKEY_SAMPLE_RATE)
.withDefault(new C2StreamSampleRateInfo::output(0u, 48000))
- .withFields({C2F(mSampleRate, value).inRange(8000, 96000)})
+ .withFields({C2F(mSampleRate, value).inRange(8000, 192000)})
.withSetter((Setter<decltype(*mSampleRate)>::StrictValueWithNoDeps))
.build());
diff --git a/media/codec2/components/vpx/C2SoftVpxDec.cpp b/media/codec2/components/vpx/C2SoftVpxDec.cpp
index a759e8f..c7d73f4 100644
--- a/media/codec2/components/vpx/C2SoftVpxDec.cpp
+++ b/media/codec2/components/vpx/C2SoftVpxDec.cpp
@@ -30,7 +30,7 @@
#include "C2SoftVpxDec.h"
namespace android {
-
+constexpr size_t kMinInputBufferSize = 2 * 1024 * 1024;
#ifdef VP9
constexpr char COMPONENT_NAME[] = "c2.android.vp9.decoder";
#else
@@ -166,7 +166,7 @@
addParameter(
DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
- .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, 320 * 240 * 3 / 4))
+ .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, kMinInputBufferSize))
.withFields({
C2F(mMaxInputSize, value).any(),
})
@@ -244,7 +244,8 @@
const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) {
(void)mayBlock;
// assume compression ratio of 2
- me.set().value = (((maxSize.v.width + 63) / 64) * ((maxSize.v.height + 63) / 64) * 3072);
+ me.set().value = c2_max((((maxSize.v.width + 63) / 64)
+ * ((maxSize.v.height + 63) / 64) * 3072), kMinInputBufferSize);
return C2R::Ok();
}
diff --git a/media/codec2/components/vpx/C2SoftVpxEnc.cpp b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
index 6dab70b..ebc7a8f 100644
--- a/media/codec2/components/vpx/C2SoftVpxEnc.cpp
+++ b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
@@ -514,7 +514,7 @@
return;
}
vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, stride, vstride,
- mStrideAlign, (uint8_t*)rView->data()[0]);
+ mStrideAlign, mConversionBuffer.data());
vpx_img_set_rect(&raw_frame, 0, 0, width, height);
} else {
ALOGE("Conversion buffer is too small: %u x %u for %zu",
diff --git a/media/codec2/components/xaac/C2SoftXaacDec.cpp b/media/codec2/components/xaac/C2SoftXaacDec.cpp
index a3ebadb..951d058 100644
--- a/media/codec2/components/xaac/C2SoftXaacDec.cpp
+++ b/media/codec2/components/xaac/C2SoftXaacDec.cpp
@@ -87,7 +87,8 @@
DefineParam(mSampleRate, C2_PARAMKEY_SAMPLE_RATE)
.withDefault(new C2StreamSampleRateInfo::output(0u, 44100))
.withFields({C2F(mSampleRate, value).oneOf({
- 7350, 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+ 7350, 8000, 11025, 12000, 16000, 22050, 24000, 32000,
+ 44100, 48000, 64000, 88200, 96000
})})
.withSetter((Setter<decltype(*mSampleRate)>::StrictValueWithNoDeps))
.build());
@@ -1309,69 +1310,84 @@
&ui_exec_done);
RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_DONE_QUERY");
- if (ui_exec_done != 1) {
- VOID* p_array; // ITTIAM:buffer to handle gain payload
- WORD32 buf_size = 0; // ITTIAM:gain payload length
- WORD32 bit_str_fmt = 1;
- WORD32 gain_stream_flag = 1;
-
- err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM,
- IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_LEN, &buf_size);
- RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_LEN");
-
- err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM,
- IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_BUF, &p_array);
- RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_BUF");
-
- if (buf_size > 0) {
- /*Set bitstream_split_format */
- err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM,
- IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT, &bit_str_fmt);
- RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
-
- memcpy(mDrcInBuf, p_array, buf_size);
- /* Set number of bytes to be processed */
- err_code =
- ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_INPUT_BYTES_BS, 0, &buf_size);
- RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
-
- err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM,
- IA_DRC_DEC_CONFIG_GAIN_STREAM_FLAG, &gain_stream_flag);
- RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
-
- /* Execute process */
- err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT,
- IA_CMD_TYPE_INIT_CPY_BSF_BUFF, nullptr);
- RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
-
- mMpegDDRCPresent = 1;
- }
- }
-
- /* How much buffer is used in input buffers */
+ int32_t num_preroll = 0;
err_code = ixheaacd_dec_api(mXheaacCodecHandle,
- IA_API_CMD_GET_CURIDX_INPUT_BUF,
- 0,
- bytesConsumed);
- RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_CURIDX_INPUT_BUF");
+ IA_API_CMD_GET_CONFIG_PARAM,
+ IA_ENHAACPLUS_DEC_CONFIG_GET_NUM_PRE_ROLL_FRAMES,
+ &num_preroll);
+ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_GET_NUM_PRE_ROLL_FRAMES");
- /* Get the output bytes */
- err_code = ixheaacd_dec_api(mXheaacCodecHandle,
- IA_API_CMD_GET_OUTPUT_BYTES,
- 0,
- outBytes);
- RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_OUTPUT_BYTES");
+ {
+ int32_t preroll_frame_offset = 0;
- if (mMpegDDRCPresent == 1) {
- memcpy(mDrcInBuf, mOutputBuffer, *outBytes);
- err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_INPUT_BYTES, 0, outBytes);
- RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_INPUT_BYTES");
+ do {
+ if (ui_exec_done != 1) {
+ VOID* p_array; // ITTIAM:buffer to handle gain payload
+ WORD32 buf_size = 0; // ITTIAM:gain payload length
+ WORD32 bit_str_fmt = 1;
+ WORD32 gain_stream_flag = 1;
- err_code =
- ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_EXECUTE, IA_CMD_TYPE_DO_EXECUTE, nullptr);
- RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_DO_EXECUTE");
+ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM,
+ IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_LEN, &buf_size);
+ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_LEN");
- memcpy(mOutputBuffer, mDrcOutBuf, *outBytes);
+ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM,
+ IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_BUF, &p_array);
+ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_BUF");
+
+ if (buf_size > 0) {
+ /*Set bitstream_split_format */
+ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM,
+ IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT, &bit_str_fmt);
+ RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
+
+ memcpy(mDrcInBuf, p_array, buf_size);
+ /* Set number of bytes to be processed */
+ err_code =
+ ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_INPUT_BYTES_BS, 0, &buf_size);
+ RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
+
+ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM,
+ IA_DRC_DEC_CONFIG_GAIN_STREAM_FLAG, &gain_stream_flag);
+ RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
+
+ /* Execute process */
+ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT,
+ IA_CMD_TYPE_INIT_CPY_BSF_BUFF, nullptr);
+ RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
+
+ mMpegDDRCPresent = 1;
+ }
+ }
+
+ /* How much buffer is used in input buffers */
+ err_code = ixheaacd_dec_api(mXheaacCodecHandle,
+ IA_API_CMD_GET_CURIDX_INPUT_BUF,
+ 0,
+ bytesConsumed);
+ RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_CURIDX_INPUT_BUF");
+
+ /* Get the output bytes */
+ err_code = ixheaacd_dec_api(mXheaacCodecHandle,
+ IA_API_CMD_GET_OUTPUT_BYTES,
+ 0,
+ outBytes);
+ RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_OUTPUT_BYTES");
+
+ if (mMpegDDRCPresent == 1) {
+ memcpy(mDrcInBuf, mOutputBuffer + preroll_frame_offset, *outBytes);
+ preroll_frame_offset += *outBytes;
+ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_INPUT_BYTES, 0, outBytes);
+ RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_INPUT_BYTES");
+
+ err_code =
+ ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_EXECUTE, IA_CMD_TYPE_DO_EXECUTE, nullptr);
+ RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_DO_EXECUTE");
+
+ memcpy(mOutputBuffer, mDrcOutBuf, *outBytes);
+ }
+ num_preroll--;
+ } while (num_preroll > 0);
}
return IA_NO_ERROR;
}
diff --git a/media/codec2/core/Android.bp b/media/codec2/core/Android.bp
index a7e8997..1f9d7ab 100644
--- a/media/codec2/core/Android.bp
+++ b/media/codec2/core/Android.bp
@@ -10,6 +10,7 @@
vndk: {
enabled: true,
},
+ double_loadable: true,
srcs: ["C2.cpp"],
diff --git a/media/codec2/core/OWNERS b/media/codec2/core/OWNERS
new file mode 100644
index 0000000..31ecca5
--- /dev/null
+++ b/media/codec2/core/OWNERS
@@ -0,0 +1,2 @@
+set noparent
+lajos@google.com
diff --git a/media/codec2/core/include/C2Config.h b/media/codec2/core/include/C2Config.h
index 3820f90..9fc0e17 100644
--- a/media/codec2/core/include/C2Config.h
+++ b/media/codec2/core/include/C2Config.h
@@ -58,6 +58,7 @@
enum bitrate_mode_t : uint32_t; ///< bitrate control mode
enum drc_compression_mode_t : int32_t; ///< DRC compression mode
enum drc_effect_type_t : int32_t; ///< DRC effect type
+ enum drc_album_mode_t : int32_t; ///< DRC album mode
enum intra_refresh_mode_t : uint32_t; ///< intra refresh modes
enum level_t : uint32_t; ///< coding level
enum ordinal_key_t : uint32_t; ///< work ordering keys
@@ -218,6 +219,8 @@
kParamIndexDrcBoostFactor, // drc, float (0-1)
kParamIndexDrcAttenuationFactor, // drc, float (0-1)
kParamIndexDrcEffectType, // drc, enum
+ kParamIndexDrcOutputLoudness, // drc, float (dBFS)
+ kParamIndexDrcAlbumMode, // drc, enum
/* ============================== platform-defined parameters ============================== */
@@ -243,6 +246,9 @@
kParamIndexTimestampGapAdjustment, // input-surface, struct
kParamIndexSurfaceAllocator, // u32
+
+ // low latency mode
+ kParamIndexLowLatencyMode, // bool
};
}
@@ -521,6 +527,7 @@
PROFILE_DV_HE_07 = _C2_PL_DV_BASE + 7, ///< Dolby Vision dvhe.07 profile
PROFILE_DV_HE_08 = _C2_PL_DV_BASE + 8, ///< Dolby Vision dvhe.08 profile
PROFILE_DV_AV_09 = _C2_PL_DV_BASE + 9, ///< Dolby Vision dvav.09 profile
+ PROFILE_DV_AV1_10 = _C2_PL_DV_BASE + 10, ///< Dolby Vision dav1.10 profile
// AV1 profiles
PROFILE_AV1_0 = _C2_PL_AV1_BASE, ///< AV1 Profile 0 (4:2:0, 8 to 10 bit)
@@ -804,6 +811,16 @@
constexpr char C2_PARAMKEY_PIPELINE_DELAY[] = "algo.delay";
/**
+ * Enable/disable low latency mode.
+ * If true, low latency is preferred over low power. Disable power optimizations that
+ * may result in increased latency. For decoders, this means that the decoder does not
+ * hold input and output data more than required by the codec standards.
+ */
+typedef C2GlobalParam<C2Tuning, C2EasyBoolValue, kParamIndexLowLatencyMode>
+ C2GlobalLowLatencyModeTuning;
+constexpr char C2_PARAMKEY_LOW_LATENCY_MODE[] = "algo.low-latency";
+
+/**
* Reference characteristics.
*
* The component may hold onto input and output buffers even after completing the corresponding
@@ -1928,6 +1945,24 @@
C2StreamDrcEffectTypeTuning;
constexpr char C2_PARAMKEY_DRC_EFFECT_TYPE[] = "coding.drc.effect-type";
+/**
+ * DRC album mode. Used during decoding.
+ */
+C2ENUM(C2Config::drc_album_mode_t, int32_t,
+ DRC_ALBUM_MODE_OFF = 0,
+ DRC_ALBUM_MODE_ON = 1
+)
+typedef C2StreamParam<C2Info, C2SimpleValueStruct<C2Config::drc_album_mode_t>, kParamIndexDrcAlbumMode>
+ C2StreamDrcAlbumModeTuning;
+constexpr char C2_PARAMKEY_DRC_ALBUM_MODE[] = "coding.drc.album-mode";
+
+/**
+ * DRC output loudness in dBFS. Retrieved during decoding
+ */
+ typedef C2StreamParam<C2Info, C2FloatValue, kParamIndexDrcOutputLoudness>
+ C2StreamDrcOutputLoudnessTuning;
+ constexpr char C2_PARAMKEY_DRC_OUTPUT_LOUDNESS[] = "output.drc.output-loudness";
+
/* --------------------------------------- AAC components --------------------------------------- */
/**
diff --git a/media/codec2/hidl/1.0/utils/Android.bp b/media/codec2/hidl/1.0/utils/Android.bp
index f1f1536..75c9424 100644
--- a/media/codec2/hidl/1.0/utils/Android.bp
+++ b/media/codec2/hidl/1.0/utils/Android.bp
@@ -6,7 +6,7 @@
defaults: ["hidl_defaults"],
srcs: [
- "ClientBlockHelper.cpp",
+ "OutputBufferQueue.cpp",
"types.cpp",
],
@@ -63,6 +63,7 @@
],
header_libs: [
+ "libbinder_headers",
"libsystem_headers",
"libcodec2_internal", // private
],
@@ -80,15 +81,24 @@
"libcodec2_vndk",
"libcutils",
"libhidlbase",
- "libhidltransport",
- "libhwbinder",
"liblog",
"libstagefright_bufferpool@2.0.1",
- "libstagefright_bufferqueue_helper",
+ "libstagefright_bufferqueue_helper_novndk",
"libui",
"libutils",
],
+ target: {
+ vendor: {
+ exclude_shared_libs: [
+ "libstagefright_bufferqueue_helper_novndk",
+ ],
+ shared_libs: [
+ "libstagefright_bufferqueue_helper",
+ ],
+ },
+ },
+
export_include_dirs: [
"include",
],
@@ -105,7 +115,7 @@
// public dependency for Codec 2.0 HAL service implementations
cc_defaults {
- name: "libcodec2-hidl-defaults",
+ name: "libcodec2-hidl-defaults@1.0",
defaults: ["libcodec2-impl-defaults"],
shared_libs: [
@@ -116,7 +126,7 @@
// public dependency for Codec 2.0 HAL client
cc_defaults {
- name: "libcodec2-hidl-client-defaults",
+ name: "libcodec2-hidl-client-defaults@1.0",
defaults: ["libcodec2-impl-defaults"],
shared_libs: [
diff --git a/media/codec2/hidl/1.0/utils/ClientBlockHelper.cpp b/media/codec2/hidl/1.0/utils/ClientBlockHelper.cpp
deleted file mode 100644
index 50790bc..0000000
--- a/media/codec2/hidl/1.0/utils/ClientBlockHelper.cpp
+++ /dev/null
@@ -1,371 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "Codec2-block_helper"
-#include <android-base/logging.h>
-
-#include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
-#include <codec2/hidl/1.0/ClientBlockHelper.h>
-#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
-
-#include <C2AllocatorGralloc.h>
-#include <C2BlockInternal.h>
-#include <C2Buffer.h>
-#include <C2PlatformSupport.h>
-
-#include <iomanip>
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace c2 {
-namespace V1_0 {
-namespace utils {
-
-using HGraphicBufferProducer = ::android::hardware::graphics::bufferqueue::
- V2_0::IGraphicBufferProducer;
-using B2HGraphicBufferProducer = ::android::hardware::graphics::bufferqueue::
- V2_0::utils::B2HGraphicBufferProducer;
-
-namespace /* unnamed */ {
-
-// Create a GraphicBuffer object from a graphic block.
-sp<GraphicBuffer> createGraphicBuffer(const C2ConstGraphicBlock& block) {
- uint32_t width;
- uint32_t height;
- uint32_t format;
- uint64_t usage;
- uint32_t stride;
- uint32_t generation;
- uint64_t bqId;
- int32_t bqSlot;
- _UnwrapNativeCodec2GrallocMetadata(
- block.handle(), &width, &height, &format, &usage,
- &stride, &generation, &bqId, reinterpret_cast<uint32_t*>(&bqSlot));
- native_handle_t *grallocHandle =
- UnwrapNativeCodec2GrallocHandle(block.handle());
- sp<GraphicBuffer> graphicBuffer =
- new GraphicBuffer(grallocHandle,
- GraphicBuffer::CLONE_HANDLE,
- width, height, format,
- 1, usage, stride);
- native_handle_delete(grallocHandle);
- return graphicBuffer;
-}
-
-template <typename BlockProcessor>
-void forEachBlock(C2FrameData& frameData,
- BlockProcessor process) {
- for (const std::shared_ptr<C2Buffer>& buffer : frameData.buffers) {
- if (buffer) {
- for (const C2ConstGraphicBlock& block :
- buffer->data().graphicBlocks()) {
- process(block);
- }
- }
- }
-}
-
-template <typename BlockProcessor>
-void forEachBlock(const std::list<std::unique_ptr<C2Work>>& workList,
- BlockProcessor process) {
- for (const std::unique_ptr<C2Work>& work : workList) {
- if (!work) {
- continue;
- }
- for (const std::unique_ptr<C2Worklet>& worklet : work->worklets) {
- if (worklet) {
- forEachBlock(worklet->output, process);
- }
- }
- }
-}
-
-sp<HGraphicBufferProducer> getHgbp(const sp<IGraphicBufferProducer>& igbp) {
- sp<HGraphicBufferProducer> hgbp =
- igbp->getHalInterface<HGraphicBufferProducer>();
- return hgbp ? hgbp :
- new B2HGraphicBufferProducer(igbp);
-}
-
-status_t attachToBufferQueue(const C2ConstGraphicBlock& block,
- const sp<IGraphicBufferProducer>& igbp,
- uint32_t generation,
- int32_t* bqSlot) {
- if (!igbp) {
- LOG(WARNING) << "attachToBufferQueue -- null producer.";
- return NO_INIT;
- }
-
- sp<GraphicBuffer> graphicBuffer = createGraphicBuffer(block);
- graphicBuffer->setGenerationNumber(generation);
-
- LOG(VERBOSE) << "attachToBufferQueue -- attaching buffer:"
- << " block dimension " << block.width() << "x"
- << block.height()
- << ", graphicBuffer dimension " << graphicBuffer->getWidth() << "x"
- << graphicBuffer->getHeight()
- << std::hex << std::setfill('0')
- << ", format 0x" << std::setw(8) << graphicBuffer->getPixelFormat()
- << ", usage 0x" << std::setw(16) << graphicBuffer->getUsage()
- << std::dec << std::setfill(' ')
- << ", stride " << graphicBuffer->getStride()
- << ", generation " << graphicBuffer->getGenerationNumber();
-
- status_t result = igbp->attachBuffer(bqSlot, graphicBuffer);
- if (result != OK) {
- LOG(WARNING) << "attachToBufferQueue -- attachBuffer failed: "
- "status = " << result << ".";
- return result;
- }
- LOG(VERBOSE) << "attachToBufferQueue -- attachBuffer returned slot #"
- << *bqSlot << ".";
- return OK;
-}
-
-bool getBufferQueueAssignment(const C2ConstGraphicBlock& block,
- uint32_t* generation,
- uint64_t* bqId,
- int32_t* bqSlot) {
- return _C2BlockFactory::GetBufferQueueData(
- _C2BlockFactory::GetGraphicBlockPoolData(block),
- generation, bqId, bqSlot);
-}
-} // unnamed namespace
-
-class OutputBufferQueue::Impl {
- std::mutex mMutex;
- sp<IGraphicBufferProducer> mIgbp;
- uint32_t mGeneration;
- uint64_t mBqId;
- std::shared_ptr<int> mOwner;
- // To migrate existing buffers
- sp<GraphicBuffer> mBuffers[BufferQueueDefs::NUM_BUFFER_SLOTS]; // find a better way
- std::weak_ptr<_C2BlockPoolData>
- mPoolDatas[BufferQueueDefs::NUM_BUFFER_SLOTS];
-
-public:
- Impl(): mGeneration(0), mBqId(0) {}
-
- bool configure(const sp<IGraphicBufferProducer>& igbp,
- uint32_t generation,
- uint64_t bqId) {
- size_t tryNum = 0;
- size_t success = 0;
- sp<GraphicBuffer> buffers[BufferQueueDefs::NUM_BUFFER_SLOTS];
- std::weak_ptr<_C2BlockPoolData>
- poolDatas[BufferQueueDefs::NUM_BUFFER_SLOTS];
- {
- std::scoped_lock<std::mutex> l(mMutex);
- if (generation == mGeneration) {
- return false;
- }
- mIgbp = igbp;
- mGeneration = generation;
- mBqId = bqId;
- mOwner = std::make_shared<int>(0);
- for (int i = 0; i < BufferQueueDefs::NUM_BUFFER_SLOTS; ++i) {
- if (mBqId == 0 || !mBuffers[i]) {
- continue;
- }
- std::shared_ptr<_C2BlockPoolData> data = mPoolDatas[i].lock();
- if (!data ||
- !_C2BlockFactory::BeginAttachBlockToBufferQueue(data)) {
- continue;
- }
- ++tryNum;
- int bqSlot;
- mBuffers[i]->setGenerationNumber(generation);
- status_t result = igbp->attachBuffer(&bqSlot, mBuffers[i]);
- if (result != OK) {
- continue;
- }
- bool attach =
- _C2BlockFactory::EndAttachBlockToBufferQueue(
- data, mOwner, getHgbp(mIgbp),
- generation, bqId, bqSlot);
- if (!attach) {
- igbp->cancelBuffer(bqSlot, Fence::NO_FENCE);
- continue;
- }
- buffers[bqSlot] = mBuffers[i];
- poolDatas[bqSlot] = data;
- ++success;
- }
- for (int i = 0; i < BufferQueueDefs::NUM_BUFFER_SLOTS; ++i) {
- mBuffers[i] = buffers[i];
- mPoolDatas[i] = poolDatas[i];
- }
- }
- ALOGD("remote graphic buffer migration %zu/%zu", success, tryNum);
- return true;
- }
-
- bool registerBuffer(const C2ConstGraphicBlock& block) {
- std::shared_ptr<_C2BlockPoolData> data =
- _C2BlockFactory::GetGraphicBlockPoolData(block);
- if (!data) {
- return false;
- }
- std::scoped_lock<std::mutex> l(mMutex);
-
- if (!mIgbp) {
- return false;
- }
-
- uint32_t oldGeneration;
- uint64_t oldId;
- int32_t oldSlot;
- // If the block is not bufferqueue-based, do nothing.
- if (!_C2BlockFactory::GetBufferQueueData(
- data, &oldGeneration, &oldId, &oldSlot) || (oldId == 0)) {
- return false;
- }
- // If the block's bqId is the same as the desired bqId, just hold.
- if ((oldId == mBqId) && (oldGeneration == mGeneration)) {
- LOG(VERBOSE) << "holdBufferQueueBlock -- import without attaching:"
- << " bqId " << oldId
- << ", bqSlot " << oldSlot
- << ", generation " << mGeneration
- << ".";
- _C2BlockFactory::HoldBlockFromBufferQueue(data, mOwner, getHgbp(mIgbp));
- mPoolDatas[oldSlot] = data;
- mBuffers[oldSlot] = createGraphicBuffer(block);
- mBuffers[oldSlot]->setGenerationNumber(mGeneration);
- return true;
- }
- int32_t d = (int32_t) mGeneration - (int32_t) oldGeneration;
- LOG(WARNING) << "receiving stale buffer: generation "
- << mGeneration << " , diff " << d << " : slot "
- << oldSlot;
- return false;
- }
-
- status_t outputBuffer(
- const C2ConstGraphicBlock& block,
- const BnGraphicBufferProducer::QueueBufferInput& input,
- BnGraphicBufferProducer::QueueBufferOutput* output) {
- uint32_t generation;
- uint64_t bqId;
- int32_t bqSlot;
- bool display = displayBufferQueueBlock(block);
- if (!getBufferQueueAssignment(block, &generation, &bqId, &bqSlot) ||
- bqId == 0) {
- // Block not from bufferqueue -- it must be attached before queuing.
-
- mMutex.lock();
- sp<IGraphicBufferProducer> outputIgbp = mIgbp;
- uint32_t outputGeneration = mGeneration;
- mMutex.unlock();
-
- status_t status = attachToBufferQueue(
- block, outputIgbp, outputGeneration, &bqSlot);
- if (status != OK) {
- LOG(WARNING) << "outputBuffer -- attaching failed.";
- return INVALID_OPERATION;
- }
-
- status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
- input, output);
- if (status != OK) {
- LOG(ERROR) << "outputBuffer -- queueBuffer() failed "
- "on non-bufferqueue-based block. "
- "Error = " << status << ".";
- return status;
- }
- return OK;
- }
-
- mMutex.lock();
- sp<IGraphicBufferProducer> outputIgbp = mIgbp;
- uint32_t outputGeneration = mGeneration;
- uint64_t outputBqId = mBqId;
- mMutex.unlock();
-
- if (!outputIgbp) {
- LOG(VERBOSE) << "outputBuffer -- output surface is null.";
- return NO_INIT;
- }
-
- if (!display) {
- LOG(WARNING) << "outputBuffer -- cannot display "
- "bufferqueue-based block to the bufferqueue.";
- return UNKNOWN_ERROR;
- }
- if (bqId != outputBqId || generation != outputGeneration) {
- int32_t diff = (int32_t) outputGeneration - (int32_t) generation;
- LOG(WARNING) << "outputBuffer -- buffers from old generation to "
- << outputGeneration << " , diff: " << diff
- << " , slot: " << bqSlot;
- return DEAD_OBJECT;
- }
-
- status_t status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
- input, output);
- if (status != OK) {
- LOG(ERROR) << "outputBuffer -- queueBuffer() failed "
- "on bufferqueue-based block. "
- "Error = " << status << ".";
- return status;
- }
- return OK;
- }
-
- Impl *getPtr() {
- return this;
- }
-
- ~Impl() {}
-};
-
-OutputBufferQueue::OutputBufferQueue(): mImpl(new Impl()) {}
-
-OutputBufferQueue::~OutputBufferQueue() {}
-
-bool OutputBufferQueue::configure(const sp<IGraphicBufferProducer>& igbp,
- uint32_t generation,
- uint64_t bqId) {
- return mImpl && mImpl->configure(igbp, generation, bqId);
-}
-
-status_t OutputBufferQueue::outputBuffer(
- const C2ConstGraphicBlock& block,
- const BnGraphicBufferProducer::QueueBufferInput& input,
- BnGraphicBufferProducer::QueueBufferOutput* output) {
- if (mImpl) {
- return mImpl->outputBuffer(block, input, output);
- }
- return DEAD_OBJECT;
-}
-
-void OutputBufferQueue::holdBufferQueueBlocks(
- const std::list<std::unique_ptr<C2Work>>& workList) {
- if (!mImpl) {
- return;
- }
- forEachBlock(workList,
- std::bind(&OutputBufferQueue::Impl::registerBuffer,
- mImpl->getPtr(), std::placeholders::_1));
-}
-
-} // namespace utils
-} // namespace V1_0
-} // namespace c2
-} // namespace media
-} // namespace hardware
-} // namespace android
-
diff --git a/media/codec2/hidl/1.0/utils/Component.cpp b/media/codec2/hidl/1.0/utils/Component.cpp
index a9f20a4..8a84601 100644
--- a/media/codec2/hidl/1.0/utils/Component.cpp
+++ b/media/codec2/hidl/1.0/utils/Component.cpp
@@ -204,7 +204,8 @@
const sp<::android::hardware::media::bufferpool::V2_0::
IClientManager>& clientPoolManager)
: mComponent{component},
- mInterface{new ComponentInterface(component->intf(), store.get())},
+ mInterface{new ComponentInterface(component->intf(),
+ store->getParameterCache())},
mListener{listener},
mStore{store},
mBufferPoolSender{clientPoolManager} {
diff --git a/media/codec2/hidl/1.0/utils/ComponentInterface.cpp b/media/codec2/hidl/1.0/utils/ComponentInterface.cpp
index 39e5357..12078e0 100644
--- a/media/codec2/hidl/1.0/utils/ComponentInterface.cpp
+++ b/media/codec2/hidl/1.0/utils/ComponentInterface.cpp
@@ -87,10 +87,10 @@
// ComponentInterface
ComponentInterface::ComponentInterface(
const std::shared_ptr<C2ComponentInterface>& intf,
- ComponentStore* store)
+ const std::shared_ptr<ParameterCache>& cache)
: mInterface{intf},
mConfigurable{new CachedConfigurable(std::make_unique<CompIntf>(intf))} {
- mInit = mConfigurable->init(store);
+ mInit = mConfigurable->init(cache);
}
c2_status_t ComponentInterface::status() const {
diff --git a/media/codec2/hidl/1.0/utils/ComponentStore.cpp b/media/codec2/hidl/1.0/utils/ComponentStore.cpp
index 1e0a190..9b9d4498 100644
--- a/media/codec2/hidl/1.0/utils/ComponentStore.cpp
+++ b/media/codec2/hidl/1.0/utils/ComponentStore.cpp
@@ -102,8 +102,29 @@
} // unnamed namespace
+struct ComponentStore::StoreParameterCache : public ParameterCache {
+ std::mutex mStoreMutex;
+ ComponentStore* mStore;
+
+ StoreParameterCache(ComponentStore* store): mStore{store} {
+ }
+
+ virtual c2_status_t validate(
+ const std::vector<std::shared_ptr<C2ParamDescriptor>>& params
+ ) override {
+ std::scoped_lock _lock(mStoreMutex);
+ return mStore ? mStore->validateSupportedParams(params) : C2_NO_INIT;
+ }
+
+ void onStoreDestroyed() {
+ std::scoped_lock _lock(mStoreMutex);
+ mStore = nullptr;
+ }
+};
+
ComponentStore::ComponentStore(const std::shared_ptr<C2ComponentStore>& store)
: mConfigurable{new CachedConfigurable(std::make_unique<StoreIntf>(store))},
+ mParameterCache{std::make_shared<StoreParameterCache>(this)},
mStore{store} {
std::shared_ptr<C2ComponentStore> platformStore = android::GetCodec2PlatformComponentStore();
@@ -113,7 +134,12 @@
mParamReflector = mStore->getParamReflector();
// Retrieve supported parameters from store
- mInit = mConfigurable->init(this);
+ using namespace std::placeholders;
+ mInit = mConfigurable->init(mParameterCache);
+}
+
+ComponentStore::~ComponentStore() {
+ mParameterCache->onStoreDestroyed();
}
c2_status_t ComponentStore::status() const {
@@ -146,6 +172,10 @@
return res;
}
+std::shared_ptr<ParameterCache> ComponentStore::getParameterCache() const {
+ return mParameterCache;
+}
+
// Methods from ::android::hardware::media::c2::V1_0::IComponentStore
Return<void> ComponentStore::createComponent(
const hidl_string& name,
@@ -187,7 +217,7 @@
sp<IComponentInterface> interface;
if (res == C2_OK) {
onInterfaceLoaded(c2interface);
- interface = new ComponentInterface(c2interface, this);
+ interface = new ComponentInterface(c2interface, mParameterCache);
}
_hidl_cb(static_cast<Status>(res), interface);
return Void();
@@ -218,8 +248,9 @@
_hidl_cb(Status::CORRUPTED, nullptr);
return Void();
}
+ using namespace std::placeholders;
sp<InputSurface> inputSurface = new InputSurface(
- this,
+ mParameterCache,
std::make_shared<C2ReflectorHelper>(),
source->getHGraphicBufferProducer(),
source);
diff --git a/media/codec2/hidl/1.0/utils/Configurable.cpp b/media/codec2/hidl/1.0/utils/Configurable.cpp
index ec9c170..530576d 100644
--- a/media/codec2/hidl/1.0/utils/Configurable.cpp
+++ b/media/codec2/hidl/1.0/utils/Configurable.cpp
@@ -38,10 +38,11 @@
: mIntf{std::move(intf)} {
}
-c2_status_t CachedConfigurable::init(ComponentStore* store) {
+c2_status_t CachedConfigurable::init(
+ const std::shared_ptr<ParameterCache>& cache) {
// Retrieve supported parameters from store
c2_status_t init = mIntf->querySupportedParams(&mSupportedParams);
- c2_status_t validate = store->validateSupportedParams(mSupportedParams);
+ c2_status_t validate = cache->validate(mSupportedParams);
return init == C2_OK ? C2_OK : validate;
}
diff --git a/media/codec2/hidl/1.0/utils/InputSurface.cpp b/media/codec2/hidl/1.0/utils/InputSurface.cpp
index 2b4ca85..c3c32e9 100644
--- a/media/codec2/hidl/1.0/utils/InputSurface.cpp
+++ b/media/codec2/hidl/1.0/utils/InputSurface.cpp
@@ -137,9 +137,9 @@
}
std::shared_ptr<C2Component> comp = Component::findLocalComponent(sink);
if (comp) {
- connection = new InputSurfaceConnection(mSource, comp, mStore);
+ connection = new InputSurfaceConnection(mSource, comp, mParameterCache);
} else {
- connection = new InputSurfaceConnection(mSource, sink, mStore);
+ connection = new InputSurfaceConnection(mSource, sink, mParameterCache);
}
if (!connection->init()) {
connection = nullptr;
@@ -153,11 +153,11 @@
// Constructor is exclusive to ComponentStore.
InputSurface::InputSurface(
- const sp<ComponentStore>& store,
+ const std::shared_ptr<ParameterCache>& cache,
const std::shared_ptr<C2ReflectorHelper>& reflector,
const sp<HGraphicBufferProducer>& producer,
const sp<GraphicBufferSource>& source)
- : mStore{store},
+ : mParameterCache{cache},
mProducer{producer},
mSource{source},
mIntf{std::make_shared<Interface>(reflector)},
@@ -165,7 +165,7 @@
std::make_unique<ConfigurableIntf>(
mIntf, source))} {
- mConfigurable->init(store.get());
+ mConfigurable->init(mParameterCache);
}
} // namespace utils
diff --git a/media/codec2/hidl/1.0/utils/InputSurfaceConnection.cpp b/media/codec2/hidl/1.0/utils/InputSurfaceConnection.cpp
index c9932ef..5ec88ec 100644
--- a/media/codec2/hidl/1.0/utils/InputSurfaceConnection.cpp
+++ b/media/codec2/hidl/1.0/utils/InputSurfaceConnection.cpp
@@ -160,12 +160,12 @@
return false;
}
for (int32_t i = 0; i < kBufferCount; ++i) {
- if (!mSource->onInputBufferAdded(i).isOk()) {
+ if (mSource->onInputBufferAdded(i) != OK) {
LOG(WARNING) << "Impl::init: failed to populate GBS slots.";
return false;
}
}
- if (!mSource->start().isOk()) {
+ if (mSource->start() != OK) {
LOG(WARNING) << "Impl::init -- GBS failed to start.";
return false;
}
@@ -445,21 +445,21 @@
InputSurfaceConnection::InputSurfaceConnection(
const sp<GraphicBufferSource>& source,
const std::shared_ptr<C2Component>& comp,
- const sp<ComponentStore>& store)
+ const std::shared_ptr<ParameterCache>& cache)
: mImpl{new Impl(source, comp)},
mConfigurable{new CachedConfigurable(
std::make_unique<Impl::ConfigurableIntf>(mImpl))} {
- mConfigurable->init(store.get());
+ mConfigurable->init(cache);
}
InputSurfaceConnection::InputSurfaceConnection(
const sp<GraphicBufferSource>& source,
const sp<IInputSink>& sink,
- const sp<ComponentStore>& store)
+ const std::shared_ptr<ParameterCache>& cache)
: mImpl{new Impl(source, sink)},
mConfigurable{new CachedConfigurable(
std::make_unique<Impl::ConfigurableIntf>(mImpl))} {
- mConfigurable->init(store.get());
+ mConfigurable->init(cache);
}
Return<Status> InputSurfaceConnection::disconnect() {
diff --git a/media/codec2/hidl/1.0/utils/OutputBufferQueue.cpp b/media/codec2/hidl/1.0/utils/OutputBufferQueue.cpp
new file mode 100644
index 0000000..c4a72ef
--- /dev/null
+++ b/media/codec2/hidl/1.0/utils/OutputBufferQueue.cpp
@@ -0,0 +1,335 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Codec2-OutputBufferQueue"
+#include <android-base/logging.h>
+
+#include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
+#include <codec2/hidl/1.0/OutputBufferQueue.h>
+#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
+
+#include <C2AllocatorGralloc.h>
+#include <C2BlockInternal.h>
+#include <C2Buffer.h>
+#include <C2PlatformSupport.h>
+
+#include <iomanip>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using HGraphicBufferProducer = ::android::hardware::graphics::bufferqueue::
+ V2_0::IGraphicBufferProducer;
+using B2HGraphicBufferProducer = ::android::hardware::graphics::bufferqueue::
+ V2_0::utils::B2HGraphicBufferProducer;
+
+namespace /* unnamed */ {
+
+// Create a GraphicBuffer object from a graphic block.
+sp<GraphicBuffer> createGraphicBuffer(const C2ConstGraphicBlock& block) {
+ uint32_t width;
+ uint32_t height;
+ uint32_t format;
+ uint64_t usage;
+ uint32_t stride;
+ uint32_t generation;
+ uint64_t bqId;
+ int32_t bqSlot;
+ _UnwrapNativeCodec2GrallocMetadata(
+ block.handle(), &width, &height, &format, &usage,
+ &stride, &generation, &bqId, reinterpret_cast<uint32_t*>(&bqSlot));
+ native_handle_t *grallocHandle =
+ UnwrapNativeCodec2GrallocHandle(block.handle());
+ sp<GraphicBuffer> graphicBuffer =
+ new GraphicBuffer(grallocHandle,
+ GraphicBuffer::CLONE_HANDLE,
+ width, height, format,
+ 1, usage, stride);
+ native_handle_delete(grallocHandle);
+ return graphicBuffer;
+}
+
+template <typename BlockProcessor>
+void forEachBlock(C2FrameData& frameData,
+ BlockProcessor process) {
+ for (const std::shared_ptr<C2Buffer>& buffer : frameData.buffers) {
+ if (buffer) {
+ for (const C2ConstGraphicBlock& block :
+ buffer->data().graphicBlocks()) {
+ process(block);
+ }
+ }
+ }
+}
+
+template <typename BlockProcessor>
+void forEachBlock(const std::list<std::unique_ptr<C2Work>>& workList,
+ BlockProcessor process) {
+ for (const std::unique_ptr<C2Work>& work : workList) {
+ if (!work) {
+ continue;
+ }
+ for (const std::unique_ptr<C2Worklet>& worklet : work->worklets) {
+ if (worklet) {
+ forEachBlock(worklet->output, process);
+ }
+ }
+ }
+}
+
+sp<HGraphicBufferProducer> getHgbp(const sp<IGraphicBufferProducer>& igbp) {
+ sp<HGraphicBufferProducer> hgbp =
+ igbp->getHalInterface<HGraphicBufferProducer>();
+ return hgbp ? hgbp :
+ new B2HGraphicBufferProducer(igbp);
+}
+
+status_t attachToBufferQueue(const C2ConstGraphicBlock& block,
+ const sp<IGraphicBufferProducer>& igbp,
+ uint32_t generation,
+ int32_t* bqSlot) {
+ if (!igbp) {
+ LOG(WARNING) << "attachToBufferQueue -- null producer.";
+ return NO_INIT;
+ }
+
+ sp<GraphicBuffer> graphicBuffer = createGraphicBuffer(block);
+ graphicBuffer->setGenerationNumber(generation);
+
+ LOG(VERBOSE) << "attachToBufferQueue -- attaching buffer:"
+ << " block dimension " << block.width() << "x"
+ << block.height()
+ << ", graphicBuffer dimension " << graphicBuffer->getWidth() << "x"
+ << graphicBuffer->getHeight()
+ << std::hex << std::setfill('0')
+ << ", format 0x" << std::setw(8) << graphicBuffer->getPixelFormat()
+ << ", usage 0x" << std::setw(16) << graphicBuffer->getUsage()
+ << std::dec << std::setfill(' ')
+ << ", stride " << graphicBuffer->getStride()
+ << ", generation " << graphicBuffer->getGenerationNumber();
+
+ status_t result = igbp->attachBuffer(bqSlot, graphicBuffer);
+ if (result != OK) {
+ LOG(WARNING) << "attachToBufferQueue -- attachBuffer failed: "
+ "status = " << result << ".";
+ return result;
+ }
+ LOG(VERBOSE) << "attachToBufferQueue -- attachBuffer returned slot #"
+ << *bqSlot << ".";
+ return OK;
+}
+
+bool getBufferQueueAssignment(const C2ConstGraphicBlock& block,
+ uint32_t* generation,
+ uint64_t* bqId,
+ int32_t* bqSlot) {
+ return _C2BlockFactory::GetBufferQueueData(
+ _C2BlockFactory::GetGraphicBlockPoolData(block),
+ generation, bqId, bqSlot);
+}
+
+} // unnamed namespace
+
+OutputBufferQueue::OutputBufferQueue()
+ : mGeneration{0}, mBqId{0} {
+}
+
+OutputBufferQueue::~OutputBufferQueue() {
+}
+
+bool OutputBufferQueue::configure(const sp<IGraphicBufferProducer>& igbp,
+ uint32_t generation,
+ uint64_t bqId) {
+ size_t tryNum = 0;
+ size_t success = 0;
+ sp<GraphicBuffer> buffers[BufferQueueDefs::NUM_BUFFER_SLOTS];
+ std::weak_ptr<_C2BlockPoolData>
+ poolDatas[BufferQueueDefs::NUM_BUFFER_SLOTS];
+ {
+ std::scoped_lock<std::mutex> l(mMutex);
+ if (generation == mGeneration) {
+ return false;
+ }
+ mIgbp = igbp;
+ mGeneration = generation;
+ mBqId = bqId;
+ mOwner = std::make_shared<int>(0);
+ for (int i = 0; i < BufferQueueDefs::NUM_BUFFER_SLOTS; ++i) {
+ if (mBqId == 0 || !mBuffers[i]) {
+ continue;
+ }
+ std::shared_ptr<_C2BlockPoolData> data = mPoolDatas[i].lock();
+ if (!data ||
+ !_C2BlockFactory::BeginAttachBlockToBufferQueue(data)) {
+ continue;
+ }
+ ++tryNum;
+ int bqSlot;
+ mBuffers[i]->setGenerationNumber(generation);
+ status_t result = igbp->attachBuffer(&bqSlot, mBuffers[i]);
+ if (result != OK) {
+ continue;
+ }
+ bool attach =
+ _C2BlockFactory::EndAttachBlockToBufferQueue(
+ data, mOwner, getHgbp(mIgbp),
+ generation, bqId, bqSlot);
+ if (!attach) {
+ igbp->cancelBuffer(bqSlot, Fence::NO_FENCE);
+ continue;
+ }
+ buffers[bqSlot] = mBuffers[i];
+ poolDatas[bqSlot] = data;
+ ++success;
+ }
+ for (int i = 0; i < BufferQueueDefs::NUM_BUFFER_SLOTS; ++i) {
+ mBuffers[i] = buffers[i];
+ mPoolDatas[i] = poolDatas[i];
+ }
+ }
+ ALOGD("remote graphic buffer migration %zu/%zu", success, tryNum);
+ return true;
+}
+
+bool OutputBufferQueue::registerBuffer(const C2ConstGraphicBlock& block) {
+ std::shared_ptr<_C2BlockPoolData> data =
+ _C2BlockFactory::GetGraphicBlockPoolData(block);
+ if (!data) {
+ return false;
+ }
+ std::scoped_lock<std::mutex> l(mMutex);
+
+ if (!mIgbp) {
+ return false;
+ }
+
+ uint32_t oldGeneration;
+ uint64_t oldId;
+ int32_t oldSlot;
+ // If the block is not bufferqueue-based, do nothing.
+ if (!_C2BlockFactory::GetBufferQueueData(
+ data, &oldGeneration, &oldId, &oldSlot) || (oldId == 0)) {
+ return false;
+ }
+ // If the block's bqId is the same as the desired bqId, just hold.
+ if ((oldId == mBqId) && (oldGeneration == mGeneration)) {
+ LOG(VERBOSE) << "holdBufferQueueBlock -- import without attaching:"
+ << " bqId " << oldId
+ << ", bqSlot " << oldSlot
+ << ", generation " << mGeneration
+ << ".";
+ _C2BlockFactory::HoldBlockFromBufferQueue(data, mOwner, getHgbp(mIgbp));
+ mPoolDatas[oldSlot] = data;
+ mBuffers[oldSlot] = createGraphicBuffer(block);
+ mBuffers[oldSlot]->setGenerationNumber(mGeneration);
+ return true;
+ }
+ int32_t d = (int32_t) mGeneration - (int32_t) oldGeneration;
+ LOG(WARNING) << "receiving stale buffer: generation "
+ << mGeneration << " , diff " << d << " : slot "
+ << oldSlot;
+ return false;
+}
+
+status_t OutputBufferQueue::outputBuffer(
+ const C2ConstGraphicBlock& block,
+ const BnGraphicBufferProducer::QueueBufferInput& input,
+ BnGraphicBufferProducer::QueueBufferOutput* output) {
+ uint32_t generation;
+ uint64_t bqId;
+ int32_t bqSlot;
+ bool display = displayBufferQueueBlock(block);
+ if (!getBufferQueueAssignment(block, &generation, &bqId, &bqSlot) ||
+ bqId == 0) {
+ // Block not from bufferqueue -- it must be attached before queuing.
+
+ mMutex.lock();
+ sp<IGraphicBufferProducer> outputIgbp = mIgbp;
+ uint32_t outputGeneration = mGeneration;
+ mMutex.unlock();
+
+ status_t status = attachToBufferQueue(
+ block, outputIgbp, outputGeneration, &bqSlot);
+ if (status != OK) {
+ LOG(WARNING) << "outputBuffer -- attaching failed.";
+ return INVALID_OPERATION;
+ }
+
+ status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
+ input, output);
+ if (status != OK) {
+ LOG(ERROR) << "outputBuffer -- queueBuffer() failed "
+ "on non-bufferqueue-based block. "
+ "Error = " << status << ".";
+ return status;
+ }
+ return OK;
+ }
+
+ mMutex.lock();
+ sp<IGraphicBufferProducer> outputIgbp = mIgbp;
+ uint32_t outputGeneration = mGeneration;
+ uint64_t outputBqId = mBqId;
+ mMutex.unlock();
+
+ if (!outputIgbp) {
+ LOG(VERBOSE) << "outputBuffer -- output surface is null.";
+ return NO_INIT;
+ }
+
+ if (!display) {
+ LOG(WARNING) << "outputBuffer -- cannot display "
+ "bufferqueue-based block to the bufferqueue.";
+ return UNKNOWN_ERROR;
+ }
+ if (bqId != outputBqId || generation != outputGeneration) {
+ int32_t diff = (int32_t) outputGeneration - (int32_t) generation;
+ LOG(WARNING) << "outputBuffer -- buffers from old generation to "
+ << outputGeneration << " , diff: " << diff
+ << " , slot: " << bqSlot;
+ return DEAD_OBJECT;
+ }
+
+ status_t status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
+ input, output);
+ if (status != OK) {
+ LOG(ERROR) << "outputBuffer -- queueBuffer() failed "
+ "on bufferqueue-based block. "
+ "Error = " << status << ".";
+ return status;
+ }
+ return OK;
+}
+
+void OutputBufferQueue::holdBufferQueueBlocks(
+ const std::list<std::unique_ptr<C2Work>>& workList) {
+ forEachBlock(workList,
+ std::bind(&OutputBufferQueue::registerBuffer,
+ this, std::placeholders::_1));
+}
+
+} // namespace utils
+} // namespace V1_0
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ClientBlockHelper.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ClientBlockHelper.h
deleted file mode 100644
index 0a2298c..0000000
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ClientBlockHelper.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CLIENT_BLOCK_HELPER_H
-#define CLIENT_BLOCK_HELPER_H
-
-#include <gui/IGraphicBufferProducer.h>
-#include <codec2/hidl/1.0/types.h>
-#include <C2Work.h>
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace c2 {
-namespace V1_0 {
-namespace utils {
-
-// BufferQueue-Based Block Operations
-// ==================================
-
-// Manage BufferQueue and graphic blocks for both component and codec.
-// Manage graphic blocks ownership consistently during surface change.
-struct OutputBufferQueue {
-
- OutputBufferQueue();
-
- ~OutputBufferQueue();
-
- // Configure a new surface to render graphic blocks.
- // Graphic blocks from older surface will be migrated to new surface.
- bool configure(const sp<IGraphicBufferProducer>& igbp,
- uint32_t generation,
- uint64_t bqId);
-
- // Render a graphic block to current surface.
- status_t outputBuffer(
- const C2ConstGraphicBlock& block,
- const BnGraphicBufferProducer::QueueBufferInput& input,
- BnGraphicBufferProducer::QueueBufferOutput* output);
-
- // Call holdBufferQueueBlock() on output blocks in the given workList.
- // The OutputBufferQueue will take the ownership of output blocks.
- //
- // Note: This function should be called after WorkBundle has been received
- // from another process.
- void holdBufferQueueBlocks(
- const std::list<std::unique_ptr<C2Work>>& workList);
-
-private:
-
- class Impl;
- std::unique_ptr<Impl> mImpl;
-};
-
-} // namespace utils
-} // namespace V1_0
-} // namespace c2
-} // namespace media
-} // namespace hardware
-} // namespace android
-
-#endif // CLIENT_BLOCK_HELPER_H
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentInterface.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentInterface.h
index a5d235e..9102f92 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentInterface.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentInterface.h
@@ -45,7 +45,7 @@
struct ComponentInterface : public IComponentInterface {
ComponentInterface(
const std::shared_ptr<C2ComponentInterface>& interface,
- ComponentStore* store);
+ const std::shared_ptr<ParameterCache>& cache);
c2_status_t status() const;
virtual Return<sp<IConfigurable>> getConfigurable() override;
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
index be80c62..fe7d048 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
@@ -54,7 +54,7 @@
struct ComponentStore : public IComponentStore {
ComponentStore(const std::shared_ptr<C2ComponentStore>& store);
- virtual ~ComponentStore() = default;
+ virtual ~ComponentStore();
/**
* Returns the status of the construction of this object.
@@ -68,6 +68,12 @@
c2_status_t validateSupportedParams(
const std::vector<std::shared_ptr<C2ParamDescriptor>>& params);
+ /**
+ * Returns the store's ParameterCache. This is used for validation by
+ * Configurable::init().
+ */
+ std::shared_ptr<ParameterCache> getParameterCache() const;
+
// Methods from ::android::hardware::media::c2::V1_0::IComponentStore.
virtual Return<void> createComponent(
const hidl_string& name,
@@ -98,6 +104,8 @@
protected:
sp<CachedConfigurable> mConfigurable;
+ struct StoreParameterCache;
+ std::shared_ptr<StoreParameterCache> mParameterCache;
// Does bookkeeping for an interface that has been loaded.
void onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf);
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Configurable.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Configurable.h
index 8095185..8f49a97 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Configurable.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Configurable.h
@@ -79,6 +79,20 @@
};
/**
+ * Type for validating and caching parameters when CachedConfigurable is
+ * initialized.
+ *
+ * This is meant to be created by the ComponentStore. The purpose of abstracting
+ * this is to allow different versions of ComponentStore to work with this
+ * CachedConfigurable.
+ */
+struct ParameterCache {
+ virtual c2_status_t validate(
+ const std::vector<std::shared_ptr<C2ParamDescriptor>>&) = 0;
+ virtual ~ParameterCache() = default;
+};
+
+/**
* Implementation of the IConfigurable interface that supports caching of
* supported parameters from a supplied ComponentStore.
*
@@ -91,7 +105,8 @@
struct CachedConfigurable : public IConfigurable {
CachedConfigurable(std::unique_ptr<ConfigurableC2Intf>&& intf);
- c2_status_t init(ComponentStore* store);
+ // Populates mSupportedParams.
+ c2_status_t init(const std::shared_ptr<ParameterCache> &cache);
// Methods from ::android::hardware::media::c2::V1_0::IConfigurable
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurface.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurface.h
index 29ed7ff..062dcd9 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurface.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurface.h
@@ -57,30 +57,26 @@
const sp<IInputSink>& sink,
connect_cb _hidl_cb) override;
+ InputSurface(
+ const std::shared_ptr<ParameterCache>& cache,
+ const std::shared_ptr<C2ReflectorHelper>& reflector,
+ const sp<HGraphicBufferProducer>& base,
+ const sp<GraphicBufferSource>& source);
+
protected:
class Interface;
class ConfigurableIntf;
- sp<ComponentStore> mStore;
+ std::shared_ptr<ParameterCache> mParameterCache;
sp<HGraphicBufferProducer> mProducer;
sp<GraphicBufferSource> mSource;
std::shared_ptr<Interface> mIntf;
sp<CachedConfigurable> mConfigurable;
- InputSurface(
- const sp<ComponentStore>& store,
- const std::shared_ptr<C2ReflectorHelper>& reflector,
- const sp<HGraphicBufferProducer>& base,
- const sp<GraphicBufferSource>& source);
-
virtual ~InputSurface() override = default;
-
- friend struct ComponentStore;
-
};
-
} // namespace utils
} // namespace V1_0
} // namespace c2
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurfaceConnection.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurfaceConnection.h
index 758b6b2..475ce8b 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurfaceConnection.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurfaceConnection.h
@@ -62,12 +62,12 @@
InputSurfaceConnection(
const sp<GraphicBufferSource>& source,
const std::shared_ptr<C2Component>& comp,
- const sp<ComponentStore>& store);
+ const std::shared_ptr<ParameterCache>& cache);
InputSurfaceConnection(
const sp<GraphicBufferSource>& source,
const sp<IInputSink>& sink,
- const sp<ComponentStore>& store);
+ const std::shared_ptr<ParameterCache>& cache);
bool init();
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/OutputBufferQueue.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/OutputBufferQueue.h
new file mode 100644
index 0000000..80368f7
--- /dev/null
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/OutputBufferQueue.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODEC2_HIDL_V1_0_UTILS_OUTPUT_BUFFER_QUEUE
+#define CODEC2_HIDL_V1_0_UTILS_OUTPUT_BUFFER_QUEUE
+
+#include <gui/IGraphicBufferProducer.h>
+#include <codec2/hidl/1.0/types.h>
+#include <C2Work.h>
+
+struct C2_HIDE _C2BlockPoolData;
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+// BufferQueue-Based Block Operations
+// ==================================
+
+// Manage BufferQueue and graphic blocks for both component and codec.
+// Manage graphic blocks ownership consistently during surface change.
+struct OutputBufferQueue {
+
+ OutputBufferQueue();
+
+ ~OutputBufferQueue();
+
+ // Configure a new surface to render graphic blocks.
+ // Graphic blocks from older surface will be migrated to new surface.
+ bool configure(const sp<IGraphicBufferProducer>& igbp,
+ uint32_t generation,
+ uint64_t bqId);
+
+ // Render a graphic block to current surface.
+ status_t outputBuffer(
+ const C2ConstGraphicBlock& block,
+ const BnGraphicBufferProducer::QueueBufferInput& input,
+ BnGraphicBufferProducer::QueueBufferOutput* output);
+
+ // Call holdBufferQueueBlock() on output blocks in the given workList.
+ // The OutputBufferQueue will take the ownership of output blocks.
+ //
+ // Note: This function should be called after WorkBundle has been received
+ // from another process.
+ void holdBufferQueueBlocks(
+ const std::list<std::unique_ptr<C2Work>>& workList);
+
+private:
+
+ std::mutex mMutex;
+ sp<IGraphicBufferProducer> mIgbp;
+ uint32_t mGeneration;
+ uint64_t mBqId;
+ std::shared_ptr<int> mOwner;
+ // To migrate existing buffers
+ sp<GraphicBuffer> mBuffers[BufferQueueDefs::NUM_BUFFER_SLOTS]; // find a better way
+ std::weak_ptr<_C2BlockPoolData> mPoolDatas[BufferQueueDefs::NUM_BUFFER_SLOTS];
+
+ bool registerBuffer(const C2ConstGraphicBlock& block);
+};
+
+} // namespace utils
+} // namespace V1_0
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // CODEC2_HIDL_V1_0_UTILS_OUTPUT_BUFFER_QUEUE
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/types.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/types.h
index a9928b3..f111f81 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/types.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/types.h
@@ -206,10 +206,23 @@
std::mutex mMutex;
sp<ClientManager> mSenderManager;
sp<IClientManager> mReceiverManager;
- int64_t mReceiverConnectionId;
- int64_t mSourceConnectionId;
- std::chrono::steady_clock::time_point mLastSent;
std::chrono::steady_clock::duration mRefreshInterval;
+
+ struct Connection {
+ int64_t receiverConnectionId;
+ std::chrono::steady_clock::time_point lastSent;
+ Connection(int64_t receiverConnectionId,
+ std::chrono::steady_clock::time_point lastSent)
+ : receiverConnectionId(receiverConnectionId),
+ lastSent(lastSent) {
+ }
+ };
+
+ // Map of connections.
+ //
+ // The key is the connection id. One sender-receiver pair may have multiple
+ // connections.
+ std::map<int64_t, Connection> mConnections;
};
// std::list<std::unique_ptr<C2Work>> -> WorkBundle
diff --git a/media/codec2/hidl/1.0/utils/types.cpp b/media/codec2/hidl/1.0/utils/types.cpp
index 04fa59c..c73cb52 100644
--- a/media/codec2/hidl/1.0/utils/types.cpp
+++ b/media/codec2/hidl/1.0/utils/types.cpp
@@ -969,8 +969,6 @@
const sp<IClientManager>& receiverManager,
std::chrono::steady_clock::duration refreshInterval)
: mReceiverManager(receiverManager),
- mSourceConnectionId(0),
- mLastSent(std::chrono::steady_clock::now()),
mRefreshInterval(refreshInterval) {
}
@@ -980,6 +978,7 @@
std::lock_guard<std::mutex> lock(mMutex);
if (mReceiverManager != receiverManager) {
mReceiverManager = receiverManager;
+ mConnections.clear();
}
mRefreshInterval = refreshInterval;
}
@@ -987,12 +986,16 @@
ResultStatus DefaultBufferPoolSender::send(
const std::shared_ptr<BufferPoolData>& bpData,
BufferStatusMessage* bpMessage) {
+ int64_t connectionId = bpData->mConnectionId;
+ if (connectionId == 0) {
+ LOG(WARNING) << "registerSender -- invalid sender connection id (0).";
+ return ResultStatus::CRITICAL_ERROR;
+ }
+ std::lock_guard<std::mutex> lock(mMutex);
if (!mReceiverManager) {
LOG(ERROR) << "No access to receiver's BufferPool.";
return ResultStatus::NOT_FOUND;
}
- ResultStatus rs;
- std::lock_guard<std::mutex> lock(mMutex);
if (!mSenderManager) {
mSenderManager = ClientManager::getInstance();
if (!mSenderManager) {
@@ -1000,52 +1003,61 @@
return ResultStatus::CRITICAL_ERROR;
}
}
- int64_t connectionId = bpData->mConnectionId;
+
+ int64_t receiverConnectionId{0};
+ auto foundConnection = mConnections.find(connectionId);
+ bool isNewConnection = foundConnection == mConnections.end();
std::chrono::steady_clock::time_point now =
std::chrono::steady_clock::now();
- std::chrono::steady_clock::duration interval = now - mLastSent;
- if (mSourceConnectionId == 0 ||
- mSourceConnectionId != connectionId ||
- interval > mRefreshInterval) {
+ if (isNewConnection ||
+ (now - foundConnection->second.lastSent > mRefreshInterval)) {
// Initialize the bufferpool connection.
- mSourceConnectionId = connectionId;
- if (mSourceConnectionId == 0) {
- return ResultStatus::CRITICAL_ERROR;
- }
-
- int64_t receiverConnectionId;
- rs = mSenderManager->registerSender(mReceiverManager,
- connectionId,
- &receiverConnectionId);
+ ResultStatus rs =
+ mSenderManager->registerSender(mReceiverManager,
+ connectionId,
+ &receiverConnectionId);
if ((rs != ResultStatus::OK) && (rs != ResultStatus::ALREADY_EXISTS)) {
LOG(WARNING) << "registerSender -- returned error: "
<< static_cast<int32_t>(rs)
<< ".";
return rs;
+ } else if (receiverConnectionId == 0) {
+ LOG(WARNING) << "registerSender -- "
+ "invalid receiver connection id (0).";
+ return ResultStatus::CRITICAL_ERROR;
} else {
- mReceiverConnectionId = receiverConnectionId;
+ if (isNewConnection) {
+ foundConnection = mConnections.try_emplace(
+ connectionId, receiverConnectionId, now).first;
+ } else {
+ foundConnection->second.receiverConnectionId = receiverConnectionId;
+ }
}
+ } else {
+ receiverConnectionId = foundConnection->second.receiverConnectionId;
}
uint64_t transactionId;
int64_t timestampUs;
- rs = mSenderManager->postSend(
- mReceiverConnectionId, bpData, &transactionId, ×tampUs);
+ ResultStatus rs = mSenderManager->postSend(
+ receiverConnectionId, bpData, &transactionId, ×tampUs);
if (rs != ResultStatus::OK) {
LOG(ERROR) << "ClientManager::postSend -- returned error: "
<< static_cast<int32_t>(rs)
<< ".";
+ mConnections.erase(foundConnection);
return rs;
}
if (!bpMessage) {
LOG(ERROR) << "Null output parameter for BufferStatusMessage.";
+ mConnections.erase(foundConnection);
return ResultStatus::CRITICAL_ERROR;
}
- bpMessage->connectionId = mReceiverConnectionId;
+ bpMessage->connectionId = receiverConnectionId;
bpMessage->bufferId = bpData->mId;
bpMessage->transactionId = transactionId;
bpMessage->timestampUs = timestampUs;
- mLastSent = now;
+ foundConnection->second.lastSent = now;
return rs;
}
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
index a8a552c..20f4665 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
@@ -71,7 +71,8 @@
mDisableTest = false;
ALOGV("Codec2AudioDecHidlTest SetUp");
mClient = android::Codec2Client::CreateFromService(
- gEnv->getInstance().c_str());
+ gEnv->getInstance().c_str(),
+ !bool(android::Codec2Client::CreateFromService("default", true)));
ASSERT_NE(mClient, nullptr);
mListener.reset(new CodecListener(
[this](std::list<std::unique_ptr<C2Work>>& workItems) {
@@ -203,7 +204,7 @@
uint32_t mFramesReceived;
std::list<uint64_t> mFlushedIndices;
std::list<uint64_t> mTimestampUslist;
- ::android::List<outputMetaData> oBufferMetaData;
+ std::list<outputMetaData> oBufferMetaData;
C2BlockPool::local_id_t mBlockPoolId;
std::shared_ptr<C2BlockPool> mLinearPool;
@@ -547,10 +548,6 @@
if (mCompName == raw) {
bitStreamInfo[0] = 8000;
bitStreamInfo[1] = 1;
- } else if (mCompName == g711alaw || mCompName == g711mlaw) {
- // g711 test data is all 1-channel and has no embedded config info.
- bitStreamInfo[0] = 8000;
- bitStreamInfo[1] = 1;
} else {
ASSERT_NO_FATAL_FAILURE(
getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
@@ -598,7 +595,7 @@
int nSampleRate = bitStreamInfo[0];
int nChannels = bitStreamInfo[1];
std::list<uint64_t>::iterator itIn = mTimestampUslist.begin();
- android::List<outputMetaData>::iterator itOut = oBufferMetaData.begin();
+ auto itOut = oBufferMetaData.begin();
EXPECT_EQ(*itIn, itOut->timestampUs);
expTs = *itIn;
while (itOut != oBufferMetaData.end()) {
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp
index 01baf7e..ab6bfb2 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp
@@ -65,7 +65,8 @@
mDisableTest = false;
ALOGV("Codec2AudioEncHidlTest SetUp");
mClient = android::Codec2Client::CreateFromService(
- gEnv->getInstance().c_str());
+ gEnv->getInstance().c_str(),
+ !bool(android::Codec2Client::CreateFromService("default", true)));
ASSERT_NE(mClient, nullptr);
mListener.reset(new CodecListener(
[this](std::list<std::unique_ptr<C2Work>>& workItems) {
diff --git a/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp b/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
index d73b731..2f02913 100644
--- a/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
@@ -20,6 +20,13 @@
#include "media_c2_hidl_test_common.h"
+#include <android/hardware/media/c2/1.0/IComponentStore.h>
+
+void ComponentTestEnvironment::registerTestServices() {
+ registerTestService<::android::hardware::media::c2::V1_0::
+ IComponentStore>();
+}
+
// Test the codecs for NullBuffer, Empty Input Buffer with(out) flags set
void testInputBuffer(
const std::shared_ptr<android::Codec2Client::Component>& component,
diff --git a/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h b/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h
index db59e54..23e332a 100644
--- a/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h
+++ b/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h
@@ -17,32 +17,23 @@
#ifndef MEDIA_C2_HIDL_TEST_COMMON_H
#define MEDIA_C2_HIDL_TEST_COMMON_H
-#include <codec2/hidl/client.h>
-
-#include <android/hardware/media/c2/1.0/types.h>
-
#include <C2Component.h>
#include <C2Config.h>
+
+#include <codec2/hidl/client.h>
#include <getopt.h>
#include <hidl/HidlSupport.h>
-#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/foundation/Mutexed.h>
-
-using namespace ::android::hardware::media::c2::V1_0;
-using namespace ::android::hardware::media::c2::V1_0::utils;
-
-using ::android::Mutexed;
-using ::android::hardware::Void;
-using ::android::hardware::Return;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-
#include <VtsHalHidlTargetTestEnvBase.h>
#define MAX_RETRY 20
#define TIME_OUT 400ms
#define MAX_INPUT_BUFFERS 8
+using ::android::hardware::Void;
+using ::android::hardware::Return;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+
/*
* Handle Callback functions onWorkDone(), onTripped(),
* onError(), onDeath(), onFramesRendered()
@@ -114,9 +105,7 @@
typedef ::testing::VtsHalHidlTargetTestEnvBase Super;
public:
- virtual void registerTestServices() override {
- registerTestService<IComponentStore>();
- }
+ virtual void registerTestServices() override;
ComponentTestEnvironment() : res("/data/local/tmp/media/") {}
diff --git a/media/codec2/hidl/1.0/vts/functional/video/Android.bp b/media/codec2/hidl/1.0/vts/functional/video/Android.bp
index be35b02..b737323 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/Android.bp
+++ b/media/codec2/hidl/1.0/vts/functional/video/Android.bp
@@ -18,6 +18,14 @@
name: "VtsHalMediaC2V1_0TargetVideoDecTest",
defaults: ["VtsHalMediaC2V1_0Defaults"],
srcs: ["VtsHalMediaC2V1_0TargetVideoDecTest.cpp"],
+ header_libs: [
+ "libnativewindow_headers",
+ ],
+ shared_libs: [
+ "libbinder",
+ "libgui",
+ "libutils",
+ ],
}
cc_test {
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
index 5e28750..256603c 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
@@ -28,6 +28,10 @@
#include <C2Debug.h>
#include <C2Buffer.h>
#include <C2BufferPriv.h>
+#include <gui/BufferQueue.h>
+#include <gui/IConsumerListener.h>
+#include <gui/IProducerListener.h>
+#include <system/window.h>
using android::C2AllocatorIon;
@@ -74,7 +78,8 @@
mDisableTest = false;
ALOGV("Codec2VideoDecHidlTest SetUp");
mClient = android::Codec2Client::CreateFromService(
- gEnv->getInstance().c_str());
+ gEnv->getInstance().c_str(),
+ !bool(android::Codec2Client::CreateFromService("default", true)));
ASSERT_NE(mClient, nullptr);
mListener.reset(new CodecListener(
[this](std::list<std::unique_ptr<C2Work>>& workItems) {
@@ -426,6 +431,48 @@
ASSERT_EQ(mDisableTest, false);
}
+TEST_F(Codec2VideoDecHidlTest, configureTunnel) {
+ description("Attempts to configure tunneling");
+ if (mDisableTest) return;
+ ALOGV("Checks if the component can be configured for tunneling");
+ native_handle_t* sidebandStream{};
+ c2_status_t err = mComponent->configureVideoTunnel(0, &sidebandStream);
+ if (err == C2_OMITTED) {
+ return;
+ }
+
+ using namespace android;
+ sp<NativeHandle> nativeHandle = NativeHandle::create(sidebandStream, true);
+
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+
+ class DummyConsumerListener : public BnConsumerListener {
+ public:
+ DummyConsumerListener() : BnConsumerListener() {}
+ void onFrameAvailable(const BufferItem&) override {}
+ void onBuffersReleased() override {}
+ void onSidebandStreamChanged() override {}
+ };
+ consumer->consumerConnect(new DummyConsumerListener(), false);
+
+ class DummyProducerListener : public BnProducerListener {
+ public:
+ DummyProducerListener() : BnProducerListener() {}
+ virtual void onBufferReleased() override {}
+ virtual bool needsReleaseNotify() override { return false; }
+ virtual void onBuffersDiscarded(const std::vector<int32_t>&) override {}
+ };
+ IGraphicBufferProducer::QueueBufferOutput qbo{};
+ producer->connect(new DummyProducerListener(),
+ NATIVE_WINDOW_API_MEDIA,
+ false,
+ &qbo);
+
+ ASSERT_EQ(producer->setSidebandStream(nativeHandle), NO_ERROR);
+}
+
class Codec2VideoDecDecodeTest
: public Codec2VideoDecHidlTest,
public ::testing::WithParamInterface<std::pair<int32_t, bool>> {
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
index c1f5a92..15f6acd 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
@@ -64,7 +64,8 @@
mDisableTest = false;
ALOGV("Codec2VideoEncHidlTest SetUp");
mClient = android::Codec2Client::CreateFromService(
- gEnv->getInstance().c_str());
+ gEnv->getInstance().c_str(),
+ !bool(android::Codec2Client::CreateFromService("default", true)));
ASSERT_NE(mClient, nullptr);
mListener.reset(new CodecListener(
[this](std::list<std::unique_ptr<C2Work>>& workItems) {
diff --git a/media/codec2/hidl/1.1/utils/Android.bp b/media/codec2/hidl/1.1/utils/Android.bp
new file mode 100644
index 0000000..8fddf98
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/Android.bp
@@ -0,0 +1,164 @@
+// DO NOT DEPEND ON THIS DIRECTLY
+// use libcodec2-hidl-client-defaults instead
+cc_library {
+ name: "libcodec2_hidl_client@1.1",
+
+ defaults: ["hidl_defaults"],
+
+ srcs: [
+ "OutputBufferQueue.cpp",
+ "types.cpp",
+ ],
+
+ header_libs: [
+ "libcodec2_internal", // private
+ ],
+
+ shared_libs: [
+ "android.hardware.media.bufferpool@2.0",
+ "android.hardware.media.c2@1.0",
+ "android.hardware.media.c2@1.1",
+ "libbase",
+ "libcodec2",
+ "libcodec2_hidl_client@1.0",
+ "libcodec2_vndk",
+ "libcutils",
+ "libgui",
+ "libhidlbase",
+ "liblog",
+ "libstagefright_bufferpool@2.0.1",
+ "libui",
+ "libutils",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+
+ export_shared_lib_headers: [
+ "android.hardware.media.c2@1.0",
+ "android.hardware.media.c2@1.1",
+ "libcodec2",
+ "libcodec2_hidl_client@1.0",
+ "libgui",
+ "libstagefright_bufferpool@2.0.1",
+ "libui",
+ ],
+}
+
+
+// DO NOT DEPEND ON THIS DIRECTLY
+// use libcodec2-hidl-defaults instead
+cc_library {
+ name: "libcodec2_hidl@1.1",
+ vendor_available: true,
+
+ defaults: ["hidl_defaults"],
+
+ srcs: [
+ "Component.cpp",
+ "ComponentInterface.cpp",
+ "ComponentStore.cpp",
+ "Configurable.cpp",
+ "InputBufferManager.cpp",
+ "InputSurface.cpp",
+ "InputSurfaceConnection.cpp",
+ "types.cpp",
+ ],
+
+ header_libs: [
+ "libbinder_headers",
+ "libsystem_headers",
+ "libcodec2_internal", // private
+ ],
+
+ shared_libs: [
+ "android.hardware.graphics.bufferqueue@1.0",
+ "android.hardware.graphics.bufferqueue@2.0",
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.media@1.0",
+ "android.hardware.media.bufferpool@2.0",
+ "android.hardware.media.c2@1.0",
+ "android.hardware.media.c2@1.1",
+ "android.hardware.media.omx@1.0",
+ "libbase",
+ "libcodec2",
+ "libcodec2_hidl@1.0",
+ "libcodec2_vndk",
+ "libcutils",
+ "libhidlbase",
+ "liblog",
+ "libstagefright_bufferpool@2.0.1",
+ "libstagefright_bufferqueue_helper_novndk",
+ "libui",
+ "libutils",
+ ],
+
+ target: {
+ vendor: {
+ exclude_shared_libs: [
+ "libstagefright_bufferqueue_helper_novndk",
+ ],
+ shared_libs: [
+ "libstagefright_bufferqueue_helper",
+ ],
+ },
+ },
+
+ export_include_dirs: [
+ "include",
+ ],
+
+ export_shared_lib_headers: [
+ "android.hardware.media.c2@1.0",
+ "android.hardware.media.c2@1.1",
+ "libcodec2",
+ "libcodec2_hidl@1.0",
+ "libcodec2_vndk",
+ "libhidlbase",
+ "libstagefright_bufferpool@2.0.1",
+ "libui",
+ ],
+}
+
+// public dependency for Codec 2.0 HAL service implementations
+cc_defaults {
+ name: "libcodec2-hidl-defaults@1.1",
+ defaults: ["libcodec2-impl-defaults"],
+
+ shared_libs: [
+ "android.hardware.media.c2@1.0",
+ "android.hardware.media.c2@1.1",
+ "libcodec2_hidl@1.0",
+ "libcodec2_hidl@1.1",
+ "libcodec2_vndk",
+ "libhidlbase",
+ ],
+}
+
+// public dependency for Codec 2.0 HAL client
+cc_defaults {
+ name: "libcodec2-hidl-client-defaults@1.1",
+ defaults: ["libcodec2-impl-defaults"],
+
+ shared_libs: [
+ "android.hardware.media.c2@1.0",
+ "android.hardware.media.c2@1.1",
+ "libcodec2_hidl_client@1.0",
+ "libcodec2_hidl_client@1.1",
+ "libcodec2_vndk",
+ "libhidlbase",
+ ],
+}
+
+// Alias to the latest "defaults" for Codec 2.0 HAL service implementations
+cc_defaults {
+ name: "libcodec2-hidl-defaults",
+ defaults: ["libcodec2-hidl-defaults@1.1"],
+}
+
+// Alias to the latest "defaults" for Codec 2.0 HAL client
+cc_defaults {
+ name: "libcodec2-hidl-client-defaults",
+ defaults: ["libcodec2-hidl-client-defaults@1.1"],
+}
diff --git a/media/codec2/hidl/1.1/utils/Component.cpp b/media/codec2/hidl/1.1/utils/Component.cpp
new file mode 100644
index 0000000..ed281e6
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/Component.cpp
@@ -0,0 +1,493 @@
+/*
+ * Copyright 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Codec2-Component@1.1"
+#include <android-base/logging.h>
+
+#include <codec2/hidl/1.1/Component.h>
+#include <codec2/hidl/1.1/ComponentStore.h>
+#include <codec2/hidl/1.1/InputBufferManager.h>
+
+#include <hidl/HidlBinderSupport.h>
+#include <utils/Timers.h>
+
+#include <C2BqBufferPriv.h>
+#include <C2Debug.h>
+#include <C2PlatformSupport.h>
+
+#include <chrono>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_1 {
+namespace utils {
+
+using namespace ::android;
+
+// ComponentListener wrapper
+struct Component::Listener : public C2Component::Listener {
+
+ Listener(const sp<Component>& component) :
+ mComponent(component),
+ mListener(component->mListener) {
+ }
+
+ virtual void onError_nb(
+ std::weak_ptr<C2Component> /* c2component */,
+ uint32_t errorCode) override {
+ sp<IComponentListener> listener = mListener.promote();
+ if (listener) {
+ Return<void> transStatus = listener->onError(Status::OK, errorCode);
+ if (!transStatus.isOk()) {
+ LOG(ERROR) << "Component::Listener::onError_nb -- "
+ << "transaction failed.";
+ }
+ }
+ }
+
+ virtual void onTripped_nb(
+ std::weak_ptr<C2Component> /* c2component */,
+ std::vector<std::shared_ptr<C2SettingResult>> c2settingResult
+ ) override {
+ sp<IComponentListener> listener = mListener.promote();
+ if (listener) {
+ hidl_vec<SettingResult> settingResults(c2settingResult.size());
+ size_t ix = 0;
+ for (const std::shared_ptr<C2SettingResult> &c2result :
+ c2settingResult) {
+ if (c2result) {
+ if (!objcpy(&settingResults[ix++], *c2result)) {
+ break;
+ }
+ }
+ }
+ settingResults.resize(ix);
+ Return<void> transStatus = listener->onTripped(settingResults);
+ if (!transStatus.isOk()) {
+ LOG(ERROR) << "Component::Listener::onTripped_nb -- "
+ << "transaction failed.";
+ }
+ }
+ }
+
+ virtual void onWorkDone_nb(
+ std::weak_ptr<C2Component> /* c2component */,
+ std::list<std::unique_ptr<C2Work>> c2workItems) override {
+ for (const std::unique_ptr<C2Work>& work : c2workItems) {
+ if (work) {
+ if (work->worklets.empty()
+ || !work->worklets.back()
+ || (work->worklets.back()->output.flags &
+ C2FrameData::FLAG_INCOMPLETE) == 0) {
+ InputBufferManager::
+ unregisterFrameData(mListener, work->input);
+ }
+ }
+ }
+
+ sp<IComponentListener> listener = mListener.promote();
+ if (listener) {
+ WorkBundle workBundle;
+
+ sp<Component> strongComponent = mComponent.promote();
+ beginTransferBufferQueueBlocks(c2workItems, true);
+ if (!objcpy(&workBundle, c2workItems, strongComponent ?
+ &strongComponent->mBufferPoolSender : nullptr)) {
+ LOG(ERROR) << "Component::Listener::onWorkDone_nb -- "
+ << "received corrupted work items.";
+ endTransferBufferQueueBlocks(c2workItems, false, true);
+ return;
+ }
+ Return<void> transStatus = listener->onWorkDone(workBundle);
+ if (!transStatus.isOk()) {
+ LOG(ERROR) << "Component::Listener::onWorkDone_nb -- "
+ << "transaction failed.";
+ endTransferBufferQueueBlocks(c2workItems, false, true);
+ return;
+ }
+ endTransferBufferQueueBlocks(c2workItems, true, true);
+ }
+ }
+
+protected:
+ wp<Component> mComponent;
+ wp<IComponentListener> mListener;
+};
+
+// Component::Sink
+struct Component::Sink : public IInputSink {
+ std::shared_ptr<Component> mComponent;
+ sp<IConfigurable> mConfigurable;
+
+ virtual Return<Status> queue(const WorkBundle& workBundle) override {
+ return mComponent->queue(workBundle);
+ }
+
+ virtual Return<sp<IConfigurable>> getConfigurable() override {
+ return mConfigurable;
+ }
+
+ Sink(const std::shared_ptr<Component>& component);
+ virtual ~Sink() override;
+
+ // Process-wide map: Component::Sink -> C2Component.
+ static std::mutex sSink2ComponentMutex;
+ static std::map<IInputSink*, std::weak_ptr<C2Component>> sSink2Component;
+
+ static std::shared_ptr<C2Component> findLocalComponent(
+ const sp<IInputSink>& sink);
+};
+
+std::mutex
+ Component::Sink::sSink2ComponentMutex{};
+std::map<IInputSink*, std::weak_ptr<C2Component>>
+ Component::Sink::sSink2Component{};
+
+Component::Sink::Sink(const std::shared_ptr<Component>& component)
+ : mComponent{component},
+ mConfigurable{[&component]() -> sp<IConfigurable> {
+ Return<sp<IComponentInterface>> ret1 = component->getInterface();
+ if (!ret1.isOk()) {
+ LOG(ERROR) << "Sink::Sink -- component's transaction failed.";
+ return nullptr;
+ }
+ Return<sp<IConfigurable>> ret2 =
+ static_cast<sp<IComponentInterface>>(ret1)->
+ getConfigurable();
+ if (!ret2.isOk()) {
+ LOG(ERROR) << "Sink::Sink -- interface's transaction failed.";
+ return nullptr;
+ }
+ return static_cast<sp<IConfigurable>>(ret2);
+ }()} {
+ std::lock_guard<std::mutex> lock(sSink2ComponentMutex);
+ sSink2Component.emplace(this, component->mComponent);
+}
+
+Component::Sink::~Sink() {
+ std::lock_guard<std::mutex> lock(sSink2ComponentMutex);
+ sSink2Component.erase(this);
+}
+
+std::shared_ptr<C2Component> Component::Sink::findLocalComponent(
+ const sp<IInputSink>& sink) {
+ std::lock_guard<std::mutex> lock(sSink2ComponentMutex);
+ auto i = sSink2Component.find(sink.get());
+ if (i == sSink2Component.end()) {
+ return nullptr;
+ }
+ return i->second.lock();
+}
+
+// Component
+Component::Component(
+ const std::shared_ptr<C2Component>& component,
+ const sp<IComponentListener>& listener,
+ const sp<ComponentStore>& store,
+ const sp<::android::hardware::media::bufferpool::V2_0::
+ IClientManager>& clientPoolManager)
+ : mComponent{component},
+ mInterface{new ComponentInterface(component->intf(),
+ store->getParameterCache())},
+ mListener{listener},
+ mStore{store},
+ mBufferPoolSender{clientPoolManager} {
+ // Retrieve supported parameters from store
+ // TODO: We could cache this per component/interface type
+ mInit = mInterface->status();
+}
+
+c2_status_t Component::status() const {
+ return mInit;
+}
+
+// Methods from ::android::hardware::media::c2::V1_1::IComponent
+Return<Status> Component::queue(const WorkBundle& workBundle) {
+ std::list<std::unique_ptr<C2Work>> c2works;
+
+ if (!objcpy(&c2works, workBundle)) {
+ return Status::CORRUPTED;
+ }
+
+ // Register input buffers.
+ for (const std::unique_ptr<C2Work>& work : c2works) {
+ if (work) {
+ InputBufferManager::
+ registerFrameData(mListener, work->input);
+ }
+ }
+
+ return static_cast<Status>(mComponent->queue_nb(&c2works));
+}
+
+Return<void> Component::flush(flush_cb _hidl_cb) {
+ std::list<std::unique_ptr<C2Work>> c2flushedWorks;
+ c2_status_t c2res = mComponent->flush_sm(
+ C2Component::FLUSH_COMPONENT,
+ &c2flushedWorks);
+
+ // Unregister input buffers.
+ for (const std::unique_ptr<C2Work>& work : c2flushedWorks) {
+ if (work) {
+ if (work->worklets.empty()
+ || !work->worklets.back()
+ || (work->worklets.back()->output.flags &
+ C2FrameData::FLAG_INCOMPLETE) == 0) {
+ InputBufferManager::
+ unregisterFrameData(mListener, work->input);
+ }
+ }
+ }
+
+ WorkBundle flushedWorkBundle;
+ Status res = static_cast<Status>(c2res);
+ beginTransferBufferQueueBlocks(c2flushedWorks, true);
+ if (c2res == C2_OK) {
+ if (!objcpy(&flushedWorkBundle, c2flushedWorks, &mBufferPoolSender)) {
+ res = Status::CORRUPTED;
+ }
+ }
+ _hidl_cb(res, flushedWorkBundle);
+ endTransferBufferQueueBlocks(c2flushedWorks, true, true);
+ return Void();
+}
+
+Return<Status> Component::drain(bool withEos) {
+ return static_cast<Status>(mComponent->drain_nb(withEos ?
+ C2Component::DRAIN_COMPONENT_WITH_EOS :
+ C2Component::DRAIN_COMPONENT_NO_EOS));
+}
+
+Return<Status> Component::setOutputSurface(
+ uint64_t blockPoolId,
+ const sp<HGraphicBufferProducer2>& surface) {
+ std::shared_ptr<C2BlockPool> pool;
+ GetCodec2BlockPool(blockPoolId, mComponent, &pool);
+ if (pool && pool->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) {
+ std::shared_ptr<C2BufferQueueBlockPool> bqPool =
+ std::static_pointer_cast<C2BufferQueueBlockPool>(pool);
+ C2BufferQueueBlockPool::OnRenderCallback cb =
+ [this](uint64_t producer, int32_t slot, int64_t nsecs) {
+ // TODO: batch this
+ hidl_vec<IComponentListener::RenderedFrame> rendered;
+ rendered.resize(1);
+ rendered[0] = { producer, slot, nsecs };
+ (void)mListener->onFramesRendered(rendered).isOk();
+ };
+ if (bqPool) {
+ bqPool->setRenderCallback(cb);
+ bqPool->configureProducer(surface);
+ }
+ }
+ return Status::OK;
+}
+
+Return<void> Component::connectToInputSurface(
+ const sp<IInputSurface>& inputSurface,
+ connectToInputSurface_cb _hidl_cb) {
+ Status status;
+ sp<IInputSurfaceConnection> connection;
+ auto transStatus = inputSurface->connect(
+ asInputSink(),
+ [&status, &connection](
+ Status s, const sp<IInputSurfaceConnection>& c) {
+ status = s;
+ connection = c;
+ }
+ );
+ _hidl_cb(status, connection);
+ return Void();
+}
+
+Return<void> Component::connectToOmxInputSurface(
+ const sp<HGraphicBufferProducer1>& producer,
+ const sp<::android::hardware::media::omx::V1_0::
+ IGraphicBufferSource>& source,
+ connectToOmxInputSurface_cb _hidl_cb) {
+ (void)producer;
+ (void)source;
+ (void)_hidl_cb;
+ return Void();
+}
+
+Return<Status> Component::disconnectFromInputSurface() {
+ // TODO implement
+ return Status::OK;
+}
+
+namespace /* unnamed */ {
+
+struct BlockPoolIntf : public ConfigurableC2Intf {
+ BlockPoolIntf(const std::shared_ptr<C2BlockPool>& pool)
+ : ConfigurableC2Intf{
+ "C2BlockPool:" +
+ (pool ? std::to_string(pool->getLocalId()) : "null"),
+ 0},
+ mPool{pool} {
+ }
+
+ virtual c2_status_t config(
+ const std::vector<C2Param*>& params,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2SettingResult>>* const failures
+ ) override {
+ (void)params;
+ (void)mayBlock;
+ (void)failures;
+ return C2_OK;
+ }
+
+ virtual c2_status_t query(
+ const std::vector<C2Param::Index>& indices,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2Param>>* const params
+ ) const override {
+ (void)indices;
+ (void)mayBlock;
+ (void)params;
+ return C2_OK;
+ }
+
+ virtual c2_status_t querySupportedParams(
+ std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
+ ) const override {
+ (void)params;
+ return C2_OK;
+ }
+
+ virtual c2_status_t querySupportedValues(
+ std::vector<C2FieldSupportedValuesQuery>& fields,
+ c2_blocking_t mayBlock) const override {
+ (void)fields;
+ (void)mayBlock;
+ return C2_OK;
+ }
+
+protected:
+ std::shared_ptr<C2BlockPool> mPool;
+};
+
+} // unnamed namespace
+
+Return<void> Component::createBlockPool(
+ uint32_t allocatorId,
+ createBlockPool_cb _hidl_cb) {
+ std::shared_ptr<C2BlockPool> blockPool;
+ c2_status_t status = CreateCodec2BlockPool(
+ static_cast<C2PlatformAllocatorStore::id_t>(allocatorId),
+ mComponent,
+ &blockPool);
+ if (status != C2_OK) {
+ blockPool = nullptr;
+ }
+ if (blockPool) {
+ mBlockPoolsMutex.lock();
+ mBlockPools.emplace(blockPool->getLocalId(), blockPool);
+ mBlockPoolsMutex.unlock();
+ } else if (status == C2_OK) {
+ status = C2_CORRUPTED;
+ }
+
+ _hidl_cb(static_cast<Status>(status),
+ blockPool ? blockPool->getLocalId() : 0,
+ new CachedConfigurable(
+ std::make_unique<BlockPoolIntf>(blockPool)));
+ return Void();
+}
+
+Return<Status> Component::destroyBlockPool(uint64_t blockPoolId) {
+ std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
+ return mBlockPools.erase(blockPoolId) == 1 ?
+ Status::OK : Status::CORRUPTED;
+}
+
+Return<Status> Component::start() {
+ return static_cast<Status>(mComponent->start());
+}
+
+Return<Status> Component::stop() {
+ InputBufferManager::unregisterFrameData(mListener);
+ return static_cast<Status>(mComponent->stop());
+}
+
+Return<Status> Component::reset() {
+ Status status = static_cast<Status>(mComponent->reset());
+ {
+ std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
+ mBlockPools.clear();
+ }
+ InputBufferManager::unregisterFrameData(mListener);
+ return status;
+}
+
+Return<Status> Component::release() {
+ Status status = static_cast<Status>(mComponent->release());
+ {
+ std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
+ mBlockPools.clear();
+ }
+ InputBufferManager::unregisterFrameData(mListener);
+ return status;
+}
+
+Return<sp<IComponentInterface>> Component::getInterface() {
+ return sp<IComponentInterface>(mInterface);
+}
+
+Return<sp<IInputSink>> Component::asInputSink() {
+ std::lock_guard<std::mutex> lock(mSinkMutex);
+ if (!mSink) {
+ mSink = new Sink(shared_from_this());
+ }
+ return {mSink};
+}
+
+Return<void> Component::configureVideoTunnel(
+ uint32_t avSyncHwId, configureVideoTunnel_cb _hidl_cb) {
+ (void)avSyncHwId;
+ _hidl_cb(Status::OMITTED, hidl_handle{});
+ return Void();
+}
+
+std::shared_ptr<C2Component> Component::findLocalComponent(
+ const sp<IInputSink>& sink) {
+ return Component::Sink::findLocalComponent(sink);
+}
+
+void Component::initListener(const sp<Component>& self) {
+ std::shared_ptr<C2Component::Listener> c2listener =
+ std::make_shared<Listener>(self);
+ c2_status_t res = mComponent->setListener_vb(c2listener, C2_DONT_BLOCK);
+ if (res != C2_OK) {
+ mInit = res;
+ }
+}
+
+Component::~Component() {
+ InputBufferManager::unregisterFrameData(mListener);
+ mStore->reportComponentDeath(this);
+}
+
+} // namespace utils
+} // namespace V1_1
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
diff --git a/media/codec2/hidl/1.1/utils/ComponentInterface.cpp b/media/codec2/hidl/1.1/utils/ComponentInterface.cpp
new file mode 100644
index 0000000..ccc30fe
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/ComponentInterface.cpp
@@ -0,0 +1,17 @@
+/*
+ * Copyright 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.
+ */
+
+#include <codec2/hidl/1.1/ComponentInterface.h>
diff --git a/media/codec2/hidl/1.1/utils/ComponentStore.cpp b/media/codec2/hidl/1.1/utils/ComponentStore.cpp
new file mode 100644
index 0000000..225cd09
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/ComponentStore.cpp
@@ -0,0 +1,499 @@
+/*
+ * Copyright 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Codec2-ComponentStore@1.1"
+#include <android-base/logging.h>
+
+#include <codec2/hidl/1.1/ComponentStore.h>
+#include <codec2/hidl/1.1/InputSurface.h>
+#include <codec2/hidl/1.1/types.h>
+
+#include <android-base/file.h>
+#include <media/stagefright/bqhelper/GraphicBufferSource.h>
+#include <utils/Errors.h>
+
+#include <C2PlatformSupport.h>
+#include <util/C2InterfaceHelper.h>
+
+#include <chrono>
+#include <ctime>
+#include <iomanip>
+#include <ostream>
+#include <sstream>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_1 {
+namespace utils {
+
+using namespace ::android;
+using ::android::GraphicBufferSource;
+using namespace ::android::hardware::media::bufferpool::V2_0::implementation;
+
+namespace /* unnamed */ {
+
+struct StoreIntf : public ConfigurableC2Intf {
+ StoreIntf(const std::shared_ptr<C2ComponentStore>& store)
+ : ConfigurableC2Intf{store ? store->getName() : "", 0},
+ mStore{store} {
+ }
+
+ virtual c2_status_t config(
+ const std::vector<C2Param*> ¶ms,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2SettingResult>> *const failures
+ ) override {
+ // Assume all params are blocking
+ // TODO: Filter for supported params
+ if (mayBlock == C2_DONT_BLOCK && params.size() != 0) {
+ return C2_BLOCKING;
+ }
+ return mStore->config_sm(params, failures);
+ }
+
+ virtual c2_status_t query(
+ const std::vector<C2Param::Index> &indices,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2Param>> *const params) const override {
+ // Assume all params are blocking
+ // TODO: Filter for supported params
+ if (mayBlock == C2_DONT_BLOCK && indices.size() != 0) {
+ return C2_BLOCKING;
+ }
+ return mStore->query_sm({}, indices, params);
+ }
+
+ virtual c2_status_t querySupportedParams(
+ std::vector<std::shared_ptr<C2ParamDescriptor>> *const params
+ ) const override {
+ return mStore->querySupportedParams_nb(params);
+ }
+
+ virtual c2_status_t querySupportedValues(
+ std::vector<C2FieldSupportedValuesQuery> &fields,
+ c2_blocking_t mayBlock) const override {
+ // Assume all params are blocking
+ // TODO: Filter for supported params
+ if (mayBlock == C2_DONT_BLOCK && fields.size() != 0) {
+ return C2_BLOCKING;
+ }
+ return mStore->querySupportedValues_sm(fields);
+ }
+
+protected:
+ std::shared_ptr<C2ComponentStore> mStore;
+};
+
+} // unnamed namespace
+
+struct ComponentStore::StoreParameterCache : public ParameterCache {
+ std::mutex mStoreMutex;
+ ComponentStore* mStore;
+
+ StoreParameterCache(ComponentStore* store): mStore{store} {
+ }
+
+ virtual c2_status_t validate(
+ const std::vector<std::shared_ptr<C2ParamDescriptor>>& params
+ ) override {
+ std::scoped_lock _lock(mStoreMutex);
+ return mStore ? mStore->validateSupportedParams(params) : C2_NO_INIT;
+ }
+
+ void onStoreDestroyed() {
+ std::scoped_lock _lock(mStoreMutex);
+ mStore = nullptr;
+ }
+};
+
+ComponentStore::ComponentStore(const std::shared_ptr<C2ComponentStore>& store)
+ : mConfigurable{new CachedConfigurable(std::make_unique<StoreIntf>(store))},
+ mParameterCache{std::make_shared<StoreParameterCache>(this)},
+ mStore{store} {
+
+ std::shared_ptr<C2ComponentStore> platformStore = android::GetCodec2PlatformComponentStore();
+ SetPreferredCodec2ComponentStore(store);
+
+ // Retrieve struct descriptors
+ mParamReflector = mStore->getParamReflector();
+
+ // Retrieve supported parameters from store
+ using namespace std::placeholders;
+ mInit = mConfigurable->init(mParameterCache);
+}
+
+ComponentStore::~ComponentStore() {
+ mParameterCache->onStoreDestroyed();
+}
+
+c2_status_t ComponentStore::status() const {
+ return mInit;
+}
+
+c2_status_t ComponentStore::validateSupportedParams(
+ const std::vector<std::shared_ptr<C2ParamDescriptor>>& params) {
+ c2_status_t res = C2_OK;
+
+ for (const std::shared_ptr<C2ParamDescriptor> &desc : params) {
+ if (!desc) {
+ // All descriptors should be valid
+ res = res ? res : C2_BAD_VALUE;
+ continue;
+ }
+ C2Param::CoreIndex coreIndex = desc->index().coreIndex();
+ std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
+ auto it = mStructDescriptors.find(coreIndex);
+ if (it == mStructDescriptors.end()) {
+ std::shared_ptr<C2StructDescriptor> structDesc =
+ mParamReflector->describe(coreIndex);
+ if (!structDesc) {
+ // All supported params must be described
+ res = C2_BAD_INDEX;
+ }
+ mStructDescriptors.insert({ coreIndex, structDesc });
+ }
+ }
+ return res;
+}
+
+std::shared_ptr<ParameterCache> ComponentStore::getParameterCache() const {
+ return mParameterCache;
+}
+
+// Methods from ::android::hardware::media::c2::V1_0::IComponentStore
+Return<void> ComponentStore::createComponent(
+ const hidl_string& name,
+ const sp<IComponentListener>& listener,
+ const sp<IClientManager>& pool,
+ createComponent_cb _hidl_cb) {
+
+ sp<Component> component;
+ std::shared_ptr<C2Component> c2component;
+ Status status = static_cast<Status>(
+ mStore->createComponent(name, &c2component));
+
+ if (status == Status::OK) {
+ onInterfaceLoaded(c2component->intf());
+ component = new Component(c2component, listener, this, pool);
+ if (!component) {
+ status = Status::CORRUPTED;
+ } else {
+ reportComponentBirth(component.get());
+ if (component->status() != C2_OK) {
+ status = static_cast<Status>(component->status());
+ } else {
+ component->initListener(component);
+ if (component->status() != C2_OK) {
+ status = static_cast<Status>(component->status());
+ }
+ }
+ }
+ }
+ _hidl_cb(status, component);
+ return Void();
+}
+
+Return<void> ComponentStore::createInterface(
+ const hidl_string& name,
+ createInterface_cb _hidl_cb) {
+ std::shared_ptr<C2ComponentInterface> c2interface;
+ c2_status_t res = mStore->createInterface(name, &c2interface);
+ sp<IComponentInterface> interface;
+ if (res == C2_OK) {
+ onInterfaceLoaded(c2interface);
+ interface = new ComponentInterface(c2interface, mParameterCache);
+ }
+ _hidl_cb(static_cast<Status>(res), interface);
+ return Void();
+}
+
+Return<void> ComponentStore::listComponents(listComponents_cb _hidl_cb) {
+ std::vector<std::shared_ptr<const C2Component::Traits>> c2traits =
+ mStore->listComponents();
+ hidl_vec<IComponentStore::ComponentTraits> traits(c2traits.size());
+ size_t ix = 0;
+ for (const std::shared_ptr<const C2Component::Traits> &c2trait : c2traits) {
+ if (c2trait) {
+ if (objcpy(&traits[ix], *c2trait)) {
+ ++ix;
+ } else {
+ break;
+ }
+ }
+ }
+ traits.resize(ix);
+ _hidl_cb(Status::OK, traits);
+ return Void();
+}
+
+Return<void> ComponentStore::createInputSurface(createInputSurface_cb _hidl_cb) {
+ sp<GraphicBufferSource> source = new GraphicBufferSource();
+ if (source->initCheck() != OK) {
+ _hidl_cb(Status::CORRUPTED, nullptr);
+ return Void();
+ }
+ using namespace std::placeholders;
+ sp<InputSurface> inputSurface = new InputSurface(
+ mParameterCache,
+ std::make_shared<C2ReflectorHelper>(),
+ source->getHGraphicBufferProducer(),
+ source);
+ _hidl_cb(inputSurface ? Status::OK : Status::NO_MEMORY,
+ inputSurface);
+ return Void();
+}
+
+void ComponentStore::onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf) {
+ // invalidate unsupported struct descriptors if a new interface is loaded as it may have
+ // exposed new descriptors
+ std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
+ if (!mLoadedInterfaces.count(intf->getName())) {
+ mUnsupportedStructDescriptors.clear();
+ mLoadedInterfaces.emplace(intf->getName());
+ }
+}
+
+Return<void> ComponentStore::getStructDescriptors(
+ const hidl_vec<uint32_t>& indices,
+ getStructDescriptors_cb _hidl_cb) {
+ hidl_vec<StructDescriptor> descriptors(indices.size());
+ size_t dstIx = 0;
+ Status res = Status::OK;
+ for (size_t srcIx = 0; srcIx < indices.size(); ++srcIx) {
+ std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
+ const C2Param::CoreIndex coreIndex = C2Param::CoreIndex(indices[srcIx]).coreIndex();
+ const auto item = mStructDescriptors.find(coreIndex);
+ if (item == mStructDescriptors.end()) {
+ // not in the cache, and not known to be unsupported, query local reflector
+ if (!mUnsupportedStructDescriptors.count(coreIndex)) {
+ std::shared_ptr<C2StructDescriptor> structDesc =
+ mParamReflector->describe(coreIndex);
+ if (!structDesc) {
+ mUnsupportedStructDescriptors.emplace(coreIndex);
+ } else {
+ mStructDescriptors.insert({ coreIndex, structDesc });
+ if (objcpy(&descriptors[dstIx], *structDesc)) {
+ ++dstIx;
+ continue;
+ }
+ res = Status::CORRUPTED;
+ break;
+ }
+ }
+ res = Status::NOT_FOUND;
+ } else if (item->second) {
+ if (objcpy(&descriptors[dstIx], *item->second)) {
+ ++dstIx;
+ continue;
+ }
+ res = Status::CORRUPTED;
+ break;
+ } else {
+ res = Status::NO_MEMORY;
+ break;
+ }
+ }
+ descriptors.resize(dstIx);
+ _hidl_cb(res, descriptors);
+ return Void();
+}
+
+Return<sp<IClientManager>> ComponentStore::getPoolClientManager() {
+ return ClientManager::getInstance();
+}
+
+Return<Status> ComponentStore::copyBuffer(const Buffer& src, const Buffer& dst) {
+ // TODO implement
+ (void)src;
+ (void)dst;
+ return Status::OMITTED;
+}
+
+Return<sp<IConfigurable>> ComponentStore::getConfigurable() {
+ return mConfigurable;
+}
+
+// Methods from ::android::hardware::media::c2::V1_1::IComponentStore
+Return<void> ComponentStore::createComponent_1_1(
+ const hidl_string& name,
+ const sp<IComponentListener>& listener,
+ const sp<IClientManager>& pool,
+ createComponent_1_1_cb _hidl_cb) {
+
+ sp<Component> component;
+ std::shared_ptr<C2Component> c2component;
+ Status status = static_cast<Status>(
+ mStore->createComponent(name, &c2component));
+
+ if (status == Status::OK) {
+ onInterfaceLoaded(c2component->intf());
+ component = new Component(c2component, listener, this, pool);
+ if (!component) {
+ status = Status::CORRUPTED;
+ } else {
+ reportComponentBirth(component.get());
+ if (component->status() != C2_OK) {
+ status = static_cast<Status>(component->status());
+ } else {
+ component->initListener(component);
+ if (component->status() != C2_OK) {
+ status = static_cast<Status>(component->status());
+ }
+ }
+ }
+ }
+ _hidl_cb(status, component);
+ return Void();
+}
+
+// Called from createComponent() after a successful creation of `component`.
+void ComponentStore::reportComponentBirth(Component* component) {
+ ComponentStatus componentStatus;
+ componentStatus.c2Component = component->mComponent;
+ componentStatus.birthTime = std::chrono::system_clock::now();
+
+ std::lock_guard<std::mutex> lock(mComponentRosterMutex);
+ mComponentRoster.emplace(component, componentStatus);
+}
+
+// Called from within the destructor of `component`. No virtual function calls
+// are made on `component` here.
+void ComponentStore::reportComponentDeath(Component* component) {
+ std::lock_guard<std::mutex> lock(mComponentRosterMutex);
+ mComponentRoster.erase(component);
+}
+
+// Dumps component traits.
+std::ostream& ComponentStore::dump(
+ std::ostream& out,
+ const std::shared_ptr<const C2Component::Traits>& comp) {
+
+ constexpr const char indent[] = " ";
+
+ out << indent << "name: " << comp->name << std::endl;
+ out << indent << "domain: " << comp->domain << std::endl;
+ out << indent << "kind: " << comp->kind << std::endl;
+ out << indent << "rank: " << comp->rank << std::endl;
+ out << indent << "mediaType: " << comp->mediaType << std::endl;
+ out << indent << "aliases:";
+ for (const auto& alias : comp->aliases) {
+ out << ' ' << alias;
+ }
+ out << std::endl;
+
+ return out;
+}
+
+// Dumps component status.
+std::ostream& ComponentStore::dump(
+ std::ostream& out,
+ ComponentStatus& compStatus) {
+
+ constexpr const char indent[] = " ";
+
+ // Print birth time.
+ std::chrono::milliseconds ms =
+ std::chrono::duration_cast<std::chrono::milliseconds>(
+ compStatus.birthTime.time_since_epoch());
+ std::time_t birthTime = std::chrono::system_clock::to_time_t(
+ compStatus.birthTime);
+ std::tm tm = *std::localtime(&birthTime);
+ out << indent << "Creation time: "
+ << std::put_time(&tm, "%Y-%m-%d %H:%M:%S")
+ << '.' << std::setfill('0') << std::setw(3) << ms.count() % 1000
+ << std::endl;
+
+ // Print name and id.
+ std::shared_ptr<C2ComponentInterface> intf = compStatus.c2Component->intf();
+ if (!intf) {
+ out << indent << "Unknown component -- null interface" << std::endl;
+ return out;
+ }
+ out << indent << "Name: " << intf->getName() << std::endl;
+ out << indent << "Id: " << intf->getId() << std::endl;
+
+ return out;
+}
+
+// Dumps information when lshal is called.
+Return<void> ComponentStore::debug(
+ const hidl_handle& handle,
+ const hidl_vec<hidl_string>& /* args */) {
+ LOG(INFO) << "debug -- dumping...";
+ const native_handle_t *h = handle.getNativeHandle();
+ if (!h || h->numFds != 1) {
+ LOG(ERROR) << "debug -- dumping failed -- "
+ "invalid file descriptor to dump to";
+ return Void();
+ }
+ std::ostringstream out;
+
+ { // Populate "out".
+
+ constexpr const char indent[] = " ";
+
+ // Show name.
+ out << "Beginning of dump -- C2ComponentStore: "
+ << mStore->getName() << std::endl << std::endl;
+
+ // Retrieve the list of supported components.
+ std::vector<std::shared_ptr<const C2Component::Traits>> traitsList =
+ mStore->listComponents();
+
+ // Dump the traits of supported components.
+ out << indent << "Supported components:" << std::endl << std::endl;
+ if (traitsList.size() == 0) {
+ out << indent << indent << "NONE" << std::endl << std::endl;
+ } else {
+ for (const auto& traits : traitsList) {
+ dump(out, traits) << std::endl;
+ }
+ }
+
+ // Dump active components.
+ {
+ out << indent << "Active components:" << std::endl << std::endl;
+ std::lock_guard<std::mutex> lock(mComponentRosterMutex);
+ if (mComponentRoster.size() == 0) {
+ out << indent << indent << "NONE" << std::endl << std::endl;
+ } else {
+ for (auto& pair : mComponentRoster) {
+ dump(out, pair.second) << std::endl;
+ }
+ }
+ }
+
+ out << "End of dump -- C2ComponentStore: "
+ << mStore->getName() << std::endl;
+ }
+
+ if (!android::base::WriteStringToFd(out.str(), h->data[0])) {
+ PLOG(WARNING) << "debug -- dumping failed -- write()";
+ } else {
+ LOG(INFO) << "debug -- dumping succeeded";
+ }
+ return Void();
+}
+
+} // namespace utils
+} // namespace V1_1
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
diff --git a/media/codec2/hidl/1.1/utils/Configurable.cpp b/media/codec2/hidl/1.1/utils/Configurable.cpp
new file mode 100644
index 0000000..1f3b2c7
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/Configurable.cpp
@@ -0,0 +1,17 @@
+/*
+ * Copyright 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.
+ */
+
+#include <codec2/hidl/1.1/Configurable.h>
diff --git a/media/codec2/hidl/1.1/utils/InputBufferManager.cpp b/media/codec2/hidl/1.1/utils/InputBufferManager.cpp
new file mode 100644
index 0000000..45bfc86
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/InputBufferManager.cpp
@@ -0,0 +1,17 @@
+/*
+ * Copyright 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.
+ */
+
+#include <codec2/hidl/1.1/InputBufferManager.h>
diff --git a/media/codec2/hidl/1.1/utils/InputSurface.cpp b/media/codec2/hidl/1.1/utils/InputSurface.cpp
new file mode 100644
index 0000000..ce40494
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/InputSurface.cpp
@@ -0,0 +1,17 @@
+/*
+ * Copyright 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.
+ */
+
+#include <codec2/hidl/1.1/InputSurface.h>
diff --git a/media/codec2/hidl/1.1/utils/InputSurfaceConnection.cpp b/media/codec2/hidl/1.1/utils/InputSurfaceConnection.cpp
new file mode 100644
index 0000000..32154a7
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/InputSurfaceConnection.cpp
@@ -0,0 +1,17 @@
+/*
+ * Copyright 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.
+ */
+
+#include <codec2/hidl/1.1/InputSurfaceConnection.h>
diff --git a/media/codec2/hidl/1.1/utils/OutputBufferQueue.cpp b/media/codec2/hidl/1.1/utils/OutputBufferQueue.cpp
new file mode 100644
index 0000000..65756e8
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/OutputBufferQueue.cpp
@@ -0,0 +1,17 @@
+/*
+ * Copyright 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.
+ */
+
+#include <codec2/hidl/1.1/OutputBufferQueue.h>
diff --git a/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/Component.h b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/Component.h
new file mode 100644
index 0000000..16c81d4
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/Component.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef CODEC2_HIDL_V1_1_UTILS_COMPONENT_H
+#define CODEC2_HIDL_V1_1_UTILS_COMPONENT_H
+
+#include <android/hardware/media/bufferpool/2.0/IClientManager.h>
+#include <android/hardware/media/c2/1.1/IComponent.h>
+#include <android/hardware/media/c2/1.0/IComponentInterface.h>
+#include <android/hardware/media/c2/1.0/IComponentListener.h>
+#include <android/hardware/media/c2/1.1/IComponentStore.h>
+#include <android/hardware/media/c2/1.0/IInputSink.h>
+#include <codec2/hidl/1.1/ComponentInterface.h>
+#include <codec2/hidl/1.1/Configurable.h>
+#include <codec2/hidl/1.1/types.h>
+#include <hidl/Status.h>
+#include <hwbinder/IBinder.h>
+
+#include <C2Component.h>
+#include <C2Buffer.h>
+#include <C2.h>
+
+#include <map>
+#include <memory>
+#include <mutex>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_1 {
+
+using ::android::hardware::media::c2::V1_1::IComponent;
+using ::android::hardware::media::c2::V1_0::IComponentListener;
+
+namespace utils {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::IBinder;
+using ::android::sp;
+using ::android::wp;
+
+struct ComponentStore;
+
+struct Component : public IComponent,
+ public std::enable_shared_from_this<Component> {
+ Component(
+ const std::shared_ptr<C2Component>&,
+ const sp<IComponentListener>& listener,
+ const sp<ComponentStore>& store,
+ const sp<::android::hardware::media::bufferpool::V2_0::
+ IClientManager>& clientPoolManager);
+ c2_status_t status() const;
+
+ typedef ::android::hardware::graphics::bufferqueue::V1_0::
+ IGraphicBufferProducer HGraphicBufferProducer1;
+ typedef ::android::hardware::graphics::bufferqueue::V2_0::
+ IGraphicBufferProducer HGraphicBufferProducer2;
+
+ // Methods from IComponent follow.
+ virtual Return<Status> queue(const WorkBundle& workBundle) override;
+ virtual Return<void> flush(flush_cb _hidl_cb) override;
+ virtual Return<Status> drain(bool withEos) override;
+ virtual Return<Status> setOutputSurface(
+ uint64_t blockPoolId,
+ const sp<HGraphicBufferProducer2>& surface) override;
+ virtual Return<void> connectToInputSurface(
+ const sp<IInputSurface>& inputSurface,
+ connectToInputSurface_cb _hidl_cb) override;
+ virtual Return<void> connectToOmxInputSurface(
+ const sp<HGraphicBufferProducer1>& producer,
+ const sp<::android::hardware::media::omx::V1_0::
+ IGraphicBufferSource>& source,
+ connectToOmxInputSurface_cb _hidl_cb) override;
+ virtual Return<Status> disconnectFromInputSurface() override;
+ virtual Return<void> createBlockPool(
+ uint32_t allocatorId,
+ createBlockPool_cb _hidl_cb) override;
+ virtual Return<Status> destroyBlockPool(uint64_t blockPoolId) override;
+ virtual Return<Status> start() override;
+ virtual Return<Status> stop() override;
+ virtual Return<Status> reset() override;
+ virtual Return<Status> release() override;
+ virtual Return<sp<IComponentInterface>> getInterface() override;
+ virtual Return<sp<IInputSink>> asInputSink() override;
+ virtual Return<void> configureVideoTunnel(
+ uint32_t avSyncHwId, configureVideoTunnel_cb _hidl_cb) override;
+
+ // Returns a C2Component associated to the given sink if the sink is indeed
+ // a local component. Returns nullptr otherwise.
+ //
+ // This function is used by InputSurface::connect().
+ static std::shared_ptr<C2Component> findLocalComponent(
+ const sp<IInputSink>& sink);
+
+protected:
+ c2_status_t mInit;
+ std::shared_ptr<C2Component> mComponent;
+ sp<ComponentInterface> mInterface;
+ sp<IComponentListener> mListener;
+ sp<ComponentStore> mStore;
+ ::android::hardware::media::c2::V1_1::utils::DefaultBufferPoolSender
+ mBufferPoolSender;
+
+ struct Sink;
+ std::mutex mSinkMutex;
+ sp<Sink> mSink;
+
+ std::mutex mBlockPoolsMutex;
+ // This map keeps C2BlockPool objects that are created by createBlockPool()
+ // alive. These C2BlockPool objects can be deleted by calling
+ // destroyBlockPool(), reset() or release(), or by destroying the component.
+ std::map<uint64_t, std::shared_ptr<C2BlockPool>> mBlockPools;
+
+ void initListener(const sp<Component>& self);
+
+ virtual ~Component() override;
+
+ friend struct ComponentStore;
+
+ struct Listener;
+};
+
+} // namespace utils
+} // namespace V1_1
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // CODEC2_HIDL_V1_1_UTILS_COMPONENT_H
diff --git a/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentInterface.h b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentInterface.h
new file mode 100644
index 0000000..723c5bd
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentInterface.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef CODEC2_HIDL_V1_1_UTILS_COMPONENT_INTERFACE_H
+#define CODEC2_HIDL_V1_1_UTILS_COMPONENT_INTERFACE_H
+
+#include <codec2/hidl/1.0/ComponentInterface.h>
+#include <codec2/hidl/1.1/types.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_1 {
+namespace utils {
+
+using ::android::hardware::media::c2::V1_0::utils::ComponentInterface;
+
+} // namespace utils
+} // namespace V1_1
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // CODEC2_HIDL_V1_1_UTILS_COMPONENT_INTERFACE_H
diff --git a/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentStore.h b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentStore.h
new file mode 100644
index 0000000..1f04391
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentStore.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef CODEC2_HIDL_V1_1_UTILS_COMPONENT_STORE_H
+#define CODEC2_HIDL_V1_1_UTILS_COMPONENT_STORE_H
+
+#include <codec2/hidl/1.1/Component.h>
+#include <codec2/hidl/1.1/ComponentInterface.h>
+#include <codec2/hidl/1.1/Configurable.h>
+#include <codec2/hidl/1.1/types.h>
+
+#include <android/hardware/media/bufferpool/2.0/IClientManager.h>
+#include <android/hardware/media/c2/1.1/IComponentStore.h>
+#include <hidl/Status.h>
+
+#include <C2Component.h>
+#include <C2Param.h>
+#include <C2.h>
+
+#include <chrono>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <set>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_1 {
+namespace utils {
+
+using ::android::hardware::media::bufferpool::V2_0::IClientManager;
+
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct ComponentStore : public IComponentStore {
+ ComponentStore(const std::shared_ptr<C2ComponentStore>& store);
+ virtual ~ComponentStore();
+
+ /**
+ * Returns the status of the construction of this object.
+ */
+ c2_status_t status() const;
+
+ /**
+ * This function is called by CachedConfigurable::init() to validate
+ * supported parameters.
+ */
+ c2_status_t validateSupportedParams(
+ const std::vector<std::shared_ptr<C2ParamDescriptor>>& params);
+
+ /**
+ * Returns the store's ParameterCache. This is used for validation by
+ * Configurable::init().
+ */
+ std::shared_ptr<ParameterCache> getParameterCache() const;
+
+ // Methods from ::android::hardware::media::c2::V1_0::IComponentStore.
+ virtual Return<void> createComponent(
+ const hidl_string& name,
+ const sp<IComponentListener>& listener,
+ const sp<IClientManager>& pool,
+ createComponent_cb _hidl_cb) override;
+ virtual Return<void> createInterface(
+ const hidl_string& name,
+ createInterface_cb _hidl_cb) override;
+ virtual Return<void> listComponents(listComponents_cb _hidl_cb) override;
+ virtual Return<void> createInputSurface(
+ createInputSurface_cb _hidl_cb) override;
+ virtual Return<void> getStructDescriptors(
+ const hidl_vec<uint32_t>& indices,
+ getStructDescriptors_cb _hidl_cb) override;
+ virtual Return<sp<IClientManager>> getPoolClientManager() override;
+ virtual Return<Status> copyBuffer(
+ const Buffer& src,
+ const Buffer& dst) override;
+ virtual Return<sp<IConfigurable>> getConfigurable() override;
+
+ // Methods from ::android::hardware::media::c2::V1_1::IComponentStore.
+ virtual Return<void> createComponent_1_1(
+ const hidl_string& name,
+ const sp<IComponentListener>& listener,
+ const sp<IClientManager>& pool,
+ createComponent_1_1_cb _hidl_cb) override;
+
+ /**
+ * Dumps information when lshal is called.
+ */
+ virtual Return<void> debug(
+ const hidl_handle& handle,
+ const hidl_vec<hidl_string>& args) override;
+
+protected:
+ sp<CachedConfigurable> mConfigurable;
+ struct StoreParameterCache;
+ std::shared_ptr<StoreParameterCache> mParameterCache;
+
+ // Does bookkeeping for an interface that has been loaded.
+ void onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf);
+
+ c2_status_t mInit;
+ std::shared_ptr<C2ComponentStore> mStore;
+ std::shared_ptr<C2ParamReflector> mParamReflector;
+
+ std::map<C2Param::CoreIndex, std::shared_ptr<C2StructDescriptor>> mStructDescriptors;
+ std::set<C2Param::CoreIndex> mUnsupportedStructDescriptors;
+ std::set<C2String> mLoadedInterfaces;
+ mutable std::mutex mStructDescriptorsMutex;
+
+ // ComponentStore keeps track of live Components.
+
+ struct ComponentStatus {
+ std::shared_ptr<C2Component> c2Component;
+ std::chrono::system_clock::time_point birthTime;
+ };
+
+ mutable std::mutex mComponentRosterMutex;
+ std::map<Component*, ComponentStatus> mComponentRoster;
+
+ // Called whenever Component is created.
+ void reportComponentBirth(Component* component);
+ // Called only from the destructor of Component.
+ void reportComponentDeath(Component* component);
+
+ friend Component;
+
+ // Helper functions for dumping.
+
+ std::ostream& dump(
+ std::ostream& out,
+ const std::shared_ptr<const C2Component::Traits>& comp);
+
+ std::ostream& dump(
+ std::ostream& out,
+ ComponentStatus& compStatus);
+
+};
+
+} // namespace utils
+} // namespace V1_1
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // CODEC2_HIDL_V1_1_UTILS_COMPONENT_STORE_H
diff --git a/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/Configurable.h b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/Configurable.h
new file mode 100644
index 0000000..fd9091b
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/Configurable.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef CODEC2_HIDL_V1_1_UTILS_CONFIGURABLE_H
+#define CODEC2_HIDL_V1_1_UTILS_CONFIGURABLE_H
+
+#include <codec2/hidl/1.0/Configurable.h>
+#include <codec2/hidl/1.1/types.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_1 {
+namespace utils {
+
+using ::android::hardware::media::c2::V1_0::utils::ConfigurableC2Intf;
+using ::android::hardware::media::c2::V1_0::utils::ParameterCache;
+using ::android::hardware::media::c2::V1_0::utils::CachedConfigurable;
+
+} // namespace utils
+} // namespace V1_1
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // CODEC2_HIDL_V1_1_UTILS_CONFIGURABLE_H
diff --git a/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/InputBufferManager.h b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/InputBufferManager.h
new file mode 100644
index 0000000..8e7a91b
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/InputBufferManager.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef CODEC2_HIDL_V1_1_UTILS_INPUT_BUFFER_MANAGER_H
+#define CODEC2_HIDL_V1_1_UTILS_INPUT_BUFFER_MANAGER_H
+
+#include <codec2/hidl/1.0/InputBufferManager.h>
+#include <codec2/hidl/1.1/types.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_1 {
+namespace utils {
+
+using ::android::hardware::media::c2::V1_0::utils::InputBufferManager;
+
+} // namespace utils
+} // namespace V1_1
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // CODEC2_HIDL_V1_1_UTILS_INPUT_BUFFER_MANAGER_H
diff --git a/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/InputSurface.h b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/InputSurface.h
new file mode 100644
index 0000000..59223b7
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/InputSurface.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef CODEC2_HIDL_V1_1_UTILS_INPUT_SURFACE_H
+#define CODEC2_HIDL_V1_1_UTILS_INPUT_SURFACE_H
+
+#include <codec2/hidl/1.0/InputSurface.h>
+#include <codec2/hidl/1.1/types.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_1 {
+namespace utils {
+
+using ::android::hardware::media::c2::V1_0::utils::InputSurface;
+
+} // namespace utils
+} // namespace V1_1
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // CODEC2_HIDL_V1_1_UTILS_INPUT_SURFACE_H
diff --git a/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/InputSurfaceConnection.h b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/InputSurfaceConnection.h
new file mode 100644
index 0000000..7f695ef
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/InputSurfaceConnection.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef CODEC2_HIDL_V1_1_UTILS_INPUT_SURFACE_CONNECTION_H
+#define CODEC2_HIDL_V1_1_UTILS_INPUT_SURFACE_CONNECTION_H
+
+#include <codec2/hidl/1.0/InputSurfaceConnection.h>
+#include <codec2/hidl/1.1/types.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_1 {
+namespace utils {
+
+using ::android::hardware::media::c2::V1_0::utils::InputSurfaceConnection;
+
+} // namespace utils
+} // namespace V1_1
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // CODEC2_HIDL_V1_1_UTILS_INPUT_SURFACE_CONNECTION_H
diff --git a/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/OutputBufferQueue.h b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/OutputBufferQueue.h
new file mode 100644
index 0000000..f77852d
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/OutputBufferQueue.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef CODEC2_HIDL_V1_1_UTILS_OUTPUT_BUFFER_QUEUE
+#define CODEC2_HIDL_V1_1_UTILS_OUTPUT_BUFFER_QUEUE
+
+#include <codec2/hidl/1.0/OutputBufferQueue.h>
+#include <codec2/hidl/1.1/types.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_1 {
+namespace utils {
+
+using ::android::hardware::media::c2::V1_0::utils::OutputBufferQueue;
+
+} // namespace utils
+} // namespace V1_1
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // CODEC2_HIDL_V1_1_UTILS_OUTPUT_BUFFER_QUEUE
diff --git a/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/types.h b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/types.h
new file mode 100644
index 0000000..d0ba93d
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/types.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef CODEC2_HIDL_V1_1_UTILS_TYPES_H
+#define CODEC2_HIDL_V1_1_UTILS_TYPES_H
+
+#include <android/hardware/media/c2/1.1/IComponent.h>
+#include <android/hardware/media/c2/1.0/IComponentInterface.h>
+#include <android/hardware/media/c2/1.0/IComponentListener.h>
+#include <android/hardware/media/c2/1.1/IComponentStore.h>
+#include <android/hardware/media/c2/1.0/IConfigurable.h>
+#include <android/hardware/media/c2/1.0/IInputSink.h>
+#include <android/hardware/media/c2/1.0/IInputSurface.h>
+#include <android/hardware/media/c2/1.0/IInputSurfaceConnection.h>
+
+#include <codec2/hidl/1.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_1 {
+
+using ::android::hardware::media::c2::V1_0::BaseBlock;
+using ::android::hardware::media::c2::V1_0::Block;
+using ::android::hardware::media::c2::V1_0::Buffer;
+using ::android::hardware::media::c2::V1_0::FieldDescriptor;
+using ::android::hardware::media::c2::V1_0::FieldId;
+using ::android::hardware::media::c2::V1_0::FieldSupportedValues;
+using ::android::hardware::media::c2::V1_0::FieldSupportedValuesQuery;
+using ::android::hardware::media::c2::V1_0::FieldSupportedValuesQueryResult;
+using ::android::hardware::media::c2::V1_0::FrameData;
+using ::android::hardware::media::c2::V1_0::InfoBuffer;
+using ::android::hardware::media::c2::V1_0::ParamDescriptor;
+using ::android::hardware::media::c2::V1_0::ParamField;
+using ::android::hardware::media::c2::V1_0::ParamFieldValues;
+using ::android::hardware::media::c2::V1_0::ParamIndex;
+using ::android::hardware::media::c2::V1_0::Params;
+using ::android::hardware::media::c2::V1_0::PrimitiveValue;
+using ::android::hardware::media::c2::V1_0::SettingResult;
+using ::android::hardware::media::c2::V1_0::Status;
+using ::android::hardware::media::c2::V1_0::StructDescriptor;
+using ::android::hardware::media::c2::V1_0::ValueRange;
+using ::android::hardware::media::c2::V1_0::Work;
+using ::android::hardware::media::c2::V1_0::WorkBundle;
+using ::android::hardware::media::c2::V1_0::WorkOrdinal;
+using ::android::hardware::media::c2::V1_0::Worklet;
+
+using ::android::hardware::media::c2::V1_0::IComponentInterface;
+using ::android::hardware::media::c2::V1_0::IComponentListener;
+using ::android::hardware::media::c2::V1_0::IConfigurable;
+using ::android::hardware::media::c2::V1_0::IInputSink;
+using ::android::hardware::media::c2::V1_0::IInputSurface;
+using ::android::hardware::media::c2::V1_0::IInputSurfaceConnection;
+
+namespace utils {
+
+using ::android::hardware::media::c2::V1_0::utils::toC2Status;
+
+using ::android::hardware::media::c2::V1_0::utils::C2Hidl_Range;
+using ::android::hardware::media::c2::V1_0::utils::C2Hidl_RangeInfo;
+using ::android::hardware::media::c2::V1_0::utils::C2Hidl_Rect;
+using ::android::hardware::media::c2::V1_0::utils::C2Hidl_RectInfo;
+
+using ::android::hardware::media::c2::V1_0::utils::objcpy;
+using ::android::hardware::media::c2::V1_0::utils::parseParamsBlob;
+using ::android::hardware::media::c2::V1_0::utils::createParamsBlob;
+using ::android::hardware::media::c2::V1_0::utils::copyParamsFromBlob;
+using ::android::hardware::media::c2::V1_0::utils::updateParamsFromBlob;
+
+using ::android::hardware::media::c2::V1_0::utils::BufferPoolSender;
+using ::android::hardware::media::c2::V1_0::utils::DefaultBufferPoolSender;
+
+using ::android::hardware::media::c2::V1_0::utils::beginTransferBufferQueueBlock;
+using ::android::hardware::media::c2::V1_0::utils::beginTransferBufferQueueBlocks;
+using ::android::hardware::media::c2::V1_0::utils::endTransferBufferQueueBlock;
+using ::android::hardware::media::c2::V1_0::utils::endTransferBufferQueueBlocks;
+using ::android::hardware::media::c2::V1_0::utils::displayBufferQueueBlock;
+
+using ::android::hardware::media::c2::V1_0::utils::operator<<;
+
+} // namespace utils
+} // namespace V1_1
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // CODEC2_HIDL_V1_1_UTILS_TYPES_H
diff --git a/media/codec2/hidl/1.1/utils/types.cpp b/media/codec2/hidl/1.1/utils/types.cpp
new file mode 100644
index 0000000..8c09023
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/types.cpp
@@ -0,0 +1,17 @@
+/*
+ * Copyright 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.
+ */
+
+#include <codec2/hidl/1.1/types.h>
diff --git a/media/codec2/hidl/client/Android.bp b/media/codec2/hidl/client/Android.bp
index e184223..3c37990 100644
--- a/media/codec2/hidl/client/Android.bp
+++ b/media/codec2/hidl/client/Android.bp
@@ -9,15 +9,16 @@
"android.hardware.graphics.bufferqueue@1.0",
"android.hardware.media.bufferpool@2.0",
"android.hardware.media.c2@1.0",
+ "android.hardware.media.c2@1.1",
"libbase",
"libbinder",
"libcodec2",
"libcodec2_hidl_client@1.0",
+ "libcodec2_hidl_client@1.1",
"libcodec2_vndk",
"libcutils",
"libgui",
"libhidlbase",
- "libhidltransport",
"liblog",
"libstagefright_bufferpool@2.0.1",
"libui",
@@ -29,8 +30,11 @@
],
export_shared_lib_headers: [
+ "android.hardware.media.c2@1.0",
+ "android.hardware.media.c2@1.1",
"libcodec2",
"libcodec2_hidl_client@1.0",
+ "libcodec2_hidl_client@1.1",
"libcodec2_vndk",
],
diff --git a/media/codec2/hidl/client/client.cpp b/media/codec2/hidl/client/client.cpp
index c747190..0acab49 100644
--- a/media/codec2/hidl/client/client.cpp
+++ b/media/codec2/hidl/client/client.cpp
@@ -19,6 +19,29 @@
#include <android-base/logging.h>
#include <codec2/hidl/client.h>
+#include <C2Debug.h>
+#include <C2BufferPriv.h>
+#include <C2PlatformSupport.h>
+
+#include <android/hardware/media/bufferpool/2.0/IClientManager.h>
+#include <android/hardware/media/c2/1.0/IComponent.h>
+#include <android/hardware/media/c2/1.0/IComponentInterface.h>
+#include <android/hardware/media/c2/1.0/IComponentListener.h>
+#include <android/hardware/media/c2/1.0/IComponentStore.h>
+#include <android/hardware/media/c2/1.0/IConfigurable.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+
+#include <android-base/properties.h>
+#include <bufferpool/ClientManager.h>
+#include <codec2/hidl/1.0/OutputBufferQueue.h>
+#include <codec2/hidl/1.0/types.h>
+#include <codec2/hidl/1.1/OutputBufferQueue.h>
+#include <codec2/hidl/1.1/types.h>
+
+#include <cutils/native_handle.h>
+#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
+#include <gui/bufferqueue/2.0/H2BGraphicBufferProducer.h>
+#include <hidl/HidlSupport.h>
#include <deque>
#include <iterator>
@@ -30,25 +53,6 @@
#include <type_traits>
#include <vector>
-#include <android-base/properties.h>
-#include <bufferpool/ClientManager.h>
-#include <cutils/native_handle.h>
-#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
-#include <gui/bufferqueue/2.0/H2BGraphicBufferProducer.h>
-#include <hidl/HidlSupport.h>
-
-#include <android/hardware/media/bufferpool/2.0/IClientManager.h>
-#include <android/hardware/media/c2/1.0/IComponent.h>
-#include <android/hardware/media/c2/1.0/IComponentInterface.h>
-#include <android/hardware/media/c2/1.0/IComponentListener.h>
-#include <android/hardware/media/c2/1.0/IComponentStore.h>
-#include <android/hardware/media/c2/1.0/IConfigurable.h>
-#include <android/hidl/manager/1.2/IServiceManager.h>
-
-#include <C2Debug.h>
-#include <C2BufferPriv.h>
-#include <C2PlatformSupport.h>
-
namespace android {
using ::android::hardware::hidl_vec;
@@ -56,8 +60,8 @@
using ::android::hardware::Return;
using ::android::hardware::Void;
-using namespace ::android::hardware::media::c2::V1_0;
-using namespace ::android::hardware::media::c2::V1_0::utils;
+using namespace ::android::hardware::media::c2::V1_1;
+using namespace ::android::hardware::media::c2::V1_1::utils;
using namespace ::android::hardware::media::bufferpool::V2_0;
using namespace ::android::hardware::media::bufferpool::V2_0::implementation;
@@ -89,6 +93,69 @@
return i;
}
+class Client2Store : public C2ComponentStore {
+ std::shared_ptr<Codec2Client> mClient;
+
+public:
+ Client2Store(std::shared_ptr<Codec2Client> const& client)
+ : mClient(client) { }
+
+ virtual ~Client2Store() = default;
+
+ virtual c2_status_t config_sm(
+ std::vector<C2Param*> const ¶ms,
+ std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
+ return mClient->config(params, C2_MAY_BLOCK, failures);
+ };
+
+ virtual c2_status_t copyBuffer(
+ std::shared_ptr<C2GraphicBuffer>,
+ std::shared_ptr<C2GraphicBuffer>) {
+ return C2_OMITTED;
+ }
+
+ virtual c2_status_t createComponent(
+ C2String, std::shared_ptr<C2Component>* const component) {
+ component->reset();
+ return C2_OMITTED;
+ }
+
+ virtual c2_status_t createInterface(
+ C2String, std::shared_ptr<C2ComponentInterface>* const interface) {
+ interface->reset();
+ return C2_OMITTED;
+ }
+
+ virtual c2_status_t query_sm(
+ std::vector<C2Param*> const& stackParams,
+ std::vector<C2Param::Index> const& heapParamIndices,
+ std::vector<std::unique_ptr<C2Param>>* const heapParams) const {
+ return mClient->query(stackParams, heapParamIndices, C2_MAY_BLOCK, heapParams);
+ }
+
+ virtual c2_status_t querySupportedParams_nb(
+ std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const {
+ return mClient->querySupportedParams(params);
+ }
+
+ virtual c2_status_t querySupportedValues_sm(
+ std::vector<C2FieldSupportedValuesQuery>& fields) const {
+ return mClient->querySupportedValues(fields, C2_MAY_BLOCK);
+ }
+
+ virtual C2String getName() const {
+ return mClient->getName();
+ }
+
+ virtual std::shared_ptr<C2ParamReflector> getParamReflector() const {
+ return mClient->getParamReflector();
+ }
+
+ virtual std::vector<std::shared_ptr<C2Component::Traits const>> listComponents() {
+ return std::vector<std::shared_ptr<C2Component::Traits const>>();
+ }
+};
+
} // unnamed namespace
// This class caches a Codec2Client object and its component traits. The client
@@ -514,8 +581,24 @@
};
+// Codec2Client::Component::BufferPoolSender
+struct Codec2Client::Component::BufferPoolSender :
+ hardware::media::c2::V1_1::utils::DefaultBufferPoolSender {
+ BufferPoolSender()
+ : hardware::media::c2::V1_1::utils::DefaultBufferPoolSender() {
+ }
+};
+
+// Codec2Client::Component::OutputBufferQueue
+struct Codec2Client::Component::OutputBufferQueue :
+ hardware::media::c2::V1_1::utils::OutputBufferQueue {
+ OutputBufferQueue()
+ : hardware::media::c2::V1_1::utils::OutputBufferQueue() {
+ }
+};
+
// Codec2Client
-Codec2Client::Codec2Client(const sp<IComponentStore>& base,
+Codec2Client::Codec2Client(sp<Base> const& base,
size_t serviceIndex)
: Configurable{
[base]() -> sp<IConfigurable> {
@@ -526,7 +609,8 @@
nullptr;
}()
},
- mBase{base},
+ mBase1_0{base},
+ mBase1_1{Base1_1::castFrom(base)},
mServiceIndex{serviceIndex} {
Return<sp<IClientManager>> transResult = base->getPoolClientManager();
if (!transResult.isOk()) {
@@ -537,7 +621,15 @@
}
sp<Codec2Client::Base> const& Codec2Client::getBase() const {
- return mBase;
+ return mBase1_0;
+}
+
+sp<Codec2Client::Base1_0> const& Codec2Client::getBase1_0() const {
+ return mBase1_0;
+}
+
+sp<Codec2Client::Base1_1> const& Codec2Client::getBase1_1() const {
+ return mBase1_1;
}
std::string const& Codec2Client::getServiceName() const {
@@ -552,7 +644,8 @@
c2_status_t status;
sp<Component::HidlListener> hidlListener = new Component::HidlListener{};
hidlListener->base = listener;
- Return<void> transStatus = mBase->createComponent(
+ Return<void> transStatus = mBase1_1 ?
+ mBase1_1->createComponent_1_1(
name,
hidlListener,
ClientManager::getInstance(),
@@ -565,14 +658,33 @@
}
*component = std::make_shared<Codec2Client::Component>(c);
hidlListener->component = *component;
+ }) :
+ mBase1_0->createComponent(
+ name,
+ hidlListener,
+ ClientManager::getInstance(),
+ [&status, component, hidlListener](
+ Status s,
+ const sp<hardware::media::c2::V1_0::IComponent>& c) {
+ status = static_cast<c2_status_t>(s);
+ if (status != C2_OK) {
+ return;
+ }
+ *component = std::make_shared<Codec2Client::Component>(c);
+ hidlListener->component = *component;
});
if (!transStatus.isOk()) {
LOG(ERROR) << "createComponent(" << name.c_str()
<< ") -- transaction failed.";
return C2_TRANSACTION_FAILED;
} else if (status != C2_OK) {
- LOG(ERROR) << "createComponent(" << name.c_str()
- << ") -- call failed: " << status << ".";
+ if (status == C2_NOT_FOUND) {
+ LOG(VERBOSE) << "createComponent(" << name.c_str()
+ << ") -- component not found.";
+ } else {
+ LOG(ERROR) << "createComponent(" << name.c_str()
+ << ") -- call failed: " << status << ".";
+ }
return status;
} else if (!*component) {
LOG(ERROR) << "createComponent(" << name.c_str()
@@ -587,7 +699,7 @@
<< status << ".";
}
- (*component)->mBufferPoolSender.setReceiver(mHostPoolManager);
+ (*component)->mBufferPoolSender->setReceiver(mHostPoolManager);
return status;
}
@@ -595,7 +707,7 @@
const C2String& name,
std::shared_ptr<Codec2Client::Interface>* const interface) {
c2_status_t status;
- Return<void> transStatus = mBase->createInterface(
+ Return<void> transStatus = mBase1_0->createInterface(
name,
[&status, interface](
Status s,
@@ -611,8 +723,13 @@
<< ") -- transaction failed.";
return C2_TRANSACTION_FAILED;
} else if (status != C2_OK) {
- LOG(ERROR) << "createComponent(" << name.c_str()
- << ") -- call failed: " << status << ".";
+ if (status == C2_NOT_FOUND) {
+ LOG(VERBOSE) << "createInterface(" << name.c_str()
+ << ") -- component not found.";
+ } else {
+ LOG(ERROR) << "createInterface(" << name.c_str()
+ << ") -- call failed: " << status << ".";
+ }
return status;
}
@@ -622,7 +739,7 @@
c2_status_t Codec2Client::createInputSurface(
std::shared_ptr<InputSurface>* const inputSurface) {
c2_status_t status;
- Return<void> transStatus = mBase->createInputSurface(
+ Return<void> transStatus = mBase1_0->createInputSurface(
[&status, inputSurface](
Status s,
const sp<IInputSurface>& i) {
@@ -650,7 +767,7 @@
bool* success) const {
std::vector<C2Component::Traits> traits;
std::string const& serviceName = getServiceName();
- Return<void> transStatus = mBase->listComponents(
+ Return<void> transStatus = mBase1_0->listComponents(
[&traits, &serviceName](Status s,
const hidl_vec<IComponentStore::ComponentTraits>& t) {
if (s != Status::OK) {
@@ -734,7 +851,7 @@
sp<Base> mBase;
};
- return std::make_shared<SimpleParamReflector>(mBase);
+ return std::make_shared<SimpleParamReflector>(mBase1_0);
};
std::vector<std::string> const& Codec2Client::GetServiceNames() {
@@ -806,10 +923,24 @@
}
std::shared_ptr<Codec2Client> Codec2Client::CreateFromService(
- const char* name) {
+ const char* name,
+ bool setAsPreferredCodec2ComponentStore) {
size_t index = getServiceIndex(name);
- return index == GetServiceNames().size() ?
- nullptr : _CreateFromIndex(index);
+ if (index == GetServiceNames().size()) {
+ if (setAsPreferredCodec2ComponentStore) {
+ LOG(WARNING) << "CreateFromService(" << name
+ << ") -- preferred C2ComponentStore not set.";
+ }
+ return nullptr;
+ }
+ std::shared_ptr<Codec2Client> client = _CreateFromIndex(index);
+ if (setAsPreferredCodec2ComponentStore) {
+ SetPreferredCodec2ComponentStore(
+ std::make_shared<Client2Store>(client));
+ LOG(INFO) << "CreateFromService(" << name
+ << ") -- service set as preferred C2ComponentStore.";
+ }
+ return client;
}
std::vector<std::shared_ptr<Codec2Client>> Codec2Client::
@@ -825,11 +956,11 @@
std::shared_ptr<Codec2Client> Codec2Client::_CreateFromIndex(size_t index) {
std::string const& name = GetServiceNames()[index];
- LOG(INFO) << "Creating a Codec2 client to service \"" << name << "\"";
+ LOG(VERBOSE) << "Creating a Codec2 client to service \"" << name << "\"";
sp<Base> baseStore = Base::getService(name);
CHECK(baseStore) << "Codec2 service \"" << name << "\""
" inaccessible for unknown reasons.";
- LOG(INFO) << "Client to Codec2 service \"" << name << "\" created";
+ LOG(VERBOSE) << "Client to Codec2 service \"" << name << "\" created";
return std::make_shared<Codec2Client>(baseStore, index);
}
@@ -1053,8 +1184,32 @@
nullptr;
}()
},
- mBase{base},
- mBufferPoolSender{nullptr} {
+ mBase1_0{base},
+ mBase1_1{Base1_1::castFrom(base)},
+ mBufferPoolSender{std::make_unique<BufferPoolSender>()},
+ mOutputBufferQueue{std::make_unique<OutputBufferQueue>()} {
+}
+
+Codec2Client::Component::Component(const sp<Base1_1>& base)
+ : Configurable{
+ [base]() -> sp<IConfigurable> {
+ Return<sp<IComponentInterface>> transResult1 =
+ base->getInterface();
+ if (!transResult1.isOk()) {
+ return nullptr;
+ }
+ Return<sp<IConfigurable>> transResult2 =
+ static_cast<sp<IComponentInterface>>(transResult1)->
+ getConfigurable();
+ return transResult2.isOk() ?
+ static_cast<sp<IConfigurable>>(transResult2) :
+ nullptr;
+ }()
+ },
+ mBase1_0{base},
+ mBase1_1{base},
+ mBufferPoolSender{std::make_unique<BufferPoolSender>()},
+ mOutputBufferQueue{std::make_unique<OutputBufferQueue>()} {
}
Codec2Client::Component::~Component() {
@@ -1065,7 +1220,7 @@
C2BlockPool::local_id_t* blockPoolId,
std::shared_ptr<Codec2Client::Configurable>* configurable) {
c2_status_t status;
- Return<void> transStatus = mBase->createBlockPool(
+ Return<void> transStatus = mBase1_0->createBlockPool(
static_cast<uint32_t>(id),
[&status, blockPoolId, configurable](
Status s,
@@ -1090,7 +1245,7 @@
c2_status_t Codec2Client::Component::destroyBlockPool(
C2BlockPool::local_id_t localId) {
- Return<Status> transResult = mBase->destroyBlockPool(
+ Return<Status> transResult = mBase1_0->destroyBlockPool(
static_cast<uint64_t>(localId));
if (!transResult.isOk()) {
LOG(ERROR) << "destroyBlockPool -- transaction failed.";
@@ -1102,17 +1257,17 @@
void Codec2Client::Component::handleOnWorkDone(
const std::list<std::unique_ptr<C2Work>> &workItems) {
// Output bufferqueue-based blocks' lifetime management
- mOutputBufferQueue.holdBufferQueueBlocks(workItems);
+ mOutputBufferQueue->holdBufferQueueBlocks(workItems);
}
c2_status_t Codec2Client::Component::queue(
std::list<std::unique_ptr<C2Work>>* const items) {
WorkBundle workBundle;
- if (!objcpy(&workBundle, *items, &mBufferPoolSender)) {
+ if (!objcpy(&workBundle, *items, mBufferPoolSender.get())) {
LOG(ERROR) << "queue -- bad input.";
return C2_TRANSACTION_FAILED;
}
- Return<Status> transStatus = mBase->queue(workBundle);
+ Return<Status> transStatus = mBase1_0->queue(workBundle);
if (!transStatus.isOk()) {
LOG(ERROR) << "queue -- transaction failed.";
return C2_TRANSACTION_FAILED;
@@ -1130,7 +1285,7 @@
std::list<std::unique_ptr<C2Work>>* const flushedWork) {
(void)mode; // Flush mode isn't supported in HIDL yet.
c2_status_t status;
- Return<void> transStatus = mBase->flush(
+ Return<void> transStatus = mBase1_0->flush(
[&status, flushedWork](
Status s, const WorkBundle& wb) {
status = static_cast<c2_status_t>(s);
@@ -1165,13 +1320,13 @@
}
// Output bufferqueue-based blocks' lifetime management
- mOutputBufferQueue.holdBufferQueueBlocks(*flushedWork);
+ mOutputBufferQueue->holdBufferQueueBlocks(*flushedWork);
return status;
}
c2_status_t Codec2Client::Component::drain(C2Component::drain_mode_t mode) {
- Return<Status> transStatus = mBase->drain(
+ Return<Status> transStatus = mBase1_0->drain(
mode == C2Component::DRAIN_COMPONENT_WITH_EOS);
if (!transStatus.isOk()) {
LOG(ERROR) << "drain -- transaction failed.";
@@ -1186,7 +1341,7 @@
}
c2_status_t Codec2Client::Component::start() {
- Return<Status> transStatus = mBase->start();
+ Return<Status> transStatus = mBase1_0->start();
if (!transStatus.isOk()) {
LOG(ERROR) << "start -- transaction failed.";
return C2_TRANSACTION_FAILED;
@@ -1200,7 +1355,7 @@
}
c2_status_t Codec2Client::Component::stop() {
- Return<Status> transStatus = mBase->stop();
+ Return<Status> transStatus = mBase1_0->stop();
if (!transStatus.isOk()) {
LOG(ERROR) << "stop -- transaction failed.";
return C2_TRANSACTION_FAILED;
@@ -1214,7 +1369,7 @@
}
c2_status_t Codec2Client::Component::reset() {
- Return<Status> transStatus = mBase->reset();
+ Return<Status> transStatus = mBase1_0->reset();
if (!transStatus.isOk()) {
LOG(ERROR) << "reset -- transaction failed.";
return C2_TRANSACTION_FAILED;
@@ -1228,7 +1383,7 @@
}
c2_status_t Codec2Client::Component::release() {
- Return<Status> transStatus = mBase->release();
+ Return<Status> transStatus = mBase1_0->release();
if (!transStatus.isOk()) {
LOG(ERROR) << "release -- transaction failed.";
return C2_TRANSACTION_FAILED;
@@ -1241,6 +1396,29 @@
return status;
}
+c2_status_t Codec2Client::Component::configureVideoTunnel(
+ uint32_t avSyncHwId,
+ native_handle_t** sidebandHandle) {
+ *sidebandHandle = nullptr;
+ if (!mBase1_1) {
+ return C2_OMITTED;
+ }
+ c2_status_t status{};
+ Return<void> transStatus = mBase1_1->configureVideoTunnel(avSyncHwId,
+ [&status, sidebandHandle](
+ Status s, hardware::hidl_handle const& h) {
+ status = static_cast<c2_status_t>(s);
+ if (h.getNativeHandle()) {
+ *sidebandHandle = native_handle_clone(h.getNativeHandle());
+ }
+ });
+ if (!transStatus.isOk()) {
+ LOG(ERROR) << "configureVideoTunnel -- transaction failed.";
+ return C2_TRANSACTION_FAILED;
+ }
+ return status;
+}
+
c2_status_t Codec2Client::Component::setOutputSurface(
C2BlockPool::local_id_t blockPoolId,
const sp<IGraphicBufferProducer>& surface,
@@ -1256,18 +1434,18 @@
}
if (!surface) {
- mOutputBufferQueue.configure(nullIgbp, generation, 0);
+ mOutputBufferQueue->configure(nullIgbp, generation, 0);
} else if (surface->getUniqueId(&bqId) != OK) {
LOG(ERROR) << "setOutputSurface -- "
"cannot obtain bufferqueue id.";
bqId = 0;
- mOutputBufferQueue.configure(nullIgbp, generation, 0);
+ mOutputBufferQueue->configure(nullIgbp, generation, 0);
} else {
- mOutputBufferQueue.configure(surface, generation, bqId);
+ mOutputBufferQueue->configure(surface, generation, bqId);
}
ALOGD("generation remote change %u", generation);
- Return<Status> transStatus = mBase->setOutputSurface(
+ Return<Status> transStatus = mBase1_0->setOutputSurface(
static_cast<uint64_t>(blockPoolId),
bqId == 0 ? nullHgbp : igbp);
if (!transStatus.isOk()) {
@@ -1286,14 +1464,14 @@
const C2ConstGraphicBlock& block,
const QueueBufferInput& input,
QueueBufferOutput* output) {
- return mOutputBufferQueue.outputBuffer(block, input, output);
+ return mOutputBufferQueue->outputBuffer(block, input, output);
}
c2_status_t Codec2Client::Component::connectToInputSurface(
const std::shared_ptr<InputSurface>& inputSurface,
std::shared_ptr<InputSurfaceConnection>* connection) {
c2_status_t status;
- Return<void> transStatus = mBase->connectToInputSurface(
+ Return<void> transStatus = mBase1_0->connectToInputSurface(
inputSurface->mBase,
[&status, connection](
Status s, const sp<IInputSurfaceConnection>& c) {
@@ -1317,7 +1495,7 @@
const sp<HGraphicBufferSource>& source,
std::shared_ptr<InputSurfaceConnection>* connection) {
c2_status_t status;
- Return<void> transStatus = mBase->connectToOmxInputSurface(
+ Return<void> transStatus = mBase1_0->connectToOmxInputSurface(
producer, source,
[&status, connection](
Status s, const sp<IInputSurfaceConnection>& c) {
@@ -1337,7 +1515,7 @@
}
c2_status_t Codec2Client::Component::disconnectFromInputSurface() {
- Return<Status> transStatus = mBase->disconnectFromInputSurface();
+ Return<Status> transStatus = mBase1_0->disconnectFromInputSurface();
if (!transStatus.isOk()) {
LOG(ERROR) << "disconnectToInputSurface -- transaction failed.";
return C2_TRANSACTION_FAILED;
@@ -1376,7 +1554,7 @@
deathRecipient->component = component;
component->mDeathRecipient = deathRecipient;
- Return<bool> transResult = component->mBase->linkToDeath(
+ Return<bool> transResult = component->mBase1_0->linkToDeath(
component->mDeathRecipient, 0);
if (!transResult.isOk()) {
LOG(ERROR) << "setDeathListener -- linkToDeath() transaction failed.";
diff --git a/media/codec2/hidl/client/include/codec2/hidl/client.h b/media/codec2/hidl/client/include/codec2/hidl/client.h
index c37407f..ffd194a 100644
--- a/media/codec2/hidl/client/include/codec2/hidl/client.h
+++ b/media/codec2/hidl/client/include/codec2/hidl/client.h
@@ -17,14 +17,13 @@
#ifndef CODEC2_HIDL_CLIENT_H
#define CODEC2_HIDL_CLIENT_H
-#include <gui/IGraphicBufferProducer.h>
-#include <codec2/hidl/1.0/ClientBlockHelper.h>
#include <C2PlatformSupport.h>
#include <C2Component.h>
#include <C2Buffer.h>
#include <C2Param.h>
#include <C2.h>
+#include <gui/IGraphicBufferProducer.h>
#include <hidl/HidlSupport.h>
#include <utils/StrongPointer.h>
@@ -74,6 +73,11 @@
struct IInputSurfaceConnection;
} // namespace android::hardware::media::c2::V1_0
+namespace android::hardware::media::c2::V1_1 {
+struct IComponent;
+struct IComponentStore;
+} // namespace android::hardware::media::c2::V1_1
+
namespace android::hardware::media::bufferpool::V2_0 {
struct IClientManager;
} // namespace android::hardware::media::bufferpool::V2_0
@@ -82,6 +86,10 @@
struct IGraphicBufferProducer;
} // android::hardware::graphics::bufferqueue::V1_0
+namespace android::hardware::graphics::bufferqueue::V2_0 {
+struct IGraphicBufferProducer;
+} // android::hardware::graphics::bufferqueue::V2_0
+
namespace android::hardware::media::omx::V1_0 {
struct IGraphicBufferSource;
} // namespace android::hardware::media::omx::V1_0
@@ -127,7 +135,9 @@
struct Codec2Client : public Codec2ConfigurableClient {
- typedef ::android::hardware::media::c2::V1_0::IComponentStore Base;
+ typedef ::android::hardware::media::c2::V1_0::IComponentStore Base1_0;
+ typedef ::android::hardware::media::c2::V1_1::IComponentStore Base1_1;
+ typedef Base1_0 Base;
struct Listener;
@@ -144,6 +154,8 @@
typedef Codec2Client Store;
sp<Base> const& getBase() const;
+ sp<Base1_0> const& getBase1_0() const;
+ sp<Base1_1> const& getBase1_1() const;
std::string const& getServiceName() const;
@@ -172,8 +184,15 @@
// Note: A software service will have "_software" as a suffix.
static std::vector<std::string> const& GetServiceNames();
- // Create a service with a given service name.
- static std::shared_ptr<Codec2Client> CreateFromService(char const* name);
+ // Create a client to a service with a given name.
+ //
+ // After a client to the service is successfully created, if
+ // setAsPreferredCodec2ComponentStore is true, the component store that the
+ // service hosts will be set as the preferred C2ComponentStore for this
+ // process. (See SetPreferredCodec2ComponentStore() for more information.)
+ static std::shared_ptr<Codec2Client> CreateFromService(
+ char const* name,
+ bool setAsPreferredCodec2ComponentStore = false);
// Get clients to all services.
static std::vector<std::shared_ptr<Codec2Client>> CreateFromAllServices();
@@ -206,7 +225,8 @@
Codec2Client(sp<Base> const& base, size_t serviceIndex);
protected:
- sp<Base> mBase;
+ sp<Base1_0> mBase1_0;
+ sp<Base1_1> mBase1_1;
// Finds the first store where the predicate returns C2_OK and returns the
// last predicate result. The predicate will be tried on all stores. The
@@ -295,7 +315,9 @@
struct Codec2Client::Component : public Codec2Client::Configurable {
- typedef ::android::hardware::media::c2::V1_0::IComponent Base;
+ typedef ::android::hardware::media::c2::V1_0::IComponent Base1_0;
+ typedef ::android::hardware::media::c2::V1_1::IComponent Base1_1;
+ typedef Base1_0 Base;
c2_status_t createBlockPool(
C2Allocator::id_t id,
@@ -322,6 +344,17 @@
c2_status_t release();
+ /**
+ * Use tunneling.
+ *
+ * On success, @p sidebandHandle will be a newly allocated native handle.
+ * File descriptors in @p sidebandHandle must be closed and
+ * @p sidebandHandle itself must be deleted afterwards.
+ */
+ c2_status_t configureVideoTunnel(
+ uint32_t avSyncHwId,
+ native_handle_t** sidebandHandle);
+
typedef ::android::
IGraphicBufferProducer IGraphicBufferProducer;
typedef IGraphicBufferProducer::
@@ -378,17 +411,19 @@
// base cannot be null.
Component(const sp<Base>& base);
+ Component(const sp<Base1_1>& base);
~Component();
protected:
- sp<Base> mBase;
+ sp<Base1_0> mBase1_0;
+ sp<Base1_1> mBase1_1;
- ::android::hardware::media::c2::V1_0::utils::DefaultBufferPoolSender
- mBufferPoolSender;
+ struct BufferPoolSender;
+ std::unique_ptr<BufferPoolSender> mBufferPoolSender;
- ::android::hardware::media::c2::V1_0::utils::OutputBufferQueue
- mOutputBufferQueue;
+ struct OutputBufferQueue;
+ std::unique_ptr<OutputBufferQueue> mOutputBufferQueue;
static c2_status_t setDeathListener(
const std::shared_ptr<Component>& component,
diff --git a/media/codec2/hidl/services/Android.bp b/media/codec2/hidl/services/Android.bp
index 216525e..a16b106 100644
--- a/media/codec2/hidl/services/Android.bp
+++ b/media/codec2/hidl/services/Android.bp
@@ -1,39 +1,87 @@
+/*
+ * Copyright 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.
+ */
+
+// This is an example of an empty Codec2.0 service.
+//
+// To use this, make a copy of this whole directory and rename modules
+// accordingly. The contents of "vendor.cpp" and files in the subdirectory
+// "seccomp_policy" may also need to be modified.
+
+// Binary file for the service.
+//
+// The init_rc file contains the absolute path to this binary on the device.
+// If the name of this module is modified, the content of the init_rc file has
+// to be modified accordingly.
+//
+// The seccomp_policy file name and its content can be modified, but note that
+// vendor.cpp also needs to be updated because it needs the absolute path to the
+// seccomp policy file on the device.
cc_binary {
- name: "android.hardware.media.c2@1.0-service",
- defaults: ["hidl_defaults"],
- soc_specific: true,
+ name: "android.hardware.media.c2@1.1-default-service",
+ vendor: true,
relative_install_path: "hw",
+
+ init_rc: ["android.hardware.media.c2@1.1-default-service.rc"],
+
+ defaults: ["libcodec2-hidl-defaults"],
srcs: [
"vendor.cpp",
],
- init_rc: ["android.hardware.media.c2@1.0-service.rc"],
-
+ // minijail is used to protect against unexpected system calls.
shared_libs: [
- "android.hardware.media.c2@1.0",
- "android.hardware.media.omx@1.0",
"libavservices_minijail_vendor",
"libbinder",
- "libcodec2_hidl@1.0",
- "libcodec2_vndk",
- "libhidlbase",
- "libhidltransport",
- "libhwbinder",
- "liblog",
- "libstagefright_omx",
- "libstagefright_xmlparser",
- "libutils",
],
+ required: ["android.hardware.media.c2@1.1-default-seccomp_policy"],
+ // The content in manifest_media_c2_V1_1_default.xml can be included
+ // directly in the main device manifest.xml file or via vintf_fragments.
+ // (Remove the line below if the entry is already in the main manifest.)
+ vintf_fragments: ["manifest_media_c2_V1_1_default.xml"],
+}
+
+// seccomp policy file.
+//
+// This should be modified to suit the target device and architecture.
+//
+// Files in the "seccomp_policy" subdirectory are only provided as examples.
+// They may not work on some devices and/or architectures without modification.
+prebuilt_etc {
+ name: "android.hardware.media.c2@1.1-default-seccomp_policy",
+ vendor: true,
+ sub_dir: "seccomp_policy",
+
+ // If a specific architecture is targeted, multiple choices are not needed.
arch: {
arm: {
- required: ["codec2.vendor.base.policy"],
+ src: "seccomp_policy/android.hardware.media.c2@1.1-default-arm.policy",
+ },
+ arm64: {
+ src: "seccomp_policy/android.hardware.media.c2@1.1-default-arm64.policy",
},
x86: {
- required: ["codec2.vendor.base.policy"],
+ src: "seccomp_policy/android.hardware.media.c2@1.1-default-x86.policy",
+ },
+ x86_64: {
+ src: "seccomp_policy/android.hardware.media.c2@1.1-default-x86_64.policy",
},
},
- compile_multilib: "32",
+ // This may be removed.
+ required: ["crash_dump.policy"],
}
diff --git a/media/codec2/hidl/services/Android.mk b/media/codec2/hidl/services/Android.mk
deleted file mode 100644
index d9b28e7..0000000
--- a/media/codec2/hidl/services/Android.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-# vendor service seccomp policy
-ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH), x86 x86_64 arm arm64))
-include $(CLEAR_VARS)
-LOCAL_MODULE := codec2.vendor.base.policy
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/etc/seccomp_policy
-LOCAL_REQUIRED_MODULES := crash_dump.policy
-ifdef TARGET_2ND_ARCH
- ifneq ($(TARGET_TRANSLATE_2ND_ARCH),true)
- LOCAL_SRC_FILES := seccomp_policy/codec2.vendor.base-$(TARGET_2ND_ARCH).policy
- else
- LOCAL_SRC_FILES := seccomp_policy/codec2.vendor.base-$(TARGET_ARCH).policy
- endif
-else
- LOCAL_SRC_FILES := seccomp_policy/codec2.vendor.base-$(TARGET_ARCH).policy
-endif
-include $(BUILD_PREBUILT)
-endif
-
-include $(call all-makefiles-under, $(LOCAL_PATH))
-
diff --git a/media/codec2/hidl/services/android.hardware.media.c2@1.0-service.rc b/media/codec2/hidl/services/android.hardware.media.c2@1.0-service.rc
deleted file mode 100644
index 8806bd1f..0000000
--- a/media/codec2/hidl/services/android.hardware.media.c2@1.0-service.rc
+++ /dev/null
@@ -1,7 +0,0 @@
-service android-hardware-media-c2-hal-1-0 /vendor/bin/hw/android.hardware.media.c2@1.0-service
- class hal
- user mediacodec
- group camera mediadrm drmrpc
- ioprio rt 4
- writepid /dev/cpuset/foreground/tasks
-
diff --git a/media/codec2/hidl/services/android.hardware.media.c2@1.1-default-service.rc b/media/codec2/hidl/services/android.hardware.media.c2@1.1-default-service.rc
new file mode 100644
index 0000000..44f2d8e
--- /dev/null
+++ b/media/codec2/hidl/services/android.hardware.media.c2@1.1-default-service.rc
@@ -0,0 +1,7 @@
+service android-hardware-media-c2-hal-1-1 /vendor/bin/hw/android.hardware.media.c2@1.1-default-service
+ class hal
+ user mediacodec
+ group camera mediadrm drmrpc
+ ioprio rt 4
+ writepid /dev/cpuset/foreground/tasks
+
diff --git a/media/codec2/hidl/services/manifest_media_c2_V1_0_default.xml b/media/codec2/hidl/services/manifest_media_c2_V1_0_default.xml
new file mode 100644
index 0000000..e97c3ce
--- /dev/null
+++ b/media/codec2/hidl/services/manifest_media_c2_V1_0_default.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+ <hal>
+ <name>android.hardware.media.c2</name>
+ <transport>hwbinder</transport>
+ <version>1.0</version>
+ <interface>
+ <name>IComponentStore</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/media/codec2/hidl/services/manifest_media_c2_V1_1_default.xml b/media/codec2/hidl/services/manifest_media_c2_V1_1_default.xml
new file mode 100644
index 0000000..bf0d72f
--- /dev/null
+++ b/media/codec2/hidl/services/manifest_media_c2_V1_1_default.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+ <hal>
+ <name>android.hardware.media.c2</name>
+ <transport>hwbinder</transport>
+ <version>1.1</version>
+ <interface>
+ <name>IComponentStore</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.1-default-arm.policy b/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.1-default-arm.policy
new file mode 100644
index 0000000..9042cd7
--- /dev/null
+++ b/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.1-default-arm.policy
@@ -0,0 +1,86 @@
+# 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.
+
+futex: 1
+# ioctl calls are filtered via the selinux policy.
+ioctl: 1
+sched_yield: 1
+close: 1
+dup: 1
+ppoll: 1
+mprotect: arg2 in ~PROT_EXEC || arg2 in ~PROT_WRITE
+mmap2: arg2 in ~PROT_EXEC || arg2 in ~PROT_WRITE
+memfd_create: 1
+ftruncate: 1
+ftruncate64: 1
+
+# mremap: Ensure |flags| are (MREMAP_MAYMOVE | MREMAP_FIXED) TODO: Once minijail
+# parser support for '<' is in this needs to be modified to also prevent
+# |old_address| and |new_address| from touching the exception vector page, which
+# 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
+munmap: 1
+prctl: 1
+getuid32: 1
+writev: 1
+sigaltstack: 1
+clone: 1
+exit: 1
+lseek: 1
+rt_sigprocmask: 1
+openat: 1
+open: 1
+fstat64: 1
+write: 1
+nanosleep: 1
+setpriority: 1
+set_tid_address: 1
+getdents64: 1
+readlinkat: 1
+readlink: 1
+read: 1
+pread64: 1
+fstatfs64: 1
+gettimeofday: 1
+faccessat: 1
+_llseek: 1
+fstatat64: 1
+ugetrlimit: 1
+exit_group: 1
+restart_syscall: 1
+rt_sigreturn: 1
+getrandom: 1
+madvise: 1
+
+# crash dump policy additions
+sigreturn: 1
+clock_gettime: 1
+futex: 1
+getpid: 1
+gettid: 1
+pipe2: 1
+recvmsg: 1
+process_vm_readv: 1
+tgkill: 1
+rt_sigaction: 1
+rt_tgsigqueueinfo: 1
+#prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41
+#mprotect: arg2 in 0x1|0x2
+#mmap2: arg2 in 0x1|0x2
+geteuid32: 1
+getgid32: 1
+getegid32: 1
+getgroups32: 1
diff --git a/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.1-default-arm64.policy b/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.1-default-arm64.policy
new file mode 100644
index 0000000..4faf8b2
--- /dev/null
+++ b/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.1-default-arm64.policy
@@ -0,0 +1,81 @@
+# 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.
+
+futex: 1
+# ioctl calls are filtered via the selinux policy.
+ioctl: 1
+sched_yield: 1
+close: 1
+dup: 1
+ppoll: 1
+mprotect: arg2 in ~PROT_EXEC || arg2 in ~PROT_WRITE
+mmap: arg2 in ~PROT_EXEC || arg2 in ~PROT_WRITE
+getuid: 1
+getrlimit: 1
+fstat: 1
+newfstatat: 1
+fstatfs: 1
+memfd_create: 1
+ftruncate: 1
+
+# mremap: Ensure |flags| are (MREMAP_MAYMOVE | MREMAP_FIXED) TODO: Once minijail
+# parser support for '<' is in this needs to be modified to also prevent
+# |old_address| and |new_address| from touching the exception vector page, which
+# 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
+munmap: 1
+prctl: 1
+writev: 1
+sigaltstack: 1
+clone: 1
+exit: 1
+lseek: 1
+rt_sigprocmask: 1
+openat: 1
+write: 1
+nanosleep: 1
+setpriority: 1
+set_tid_address: 1
+getdents64: 1
+readlinkat: 1
+read: 1
+pread64: 1
+gettimeofday: 1
+faccessat: 1
+exit_group: 1
+restart_syscall: 1
+rt_sigreturn: 1
+getrandom: 1
+madvise: 1
+
+# crash dump policy additions
+clock_gettime: 1
+getpid: 1
+gettid: 1
+pipe2: 1
+recvmsg: 1
+process_vm_readv: 1
+tgkill: 1
+rt_sigaction: 1
+rt_tgsigqueueinfo: 1
+#mprotect: arg2 in 0x1|0x2
+munmap: 1
+#mmap: arg2 in 0x1|0x2
+geteuid: 1
+getgid: 1
+getegid: 1
+getgroups: 1
+
diff --git a/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.1-default-x86.policy b/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.1-default-x86.policy
new file mode 100644
index 0000000..d9c4045
--- /dev/null
+++ b/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.1-default-x86.policy
@@ -0,0 +1,71 @@
+# Copyright (C) 2017 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.
+
+read: 1
+mprotect: 1
+prctl: 1
+openat: 1
+open: 1
+getuid32: 1
+getuid: 1
+getrlimit: 1
+writev: 1
+ioctl: 1
+close: 1
+mmap2: 1
+mmap: 1
+fstat64: 1
+fstat: 1
+stat64: 1
+statfs64: 1
+madvise: 1
+fstatat64: 1
+newfstatat: 1
+futex: 1
+munmap: 1
+faccessat: 1
+_llseek: 1
+lseek: 1
+clone: 1
+sigaltstack: 1
+setpriority: 1
+restart_syscall: 1
+exit: 1
+exit_group: 1
+rt_sigreturn: 1
+ugetrlimit: 1
+readlink: 1
+readlinkat: 1
+_llseek: 1
+fstatfs64: 1
+fstatfs: 1
+pread64: 1
+mremap: 1
+dup: 1
+set_tid_address: 1
+write: 1
+nanosleep: 1
+sched_setscheduler: 1
+uname: 1
+memfd_create: 1
+ftruncate: 1
+ftruncate64: 1
+
+# Required by AddressSanitizer
+gettid: 1
+sched_yield: 1
+getpid: 1
+gettid: 1
+
+@include /system/etc/seccomp_policy/crash_dump.x86.policy
diff --git a/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.1-default-x86_64.policy b/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.1-default-x86_64.policy
new file mode 100644
index 0000000..d9c4045
--- /dev/null
+++ b/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.1-default-x86_64.policy
@@ -0,0 +1,71 @@
+# Copyright (C) 2017 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.
+
+read: 1
+mprotect: 1
+prctl: 1
+openat: 1
+open: 1
+getuid32: 1
+getuid: 1
+getrlimit: 1
+writev: 1
+ioctl: 1
+close: 1
+mmap2: 1
+mmap: 1
+fstat64: 1
+fstat: 1
+stat64: 1
+statfs64: 1
+madvise: 1
+fstatat64: 1
+newfstatat: 1
+futex: 1
+munmap: 1
+faccessat: 1
+_llseek: 1
+lseek: 1
+clone: 1
+sigaltstack: 1
+setpriority: 1
+restart_syscall: 1
+exit: 1
+exit_group: 1
+rt_sigreturn: 1
+ugetrlimit: 1
+readlink: 1
+readlinkat: 1
+_llseek: 1
+fstatfs64: 1
+fstatfs: 1
+pread64: 1
+mremap: 1
+dup: 1
+set_tid_address: 1
+write: 1
+nanosleep: 1
+sched_setscheduler: 1
+uname: 1
+memfd_create: 1
+ftruncate: 1
+ftruncate64: 1
+
+# Required by AddressSanitizer
+gettid: 1
+sched_yield: 1
+getpid: 1
+gettid: 1
+
+@include /system/etc/seccomp_policy/crash_dump.x86.policy
diff --git a/media/codec2/hidl/services/seccomp_policy/codec2.software.base-arm.policy b/media/codec2/hidl/services/seccomp_policy/codec2.software.base-arm.policy
deleted file mode 100644
index d5871d1..0000000
--- a/media/codec2/hidl/services/seccomp_policy/codec2.software.base-arm.policy
+++ /dev/null
@@ -1,73 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Organized by frequency of systemcall - in descending order for
-# best performance.
-futex: 1
-ioctl: 1
-write: 1
-prctl: 1
-clock_gettime: 1
-getpriority: 1
-read: 1
-close: 1
-writev: 1
-dup: 1
-ppoll: 1
-mmap2: 1
-getrandom: 1
-
-# mremap: Ensure |flags| are (MREMAP_MAYMOVE | MREMAP_FIXED) TODO: Once minijail
-# parser support for '<' is in this needs to be modified to also prevent
-# |old_address| and |new_address| from touching the exception vector page, which
-# 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
-munmap: 1
-mprotect: 1
-madvise: 1
-openat: 1
-sigaltstack: 1
-clone: 1
-setpriority: 1
-getuid32: 1
-fstat64: 1
-fstatfs64: 1
-pread64: 1
-faccessat: 1
-readlinkat: 1
-exit: 1
-rt_sigprocmask: 1
-set_tid_address: 1
-restart_syscall: 1
-exit_group: 1
-rt_sigreturn: 1
-pipe2: 1
-gettimeofday: 1
-sched_yield: 1
-nanosleep: 1
-lseek: 1
-_llseek: 1
-sched_get_priority_max: 1
-sched_get_priority_min: 1
-statfs64: 1
-sched_setscheduler: 1
-fstatat64: 1
-ugetrlimit: 1
-getdents64: 1
-getrandom: 1
-
-@include /system/etc/seccomp_policy/crash_dump.arm.policy
-
diff --git a/media/codec2/hidl/services/seccomp_policy/codec2.software.base-x86.policy b/media/codec2/hidl/services/seccomp_policy/codec2.software.base-x86.policy
deleted file mode 100644
index 20c7625..0000000
--- a/media/codec2/hidl/services/seccomp_policy/codec2.software.base-x86.policy
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-read: 1
-mprotect: 1
-prctl: 1
-openat: 1
-getuid32: 1
-writev: 1
-ioctl: 1
-close: 1
-mmap2: 1
-fstat64: 1
-madvise: 1
-fstatat64: 1
-futex: 1
-munmap: 1
-faccessat: 1
-_llseek: 1
-lseek: 1
-clone: 1
-sigaltstack: 1
-setpriority: 1
-restart_syscall: 1
-exit: 1
-exit_group: 1
-rt_sigreturn: 1
-ugetrlimit: 1
-readlinkat: 1
-_llseek: 1
-fstatfs64: 1
-pread64: 1
-mremap: 1
-dup: 1
-set_tid_address: 1
-write: 1
-nanosleep: 1
-
-# Required by AddressSanitizer
-gettid: 1
-sched_yield: 1
-getpid: 1
-gettid: 1
-
-@include /system/etc/seccomp_policy/crash_dump.x86.policy
-
diff --git a/media/codec2/hidl/services/seccomp_policy/codec2.vendor.base-arm.policy b/media/codec2/hidl/services/seccomp_policy/codec2.vendor.base-arm.policy
deleted file mode 100644
index d5871d1..0000000
--- a/media/codec2/hidl/services/seccomp_policy/codec2.vendor.base-arm.policy
+++ /dev/null
@@ -1,73 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Organized by frequency of systemcall - in descending order for
-# best performance.
-futex: 1
-ioctl: 1
-write: 1
-prctl: 1
-clock_gettime: 1
-getpriority: 1
-read: 1
-close: 1
-writev: 1
-dup: 1
-ppoll: 1
-mmap2: 1
-getrandom: 1
-
-# mremap: Ensure |flags| are (MREMAP_MAYMOVE | MREMAP_FIXED) TODO: Once minijail
-# parser support for '<' is in this needs to be modified to also prevent
-# |old_address| and |new_address| from touching the exception vector page, which
-# 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
-munmap: 1
-mprotect: 1
-madvise: 1
-openat: 1
-sigaltstack: 1
-clone: 1
-setpriority: 1
-getuid32: 1
-fstat64: 1
-fstatfs64: 1
-pread64: 1
-faccessat: 1
-readlinkat: 1
-exit: 1
-rt_sigprocmask: 1
-set_tid_address: 1
-restart_syscall: 1
-exit_group: 1
-rt_sigreturn: 1
-pipe2: 1
-gettimeofday: 1
-sched_yield: 1
-nanosleep: 1
-lseek: 1
-_llseek: 1
-sched_get_priority_max: 1
-sched_get_priority_min: 1
-statfs64: 1
-sched_setscheduler: 1
-fstatat64: 1
-ugetrlimit: 1
-getdents64: 1
-getrandom: 1
-
-@include /system/etc/seccomp_policy/crash_dump.arm.policy
-
diff --git a/media/codec2/hidl/services/seccomp_policy/codec2.vendor.base-x86.policy b/media/codec2/hidl/services/seccomp_policy/codec2.vendor.base-x86.policy
deleted file mode 100644
index 20c7625..0000000
--- a/media/codec2/hidl/services/seccomp_policy/codec2.vendor.base-x86.policy
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-read: 1
-mprotect: 1
-prctl: 1
-openat: 1
-getuid32: 1
-writev: 1
-ioctl: 1
-close: 1
-mmap2: 1
-fstat64: 1
-madvise: 1
-fstatat64: 1
-futex: 1
-munmap: 1
-faccessat: 1
-_llseek: 1
-lseek: 1
-clone: 1
-sigaltstack: 1
-setpriority: 1
-restart_syscall: 1
-exit: 1
-exit_group: 1
-rt_sigreturn: 1
-ugetrlimit: 1
-readlinkat: 1
-_llseek: 1
-fstatfs64: 1
-pread64: 1
-mremap: 1
-dup: 1
-set_tid_address: 1
-write: 1
-nanosleep: 1
-
-# Required by AddressSanitizer
-gettid: 1
-sched_yield: 1
-getpid: 1
-gettid: 1
-
-@include /system/etc/seccomp_policy/crash_dump.x86.policy
-
diff --git a/media/codec2/hidl/services/vendor.cpp b/media/codec2/hidl/services/vendor.cpp
index ef2f98e..81bffeb 100644
--- a/media/codec2/hidl/services/vendor.cpp
+++ b/media/codec2/hidl/services/vendor.cpp
@@ -15,31 +15,38 @@
*/
//#define LOG_NDEBUG 0
-#define LOG_TAG "android.hardware.media.c2@1.0-service"
+#define LOG_TAG "android.hardware.media.c2@1.1-service"
-#include <codec2/hidl/1.0/ComponentStore.h>
-#include <hidl/HidlTransportSupport.h>
+#include <android-base/logging.h>
#include <binder/ProcessState.h>
+#include <codec2/hidl/1.1/ComponentStore.h>
+#include <hidl/HidlTransportSupport.h>
#include <minijail.h>
+#include <util/C2InterfaceHelper.h>
#include <C2Component.h>
+#include <C2Config.h>
-// OmxStore is added for visibility by dumpstate.
-#include <media/stagefright/omx/1.0/OmxStore.h>
-
-// This is created by module "codec2.vendor.base.policy". This can be modified.
+// This is the absolute on-device path of the prebuild_etc module
+// "android.hardware.media.c2@1.1-default-seccomp_policy" in Android.bp.
static constexpr char kBaseSeccompPolicyPath[] =
- "/vendor/etc/seccomp_policy/codec2.vendor.base.policy";
+ "/vendor/etc/seccomp_policy/"
+ "android.hardware.media.c2@1.1-default-seccomp-policy";
-// Additional device-specific seccomp permissions can be added in this file.
+// Additional seccomp permissions can be added in this file.
+// This file does not exist by default.
static constexpr char kExtSeccompPolicyPath[] =
- "/vendor/etc/seccomp_policy/codec2.vendor.ext.policy";
+ "/vendor/etc/seccomp_policy/"
+ "android.hardware.media.c2@1.1-extended-seccomp-policy";
-class DummyC2Store : public C2ComponentStore {
+class StoreImpl : public C2ComponentStore {
public:
- DummyC2Store() = default;
+ StoreImpl()
+ : mReflectorHelper(std::make_shared<C2ReflectorHelper>()),
+ mInterface(mReflectorHelper) {
+ }
- virtual ~DummyC2Store() override = default;
+ virtual ~StoreImpl() override = default;
virtual C2String getName() const override {
return "default";
@@ -69,82 +76,114 @@
}
virtual c2_status_t query_sm(
- const std::vector<C2Param*>& /* stackParams */,
- const std::vector<C2Param::Index>& /* heapParamIndices */,
- std::vector<std::unique_ptr<C2Param>>* const /* heapParams */) const override {
- return C2_OMITTED;
+ const std::vector<C2Param*>& stackParams,
+ const std::vector<C2Param::Index>& heapParamIndices,
+ std::vector<std::unique_ptr<C2Param>>* const heapParams) const override {
+ return mInterface.query(stackParams, heapParamIndices, C2_MAY_BLOCK, heapParams);
}
virtual c2_status_t config_sm(
- const std::vector<C2Param*>& /* params */,
- std::vector<std::unique_ptr<C2SettingResult>>* const /* failures */) override {
- return C2_OMITTED;
+ const std::vector<C2Param*>& params,
+ std::vector<std::unique_ptr<C2SettingResult>>* const failures) override {
+ return mInterface.config(params, C2_MAY_BLOCK, failures);
}
virtual std::shared_ptr<C2ParamReflector> getParamReflector() const override {
- return nullptr;
+ return mReflectorHelper;
}
virtual c2_status_t querySupportedParams_nb(
- std::vector<std::shared_ptr<C2ParamDescriptor>>* const /* params */) const override {
- return C2_OMITTED;
+ std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const override {
+ return mInterface.querySupportedParams(params);
}
virtual c2_status_t querySupportedValues_sm(
- std::vector<C2FieldSupportedValuesQuery>& /* fields */) const override {
- return C2_OMITTED;
+ std::vector<C2FieldSupportedValuesQuery>& fields) const override {
+ return mInterface.querySupportedValues(fields, C2_MAY_BLOCK);
}
+
+private:
+ class Interface : public C2InterfaceHelper {
+ public:
+ Interface(const std::shared_ptr<C2ReflectorHelper> &helper)
+ : C2InterfaceHelper(helper) {
+ setDerivedInstance(this);
+
+ addParameter(
+ DefineParam(mIonUsageInfo, "ion-usage")
+ .withDefault(new C2StoreIonUsageInfo())
+ .withFields({
+ C2F(mIonUsageInfo, usage).flags(
+ {C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE}),
+ C2F(mIonUsageInfo, capacity).inRange(0, UINT32_MAX, 1024),
+ C2F(mIonUsageInfo, heapMask).any(),
+ C2F(mIonUsageInfo, allocFlags).flags({}),
+ C2F(mIonUsageInfo, minAlignment).equalTo(0)
+ })
+ .withSetter(SetIonUsage)
+ .build());
+ }
+
+ virtual ~Interface() = default;
+
+ private:
+ static C2R SetIonUsage(bool /* mayBlock */, C2P<C2StoreIonUsageInfo> &me) {
+ // Vendor's TODO: put appropriate mapping logic
+ me.set().heapMask = ~0;
+ me.set().allocFlags = 0;
+ me.set().minAlignment = 0;
+ return C2R::Ok();
+ }
+
+ std::shared_ptr<C2StoreIonUsageInfo> mIonUsageInfo;
+ };
+ std::shared_ptr<C2ReflectorHelper> mReflectorHelper;
+ Interface mInterface;
};
int main(int /* argc */, char** /* argv */) {
- ALOGD("android.hardware.media.c2@1.0-service starting...");
+ using namespace ::android;
+ LOG(DEBUG) << "android.hardware.media.c2@1.1-service starting...";
+ // Set up minijail to limit system calls.
signal(SIGPIPE, SIG_IGN);
- android::SetUpMinijail(kBaseSeccompPolicyPath, kExtSeccompPolicyPath);
+ SetUpMinijail(kBaseSeccompPolicyPath, kExtSeccompPolicyPath);
- // vndbinder is needed by BufferQueue.
- android::ProcessState::initWithDriver("/dev/vndbinder");
- android::ProcessState::self()->startThreadPool();
+ // Enable vndbinder to allow vendor-to-vendor binder calls.
+ ProcessState::initWithDriver("/dev/vndbinder");
+ ProcessState::self()->startThreadPool();
// Extra threads may be needed to handle a stacked IPC sequence that
// contains alternating binder and hwbinder calls. (See b/35283480.)
- android::hardware::configureRpcThreadpool(8, true /* callerWillJoin */);
+ hardware::configureRpcThreadpool(8, true /* callerWillJoin */);
// Create IComponentStore service.
{
- using namespace ::android::hardware::media::c2::V1_0;
- android::sp<IComponentStore> store;
+ using namespace ::android::hardware::media::c2::V1_1;
+ sp<IComponentStore> store;
- // Vendor's TODO: Replace this with
+ // TODO: Replace this with
// store = new utils::ComponentStore(
// /* implementation of C2ComponentStore */);
- ALOGD("Instantiating Codec2's dummy IComponentStore service...");
+ LOG(DEBUG) << "Instantiating Codec2's IComponentStore service...";
store = new utils::ComponentStore(
- std::make_shared<DummyC2Store>());
+ std::make_shared<StoreImpl>());
if (store == nullptr) {
- ALOGE("Cannot create Codec2's IComponentStore service.");
+ LOG(ERROR) << "Cannot create Codec2's IComponentStore service.";
} else {
- if (store->registerAsService("default") != android::OK) {
- ALOGE("Cannot register Codec2's "
- "IComponentStore service.");
+ constexpr char const* serviceName = "default";
+ if (store->registerAsService(serviceName) != OK) {
+ LOG(ERROR) << "Cannot register Codec2's IComponentStore service"
+ " with instance name << \""
+ << serviceName << "\".";
} else {
- ALOGI("Codec2's IComponentStore service created.");
+ LOG(DEBUG) << "Codec2's IComponentStore service registered. "
+ "Instance name: \"" << serviceName << "\".";
}
}
}
- // Register IOmxStore service.
- {
- using namespace ::android::hardware::media::omx::V1_0;
- android::sp<IOmxStore> omxStore = new implementation::OmxStore();
- if (omxStore == nullptr) {
- ALOGE("Cannot create IOmxStore HAL service.");
- } else if (omxStore->registerAsService() != android::OK) {
- ALOGE("Cannot register IOmxStore HAL service.");
- }
- }
-
- android::hardware::joinRpcThreadpool();
+ hardware::joinRpcThreadpool();
return 0;
}
diff --git a/media/codec2/sfplugin/Android.bp b/media/codec2/sfplugin/Android.bp
index 9c84c71..94034b5 100644
--- a/media/codec2/sfplugin/Android.bp
+++ b/media/codec2/sfplugin/Android.bp
@@ -1,6 +1,8 @@
cc_library_shared {
name: "libsfplugin_ccodec",
+ export_include_dirs: ["include"],
+
srcs: [
"C2OMXNode.cpp",
"CCodec.cpp",
@@ -9,10 +11,8 @@
"CCodecConfig.cpp",
"Codec2Buffer.cpp",
"Codec2InfoBuilder.cpp",
- "Omx2IGraphicBufferSource.cpp",
"PipelineWatcher.cpp",
"ReflectedParamUpdater.cpp",
- "SkipCutBuffer.cpp",
],
cflags: [
@@ -22,11 +22,14 @@
header_libs: [
"libcodec2_internal",
+ "libmediadrm_headers",
+ "libmediametrics_headers",
+ "media_ndk_headers",
],
shared_libs: [
"android.hardware.cas.native@1.0",
- "android.hardware.graphics.bufferqueue@1.0",
+ "android.hardware.drm@1.0",
"android.hardware.media.c2@1.0",
"android.hardware.media.omx@1.0",
"libbase",
@@ -39,19 +42,23 @@
"libhidlallocatorutils",
"libhidlbase",
"liblog",
- "libmedia",
+ "libmedia_codeclist",
"libmedia_omx",
"libsfplugin_ccodec_utils",
"libstagefright_bufferqueue_helper",
"libstagefright_codecbase",
"libstagefright_foundation",
"libstagefright_omx",
- "libstagefright_omx_utils",
"libstagefright_xmlparser",
"libui",
"libutils",
],
+ export_shared_lib_headers: [
+ "libcodec2",
+ "libcodec2_client",
+ ],
+
sanitize: {
cfi: true,
misc_undefined: [
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 78ddd6d..cc132de 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -26,8 +26,8 @@
#include <C2ParamInternal.h>
#include <C2PlatformSupport.h>
-#include <android/IGraphicBufferSource.h>
#include <android/IOMXBufferSource.h>
+#include <android/hardware/media/c2/1.0/IInputSurface.h>
#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
#include <android/hardware/media/omx/1.0/IOmx.h>
#include <android-base/stringprintf.h>
@@ -35,17 +35,21 @@
#include <gui/IGraphicBufferProducer.h>
#include <gui/Surface.h>
#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
-#include <media/omx/1.0/WGraphicBufferSource.h>
+#include <media/omx/1.0/WOmxNode.h>
+#include <media/openmax/OMX_Core.h>
#include <media/openmax/OMX_IndexExt.h>
+#include <media/stagefright/omx/1.0/WGraphicBufferSource.h>
+#include <media/stagefright/omx/OmxGraphicBufferSource.h>
+#include <media/stagefright/CCodec.h>
#include <media/stagefright/BufferProducerWrapper.h>
#include <media/stagefright/MediaCodecConstants.h>
#include <media/stagefright/PersistentSurface.h>
#include "C2OMXNode.h"
-#include "CCodec.h"
#include "CCodecBufferChannel.h"
+#include "CCodecConfig.h"
+#include "Codec2Mapper.h"
#include "InputSurfaceWrapper.h"
-#include "Omx2IGraphicBufferSource.h"
extern "C" android::PersistentSurface *CreateInputSurface();
@@ -54,9 +58,11 @@
using namespace std::chrono_literals;
using ::android::hardware::graphics::bufferqueue::V1_0::utils::H2BGraphicBufferProducer;
using android::base::StringPrintf;
-using BGraphicBufferSource = ::android::IGraphicBufferSource;
using ::android::hardware::media::c2::V1_0::IInputSurface;
+typedef hardware::media::omx::V1_0::IGraphicBufferSource HGraphicBufferSource;
+typedef CCodecConfig Config;
+
namespace {
class CCodecWatchdog : public AHandler {
@@ -180,9 +186,10 @@
class GraphicBufferSourceWrapper : public InputSurfaceWrapper {
public:
-// explicit GraphicBufferSourceWrapper(const sp<BGraphicBufferSource> &source) : mSource(source) {}
+ typedef hardware::media::omx::V1_0::Status OmxStatus;
+
GraphicBufferSourceWrapper(
- const sp<BGraphicBufferSource> &source,
+ const sp<HGraphicBufferSource> &source,
uint32_t width,
uint32_t height,
uint64_t usage)
@@ -194,6 +201,7 @@
status_t connect(const std::shared_ptr<Codec2Client::Component> &comp) override {
mNode = new C2OMXNode(comp);
+ mOmxNode = new hardware::media::omx::V1_0::utils::TWOmxNode(mNode);
mNode->setFrameSize(mWidth, mHeight);
// Usage is queried during configure(), so setting it beforehand.
@@ -204,7 +212,8 @@
// NOTE: we do not use/pass through color aspects from GraphicBufferSource as we
// communicate that directly to the component.
- mSource->configure(mNode, mDataSpace);
+ mSource->configure(
+ mOmxNode, static_cast<hardware::graphics::common::V1_0::Dataspace>(mDataSpace));
return OK;
}
@@ -220,21 +229,16 @@
source->onOmxIdle();
source->onOmxLoaded();
mNode.clear();
+ mOmxNode.clear();
}
- status_t GetStatus(const binder::Status &status) {
- status_t err = OK;
- if (!status.isOk()) {
- err = status.serviceSpecificErrorCode();
- if (err == OK) {
- err = status.transactionError();
- if (err == OK) {
- // binder status failed, but there is no servie or transaction error
- err = UNKNOWN_ERROR;
- }
- }
+ status_t GetStatus(hardware::Return<OmxStatus> &&status) {
+ if (status.isOk()) {
+ return static_cast<status_t>(status.withDefault(OmxStatus::UNKNOWN_ERROR));
+ } else if (status.isDeadObject()) {
+ return DEAD_OBJECT;
}
- return err;
+ return UNKNOWN_ERROR;
}
status_t start() override {
@@ -359,7 +363,15 @@
err = res;
} else {
status << " delayUs";
- res = GetStatus(mSource->getStopTimeOffsetUs(&config.mInputDelayUs));
+ hardware::Return<void> trans = mSource->getStopTimeOffsetUs(
+ [&res, &delayUs = config.mInputDelayUs](
+ auto status, auto stopTimeOffsetUs) {
+ res = static_cast<status_t>(status);
+ delayUs = stopTimeOffsetUs;
+ });
+ if (!trans.isOk()) {
+ res = trans.isDeadObject() ? DEAD_OBJECT : UNKNOWN_ERROR;
+ }
if (res != OK) {
status << " (=> " << asString(res) << ")";
} else {
@@ -388,8 +400,9 @@
}
private:
- sp<BGraphicBufferSource> mSource;
+ sp<HGraphicBufferSource> mSource;
sp<C2OMXNode> mNode;
+ sp<hardware::media::omx::V1_0::IOmxNode> mOmxNode;
uint32_t mWidth;
uint32_t mHeight;
Config mConfig;
@@ -561,7 +574,8 @@
// CCodec
CCodec::CCodec()
- : mChannel(new CCodecBufferChannel(std::make_shared<CCodecCallbackImpl>(this))) {
+ : mChannel(new CCodecBufferChannel(std::make_shared<CCodecCallbackImpl>(this))),
+ mConfig(new CCodecConfig) {
}
CCodec::~CCodec() {
@@ -652,8 +666,9 @@
}
// initialize config here in case setParameters is called prior to configure
- Mutexed<Config>::Locked config(mConfig);
- status_t err = config->initialize(mClient, comp);
+ Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
+ const std::unique_ptr<Config> &config = *configLocked;
+ status_t err = config->initialize(mClient->getParamReflector(), comp);
if (err != OK) {
ALOGW("Failed to initialize configuration support");
// TODO: report error once we complete implementation.
@@ -703,6 +718,11 @@
encoder = false;
}
+ int32_t flags;
+ if (!msg->findInt32("flags", &flags)) {
+ return BAD_VALUE;
+ }
+
// TODO: read from intf()
if ((!encoder) != (comp->getName().find("encoder") == std::string::npos)) {
return UNKNOWN_ERROR;
@@ -726,8 +746,12 @@
setSurface(surface);
}
- Mutexed<Config>::Locked config(mConfig);
+ Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
+ const std::unique_ptr<Config> &config = *configLocked;
config->mUsingSurface = surface != nullptr;
+ config->mBuffersBoundToCodec = ((flags & CONFIGURE_FLAG_USE_BLOCK_MODEL) == 0);
+ ALOGD("[%s] buffers are %sbound to CCodec for this session",
+ comp->getName().c_str(), config->mBuffersBoundToCodec ? "" : "not ");
// Enforce required parameters
int32_t i32;
@@ -860,6 +884,13 @@
}
}
+ int32_t subscribeToAllVendorParams;
+ if (msg->findInt32("x-*", &subscribeToAllVendorParams) && subscribeToAllVendorParams) {
+ if (config->subscribeToAllVendorParams(comp, C2_MAY_BLOCK) != OK) {
+ ALOGD("[%s] Failed to subscribe to all vendor params", comp->getName().c_str());
+ }
+ }
+
std::vector<std::unique_ptr<C2Param>> configUpdate;
// NOTE: We used to ignore "video-bitrate" at configure; replicate
// the behavior here.
@@ -1042,7 +1073,8 @@
return;
}
- Mutexed<Config>::Locked config(mConfig);
+ Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
+ const std::unique_ptr<Config> &config = *configLocked;
mCallback->onComponentConfigured(config->mInputFormat, config->mOutputFormat);
}
@@ -1092,9 +1124,7 @@
gbs = source;
});
if (transStatus.isOk() && s == OmxStatus::OK) {
- return new PersistentSurface(
- new H2BGraphicBufferProducer(gbp),
- sp<::android::IGraphicBufferSource>(new LWGraphicBufferSource(gbs)));
+ return new PersistentSurface(new H2BGraphicBufferProducer(gbp), gbs);
}
return nullptr;
@@ -1118,35 +1148,36 @@
sp<AMessage> outputFormat;
uint64_t usage = 0;
{
- Mutexed<Config>::Locked config(mConfig);
+ Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
+ const std::unique_ptr<Config> &config = *configLocked;
inputFormat = config->mInputFormat;
outputFormat = config->mOutputFormat;
usage = config->mISConfig ? config->mISConfig->mUsage : 0;
}
sp<PersistentSurface> persistentSurface = CreateCompatibleInputSurface();
+ sp<hidl::base::V1_0::IBase> hidlTarget = persistentSurface->getHidlTarget();
+ sp<IInputSurface> hidlInputSurface = IInputSurface::castFrom(hidlTarget);
+ sp<HGraphicBufferSource> gbs = HGraphicBufferSource::castFrom(hidlTarget);
- if (persistentSurface->getHidlTarget()) {
- sp<IInputSurface> hidlInputSurface = IInputSurface::castFrom(
- persistentSurface->getHidlTarget());
- if (!hidlInputSurface) {
- ALOGE("Corrupted input surface");
- mCallback->onInputSurfaceCreationFailed(UNKNOWN_ERROR);
- return;
- }
+ if (hidlInputSurface) {
std::shared_ptr<Codec2Client::InputSurface> inputSurface =
std::make_shared<Codec2Client::InputSurface>(hidlInputSurface);
err = setupInputSurface(std::make_shared<C2InputSurfaceWrapper>(
inputSurface));
bufferProducer = inputSurface->getGraphicBufferProducer();
- } else {
+ } else if (gbs) {
int32_t width = 0;
(void)outputFormat->findInt32("width", &width);
int32_t height = 0;
(void)outputFormat->findInt32("height", &height);
err = setupInputSurface(std::make_shared<GraphicBufferSourceWrapper>(
- persistentSurface->getBufferSource(), width, height, usage));
+ gbs, width, height, usage));
bufferProducer = persistentSurface->getBufferProducer();
+ } else {
+ ALOGE("Corrupted input surface");
+ mCallback->onInputSurfaceCreationFailed(UNKNOWN_ERROR);
+ return;
}
if (err != OK) {
@@ -1162,12 +1193,13 @@
}
status_t CCodec::setupInputSurface(const std::shared_ptr<InputSurfaceWrapper> &surface) {
- Mutexed<Config>::Locked config(mConfig);
+ Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
+ const std::unique_ptr<Config> &config = *configLocked;
config->mUsingSurface = true;
// we are now using surface - apply default color aspects to input format - as well as
// get dataspace
- bool inputFormatChanged = config->updateFormats(config->IS_INPUT);
+ bool inputFormatChanged = config->updateFormats(Config::IS_INPUT);
ALOGD("input format %s to %s",
inputFormatChanged ? "changed" : "unchanged",
config->mInputFormat->debugString().c_str());
@@ -1182,7 +1214,7 @@
if (err != OK) {
// undo input format update
config->mUsingSurface = false;
- (void)config->updateFormats(config->IS_INPUT);
+ (void)config->updateFormats(Config::IS_INPUT);
return err;
}
config->mInputSurface = surface;
@@ -1207,20 +1239,16 @@
sp<AMessage> outputFormat;
uint64_t usage = 0;
{
- Mutexed<Config>::Locked config(mConfig);
+ Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
+ const std::unique_ptr<Config> &config = *configLocked;
inputFormat = config->mInputFormat;
outputFormat = config->mOutputFormat;
usage = config->mISConfig ? config->mISConfig->mUsage : 0;
}
- auto hidlTarget = surface->getHidlTarget();
- if (hidlTarget) {
- sp<IInputSurface> inputSurface =
- IInputSurface::castFrom(hidlTarget);
- if (!inputSurface) {
- ALOGE("Failed to set input surface: Corrupted surface.");
- mCallback->onInputSurfaceDeclined(UNKNOWN_ERROR);
- return;
- }
+ sp<hidl::base::V1_0::IBase> hidlTarget = surface->getHidlTarget();
+ sp<IInputSurface> inputSurface = IInputSurface::castFrom(hidlTarget);
+ sp<HGraphicBufferSource> gbs = HGraphicBufferSource::castFrom(hidlTarget);
+ if (inputSurface) {
status_t err = setupInputSurface(std::make_shared<C2InputSurfaceWrapper>(
std::make_shared<Codec2Client::InputSurface>(inputSurface)));
if (err != OK) {
@@ -1228,18 +1256,22 @@
mCallback->onInputSurfaceDeclined(err);
return;
}
- } else {
+ } else if (gbs) {
int32_t width = 0;
(void)outputFormat->findInt32("width", &width);
int32_t height = 0;
(void)outputFormat->findInt32("height", &height);
status_t err = setupInputSurface(std::make_shared<GraphicBufferSourceWrapper>(
- surface->getBufferSource(), width, height, usage));
+ gbs, width, height, usage));
if (err != OK) {
ALOGE("Failed to set up input surface: %d", err);
mCallback->onInputSurfaceDeclined(err);
return;
}
+ } else {
+ ALOGE("Failed to set input surface: Corrupted surface.");
+ mCallback->onInputSurfaceDeclined(UNKNOWN_ERROR);
+ return;
}
mCallback->onInputSurfaceAccepted(inputFormat, outputFormat);
}
@@ -1283,14 +1315,17 @@
sp<AMessage> inputFormat;
sp<AMessage> outputFormat;
status_t err2 = OK;
+ bool buffersBoundToCodec = false;
{
- Mutexed<Config>::Locked config(mConfig);
+ Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
+ const std::unique_ptr<Config> &config = *configLocked;
inputFormat = config->mInputFormat;
// start triggers format dup
outputFormat = config->mOutputFormat = config->mOutputFormat->dup();
if (config->mInputSurface) {
err2 = config->mInputSurface->start();
}
+ buffersBoundToCodec = config->mBuffersBoundToCodec;
}
if (err2 != OK) {
mCallback->onError(err2, ACTION_CODE_FATAL);
@@ -1298,7 +1333,7 @@
}
// We're not starting after flush.
(void)mSentConfigAfterResume.test_and_set();
- err2 = mChannel->start(inputFormat, outputFormat);
+ err2 = mChannel->start(inputFormat, outputFormat, buffersBoundToCodec);
if (err2 != OK) {
mCallback->onError(err2, ACTION_CODE_FATAL);
return;
@@ -1373,7 +1408,8 @@
}
{
- Mutexed<Config>::Locked config(mConfig);
+ Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
+ const std::unique_ptr<Config> &config = *configLocked;
if (config->mInputSurface) {
config->mInputSurface->disconnect();
config->mInputSurface = nullptr;
@@ -1421,7 +1457,8 @@
}
if (clearInputSurfaceIfNeeded) {
- Mutexed<Config>::Locked config(mConfig);
+ Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
+ const std::unique_ptr<Config> &config = *configLocked;
if (config->mInputSurface) {
config->mInputSurface->disconnect();
config->mInputSurface = nullptr;
@@ -1520,7 +1557,9 @@
{
Mutexed<State>::Locked state(mState);
- state->set(FLUSHED);
+ if (state->get() == FLUSHING) {
+ state->set(FLUSHED);
+ }
}
mCallback->onFlushCompleted();
}
@@ -1542,11 +1581,16 @@
mSentConfigAfterResume.clear();
{
- Mutexed<Config>::Locked config(mConfig);
+ Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
+ const std::unique_ptr<Config> &config = *configLocked;
config->queryConfiguration(comp);
}
- (void)mChannel->start(nullptr, nullptr);
+ (void)mChannel->start(nullptr, nullptr, [&]{
+ Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
+ const std::unique_ptr<Config> &config = *configLocked;
+ return config->mBuffersBoundToCodec;
+ }());
{
Mutexed<State>::Locked state(mState);
@@ -1585,13 +1629,15 @@
params->removeEntryAt(params->findEntryByName(KEY_BIT_RATE));
}
- Mutexed<Config>::Locked config(mConfig);
+ Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
+ const std::unique_ptr<Config> &config = *configLocked;
/**
* Handle input surface parameters
*/
if ((config->mDomain & (Config::IS_VIDEO | Config::IS_IMAGE))
- && (config->mDomain & Config::IS_ENCODER) && config->mInputSurface && config->mISConfig) {
+ && (config->mDomain & Config::IS_ENCODER)
+ && config->mInputSurface && config->mISConfig) {
(void)params->findInt64(PARAMETER_KEY_OFFSET_TIME, &config->mISConfig->mTimeOffsetUs);
if (params->findInt64("skip-frames-before", &config->mISConfig->mStartAtUs)) {
@@ -1644,7 +1690,8 @@
comp = state->comp;
}
ALOGV("request IDR");
- Mutexed<Config>::Locked config(mConfig);
+ Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
+ const std::unique_ptr<Config> &config = *configLocked;
std::vector<std::unique_ptr<C2Param>> params;
params.push_back(
std::make_unique<C2StreamRequestSyncFrameTuning::output>(0u, true));
@@ -1663,7 +1710,8 @@
mChannel->onInputBufferDone(frameIndex, arrayIndex);
if (arrayIndex == 0) {
// We always put no more than one buffer per work, if we use an input surface.
- Mutexed<Config>::Locked config(mConfig);
+ Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
+ const std::unique_ptr<Config> &config = *configLocked;
if (config->mInputSurface) {
config->mInputSurface->onInputBufferDone(frameIndex);
}
@@ -1740,7 +1788,8 @@
}
// handle configuration changes in work done
- Mutexed<Config>::Locked config(mConfig);
+ Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
+ const std::unique_ptr<Config> &config = *configLocked;
bool changed = !mSentConfigAfterResume.test_and_set();
Config::Watcher<C2StreamInitDataInfo::output> initData =
config->watch<C2StreamInitDataInfo::output>();
@@ -1871,15 +1920,10 @@
mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
}
-} // namespace android
-
-extern "C" android::CodecBase *CreateCodec() {
- return new android::CCodec;
-}
-
-// Create Codec 2.0 input surface
-extern "C" android::PersistentSurface *CreateInputSurface() {
+// static
+PersistentSurface *CCodec::CreateInputSurface() {
using namespace android;
+ using ::android::hardware::media::omx::V1_0::implementation::TWGraphicBufferSource;
// Attempt to create a Codec2's input surface.
std::shared_ptr<Codec2Client::InputSurface> inputSurface =
Codec2Client::CreateInputSurface();
@@ -1893,9 +1937,7 @@
return nullptr;
}
return new PersistentSurface(
- gbs->getIGraphicBufferProducer(),
- sp<IGraphicBufferSource>(
- new Omx2IGraphicBufferSource(gbs)));
+ gbs->getIGraphicBufferProducer(), new TWGraphicBufferSource(gbs));
} else {
return nullptr;
}
@@ -1906,3 +1948,243 @@
inputSurface->getHalInterface()));
}
+static status_t GetCommonAllocatorIds(
+ const std::vector<std::string> &names,
+ C2Allocator::type_t type,
+ std::set<C2Allocator::id_t> *ids) {
+ int poolMask = GetCodec2PoolMask();
+ C2PlatformAllocatorStore::id_t preferredLinearId = GetPreferredLinearAllocatorId(poolMask);
+ C2Allocator::id_t defaultAllocatorId =
+ (type == C2Allocator::LINEAR) ? preferredLinearId : C2PlatformAllocatorStore::GRALLOC;
+
+ ids->clear();
+ if (names.empty()) {
+ return OK;
+ }
+ std::shared_ptr<Codec2Client::Interface> intf{
+ Codec2Client::CreateInterfaceByName(names[0].c_str())};
+ std::vector<std::unique_ptr<C2Param>> params;
+ c2_status_t err = intf->query(
+ {}, {C2PortAllocatorsTuning::input::PARAM_TYPE}, C2_MAY_BLOCK, ¶ms);
+ if (err == C2_OK && params.size() == 1u) {
+ C2PortAllocatorsTuning::input *allocators =
+ C2PortAllocatorsTuning::input::From(params[0].get());
+ if (allocators && allocators->flexCount() > 0) {
+ ids->insert(allocators->m.values, allocators->m.values + allocators->flexCount());
+ }
+ }
+ if (ids->empty()) {
+ // The component does not advertise allocators. Use default.
+ ids->insert(defaultAllocatorId);
+ }
+ for (size_t i = 1; i < names.size(); ++i) {
+ intf = Codec2Client::CreateInterfaceByName(names[i].c_str());
+ err = intf->query(
+ {}, {C2PortAllocatorsTuning::input::PARAM_TYPE}, C2_MAY_BLOCK, ¶ms);
+ bool filtered = false;
+ if (err == C2_OK && params.size() == 1u) {
+ C2PortAllocatorsTuning::input *allocators =
+ C2PortAllocatorsTuning::input::From(params[0].get());
+ if (allocators && allocators->flexCount() > 0) {
+ filtered = true;
+ for (auto it = ids->begin(); it != ids->end(); ) {
+ bool found = false;
+ for (size_t j = 0; j < allocators->flexCount(); ++j) {
+ if (allocators->m.values[j] == *it) {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ ++it;
+ } else {
+ it = ids->erase(it);
+ }
+ }
+ }
+ }
+ if (!filtered) {
+ // The component does not advertise supported allocators. Use default.
+ bool containsDefault = (ids->count(defaultAllocatorId) > 0u);
+ if (ids->size() != (containsDefault ? 1 : 0)) {
+ ids->clear();
+ if (containsDefault) {
+ ids->insert(defaultAllocatorId);
+ }
+ }
+ }
+ }
+ // Finally, filter with pool masks
+ for (auto it = ids->begin(); it != ids->end(); ) {
+ if ((poolMask >> *it) & 1) {
+ ++it;
+ } else {
+ it = ids->erase(it);
+ }
+ }
+ return OK;
+}
+
+static status_t CalculateMinMaxUsage(
+ const std::vector<std::string> &names, uint64_t *minUsage, uint64_t *maxUsage) {
+ static C2StreamUsageTuning::input sUsage{0u /* stream id */};
+ *minUsage = 0;
+ *maxUsage = ~0ull;
+ for (const std::string &name : names) {
+ std::shared_ptr<Codec2Client::Interface> intf{
+ Codec2Client::CreateInterfaceByName(name.c_str())};
+ std::vector<C2FieldSupportedValuesQuery> fields;
+ fields.push_back(C2FieldSupportedValuesQuery::Possible(
+ C2ParamField{&sUsage, &sUsage.value}));
+ c2_status_t err = intf->querySupportedValues(fields, C2_MAY_BLOCK);
+ if (err != C2_OK) {
+ continue;
+ }
+ if (fields[0].status != C2_OK) {
+ continue;
+ }
+ const C2FieldSupportedValues &supported = fields[0].values;
+ if (supported.type != C2FieldSupportedValues::FLAGS) {
+ continue;
+ }
+ if (supported.values.empty()) {
+ *maxUsage = 0;
+ continue;
+ }
+ *minUsage |= supported.values[0].u64;
+ int64_t currentMaxUsage = 0;
+ for (const C2Value::Primitive &flags : supported.values) {
+ currentMaxUsage |= flags.u64;
+ }
+ *maxUsage &= currentMaxUsage;
+ }
+ return OK;
+}
+
+// static
+status_t CCodec::CanFetchLinearBlock(
+ const std::vector<std::string> &names, const C2MemoryUsage &usage, bool *isCompatible) {
+ uint64_t minUsage = usage.expected;
+ uint64_t maxUsage = ~0ull;
+ std::set<C2Allocator::id_t> allocators;
+ GetCommonAllocatorIds(names, C2Allocator::LINEAR, &allocators);
+ if (allocators.empty()) {
+ *isCompatible = false;
+ return OK;
+ }
+ CalculateMinMaxUsage(names, &minUsage, &maxUsage);
+ *isCompatible = ((maxUsage & minUsage) == minUsage);
+ return OK;
+}
+
+static std::shared_ptr<C2BlockPool> GetPool(C2Allocator::id_t allocId) {
+ static std::mutex sMutex{};
+ static std::map<C2Allocator::id_t, std::shared_ptr<C2BlockPool>> sPools;
+ std::unique_lock<std::mutex> lock{sMutex};
+ std::shared_ptr<C2BlockPool> pool;
+ auto it = sPools.find(allocId);
+ if (it == sPools.end()) {
+ c2_status_t err = CreateCodec2BlockPool(allocId, nullptr, &pool);
+ if (err == OK) {
+ sPools.emplace(allocId, pool);
+ } else {
+ pool.reset();
+ }
+ } else {
+ pool = it->second;
+ }
+ return pool;
+}
+
+// static
+std::shared_ptr<C2LinearBlock> CCodec::FetchLinearBlock(
+ size_t capacity, const C2MemoryUsage &usage, const std::vector<std::string> &names) {
+ uint64_t minUsage = usage.expected;
+ uint64_t maxUsage = ~0ull;
+ std::set<C2Allocator::id_t> allocators;
+ GetCommonAllocatorIds(names, C2Allocator::LINEAR, &allocators);
+ if (allocators.empty()) {
+ allocators.insert(C2PlatformAllocatorStore::DEFAULT_LINEAR);
+ }
+ CalculateMinMaxUsage(names, &minUsage, &maxUsage);
+ if ((maxUsage & minUsage) != minUsage) {
+ allocators.clear();
+ allocators.insert(C2PlatformAllocatorStore::DEFAULT_LINEAR);
+ }
+ std::shared_ptr<C2LinearBlock> block;
+ for (C2Allocator::id_t allocId : allocators) {
+ std::shared_ptr<C2BlockPool> pool = GetPool(allocId);
+ if (!pool) {
+ continue;
+ }
+ c2_status_t err = pool->fetchLinearBlock(capacity, C2MemoryUsage{minUsage}, &block);
+ if (err != C2_OK || !block) {
+ block.reset();
+ continue;
+ }
+ break;
+ }
+ return block;
+}
+
+// static
+status_t CCodec::CanFetchGraphicBlock(
+ const std::vector<std::string> &names, bool *isCompatible) {
+ uint64_t minUsage = 0;
+ uint64_t maxUsage = ~0ull;
+ std::set<C2Allocator::id_t> allocators;
+ GetCommonAllocatorIds(names, C2Allocator::GRAPHIC, &allocators);
+ if (allocators.empty()) {
+ *isCompatible = false;
+ return OK;
+ }
+ CalculateMinMaxUsage(names, &minUsage, &maxUsage);
+ *isCompatible = ((maxUsage & minUsage) == minUsage);
+ return OK;
+}
+
+// static
+std::shared_ptr<C2GraphicBlock> CCodec::FetchGraphicBlock(
+ int32_t width,
+ int32_t height,
+ int32_t format,
+ uint64_t usage,
+ const std::vector<std::string> &names) {
+ uint32_t halPixelFormat = HAL_PIXEL_FORMAT_YCBCR_420_888;
+ if (!C2Mapper::mapPixelFormatFrameworkToCodec(format, &halPixelFormat)) {
+ ALOGD("Unrecognized pixel format: %d", format);
+ return nullptr;
+ }
+ uint64_t minUsage = 0;
+ uint64_t maxUsage = ~0ull;
+ std::set<C2Allocator::id_t> allocators;
+ GetCommonAllocatorIds(names, C2Allocator::GRAPHIC, &allocators);
+ if (allocators.empty()) {
+ allocators.insert(C2PlatformAllocatorStore::DEFAULT_GRAPHIC);
+ }
+ CalculateMinMaxUsage(names, &minUsage, &maxUsage);
+ minUsage |= usage;
+ if ((maxUsage & minUsage) != minUsage) {
+ allocators.clear();
+ allocators.insert(C2PlatformAllocatorStore::DEFAULT_GRAPHIC);
+ }
+ std::shared_ptr<C2GraphicBlock> block;
+ for (C2Allocator::id_t allocId : allocators) {
+ std::shared_ptr<C2BlockPool> pool;
+ c2_status_t err = CreateCodec2BlockPool(allocId, nullptr, &pool);
+ if (err != C2_OK || !pool) {
+ continue;
+ }
+ err = pool->fetchGraphicBlock(
+ width, height, halPixelFormat, C2MemoryUsage{minUsage}, &block);
+ if (err != C2_OK || !block) {
+ block.reset();
+ continue;
+ }
+ break;
+ }
+ return block;
+}
+
+} // namespace android
+
diff --git a/media/codec2/sfplugin/CCodec.h b/media/codec2/sfplugin/CCodec.h
deleted file mode 100644
index a580d1d..0000000
--- a/media/codec2/sfplugin/CCodec.h
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef C_CODEC_H_
-#define C_CODEC_H_
-
-#include <atomic>
-#include <chrono>
-#include <list>
-#include <memory>
-#include <set>
-
-#include <C2Component.h>
-#include <codec2/hidl/client.h>
-
-#include <android/native_window.h>
-#include <media/hardware/MetadataBufferType.h>
-#include <media/stagefright/foundation/Mutexed.h>
-#include <media/stagefright/CodecBase.h>
-#include <media/stagefright/FrameRenderTracker.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/SkipCutBuffer.h>
-#include <utils/NativeHandle.h>
-#include <hardware/gralloc.h>
-#include <nativebase/nativebase.h>
-
-#include "CCodecConfig.h"
-
-namespace android {
-
-class CCodecBufferChannel;
-class InputSurfaceWrapper;
-struct MediaCodecInfo;
-
-class CCodec : public CodecBase {
-public:
- CCodec();
-
- virtual std::shared_ptr<BufferChannelBase> getBufferChannel() override;
- virtual void initiateAllocateComponent(const sp<AMessage> &msg) override;
- virtual void initiateConfigureComponent(const sp<AMessage> &msg) override;
- virtual void initiateCreateInputSurface() override;
- virtual void initiateSetInputSurface(const sp<PersistentSurface> &surface) override;
- virtual void initiateStart() override;
- virtual void initiateShutdown(bool keepComponentAllocated = false) override;
-
- virtual status_t setSurface(const sp<Surface> &surface) override;
-
- virtual void signalFlush() override;
- virtual void signalResume() override;
-
- virtual void signalSetParameters(const sp<AMessage> ¶ms) override;
- virtual void signalEndOfInputStream() override;
- virtual void signalRequestIDRFrame() override;
-
- void initiateReleaseIfStuck();
- void onWorkDone(std::list<std::unique_ptr<C2Work>> &workItems);
- void onInputBufferDone(uint64_t frameIndex, size_t arrayIndex);
-
-protected:
- virtual ~CCodec();
-
- virtual void onMessageReceived(const sp<AMessage> &msg) override;
-
-private:
- typedef std::chrono::steady_clock::time_point TimePoint;
-
- status_t tryAndReportOnError(std::function<status_t()> job);
-
- void initiateStop();
- void initiateRelease(bool sendCallback = true);
-
- void allocate(const sp<MediaCodecInfo> &codecInfo);
- void configure(const sp<AMessage> &msg);
- void start();
- void stop();
- void flush();
- void release(bool sendCallback);
-
- /**
- * Creates an input surface for the current device configuration compatible with CCodec.
- * This could be backed by the C2 HAL or the OMX HAL.
- */
- static sp<PersistentSurface> CreateCompatibleInputSurface();
-
- /// Creates an input surface to the OMX HAL
- static sp<PersistentSurface> CreateOmxInputSurface();
-
- /// handle a create input surface call
- void createInputSurface();
- void setInputSurface(const sp<PersistentSurface> &surface);
- status_t setupInputSurface(const std::shared_ptr<InputSurfaceWrapper> &surface);
-
- void setDeadline(
- const TimePoint &now,
- const std::chrono::milliseconds &timeout,
- const char *name);
-
- enum {
- kWhatAllocate,
- kWhatConfigure,
- kWhatStart,
- kWhatFlush,
- kWhatStop,
- kWhatRelease,
- kWhatCreateInputSurface,
- kWhatSetInputSurface,
- kWhatSetParameters,
-
- kWhatWorkDone,
- kWhatWatch,
- };
-
- enum {
- RELEASED,
- ALLOCATED,
- FLUSHED,
- RUNNING,
-
- ALLOCATING, // RELEASED -> ALLOCATED
- STARTING, // ALLOCATED -> RUNNING
- STOPPING, // RUNNING -> ALLOCATED
- FLUSHING, // RUNNING -> FLUSHED
- RESUMING, // FLUSHED -> RUNNING
- RELEASING, // {ANY EXCEPT RELEASED} -> RELEASED
- };
-
- struct State {
- inline State() : mState(RELEASED) {}
- inline int get() const { return mState; }
- inline void set(int newState) { mState = newState; }
-
- std::shared_ptr<Codec2Client::Component> comp;
- private:
- int mState;
- };
-
- struct NamedTimePoint {
- NamedTimePoint() : mTimePoint(TimePoint::max()), mName("") {}
-
- inline void set(
- const TimePoint &timePoint,
- const char *name) {
- mTimePoint = timePoint;
- mName = name;
- }
-
- inline TimePoint get() const { return mTimePoint; }
- inline const char *getName() const { return mName; }
- private:
- TimePoint mTimePoint;
- const char *mName;
- };
-
- Mutexed<State> mState;
- std::shared_ptr<CCodecBufferChannel> mChannel;
-
- std::shared_ptr<Codec2Client> mClient;
- std::shared_ptr<Codec2Client::Listener> mClientListener;
- struct ClientListener;
-
- Mutexed<NamedTimePoint> mDeadline;
- typedef CCodecConfig Config;
- Mutexed<Config> mConfig;
- Mutexed<std::list<std::unique_ptr<C2Work>>> mWorkDoneQueue;
- std::atomic_flag mSentConfigAfterResume;
-
- friend class CCodecCallbackImpl;
-
- DISALLOW_EVIL_CONSTRUCTORS(CCodec);
-};
-
-} // namespace android
-
-#endif // C_CODEC_H_
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 4ee6c1c..6b389d5 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -27,9 +27,13 @@
#include <C2Debug.h>
#include <android/hardware/cas/native/1.0/IDescrambler.h>
+#include <android/hardware/drm/1.0/types.h>
#include <android-base/stringprintf.h>
+#include <binder/MemoryBase.h>
#include <binder/MemoryDealer.h>
+#include <cutils/properties.h>
#include <gui/Surface.h>
+#include <hidlmemory/FrameworkUtils.h>
#include <media/openmax/OMX_Core.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ALookup.h>
@@ -38,12 +42,12 @@
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MediaCodec.h>
#include <media/stagefright/MediaCodecConstants.h>
+#include <media/stagefright/SkipCutBuffer.h>
#include <media/MediaCodecBuffer.h>
#include <system/window.h>
#include "CCodecBufferChannel.h"
#include "Codec2Buffer.h"
-#include "SkipCutBuffer.h"
namespace android {
@@ -51,10 +55,14 @@
using hardware::hidl_handle;
using hardware::hidl_string;
using hardware::hidl_vec;
+using hardware::fromHeap;
+using hardware::HidlMemory;
+
using namespace hardware::cas::V1_0;
using namespace hardware::cas::native::V1_0;
using CasStatus = hardware::cas::V1_0::Status;
+using DrmBufferType = hardware::drm::V1_0::BufferType;
namespace {
@@ -242,7 +250,7 @@
}
CCodecBufferChannel::~CCodecBufferChannel() {
- if (mCrypto != nullptr && mDealer != nullptr && mHeapSeqNum >= 0) {
+ if (mCrypto != nullptr && mHeapSeqNum >= 0) {
mCrypto->unsetHeap(mHeapSeqNum);
}
}
@@ -402,6 +410,173 @@
return OK;
}
+status_t CCodecBufferChannel::attachBuffer(
+ const std::shared_ptr<C2Buffer> &c2Buffer,
+ const sp<MediaCodecBuffer> &buffer) {
+ if (!buffer->copy(c2Buffer)) {
+ return -ENOSYS;
+ }
+ return OK;
+}
+
+void CCodecBufferChannel::ensureDecryptDestination(size_t size) {
+ if (!mDecryptDestination || mDecryptDestination->size() < size) {
+ sp<IMemoryHeap> heap{new MemoryHeapBase(size * 2)};
+ if (mDecryptDestination && mCrypto && mHeapSeqNum >= 0) {
+ mCrypto->unsetHeap(mHeapSeqNum);
+ }
+ mDecryptDestination = new MemoryBase(heap, 0, size * 2);
+ if (mCrypto) {
+ mHeapSeqNum = mCrypto->setHeap(hardware::fromHeap(heap));
+ }
+ }
+}
+
+int32_t CCodecBufferChannel::getHeapSeqNum(const sp<HidlMemory> &memory) {
+ CHECK(mCrypto);
+ auto it = mHeapSeqNumMap.find(memory);
+ int32_t heapSeqNum = -1;
+ if (it == mHeapSeqNumMap.end()) {
+ heapSeqNum = mCrypto->setHeap(memory);
+ mHeapSeqNumMap.emplace(memory, heapSeqNum);
+ } else {
+ heapSeqNum = it->second;
+ }
+ return heapSeqNum;
+}
+
+status_t CCodecBufferChannel::attachEncryptedBuffer(
+ const sp<hardware::HidlMemory> &memory,
+ bool secure,
+ const uint8_t *key,
+ const uint8_t *iv,
+ CryptoPlugin::Mode mode,
+ CryptoPlugin::Pattern pattern,
+ size_t offset,
+ const CryptoPlugin::SubSample *subSamples,
+ size_t numSubSamples,
+ const sp<MediaCodecBuffer> &buffer) {
+ static const C2MemoryUsage kSecureUsage{C2MemoryUsage::READ_PROTECTED, 0};
+ static const C2MemoryUsage kDefaultReadWriteUsage{
+ C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
+
+ size_t size = 0;
+ for (size_t i = 0; i < numSubSamples; ++i) {
+ size += subSamples[i].mNumBytesOfClearData + subSamples[i].mNumBytesOfEncryptedData;
+ }
+ std::shared_ptr<C2BlockPool> pool = mBlockPools.lock()->inputPool;
+ std::shared_ptr<C2LinearBlock> block;
+ c2_status_t err = pool->fetchLinearBlock(
+ size,
+ secure ? kSecureUsage : kDefaultReadWriteUsage,
+ &block);
+ if (err != C2_OK) {
+ return NO_MEMORY;
+ }
+ if (!secure) {
+ ensureDecryptDestination(size);
+ }
+ ssize_t result = -1;
+ ssize_t codecDataOffset = 0;
+ if (mCrypto) {
+ AString errorDetailMsg;
+ int32_t heapSeqNum = getHeapSeqNum(memory);
+ hardware::drm::V1_0::SharedBuffer src{(uint32_t)heapSeqNum, offset, size};
+ hardware::drm::V1_0::DestinationBuffer dst;
+ if (secure) {
+ dst.type = DrmBufferType::NATIVE_HANDLE;
+ dst.secureMemory = hardware::hidl_handle(block->handle());
+ } else {
+ dst.type = DrmBufferType::SHARED_MEMORY;
+ IMemoryToSharedBuffer(
+ mDecryptDestination, mHeapSeqNum, &dst.nonsecureMemory);
+ }
+ result = mCrypto->decrypt(
+ key, iv, mode, pattern, src, 0, subSamples, numSubSamples,
+ dst, &errorDetailMsg);
+ if (result < 0) {
+ return result;
+ }
+ if (dst.type == DrmBufferType::SHARED_MEMORY) {
+ C2WriteView view = block->map().get();
+ if (view.error() != C2_OK) {
+ return false;
+ }
+ if (view.size() < result) {
+ return false;
+ }
+ memcpy(view.data(), mDecryptDestination->unsecurePointer(), result);
+ }
+ } else {
+ // Here we cast CryptoPlugin::SubSample to hardware::cas::native::V1_0::SubSample
+ // directly, the structure definitions should match as checked in DescramblerImpl.cpp.
+ hidl_vec<SubSample> hidlSubSamples;
+ hidlSubSamples.setToExternal((SubSample *)subSamples, numSubSamples, false /*own*/);
+
+ hardware::cas::native::V1_0::SharedBuffer src{*memory, offset, size};
+ hardware::cas::native::V1_0::DestinationBuffer dst;
+ if (secure) {
+ dst.type = BufferType::NATIVE_HANDLE;
+ dst.secureMemory = hardware::hidl_handle(block->handle());
+ } else {
+ dst.type = BufferType::SHARED_MEMORY;
+ dst.nonsecureMemory = src;
+ }
+
+ CasStatus status = CasStatus::OK;
+ hidl_string detailedError;
+ ScramblingControl sctrl = ScramblingControl::UNSCRAMBLED;
+
+ if (key != nullptr) {
+ sctrl = (ScramblingControl)key[0];
+ // Adjust for the PES offset
+ codecDataOffset = key[2] | (key[3] << 8);
+ }
+
+ auto returnVoid = mDescrambler->descramble(
+ sctrl,
+ hidlSubSamples,
+ src,
+ 0,
+ dst,
+ 0,
+ [&status, &result, &detailedError] (
+ CasStatus _status, uint32_t _bytesWritten,
+ const hidl_string& _detailedError) {
+ status = _status;
+ result = (ssize_t)_bytesWritten;
+ detailedError = _detailedError;
+ });
+
+ if (!returnVoid.isOk() || status != CasStatus::OK || result < 0) {
+ ALOGI("[%s] descramble failed, trans=%s, status=%d, result=%zd",
+ mName, returnVoid.description().c_str(), status, result);
+ return UNKNOWN_ERROR;
+ }
+
+ if (result < codecDataOffset) {
+ ALOGD("invalid codec data offset: %zd, result %zd", codecDataOffset, result);
+ return BAD_VALUE;
+ }
+ }
+ if (!secure) {
+ C2WriteView view = block->map().get();
+ if (view.error() != C2_OK) {
+ return UNKNOWN_ERROR;
+ }
+ if (view.size() < result) {
+ return UNKNOWN_ERROR;
+ }
+ memcpy(view.data(), mDecryptDestination->unsecurePointer(), result);
+ }
+ std::shared_ptr<C2Buffer> c2Buffer{C2Buffer::CreateLinearBuffer(
+ block->share(codecDataOffset, result - codecDataOffset, C2Fence{}))};
+ if (!buffer->copy(c2Buffer)) {
+ return -ENOSYS;
+ }
+ return OK;
+}
+
status_t CCodecBufferChannel::queueInputBuffer(const sp<MediaCodecBuffer> &buffer) {
QueueGuard guard(mSync);
if (!guard.isRunning()) {
@@ -429,24 +604,31 @@
ssize_t result = -1;
ssize_t codecDataOffset = 0;
- if (mCrypto != nullptr) {
- ICrypto::DestinationBuffer destination;
+ if (numSubSamples == 1
+ && subSamples[0].mNumBytesOfClearData == 0
+ && subSamples[0].mNumBytesOfEncryptedData == 0) {
+ // We don't need to go through crypto or descrambler if the input is empty.
+ result = 0;
+ } else if (mCrypto != nullptr) {
+ hardware::drm::V1_0::DestinationBuffer destination;
if (secure) {
- destination.mType = ICrypto::kDestinationTypeNativeHandle;
- destination.mHandle = encryptedBuffer->handle();
+ destination.type = DrmBufferType::NATIVE_HANDLE;
+ destination.secureMemory = hidl_handle(encryptedBuffer->handle());
} else {
- destination.mType = ICrypto::kDestinationTypeSharedMemory;
- destination.mSharedMemory = mDecryptDestination;
+ destination.type = DrmBufferType::SHARED_MEMORY;
+ IMemoryToSharedBuffer(
+ mDecryptDestination, mHeapSeqNum, &destination.nonsecureMemory);
}
- ICrypto::SourceBuffer source;
+ hardware::drm::V1_0::SharedBuffer source;
encryptedBuffer->fillSourceBuffer(&source);
result = mCrypto->decrypt(
key, iv, mode, pattern, source, buffer->offset(),
subSamples, numSubSamples, destination, errorDetailMsg);
if (result < 0) {
+ ALOGI("[%s] decrypt failed: result=%zd", mName, result);
return result;
}
- if (destination.mType == ICrypto::kDestinationTypeSharedMemory) {
+ if (destination.type == DrmBufferType::SHARED_MEMORY) {
encryptedBuffer->copyDecryptedContent(mDecryptDestination, result);
}
} else {
@@ -766,7 +948,9 @@
}
status_t CCodecBufferChannel::start(
- const sp<AMessage> &inputFormat, const sp<AMessage> &outputFormat) {
+ const sp<AMessage> &inputFormat,
+ const sp<AMessage> &outputFormat,
+ bool buffersBoundToCodec) {
C2StreamBufferTypeSetting::input iStreamFormat(0u);
C2StreamBufferTypeSetting::output oStreamFormat(0u);
C2PortReorderBufferDepthTuning::output reorderDepth;
@@ -818,10 +1002,8 @@
bool secure = mComponent->getName().find(".secure") != std::string::npos;
std::shared_ptr<C2AllocatorStore> allocatorStore = GetCodec2PlatformAllocatorStore();
- int poolMask = property_get_int32(
- "debug.stagefright.c2-poolmask",
- 1 << C2PlatformAllocatorStore::ION |
- 1 << C2PlatformAllocatorStore::BUFFERQUEUE);
+ int poolMask = GetCodec2PoolMask();
+ C2PlatformAllocatorStore::id_t preferredLinearId = GetPreferredLinearAllocatorId(poolMask);
if (inputFormat != nullptr) {
bool graphic = (iStreamFormat.value == C2BufferData::GRAPHIC);
@@ -831,7 +1013,7 @@
// set default allocator ID.
pools->inputAllocatorId = (graphic) ? C2PlatformAllocatorStore::GRALLOC
- : C2PlatformAllocatorStore::ION;
+ : preferredLinearId;
// query C2PortAllocatorsTuning::input from component. If an allocator ID is obtained
// from component, create the input block pool with given ID. Otherwise, use default IDs.
@@ -891,7 +1073,9 @@
input->numSlots = numInputSlots;
input->extraBuffers.flush();
input->numExtraSlots = 0u;
- if (graphic) {
+ if (!buffersBoundToCodec) {
+ input->buffers.reset(new SlotInputBuffers(mName));
+ } else if (graphic) {
if (mInputSurface) {
input->buffers.reset(new DummyInputBuffers(mName));
} else if (mMetaMode == MODE_ANW) {
@@ -918,7 +1102,8 @@
mDecryptDestination = mDealer->allocate((size_t)capacity);
}
if (mCrypto != nullptr && mHeapSeqNum < 0) {
- mHeapSeqNum = mCrypto->setHeap(mDealer->getMemoryHeap());
+ sp<HidlMemory> heap = fromHeap(mDealer->getMemoryHeap());
+ mHeapSeqNum = mCrypto->setHeap(heap);
} else {
mHeapSeqNum = -1;
}
@@ -969,7 +1154,7 @@
// set default allocator ID.
pools->outputAllocatorId = (graphic) ? C2PlatformAllocatorStore::GRALLOC
- : C2PlatformAllocatorStore::ION;
+ : preferredLinearId;
// query C2PortAllocatorsTuning::output from component, or use default allocator if
// unsuccessful.
@@ -1064,7 +1249,7 @@
output->outputDelay = outputDelayValue;
output->numSlots = numOutputSlots;
if (graphic) {
- if (outputSurface) {
+ if (outputSurface || !buffersBoundToCodec) {
output->buffers.reset(new GraphicOutputBuffers(mName));
} else {
output->buffers.reset(new RawGraphicOutputBuffers(numOutputSlots, mName));
@@ -1083,12 +1268,13 @@
outputGeneration);
}
- if (oStreamFormat.value == C2BufferData::LINEAR
- && mComponentName.find("c2.qti.") == std::string::npos) {
- // WORKAROUND: if we're using early CSD workaround we convert to
- // array mode, to appease apps assuming the output
- // buffers to be of the same size.
- output->buffers = output->buffers->toArrayMode(numOutputSlots);
+ if (oStreamFormat.value == C2BufferData::LINEAR) {
+ if (buffersBoundToCodec) {
+ // WORKAROUND: if we're using early CSD workaround we convert to
+ // array mode, to appease apps assuming the output
+ // buffers to be of the same size.
+ output->buffers = output->buffers->toArrayMode(numOutputSlots);
+ }
int32_t channelCount;
int32_t sampleRate;
@@ -1136,8 +1322,9 @@
}
C2StreamBufferTypeSetting::output oStreamFormat(0u);
- c2_status_t err = mComponent->query({ &oStreamFormat }, {}, C2_DONT_BLOCK, nullptr);
- if (err != C2_OK) {
+ C2PrependHeaderModeSetting prepend(PREPEND_HEADER_TO_NONE);
+ c2_status_t err = mComponent->query({ &oStreamFormat, &prepend }, {}, C2_DONT_BLOCK, nullptr);
+ if (err != C2_OK && err != C2_BAD_INDEX) {
return UNKNOWN_ERROR;
}
size_t numInputSlots = mInput.lock()->numSlots;
@@ -1177,7 +1364,7 @@
mName, buffer->capacity(), config->size());
}
} else if (oStreamFormat.value == C2BufferData::LINEAR && i == 0
- && mComponentName.find("c2.qti.") == std::string::npos) {
+ && (!prepend || prepend.value == PREPEND_HEADER_TO_NONE)) {
// WORKAROUND: Some apps expect CSD available without queueing
// any input. Queue an empty buffer to get the CSD.
buffer->setRange(0, 0);
@@ -1661,6 +1848,24 @@
mMetaMode = mode;
}
+void CCodecBufferChannel::setCrypto(const sp<ICrypto> &crypto) {
+ if (mCrypto != nullptr) {
+ for (std::pair<wp<HidlMemory>, int32_t> entry : mHeapSeqNumMap) {
+ mCrypto->unsetHeap(entry.second);
+ }
+ mHeapSeqNumMap.clear();
+ if (mHeapSeqNum >= 0) {
+ mCrypto->unsetHeap(mHeapSeqNum);
+ mHeapSeqNum = -1;
+ }
+ }
+ mCrypto = crypto;
+}
+
+void CCodecBufferChannel::setDescrambler(const sp<IDescrambler> &descrambler) {
+ mDescrambler = descrambler;
+}
+
status_t toStatusT(c2_status_t c2s, c2_operation_t c2op) {
// C2_OK is always translated to OK.
if (c2s == C2_OK) {
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.h b/media/codec2/sfplugin/CCodecBufferChannel.h
index ee3455d..0263211 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.h
+++ b/media/codec2/sfplugin/CCodecBufferChannel.h
@@ -29,7 +29,6 @@
#include <codec2/hidl/client.h>
#include <media/stagefright/foundation/Mutexed.h>
#include <media/stagefright/CodecBase.h>
-#include <media/ICrypto.h>
#include "CCodecBuffers.h"
#include "InputSurfaceWrapper.h"
@@ -57,6 +56,9 @@
virtual ~CCodecBufferChannel();
// BufferChannelBase interface
+ void setCrypto(const sp<ICrypto> &crypto) override;
+ void setDescrambler(const sp<IDescrambler> &descrambler) override;
+
virtual status_t queueInputBuffer(const sp<MediaCodecBuffer> &buffer) override;
virtual status_t queueSecureInputBuffer(
const sp<MediaCodecBuffer> &buffer,
@@ -68,6 +70,20 @@
const CryptoPlugin::SubSample *subSamples,
size_t numSubSamples,
AString *errorDetailMsg) override;
+ virtual status_t attachBuffer(
+ const std::shared_ptr<C2Buffer> &c2Buffer,
+ const sp<MediaCodecBuffer> &buffer) override;
+ virtual status_t attachEncryptedBuffer(
+ const sp<hardware::HidlMemory> &memory,
+ bool secure,
+ const uint8_t *key,
+ const uint8_t *iv,
+ CryptoPlugin::Mode mode,
+ CryptoPlugin::Pattern pattern,
+ size_t offset,
+ const CryptoPlugin::SubSample *subSamples,
+ size_t numSubSamples,
+ const sp<MediaCodecBuffer> &buffer) override;
virtual status_t renderOutputBuffer(
const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) override;
virtual status_t discardBuffer(const sp<MediaCodecBuffer> &buffer) override;
@@ -106,7 +122,10 @@
* Start queueing buffers to the component. This object should never queue
* buffers before this call has completed.
*/
- status_t start(const sp<AMessage> &inputFormat, const sp<AMessage> &outputFormat);
+ status_t start(
+ const sp<AMessage> &inputFormat,
+ const sp<AMessage> &outputFormat,
+ bool buffersBoundToCodec);
/**
* Request initial input buffers to be filled by client.
@@ -214,11 +233,14 @@
std::unique_ptr<C2Work> work, const sp<AMessage> &outputFormat,
const C2StreamInitDataInfo::output *initData);
void sendOutputBuffers();
+ void ensureDecryptDestination(size_t size);
+ int32_t getHeapSeqNum(const sp<hardware::HidlMemory> &memory);
QueueSync mSync;
sp<MemoryDealer> mDealer;
sp<IMemory> mDecryptDestination;
int32_t mHeapSeqNum;
+ std::map<wp<hardware::HidlMemory>, int32_t> mHeapSeqNumMap;
std::shared_ptr<Codec2Client::Component> mComponent;
std::string mComponentName; ///< component name for debugging
@@ -319,6 +341,9 @@
std::atomic_bool mInputMetEos;
std::once_flag mRenderWarningFlag;
+ sp<ICrypto> mCrypto;
+ sp<IDescrambler> mDescrambler;
+
inline bool hasCryptoOrDescrambler() {
return mCrypto != nullptr || mDescrambler != nullptr;
}
diff --git a/media/codec2/sfplugin/CCodecBuffers.cpp b/media/codec2/sfplugin/CCodecBuffers.cpp
index 26c702d..265eeb7 100644
--- a/media/codec2/sfplugin/CCodecBuffers.cpp
+++ b/media/codec2/sfplugin/CCodecBuffers.cpp
@@ -22,6 +22,7 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaCodecConstants.h>
+#include <media/stagefright/SkipCutBuffer.h>
#include "CCodecBuffers.h"
@@ -493,6 +494,44 @@
return mAllocate();
}
+// SlotInputBuffers
+
+bool SlotInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
+ sp<Codec2Buffer> newBuffer = createNewBuffer();
+ *index = mImpl.assignSlot(newBuffer);
+ *buffer = newBuffer;
+ return true;
+}
+
+bool SlotInputBuffers::releaseBuffer(
+ const sp<MediaCodecBuffer> &buffer,
+ std::shared_ptr<C2Buffer> *c2buffer,
+ bool release) {
+ return mImpl.releaseSlot(buffer, c2buffer, release);
+}
+
+bool SlotInputBuffers::expireComponentBuffer(
+ const std::shared_ptr<C2Buffer> &c2buffer) {
+ return mImpl.expireComponentBuffer(c2buffer);
+}
+
+void SlotInputBuffers::flush() {
+ mImpl.flush();
+}
+
+std::unique_ptr<InputBuffers> SlotInputBuffers::toArrayMode(size_t) {
+ TRESPASS("Array mode should not be called at non-legacy mode");
+ return nullptr;
+}
+
+size_t SlotInputBuffers::numClientBuffers() const {
+ return mImpl.numClientBuffers();
+}
+
+sp<Codec2Buffer> SlotInputBuffers::createNewBuffer() {
+ return new DummyContainerBuffer{mFormat, nullptr};
+}
+
// LinearInputBuffers
bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
@@ -878,9 +917,10 @@
switch (c2buffer->data().type()) {
case C2BufferData::LINEAR: {
uint32_t size = kLinearBufferSize;
- const C2ConstLinearBlock &block = c2buffer->data().linearBlocks().front();
- if (block.size() < kMaxLinearBufferSize / 2) {
- size = block.size() * 2;
+ const std::vector<C2ConstLinearBlock> &linear_blocks = c2buffer->data().linearBlocks();
+ const uint32_t block_size = linear_blocks.front().size();
+ if (block_size < kMaxLinearBufferSize / 2) {
+ size = block_size * 2;
} else {
size = kMaxLinearBufferSize;
}
diff --git a/media/codec2/sfplugin/CCodecBuffers.h b/media/codec2/sfplugin/CCodecBuffers.h
index 2cb6b81..bae08e0 100644
--- a/media/codec2/sfplugin/CCodecBuffers.h
+++ b/media/codec2/sfplugin/CCodecBuffers.h
@@ -25,10 +25,11 @@
#include <media/MediaCodecBuffer.h>
#include "Codec2Buffer.h"
-#include "SkipCutBuffer.h"
namespace android {
+class SkipCutBuffer;
+
constexpr size_t kLinearBufferSize = 1048576;
// This can fit 4K RGBA frame, and most likely client won't need more than this.
constexpr size_t kMaxLinearBufferSize = 4096 * 2304 * 4;
@@ -546,6 +547,36 @@
std::function<sp<Codec2Buffer>()> mAllocate;
};
+class SlotInputBuffers : public InputBuffers {
+public:
+ SlotInputBuffers(const char *componentName, const char *name = "Slot-Input")
+ : InputBuffers(componentName, name),
+ mImpl(mName) { }
+ ~SlotInputBuffers() override = default;
+
+ bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) final;
+
+ bool releaseBuffer(
+ const sp<MediaCodecBuffer> &buffer,
+ std::shared_ptr<C2Buffer> *c2buffer,
+ bool release) final;
+
+ bool expireComponentBuffer(
+ const std::shared_ptr<C2Buffer> &c2buffer) final;
+
+ void flush() final;
+
+ std::unique_ptr<InputBuffers> toArrayMode(size_t size) final;
+
+ size_t numClientBuffers() const final;
+
+protected:
+ sp<Codec2Buffer> createNewBuffer() final;
+
+private:
+ FlexBuffersImpl mImpl;
+};
+
class LinearInputBuffers : public InputBuffers {
public:
LinearInputBuffers(const char *componentName, const char *name = "1D-Input")
diff --git a/media/codec2/sfplugin/CCodecConfig.cpp b/media/codec2/sfplugin/CCodecConfig.cpp
index 5adcd94..051f88a 100644
--- a/media/codec2/sfplugin/CCodecConfig.cpp
+++ b/media/codec2/sfplugin/CCodecConfig.cpp
@@ -20,7 +20,6 @@
#include <log/log.h>
#include <C2Component.h>
-#include <C2Debug.h>
#include <C2Param.h>
#include <util/C2InterfaceHelper.h>
@@ -34,6 +33,8 @@
#define DRC_DEFAULT_MOBILE_DRC_BOOST 127 /* maximum compression of dynamic range for mobile conf */
#define DRC_DEFAULT_MOBILE_DRC_HEAVY 1 /* switch for heavy compression for mobile conf */
#define DRC_DEFAULT_MOBILE_DRC_EFFECT 3 /* MPEG-D DRC effect type; 3 => Limited playback range */
+#define DRC_DEFAULT_MOBILE_DRC_ALBUM 0 /* MPEG-D DRC album mode; 0 => album mode is disabled, 1 => album mode is enabled */
+#define DRC_DEFAULT_MOBILE_OUTPUT_LOUDNESS -1 /* decoder output loudness; -1 => the value is unknown, otherwise dB step value (e.g. 64 for -16 dB) */
#define DRC_DEFAULT_MOBILE_ENC_LEVEL (-1) /* encoder target level; -1 => the value is unknown, otherwise dB step value (e.g. 64 for -16 dB) */
// names of properties that can be used to override the default DRC settings
#define PROP_DRC_OVERRIDE_REF_LEVEL "aac_drc_reference_level"
@@ -49,6 +50,27 @@
namespace {
+void C2ValueToMessageItem(const C2Value &value, AMessage::ItemData &item) {
+ int32_t int32Value;
+ uint32_t uint32Value;
+ int64_t int64Value;
+ uint64_t uint64Value;
+ float floatValue;
+ if (value.get(&int32Value)) {
+ item.set(int32Value);
+ } else if (value.get(&uint32Value) && uint32Value <= uint32_t(INT32_MAX)) {
+ // SDK does not support unsigned values
+ item.set((int32_t)uint32Value);
+ } else if (value.get(&int64Value)) {
+ item.set(int64Value);
+ } else if (value.get(&uint64Value) && uint64Value <= uint64_t(INT64_MAX)) {
+ // SDK does not support unsigned values
+ item.set((int64_t)uint64Value);
+ } else if (value.get(&floatValue)) {
+ item.set(floatValue);
+ }
+}
+
/**
* mapping between SDK and Codec 2.0 configurations.
*/
@@ -138,27 +160,10 @@
/// Maps from a C2Value to an SDK value in an AMessage.
AMessage::ItemData mapToMessage(C2Value value) const {
AMessage::ItemData item;
- int32_t int32Value;
- uint32_t uint32Value;
- int64_t int64Value;
- uint64_t uint64Value;
- float floatValue;
if (value.type() != C2Value::NO_INIT && mReverse) {
value = mReverse(value);
}
- if (value.get(&int32Value)) {
- item.set(int32Value);
- } else if (value.get(&uint32Value) && uint32Value <= uint32_t(INT32_MAX)) {
- // SDK does not support unsigned values
- item.set((int32_t)uint32Value);
- } else if (value.get(&int64Value)) {
- item.set(int64Value);
- } else if (value.get(&uint64Value) && uint64Value <= uint64_t(INT64_MAX)) {
- // SDK does not support unsigned values
- item.set((int64_t)uint64Value);
- } else if (value.get(&floatValue)) {
- item.set(floatValue);
- }
+ C2ValueToMessageItem(value, item);
return item;
}
@@ -179,10 +184,10 @@
template <typename PORT, typename STREAM>
AString QueryMediaTypeImpl(
- const std::shared_ptr<Codec2Client::Component> &component) {
+ const std::shared_ptr<Codec2Client::Configurable> &configurable) {
AString mediaType;
std::vector<std::unique_ptr<C2Param>> queried;
- c2_status_t c2err = component->query(
+ c2_status_t c2err = configurable->query(
{}, { PORT::PARAM_TYPE, STREAM::PARAM_TYPE }, C2_DONT_BLOCK, &queried);
if (c2err != C2_OK && queried.size() == 0) {
ALOGD("Query media type failed => %s", asString(c2err));
@@ -207,13 +212,13 @@
}
AString QueryMediaType(
- bool input, const std::shared_ptr<Codec2Client::Component> &component) {
+ bool input, const std::shared_ptr<Codec2Client::Configurable> &configurable) {
typedef C2PortMediaTypeSetting P;
typedef C2StreamMediaTypeSetting S;
if (input) {
- return QueryMediaTypeImpl<P::input, S::input>(component);
+ return QueryMediaTypeImpl<P::input, S::input>(configurable);
} else {
- return QueryMediaTypeImpl<P::output, S::output>(component);
+ return QueryMediaTypeImpl<P::output, S::output>(configurable);
}
}
@@ -595,34 +600,18 @@
.withMappers([](C2Value v) -> C2Value {
int32_t value;
if (v.get(&value)) {
- switch (value) {
- case COLOR_FormatSurface:
- return (uint32_t)HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
- case COLOR_FormatYUV420Flexible:
- return (uint32_t)HAL_PIXEL_FORMAT_YCBCR_420_888;
- case COLOR_FormatYUV420Planar:
- case COLOR_FormatYUV420SemiPlanar:
- case COLOR_FormatYUV420PackedPlanar:
- case COLOR_FormatYUV420PackedSemiPlanar:
- return (uint32_t)HAL_PIXEL_FORMAT_YV12;
- default:
- // TODO: support some sort of passthrough
- break;
+ uint32_t result;
+ if (C2Mapper::mapPixelFormatFrameworkToCodec(value, &result)) {
+ return result;
}
}
return C2Value();
}, [](C2Value v) -> C2Value {
uint32_t value;
if (v.get(&value)) {
- switch (value) {
- case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
- return COLOR_FormatSurface;
- case HAL_PIXEL_FORMAT_YV12:
- case HAL_PIXEL_FORMAT_YCBCR_420_888:
- return COLOR_FormatYUV420Flexible;
- default:
- // TODO: support some sort of passthrough
- break;
+ int32_t result;
+ if (C2Mapper::mapPixelFormatCodecToFramework(value, &result)) {
+ return result;
}
}
return C2Value();
@@ -716,63 +705,101 @@
// convert to dBFS and add default
add(ConfigMapper(KEY_AAC_DRC_TARGET_REFERENCE_LEVEL, C2_PARAMKEY_DRC_TARGET_REFERENCE_LEVEL, "value")
- .limitTo(D::AUDIO & D::DECODER & D::CONFIG)
- .withMapper([](C2Value v) -> C2Value {
+ .limitTo(D::AUDIO & D::DECODER & (D::CONFIG | D::PARAM | D::READ))
+ .withMappers([](C2Value v) -> C2Value {
int32_t value;
- if (!v.get(&value) || value < 0) {
+ if (!v.get(&value) || value < -1) {
value = property_get_int32(PROP_DRC_OVERRIDE_REF_LEVEL, DRC_DEFAULT_MOBILE_REF_LEVEL);
}
return float(-0.25 * c2_min(value, 127));
+ },[](C2Value v) -> C2Value {
+ float value;
+ if (v.get(&value)) {
+ return (int32_t) (-4. * value);
+ }
+ return C2Value();
}));
// convert to 0-1 (%) and add default
add(ConfigMapper(KEY_AAC_DRC_ATTENUATION_FACTOR, C2_PARAMKEY_DRC_ATTENUATION_FACTOR, "value")
- .limitTo(D::AUDIO & D::DECODER & D::CONFIG)
- .withMapper([](C2Value v) -> C2Value {
+ .limitTo(D::AUDIO & D::DECODER & (D::CONFIG | D::PARAM | D::READ))
+ .withMappers([](C2Value v) -> C2Value {
int32_t value;
if (!v.get(&value) || value < 0) {
value = property_get_int32(PROP_DRC_OVERRIDE_CUT, DRC_DEFAULT_MOBILE_DRC_CUT);
}
return float(c2_min(value, 127) / 127.);
+ },[](C2Value v) -> C2Value {
+ float value;
+ if (v.get(&value)) {
+ return (int32_t) (value * 127. + 0.5);
+ }
+ else {
+ return C2Value();
+ }
}));
// convert to 0-1 (%) and add default
add(ConfigMapper(KEY_AAC_DRC_BOOST_FACTOR, C2_PARAMKEY_DRC_BOOST_FACTOR, "value")
- .limitTo(D::AUDIO & D::DECODER & D::CONFIG)
- .withMapper([](C2Value v) -> C2Value {
+ .limitTo(D::AUDIO & D::DECODER & (D::CONFIG | D::PARAM | D::READ))
+ .withMappers([](C2Value v) -> C2Value {
int32_t value;
if (!v.get(&value) || value < 0) {
value = property_get_int32(PROP_DRC_OVERRIDE_BOOST, DRC_DEFAULT_MOBILE_DRC_BOOST);
}
return float(c2_min(value, 127) / 127.);
+ },[](C2Value v) -> C2Value {
+ float value;
+ if (v.get(&value)) {
+ return (int32_t) (value * 127. + 0.5);
+ }
+ else {
+ return C2Value();
+ }
}));
// convert to compression type and add default
add(ConfigMapper(KEY_AAC_DRC_HEAVY_COMPRESSION, C2_PARAMKEY_DRC_COMPRESSION_MODE, "value")
- .limitTo(D::AUDIO & D::DECODER & D::CONFIG)
- .withMapper([](C2Value v) -> C2Value {
+ .limitTo(D::AUDIO & D::DECODER & (D::CONFIG | D::PARAM | D::READ))
+ .withMappers([](C2Value v) -> C2Value {
int32_t value;
if (!v.get(&value) || value < 0) {
value = property_get_int32(PROP_DRC_OVERRIDE_HEAVY, DRC_DEFAULT_MOBILE_DRC_HEAVY);
}
return value == 1 ? C2Config::DRC_COMPRESSION_HEAVY : C2Config::DRC_COMPRESSION_LIGHT;
+ },[](C2Value v) -> C2Value {
+ int32_t value;
+ if (v.get(&value)) {
+ return value;
+ }
+ else {
+ return C2Value();
+ }
}));
// convert to dBFS and add default
add(ConfigMapper(KEY_AAC_ENCODED_TARGET_LEVEL, C2_PARAMKEY_DRC_ENCODED_TARGET_LEVEL, "value")
- .limitTo(D::AUDIO & D::DECODER & D::CONFIG)
- .withMapper([](C2Value v) -> C2Value {
+ .limitTo(D::AUDIO & D::DECODER & (D::CONFIG | D::PARAM | D::READ))
+ .withMappers([](C2Value v) -> C2Value {
int32_t value;
if (!v.get(&value) || value < 0) {
value = property_get_int32(PROP_DRC_OVERRIDE_ENC_LEVEL, DRC_DEFAULT_MOBILE_ENC_LEVEL);
}
return float(-0.25 * c2_min(value, 127));
+ },[](C2Value v) -> C2Value {
+ float value;
+ if (v.get(&value)) {
+ return (int32_t) (-4. * value);
+ }
+ else {
+ return C2Value();
+ }
}));
// convert to effect type (these map to SDK values) and add default
add(ConfigMapper(KEY_AAC_DRC_EFFECT_TYPE, C2_PARAMKEY_DRC_EFFECT_TYPE, "value")
- .limitTo(D::AUDIO & D::DECODER & D::CONFIG)
- .withMapper([](C2Value v) -> C2Value {
+ .limitTo(D::AUDIO & D::DECODER & (D::CONFIG | D::PARAM | D::READ))
+ .withMappers([](C2Value v) -> C2Value {
int32_t value;
if (!v.get(&value) || value < -1 || value > 8) {
value = property_get_int32(PROP_DRC_OVERRIDE_EFFECT, DRC_DEFAULT_MOBILE_DRC_EFFECT);
@@ -782,13 +809,60 @@
}
}
return value;
+ },[](C2Value v) -> C2Value {
+ int32_t value;
+ if (v.get(&value)) {
+ return value;
+ }
+ else {
+ return C2Value();
+ }
+ }));
+
+ // convert to album mode and add default
+ add(ConfigMapper(KEY_AAC_DRC_ALBUM_MODE, C2_PARAMKEY_DRC_ALBUM_MODE, "value")
+ .limitTo(D::AUDIO & D::DECODER & (D::CONFIG | D::PARAM | D::READ))
+ .withMappers([](C2Value v) -> C2Value {
+ int32_t value;
+ if (!v.get(&value) || value < 0 || value > 1) {
+ value = DRC_DEFAULT_MOBILE_DRC_ALBUM;
+ // ensure value is within range
+ if (value < 0 || value > 1) {
+ value = DRC_DEFAULT_MOBILE_DRC_ALBUM;
+ }
+ }
+ return value;
+ },[](C2Value v) -> C2Value {
+ int32_t value;
+ if (v.get(&value)) {
+ return value;
+ }
+ else {
+ return C2Value();
+ }
+ }));
+
+ add(ConfigMapper(KEY_AAC_DRC_OUTPUT_LOUDNESS, C2_PARAMKEY_DRC_OUTPUT_LOUDNESS, "value")
+ .limitTo(D::OUTPUT & D::DECODER & D::READ)
+ .withMappers([](C2Value v) -> C2Value {
+ int32_t value;
+ if (!v.get(&value) || value < -1) {
+ value = DRC_DEFAULT_MOBILE_OUTPUT_LOUDNESS;
+ }
+ return float(-0.25 * c2_min(value, 127));
+ },[](C2Value v) -> C2Value {
+ float value;
+ if (v.get(&value)) {
+ return (int32_t) (-4. * value);
+ }
+ return C2Value();
}));
add(ConfigMapper(KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT, C2_PARAMKEY_MAX_CHANNEL_COUNT, "value")
- .limitTo(D::AUDIO));
+ .limitTo(D::AUDIO & (D::CONFIG | D::PARAM | D::READ)));
add(ConfigMapper(KEY_AAC_SBR_MODE, C2_PARAMKEY_AAC_SBR_MODE, "value")
- .limitTo(D::AUDIO & D::ENCODER & D::CONFIG)
+ .limitTo(D::AUDIO & D::ENCODER & (D::CONFIG | D::PARAM | D::READ))
.withMapper([](C2Value v) -> C2Value {
int32_t value;
if (!v.get(&value) || value < 0) {
@@ -823,6 +897,14 @@
add(ConfigMapper(C2_PARAMKEY_INPUT_TIME_STRETCH, C2_PARAMKEY_INPUT_TIME_STRETCH, "value"));
+ add(ConfigMapper(KEY_LOW_LATENCY, C2_PARAMKEY_LOW_LATENCY_MODE, "value")
+ .limitTo(D::DECODER & (D::CONFIG | D::PARAM))
+ .withMapper([](C2Value v) -> C2Value {
+ int32_t value = 0;
+ (void)v.get(&value);
+ return value == 0 ? C2_FALSE : C2_TRUE;
+ }));
+
/* still to do
constexpr char KEY_PUSH_BLANK_BUFFERS_ON_STOP[] = "push-blank-buffers-on-shutdown";
@@ -833,27 +915,27 @@
}
status_t CCodecConfig::initialize(
- const std::shared_ptr<Codec2Client> &client,
- const std::shared_ptr<Codec2Client::Component> &component) {
+ const std::shared_ptr<C2ParamReflector> &reflector,
+ const std::shared_ptr<Codec2Client::Configurable> &configurable) {
C2ComponentDomainSetting domain(C2Component::DOMAIN_OTHER);
C2ComponentKindSetting kind(C2Component::KIND_OTHER);
std::vector<std::unique_ptr<C2Param>> queried;
- c2_status_t c2err = component->query({ &domain, &kind }, {}, C2_DONT_BLOCK, &queried);
+ c2_status_t c2err = configurable->query({ &domain, &kind }, {}, C2_DONT_BLOCK, &queried);
if (c2err != C2_OK) {
ALOGD("Query domain & kind failed => %s", asString(c2err));
// TEMP: determine kind from component name
if (kind.value == C2Component::KIND_OTHER) {
- if (component->getName().find("encoder") != std::string::npos) {
+ if (configurable->getName().find("encoder") != std::string::npos) {
kind.value = C2Component::KIND_ENCODER;
- } else if (component->getName().find("decoder") != std::string::npos) {
+ } else if (configurable->getName().find("decoder") != std::string::npos) {
kind.value = C2Component::KIND_DECODER;
}
}
// TEMP: determine domain from media type (port (preferred) or stream #0)
if (domain.value == C2Component::DOMAIN_OTHER) {
- AString mediaType = QueryMediaType(true /* input */, component);
+ AString mediaType = QueryMediaType(true /* input */, configurable);
if (mediaType.startsWith("audio/")) {
domain.value = C2Component::DOMAIN_AUDIO;
} else if (mediaType.startsWith("video/")) {
@@ -878,16 +960,16 @@
std::vector<C2Param::Index> paramIndices;
switch (kind.value) {
case C2Component::KIND_DECODER:
- mCodingMediaType = QueryMediaType(true /* input */, component).c_str();
+ mCodingMediaType = QueryMediaType(true /* input */, configurable).c_str();
break;
case C2Component::KIND_ENCODER:
- mCodingMediaType = QueryMediaType(false /* input */, component).c_str();
+ mCodingMediaType = QueryMediaType(false /* input */, configurable).c_str();
break;
default:
mCodingMediaType = "";
}
- c2err = component->querySupportedParams(&mParamDescs);
+ c2err = configurable->querySupportedParams(&mParamDescs);
if (c2err != C2_OK) {
ALOGD("Query supported params failed after returning %zu values => %s",
mParamDescs.size(), asString(c2err));
@@ -897,9 +979,9 @@
mSupportedIndices.emplace(desc->index());
}
- mReflector = client->getParamReflector();
+ mReflector = reflector;
if (mReflector == nullptr) {
- ALOGE("Failed to get param reflector");
+ ALOGE("Null param reflector");
return UNKNOWN_ERROR;
}
@@ -953,11 +1035,21 @@
// init data (CSD)
mSubscribedIndices.emplace(C2StreamInitDataInfo::output::PARAM_TYPE);
+ for (const std::shared_ptr<C2ParamDescriptor> &desc : mParamDescs) {
+ if (desc->index().isVendor()) {
+ std::vector<std::string> keys;
+ mParamUpdater->getKeysForParamIndex(desc->index(), &keys);
+ for (const std::string &key : keys) {
+ mVendorParamIndices.insert_or_assign(key, desc->index());
+ }
+ }
+ }
+
return OK;
}
status_t CCodecConfig::subscribeToConfigUpdate(
- const std::shared_ptr<Codec2Client::Component> &component,
+ const std::shared_ptr<Codec2Client::Configurable> &configurable,
const std::vector<C2Param::Index> &indices,
c2_blocking_t blocking) {
mSubscribedIndices.insert(indices.begin(), indices.end());
@@ -970,7 +1062,7 @@
std::unique_ptr<C2SubscribedParamIndicesTuning> subscribeTuning =
C2SubscribedParamIndicesTuning::AllocUnique(indices);
std::vector<std::unique_ptr<C2SettingResult>> results;
- c2_status_t c2Err = component->config({ subscribeTuning.get() }, blocking, &results);
+ c2_status_t c2Err = configurable->config({ subscribeTuning.get() }, blocking, &results);
if (c2Err != C2_OK && c2Err != C2_BAD_INDEX) {
ALOGD("Failed to subscribe to parameters => %s", asString(c2Err));
// TODO: error
@@ -982,11 +1074,11 @@
}
status_t CCodecConfig::queryConfiguration(
- const std::shared_ptr<Codec2Client::Component> &component) {
+ const std::shared_ptr<Codec2Client::Configurable> &configurable) {
// query all subscribed parameters
std::vector<C2Param::Index> indices(mSubscribedIndices.begin(), mSubscribedIndices.end());
std::vector<std::unique_ptr<C2Param>> queried;
- c2_status_t c2Err = component->query({}, indices, C2_MAY_BLOCK, &queried);
+ c2_status_t c2Err = configurable->query({}, indices, C2_MAY_BLOCK, &queried);
if (c2Err != OK) {
ALOGI("query failed after returning %zu values (%s)", queried.size(), asString(c2Err));
// TODO: error
@@ -1056,7 +1148,7 @@
if (domain & mInputDomain) {
sp<AMessage> oldFormat = mInputFormat;
mInputFormat = mInputFormat->dup(); // trigger format changed
- mInputFormat->extend(getSdkFormatForDomain(reflected, mInputDomain));
+ mInputFormat->extend(getFormatForDomain(reflected, mInputDomain));
if (mInputFormat->countEntries() != oldFormat->countEntries()
|| mInputFormat->changesFrom(oldFormat)->countEntries() > 0) {
changed = true;
@@ -1067,7 +1159,7 @@
if (domain & mOutputDomain) {
sp<AMessage> oldFormat = mOutputFormat;
mOutputFormat = mOutputFormat->dup(); // trigger output format changed
- mOutputFormat->extend(getSdkFormatForDomain(reflected, mOutputDomain));
+ mOutputFormat->extend(getFormatForDomain(reflected, mOutputDomain));
if (mOutputFormat->countEntries() != oldFormat->countEntries()
|| mOutputFormat->changesFrom(oldFormat)->countEntries() > 0) {
changed = true;
@@ -1079,8 +1171,9 @@
return changed;
}
-sp<AMessage> CCodecConfig::getSdkFormatForDomain(
- const ReflectedParamUpdater::Dict &reflected, Domain portDomain) const {
+sp<AMessage> CCodecConfig::getFormatForDomain(
+ const ReflectedParamUpdater::Dict &reflected,
+ Domain portDomain) const {
sp<AMessage> msg = new AMessage;
for (const std::pair<std::string, std::vector<ConfigMapper>> &el : mStandardParams->getKeys()) {
for (const ConfigMapper &cm : el.second) {
@@ -1111,6 +1204,39 @@
}
}
+ bool input = (portDomain & Domain::IS_INPUT);
+ std::vector<std::string> vendorKeys;
+ for (const std::pair<std::string, ReflectedParamUpdater::Value> &entry : reflected) {
+ auto it = mVendorParamIndices.find(entry.first);
+ if (it == mVendorParamIndices.end()) {
+ continue;
+ }
+ if (mSubscribedIndices.count(it->second) == 0) {
+ continue;
+ }
+ // For vendor parameters, we only care about direction
+ if ((input && !it->second.forInput())
+ || (!input && !it->second.forOutput())) {
+ continue;
+ }
+ const ReflectedParamUpdater::Value &value = entry.second;
+ C2Value c2Value;
+ sp<ABuffer> bufValue;
+ AString strValue;
+ AMessage::ItemData item;
+ if (value.find(&c2Value)) {
+ C2ValueToMessageItem(c2Value, item);
+ } else if (value.find(&bufValue)) {
+ item.set(bufValue);
+ } else if (value.find(&strValue)) {
+ item.set(strValue);
+ } else {
+ ALOGD("unexpected untyped query value for key: %s", entry.first.c_str());
+ continue;
+ }
+ msg->setItem(entry.first.c_str(), item);
+ }
+
{ // convert from Codec 2.0 rect to MediaFormat rect and add crop rect if not present
int32_t left, top, width, height;
if (msg->findInt32("crop-left", &left) && msg->findInt32("crop-width", &width)
@@ -1518,7 +1644,7 @@
}
status_t CCodecConfig::getConfigUpdateFromSdkParams(
- std::shared_ptr<Codec2Client::Component> component,
+ std::shared_ptr<Codec2Client::Configurable> configurable,
const sp<AMessage> &sdkParams, Domain configDomain,
c2_blocking_t blocking,
std::vector<std::unique_ptr<C2Param>> *configUpdate) const {
@@ -1545,7 +1671,7 @@
}
}
- c2_status_t err = component->query({ }, supportedIndices, blocking, configUpdate);
+ c2_status_t err = configurable->query({ }, supportedIndices, blocking, configUpdate);
if (err != C2_OK) {
ALOGD("query failed after returning %zu params => %s", configUpdate->size(), asString(err));
}
@@ -1557,7 +1683,7 @@
}
status_t CCodecConfig::setParameters(
- std::shared_ptr<Codec2Client::Component> component,
+ std::shared_ptr<Codec2Client::Configurable> configurable,
std::vector<std::unique_ptr<C2Param>> &configUpdate,
c2_blocking_t blocking) {
status_t result = OK;
@@ -1593,10 +1719,10 @@
}
}
// update subscribed param indices
- subscribeToConfigUpdate(component, indices, blocking);
+ subscribeToConfigUpdate(configurable, indices, blocking);
std::vector<std::unique_ptr<C2SettingResult>> failures;
- c2_status_t err = component->config(paramVector, blocking, &failures);
+ c2_status_t err = configurable->config(paramVector, blocking, &failures);
if (err != C2_OK) {
ALOGD("config failed => %s", asString(err));
// This is non-fatal.
@@ -1616,7 +1742,7 @@
// Re-query parameter values in case config could not update them and update the current
// configuration.
configUpdate.clear();
- err = component->query({}, indices, blocking, &configUpdate);
+ err = configurable->query({}, indices, blocking, &configUpdate);
if (err != C2_OK) {
ALOGD("query failed after returning %zu params => %s", configUpdate.size(), asString(err));
}
@@ -1635,4 +1761,13 @@
}
}
+status_t CCodecConfig::subscribeToAllVendorParams(
+ const std::shared_ptr<Codec2Client::Configurable> &configurable,
+ c2_blocking_t blocking) {
+ for (const std::pair<std::string, C2Param::Index> &entry : mVendorParamIndices) {
+ mSubscribedIndices.insert(entry.second);
+ }
+ return subscribeToConfigUpdate(configurable, {}, blocking);
+}
+
} // namespace android
diff --git a/media/codec2/sfplugin/CCodecConfig.h b/media/codec2/sfplugin/CCodecConfig.h
index a61c8b7..2895746 100644
--- a/media/codec2/sfplugin/CCodecConfig.h
+++ b/media/codec2/sfplugin/CCodecConfig.h
@@ -23,8 +23,10 @@
#include <vector>
#include <C2Component.h>
-#include <codec2/hidl/client.h>
+#include <C2Config.h>
+#include <C2Debug.h>
+#include <codec2/hidl/client.h>
#include <utils/RefBase.h>
#include "InputSurfaceWrapper.h"
@@ -39,7 +41,6 @@
* Struct managing the codec configuration for CCodec.
*/
struct CCodecConfig {
-
/**
* Domain consists of a bitmask divided into fields, and specifiers work by excluding other
* values in those domains.
@@ -118,6 +119,7 @@
sp<AMessage> mOutputFormat;
bool mUsingSurface; ///< using input or output surface
+ bool mBuffersBoundToCodec; ///< whether buffers are bound to codecs or not.
std::shared_ptr<InputSurfaceWrapper> mInputSurface;
std::unique_ptr<InputSurfaceWrapper::Config> mISConfig;
@@ -134,6 +136,9 @@
/// For now support a validation function.
std::map<C2Param::Index, LocalParamValidator> mLocalParams;
+ /// Vendor field name -> index map.
+ std::map<std::string, C2Param::Index> mVendorParamIndices;
+
std::set<std::string> mLastConfig;
CCodecConfig();
@@ -142,9 +147,8 @@
/// reflected param helper, domain, standard params, and subscribes to standard
/// indices.
status_t initialize(
- const std::shared_ptr<Codec2Client> &client,
- const std::shared_ptr<Codec2Client::Component> &component);
-
+ const std::shared_ptr<C2ParamReflector> &client,
+ const std::shared_ptr<Codec2Client::Configurable> &configurable);
/**
* Adds a locally maintained parameter. This is used for output configuration that can be
@@ -237,7 +241,7 @@
* \param blocking blocking mode to use with the component
*/
status_t getConfigUpdateFromSdkParams(
- std::shared_ptr<Codec2Client::Component> component,
+ std::shared_ptr<Codec2Client::Configurable> configurable,
const sp<AMessage> &sdkParams, Domain domain,
c2_blocking_t blocking,
std::vector<std::unique_ptr<C2Param>> *configUpdate) const;
@@ -249,19 +253,24 @@
* \param blocking blocking mode to use with the component
*/
status_t setParameters(
- std::shared_ptr<Codec2Client::Component> component,
+ std::shared_ptr<Codec2Client::Configurable> configurable,
std::vector<std::unique_ptr<C2Param>> &configUpdate,
c2_blocking_t blocking);
/// Queries subscribed indices (which contains all SDK-exposed values) and updates
/// input/output formats.
status_t queryConfiguration(
- const std::shared_ptr<Codec2Client::Component> &component);
+ const std::shared_ptr<Codec2Client::Configurable> &configurable);
/// Queries a configuration parameter value. Returns nullptr if the parameter is not
/// part of the current configuration
const C2Param *getConfigParameterValue(C2Param::Index index) const;
+ /// Subscribe to all vendor parameters.
+ status_t subscribeToAllVendorParams(
+ const std::shared_ptr<Codec2Client::Configurable> &configurable,
+ c2_blocking_t blocking);
+
/**
* Object that can be used to access configuration parameters and if they change.
*/
@@ -320,14 +329,15 @@
/// Adds indices to the subscribed indices, and updated subscription to component
/// \param blocking blocking mode to use with the component
status_t subscribeToConfigUpdate(
- const std::shared_ptr<Codec2Client::Component> &component,
+ const std::shared_ptr<Codec2Client::Configurable> &configurable,
const std::vector<C2Param::Index> &indices,
c2_blocking_t blocking = C2_DONT_BLOCK);
/// Gets SDK format from codec 2.0 reflected configuration
/// \param domain input/output bitmask
- sp<AMessage> getSdkFormatForDomain(
- const ReflectedParamUpdater::Dict &reflected, Domain domain) const;
+ sp<AMessage> getFormatForDomain(
+ const ReflectedParamUpdater::Dict &reflected,
+ Domain domain) const;
/**
* Converts a set of configuration parameters in an AMessage to a list of path-based Codec
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index 5c8ad56..b6d18e2 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -20,6 +20,7 @@
#include <hidlmemory/FrameworkUtils.h>
#include <media/hardware/HardwareAPI.h>
+#include <media/stagefright/CodecBase.h>
#include <media/stagefright/MediaCodecConstants.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/AMessage.h>
@@ -764,7 +765,11 @@
const std::shared_ptr<C2LinearBlock> &block,
const sp<IMemory> &memory,
int32_t heapSeqNum)
- : Codec2Buffer(format, new ABuffer(memory->pointer(), memory->size())),
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
+ : Codec2Buffer(format, new ABuffer(memory->unsecurePointer(), memory->size())),
mBlock(block),
mMemory(memory),
mHeapSeqNum(heapSeqNum) {
@@ -775,9 +780,8 @@
}
void EncryptedLinearBlockBuffer::fillSourceBuffer(
- ICrypto::SourceBuffer *source) {
- source->mSharedMemory = mMemory;
- source->mHeapSeqNum = mHeapSeqNum;
+ hardware::drm::V1_0::SharedBuffer *source) {
+ BufferChannelBase::IMemoryToSharedBuffer(mMemory, mHeapSeqNum, source);
}
void EncryptedLinearBlockBuffer::fillSourceBuffer(
@@ -800,7 +804,7 @@
if (view.size() < length) {
return false;
}
- memcpy(view.data(), decrypted->pointer(), length);
+ memcpy(view.data(), decrypted->unsecurePointer(), length);
return true;
}
diff --git a/media/codec2/sfplugin/Codec2Buffer.h b/media/codec2/sfplugin/Codec2Buffer.h
index 36dcab9..09475ef 100644
--- a/media/codec2/sfplugin/Codec2Buffer.h
+++ b/media/codec2/sfplugin/Codec2Buffer.h
@@ -21,11 +21,12 @@
#include <C2Buffer.h>
#include <android/hardware/cas/native/1.0/types.h>
+#include <android/hardware/drm/1.0/types.h>
#include <binder/IMemory.h>
#include <media/hardware/VideoAPI.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/MediaCodecBuffer.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
namespace android {
@@ -56,36 +57,6 @@
using MediaCodecBuffer::MediaCodecBuffer;
~Codec2Buffer() override = default;
- /**
- * \return C2Buffer object represents this buffer.
- */
- virtual std::shared_ptr<C2Buffer> asC2Buffer() = 0;
-
- /**
- * Test if we can copy the content of |buffer| into this object.
- *
- * \param buffer C2Buffer object to copy.
- * \return true if the content of buffer can be copied over to this buffer
- * false otherwise.
- */
- virtual bool canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
- (void)buffer;
- return false;
- }
-
- /**
- * Copy the content of |buffer| into this object. This method assumes that
- * canCopy() check already passed.
- *
- * \param buffer C2Buffer object to copy.
- * \return true if successful
- * false otherwise.
- */
- virtual bool copy(const std::shared_ptr<C2Buffer> &buffer) {
- (void)buffer;
- return false;
- }
-
sp<ABuffer> getImageData() const { return mImageData; }
protected:
@@ -361,7 +332,8 @@
*
* \param source source buffer structure to fill.
*/
- void fillSourceBuffer(ICrypto::SourceBuffer *source);
+ void fillSourceBuffer(
+ hardware::drm::V1_0::SharedBuffer *source);
void fillSourceBuffer(
hardware::cas::native::V1_0::SharedBuffer *source);
diff --git a/media/codec2/sfplugin/Codec2InfoBuilder.cpp b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
index 6b75eba..b112249 100644
--- a/media/codec2/sfplugin/Codec2InfoBuilder.cpp
+++ b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
@@ -43,13 +43,12 @@
#include <codec2/hidl/client.h>
#include <cutils/native_handle.h>
#include <media/omx/1.0/WOmxNode.h>
-#include <media/stagefright/MediaCodecConstants.h>
#include <media/stagefright/foundation/ALookup.h>
#include <media/stagefright/foundation/MediaDefs.h>
#include <media/stagefright/omx/OMXUtils.h>
#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
-
-#include "Codec2InfoBuilder.h"
+#include <media/stagefright/Codec2InfoBuilder.h>
+#include <media/stagefright/MediaCodecConstants.h>
namespace android {
@@ -117,8 +116,9 @@
}
}
- // For VP9, the static info is always propagated by framework.
+ // For VP9/AV1, the static info is always propagated by framework.
supportsHdr |= (mediaType == MIMETYPE_VIDEO_VP9);
+ supportsHdr |= (mediaType == MIMETYPE_VIDEO_AV1);
for (C2Value::Primitive profile : profileQuery[0].values.values) {
pl.profile = (C2Config::profile_t)profile.ref<uint32_t>();
@@ -319,10 +319,11 @@
// Obtain Codec2Client
std::vector<Traits> traits = Codec2Client::ListComponents();
- // parse APEX XML first, followed by vendor XML
+ // parse APEX XML first, followed by vendor XML.
+ // Note: APEX XML names do not depend on ro.media.xml_variant.* properties.
MediaCodecsXmlParser parser;
parser.parseXmlFilesInSearchDirs(
- parser.getDefaultXmlNames(),
+ { "media_codecs.xml", "media_codecs_performance.xml" },
{ "/apex/com.android.media.swcodec/etc" });
// TODO: remove these c2-specific files once product moved to default file names
diff --git a/media/codec2/sfplugin/ReflectedParamUpdater.cpp b/media/codec2/sfplugin/ReflectedParamUpdater.cpp
index 55b0ec9..f39051b 100644
--- a/media/codec2/sfplugin/ReflectedParamUpdater.cpp
+++ b/media/codec2/sfplugin/ReflectedParamUpdater.cpp
@@ -125,18 +125,6 @@
}
addParamDesc(desc, *structDesc, reflector, true /* markVendor */);
}
-
- // TEMP: also add vendor parameters as non-vendor
- for (const std::shared_ptr<C2ParamDescriptor> &desc : paramDescs) {
- if (!desc->index().isVendor()) {
- continue;
- }
- std::unique_ptr<C2StructDescriptor> structDesc = reflector->describe(
- desc->index().coreIndex());
- if (structDesc) {
- addParamDesc(desc, *structDesc, reflector, false /* markVendor */);
- }
- }
}
void ReflectedParamUpdater::addParamStructDesc(
@@ -286,6 +274,20 @@
}
}
+void ReflectedParamUpdater::getKeysForParamIndex(
+ const C2Param::Index &index,
+ std::vector<std::string> *keys /* nonnull */) const {
+ CHECK(keys != nullptr);
+ keys->clear();
+ for (const std::pair<const std::string, FieldDesc> &kv : mMap) {
+ const std::string &name = kv.first;
+ const FieldDesc &desc = kv.second;
+ if (desc.paramDesc->index() == index) {
+ keys->push_back(name);
+ }
+ }
+}
+
void ReflectedParamUpdater::updateParamsFromMessage(
const Dict ¶ms,
std::vector<std::unique_ptr<C2Param>> *vec /* nonnull */) const {
diff --git a/media/codec2/sfplugin/ReflectedParamUpdater.h b/media/codec2/sfplugin/ReflectedParamUpdater.h
index 5436ba5..752c7e4 100644
--- a/media/codec2/sfplugin/ReflectedParamUpdater.h
+++ b/media/codec2/sfplugin/ReflectedParamUpdater.h
@@ -166,6 +166,16 @@
std::vector<C2Param::Index> *vec /* nonnull */) const;
/**
+ * Get list of field names for the given param index.
+ *
+ * \param index[in] param index
+ * \param keys[out] vector to store the field names
+ */
+ void getKeysForParamIndex(
+ const C2Param::Index &index,
+ std::vector<std::string> *keys /* nonnull */) const;
+
+ /**
* Update C2Param objects from field name and value in AMessage object.
*
* \param params[in] Dict object with field name to value pairs.
diff --git a/media/codec2/sfplugin/SkipCutBuffer.cpp b/media/codec2/sfplugin/SkipCutBuffer.cpp
deleted file mode 100644
index 8d1de65..0000000
--- a/media/codec2/sfplugin/SkipCutBuffer.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "SkipCutBuffer"
-#include <utils/Log.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MediaBuffer.h>
-#include "SkipCutBuffer.h"
-
-namespace android {
-
-SkipCutBuffer::SkipCutBuffer(size_t skip, size_t cut, size_t num16BitChannels) {
-
- mWriteHead = 0;
- mReadHead = 0;
- mCapacity = 0;
- mCutBuffer = nullptr;
-
- if (num16BitChannels == 0 || num16BitChannels > INT32_MAX / 2) {
- ALOGW("# channels out of range: %zu, using passthrough instead", num16BitChannels);
- return;
- }
- size_t frameSize = num16BitChannels * 2;
- if (skip > INT32_MAX / frameSize || cut > INT32_MAX / frameSize
- || cut * frameSize > INT32_MAX - 4096) {
- ALOGW("out of range skip/cut: %zu/%zu, using passthrough instead",
- skip, cut);
- return;
- }
- skip *= frameSize;
- cut *= frameSize;
-
- mFrontPadding = mSkip = skip;
- mBackPadding = cut;
- mCapacity = cut + 4096;
- mCutBuffer = new (std::nothrow) char[mCapacity];
- ALOGV("skipcutbuffer %zu %zu %d", skip, cut, mCapacity);
-}
-
-SkipCutBuffer::~SkipCutBuffer() {
- delete[] mCutBuffer;
-}
-
-void SkipCutBuffer::submit(MediaBuffer *buffer) {
- if (mCutBuffer == nullptr) {
- // passthrough mode
- return;
- }
-
- int32_t offset = buffer->range_offset();
- int32_t buflen = buffer->range_length();
-
- // drop the initial data from the buffer if needed
- if (mFrontPadding > 0) {
- // still data left to drop
- int32_t to_drop = (buflen < mFrontPadding) ? buflen : mFrontPadding;
- offset += to_drop;
- buflen -= to_drop;
- buffer->set_range(offset, buflen);
- mFrontPadding -= to_drop;
- }
-
-
- // append data to cutbuffer
- char *src = ((char*) buffer->data()) + offset;
- write(src, buflen);
-
-
- // the mediabuffer is now empty. Fill it from cutbuffer, always leaving
- // at least mBackPadding bytes in the cutbuffer
- char *dst = (char*) buffer->data();
- size_t copied = read(dst, buffer->size());
- buffer->set_range(0, copied);
-}
-
-template <typename T>
-void SkipCutBuffer::submitInternal(const sp<T>& buffer) {
- if (mCutBuffer == nullptr) {
- // passthrough mode
- return;
- }
-
- int32_t offset = buffer->offset();
- int32_t buflen = buffer->size();
-
- // drop the initial data from the buffer if needed
- if (mFrontPadding > 0) {
- // still data left to drop
- int32_t to_drop = (buflen < mFrontPadding) ? buflen : mFrontPadding;
- offset += to_drop;
- buflen -= to_drop;
- buffer->setRange(offset, buflen);
- mFrontPadding -= to_drop;
- }
-
-
- // append data to cutbuffer
- char *src = (char*) buffer->data();
- write(src, buflen);
-
-
- // the mediabuffer is now empty. Fill it from cutbuffer, always leaving
- // at least mBackPadding bytes in the cutbuffer
- char *dst = (char*) buffer->base();
- size_t copied = read(dst, buffer->capacity());
- buffer->setRange(0, copied);
-}
-
-void SkipCutBuffer::submit(const sp<ABuffer>& buffer) {
- submitInternal(buffer);
-}
-
-void SkipCutBuffer::submit(const sp<MediaCodecBuffer>& buffer) {
- submitInternal(buffer);
-}
-
-void SkipCutBuffer::clear() {
- mWriteHead = mReadHead = 0;
- mFrontPadding = mSkip;
-}
-
-void SkipCutBuffer::write(const char *src, size_t num) {
- int32_t sizeused = (mWriteHead - mReadHead);
- if (sizeused < 0) sizeused += mCapacity;
-
- // Everything must fit. Make sure the buffer is a little larger than needed,
- // so there is no ambiguity as to whether mWriteHead == mReadHead means buffer
- // full or empty
- size_t available = mCapacity - sizeused - 32;
- if (available < num) {
- int32_t newcapacity = mCapacity + (num - available);
- char * newbuffer = new char[newcapacity];
- memcpy(newbuffer, mCutBuffer, mCapacity);
- delete [] mCutBuffer;
- mCapacity = newcapacity;
- mCutBuffer = newbuffer;
- ALOGV("reallocated buffer at size %d", newcapacity);
- }
-
- size_t copyfirst = (mCapacity - mWriteHead);
- if (copyfirst > num) copyfirst = num;
- if (copyfirst) {
- memcpy(mCutBuffer + mWriteHead, src, copyfirst);
- num -= copyfirst;
- src += copyfirst;
- mWriteHead += copyfirst;
- CHECK_LE(mWriteHead, mCapacity);
- if (mWriteHead == mCapacity) mWriteHead = 0;
- if (num) {
- memcpy(mCutBuffer, src, num);
- mWriteHead += num;
- }
- }
-}
-
-size_t SkipCutBuffer::read(char *dst, size_t num) {
- int32_t available = (mWriteHead - mReadHead);
- if (available < 0) available += mCapacity;
-
- available -= mBackPadding;
- if (available <=0) {
- return 0;
- }
- if (available < int32_t(num)) {
- num = available;
- }
-
- size_t copyfirst = (mCapacity - mReadHead);
- if (copyfirst > num) copyfirst = num;
- if (copyfirst) {
- memcpy(dst, mCutBuffer + mReadHead, copyfirst);
- num -= copyfirst;
- dst += copyfirst;
- mReadHead += copyfirst;
- CHECK_LE(mReadHead, mCapacity);
- if (mReadHead == mCapacity) mReadHead = 0;
- if (num) {
- memcpy(dst, mCutBuffer, num);
- mReadHead += num;
- }
- }
- return available;
-}
-
-size_t SkipCutBuffer::size() {
- int32_t available = (mWriteHead - mReadHead);
- if (available < 0) available += mCapacity;
- return available;
-}
-
-} // namespace android
diff --git a/media/codec2/sfplugin/SkipCutBuffer.h b/media/codec2/sfplugin/SkipCutBuffer.h
deleted file mode 100644
index 0fb5690..0000000
--- a/media/codec2/sfplugin/SkipCutBuffer.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef SKIP_CUT_BUFFER_H_
-
-#define SKIP_CUT_BUFFER_H_
-
-#include <media/MediaCodecBuffer.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/foundation/ABuffer.h>
-
-namespace android {
-
-/**
- * utility class to cut the start and end off a stream of data in MediaBuffers
- *
- */
-class SkipCutBuffer: public RefBase {
- public:
- // 'skip' is the number of frames to skip from the beginning
- // 'cut' is the number of frames to cut from the end
- // 'num16BitChannels' is the number of channels, which are assumed to be 16 bit wide each
- SkipCutBuffer(size_t skip, size_t cut, size_t num16Channels);
-
- // Submit one MediaBuffer for skipping and cutting. This may consume all or
- // some of the data in the buffer, or it may add data to it.
- // After this, the caller should continue processing the buffer as usual.
- void submit(MediaBuffer *buffer);
- void submit(const sp<ABuffer>& buffer); // same as above, but with an ABuffer
- void submit(const sp<MediaCodecBuffer>& buffer); // same as above, but with an ABuffer
- void clear();
- size_t size(); // how many bytes are currently stored in the buffer
-
- protected:
- virtual ~SkipCutBuffer();
-
- private:
- void write(const char *src, size_t num);
- size_t read(char *dst, size_t num);
- template <typename T>
- void submitInternal(const sp<T>& buffer);
- int32_t mSkip;
- int32_t mFrontPadding;
- int32_t mBackPadding;
- int32_t mWriteHead;
- int32_t mReadHead;
- int32_t mCapacity;
- char* mCutBuffer;
- DISALLOW_EVIL_CONSTRUCTORS(SkipCutBuffer);
-};
-
-} // namespace android
-
-#endif // OMX_CODEC_H_
diff --git a/media/codec2/sfplugin/include/media/stagefright/CCodec.h b/media/codec2/sfplugin/include/media/stagefright/CCodec.h
new file mode 100644
index 0000000..ecb2506
--- /dev/null
+++ b/media/codec2/sfplugin/include/media/stagefright/CCodec.h
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef C_CODEC_H_
+#define C_CODEC_H_
+
+#include <atomic>
+#include <chrono>
+#include <list>
+#include <memory>
+#include <set>
+
+#include <C2Component.h>
+#include <codec2/hidl/client.h>
+
+#include <android/native_window.h>
+#include <media/hardware/MetadataBufferType.h>
+#include <media/stagefright/foundation/Mutexed.h>
+#include <media/stagefright/CodecBase.h>
+#include <media/stagefright/FrameRenderTracker.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/SkipCutBuffer.h>
+#include <utils/NativeHandle.h>
+#include <hardware/gralloc.h>
+#include <nativebase/nativebase.h>
+
+namespace android {
+
+class CCodecBufferChannel;
+class InputSurfaceWrapper;
+struct CCodecConfig;
+struct MediaCodecInfo;
+
+class CCodec : public CodecBase {
+public:
+ CCodec();
+
+ virtual std::shared_ptr<BufferChannelBase> getBufferChannel() override;
+ virtual void initiateAllocateComponent(const sp<AMessage> &msg) override;
+ virtual void initiateConfigureComponent(const sp<AMessage> &msg) override;
+ virtual void initiateCreateInputSurface() override;
+ virtual void initiateSetInputSurface(const sp<PersistentSurface> &surface) override;
+ virtual void initiateStart() override;
+ virtual void initiateShutdown(bool keepComponentAllocated = false) override;
+
+ virtual status_t setSurface(const sp<Surface> &surface) override;
+
+ virtual void signalFlush() override;
+ virtual void signalResume() override;
+
+ virtual void signalSetParameters(const sp<AMessage> ¶ms) override;
+ virtual void signalEndOfInputStream() override;
+ virtual void signalRequestIDRFrame() override;
+
+ void initiateReleaseIfStuck();
+ void onWorkDone(std::list<std::unique_ptr<C2Work>> &workItems);
+ void onInputBufferDone(uint64_t frameIndex, size_t arrayIndex);
+
+ static PersistentSurface *CreateInputSurface();
+
+ static status_t CanFetchLinearBlock(
+ const std::vector<std::string> &names, const C2MemoryUsage &usage, bool *isCompatible);
+
+ static std::shared_ptr<C2LinearBlock> FetchLinearBlock(
+ size_t capacity, const C2MemoryUsage &usage, const std::vector<std::string> &names);
+
+ static status_t CanFetchGraphicBlock(
+ const std::vector<std::string> &names, bool *isCompatible);
+
+ static std::shared_ptr<C2GraphicBlock> FetchGraphicBlock(
+ int32_t width,
+ int32_t height,
+ int32_t format,
+ uint64_t usage,
+ const std::vector<std::string> &names);
+
+protected:
+ virtual ~CCodec();
+
+ virtual void onMessageReceived(const sp<AMessage> &msg) override;
+
+private:
+ typedef std::chrono::steady_clock::time_point TimePoint;
+
+ status_t tryAndReportOnError(std::function<status_t()> job);
+
+ void initiateStop();
+ void initiateRelease(bool sendCallback = true);
+
+ void allocate(const sp<MediaCodecInfo> &codecInfo);
+ void configure(const sp<AMessage> &msg);
+ void start();
+ void stop();
+ void flush();
+ void release(bool sendCallback);
+
+ /**
+ * Creates an input surface for the current device configuration compatible with CCodec.
+ * This could be backed by the C2 HAL or the OMX HAL.
+ */
+ static sp<PersistentSurface> CreateCompatibleInputSurface();
+
+ /// Creates an input surface to the OMX HAL
+ static sp<PersistentSurface> CreateOmxInputSurface();
+
+ /// handle a create input surface call
+ void createInputSurface();
+ void setInputSurface(const sp<PersistentSurface> &surface);
+ status_t setupInputSurface(const std::shared_ptr<InputSurfaceWrapper> &surface);
+
+ void setDeadline(
+ const TimePoint &now,
+ const std::chrono::milliseconds &timeout,
+ const char *name);
+
+ enum {
+ kWhatAllocate,
+ kWhatConfigure,
+ kWhatStart,
+ kWhatFlush,
+ kWhatStop,
+ kWhatRelease,
+ kWhatCreateInputSurface,
+ kWhatSetInputSurface,
+ kWhatSetParameters,
+
+ kWhatWorkDone,
+ kWhatWatch,
+ };
+
+ enum {
+ RELEASED,
+ ALLOCATED,
+ FLUSHED,
+ RUNNING,
+
+ ALLOCATING, // RELEASED -> ALLOCATED
+ STARTING, // ALLOCATED -> RUNNING
+ STOPPING, // RUNNING -> ALLOCATED
+ FLUSHING, // RUNNING -> FLUSHED
+ RESUMING, // FLUSHED -> RUNNING
+ RELEASING, // {ANY EXCEPT RELEASED} -> RELEASED
+ };
+
+ struct State {
+ inline State() : mState(RELEASED) {}
+ inline int get() const { return mState; }
+ inline void set(int newState) { mState = newState; }
+
+ std::shared_ptr<Codec2Client::Component> comp;
+ private:
+ int mState;
+ };
+
+ struct NamedTimePoint {
+ NamedTimePoint() : mTimePoint(TimePoint::max()), mName("") {}
+
+ inline void set(
+ const TimePoint &timePoint,
+ const char *name) {
+ mTimePoint = timePoint;
+ mName = name;
+ }
+
+ inline TimePoint get() const { return mTimePoint; }
+ inline const char *getName() const { return mName; }
+ private:
+ TimePoint mTimePoint;
+ const char *mName;
+ };
+
+ Mutexed<State> mState;
+ std::shared_ptr<CCodecBufferChannel> mChannel;
+
+ std::shared_ptr<Codec2Client> mClient;
+ std::shared_ptr<Codec2Client::Listener> mClientListener;
+ struct ClientListener;
+
+ Mutexed<NamedTimePoint> mDeadline;
+
+ Mutexed<std::unique_ptr<CCodecConfig>> mConfig;
+ Mutexed<std::list<std::unique_ptr<C2Work>>> mWorkDoneQueue;
+ std::atomic_flag mSentConfigAfterResume;
+
+ friend class CCodecCallbackImpl;
+
+ DISALLOW_EVIL_CONSTRUCTORS(CCodec);
+};
+
+} // namespace android
+
+#endif // C_CODEC_H_
diff --git a/media/codec2/sfplugin/Codec2InfoBuilder.h b/media/codec2/sfplugin/include/media/stagefright/Codec2InfoBuilder.h
similarity index 100%
rename from media/codec2/sfplugin/Codec2InfoBuilder.h
rename to media/codec2/sfplugin/include/media/stagefright/Codec2InfoBuilder.h
diff --git a/media/codec2/sfplugin/tests/Android.bp b/media/codec2/sfplugin/tests/Android.bp
index be7f55c..fe5fa68 100644
--- a/media/codec2/sfplugin/tests/Android.bp
+++ b/media/codec2/sfplugin/tests/Android.bp
@@ -2,16 +2,24 @@
name: "ccodec_unit_test",
srcs: [
+ "CCodecConfig_test.cpp",
"ReflectedParamUpdater_test.cpp",
],
+ defaults: [
+ "libcodec2-hidl-defaults@1.0",
+ "libcodec2-internal-defaults",
+ ],
+
include_dirs: [
"frameworks/av/media/codec2/sfplugin",
],
shared_libs: [
"libcodec2",
+ "libcodec2_client",
"libsfplugin_ccodec",
+ "libsfplugin_ccodec_utils",
"libstagefright_foundation",
"libutils",
],
@@ -33,6 +41,11 @@
"frameworks/av/media/codec2/sfplugin",
],
+ header_libs: [
+ "libmediadrm_headers",
+ "libmediametrics_headers",
+ ],
+
shared_libs: [
"libbinder",
"libcodec2",
diff --git a/media/codec2/sfplugin/tests/CCodecConfig_test.cpp b/media/codec2/sfplugin/tests/CCodecConfig_test.cpp
new file mode 100644
index 0000000..7b445a0
--- /dev/null
+++ b/media/codec2/sfplugin/tests/CCodecConfig_test.cpp
@@ -0,0 +1,311 @@
+/*
+ * Copyright 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.
+ */
+
+#include "CCodecConfig.h"
+
+#include <set>
+
+#include <gtest/gtest.h>
+
+#include <codec2/hidl/1.0/Configurable.h>
+#include <codec2/hidl/client.h>
+#include <util/C2InterfaceHelper.h>
+
+namespace {
+
+enum ExtendedC2ParamIndexKind : C2Param::type_index_t {
+ kParamIndexVendorInt32 = C2Param::TYPE_INDEX_VENDOR_START,
+ kParamIndexVendorInt64,
+ kParamIndexVendorString,
+};
+
+typedef C2PortParam<C2Info, C2Int32Value, kParamIndexVendorInt32> C2PortVendorInt32Info;
+constexpr char C2_PARAMKEY_VENDOR_INT32[] = "example.int32";
+constexpr char KEY_VENDOR_INT32[] = "vendor.example.int32.value";
+
+typedef C2StreamParam<C2Info, C2Int64Value, kParamIndexVendorInt64> C2StreamVendorInt64Info;
+constexpr char C2_PARAMKEY_VENDOR_INT64[] = "example.int64";
+constexpr char KEY_VENDOR_INT64[] = "vendor.example.int64.value";
+
+typedef C2PortParam<C2Info, C2StringValue, kParamIndexVendorString> C2PortVendorStringInfo;
+constexpr char C2_PARAMKEY_VENDOR_STRING[] = "example.string";
+constexpr char KEY_VENDOR_STRING[] = "vendor.example.string.value";
+
+} // namespace
+
+namespace android {
+
+class CCodecConfigTest : public ::testing::Test {
+public:
+ constexpr static int32_t kCodec2Int32 = 0xC0DEC2;
+ constexpr static int64_t kCodec2Int64 = 0xC0DEC2C0DEC2ll;
+ constexpr static char kCodec2Str[] = "codec2";
+
+ CCodecConfigTest()
+ : mReflector{std::make_shared<C2ReflectorHelper>()} {
+ sp<hardware::media::c2::V1_0::utils::CachedConfigurable> cachedConfigurable =
+ new hardware::media::c2::V1_0::utils::CachedConfigurable(
+ std::make_unique<Configurable>(mReflector));
+ cachedConfigurable->init(std::make_shared<Cache>());
+ mConfigurable = std::make_shared<Codec2Client::Configurable>(cachedConfigurable);
+ }
+
+ struct Cache : public hardware::media::c2::V1_0::utils::ParameterCache {
+ c2_status_t validate(const std::vector<std::shared_ptr<C2ParamDescriptor>>&) override {
+ return C2_OK;
+ }
+ };
+
+ class Configurable : public hardware::media::c2::V1_0::utils::ConfigurableC2Intf {
+ public:
+ explicit Configurable(const std::shared_ptr<C2ReflectorHelper> &reflector)
+ : ConfigurableC2Intf("name", 0u),
+ mImpl(reflector) {
+ }
+
+ c2_status_t query(
+ const std::vector<C2Param::Index> &indices,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2Param>>* const params) const override {
+ return mImpl.query({}, indices, mayBlock, params);
+ }
+
+ c2_status_t config(
+ const std::vector<C2Param*> ¶ms,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2SettingResult>>* const failures) override {
+ return mImpl.config(params, mayBlock, failures);
+ }
+
+ c2_status_t querySupportedParams(
+ std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const override {
+ return mImpl.querySupportedParams(params);
+ }
+
+ c2_status_t querySupportedValues(
+ std::vector<C2FieldSupportedValuesQuery>& fields,
+ c2_blocking_t mayBlock) const override {
+ return mImpl.querySupportedValues(fields, mayBlock);
+ }
+
+ private:
+ class Impl : public C2InterfaceHelper {
+ public:
+ explicit Impl(const std::shared_ptr<C2ReflectorHelper> &reflector)
+ : C2InterfaceHelper{reflector} {
+ setDerivedInstance(this);
+
+ addParameter(
+ DefineParam(mInt32Input, C2_PARAMKEY_VENDOR_INT32)
+ .withDefault(new C2PortVendorInt32Info::input(0))
+ .withFields({C2F(mInt32Input, value).any()})
+ .withSetter(Setter<decltype(mInt32Input)::element_type>)
+ .build());
+
+ addParameter(
+ DefineParam(mInt64Output, C2_PARAMKEY_VENDOR_INT64)
+ .withDefault(new C2StreamVendorInt64Info::output(0u, 0))
+ .withFields({C2F(mInt64Output, value).any()})
+ .withSetter(Setter<decltype(mInt64Output)::element_type>)
+ .build());
+
+ addParameter(
+ DefineParam(mStringInput, C2_PARAMKEY_VENDOR_STRING)
+ .withDefault(decltype(mStringInput)::element_type::AllocShared(1, ""))
+ .withFields({C2F(mStringInput, m.value).any()})
+ .withSetter(Setter<decltype(mStringInput)::element_type>)
+ .build());
+
+ // TODO: SDK params
+ }
+ private:
+ std::shared_ptr<C2PortVendorInt32Info::input> mInt32Input;
+ std::shared_ptr<C2StreamVendorInt64Info::output> mInt64Output;
+ std::shared_ptr<C2PortVendorStringInfo::input> mStringInput;
+
+ template<typename T>
+ static C2R Setter(bool, C2P<T> &) {
+ return C2R::Ok();
+ }
+ };
+
+ Impl mImpl;
+ };
+
+ std::shared_ptr<C2ReflectorHelper> mReflector;
+ std::shared_ptr<Codec2Client::Configurable> mConfigurable;
+ CCodecConfig mConfig;
+};
+
+using D = CCodecConfig::Domain;
+
+template<typename T>
+T *FindParam(const std::vector<std::unique_ptr<C2Param>> &vec) {
+ for (const std::unique_ptr<C2Param> ¶m : vec) {
+ if (param->coreIndex() == T::CORE_INDEX) {
+ return static_cast<T *>(param.get());
+ }
+ }
+ return nullptr;
+}
+
+TEST_F(CCodecConfigTest, SetVendorParam) {
+ ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
+
+ sp<AMessage> format{new AMessage};
+ format->setInt32(KEY_VENDOR_INT32, kCodec2Int32);
+ format->setInt64(KEY_VENDOR_INT64, kCodec2Int64);
+ format->setString(KEY_VENDOR_STRING, kCodec2Str);
+
+ std::vector<std::unique_ptr<C2Param>> configUpdate;
+ ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams(
+ mConfigurable, format, D::IS_INPUT | D::IS_OUTPUT, C2_MAY_BLOCK, &configUpdate));
+
+ ASSERT_EQ(3u, configUpdate.size());
+ C2PortVendorInt32Info::input *i32 =
+ FindParam<std::remove_pointer<decltype(i32)>::type>(configUpdate);
+ ASSERT_NE(nullptr, i32);
+ ASSERT_EQ(kCodec2Int32, i32->value);
+
+ C2StreamVendorInt64Info::output *i64 =
+ FindParam<std::remove_pointer<decltype(i64)>::type>(configUpdate);
+ ASSERT_NE(nullptr, i64);
+ ASSERT_EQ(kCodec2Int64, i64->value);
+
+ C2PortVendorStringInfo::input *str =
+ FindParam<std::remove_pointer<decltype(str)>::type>(configUpdate);
+ ASSERT_NE(nullptr, str);
+ ASSERT_STREQ(kCodec2Str, str->m.value);
+}
+
+TEST_F(CCodecConfigTest, VendorParamUpdate_Unsubscribed) {
+ ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
+
+ std::vector<std::unique_ptr<C2Param>> configUpdate;
+ C2PortVendorInt32Info::input i32(kCodec2Int32);
+ C2StreamVendorInt64Info::output i64(0u, kCodec2Int64);
+ std::unique_ptr<C2PortVendorStringInfo::input> str =
+ C2PortVendorStringInfo::input::AllocUnique(strlen(kCodec2Str) + 1, kCodec2Str);
+ configUpdate.push_back(C2Param::Copy(i32));
+ configUpdate.push_back(C2Param::Copy(i64));
+ configUpdate.push_back(std::move(str));
+
+ // The vendor parameters are not yet subscribed
+ ASSERT_FALSE(mConfig.updateConfiguration(configUpdate, D::IS_INPUT | D::IS_OUTPUT));
+
+ int32_t vendorInt32{0};
+ ASSERT_FALSE(mConfig.mInputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
+ << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
+ ASSERT_FALSE(mConfig.mOutputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
+ << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
+
+ int64_t vendorInt64{0};
+ ASSERT_FALSE(mConfig.mInputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64))
+ << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
+ ASSERT_FALSE(mConfig.mOutputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64))
+ << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
+
+ AString vendorString;
+ ASSERT_FALSE(mConfig.mInputFormat->findString(KEY_VENDOR_STRING, &vendorString))
+ << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
+ ASSERT_FALSE(mConfig.mOutputFormat->findString(KEY_VENDOR_STRING, &vendorString))
+ << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
+}
+
+TEST_F(CCodecConfigTest, VendorParamUpdate_AllSubscribed) {
+ ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
+
+ // Force subscribe to all vendor params
+ ASSERT_EQ(OK, mConfig.subscribeToAllVendorParams(mConfigurable, C2_MAY_BLOCK));
+
+ std::vector<std::unique_ptr<C2Param>> configUpdate;
+ C2PortVendorInt32Info::input i32(kCodec2Int32);
+ C2StreamVendorInt64Info::output i64(0u, kCodec2Int64);
+ std::unique_ptr<C2PortVendorStringInfo::input> str =
+ C2PortVendorStringInfo::input::AllocUnique(strlen(kCodec2Str) + 1, kCodec2Str);
+ configUpdate.push_back(C2Param::Copy(i32));
+ configUpdate.push_back(C2Param::Copy(i64));
+ configUpdate.push_back(std::move(str));
+
+ ASSERT_TRUE(mConfig.updateConfiguration(configUpdate, D::IS_INPUT | D::IS_OUTPUT));
+
+ int32_t vendorInt32{0};
+ ASSERT_TRUE(mConfig.mInputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
+ << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
+ ASSERT_EQ(kCodec2Int32, vendorInt32);
+ ASSERT_FALSE(mConfig.mOutputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
+ << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
+
+ int64_t vendorInt64{0};
+ ASSERT_FALSE(mConfig.mInputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64))
+ << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
+ ASSERT_TRUE(mConfig.mOutputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64))
+ << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
+ ASSERT_EQ(kCodec2Int64, vendorInt64);
+
+ AString vendorString;
+ ASSERT_TRUE(mConfig.mInputFormat->findString(KEY_VENDOR_STRING, &vendorString))
+ << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
+ ASSERT_STREQ(kCodec2Str, vendorString.c_str());
+ ASSERT_FALSE(mConfig.mOutputFormat->findString(KEY_VENDOR_STRING, &vendorString))
+ << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
+}
+
+TEST_F(CCodecConfigTest, VendorParamUpdate_PartiallySubscribed) {
+ ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
+
+ // Subscribe to example.int32 only
+ std::vector<std::unique_ptr<C2Param>> configUpdate;
+ sp<AMessage> format{new AMessage};
+ format->setInt32(KEY_VENDOR_INT32, 0);
+ configUpdate.clear();
+ ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams(
+ mConfigurable, format, D::IS_INPUT | D::IS_OUTPUT, C2_MAY_BLOCK, &configUpdate));
+ ASSERT_EQ(OK, mConfig.setParameters(mConfigurable, configUpdate, C2_MAY_BLOCK));
+
+ C2PortVendorInt32Info::input i32(kCodec2Int32);
+ C2StreamVendorInt64Info::output i64(0u, kCodec2Int64);
+ std::unique_ptr<C2PortVendorStringInfo::input> str =
+ C2PortVendorStringInfo::input::AllocUnique(strlen(kCodec2Str) + 1, kCodec2Str);
+ configUpdate.clear();
+ configUpdate.push_back(C2Param::Copy(i32));
+ configUpdate.push_back(C2Param::Copy(i64));
+ configUpdate.push_back(std::move(str));
+
+ // Only example.i32 should be updated
+ ASSERT_TRUE(mConfig.updateConfiguration(configUpdate, D::IS_INPUT | D::IS_OUTPUT));
+
+ int32_t vendorInt32{0};
+ ASSERT_TRUE(mConfig.mInputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
+ << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
+ ASSERT_EQ(kCodec2Int32, vendorInt32);
+ ASSERT_FALSE(mConfig.mOutputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
+ << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
+
+ int64_t vendorInt64{0};
+ ASSERT_FALSE(mConfig.mInputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64))
+ << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
+ ASSERT_FALSE(mConfig.mOutputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64))
+ << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
+
+ AString vendorString;
+ ASSERT_FALSE(mConfig.mInputFormat->findString(KEY_VENDOR_STRING, &vendorString))
+ << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
+ ASSERT_FALSE(mConfig.mOutputFormat->findString(KEY_VENDOR_STRING, &vendorString))
+ << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
+}
+
+} // namespace android
diff --git a/media/codec2/sfplugin/tests/MediaCodec_sanity_test.cpp b/media/codec2/sfplugin/tests/MediaCodec_sanity_test.cpp
index ba3687b..6deede0 100644
--- a/media/codec2/sfplugin/tests/MediaCodec_sanity_test.cpp
+++ b/media/codec2/sfplugin/tests/MediaCodec_sanity_test.cpp
@@ -21,7 +21,7 @@
#include <binder/ProcessState.h>
#include <gtest/gtest.h>
#include <gui/Surface.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/MediaCodecBuffer.h>
#include <media/hardware/VideoAPI.h>
#include <media/stagefright/MediaCodec.h>
diff --git a/media/codec2/sfplugin/utils/Android.bp b/media/codec2/sfplugin/utils/Android.bp
index 8c8f025..205abdc 100644
--- a/media/codec2/sfplugin/utils/Android.bp
+++ b/media/codec2/sfplugin/utils/Android.bp
@@ -1,6 +1,7 @@
cc_library_shared {
name: "libsfplugin_ccodec_utils",
vendor_available: true,
+ double_loadable: true,
srcs: [
"Codec2BufferUtils.cpp",
diff --git a/media/codec2/sfplugin/utils/Codec2Mapper.cpp b/media/codec2/sfplugin/utils/Codec2Mapper.cpp
index 40160c7..903db6c 100644
--- a/media/codec2/sfplugin/utils/Codec2Mapper.cpp
+++ b/media/codec2/sfplugin/utils/Codec2Mapper.cpp
@@ -190,6 +190,7 @@
{ C2Config::PROFILE_DV_HE_07, DolbyVisionProfileDvheDtb },
{ C2Config::PROFILE_DV_HE_08, DolbyVisionProfileDvheSt },
{ C2Config::PROFILE_DV_AV_09, DolbyVisionProfileDvavSe },
+ { C2Config::PROFILE_DV_AV1_10, DolbyVisionProfileDvav110 },
};
ALookup<C2Config::level_t, int32_t> sH263Levels = {
@@ -382,10 +383,11 @@
// TODO: will need to disambiguate between Main8 and Main10
{ C2Config::PROFILE_AV1_0, AV1ProfileMain8 },
{ C2Config::PROFILE_AV1_0, AV1ProfileMain10 },
+ { C2Config::PROFILE_AV1_0, AV1ProfileMain10HDR10 },
+ { C2Config::PROFILE_AV1_0, AV1ProfileMain10HDR10Plus },
};
ALookup<C2Config::profile_t, int32_t> sAv1HdrProfiles = {
- { C2Config::PROFILE_AV1_0, AV1ProfileMain10 },
{ C2Config::PROFILE_AV1_0, AV1ProfileMain10HDR10 },
};
@@ -629,7 +631,7 @@
// static
std::shared_ptr<C2Mapper::ProfileLevelMapper>
C2Mapper::GetProfileLevelMapper(std::string mediaType) {
- std::transform(mediaType.begin(), mediaType.begin(), mediaType.end(), ::tolower);
+ std::transform(mediaType.begin(), mediaType.end(), mediaType.begin(), ::tolower);
if (mediaType == MIMETYPE_AUDIO_AAC) {
return std::make_shared<AacProfileLevelMapper>();
} else if (mediaType == MIMETYPE_VIDEO_AVC) {
@@ -657,11 +659,13 @@
// static
std::shared_ptr<C2Mapper::ProfileLevelMapper>
C2Mapper::GetHdrProfileLevelMapper(std::string mediaType, bool isHdr10Plus) {
- std::transform(mediaType.begin(), mediaType.begin(), mediaType.end(), ::tolower);
+ std::transform(mediaType.begin(), mediaType.end(), mediaType.begin(), ::tolower);
if (mediaType == MIMETYPE_VIDEO_HEVC) {
return std::make_shared<HevcProfileLevelMapper>(true, isHdr10Plus);
} else if (mediaType == MIMETYPE_VIDEO_VP9) {
return std::make_shared<Vp9ProfileLevelMapper>(true, isHdr10Plus);
+ } else if (mediaType == MIMETYPE_VIDEO_AV1) {
+ return std::make_shared<Av1ProfileLevelMapper>(true, isHdr10Plus);
}
return nullptr;
}
@@ -945,3 +949,41 @@
bool C2Mapper::map(ColorAspects::Transfer from, C2Color::transfer_t *to) {
return sColorTransfersSf.map(from, to);
}
+
+// static
+bool C2Mapper::mapPixelFormatFrameworkToCodec(
+ int32_t frameworkValue, uint32_t *c2Value) {
+ switch (frameworkValue) {
+ case COLOR_FormatSurface:
+ *c2Value = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+ return true;
+ case COLOR_FormatYUV420Flexible:
+ *c2Value = HAL_PIXEL_FORMAT_YCBCR_420_888;
+ return true;
+ case COLOR_FormatYUV420Planar:
+ case COLOR_FormatYUV420SemiPlanar:
+ case COLOR_FormatYUV420PackedPlanar:
+ case COLOR_FormatYUV420PackedSemiPlanar:
+ *c2Value = HAL_PIXEL_FORMAT_YV12;
+ return true;
+ default:
+ // TODO: support some sort of passthrough
+ return false;
+ }
+}
+
+// static
+bool C2Mapper::mapPixelFormatCodecToFramework(
+ uint32_t c2Value, int32_t *frameworkValue) {
+ switch (c2Value) {
+ case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+ *frameworkValue = COLOR_FormatSurface;
+ return true;
+ case HAL_PIXEL_FORMAT_YV12:
+ case HAL_PIXEL_FORMAT_YCBCR_420_888:
+ *frameworkValue = COLOR_FormatYUV420Flexible;
+ return true;
+ default:
+ return false;
+ }
+}
diff --git a/media/codec2/sfplugin/utils/Codec2Mapper.h b/media/codec2/sfplugin/utils/Codec2Mapper.h
index cec6f07..797c8a8 100644
--- a/media/codec2/sfplugin/utils/Codec2Mapper.h
+++ b/media/codec2/sfplugin/utils/Codec2Mapper.h
@@ -75,6 +75,11 @@
static bool map(ColorAspects::MatrixCoeffs, C2Color::matrix_t*);
static bool map(C2Color::transfer_t, ColorAspects::Transfer*);
static bool map(ColorAspects::Transfer, C2Color::transfer_t*);
+
+ static bool mapPixelFormatFrameworkToCodec(
+ int32_t frameworkValue, uint32_t *c2Value);
+ static bool mapPixelFormatCodecToFramework(
+ uint32_t c2Value, int32_t *frameworkValue);
};
}
diff --git a/media/codec2/vndk/Android.bp b/media/codec2/vndk/Android.bp
index 52cc7ad..f3e37e0 100644
--- a/media/codec2/vndk/Android.bp
+++ b/media/codec2/vndk/Android.bp
@@ -14,8 +14,11 @@
cc_library_shared {
name: "libcodec2_vndk",
vendor_available: true,
+ // TODO: b/147147883
+ double_loadable: true,
srcs: [
+ "C2AllocatorBlob.cpp",
"C2AllocatorIon.cpp",
"C2AllocatorGralloc.cpp",
"C2Buffer.cpp",
@@ -49,14 +52,10 @@
],
shared_libs: [
- "android.hardware.graphics.allocator@2.0",
- "android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.bufferqueue@2.0",
- "android.hardware.graphics.mapper@2.0",
- "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.common@1.2",
"android.hardware.media.bufferpool@2.0",
"libbase",
- "libbinder",
"libcutils",
"libdl",
"libhardware",
@@ -96,6 +95,10 @@
name: "libcodec2-internal-defaults",
defaults: ["libcodec2-impl-defaults"],
+ header_libs: [
+ "libcodec2_internal",
+ ],
+
shared_libs: [
"libcutils", // for properties
],
diff --git a/media/codec2/vndk/C2AllocatorBlob.cpp b/media/codec2/vndk/C2AllocatorBlob.cpp
new file mode 100644
index 0000000..50c9e59
--- /dev/null
+++ b/media/codec2/vndk/C2AllocatorBlob.cpp
@@ -0,0 +1,186 @@
+/*
+ * 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.
+ */
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "C2AllocatorBlob"
+
+#include <C2AllocatorBlob.h>
+#include <C2PlatformSupport.h>
+
+#include <android/hardware/graphics/common/1.2/types.h>
+#include <utils/Log.h>
+
+namespace android {
+
+using ::android::hardware::graphics::common::V1_2::PixelFormat;
+
+constexpr uint32_t kLinearBufferHeight = 1u;
+constexpr uint32_t kLinearBufferFormat = static_cast<uint32_t>(PixelFormat::BLOB);
+
+namespace {
+
+c2_status_t GetCapacityFromHandle(const C2Handle* const grallocHandle, size_t* capacity) {
+ uint32_t width, height, format, stride, generation, igbp_slot;
+ uint64_t usage, igbp_id;
+ _UnwrapNativeCodec2GrallocMetadata(grallocHandle, &width, &height, &format, &usage, &stride,
+ &generation, &igbp_id, &igbp_slot);
+
+ if (height != kLinearBufferHeight || format != kLinearBufferFormat) {
+ return C2_BAD_VALUE;
+ }
+ *capacity = width;
+ return C2_OK;
+}
+
+} // namespace
+
+// C2AllocationBlob is a wrapper for C2AllocationGralloc allocated by C2AllocatorGralloc.
+// C2AllocationBlob::handle() delegates to the backed C2AllocationGralloc::handle().
+class C2AllocationBlob : public C2LinearAllocation {
+public:
+ C2AllocationBlob(std::shared_ptr<C2GraphicAllocation> graphicAllocation, size_t capacity,
+ C2Allocator::id_t allocatorId);
+ ~C2AllocationBlob() override;
+ c2_status_t map(size_t offset, size_t size, C2MemoryUsage usage, C2Fence* fence,
+ void** addr /* nonnull */) override;
+ c2_status_t unmap(void* addr, size_t size, C2Fence* fenceFd) override;
+
+ id_t getAllocatorId() const override { return mAllocatorId; }
+ const C2Handle* handle() const override { return mGraphicAllocation->handle(); }
+ bool equals(const std::shared_ptr<C2LinearAllocation>& other) const override {
+ return other && other->handle() == handle();
+ }
+
+private:
+ const std::shared_ptr<C2GraphicAllocation> mGraphicAllocation;
+ const C2Allocator::id_t mAllocatorId;
+};
+
+C2AllocationBlob::C2AllocationBlob(
+ std::shared_ptr<C2GraphicAllocation> graphicAllocation, size_t capacity,
+ C2Allocator::id_t allocatorId)
+ : C2LinearAllocation(capacity),
+ mGraphicAllocation(std::move(graphicAllocation)),
+ mAllocatorId(allocatorId) {}
+
+C2AllocationBlob::~C2AllocationBlob() {}
+
+c2_status_t C2AllocationBlob::map(size_t offset, size_t size, C2MemoryUsage usage,
+ C2Fence* fence, void** addr /* nonnull */) {
+ C2PlanarLayout layout;
+ C2Rect rect = C2Rect(size, kLinearBufferHeight).at(offset, 0u);
+ return mGraphicAllocation->map(rect, usage, fence, &layout, reinterpret_cast<uint8_t**>(addr));
+}
+
+c2_status_t C2AllocationBlob::unmap(void* addr, size_t size, C2Fence* fenceFd) {
+ C2Rect rect(size, kLinearBufferHeight);
+ return mGraphicAllocation->unmap(reinterpret_cast<uint8_t**>(&addr), rect, fenceFd);
+}
+
+/* ====================================== BLOB ALLOCATOR ====================================== */
+C2AllocatorBlob::C2AllocatorBlob(id_t id) {
+ C2MemoryUsage minUsage = {0, 0};
+ C2MemoryUsage maxUsage = {C2MemoryUsage::CPU_READ | C2MemoryUsage::READ_PROTECTED,
+ C2MemoryUsage::CPU_WRITE};
+ Traits traits = {"android.allocator.blob", id, LINEAR, minUsage, maxUsage};
+ mTraits = std::make_shared<C2Allocator::Traits>(traits);
+ auto allocatorStore = GetCodec2PlatformAllocatorStore();
+ allocatorStore->fetchAllocator(C2PlatformAllocatorStore::GRALLOC, &mC2AllocatorGralloc);
+ if (!mC2AllocatorGralloc) {
+ ALOGE("Failed to obtain C2AllocatorGralloc as backed allocator");
+ }
+}
+
+C2AllocatorBlob::~C2AllocatorBlob() {}
+
+c2_status_t C2AllocatorBlob::newLinearAllocation(
+ uint32_t capacity, C2MemoryUsage usage, std::shared_ptr<C2LinearAllocation>* allocation) {
+ if (allocation == nullptr) {
+ return C2_BAD_VALUE;
+ }
+
+ allocation->reset();
+
+ if (!mC2AllocatorGralloc) {
+ return C2_CORRUPTED;
+ }
+
+ std::shared_ptr<C2GraphicAllocation> graphicAllocation;
+ c2_status_t status = mC2AllocatorGralloc->newGraphicAllocation(
+ capacity, kLinearBufferHeight, kLinearBufferFormat, usage, &graphicAllocation);
+ if (status != C2_OK) {
+ ALOGE("Failed newGraphicAllocation");
+ return status;
+ }
+
+ allocation->reset(new C2AllocationBlob(std::move(graphicAllocation),
+ static_cast<size_t>(capacity), mTraits->id));
+ return C2_OK;
+}
+
+c2_status_t C2AllocatorBlob::priorLinearAllocation(
+ const C2Handle* handle, std::shared_ptr<C2LinearAllocation>* allocation) {
+ if (allocation == nullptr) {
+ return C2_BAD_VALUE;
+ }
+
+ allocation->reset();
+
+ if (!mC2AllocatorGralloc) {
+ return C2_CORRUPTED;
+ }
+
+ std::shared_ptr<C2GraphicAllocation> graphicAllocation;
+ c2_status_t status = mC2AllocatorGralloc->priorGraphicAllocation(handle, &graphicAllocation);
+ if (status != C2_OK) {
+ ALOGE("Failed priorGraphicAllocation");
+ return status;
+ }
+
+ const C2Handle* const grallocHandle = graphicAllocation->handle();
+ size_t capacity = 0;
+ status = GetCapacityFromHandle(grallocHandle, &capacity);
+ if (status != C2_OK) {
+ ALOGE("Failed to extract capacity from Handle");
+ return status;
+ }
+
+ allocation->reset(new C2AllocationBlob(std::move(graphicAllocation), capacity, mTraits->id));
+ return C2_OK;
+}
+
+id_t C2AllocatorBlob::getId() const {
+ return mTraits->id;
+}
+
+C2String C2AllocatorBlob::getName() const {
+ return mTraits->name;
+}
+
+std::shared_ptr<const C2Allocator::Traits> C2AllocatorBlob::getTraits() const {
+ return mTraits;
+}
+
+// static
+bool C2AllocatorBlob::isValid(const C2Handle* const o) {
+ size_t capacity;
+ // Distinguish C2Handle purely allocated by C2AllocatorGralloc, or one allocated through
+ // C2AllocatorBlob, by checking the handle's height is 1, and its format is
+ // PixelFormat::BLOB by GetCapacityFromHandle().
+ return C2AllocatorGralloc::isValid(o) && GetCapacityFromHandle(o, &capacity) == C2_OK;
+}
+
+} // namespace android
diff --git a/media/codec2/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp
index af97e61..3ac3d89 100644
--- a/media/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/codec2/vndk/C2AllocatorGralloc.cpp
@@ -18,17 +18,21 @@
#define LOG_TAG "C2AllocatorGralloc"
#include <utils/Log.h>
-#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
-#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <mutex>
+
+#include <android/hardware/graphics/common/1.2/types.h>
#include <cutils/native_handle.h>
#include <hardware/gralloc.h>
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/GraphicBufferMapper.h>
#include <C2AllocatorGralloc.h>
#include <C2Buffer.h>
#include <C2PlatformSupport.h>
+using ::android::hardware::hidl_handle;
+using PixelFormat4 = ::android::hardware::graphics::common::V1_2::PixelFormat;
+
namespace android {
namespace /* unnamed */ {
@@ -61,59 +65,9 @@
(expected & PASSTHROUGH_USAGE_MASK));
}
-using ::android::hardware::hidl_handle;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::graphics::common::V1_0::BufferUsage;
-using PixelFormat2 = ::android::hardware::graphics::common::V1_0::PixelFormat;
-using PixelFormat3 = ::android::hardware::graphics::common::V1_2::PixelFormat;
-
-using IAllocator2 = ::android::hardware::graphics::allocator::V2_0::IAllocator;
-using BufferDescriptor2 = ::android::hardware::graphics::mapper::V2_0::BufferDescriptor;
-using Error2 = ::android::hardware::graphics::mapper::V2_0::Error;
-using IMapper2 = ::android::hardware::graphics::mapper::V2_0::IMapper;
-
-using IAllocator3 = ::android::hardware::graphics::allocator::V3_0::IAllocator;
-using BufferDescriptor3 = ::android::hardware::graphics::mapper::V3_0::BufferDescriptor;
-using Error3 = ::android::hardware::graphics::mapper::V3_0::Error;
-using IMapper3 = ::android::hardware::graphics::mapper::V3_0::IMapper;
-
namespace /* unnamed */ {
-struct BufferDescriptorInfo2 {
- IMapper2::BufferDescriptorInfo mapperInfo;
- uint32_t stride;
-};
-
-struct BufferDescriptorInfo3 {
- IMapper3::BufferDescriptorInfo mapperInfo;
- uint32_t stride;
-};
-
/* ===================================== GRALLOC ALLOCATION ==================================== */
-c2_status_t maperr2error(Error2 maperr) {
- switch (maperr) {
- case Error2::NONE: return C2_OK;
- case Error2::BAD_DESCRIPTOR: return C2_BAD_VALUE;
- case Error2::BAD_BUFFER: return C2_BAD_VALUE;
- case Error2::BAD_VALUE: return C2_BAD_VALUE;
- case Error2::NO_RESOURCES: return C2_NO_MEMORY;
- case Error2::UNSUPPORTED: return C2_CANNOT_DO;
- }
- return C2_CORRUPTED;
-}
-
-c2_status_t maperr2error(Error3 maperr) {
- switch (maperr) {
- case Error3::NONE: return C2_OK;
- case Error3::BAD_DESCRIPTOR: return C2_BAD_VALUE;
- case Error3::BAD_BUFFER: return C2_BAD_VALUE;
- case Error3::BAD_VALUE: return C2_BAD_VALUE;
- case Error3::NO_RESOURCES: return C2_NO_MEMORY;
- case Error3::UNSUPPORTED: return C2_CANNOT_DO;
- }
- return C2_CORRUPTED;
-}
-
bool native_handle_is_invalid(const native_handle_t *const handle) {
// perform basic validation of a native handle
if (handle == nullptr) {
@@ -309,15 +263,11 @@
// internal methods
// |handle| will be moved.
+
C2AllocationGralloc(
- const BufferDescriptorInfo2 &info,
- const sp<IMapper2> &mapper,
- hidl_handle &hidlHandle,
- const C2HandleGralloc *const handle,
- C2Allocator::id_t allocatorId);
- C2AllocationGralloc(
- const BufferDescriptorInfo3 &info,
- const sp<IMapper3> &mapper,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t layerCount,
+ uint64_t grallocUsage, uint32_t stride,
hidl_handle &hidlHandle,
const C2HandleGralloc *const handle,
C2Allocator::id_t allocatorId);
@@ -325,10 +275,12 @@
c2_status_t status() const;
private:
- const BufferDescriptorInfo2 mInfo2{};
- const sp<IMapper2> mMapper2{nullptr};
- const BufferDescriptorInfo3 mInfo3{};
- const sp<IMapper3> mMapper3{nullptr};
+ const uint32_t mWidth;
+ const uint32_t mHeight;
+ const uint32_t mFormat;
+ const uint32_t mLayerCount;
+ const uint64_t mGrallocUsage;
+ const uint32_t mStride;
const hidl_handle mHidlHandle;
const C2HandleGralloc *mHandle;
buffer_handle_t mBuffer;
@@ -339,31 +291,19 @@
};
C2AllocationGralloc::C2AllocationGralloc(
- const BufferDescriptorInfo2 &info,
- const sp<IMapper2> &mapper,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t layerCount,
+ uint64_t grallocUsage, uint32_t stride,
hidl_handle &hidlHandle,
const C2HandleGralloc *const handle,
C2Allocator::id_t allocatorId)
- : C2GraphicAllocation(info.mapperInfo.width, info.mapperInfo.height),
- mInfo2(info),
- mMapper2(mapper),
- mHidlHandle(std::move(hidlHandle)),
- mHandle(handle),
- mBuffer(nullptr),
- mLockedHandle(nullptr),
- mLocked(false),
- mAllocatorId(allocatorId) {
-}
-
-C2AllocationGralloc::C2AllocationGralloc(
- const BufferDescriptorInfo3 &info,
- const sp<IMapper3> &mapper,
- hidl_handle &hidlHandle,
- const C2HandleGralloc *const handle,
- C2Allocator::id_t allocatorId)
- : C2GraphicAllocation(info.mapperInfo.width, info.mapperInfo.height),
- mInfo3(info),
- mMapper3(mapper),
+ : C2GraphicAllocation(width, height),
+ mWidth(width),
+ mHeight(height),
+ mFormat(format),
+ mLayerCount(layerCount),
+ mGrallocUsage(grallocUsage),
+ mStride(stride),
mHidlHandle(std::move(hidlHandle)),
mHandle(handle),
mBuffer(nullptr),
@@ -379,16 +319,9 @@
unmap(addr, C2Rect(), nullptr);
}
if (mBuffer) {
- if (mMapper2) {
- if (!mMapper2->freeBuffer(const_cast<native_handle_t *>(
- mBuffer)).isOk()) {
- ALOGE("failed transaction: freeBuffer");
- }
- } else {
- if (!mMapper3->freeBuffer(const_cast<native_handle_t *>(
- mBuffer)).isOk()) {
- ALOGE("failed transaction: freeBuffer");
- }
+ status_t err = GraphicBufferMapper::get().freeBuffer(mBuffer);
+ if (err) {
+ ALOGE("failed transaction: freeBuffer");
}
}
if (mHandle) {
@@ -410,7 +343,7 @@
(long long)usage.expected, (long long)grallocUsage);
// TODO
- (void) fence;
+ (void)fence;
std::lock_guard<std::mutex> lock(mMappedLock);
if (mBuffer && mLocked) {
@@ -422,34 +355,13 @@
return C2_BAD_VALUE;
}
- c2_status_t err = C2_OK;
if (!mBuffer) {
- if (mMapper2) {
- if (!mMapper2->importBuffer(
- mHidlHandle, [&err, this](const auto &maperr, const auto &buffer) {
- err = maperr2error(maperr);
- if (err == C2_OK) {
- mBuffer = static_cast<buffer_handle_t>(buffer);
- }
- }).isOk()) {
- ALOGE("failed transaction: importBuffer");
- return C2_CORRUPTED;
- }
- } else {
- if (!mMapper3->importBuffer(
- mHidlHandle, [&err, this](const auto &maperr, const auto &buffer) {
- err = maperr2error(maperr);
- if (err == C2_OK) {
- mBuffer = static_cast<buffer_handle_t>(buffer);
- }
- }).isOk()) {
- ALOGE("failed transaction: importBuffer (@3.0)");
- return C2_CORRUPTED;
- }
- }
- if (err != C2_OK) {
- ALOGD("importBuffer failed: %d", err);
- return err;
+ status_t err = GraphicBufferMapper::get().importBuffer(
+ mHidlHandle.getNativeHandle(), mWidth, mHeight, mLayerCount,
+ mFormat, mGrallocUsage, mStride, &mBuffer);
+ if (err) {
+ ALOGE("failed transaction: importBuffer");
+ return C2_CORRUPTED;
}
if (mBuffer == nullptr) {
ALOGD("importBuffer returned null buffer");
@@ -461,69 +373,26 @@
if (mHandle) {
mHandle->getIgbpData(&generation, &igbp_id, &igbp_slot);
}
- if (mMapper2) {
- mLockedHandle = C2HandleGralloc::WrapAndMoveNativeHandle(
- mBuffer, mInfo2.mapperInfo.width, mInfo2.mapperInfo.height,
- (uint32_t)mInfo2.mapperInfo.format, mInfo2.mapperInfo.usage,
- mInfo2.stride, generation, igbp_id, igbp_slot);
- } else {
- mLockedHandle = C2HandleGralloc::WrapAndMoveNativeHandle(
- mBuffer, mInfo3.mapperInfo.width, mInfo3.mapperInfo.height,
- (uint32_t)mInfo3.mapperInfo.format, mInfo3.mapperInfo.usage,
- mInfo3.stride, generation, igbp_id, igbp_slot);
- }
- }
- PixelFormat3 format = mMapper2 ?
- PixelFormat3(mInfo2.mapperInfo.format) :
- PixelFormat3(mInfo3.mapperInfo.format);
- switch (format) {
- case PixelFormat3::RGBA_1010102: {
+ mLockedHandle = C2HandleGralloc::WrapAndMoveNativeHandle(
+ mBuffer, mWidth, mHeight, mFormat, mGrallocUsage,
+ mStride, generation, igbp_id, igbp_slot);
+ }
+ switch (mFormat) {
+ case static_cast<uint32_t>(PixelFormat4::RGBA_1010102): {
// TRICKY: this is used for media as YUV444 in the case when it is queued directly to a
// Surface. In all other cases it is RGBA. We don't know which case it is here, so
// default to YUV for now.
void *pointer = nullptr;
- if (mMapper2) {
- if (!mMapper2->lock(
- const_cast<native_handle_t *>(mBuffer),
- grallocUsage,
- { (int32_t)rect.left, (int32_t)rect.top,
- (int32_t)rect.width, (int32_t)rect.height },
- // TODO: fence
- hidl_handle(),
- [&err, &pointer](const auto &maperr, const auto &mapPointer) {
- err = maperr2error(maperr);
- if (err == C2_OK) {
- pointer = mapPointer;
- }
- }).isOk()) {
- ALOGE("failed transaction: lock(RGBA_1010102)");
- return C2_CORRUPTED;
- }
- } else {
- if (!mMapper3->lock(
- const_cast<native_handle_t *>(mBuffer),
- grallocUsage,
- { (int32_t)rect.left, (int32_t)rect.top,
- (int32_t)rect.width, (int32_t)rect.height },
- // TODO: fence
- hidl_handle(),
- [&err, &pointer](const auto &maperr, const auto &mapPointer,
- int32_t bytesPerPixel, int32_t bytesPerStride) {
- err = maperr2error(maperr);
- if (err == C2_OK) {
- pointer = mapPointer;
- }
- (void)bytesPerPixel;
- (void)bytesPerStride;
- }).isOk()) {
- ALOGE("failed transaction: lock(RGBA_1010102) (@3.0)");
- return C2_CORRUPTED;
- }
- }
- if (err != C2_OK) {
- ALOGD("lock failed: %d", err);
- return err;
+ // TODO: fence
+ status_t err = GraphicBufferMapper::get().lock(
+ const_cast<native_handle_t *>(mBuffer), grallocUsage,
+ { (int32_t)rect.left, (int32_t)rect.top,
+ (int32_t)rect.width, (int32_t)rect.height },
+ &pointer);
+ if (err) {
+ ALOGE("failed transaction: lock(RGBA_1010102)");
+ return C2_CORRUPTED;
}
// treat as 32-bit values
addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)pointer;
@@ -533,13 +402,10 @@
layout->type = C2PlanarLayout::TYPE_YUVA;
layout->numPlanes = 4;
layout->rootPlanes = 1;
- int32_t stride = mMapper2 ?
- int32_t(mInfo2.stride) :
- int32_t(mInfo3.stride);
layout->planes[C2PlanarLayout::PLANE_Y] = {
C2PlaneInfo::CHANNEL_Y, // channel
4, // colInc
- 4 * stride, // rowInc
+ static_cast<int32_t>(4 * mStride), // rowInc
1, // mColSampling
1, // mRowSampling
32, // allocatedDepth
@@ -552,7 +418,7 @@
layout->planes[C2PlanarLayout::PLANE_U] = {
C2PlaneInfo::CHANNEL_CB, // channel
4, // colInc
- 4 * stride, // rowInc
+ static_cast<int32_t>(4 * mStride), // rowInc
1, // mColSampling
1, // mRowSampling
32, // allocatedDepth
@@ -565,7 +431,7 @@
layout->planes[C2PlanarLayout::PLANE_V] = {
C2PlaneInfo::CHANNEL_CR, // channel
4, // colInc
- 4 * stride, // rowInc
+ static_cast<int32_t>(4 * mStride), // rowInc
1, // mColSampling
1, // mRowSampling
32, // allocatedDepth
@@ -578,7 +444,7 @@
layout->planes[C2PlanarLayout::PLANE_A] = {
C2PlaneInfo::CHANNEL_A, // channel
4, // colInc
- 4 * stride, // rowInc
+ static_cast<int32_t>(4 * mStride), // rowInc
1, // mColSampling
1, // mRowSampling
32, // allocatedDepth
@@ -591,52 +457,20 @@
break;
}
- case PixelFormat3::RGBA_8888:
+ case static_cast<uint32_t>(PixelFormat4::RGBA_8888):
// TODO: alpha channel
// fall-through
- case PixelFormat3::RGBX_8888: {
+ case static_cast<uint32_t>(PixelFormat4::RGBX_8888): {
void *pointer = nullptr;
- if (mMapper2) {
- if (!mMapper2->lock(
- const_cast<native_handle_t *>(mBuffer),
- grallocUsage,
- { (int32_t)rect.left, (int32_t)rect.top,
- (int32_t)rect.width, (int32_t)rect.height },
- // TODO: fence
- hidl_handle(),
- [&err, &pointer](const auto &maperr, const auto &mapPointer) {
- err = maperr2error(maperr);
- if (err == C2_OK) {
- pointer = mapPointer;
- }
- }).isOk()) {
- ALOGE("failed transaction: lock(RGBA_8888)");
- return C2_CORRUPTED;
- }
- } else {
- if (!mMapper3->lock(
- const_cast<native_handle_t *>(mBuffer),
- grallocUsage,
- { (int32_t)rect.left, (int32_t)rect.top,
- (int32_t)rect.width, (int32_t)rect.height },
- // TODO: fence
- hidl_handle(),
- [&err, &pointer](const auto &maperr, const auto &mapPointer,
- int32_t bytesPerPixel, int32_t bytesPerStride) {
- err = maperr2error(maperr);
- if (err == C2_OK) {
- pointer = mapPointer;
- }
- (void)bytesPerPixel;
- (void)bytesPerStride;
- }).isOk()) {
- ALOGE("failed transaction: lock(RGBA_8888) (@3.0)");
- return C2_CORRUPTED;
- }
- }
- if (err != C2_OK) {
- ALOGD("lock failed: %d", err);
- return err;
+ // TODO: fence
+ status_t err = GraphicBufferMapper::get().lock(
+ const_cast<native_handle_t*>(mBuffer), grallocUsage,
+ { (int32_t)rect.left, (int32_t)rect.top,
+ (int32_t)rect.width, (int32_t)rect.height },
+ &pointer);
+ if (err) {
+ ALOGE("failed transaction: lock(RGBA_8888)");
+ return C2_CORRUPTED;
}
addr[C2PlanarLayout::PLANE_R] = (uint8_t *)pointer;
addr[C2PlanarLayout::PLANE_G] = (uint8_t *)pointer + 1;
@@ -644,13 +478,10 @@
layout->type = C2PlanarLayout::TYPE_RGB;
layout->numPlanes = 3;
layout->rootPlanes = 1;
- int32_t stride = mMapper2 ?
- int32_t(mInfo2.stride) :
- int32_t(mInfo3.stride);
layout->planes[C2PlanarLayout::PLANE_R] = {
C2PlaneInfo::CHANNEL_R, // channel
4, // colInc
- 4 * stride, // rowInc
+ static_cast<int32_t>(4 * mStride), // rowInc
1, // mColSampling
1, // mRowSampling
8, // allocatedDepth
@@ -663,7 +494,7 @@
layout->planes[C2PlanarLayout::PLANE_G] = {
C2PlaneInfo::CHANNEL_G, // channel
4, // colInc
- 4 * stride, // rowInc
+ static_cast<int32_t>(4 * mStride), // rowInc
1, // mColSampling
1, // mRowSampling
8, // allocatedDepth
@@ -676,7 +507,7 @@
layout->planes[C2PlanarLayout::PLANE_B] = {
C2PlaneInfo::CHANNEL_B, // channel
4, // colInc
- 4 * stride, // rowInc
+ static_cast<int32_t>(4 * mStride), // rowInc
1, // mColSampling
1, // mRowSampling
8, // allocatedDepth
@@ -689,69 +520,23 @@
break;
}
- case PixelFormat3::YCBCR_420_888:
+ case static_cast<uint32_t>(PixelFormat4::YCBCR_420_888):
// fall-through
- case PixelFormat3::YV12:
+ case static_cast<uint32_t>(PixelFormat4::YV12):
// fall-through
default: {
- struct YCbCrLayout {
- void* y;
- void* cb;
- void* cr;
- uint32_t yStride;
- uint32_t cStride;
- uint32_t chromaStep;
- };
- YCbCrLayout ycbcrLayout;
- if (mMapper2) {
- if (!mMapper2->lockYCbCr(
- const_cast<native_handle_t *>(mBuffer), grallocUsage,
+ android_ycbcr ycbcrLayout;
+
+ status_t err = GraphicBufferMapper::get().lockYCbCr(
+ const_cast<native_handle_t*>(mBuffer), grallocUsage,
{ (int32_t)rect.left, (int32_t)rect.top,
(int32_t)rect.width, (int32_t)rect.height },
- // TODO: fence
- hidl_handle(),
- [&err, &ycbcrLayout](const auto &maperr, const auto &mapLayout) {
- err = maperr2error(maperr);
- if (err == C2_OK) {
- ycbcrLayout = YCbCrLayout{
- mapLayout.y,
- mapLayout.cb,
- mapLayout.cr,
- mapLayout.yStride,
- mapLayout.cStride,
- mapLayout.chromaStep};
- }
- }).isOk()) {
- ALOGE("failed transaction: lockYCbCr");
- return C2_CORRUPTED;
- }
- } else {
- if (!mMapper3->lockYCbCr(
- const_cast<native_handle_t *>(mBuffer), grallocUsage,
- { (int32_t)rect.left, (int32_t)rect.top,
- (int32_t)rect.width, (int32_t)rect.height },
- // TODO: fence
- hidl_handle(),
- [&err, &ycbcrLayout](const auto &maperr, const auto &mapLayout) {
- err = maperr2error(maperr);
- if (err == C2_OK) {
- ycbcrLayout = YCbCrLayout{
- mapLayout.y,
- mapLayout.cb,
- mapLayout.cr,
- mapLayout.yStride,
- mapLayout.cStride,
- mapLayout.chromaStep};
- }
- }).isOk()) {
- ALOGE("failed transaction: lockYCbCr (@3.0)");
- return C2_CORRUPTED;
- }
+ &ycbcrLayout);
+ if (err) {
+ ALOGE("failed transaction: lockYCbCr");
+ return C2_CORRUPTED;
}
- if (err != C2_OK) {
- ALOGD("lockYCbCr failed: %d", err);
- return err;
- }
+
addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)ycbcrLayout.y;
addr[C2PlanarLayout::PLANE_U] = (uint8_t *)ycbcrLayout.cb;
addr[C2PlanarLayout::PLANE_V] = (uint8_t *)ycbcrLayout.cr;
@@ -761,7 +546,7 @@
layout->planes[C2PlanarLayout::PLANE_Y] = {
C2PlaneInfo::CHANNEL_Y, // channel
1, // colInc
- (int32_t)ycbcrLayout.yStride, // rowInc
+ (int32_t)ycbcrLayout.ystride, // rowInc
1, // mColSampling
1, // mRowSampling
8, // allocatedDepth
@@ -773,8 +558,8 @@
};
layout->planes[C2PlanarLayout::PLANE_U] = {
C2PlaneInfo::CHANNEL_CB, // channel
- (int32_t)ycbcrLayout.chromaStep, // colInc
- (int32_t)ycbcrLayout.cStride, // rowInc
+ (int32_t)ycbcrLayout.chroma_step, // colInc
+ (int32_t)ycbcrLayout.cstride, // rowInc
2, // mColSampling
2, // mRowSampling
8, // allocatedDepth
@@ -786,8 +571,8 @@
};
layout->planes[C2PlanarLayout::PLANE_V] = {
C2PlaneInfo::CHANNEL_CR, // channel
- (int32_t)ycbcrLayout.chromaStep, // colInc
- (int32_t)ycbcrLayout.cStride, // rowInc
+ (int32_t)ycbcrLayout.chroma_step, // colInc
+ (int32_t)ycbcrLayout.cstride, // rowInc
2, // mColSampling
2, // mRowSampling
8, // allocatedDepth
@@ -799,11 +584,11 @@
};
// handle interleaved formats
intptr_t uvOffset = addr[C2PlanarLayout::PLANE_V] - addr[C2PlanarLayout::PLANE_U];
- if (uvOffset > 0 && uvOffset < (intptr_t)ycbcrLayout.chromaStep) {
+ if (uvOffset > 0 && uvOffset < (intptr_t)ycbcrLayout.chroma_step) {
layout->rootPlanes = 2;
layout->planes[C2PlanarLayout::PLANE_V].rootIx = C2PlanarLayout::PLANE_U;
layout->planes[C2PlanarLayout::PLANE_V].offset = uvOffset;
- } else if (uvOffset < 0 && uvOffset > -(intptr_t)ycbcrLayout.chromaStep) {
+ } else if (uvOffset < 0 && uvOffset > -(intptr_t)ycbcrLayout.chroma_step) {
layout->rootPlanes = 2;
layout->planes[C2PlanarLayout::PLANE_U].rootIx = C2PlanarLayout::PLANE_V;
layout->planes[C2PlanarLayout::PLANE_U].offset = -uvOffset;
@@ -821,44 +606,18 @@
// TODO: check addr and size, use fence
(void)addr;
(void)rect;
+ (void)fence;
std::lock_guard<std::mutex> lock(mMappedLock);
- c2_status_t err = C2_OK;
- if (mMapper2) {
- if (!mMapper2->unlock(
- const_cast<native_handle_t *>(mBuffer),
- [&err, &fence](const auto &maperr, const auto &releaseFence) {
- // TODO
- (void) fence;
- (void) releaseFence;
- err = maperr2error(maperr);
- if (err == C2_OK) {
- // TODO: fence
- }
- }).isOk()) {
- ALOGE("failed transaction: unlock");
- return C2_CORRUPTED;
- }
- } else {
- if (!mMapper3->unlock(
- const_cast<native_handle_t *>(mBuffer),
- [&err, &fence](const auto &maperr, const auto &releaseFence) {
- // TODO
- (void) fence;
- (void) releaseFence;
- err = maperr2error(maperr);
- if (err == C2_OK) {
- // TODO: fence
- }
- }).isOk()) {
- ALOGE("failed transaction: unlock (@3.0)");
- return C2_CORRUPTED;
- }
+ // TODO: fence
+ status_t err = GraphicBufferMapper::get().unlock(mBuffer);
+ if (err) {
+ ALOGE("failed transaction: unlock");
+ return C2_CORRUPTED;
}
- if (err == C2_OK) {
- mLocked = false;
- }
- return err;
+
+ mLocked = false;
+ return C2_OK;
}
bool C2AllocationGralloc::equals(const std::shared_ptr<const C2GraphicAllocation> &other) const {
@@ -895,10 +654,6 @@
private:
std::shared_ptr<C2Allocator::Traits> mTraits;
c2_status_t mInit;
- sp<IAllocator2> mAllocator2;
- sp<IMapper2> mMapper2;
- sp<IAllocator3> mAllocator3;
- sp<IMapper3> mMapper3;
const bool mBufferQueue;
};
@@ -916,21 +671,6 @@
C2MemoryUsage minUsage = { 0, 0 }, maxUsage = { ~(uint64_t)0, ~(uint64_t)0 };
Traits traits = { "android.allocator.gralloc", id, C2Allocator::GRAPHIC, minUsage, maxUsage };
mTraits = std::make_shared<C2Allocator::Traits>(traits);
-
- // gralloc allocator is a singleton, so all objects share a global service
- mAllocator3 = IAllocator3::getService();
- mMapper3 = IMapper3::getService();
- if (!mAllocator3 || !mMapper3) {
- mAllocator3 = nullptr;
- mMapper3 = nullptr;
- mAllocator2 = IAllocator2::getService();
- mMapper2 = IMapper2::getService();
- if (!mAllocator2 || !mMapper2) {
- mAllocator2 = nullptr;
- mMapper2 = nullptr;
- mInit = C2_CORRUPTED;
- }
- }
}
c2_status_t C2AllocatorGralloc::Impl::newGraphicAllocation(
@@ -940,176 +680,59 @@
ALOGV("allocating buffer with usage %#llx => %#llx",
(long long)usage.expected, (long long)grallocUsage);
- c2_status_t err = C2_OK;
- hidl_handle buffer{};
+ buffer_handle_t buffer;
- if (mMapper2) {
- BufferDescriptorInfo2 info = {
- {
- width,
- height,
- 1u, // layerCount
- PixelFormat2(format),
- grallocUsage,
- },
- 0u, // stride placeholder
- };
- BufferDescriptor2 desc;
- if (!mMapper2->createDescriptor(
- info.mapperInfo, [&err, &desc](const auto &maperr, const auto &descriptor) {
- err = maperr2error(maperr);
- if (err == C2_OK) {
- desc = descriptor;
- }
- }).isOk()) {
- ALOGE("failed transaction: createDescriptor");
- return C2_CORRUPTED;
- }
- if (err != C2_OK) {
- return err;
- }
+ uint32_t stride = 0;
- // IAllocator shares IMapper error codes.
- if (!mAllocator2->allocate(
- desc,
- 1u,
- [&err, &buffer, &info](const auto &maperr, const auto &stride, auto &buffers) {
- err = maperr2error(maperr);
- if (err != C2_OK) {
- return;
- }
- if (buffers.size() != 1u) {
- err = C2_CORRUPTED;
- return;
- }
- info.stride = stride;
- buffer = buffers[0];
- }).isOk()) {
- ALOGE("failed transaction: allocate");
- return C2_CORRUPTED;
- }
- if (err != C2_OK) {
- return err;
- }
- allocation->reset(new C2AllocationGralloc(
- info, mMapper2, buffer,
- C2HandleGralloc::WrapAndMoveNativeHandle(
- buffer.getNativeHandle(),
- width, height,
- format, grallocUsage, info.stride,
- 0, 0, mBufferQueue ? ~0 : 0),
- mTraits->id));
- return C2_OK;
- } else {
- BufferDescriptorInfo3 info = {
- {
- width,
- height,
- 1u, // layerCount
- PixelFormat3(format),
- grallocUsage,
- },
- 0u, // stride placeholder
- };
- BufferDescriptor3 desc;
- if (!mMapper3->createDescriptor(
- info.mapperInfo, [&err, &desc](const auto &maperr, const auto &descriptor) {
- err = maperr2error(maperr);
- if (err == C2_OK) {
- desc = descriptor;
- }
- }).isOk()) {
- ALOGE("failed transaction: createDescriptor");
- return C2_CORRUPTED;
- }
- if (err != C2_OK) {
- return err;
- }
-
- // IAllocator shares IMapper error codes.
- if (!mAllocator3->allocate(
- desc,
- 1u,
- [&err, &buffer, &info](const auto &maperr, const auto &stride, auto &buffers) {
- err = maperr2error(maperr);
- if (err != C2_OK) {
- return;
- }
- if (buffers.size() != 1u) {
- err = C2_CORRUPTED;
- return;
- }
- info.stride = stride;
- buffer = buffers[0];
- }).isOk()) {
- ALOGE("failed transaction: allocate");
- return C2_CORRUPTED;
- }
- if (err != C2_OK) {
- return err;
- }
- allocation->reset(new C2AllocationGralloc(
- info, mMapper3, buffer,
- C2HandleGralloc::WrapAndMoveNativeHandle(
- buffer.getNativeHandle(),
- width, height,
- format, grallocUsage, info.stride,
- 0, 0, mBufferQueue ? ~0 : 0),
- mTraits->id));
- return C2_OK;
+ status_t err = GraphicBufferAllocator::get().allocateRawHandle(width, height, format,
+ 1u /* layer count */, grallocUsage, &buffer, &stride, "C2GrallocAllocation");
+ if (err) {
+ ALOGE("failed transaction: allocate");
+ return C2_CORRUPTED;
}
+
+ hidl_handle hidlHandle;
+ hidlHandle.setTo(const_cast<native_handle_t*>(buffer), true);
+
+ allocation->reset(new C2AllocationGralloc(
+ width, height, format, 1u /* layer count */, grallocUsage, stride, hidlHandle,
+ C2HandleGralloc::WrapAndMoveNativeHandle(
+ hidlHandle, width, height,
+ format, grallocUsage, stride,
+ 0, 0, mBufferQueue ? ~0 : 0),
+ mTraits->id));
+ return C2_OK;
}
c2_status_t C2AllocatorGralloc::Impl::priorGraphicAllocation(
const C2Handle *handle,
std::shared_ptr<C2GraphicAllocation> *allocation) {
- if (mMapper2) {
- BufferDescriptorInfo2 info;
- info.mapperInfo.layerCount = 1u;
- uint32_t generation;
- uint64_t igbp_id;
- uint32_t igbp_slot;
- const C2HandleGralloc *grallocHandle = C2HandleGralloc::Import(
- handle,
- &info.mapperInfo.width, &info.mapperInfo.height,
- (uint32_t *)&info.mapperInfo.format,
- (uint64_t *)&info.mapperInfo.usage,
- &info.stride,
- &generation, &igbp_id, &igbp_slot);
- if (grallocHandle == nullptr) {
- return C2_BAD_VALUE;
- }
- hidl_handle hidlHandle;
- hidlHandle.setTo(C2HandleGralloc::UnwrapNativeHandle(grallocHandle), true);
+ uint32_t generation;
+ uint64_t igbp_id;
+ uint32_t igbp_slot;
- allocation->reset(new C2AllocationGralloc(
- info, mMapper2, hidlHandle, grallocHandle, mTraits->id));
- return C2_OK;
- } else {
- BufferDescriptorInfo3 info;
- info.mapperInfo.layerCount = 1u;
- uint32_t generation;
- uint64_t igbp_id;
- uint32_t igbp_slot;
- const C2HandleGralloc *grallocHandle = C2HandleGralloc::Import(
- handle,
- &info.mapperInfo.width, &info.mapperInfo.height,
- (uint32_t *)&info.mapperInfo.format,
- (uint64_t *)&info.mapperInfo.usage,
- &info.stride,
- &generation, &igbp_id, &igbp_slot);
- if (grallocHandle == nullptr) {
- return C2_BAD_VALUE;
- }
+ uint32_t width;
+ uint32_t height;
+ uint32_t format;
+ uint32_t layerCount = 1;
+ uint64_t grallocUsage;
+ uint32_t stride;
- hidl_handle hidlHandle;
- hidlHandle.setTo(C2HandleGralloc::UnwrapNativeHandle(grallocHandle), true);
-
- allocation->reset(new C2AllocationGralloc(
- info, mMapper3, hidlHandle, grallocHandle, mTraits->id));
- return C2_OK;
+ const C2HandleGralloc *grallocHandle = C2HandleGralloc::Import(
+ handle, &width, &height, &format, &grallocUsage, &stride,
+ &generation, &igbp_id, &igbp_slot);
+ if (grallocHandle == nullptr) {
+ return C2_BAD_VALUE;
}
+
+ hidl_handle hidlHandle;
+ hidlHandle.setTo(C2HandleGralloc::UnwrapNativeHandle(grallocHandle), true);
+
+ allocation->reset(new C2AllocationGralloc(
+ width, height, format, layerCount,
+ grallocUsage, stride, hidlHandle, grallocHandle, mTraits->id));
+ return C2_OK;
}
C2AllocatorGralloc::C2AllocatorGralloc(id_t id, bool bufferQueue)
diff --git a/media/codec2/vndk/C2AllocatorIon.cpp b/media/codec2/vndk/C2AllocatorIon.cpp
index 752bc46..6d27a02 100644
--- a/media/codec2/vndk/C2AllocatorIon.cpp
+++ b/media/codec2/vndk/C2AllocatorIon.cpp
@@ -28,6 +28,7 @@
#include <C2Buffer.h>
#include <C2Debug.h>
#include <C2ErrnoUtils.h>
+#include <C2HandleIonInternal.h>
namespace android {
@@ -64,43 +65,6 @@
* This handle will not capture mapped fd-s as updating that would require a global mutex.
*/
-struct C2HandleIon : public C2Handle {
- // ion handle owns ionFd(!) and bufferFd
- C2HandleIon(int bufferFd, size_t size)
- : C2Handle(cHeader),
- mFds{ bufferFd },
- mInts{ int(size & 0xFFFFFFFF), int((uint64_t(size) >> 32) & 0xFFFFFFFF), kMagic } { }
-
- static bool isValid(const C2Handle * const o);
-
- int bufferFd() const { return mFds.mBuffer; }
- size_t size() const {
- return size_t(unsigned(mInts.mSizeLo))
- | size_t(uint64_t(unsigned(mInts.mSizeHi)) << 32);
- }
-
-protected:
- struct {
- int mBuffer; // shared ion buffer
- } mFds;
- struct {
- int mSizeLo; // low 32-bits of size
- int mSizeHi; // high 32-bits of size
- int mMagic;
- } mInts;
-
-private:
- typedef C2HandleIon _type;
- enum {
- kMagic = '\xc2io\x00',
- numFds = sizeof(mFds) / sizeof(int),
- numInts = sizeof(mInts) / sizeof(int),
- version = sizeof(C2Handle)
- };
- //constexpr static C2Handle cHeader = { version, numFds, numInts, {} };
- const static C2Handle cHeader;
-};
-
const C2Handle C2HandleIon::cHeader = {
C2HandleIon::version,
C2HandleIon::numFds,
@@ -262,7 +226,7 @@
*fence = C2Fence(); // not using fences
}
(void)mMappings.erase(it);
- ALOGV("successfully unmapped: %d", mHandle.bufferFd());
+ ALOGV("successfully unmapped: addr=%p size=%zu fd=%d", addr, size, mHandle.bufferFd());
return C2_OK;
}
ALOGD("unmap failed to find specified map");
@@ -600,7 +564,7 @@
}
std::shared_ptr<C2AllocationIon> alloc
- = std::make_shared<C2AllocationIon>(dup(mIonFd), capacity, align, heapMask, flags, mTraits->id);
+ = std::make_shared<C2AllocationIon>(dup(mIonFd), capacity, align, heapMask, flags, getId());
ret = alloc->status();
if (ret == C2_OK) {
*allocation = alloc;
@@ -622,7 +586,7 @@
// TODO: get capacity and validate it
const C2HandleIon *h = static_cast<const C2HandleIon*>(handle);
std::shared_ptr<C2AllocationIon> alloc
- = std::make_shared<C2AllocationIon>(dup(mIonFd), h->size(), h->bufferFd(), mTraits->id);
+ = std::make_shared<C2AllocationIon>(dup(mIonFd), h->size(), h->bufferFd(), getId());
c2_status_t ret = alloc->status();
if (ret == C2_OK) {
*allocation = alloc;
diff --git a/media/codec2/vndk/C2Buffer.cpp b/media/codec2/vndk/C2Buffer.cpp
index 2d99b53..0b08f31 100644
--- a/media/codec2/vndk/C2Buffer.cpp
+++ b/media/codec2/vndk/C2Buffer.cpp
@@ -22,14 +22,17 @@
#include <map>
#include <mutex>
-#include <C2AllocatorIon.h>
+#include <C2AllocatorBlob.h>
#include <C2AllocatorGralloc.h>
+#include <C2AllocatorIon.h>
#include <C2BufferPriv.h>
#include <C2BlockInternal.h>
+#include <C2PlatformSupport.h>
#include <bufferpool/ClientManager.h>
namespace {
+using android::C2AllocatorBlob;
using android::C2AllocatorGralloc;
using android::C2AllocatorIon;
using android::hardware::media::bufferpool::BufferPoolData;
@@ -393,10 +396,29 @@
std::shared_ptr<C2LinearBlock> _C2BlockFactory::CreateLinearBlock(
const C2Handle *handle) {
// TODO: get proper allocator? and mutex?
- static std::unique_ptr<C2AllocatorIon> sAllocator = std::make_unique<C2AllocatorIon>(0);
+ static std::unique_ptr<C2Allocator> sAllocator = []{
+ std::unique_ptr<C2Allocator> allocator;
+ if (android::GetPreferredLinearAllocatorId(android::GetCodec2PoolMask()) ==
+ android::C2PlatformAllocatorStore::BLOB) {
+ allocator = std::make_unique<C2AllocatorBlob>(android::C2PlatformAllocatorStore::BLOB);
+ } else {
+ allocator = std::make_unique<C2AllocatorIon>(android::C2PlatformAllocatorStore::ION);
+ }
+ return allocator;
+ }();
+
+ if (sAllocator == nullptr)
+ return nullptr;
+
+ bool isValidHandle = false;
+ if (sAllocator->getId() == android::C2PlatformAllocatorStore::BLOB) {
+ isValidHandle = C2AllocatorBlob::isValid(handle);
+ } else {
+ isValidHandle = C2AllocatorIon::isValid(handle);
+ }
std::shared_ptr<C2LinearAllocation> alloc;
- if (C2AllocatorIon::isValid(handle)) {
+ if (isValidHandle) {
c2_status_t err = sAllocator->priorLinearAllocation(handle, &alloc);
if (err == C2_OK) {
std::shared_ptr<C2LinearBlock> block = _C2BlockFactory::CreateLinearBlock(alloc);
@@ -409,10 +431,29 @@
std::shared_ptr<C2LinearBlock> _C2BlockFactory::CreateLinearBlock(
const C2Handle *cHandle, const std::shared_ptr<BufferPoolData> &data) {
// TODO: get proper allocator? and mutex?
- static std::unique_ptr<C2AllocatorIon> sAllocator = std::make_unique<C2AllocatorIon>(0);
+ static std::unique_ptr<C2Allocator> sAllocator = []{
+ std::unique_ptr<C2Allocator> allocator;
+ if (android::GetPreferredLinearAllocatorId(android::GetCodec2PoolMask()) ==
+ android::C2PlatformAllocatorStore::BLOB) {
+ allocator = std::make_unique<C2AllocatorBlob>(android::C2PlatformAllocatorStore::BLOB);
+ } else {
+ allocator = std::make_unique<C2AllocatorIon>(android::C2PlatformAllocatorStore::ION);
+ }
+ return allocator;
+ }();
+
+ if (sAllocator == nullptr)
+ return nullptr;
+
+ bool isValidHandle = false;
+ if (sAllocator->getId() == android::C2PlatformAllocatorStore::BLOB) {
+ isValidHandle = C2AllocatorBlob::isValid(cHandle);
+ } else {
+ isValidHandle = C2AllocatorIon::isValid(cHandle);
+ }
std::shared_ptr<C2LinearAllocation> alloc;
- if (C2AllocatorIon::isValid(cHandle)) {
+ if (isValidHandle) {
c2_status_t err = sAllocator->priorLinearAllocation(cHandle, &alloc);
const std::shared_ptr<C2PooledBlockPoolData> poolData =
std::make_shared<C2PooledBlockPoolData>(data);
diff --git a/media/codec2/vndk/C2Store.cpp b/media/codec2/vndk/C2Store.cpp
index 5b2bd7b..d16527e 100644
--- a/media/codec2/vndk/C2Store.cpp
+++ b/media/codec2/vndk/C2Store.cpp
@@ -18,6 +18,7 @@
#define LOG_NDEBUG 0
#include <utils/Log.h>
+#include <C2AllocatorBlob.h>
#include <C2AllocatorGralloc.h>
#include <C2AllocatorIon.h>
#include <C2BufferPriv.h>
@@ -26,6 +27,7 @@
#include <C2Config.h>
#include <C2PlatformStorePluginLoader.h>
#include <C2PlatformSupport.h>
+#include <cutils/properties.h>
#include <util/C2InterfaceHelper.h>
#include <dlfcn.h>
@@ -35,6 +37,10 @@
#include <memory>
#include <mutex>
+#ifdef __ANDROID_APEX__
+#include <android-base/properties.h>
+#endif
+
namespace android {
/**
@@ -71,6 +77,9 @@
~C2PlatformAllocatorStoreImpl() override = default;
private:
+ /// returns a shared-singleton blob allocator (gralloc-backed)
+ std::shared_ptr<C2Allocator> fetchBlobAllocator();
+
/// returns a shared-singleton ion allocator
std::shared_ptr<C2Allocator> fetchIonAllocator();
@@ -93,10 +102,12 @@
c2_status_t C2PlatformAllocatorStoreImpl::fetchAllocator(
id_t id, std::shared_ptr<C2Allocator> *const allocator) {
allocator->reset();
+ if (id == C2AllocatorStore::DEFAULT_LINEAR) {
+ id = GetPreferredLinearAllocatorId(GetCodec2PoolMask());
+ }
switch (id) {
// TODO: should we implement a generic registry for all, and use that?
case C2PlatformAllocatorStore::ION:
- case C2AllocatorStore::DEFAULT_LINEAR:
*allocator = fetchIonAllocator();
break;
@@ -109,6 +120,10 @@
*allocator = fetchBufferQueueAllocator();
break;
+ case C2PlatformAllocatorStore::BLOB:
+ *allocator = fetchBlobAllocator();
+ break;
+
default:
// Try to create allocator from platform store plugins.
c2_status_t res =
@@ -218,6 +233,18 @@
return allocator;
}
+std::shared_ptr<C2Allocator> C2PlatformAllocatorStoreImpl::fetchBlobAllocator() {
+ static std::mutex mutex;
+ static std::weak_ptr<C2Allocator> blobAllocator;
+ std::lock_guard<std::mutex> lock(mutex);
+ std::shared_ptr<C2Allocator> allocator = blobAllocator.lock();
+ if (allocator == nullptr) {
+ allocator = std::make_shared<C2AllocatorBlob>(C2PlatformAllocatorStore::BLOB);
+ blobAllocator = allocator;
+ }
+ return allocator;
+}
+
std::shared_ptr<C2Allocator> C2PlatformAllocatorStoreImpl::fetchGrallocAllocator() {
static std::mutex mutex;
static std::weak_ptr<C2Allocator> grallocAllocator;
@@ -288,6 +315,18 @@
return gPreferredComponentStore ? gPreferredComponentStore : GetCodec2PlatformComponentStore();
}
+int GetCodec2PoolMask() {
+ return property_get_int32(
+ "debug.stagefright.c2-poolmask",
+ 1 << C2PlatformAllocatorStore::ION |
+ 1 << C2PlatformAllocatorStore::BUFFERQUEUE);
+}
+
+C2PlatformAllocatorStore::id_t GetPreferredLinearAllocatorId(int poolMask) {
+ return ((poolMask >> C2PlatformAllocatorStore::BLOB) & 1) ? C2PlatformAllocatorStore::BLOB
+ : C2PlatformAllocatorStore::ION;
+}
+
namespace {
class _C2BlockPoolCache {
@@ -304,11 +343,25 @@
std::shared_ptr<C2Allocator> allocator;
c2_status_t res = C2_NOT_FOUND;
+ if (allocatorId == C2AllocatorStore::DEFAULT_LINEAR) {
+ allocatorId = GetPreferredLinearAllocatorId(GetCodec2PoolMask());
+ }
switch(allocatorId) {
case C2PlatformAllocatorStore::ION:
- case C2AllocatorStore::DEFAULT_LINEAR:
res = allocatorStore->fetchAllocator(
- C2AllocatorStore::DEFAULT_LINEAR, &allocator);
+ C2PlatformAllocatorStore::ION, &allocator);
+ if (res == C2_OK) {
+ std::shared_ptr<C2BlockPool> ptr =
+ std::make_shared<C2PooledBlockPool>(
+ allocator, poolId);
+ *pool = ptr;
+ mBlockPools[poolId] = ptr;
+ mComponents[poolId] = component;
+ }
+ break;
+ case C2PlatformAllocatorStore::BLOB:
+ res = allocatorStore->fetchAllocator(
+ C2PlatformAllocatorStore::BLOB, &allocator);
if (res == C2_OK) {
std::shared_ptr<C2BlockPool> ptr =
std::make_shared<C2PooledBlockPool>(
@@ -599,9 +652,33 @@
struct Setter {
static C2R setIonUsage(bool /* mayBlock */, C2P<C2StoreIonUsageInfo> &me) {
+#ifdef __ANDROID_APEX__
+ static int32_t defaultHeapMask = [] {
+ int32_t heapmask = base::GetIntProperty(
+ "ro.com.android.media.swcodec.ion.heapmask", int32_t(0xFFFFFFFF));
+ ALOGD("Default ION heapmask = %d", heapmask);
+ return heapmask;
+ }();
+ static int32_t defaultFlags = [] {
+ int32_t flags = base::GetIntProperty(
+ "ro.com.android.media.swcodec.ion.flags", 0);
+ ALOGD("Default ION flags = %d", flags);
+ return flags;
+ }();
+ static uint32_t defaultAlign = [] {
+ uint32_t align = base::GetUintProperty(
+ "ro.com.android.media.swcodec.ion.align", 0u);
+ ALOGD("Default ION align = %d", align);
+ return align;
+ }();
+ me.set().heapMask = defaultHeapMask;
+ me.set().allocFlags = defaultFlags;
+ me.set().minAlignment = defaultAlign;
+#else
me.set().heapMask = ~0;
me.set().allocFlags = 0;
me.set().minAlignment = 0;
+#endif
return C2R::Ok();
}
};
diff --git a/media/codec2/vndk/include/C2AllocatorBlob.h b/media/codec2/vndk/include/C2AllocatorBlob.h
new file mode 100644
index 0000000..89ce949
--- /dev/null
+++ b/media/codec2/vndk/include/C2AllocatorBlob.h
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+#ifndef STAGEFRIGHT_CODEC2_ALLOCATOR_BLOB_H_
+#define STAGEFRIGHT_CODEC2_ALLOCATOR_BLOB_H_
+
+#include <functional>
+
+#include <C2AllocatorGralloc.h>
+#include <C2Buffer.h>
+
+namespace android {
+
+class C2AllocatorBlob : public C2Allocator {
+public:
+ virtual id_t getId() const override;
+
+ virtual C2String getName() const override;
+
+ virtual std::shared_ptr<const Traits> getTraits() const override;
+
+ virtual c2_status_t newLinearAllocation(
+ uint32_t capacity, C2MemoryUsage usage,
+ std::shared_ptr<C2LinearAllocation> *allocation) override;
+
+ virtual c2_status_t priorLinearAllocation(
+ const C2Handle *handle,
+ std::shared_ptr<C2LinearAllocation> *allocation) override;
+
+ C2AllocatorBlob(id_t id);
+
+ virtual ~C2AllocatorBlob() override;
+
+ static bool isValid(const C2Handle* const o);
+
+private:
+ std::shared_ptr<const Traits> mTraits;
+ // Design as C2AllocatorGralloc-backed to unify Gralloc implementations.
+ std::shared_ptr<C2Allocator> mC2AllocatorGralloc;
+};
+
+} // namespace android
+
+#endif // STAGEFRIGHT_CODEC2_ALLOCATOR_BLOB_H_
diff --git a/media/codec2/vndk/include/C2PlatformSupport.h b/media/codec2/vndk/include/C2PlatformSupport.h
index f31282c..a14e0d3 100644
--- a/media/codec2/vndk/include/C2PlatformSupport.h
+++ b/media/codec2/vndk/include/C2PlatformSupport.h
@@ -66,6 +66,15 @@
BUFFERQUEUE,
/**
+ * ID of the gralloc backed platform allocator for linear blob buffer.
+ *
+ * C2Handle layout is not public. Use C2AllocatorGralloc::UnwrapNativeCodec2GrallocHandle
+ * to get the underlying gralloc handle from a C2Handle, and WrapNativeCodec2GrallocHandle
+ * to create a C2Handle from a gralloc handle - for C2Allocator::priorAllocation.
+ */
+ BLOB,
+
+ /**
* ID of indicating the end of platform allocator definition.
*
* \note always put this macro in the last place.
@@ -131,6 +140,20 @@
*/
void SetPreferredCodec2ComponentStore(std::shared_ptr<C2ComponentStore> store);
+/**
+ * Returns the pool mask.
+ * \retval the default pool mask should be adopted if it could not be obtained from property
+ * "debug.stagefright.c2-poolmask"
+ */
+int GetCodec2PoolMask();
+
+/**
+ * Returns the preferred linear buffer allocator id from param poolMask.
+ * C2PlatformAllocatorStore::ION should be chosen as fallback allocator if BLOB is not enabled from
+ * param poolMask.
+ */
+C2PlatformAllocatorStore::id_t GetPreferredLinearAllocatorId(int poolMask);
+
} // namespace android
#endif // STAGEFRIGHT_CODEC2_PLATFORM_SUPPORT_H_
diff --git a/media/codec2/vndk/internal/C2HandleIonInternal.h b/media/codec2/vndk/internal/C2HandleIonInternal.h
new file mode 100644
index 0000000..c0e1d83
--- /dev/null
+++ b/media/codec2/vndk/internal/C2HandleIonInternal.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STAGEFRIGHT_CODEC2_ALLOCATION_ION_H_
+#define STAGEFRIGHT_CODEC2_ALLOCATION_ION_H_
+
+#include <C2Buffer.h>
+
+namespace android {
+
+struct C2HandleIon : public C2Handle {
+ // ion handle owns ionFd(!) and bufferFd
+ C2HandleIon(int bufferFd, size_t size)
+ : C2Handle(cHeader),
+ mFds{ bufferFd },
+ mInts{ int(size & 0xFFFFFFFF), int((uint64_t(size) >> 32) & 0xFFFFFFFF), kMagic } { }
+
+ static bool isValid(const C2Handle * const o);
+
+ int bufferFd() const { return mFds.mBuffer; }
+ size_t size() const {
+ return size_t(unsigned(mInts.mSizeLo))
+ | size_t(uint64_t(unsigned(mInts.mSizeHi)) << 32);
+ }
+
+protected:
+ struct {
+ int mBuffer; // shared ion buffer
+ } mFds;
+ struct {
+ int mSizeLo; // low 32-bits of size
+ int mSizeHi; // high 32-bits of size
+ int mMagic;
+ } mInts;
+
+private:
+ typedef C2HandleIon _type;
+ enum {
+ kMagic = '\xc2io\x00',
+ numFds = sizeof(mFds) / sizeof(int),
+ numInts = sizeof(mInts) / sizeof(int),
+ version = sizeof(C2Handle)
+ };
+ //constexpr static C2Handle cHeader = { version, numFds, numInts, {} };
+ const static C2Handle cHeader;
+};
+} // namespace android
+
+#endif // STAGEFRIGHT_CODEC2_ALLOCATION_ION_H_
diff --git a/media/codec2/vndk/platform/C2BqBuffer.cpp b/media/codec2/vndk/platform/C2BqBuffer.cpp
index 8304f74..62936f6 100644
--- a/media/codec2/vndk/platform/C2BqBuffer.cpp
+++ b/media/codec2/vndk/platform/C2BqBuffer.cpp
@@ -576,10 +576,11 @@
}
}
int migrated = 0;
+ // poolDatas dtor should not be called during lock is held.
+ std::shared_ptr<C2BufferQueueBlockPoolData>
+ poolDatas[NUM_BUFFER_SLOTS];
{
sp<GraphicBuffer> buffers[NUM_BUFFER_SLOTS];
- std::weak_ptr<C2BufferQueueBlockPoolData>
- poolDatas[NUM_BUFFER_SLOTS];
std::scoped_lock<std::mutex> lock(mMutex);
bool noInit = false;
for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
diff --git a/media/extractors/Android.bp b/media/extractors/Android.bp
new file mode 100644
index 0000000..bb42580
--- /dev/null
+++ b/media/extractors/Android.bp
@@ -0,0 +1,46 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_defaults {
+ name: "extractor-defaults",
+
+ include_dirs: [
+ "frameworks/av/media/libstagefright/include",
+ ],
+
+ shared_libs: [
+ "liblog",
+ "libmediandk#29",
+ ],
+
+ relative_install_path: "extractors",
+
+ compile_multilib: "first",
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ "-fvisibility=hidden",
+ ],
+
+ version_script: "exports.lds",
+
+ sanitize: {
+ cfi: true,
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ },
+}
\ No newline at end of file
diff --git a/media/extractors/aac/AACExtractor.cpp b/media/extractors/aac/AACExtractor.cpp
index 9d183d4..8f60f6b 100644
--- a/media/extractors/aac/AACExtractor.cpp
+++ b/media/extractors/aac/AACExtractor.cpp
@@ -132,6 +132,7 @@
AACExtractor::AACExtractor(
DataSourceHelper *source, off64_t offset)
: mDataSource(source),
+ mMeta(nullptr),
mInitCheck(NO_INIT),
mFrameDurationUs(0) {
@@ -180,7 +181,11 @@
}
AACExtractor::~AACExtractor() {
- AMediaFormat_delete(mMeta);
+ mOffsetVector.clear();
+ delete mDataSource;
+ if (mMeta != nullptr) {
+ AMediaFormat_delete(mMeta);
+ }
}
media_status_t AACExtractor::getMetaData(AMediaFormat *meta) {
diff --git a/media/extractors/aac/Android.bp b/media/extractors/aac/Android.bp
index a58167a..60d3ae1 100644
--- a/media/extractors/aac/Android.bp
+++ b/media/extractors/aac/Android.bp
@@ -1,40 +1,13 @@
-cc_library_shared {
+cc_library {
+ name: "libaacextractor",
+ defaults: ["extractor-defaults"],
srcs: ["AACExtractor.cpp"],
- include_dirs: [
- "frameworks/av/media/libstagefright/",
- ],
-
- shared_libs: [
- "liblog",
- "libmediandk",
- ],
-
static_libs: [
"libstagefright_foundation",
"libstagefright_metadatautils",
"libutils",
],
- name: "libaacextractor",
- relative_install_path: "extractors",
-
- compile_multilib: "first",
-
- cflags: [
- "-Werror",
- "-Wall",
- "-fvisibility=hidden",
- ],
- version_script: "exports.lds",
-
- sanitize: {
- cfi: true,
- misc_undefined: [
- "unsigned-integer-overflow",
- "signed-integer-overflow",
- ],
- },
-
}
diff --git a/media/extractors/amr/AMRExtractor.cpp b/media/extractors/amr/AMRExtractor.cpp
index ffeff42..26431a4 100644
--- a/media/extractors/amr/AMRExtractor.cpp
+++ b/media/extractors/amr/AMRExtractor.cpp
@@ -144,6 +144,7 @@
AMRExtractor::AMRExtractor(DataSourceHelper *source)
: mDataSource(source),
+ mMeta(NULL),
mInitCheck(NO_INIT),
mOffsetTableLength(0) {
float confidence;
@@ -191,7 +192,9 @@
AMRExtractor::~AMRExtractor() {
delete mDataSource;
- AMediaFormat_delete(mMeta);
+ if (mMeta) {
+ AMediaFormat_delete(mMeta);
+ }
}
media_status_t AMRExtractor::getMetaData(AMediaFormat *meta) {
diff --git a/media/extractors/amr/Android.bp b/media/extractors/amr/Android.bp
index 4bd933d..49c9567 100644
--- a/media/extractors/amr/Android.bp
+++ b/media/extractors/amr/Android.bp
@@ -1,38 +1,11 @@
-cc_library_shared {
+cc_library {
+ name: "libamrextractor",
+ defaults: ["extractor-defaults"],
srcs: ["AMRExtractor.cpp"],
- include_dirs: [
- "frameworks/av/media/libstagefright/include",
- ],
-
- shared_libs: [
- "liblog",
- "libmediandk",
- ],
-
static_libs: [
"libstagefright_foundation",
],
- name: "libamrextractor",
- relative_install_path: "extractors",
-
- compile_multilib: "first",
-
- cflags: [
- "-Werror",
- "-Wall",
- "-fvisibility=hidden",
- ],
- version_script: "exports.lds",
-
- sanitize: {
- cfi: true,
- misc_undefined: [
- "unsigned-integer-overflow",
- "signed-integer-overflow",
- ],
- },
-
}
diff --git a/media/extractors/flac/Android.bp b/media/extractors/flac/Android.bp
index 3a3d051..3675611 100644
--- a/media/extractors/flac/Android.bp
+++ b/media/extractors/flac/Android.bp
@@ -1,16 +1,15 @@
-cc_library_shared {
+cc_library {
+ name: "libflacextractor",
+ defaults: ["extractor-defaults"],
srcs: ["FLACExtractor.cpp"],
include_dirs: [
- "frameworks/av/media/libstagefright/include",
"external/flac/include",
],
shared_libs: [
"libbinder_ndk",
- "liblog",
- "libmediandk",
],
static_libs: [
@@ -21,24 +20,4 @@
"libutils",
],
- name: "libflacextractor",
- relative_install_path: "extractors",
-
- compile_multilib: "first",
-
- cflags: [
- "-Werror",
- "-Wall",
- "-fvisibility=hidden",
- ],
- version_script: "exports.lds",
-
- sanitize: {
- cfi: true,
- misc_undefined: [
- "unsigned-integer-overflow",
- "signed-integer-overflow",
- ],
- },
-
}
diff --git a/media/extractors/flac/FLACExtractor.h b/media/extractors/flac/FLACExtractor.h
index 5a73d20..223d359 100644
--- a/media/extractors/flac/FLACExtractor.h
+++ b/media/extractors/flac/FLACExtractor.h
@@ -17,7 +17,6 @@
#ifndef FLAC_EXTRACTOR_H_
#define FLAC_EXTRACTOR_H_
-#include <media/DataSourceBase.h>
#include <media/MediaExtractorPluginApi.h>
#include <media/MediaExtractorPluginHelper.h>
#include <media/NdkMediaFormat.h>
diff --git a/media/extractors/midi/Android.bp b/media/extractors/midi/Android.bp
index 7d42e70..bdb724b 100644
--- a/media/extractors/midi/Android.bp
+++ b/media/extractors/midi/Android.bp
@@ -1,39 +1,21 @@
-cc_library_shared {
+cc_library {
+ name: "libmidiextractor",
+ defaults: ["extractor-defaults"],
srcs: ["MidiExtractor.cpp"],
- include_dirs: [
- "frameworks/av/media/libstagefright/include",
- ],
-
- shared_libs: [
- "liblog",
- "libmediandk",
+ header_libs: [
+ "libmedia_headers",
],
static_libs: [
"libmedia_midiiowrapper",
"libsonivox",
- "libstagefright_foundation"
+ "libstagefright_foundation",
+ "libwatchdog",
],
- name: "libmidiextractor",
- relative_install_path: "extractors",
- compile_multilib: "first",
-
- cflags: [
- "-Werror",
- "-Wall",
- "-fvisibility=hidden",
+ shared_libs: [
+ "libbase",
],
- version_script: "exports.lds",
-
- sanitize: {
- cfi: true,
- misc_undefined: [
- "unsigned-integer-overflow",
- "signed-integer-overflow",
- ],
- },
-
}
diff --git a/media/extractors/midi/MidiExtractor.cpp b/media/extractors/midi/MidiExtractor.cpp
index 9f4f9e6..d0efb2f 100644
--- a/media/extractors/midi/MidiExtractor.cpp
+++ b/media/extractors/midi/MidiExtractor.cpp
@@ -26,6 +26,7 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <libsonivox/eas_reverb.h>
+#include <watchdog/Watchdog.h>
namespace android {
@@ -116,6 +117,7 @@
MediaBufferHelper **outBuffer, const ReadOptions *options)
{
ALOGV("MidiSource::read");
+
MediaBufferHelper *buffer;
// process an optional seek request
int64_t seekTimeUs;
@@ -139,6 +141,8 @@
}
// MidiEngine
+using namespace std::chrono_literals;
+static constexpr auto kTimeout = 10s;
MidiEngine::MidiEngine(CDataSource *dataSource,
AMediaFormat *fileMetadata,
@@ -147,6 +151,8 @@
mEasHandle(NULL),
mEasConfig(NULL),
mIsInitialized(false) {
+ Watchdog watchdog(kTimeout);
+
mIoWrapper = new MidiIoWrapper(dataSource);
// spin up a new EAS engine
EAS_I32 temp;
@@ -186,6 +192,8 @@
}
MidiEngine::~MidiEngine() {
+ Watchdog watchdog(kTimeout);
+
if (mEasHandle) {
EAS_CloseFile(mEasData, mEasHandle);
}
@@ -217,12 +225,16 @@
}
status_t MidiEngine::seekTo(int64_t positionUs) {
+ Watchdog watchdog(kTimeout);
+
ALOGV("seekTo %lld", (long long)positionUs);
EAS_RESULT result = EAS_Locate(mEasData, mEasHandle, positionUs / 1000, false);
return result == EAS_SUCCESS ? OK : UNKNOWN_ERROR;
}
MediaBufferHelper* MidiEngine::readBuffer() {
+ Watchdog watchdog(kTimeout);
+
EAS_STATE state;
EAS_State(mEasData, mEasHandle, &state);
if ((state == EAS_STATE_STOPPED) || (state == EAS_STATE_ERROR)) {
diff --git a/media/extractors/midi/MidiExtractor.h b/media/extractors/midi/MidiExtractor.h
index 2e78086..b486fc6 100644
--- a/media/extractors/midi/MidiExtractor.h
+++ b/media/extractors/midi/MidiExtractor.h
@@ -17,7 +17,6 @@
#ifndef MIDI_EXTRACTOR_H_
#define MIDI_EXTRACTOR_H_
-#include <media/DataSourceBase.h>
#include <media/MediaExtractorPluginApi.h>
#include <media/MediaExtractorPluginHelper.h>
#include <media/stagefright/MediaBufferBase.h>
diff --git a/media/extractors/mkv/Android.bp b/media/extractors/mkv/Android.bp
index 1744d3d..7ad8cc1 100644
--- a/media/extractors/mkv/Android.bp
+++ b/media/extractors/mkv/Android.bp
@@ -1,4 +1,6 @@
-cc_library_shared {
+cc_library {
+ name: "libmkvextractor",
+ defaults: ["extractor-defaults"],
srcs: ["MatroskaExtractor.cpp"],
@@ -6,40 +8,17 @@
"external/flac/include",
"external/libvpx/libwebm",
"frameworks/av/media/libstagefright/flac/dec",
- "frameworks/av/media/libstagefright/include",
],
shared_libs: [
- "liblog",
- "libmediandk",
+ "libstagefright_flacdec",
],
static_libs: [
- "libstagefright_flacdec",
"libstagefright_foundation",
"libstagefright_metadatautils",
"libwebm",
"libutils",
],
- name: "libmkvextractor",
- relative_install_path: "extractors",
-
- compile_multilib: "first",
-
- cflags: [
- "-Werror",
- "-Wall",
- "-fvisibility=hidden",
- ],
- version_script: "exports.lds",
-
- sanitize: {
- cfi: true,
- misc_undefined: [
- "unsigned-integer-overflow",
- "signed-integer-overflow",
- ],
- },
-
}
diff --git a/media/extractors/mkv/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp
index 23022e4..044c4d0 100644
--- a/media/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/extractors/mkv/MatroskaExtractor.cpp
@@ -22,7 +22,7 @@
#include "MatroskaExtractor.h"
#include "common/webmids.h"
-#include <media/DataSourceBase.h>
+#include <media/stagefright/DataSourceBase.h>
#include <media/ExtractorUtils.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AUtils.h>
diff --git a/media/extractors/mp3/Android.bp b/media/extractors/mp3/Android.bp
index 4e2f248..102ac81 100644
--- a/media/extractors/mp3/Android.bp
+++ b/media/extractors/mp3/Android.bp
@@ -1,44 +1,16 @@
-cc_library_shared {
-
+cc_library {
+ name: "libmp3extractor",
+ defaults: ["extractor-defaults"],
srcs: [
"MP3Extractor.cpp",
"VBRISeeker.cpp",
"XINGSeeker.cpp",
],
- include_dirs: [
- "frameworks/av/media/libstagefright/include",
- ],
-
- shared_libs: [
- "liblog",
- "libmediandk",
- ],
-
static_libs: [
"libutils",
"libstagefright_id3",
"libstagefright_foundation",
],
- name: "libmp3extractor",
- relative_install_path: "extractors",
-
- compile_multilib: "first",
-
- cflags: [
- "-Werror",
- "-Wall",
- "-fvisibility=hidden",
- ],
- version_script: "exports.lds",
-
- sanitize: {
- cfi: true,
- misc_undefined: [
- "unsigned-integer-overflow",
- "signed-integer-overflow",
- ],
- },
-
}
diff --git a/media/extractors/mp4/AC4Parser.cpp b/media/extractors/mp4/AC4Parser.cpp
index 13d60c8..25fc4cd 100644
--- a/media/extractors/mp4/AC4Parser.cpp
+++ b/media/extractors/mp4/AC4Parser.cpp
@@ -600,6 +600,10 @@
if (ac4_dsi_version == 1) {
uint64_t end = (mDSISize - mBitReader.numBitsLeft()) / 8;
uint64_t presentation_bytes = end - start;
+ if (pres_bytes < presentation_bytes) {
+ ALOGE("pres_bytes is smaller than presentation_bytes.");
+ return false;
+ }
uint64_t skip_bytes = pres_bytes - presentation_bytes;
ALOGV("skipping = %" PRIu64 " bytes", skip_bytes);
CHECK_BITS_LEFT(skip_bytes * 8);
diff --git a/media/extractors/mp4/Android.bp b/media/extractors/mp4/Android.bp
index 1b308aa..e48e1b7 100644
--- a/media/extractors/mp4/Android.bp
+++ b/media/extractors/mp4/Android.bp
@@ -1,5 +1,6 @@
-cc_defaults {
- name: "libmp4extractor_defaults",
+cc_library {
+ name: "libmp4extractor",
+ defaults: ["extractor-defaults"],
srcs: [
"AC4Parser.cpp",
@@ -9,50 +10,10 @@
"SampleTable.cpp",
],
- include_dirs: [
- "frameworks/av/media/libstagefright/",
- ],
-
- shared_libs: [
- "liblog",
- "libmediandk"
- ],
-
static_libs: [
"libstagefright_esds",
"libstagefright_foundation",
"libstagefright_id3",
"libutils",
],
-
- cflags: [
- "-Werror",
- "-Wall",
- "-fvisibility=hidden",
- ],
- version_script: "exports.lds",
- relative_install_path: "extractors",
- compile_multilib: "first",
-}
-
-cc_library_shared {
-
-
- name: "libmp4extractor",
- defaults: ["libmp4extractor_defaults"],
-
- sanitize: {
- cfi: true,
- misc_undefined: [
- "unsigned-integer-overflow",
- "signed-integer-overflow",
- ],
- },
-
-}
-
-cc_library_static {
- name: "libmp4extractor_fuzzing",
-
- defaults: ["libmp4extractor_defaults"],
}
diff --git a/media/extractors/mp4/ItemTable.cpp b/media/extractors/mp4/ItemTable.cpp
index 8c8e6d1..0773387 100644
--- a/media/extractors/mp4/ItemTable.cpp
+++ b/media/extractors/mp4/ItemTable.cpp
@@ -700,8 +700,8 @@
}
private:
- uint32_t mWidth;
- uint32_t mHeight;
+ int32_t mWidth;
+ int32_t mHeight;
};
status_t IspeBox::parse(off64_t offset, size_t size) {
@@ -715,12 +715,19 @@
if (size < 8) {
return ERROR_MALFORMED;
}
- if (!source()->getUInt32(offset, &mWidth)
- || !source()->getUInt32(offset + 4, &mHeight)) {
+ if (!source()->getUInt32(offset, (uint32_t *)&mWidth)
+ || !source()->getUInt32(offset + 4, (uint32_t *)&mHeight)) {
return ERROR_IO;
}
- ALOGV("property ispe: %dx%d", mWidth, mHeight);
+ // Validate that the dimension doesn't cause overflow on calculated max input size.
+ // Max input size is width*height*1.5, restrict width*height to 1<<29 so that
+ // we don't need to cast to int64_t when doing mults.
+ if (mWidth <= 0 || mHeight <= 0 || mWidth > (1 << 29) / mHeight) {
+ return ERROR_MALFORMED;
+ }
+
+ ALOGV("property ispe: %dx%d", mWidth, mHeight);
return OK;
}
@@ -1524,8 +1531,9 @@
default: break; // don't set if invalid
}
}
+ // we validated no overflow in IspeBox::parse()
AMediaFormat_setInt32(meta,
- AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, image->width * image->height * 1.5);
+ AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, image->width * image->height * 3 / 2);
if (!image->thumbnails.empty()) {
ssize_t thumbItemIndex = mItemIdToItemMap.indexOfKey(image->thumbnails[0]);
@@ -1561,8 +1569,9 @@
AMEDIAFORMAT_KEY_TILE_WIDTH, image->width);
AMediaFormat_setInt32(meta,
AMEDIAFORMAT_KEY_TILE_HEIGHT, image->height);
+ // we validated no overflow in IspeBox::parse()
AMediaFormat_setInt32(meta,
- AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, image->width * image->height * 1.5);
+ AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, image->width * image->height * 3 / 2);
}
if (image->hvcc == NULL) {
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 14fe0dc..ce82861 100755
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -31,9 +31,10 @@
#include "MPEG4Extractor.h"
#include "SampleTable.h"
#include "ItemTable.h"
-#include "include/ESDS.h"
-#include <media/DataSourceBase.h>
+#include <ESDS.h>
+#include <ID3.h>
+#include <media/stagefright/DataSourceBase.h>
#include <media/ExtractorUtils.h>
#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ABuffer.h>
@@ -52,7 +53,6 @@
#include <utils/String8.h>
#include <byteswap.h>
-#include "include/ID3.h"
#ifndef UINT32_MAX
#define UINT32_MAX (4294967295U)
@@ -83,7 +83,8 @@
const Trex *trex,
off64_t firstMoofOffset,
const sp<ItemTable> &itemTable,
- uint64_t elstShiftStartTicks);
+ uint64_t elstShiftStartTicks,
+ uint64_t elstInitialEmptyEditTicks);
virtual status_t init();
virtual media_status_t start();
@@ -133,6 +134,7 @@
bool mIsAVC;
bool mIsHEVC;
+ bool mIsDolbyVision;
bool mIsAC4;
bool mIsPcm;
size_t mNALLengthSize;
@@ -150,6 +152,7 @@
// Start offset from composition time to presentation time.
// Support shift only for video tracks through mElstShiftStartTicks for now.
uint64_t mElstShiftStartTicks;
+ uint64_t mElstInitialEmptyEditTicks;
size_t parseNALSize(const uint8_t *data) const;
status_t parseChunk(off64_t *offset);
@@ -337,6 +340,14 @@
case FOURCC("hvc1"):
case FOURCC("hev1"):
return MEDIA_MIMETYPE_VIDEO_HEVC;
+
+ case FOURCC("dvav"):
+ case FOURCC("dva1"):
+ case FOURCC("dvhe"):
+ case FOURCC("dvh1"):
+ case FOURCC("dav1"):
+ return MEDIA_MIMETYPE_VIDEO_DOLBY_VISION;
+
case FOURCC("ac-4"):
return MEDIA_MIMETYPE_AUDIO_AC4;
case FOURCC("Opus"):
@@ -475,12 +486,11 @@
int64_t duration;
int32_t samplerate;
// Only for audio track.
- if (track->has_elst && mHeaderTimescale != 0 &&
- AMediaFormat_getInt64(track->meta, AMEDIAFORMAT_KEY_DURATION, &duration) &&
- AMediaFormat_getInt32(track->meta, AMEDIAFORMAT_KEY_SAMPLE_RATE, &samplerate)) {
-
+ if (track->elst_needs_processing && mHeaderTimescale != 0 &&
+ AMediaFormat_getInt64(track->meta, AMEDIAFORMAT_KEY_DURATION, &duration) &&
+ AMediaFormat_getInt32(track->meta, AMEDIAFORMAT_KEY_SAMPLE_RATE, &samplerate)) {
// Elst has to be processed only the first time this function is called.
- track->has_elst = false;
+ track->elst_needs_processing = false;
if (track->elst_segment_duration > INT64_MAX) {
return;
@@ -1062,6 +1072,68 @@
mLastTrack->mTx3gBuffer = NULL;
}
+ const char *mime;
+ AMediaFormat_getString(mLastTrack->meta, AMEDIAFORMAT_KEY_MIME, &mime);
+
+ if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION)) {
+ void *data;
+ size_t size;
+
+ if (AMediaFormat_getBuffer(mLastTrack->meta, AMEDIAFORMAT_KEY_CSD_2, &data, &size)) {
+ const uint8_t *ptr = (const uint8_t *)data;
+ const uint8_t profile = ptr[2] >> 1;
+ const uint8_t bl_compatibility_id = (ptr[4]) >> 4;
+ bool create_two_tracks = false;
+
+ if (bl_compatibility_id && bl_compatibility_id != 15) {
+ create_two_tracks = true;
+ }
+
+ if (4 == profile || 7 == profile ||
+ (profile >= 8 && profile < 11 && create_two_tracks)) {
+ // we need a backward compatible track
+ ALOGV("Adding new backward compatible track");
+ Track *track_b = new Track;
+
+ track_b->timescale = mLastTrack->timescale;
+ track_b->sampleTable = mLastTrack->sampleTable;
+ track_b->includes_expensive_metadata = mLastTrack->includes_expensive_metadata;
+ track_b->skipTrack = mLastTrack->skipTrack;
+ track_b->elst_needs_processing = mLastTrack->elst_needs_processing;
+ track_b->elst_media_time = mLastTrack->elst_media_time;
+ track_b->elst_segment_duration = mLastTrack->elst_segment_duration;
+ track_b->elst_shift_start_ticks = mLastTrack->elst_shift_start_ticks;
+ track_b->elst_initial_empty_edit_ticks = mLastTrack->elst_initial_empty_edit_ticks;
+ track_b->subsample_encryption = mLastTrack->subsample_encryption;
+
+ track_b->mTx3gBuffer = mLastTrack->mTx3gBuffer;
+ track_b->mTx3gSize = mLastTrack->mTx3gSize;
+ track_b->mTx3gFilled = mLastTrack->mTx3gFilled;
+
+ track_b->meta = AMediaFormat_new();
+ AMediaFormat_copy(track_b->meta, mLastTrack->meta);
+
+ mLastTrack->next = track_b;
+ track_b->next = NULL;
+
+ auto id = track_b->meta->mFormat->findEntryByName(AMEDIAFORMAT_KEY_CSD_2);
+ track_b->meta->mFormat->removeEntryAt(id);
+
+ if (4 == profile || 7 == profile || 8 == profile ) {
+ AMediaFormat_setString(track_b->meta,
+ AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_HEVC);
+ } else if (9 == profile) {
+ AMediaFormat_setString(track_b->meta,
+ AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_AVC);
+ } else if (10 == profile) {
+ AMediaFormat_setString(track_b->meta,
+ AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_AV1);
+ } // Should never get to else part
+
+ mLastTrack = track_b;
+ }
+ }
+ }
} else if (chunk_type == FOURCC("moov")) {
mInitCheck = OK;
@@ -1134,39 +1206,86 @@
return ERROR_IO;
}
- if (entry_count != 1) {
- // we only support a single entry at the moment, for gapless playback
- // or start offset
+ if (entry_count > 2) {
+ /* We support a single entry for gapless playback or negating offset for
+ * reordering B frames, two entries (empty edit) for start offset at the moment.
+ */
ALOGW("ignoring edit list with %d entries", entry_count);
} else {
off64_t entriesoffset = data_offset + 8;
uint64_t segment_duration;
int64_t media_time;
-
- if (version == 1) {
- if (!mDataSource->getUInt64(entriesoffset, &segment_duration) ||
- !mDataSource->getUInt64(entriesoffset + 8, (uint64_t*)&media_time)) {
- return ERROR_IO;
- }
- } else if (version == 0) {
- uint32_t sd;
- int32_t mt;
- if (!mDataSource->getUInt32(entriesoffset, &sd) ||
+ uint64_t empty_edit_ticks = 0;
+ bool empty_edit_present = false;
+ for (int i = 0; i < entry_count; ++i) {
+ switch (version) {
+ case 0: {
+ uint32_t sd;
+ int32_t mt;
+ if (!mDataSource->getUInt32(entriesoffset, &sd) ||
!mDataSource->getUInt32(entriesoffset + 4, (uint32_t*)&mt)) {
- return ERROR_IO;
+ return ERROR_IO;
+ }
+ segment_duration = sd;
+ media_time = mt;
+ // 4(segment duration) + 4(media time) + 4(media rate)
+ entriesoffset += 12;
+ break;
}
- segment_duration = sd;
- media_time = mt;
- } else {
- return ERROR_IO;
+ case 1: {
+ if (!mDataSource->getUInt64(entriesoffset, &segment_duration) ||
+ !mDataSource->getUInt64(entriesoffset + 8, (uint64_t*)&media_time)) {
+ return ERROR_IO;
+ }
+ // 8(segment duration) + 8(media time) + 4(media rate)
+ entriesoffset += 20;
+ break;
+ }
+ default:
+ return ERROR_IO;
+ break;
+ }
+ // Empty edit entry would have to be first entry.
+ if (media_time == -1 && i == 0) {
+ int64_t durationUs;
+ if (AMediaFormat_getInt64(mFileMetaData, AMEDIAFORMAT_KEY_DURATION,
+ &durationUs)) {
+ empty_edit_ticks = segment_duration;
+ ALOGV("initial empty edit ticks: %" PRIu64, empty_edit_ticks);
+ empty_edit_present = true;
+ }
+ }
+ // Process second entry only when the first entry was an empty edit entry.
+ if (empty_edit_present && i == 1) {
+ int64_t durationUs;
+ if (AMediaFormat_getInt64(mLastTrack->meta, AMEDIAFORMAT_KEY_DURATION,
+ &durationUs) &&
+ mHeaderTimescale != 0) {
+ // Support only segment_duration<=track_duration and media_time==0 case.
+ uint64_t segmentDurationUs =
+ segment_duration * 1000000 / mHeaderTimescale;
+ if (segmentDurationUs == 0 || segmentDurationUs > durationUs ||
+ media_time != 0) {
+ ALOGW("for now, unsupported second entry in empty edit list");
+ }
+ }
+ }
}
-
// save these for later, because the elst atom might precede
// the atoms that actually gives us the duration and sample rate
// needed to calculate the padding and delay values
- mLastTrack->has_elst = true;
- mLastTrack->elst_media_time = media_time;
- mLastTrack->elst_segment_duration = segment_duration;
+ mLastTrack->elst_needs_processing = true;
+ if (empty_edit_present) {
+ /* In movie header timescale, and needs to be converted to media timescale once
+ * we get that from a track's 'mdhd' atom, which at times come after 'elst'.
+ */
+ mLastTrack->elst_initial_empty_edit_ticks = empty_edit_ticks;
+ } else {
+ mLastTrack->elst_media_time = media_time;
+ mLastTrack->elst_segment_duration = segment_duration;
+ ALOGV("segment_duration: %" PRIu64 " media_time: %" PRId64, segment_duration,
+ media_time);
+ }
}
break;
}
@@ -1561,8 +1680,12 @@
{
*offset += chunk_size;
- if (mLastTrack == NULL)
+ // the absolute minimum size of a compliant mett box is 11 bytes:
+ // 6 byte reserved, 2 byte index, null byte, one char mime_format, null byte
+ // The resulting mime_format would be invalid at that size though.
+ if (mLastTrack == NULL || chunk_data_size < 11) {
return ERROR_MALFORMED;
+ }
auto buffer = heapbuffer<uint8_t>(chunk_data_size);
if (buffer.get() == NULL) {
@@ -1574,10 +1697,24 @@
return ERROR_IO;
}
+ // ISO-14496-12:
+ // int8 reserved[6]; // should be all zeroes
+ // int16_t data_reference_index;
+ // char content_encoding[]; // null terminated, optional (= just the null byte)
+ // char mime_format[]; // null terminated, mandatory
+ // optional other boxes
+ //
+ // API < 29:
+ // char mime_format[]; // null terminated
+ //
+ // API >= 29
+ // char mime_format[]; // null terminated
+ // char mime_format[]; // null terminated
+
// Prior to API 29, the metadata track was not compliant with ISO/IEC
// 14496-12-2015. This led to some ISO-compliant parsers failing to read the
// metatrack. As of API 29 and onwards, a change was made to metadata track to
- // make it compliant with the standard. The workaround is to write the
+ // make it somewhat compatible with the standard. The workaround is to write the
// null-terminated mime_format string twice. This allows compliant parsers to
// read the missing reserved, data_reference_index, and content_encoding fields
// from the first mime_type string. The actual mime_format field would then be
@@ -1586,27 +1723,27 @@
// as it would only read the first null-terminated mime_format string. To enable
// reading metadata tracks generated from both the non-compliant and compliant
// formats, a check needs to be done to see which format is used.
- int null_pos = 0;
- const unsigned char *str = buffer.get();
- while (null_pos < chunk_data_size) {
- if (*(str + null_pos) == '\0') {
- break;
- }
- ++null_pos;
- }
+ const char *str = (const char*) buffer.get();
+ size_t string_length = strnlen(str, chunk_data_size);
- if (null_pos == chunk_data_size - 1) {
- // This is not a standard ompliant metadata track.
- String8 mimeFormat((const char *)(buffer.get()), chunk_data_size);
- AMediaFormat_setString(mLastTrack->meta,
- AMEDIAFORMAT_KEY_MIME, mimeFormat.string());
+ if (string_length == chunk_data_size - 1) {
+ // This is likely a pre API 29 file, since it's a single null terminated
+ // string filling the entire box.
+ AMediaFormat_setString(mLastTrack->meta, AMEDIAFORMAT_KEY_MIME, str);
} else {
- // This is a standard compliant metadata track.
- String8 contentEncoding((const char *)(buffer.get() + 8));
- String8 mimeFormat((const char *)(buffer.get() + 8 + contentEncoding.size() + 1),
- chunk_data_size - 8 - contentEncoding.size() - 1);
- AMediaFormat_setString(mLastTrack->meta,
- AMEDIAFORMAT_KEY_MIME, mimeFormat.string());
+ // This might be a fully compliant metadata track, a "double mime" compatibility
+ // track, or anything else, including a single non-terminated string, so we need
+ // to determine the length of each string we want to parse out of the box.
+ size_t encoding_length = strnlen(str + 8, chunk_data_size - 8);
+ if (encoding_length + 8 >= chunk_data_size - 2) {
+ // the encoding extends to the end of the box, so there's no mime_format
+ return ERROR_MALFORMED;
+ }
+ String8 contentEncoding(str + 8, encoding_length);
+ String8 mimeFormat(str + 8 + encoding_length + 1,
+ chunk_data_size - 8 - encoding_length - 1);
+ AMediaFormat_setString(mLastTrack->meta,
+ AMEDIAFORMAT_KEY_MIME, mimeFormat.string());
}
break;
}
@@ -1830,6 +1967,11 @@
case FOURCC("avc1"):
case FOURCC("hvc1"):
case FOURCC("hev1"):
+ case FOURCC("dvav"):
+ case FOURCC("dva1"):
+ case FOURCC("dvhe"):
+ case FOURCC("dvh1"):
+ case FOURCC("dav1"):
case FOURCC("av01"):
{
uint8_t buffer[78];
@@ -1984,7 +2126,8 @@
// for audio, use 128KB
max_size = 1024 * 128;
} else if (!strcmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)
- || !strcmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)) {
+ || !strcmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)
+ || !strcmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION)) {
// AVC & HEVC requires compression ratio of at least 2, and uses
// macroblocks
max_size = ((width + 15) / 16) * ((height + 15) / 16) * 192;
@@ -2315,6 +2458,33 @@
*offset += chunk_size;
break;
}
+ case FOURCC("dvcC"):
+ case FOURCC("dvvC"): {
+
+ CHECK_EQ(chunk_data_size, 24);
+
+ auto buffer = heapbuffer<uint8_t>(chunk_data_size);
+
+ if (buffer.get() == NULL) {
+ ALOGE("b/28471206");
+ return NO_MEMORY;
+ }
+
+ if (mDataSource->readAt(data_offset, buffer.get(), chunk_data_size) < chunk_data_size) {
+ return ERROR_IO;
+ }
+
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
+ AMediaFormat_setBuffer(mLastTrack->meta, AMEDIAFORMAT_KEY_CSD_2,
+ buffer.get(), chunk_data_size);
+ AMediaFormat_setString(mLastTrack->meta, AMEDIAFORMAT_KEY_MIME,
+ MEDIA_MIMETYPE_VIDEO_DOLBY_VISION);
+
+ *offset += chunk_size;
+ break;
+ }
case FOURCC("d263"):
{
*offset += chunk_size;
@@ -4127,7 +4297,20 @@
if (!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC)) {
itemTable = mItemTable;
}
- } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AV1)) {
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION)) {
+ void *data;
+ size_t size;
+ if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_2, &data, &size)) {
+ return NULL;
+ }
+
+ const uint8_t *ptr = (const uint8_t *)data;
+
+ // dv_major.dv_minor Should be 1.0 or 2.1
+ if (size != 24 || ((ptr[0] != 1 || ptr[1] != 0) && (ptr[0] != 2 || ptr[1] != 1))) {
+ return NULL;
+ }
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AV1)) {
void *data;
size_t size;
if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_0, &data, &size)) {
@@ -4141,15 +4324,28 @@
}
}
- if (track->has_elst and !strncasecmp("video/", mime, 6) and track->elst_media_time > 0) {
- track->elstShiftStartTicks = track->elst_media_time;
- ALOGV("video track->elstShiftStartTicks :%" PRIu64, track->elstShiftStartTicks);
+ // media_time is in media timescale as are STTS/CTTS entries.
+ track->elst_shift_start_ticks = track->elst_media_time;
+ ALOGV("track->elst_shift_start_ticks :%" PRIu64, track->elst_shift_start_ticks);
+ if (mHeaderTimescale != 0) {
+ // Convert empty_edit_ticks from movie timescale to media timescale.
+ uint64_t elst_initial_empty_edit_ticks_mul = 0, elst_initial_empty_edit_ticks_add = 0;
+ if (__builtin_mul_overflow(track->elst_initial_empty_edit_ticks, track->timescale,
+ &elst_initial_empty_edit_ticks_mul) ||
+ __builtin_add_overflow(elst_initial_empty_edit_ticks_mul, (mHeaderTimescale / 2),
+ &elst_initial_empty_edit_ticks_add)) {
+ ALOGE("track->elst_initial_empty_edit_ticks overflow");
+ return nullptr;
+ }
+ track->elst_initial_empty_edit_ticks = elst_initial_empty_edit_ticks_add / mHeaderTimescale;
+ ALOGV("track->elst_initial_empty_edit_ticks :%" PRIu64,
+ track->elst_initial_empty_edit_ticks);
}
- MPEG4Source *source = new MPEG4Source(
- track->meta, mDataSource, track->timescale, track->sampleTable,
- mSidxEntries, trex, mMoofOffset, itemTable,
- track->elstShiftStartTicks);
+ MPEG4Source* source =
+ new MPEG4Source(track->meta, mDataSource, track->timescale, track->sampleTable,
+ mSidxEntries, trex, mMoofOffset, itemTable,
+ track->elst_shift_start_ticks, track->elst_initial_empty_edit_ticks);
if (source->init() != OK) {
delete source;
return NULL;
@@ -4172,6 +4368,10 @@
if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_HEVC, &data, &size)) {
return ERROR_MALFORMED;
}
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION)) {
+ if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_2, &data, &size)) {
+ return ERROR_MALFORMED;
+ }
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AV1)) {
if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_0, &data, &size)) {
return ERROR_MALFORMED;
@@ -4638,7 +4838,8 @@
const Trex *trex,
off64_t firstMoofOffset,
const sp<ItemTable> &itemTable,
- uint64_t elstShiftStartTicks)
+ uint64_t elstShiftStartTicks,
+ uint64_t elstInitialEmptyEditTicks)
: mFormat(format),
mDataSource(dataSource),
mTimescale(timeScale),
@@ -4659,6 +4860,7 @@
mCurrentSampleInfoOffsets(NULL),
mIsAVC(false),
mIsHEVC(false),
+ mIsDolbyVision(false),
mIsAC4(false),
mIsPcm(false),
mNALLengthSize(0),
@@ -4667,7 +4869,8 @@
mSrcBuffer(NULL),
mIsHeif(itemTable != NULL),
mItemTable(itemTable),
- mElstShiftStartTicks(elstShiftStartTicks) {
+ mElstShiftStartTicks(elstShiftStartTicks),
+ mElstInitialEmptyEditTicks(elstInitialEmptyEditTicks) {
memset(&mTrackFragmentHeaderInfo, 0, sizeof(mTrackFragmentHeaderInfo));
@@ -4698,6 +4901,7 @@
mIsHEVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC) ||
!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC);
mIsAC4 = !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AC4);
+ mIsDolbyVision = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION);
if (mIsAVC) {
void *data;
@@ -4722,6 +4926,42 @@
CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1
mNALLengthSize = 1 + (ptr[14 + 7] & 3);
+ } else if (mIsDolbyVision) {
+ ALOGV("%s DolbyVision stream detected", __FUNCTION__);
+ void *data;
+ size_t size;
+ CHECK(AMediaFormat_getBuffer(format, AMEDIAFORMAT_KEY_CSD_2, &data, &size));
+
+ const uint8_t *ptr = (const uint8_t *)data;
+
+ CHECK(size == 24);
+
+ // dv_major.dv_minor Should be 1.0 or 2.1
+ CHECK(!((ptr[0] != 1 || ptr[1] != 0) && (ptr[0] != 2 || ptr[1] != 1)));
+
+ const uint8_t profile = ptr[2] >> 1;
+ // profile == (unknown,1,9) --> AVC; profile = (2,3,4,5,6,7,8) --> HEVC;
+ // profile == (10) --> AV1
+ if (profile > 1 && profile < 9) {
+ CHECK(AMediaFormat_getBuffer(format, AMEDIAFORMAT_KEY_CSD_HEVC, &data, &size));
+
+ const uint8_t *ptr = (const uint8_t *)data;
+
+ CHECK(size >= 22);
+ CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1
+
+ mNALLengthSize = 1 + (ptr[14 + 7] & 3);
+ } else if (10 == profile) {
+ /* AV1 profile nothing to do */
+ } else {
+ CHECK(AMediaFormat_getBuffer(format, AMEDIAFORMAT_KEY_CSD_AVC, &data, &size));
+ const uint8_t *ptr = (const uint8_t *)data;
+
+ CHECK(size >= 7);
+ CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1
+ // The number of bytes used to encode the length of a NAL unit.
+ mNALLengthSize = 1 + (ptr[4] & 3);
+ }
}
mIsPcm = !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW);
@@ -4749,35 +4989,14 @@
}
CHECK(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_TRACK_ID, &mTrackId));
-
}
status_t MPEG4Source::init() {
- status_t err = OK;
- const char *mime;
- CHECK(AMediaFormat_getString(mFormat, AMEDIAFORMAT_KEY_MIME, &mime));
if (mFirstMoofOffset != 0) {
off64_t offset = mFirstMoofOffset;
- err = parseChunk(&offset);
- if(err == OK && !strncasecmp("video/", mime, 6)
- && !mCurrentSamples.isEmpty()) {
- // Start offset should be less or equal to composition time of first sample.
- // ISO : sample_composition_time_offset, version 0 (unsigned) for major brands.
- mElstShiftStartTicks = std::min(mElstShiftStartTicks,
- (uint64_t)(*mCurrentSamples.begin()).compositionOffset);
- }
- return err;
+ return parseChunk(&offset);
}
-
- if (!strncasecmp("video/", mime, 6)) {
- uint64_t firstSampleCTS = 0;
- err = mSampleTable->getMetaDataForSample(0, NULL, NULL, &firstSampleCTS);
- // Start offset should be less or equal to composition time of first sample.
- // Composition time stamp of first sample cannot be negative.
- mElstShiftStartTicks = std::min(mElstShiftStartTicks, firstSampleCTS);
- }
-
- return err;
+ return OK;
}
MPEG4Source::~MPEG4Source() {
@@ -4993,8 +5212,11 @@
}
status_t MPEG4Source::parseSampleAuxiliaryInformationSizes(
- off64_t offset, off64_t /* size */) {
+ off64_t offset, off64_t size) {
ALOGV("parseSampleAuxiliaryInformationSizes");
+ if (size < 9) {
+ return -EINVAL;
+ }
// 14496-12 8.7.12
uint8_t version;
if (mDataSource->readAt(
@@ -5007,25 +5229,32 @@
return ERROR_UNSUPPORTED;
}
offset++;
+ size--;
uint32_t flags;
if (!mDataSource->getUInt24(offset, &flags)) {
return ERROR_IO;
}
offset += 3;
+ size -= 3;
if (flags & 1) {
+ if (size < 13) {
+ return -EINVAL;
+ }
uint32_t tmp;
if (!mDataSource->getUInt32(offset, &tmp)) {
return ERROR_MALFORMED;
}
mCurrentAuxInfoType = tmp;
offset += 4;
+ size -= 4;
if (!mDataSource->getUInt32(offset, &tmp)) {
return ERROR_MALFORMED;
}
mCurrentAuxInfoTypeParameter = tmp;
offset += 4;
+ size -= 4;
}
uint8_t defsize;
@@ -5034,6 +5263,7 @@
}
mCurrentDefaultSampleInfoSize = defsize;
offset++;
+ size--;
uint32_t smplcnt;
if (!mDataSource->getUInt32(offset, &smplcnt)) {
@@ -5041,11 +5271,16 @@
}
mCurrentSampleInfoCount = smplcnt;
offset += 4;
-
+ size -= 4;
if (mCurrentDefaultSampleInfoSize != 0) {
ALOGV("@@@@ using default sample info size of %d", mCurrentDefaultSampleInfoSize);
return OK;
}
+ if(smplcnt > size) {
+ ALOGW("b/124525515 - smplcnt(%u) > size(%ld)", (unsigned int)smplcnt, (unsigned long)size);
+ android_errorWriteLog(0x534e4554, "124525515");
+ return -EINVAL;
+ }
if (smplcnt > mCurrentSampleInfoAllocSize) {
uint8_t * newPtr = (uint8_t*) realloc(mCurrentSampleInfoSizes, smplcnt);
if (newPtr == NULL) {
@@ -5061,26 +5296,32 @@
}
status_t MPEG4Source::parseSampleAuxiliaryInformationOffsets(
- off64_t offset, off64_t /* size */) {
+ off64_t offset, off64_t size) {
ALOGV("parseSampleAuxiliaryInformationOffsets");
+ if (size < 8) {
+ return -EINVAL;
+ }
// 14496-12 8.7.13
uint8_t version;
if (mDataSource->readAt(offset, &version, sizeof(version)) != 1) {
return ERROR_IO;
}
offset++;
+ size--;
uint32_t flags;
if (!mDataSource->getUInt24(offset, &flags)) {
return ERROR_IO;
}
offset += 3;
+ size -= 3;
uint32_t entrycount;
if (!mDataSource->getUInt32(offset, &entrycount)) {
return ERROR_IO;
}
offset += 4;
+ size -= 4;
if (entrycount == 0) {
return OK;
}
@@ -5106,19 +5347,31 @@
for (size_t i = 0; i < entrycount; i++) {
if (version == 0) {
+ if (size < 4) {
+ ALOGW("b/124526959");
+ android_errorWriteLog(0x534e4554, "124526959");
+ return -EINVAL;
+ }
uint32_t tmp;
if (!mDataSource->getUInt32(offset, &tmp)) {
return ERROR_IO;
}
mCurrentSampleInfoOffsets[i] = tmp;
offset += 4;
+ size -= 4;
} else {
+ if (size < 8) {
+ ALOGW("b/124526959");
+ android_errorWriteLog(0x534e4554, "124526959");
+ return -EINVAL;
+ }
uint64_t tmp;
if (!mDataSource->getUInt64(offset, &tmp)) {
return ERROR_IO;
}
mCurrentSampleInfoOffsets[i] = tmp;
offset += 8;
+ size -= 8;
}
}
@@ -5405,20 +5658,30 @@
if (flags & kSampleSizePresent) {
bytesPerSample += 4;
- } else if (mTrackFragmentHeaderInfo.mFlags
- & TrackFragmentHeaderInfo::kDefaultSampleSizePresent) {
- sampleSize = mTrackFragmentHeaderInfo.mDefaultSampleSize;
} else {
sampleSize = mTrackFragmentHeaderInfo.mDefaultSampleSize;
+#ifdef VERY_VERY_VERBOSE_LOGGING
+ // We don't expect this, but also want to avoid spamming the log if
+ // we hit this case.
+ if (!(mTrackFragmentHeaderInfo.mFlags
+ & TrackFragmentHeaderInfo::kDefaultSampleSizePresent)) {
+ ALOGW("No sample size specified");
+ }
+#endif
}
if (flags & kSampleFlagsPresent) {
bytesPerSample += 4;
- } else if (mTrackFragmentHeaderInfo.mFlags
- & TrackFragmentHeaderInfo::kDefaultSampleFlagsPresent) {
- sampleFlags = mTrackFragmentHeaderInfo.mDefaultSampleFlags;
} else {
sampleFlags = mTrackFragmentHeaderInfo.mDefaultSampleFlags;
+#ifdef VERY_VERY_VERBOSE_LOGGING
+ // We don't expect this, but also want to avoid spamming the log if
+ // we hit this case.
+ if (!(mTrackFragmentHeaderInfo.mFlags
+ & TrackFragmentHeaderInfo::kDefaultSampleFlagsPresent)) {
+ ALOGW("No sample flags specified");
+ }
+#endif
}
if (flags & kSampleCompositionTimeOffsetPresent) {
@@ -5581,6 +5844,7 @@
int64_t seekTimeUs;
ReadOptions::SeekMode mode;
+
if (options && options->getSeekTo(&seekTimeUs, &mode)) {
if (mIsHeif) {
@@ -5622,6 +5886,8 @@
}
if( mode != ReadOptions::SEEK_FRAME_INDEX) {
seekTimeUs += ((long double)mElstShiftStartTicks * 1000000) / mTimescale;
+ ALOGV("shifted seekTimeUs :%" PRId64 ", mElstShiftStartTicks:%" PRIu64, seekTimeUs,
+ mElstShiftStartTicks);
}
uint32_t sampleIndex;
@@ -5696,7 +5962,8 @@
off64_t offset = 0;
size_t size = 0;
- uint64_t cts, stts;
+ int64_t cts;
+ uint64_t stts;
bool isSyncSample;
bool newBuffer = false;
if (mBuffer == NULL) {
@@ -5704,14 +5971,15 @@
status_t err;
if (!mIsHeif) {
- err = mSampleTable->getMetaDataForSample(
- mCurrentSampleIndex, &offset, &size, &cts, &isSyncSample, &stts);
+ err = mSampleTable->getMetaDataForSample(mCurrentSampleIndex, &offset, &size,
+ (uint64_t*)&cts, &isSyncSample, &stts);
if(err == OK) {
- /* Composition Time Stamp cannot be negative. Some files have video Sample
- * Time(STTS)delta with zero value(b/117402420). Hence subtract only
- * min(cts, mElstShiftStartTicks), so that audio tracks can be played.
- */
- cts -= std::min(cts, mElstShiftStartTicks);
+ if (mElstInitialEmptyEditTicks > 0) {
+ cts += mElstInitialEmptyEditTicks;
+ } else {
+ // cts can be negative. for example, initial audio samples for gapless playback.
+ cts -= (int64_t)mElstShiftStartTicks;
+ }
}
} else {
@@ -5745,7 +6013,7 @@
}
}
- if (!mIsAVC && !mIsHEVC && !mIsAC4) {
+ if (!mIsAVC && !mIsHEVC && !(mIsDolbyVision && mNALLengthSize) && !mIsAC4) {
if (newBuffer) {
if (mIsPcm) {
// The twos' PCM block reader assumes that all samples has the same size.
@@ -5776,11 +6044,11 @@
meta, AMEDIAFORMAT_KEY_TIME_US, ((long double)cts * 1000000) / mTimescale);
AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_IS_SYNC_FRAME, 1);
- int32_t byteOrder;
- AMediaFormat_getInt32(mFormat,
+ int32_t byteOrder = 0;
+ bool isGetBigEndian = AMediaFormat_getInt32(mFormat,
AMEDIAFORMAT_KEY_PCM_BIG_ENDIAN, &byteOrder);
- if (byteOrder == 1) {
+ if (isGetBigEndian && byteOrder == 1) {
// Big-endian -> little-endian
uint16_t *dstData = (uint16_t *)buf;
uint16_t *srcData = (uint16_t *)buf;
@@ -6052,7 +6320,7 @@
off64_t offset = 0;
size_t size = 0;
- uint64_t cts = 0;
+ int64_t cts = 0;
bool isSyncSample = false;
bool newBuffer = false;
if (mBuffer == NULL || mCurrentSampleIndex >= mCurrentSamples.size()) {
@@ -6084,11 +6352,13 @@
offset = smpl->offset;
size = smpl->size;
cts = mCurrentTime + smpl->compositionOffset;
- /* Composition Time Stamp cannot be negative. Some files have video Sample
- * Time(STTS)delta with zero value(b/117402420). Hence subtract only
- * min(cts, mElstShiftStartTicks), so that audio tracks can be played.
- */
- cts -= std::min(cts, mElstShiftStartTicks);
+
+ if (mElstInitialEmptyEditTicks > 0) {
+ cts += mElstInitialEmptyEditTicks;
+ } else {
+ // cts can be negative. for example, initial audio samples for gapless playback.
+ cts -= (int64_t)mElstShiftStartTicks;
+ }
mCurrentTime += smpl->duration;
isSyncSample = (mCurrentSampleIndex == 0);
@@ -6135,7 +6405,7 @@
AMediaFormat_setBuffer(bufmeta, AMEDIAFORMAT_KEY_CRYPTO_IV, iv, ivlength);
}
- if (!mIsAVC && !mIsHEVC) {
+ if (!mIsAVC && !mIsHEVC && !(mIsDolbyVision && mNALLengthSize)) {
if (newBuffer) {
if (!isInRange((size_t)0u, mBuffer->size(), size)) {
mBuffer->release();
@@ -6409,6 +6679,12 @@
// The smallest valid chunk is 16 bytes long in this case.
return false;
}
+ if (chunkSize > INT64_MAX) {
+ // reject overly large chunk sizes that could
+ // be interpreted as negative
+ ALOGE("chunk size too large");
+ return false;
+ }
} else if (chunkSize < 8) {
// The smallest valid chunk is 8 bytes long.
@@ -6464,7 +6740,10 @@
case FOURCC("moov"):
{
- moovAtomEndOffset = offset + chunkSize;
+ if (__builtin_add_overflow(offset, chunkSize, &moovAtomEndOffset)) {
+ ALOGE("chunk size + offset would overflow");
+ return false;
+ }
done = true;
break;
@@ -6474,7 +6753,10 @@
break;
}
- offset += chunkSize;
+ if (__builtin_add_overflow(offset, chunkSize, &offset)) {
+ ALOGE("chunk size + offset would overflow");
+ return false;
+ }
}
if (!foundGoodFileType) {
diff --git a/media/extractors/mp4/MPEG4Extractor.h b/media/extractors/mp4/MPEG4Extractor.h
index fcddbb8..53ec6bc 100644
--- a/media/extractors/mp4/MPEG4Extractor.h
+++ b/media/extractors/mp4/MPEG4Extractor.h
@@ -82,14 +82,16 @@
sp<SampleTable> sampleTable;
bool includes_expensive_metadata;
bool skipTrack;
- bool has_elst;
+ bool elst_needs_processing;
/* signed int, ISO Spec allows media_time = -1 for other use cases.
* but we don't support empty edits for now.
*/
int64_t elst_media_time;
uint64_t elst_segment_duration;
- // unsigned int, shift start offset only when media_time > 0.
- uint64_t elstShiftStartTicks;
+ // Shift start offset only when media_time > 0.
+ uint64_t elst_shift_start_ticks;
+ // Initial start offset, empty edit list entry.
+ uint64_t elst_initial_empty_edit_ticks;
bool subsample_encryption;
uint8_t *mTx3gBuffer;
@@ -102,9 +104,11 @@
timescale = 0;
includes_expensive_metadata = false;
skipTrack = false;
- has_elst = false;
+ elst_needs_processing = false;
elst_media_time = 0;
- elstShiftStartTicks = 0;
+ elst_segment_duration = 0;
+ elst_shift_start_ticks = 0;
+ elst_initial_empty_edit_ticks = 0;
subsample_encryption = false;
mTx3gBuffer = NULL;
mTx3gSize = mTx3gFilled = 0;
diff --git a/media/extractors/mp4/SampleIterator.cpp b/media/extractors/mp4/SampleIterator.cpp
index 2890b26..85fbf97 100644
--- a/media/extractors/mp4/SampleIterator.cpp
+++ b/media/extractors/mp4/SampleIterator.cpp
@@ -22,7 +22,6 @@
#include <arpa/inet.h>
-#include <media/DataSourceBase.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ByteUtils.h>
@@ -355,7 +354,7 @@
if (offset > 0) {
*time += offset;
} else {
- *time -= (offset == INT64_MIN ? INT64_MAX : (-offset));
+ *time -= (offset == INT32_MIN ? INT64_MAX : (-offset));
}
*duration = mTTSDuration;
diff --git a/media/extractors/mp4/SampleTable.cpp b/media/extractors/mp4/SampleTable.cpp
index bf29bf1..a00812b 100644
--- a/media/extractors/mp4/SampleTable.cpp
+++ b/media/extractors/mp4/SampleTable.cpp
@@ -391,20 +391,11 @@
}
mTimeToSampleCount = U32_AT(&header[4]);
- if (mTimeToSampleCount > UINT32_MAX / (2 * sizeof(uint32_t))) {
- // Choose this bound because
- // 1) 2 * sizeof(uint32_t) is the amount of memory needed for one
- // time-to-sample entry in the time-to-sample table.
- // 2) mTimeToSampleCount is the number of entries of the time-to-sample
- // table.
- // 3) We hope that the table size does not exceed UINT32_MAX.
+ if (mTimeToSampleCount > (data_size - 8) / (2 * sizeof(uint32_t))) {
ALOGE("Time-to-sample table size too large.");
return ERROR_OUT_OF_RANGE;
}
- // Note: At this point, we know that mTimeToSampleCount * 2 will not
- // overflow because of the above condition.
-
uint64_t allocSize = (uint64_t)mTimeToSampleCount * 2 * sizeof(uint32_t);
mTotalSize += allocSize;
if (mTotalSize > kMaxTotalSize) {
@@ -540,6 +531,12 @@
}
uint64_t allocSize = (uint64_t)numSyncSamples * sizeof(uint32_t);
+ if (allocSize > data_size - 8) {
+ ALOGW("b/124771364 - allocSize(%lu) > size(%lu)",
+ (unsigned long)allocSize, (unsigned long)(data_size - 8));
+ android_errorWriteLog(0x534e4554, "124771364");
+ return ERROR_MALFORMED;
+ }
if (allocSize > kMaxTotalSize) {
ALOGE("Sync sample table size too large.");
return ERROR_OUT_OF_RANGE;
@@ -655,11 +652,13 @@
}
mSampleTimeEntries = new (std::nothrow) SampleTimeEntry[mNumSampleSizes];
+
if (!mSampleTimeEntries) {
ALOGE("Cannot allocate sample entry table with %llu entries.",
(unsigned long long)mNumSampleSizes);
return;
}
+ memset(mSampleTimeEntries, 0, sizeof(SampleTimeEntry) * mNumSampleSizes);
uint32_t sampleIndex = 0;
uint64_t sampleTime = 0;
diff --git a/media/extractors/mpeg2/Android.bp b/media/extractors/mpeg2/Android.bp
index 0f0c72c..bc8632c 100644
--- a/media/extractors/mpeg2/Android.bp
+++ b/media/extractors/mpeg2/Android.bp
@@ -1,4 +1,7 @@
-cc_library_shared {
+cc_library {
+ name: "libmpeg2extractor",
+
+ defaults: ["extractor-defaults"],
srcs: [
"ExtractorBundle.cpp",
@@ -6,55 +9,47 @@
"MPEG2TSExtractor.cpp",
],
- include_dirs: [
- "frameworks/av/media/libstagefright",
- "frameworks/av/media/libstagefright/include",
- ],
-
shared_libs: [
- "android.hardware.cas@1.0",
- "android.hardware.cas.native@1.0",
- "android.hidl.token@1.0-utils",
- "android.hidl.allocator@1.0",
- "libhidlmemory",
- "libhidlbase",
- "liblog",
- "libmediandk",
+ "libbase",
+ "libcgrouprc#29",
+ "libvndksupport#29",
],
header_libs: [
+ "libaudioclient_headers",
"libbase_headers",
"libstagefright_headers",
"libmedia_headers",
],
static_libs: [
- "libcrypto",
+ "android.hardware.cas@1.0",
+ "android.hardware.cas.native@1.0",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ "android.hidl.token@1.0",
+ "android.hidl.token@1.0-utils",
+ "libcutils",
+ "libhidlbase",
+ "libhidlmemory",
+ "libjsoncpp",
+ "libprocessgroup",
+ "libstagefright_esds",
"libstagefright_foundation_without_imemory",
+ "libstagefright_mpeg2extractor",
"libstagefright_mpeg2support",
"libutils",
- "libstagefright_mpeg2extractor",
- "libstagefright_esds",
],
- name: "libmpeg2extractor",
- relative_install_path: "extractors",
-
- compile_multilib: "first",
-
- cflags: [
- "-Werror",
- "-Wall",
- "-fvisibility=hidden",
+ apex_available: [
+ "com.android.media",
+ "test_com.android.media",
],
- version_script: "exports.lds",
- sanitize: {
- cfi: true,
- misc_undefined: [
- "unsigned-integer-overflow",
- "signed-integer-overflow",
+ static: {
+ apex_available: [
+ // Needed for unit tests
+ "//apex_available:platform",
],
},
-
}
diff --git a/media/extractors/mpeg2/MPEG2PSExtractor.cpp b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
index 731584d..d431b05 100644
--- a/media/extractors/mpeg2/MPEG2PSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
@@ -20,10 +20,9 @@
#include "MPEG2PSExtractor.h"
-#include "mpeg2ts/AnotherPacketSource.h"
-#include "mpeg2ts/ESQueue.h"
+#include <AnotherPacketSource.h>
+#include <ESQueue.h>
-#include <media/DataSourceBase.h>
#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -111,8 +110,10 @@
AMediaFormat *meta = AMediaFormat_new();
for (size_t i = mTracks.size(); i > 0;) {
i--;
- if (mTracks.valueAt(i)->getFormat(meta) != AMEDIA_OK) {
+ Track *track = mTracks.valueAt(i);
+ if (track->getFormat(meta) != AMEDIA_OK) {
mTracks.removeItemsAt(i);
+ delete track;
}
}
AMediaFormat_delete(meta);
@@ -122,6 +123,10 @@
MPEG2PSExtractor::~MPEG2PSExtractor() {
delete mDataSource;
+ for (size_t i = mTracks.size(); i > 0;) {
+ i--;
+ delete mTracks.valueAt(i);
+ }
}
size_t MPEG2PSExtractor::countTracks() {
@@ -793,7 +798,9 @@
}
media_status_t MPEG2PSExtractor::WrappedTrack::start() {
+ delete mTrack->mBufferGroup;
mTrack->mBufferGroup = mBufferGroup;
+ mBufferGroup = nullptr;
return mTrack->start();
}
diff --git a/media/extractors/mpeg2/MPEG2TSExtractor.cpp b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
index 50ce657..9e093eb 100644
--- a/media/extractors/mpeg2/MPEG2TSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
@@ -24,21 +24,20 @@
#include "MPEG2TSExtractor.h"
-#include <media/DataSourceBase.h>
#include <media/IStreamSource.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AUtils.h>
#include <media/stagefright/foundation/MediaKeys.h>
+#include <media/stagefright/DataSourceBase.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
#include <utils/String8.h>
-#include "mpeg2ts/AnotherPacketSource.h"
-#include "mpeg2ts/ATSParser.h"
+#include <AnotherPacketSource.h>
#include <hidl/HybridInterface.h>
#include <android/hardware/cas/1.0/ICas.h>
diff --git a/media/extractors/mpeg2/MPEG2TSExtractor.h b/media/extractors/mpeg2/MPEG2TSExtractor.h
index dcd1e7b..fd77b08 100644
--- a/media/extractors/mpeg2/MPEG2TSExtractor.h
+++ b/media/extractors/mpeg2/MPEG2TSExtractor.h
@@ -27,7 +27,7 @@
#include <utils/KeyedVector.h>
#include <utils/Vector.h>
-#include "mpeg2ts/ATSParser.h"
+#include <ATSParser.h>
namespace android {
diff --git a/media/extractors/ogg/Android.bp b/media/extractors/ogg/Android.bp
index 604ec59..7aed683 100644
--- a/media/extractors/ogg/Android.bp
+++ b/media/extractors/ogg/Android.bp
@@ -1,9 +1,11 @@
-cc_library_shared {
+cc_library {
+ name: "liboggextractor",
+
+ defaults: ["extractor-defaults"],
srcs: ["OggExtractor.cpp"],
include_dirs: [
- "frameworks/av/media/libstagefright/include",
"external/tremolo",
],
@@ -11,11 +13,6 @@
"libaudio_system_headers",
],
- shared_libs: [
- "liblog",
- "libmediandk",
- ],
-
static_libs: [
"libstagefright_foundation",
"libstagefright_metadatautils",
@@ -23,24 +20,4 @@
"libvorbisidec",
],
- name: "liboggextractor",
- relative_install_path: "extractors",
-
- compile_multilib: "first",
-
- cflags: [
- "-Werror",
- "-Wall",
- "-fvisibility=hidden",
- ],
- version_script: "exports.lds",
-
- sanitize: {
- cfi: true,
- misc_undefined: [
- "unsigned-integer-overflow",
- "signed-integer-overflow",
- ],
- },
-
}
diff --git a/media/extractors/ogg/OggExtractor.cpp b/media/extractors/ogg/OggExtractor.cpp
index 72b94bb..828bcd6 100644
--- a/media/extractors/ogg/OggExtractor.cpp
+++ b/media/extractors/ogg/OggExtractor.cpp
@@ -22,7 +22,7 @@
#include <cutils/properties.h>
#include <utils/Vector.h>
-#include <media/DataSourceBase.h>
+#include <media/stagefright/DataSourceBase.h>
#include <media/ExtractorUtils.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -635,7 +635,8 @@
currentPageSamples -= mStartGranulePosition;
AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_VALID_SAMPLES, currentPageSamples);
}
- mCurGranulePosition = mCurrentPage.mGranulePosition - currentPageSamples;
+ (void) __builtin_sub_overflow(mCurrentPage.mGranulePosition, currentPageSamples,
+ &mCurGranulePosition);
}
int64_t timeUs = getTimeUsOfGranule(mCurGranulePosition);
@@ -1062,8 +1063,15 @@
size_t size = buffer->range_length();
if (size < kOpusHeaderSize
- || memcmp(data, "OpusHead", 8)
- || /* version = */ data[8] != 1) {
+ || memcmp(data, "OpusHead", 8)) {
+ return AMEDIA_ERROR_MALFORMED;
+ }
+ // allow both version 0 and 1. Per the opus specification:
+ // An earlier draft of the specification described a version 0, but the only difference
+ // between version 1 and version 0 is that version 0 did not specify the semantics for
+ // handling the version field
+ if ( /* version = */ data[8] > 1) {
+ ALOGW("no support for opus version %d", data[8]);
return AMEDIA_ERROR_MALFORMED;
}
@@ -1384,7 +1392,7 @@
return NULL;
}
- *confidence = 0.2f;
+ *confidence = 0.5f;
return CreateExtractor;
}
diff --git a/media/extractors/tests/Android.bp b/media/extractors/tests/Android.bp
new file mode 100644
index 0000000..fa39b64
--- /dev/null
+++ b/media/extractors/tests/Android.bp
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+cc_test {
+ name: "ExtractorUnitTest",
+ gtest: true,
+
+ srcs: ["ExtractorUnitTest.cpp"],
+
+ static_libs: [
+ "libaacextractor",
+ "libamrextractor",
+ "libmp3extractor",
+ "libwavextractor",
+ "liboggextractor",
+ "libflacextractor",
+ "libmidiextractor",
+ "libmkvextractor",
+ "libmpeg2extractor",
+ "libmp4extractor",
+ "libaudioutils",
+ "libdatasource",
+ "libwatchdog",
+
+ "libstagefright",
+ "libstagefright_id3",
+ "libstagefright_flacdec",
+ "libstagefright_esds",
+ "libstagefright_mpeg2support",
+ "libstagefright_mpeg2extractor",
+ "libstagefright_foundation",
+ "libstagefright_metadatautils",
+
+ "libmedia_midiiowrapper",
+ "libsonivox",
+ "libvorbisidec",
+ "libwebm",
+ "libFLAC",
+ ],
+
+ shared_libs: [
+ "android.hardware.cas@1.0",
+ "android.hardware.cas.native@1.0",
+ "android.hidl.token@1.0-utils",
+ "android.hidl.allocator@1.0",
+ "libbinder",
+ "libbinder_ndk",
+ "libutils",
+ "liblog",
+ "libcutils",
+ "libmediandk",
+ "libmedia",
+ "libcrypto",
+ "libhidlmemory",
+ "libhidlbase",
+ "libbase",
+ ],
+
+ include_dirs: [
+ "frameworks/av/media/extractors/",
+ "frameworks/av/media/libstagefright/",
+ ],
+
+ compile_multilib: "first",
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ ldflags: [
+ "-Wl",
+ "-Bsymbolic",
+ // to ignore duplicate symbol: GETEXTRACTORDEF
+ "-z muldefs",
+ ],
+
+ sanitize: {
+ cfi: true,
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ },
+}
diff --git a/media/extractors/tests/AndroidTest.xml b/media/extractors/tests/AndroidTest.xml
new file mode 100644
index 0000000..6bb2c8a
--- /dev/null
+++ b/media/extractors/tests/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Test module config for extractor unit tests">
+ <option name="test-suite-tag" value="ExtractorUnitTest" />
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="ExtractorUnitTest->/data/local/tmp/ExtractorUnitTest" />
+ <option name="push-file"
+ key="https://storage.googleapis.com/android_media/frameworks/av/media/extractors/tests/extractor.zip?unzip=true"
+ value="/data/local/tmp/ExtractorUnitTestRes/" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="ExtractorUnitTest" />
+ <option name="native-test-flag" value="-P /data/local/tmp/ExtractorUnitTestRes/" />
+ </test>
+</configuration>
diff --git a/media/extractors/tests/ExtractorUnitTest.cpp b/media/extractors/tests/ExtractorUnitTest.cpp
new file mode 100644
index 0000000..518166e
--- /dev/null
+++ b/media/extractors/tests/ExtractorUnitTest.cpp
@@ -0,0 +1,528 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ExtractorUnitTest"
+#include <utils/Log.h>
+
+#include <datasource/FileSource.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaDataUtils.h>
+
+#include "aac/AACExtractor.h"
+#include "amr/AMRExtractor.h"
+#include "flac/FLACExtractor.h"
+#include "midi/MidiExtractor.h"
+#include "mkv/MatroskaExtractor.h"
+#include "mp3/MP3Extractor.h"
+#include "mp4/MPEG4Extractor.h"
+#include "mp4/SampleTable.h"
+#include "mpeg2/MPEG2PSExtractor.h"
+#include "mpeg2/MPEG2TSExtractor.h"
+#include "ogg/OggExtractor.h"
+#include "wav/WAVExtractor.h"
+
+#include "ExtractorUnitTestEnvironment.h"
+
+using namespace android;
+
+#define OUTPUT_DUMP_FILE "/data/local/tmp/extractorOutput"
+
+constexpr int32_t kMaxCount = 10;
+constexpr int32_t kOpusSeekPreRollUs = 80000; // 80 ms;
+
+static ExtractorUnitTestEnvironment *gEnv = nullptr;
+
+class ExtractorUnitTest : public ::testing::TestWithParam<pair<string, string>> {
+ public:
+ ExtractorUnitTest() : mInputFp(nullptr), mDataSource(nullptr), mExtractor(nullptr) {}
+
+ ~ExtractorUnitTest() {
+ if (mInputFp) {
+ fclose(mInputFp);
+ mInputFp = nullptr;
+ }
+ if (mDataSource) {
+ mDataSource.clear();
+ mDataSource = nullptr;
+ }
+ if (mExtractor) {
+ delete mExtractor;
+ mExtractor = nullptr;
+ }
+ }
+
+ virtual void SetUp() override {
+ mExtractorName = unknown_comp;
+ mDisableTest = false;
+
+ static const std::map<std::string, standardExtractors> mapExtractor = {
+ {"aac", AAC}, {"amr", AMR}, {"mp3", MP3}, {"ogg", OGG},
+ {"wav", WAV}, {"mkv", MKV}, {"flac", FLAC}, {"midi", MIDI},
+ {"mpeg4", MPEG4}, {"mpeg2ts", MPEG2TS}, {"mpeg2ps", MPEG2PS}};
+ // Find the component type
+ string writerFormat = GetParam().first;
+ if (mapExtractor.find(writerFormat) != mapExtractor.end()) {
+ mExtractorName = mapExtractor.at(writerFormat);
+ }
+ if (mExtractorName == standardExtractors::unknown_comp) {
+ cout << "[ WARN ] Test Skipped. Invalid extractor\n";
+ mDisableTest = true;
+ }
+ }
+
+ int32_t setDataSource(string inputFileName);
+
+ int32_t createExtractor();
+
+ enum standardExtractors {
+ AAC,
+ AMR,
+ FLAC,
+ MIDI,
+ MKV,
+ MP3,
+ MPEG4,
+ MPEG2PS,
+ MPEG2TS,
+ OGG,
+ WAV,
+ unknown_comp,
+ };
+
+ bool mDisableTest;
+ standardExtractors mExtractorName;
+
+ FILE *mInputFp;
+ sp<DataSource> mDataSource;
+ MediaExtractorPluginHelper *mExtractor;
+};
+
+int32_t ExtractorUnitTest::setDataSource(string inputFileName) {
+ mInputFp = fopen(inputFileName.c_str(), "rb");
+ if (!mInputFp) {
+ ALOGE("Unable to open input file for reading");
+ return -1;
+ }
+ struct stat buf;
+ stat(inputFileName.c_str(), &buf);
+ int32_t fd = fileno(mInputFp);
+ mDataSource = new FileSource(dup(fd), 0, buf.st_size);
+ if (!mDataSource) return -1;
+ return 0;
+}
+
+int32_t ExtractorUnitTest::createExtractor() {
+ switch (mExtractorName) {
+ case AAC:
+ mExtractor = new AACExtractor(new DataSourceHelper(mDataSource->wrap()), 0);
+ break;
+ case AMR:
+ mExtractor = new AMRExtractor(new DataSourceHelper(mDataSource->wrap()));
+ break;
+ case MP3:
+ mExtractor = new MP3Extractor(new DataSourceHelper(mDataSource->wrap()), nullptr);
+ break;
+ case OGG:
+ mExtractor = new OggExtractor(new DataSourceHelper(mDataSource->wrap()));
+ break;
+ case WAV:
+ mExtractor = new WAVExtractor(new DataSourceHelper(mDataSource->wrap()));
+ break;
+ case MKV:
+ mExtractor = new MatroskaExtractor(new DataSourceHelper(mDataSource->wrap()));
+ break;
+ case FLAC:
+ mExtractor = new FLACExtractor(new DataSourceHelper(mDataSource->wrap()));
+ break;
+ case MPEG4:
+ mExtractor = new MPEG4Extractor(new DataSourceHelper(mDataSource->wrap()));
+ break;
+ case MPEG2TS:
+ mExtractor = new MPEG2TSExtractor(new DataSourceHelper(mDataSource->wrap()));
+ break;
+ case MPEG2PS:
+ mExtractor = new MPEG2PSExtractor(new DataSourceHelper(mDataSource->wrap()));
+ break;
+ case MIDI:
+ mExtractor = new MidiExtractor(mDataSource->wrap());
+ break;
+ default:
+ return -1;
+ }
+ if (!mExtractor) return -1;
+ return 0;
+}
+
+void getSeekablePoints(vector<int64_t> &seekablePoints, MediaTrackHelper *track) {
+ int32_t status = 0;
+ if (!seekablePoints.empty()) {
+ seekablePoints.clear();
+ }
+ int64_t timeStamp;
+ while (status != AMEDIA_ERROR_END_OF_STREAM) {
+ MediaBufferHelper *buffer = nullptr;
+ status = track->read(&buffer);
+ if (buffer) {
+ AMediaFormat *metaData = buffer->meta_data();
+ int32_t isSync = 0;
+ AMediaFormat_getInt32(metaData, AMEDIAFORMAT_KEY_IS_SYNC_FRAME, &isSync);
+ if (isSync) {
+ AMediaFormat_getInt64(metaData, AMEDIAFORMAT_KEY_TIME_US, &timeStamp);
+ seekablePoints.push_back(timeStamp);
+ }
+ buffer->release();
+ }
+ }
+}
+
+TEST_P(ExtractorUnitTest, CreateExtractorTest) {
+ if (mDisableTest) return;
+
+ ALOGV("Checks if a valid extractor is created for a given input file");
+ string inputFileName = gEnv->getRes() + GetParam().second;
+
+ ASSERT_EQ(setDataSource(inputFileName), 0)
+ << "SetDataSource failed for" << GetParam().first << "extractor";
+
+ ASSERT_EQ(createExtractor(), 0)
+ << "Extractor creation failed for" << GetParam().first << "extractor";
+
+ // A valid extractor instace should return success for following calls
+ ASSERT_GT(mExtractor->countTracks(), 0);
+
+ AMediaFormat *format = AMediaFormat_new();
+ ASSERT_NE(format, nullptr) << "AMediaFormat_new returned null AMediaformat";
+
+ ASSERT_EQ(mExtractor->getMetaData(format), AMEDIA_OK);
+ AMediaFormat_delete(format);
+}
+
+TEST_P(ExtractorUnitTest, ExtractorTest) {
+ if (mDisableTest) return;
+
+ ALOGV("Validates %s Extractor for a given input file", GetParam().first.c_str());
+ string inputFileName = gEnv->getRes() + GetParam().second;
+
+ int32_t status = setDataSource(inputFileName);
+ ASSERT_EQ(status, 0) << "SetDataSource failed for" << GetParam().first << "extractor";
+
+ status = createExtractor();
+ ASSERT_EQ(status, 0) << "Extractor creation failed for" << GetParam().first << "extractor";
+
+ int32_t numTracks = mExtractor->countTracks();
+ ASSERT_GT(numTracks, 0) << "Extractor didn't find any track for the given clip";
+
+ for (int32_t idx = 0; idx < numTracks; idx++) {
+ MediaTrackHelper *track = mExtractor->getTrack(idx);
+ ASSERT_NE(track, nullptr) << "Failed to get track for index " << idx;
+
+ CMediaTrack *cTrack = wrap(track);
+ ASSERT_NE(cTrack, nullptr) << "Failed to get track wrapper for index " << idx;
+
+ MediaBufferGroup *bufferGroup = new MediaBufferGroup();
+ status = cTrack->start(track, bufferGroup->wrap());
+ ASSERT_EQ(OK, (media_status_t)status) << "Failed to start the track";
+
+ FILE *outFp = fopen((OUTPUT_DUMP_FILE + to_string(idx)).c_str(), "wb");
+ if (!outFp) {
+ ALOGW("Unable to open output file for dumping extracted stream");
+ }
+
+ while (status != AMEDIA_ERROR_END_OF_STREAM) {
+ MediaBufferHelper *buffer = nullptr;
+ status = track->read(&buffer);
+ ALOGV("track->read Status = %d buffer %p", status, buffer);
+ if (buffer) {
+ ALOGV("buffer->data %p buffer->size() %zu buffer->range_length() %zu",
+ buffer->data(), buffer->size(), buffer->range_length());
+ if (outFp) fwrite(buffer->data(), 1, buffer->range_length(), outFp);
+ buffer->release();
+ }
+ }
+ if (outFp) fclose(outFp);
+ status = cTrack->stop(track);
+ ASSERT_EQ(OK, status) << "Failed to stop the track";
+ delete bufferGroup;
+ delete track;
+ }
+}
+
+TEST_P(ExtractorUnitTest, MetaDataComparisonTest) {
+ if (mDisableTest) return;
+
+ ALOGV("Validates Extractor's meta data for a given input file");
+ string inputFileName = gEnv->getRes() + GetParam().second;
+
+ int32_t status = setDataSource(inputFileName);
+ ASSERT_EQ(status, 0) << "SetDataSource failed for" << GetParam().first << "extractor";
+
+ status = createExtractor();
+ ASSERT_EQ(status, 0) << "Extractor creation failed for" << GetParam().first << "extractor";
+
+ int32_t numTracks = mExtractor->countTracks();
+ ASSERT_GT(numTracks, 0) << "Extractor didn't find any track for the given clip";
+
+ AMediaFormat *extractorFormat = AMediaFormat_new();
+ ASSERT_NE(extractorFormat, nullptr) << "AMediaFormat_new returned null AMediaformat";
+ AMediaFormat *trackFormat = AMediaFormat_new();
+ ASSERT_NE(trackFormat, nullptr) << "AMediaFormat_new returned null AMediaformat";
+
+ for (int32_t idx = 0; idx < numTracks; idx++) {
+ MediaTrackHelper *track = mExtractor->getTrack(idx);
+ ASSERT_NE(track, nullptr) << "Failed to get track for index " << idx;
+
+ CMediaTrack *cTrack = wrap(track);
+ ASSERT_NE(cTrack, nullptr) << "Failed to get track wrapper for index " << idx;
+
+ MediaBufferGroup *bufferGroup = new MediaBufferGroup();
+ status = cTrack->start(track, bufferGroup->wrap());
+ ASSERT_EQ(OK, (media_status_t)status) << "Failed to start the track";
+
+ status = mExtractor->getTrackMetaData(extractorFormat, idx, 1);
+ ASSERT_EQ(OK, (media_status_t)status) << "Failed to get trackMetaData";
+
+ status = track->getFormat(trackFormat);
+ ASSERT_EQ(OK, (media_status_t)status) << "Failed to get track meta data";
+
+ const char *extractorMime, *trackMime;
+ AMediaFormat_getString(extractorFormat, AMEDIAFORMAT_KEY_MIME, &extractorMime);
+ AMediaFormat_getString(trackFormat, AMEDIAFORMAT_KEY_MIME, &trackMime);
+ ASSERT_TRUE(!strcmp(extractorMime, trackMime))
+ << "Extractor's format doesn't match track format";
+
+ if (!strncmp(extractorMime, "audio/", 6)) {
+ int32_t exSampleRate, exChannelCount;
+ int32_t trackSampleRate, trackChannelCount;
+ ASSERT_TRUE(AMediaFormat_getInt32(extractorFormat, AMEDIAFORMAT_KEY_CHANNEL_COUNT,
+ &exChannelCount));
+ ASSERT_TRUE(AMediaFormat_getInt32(extractorFormat, AMEDIAFORMAT_KEY_SAMPLE_RATE,
+ &exSampleRate));
+ ASSERT_TRUE(AMediaFormat_getInt32(trackFormat, AMEDIAFORMAT_KEY_CHANNEL_COUNT,
+ &trackChannelCount));
+ ASSERT_TRUE(AMediaFormat_getInt32(trackFormat, AMEDIAFORMAT_KEY_SAMPLE_RATE,
+ &trackSampleRate));
+ ASSERT_EQ(exChannelCount, trackChannelCount) << "ChannelCount not as expected";
+ ASSERT_EQ(exSampleRate, trackSampleRate) << "SampleRate not as expected";
+ } else {
+ int32_t exWidth, exHeight;
+ int32_t trackWidth, trackHeight;
+ ASSERT_TRUE(AMediaFormat_getInt32(extractorFormat, AMEDIAFORMAT_KEY_WIDTH, &exWidth));
+ ASSERT_TRUE(AMediaFormat_getInt32(extractorFormat, AMEDIAFORMAT_KEY_HEIGHT, &exHeight));
+ ASSERT_TRUE(AMediaFormat_getInt32(trackFormat, AMEDIAFORMAT_KEY_WIDTH, &trackWidth));
+ ASSERT_TRUE(AMediaFormat_getInt32(trackFormat, AMEDIAFORMAT_KEY_HEIGHT, &trackHeight));
+ ASSERT_EQ(exWidth, trackWidth) << "Width not as expected";
+ ASSERT_EQ(exHeight, trackHeight) << "Height not as expected";
+ }
+ status = cTrack->stop(track);
+ ASSERT_EQ(OK, status) << "Failed to stop the track";
+ delete bufferGroup;
+ delete track;
+ }
+ AMediaFormat_delete(trackFormat);
+ AMediaFormat_delete(extractorFormat);
+}
+
+TEST_P(ExtractorUnitTest, MultipleStartStopTest) {
+ if (mDisableTest) return;
+
+ ALOGV("Test %s extractor for multiple start and stop calls", GetParam().first.c_str());
+ string inputFileName = gEnv->getRes() + GetParam().second;
+
+ int32_t status = setDataSource(inputFileName);
+ ASSERT_EQ(status, 0) << "SetDataSource failed for" << GetParam().first << "extractor";
+
+ status = createExtractor();
+ ASSERT_EQ(status, 0) << "Extractor creation failed for" << GetParam().first << "extractor";
+
+ int32_t numTracks = mExtractor->countTracks();
+ ASSERT_GT(numTracks, 0) << "Extractor didn't find any track for the given clip";
+
+ // start/stop the tracks multiple times
+ for (int32_t count = 0; count < kMaxCount; count++) {
+ for (int32_t idx = 0; idx < numTracks; idx++) {
+ MediaTrackHelper *track = mExtractor->getTrack(idx);
+ ASSERT_NE(track, nullptr) << "Failed to get track for index " << idx;
+
+ CMediaTrack *cTrack = wrap(track);
+ ASSERT_NE(cTrack, nullptr) << "Failed to get track wrapper for index " << idx;
+
+ MediaBufferGroup *bufferGroup = new MediaBufferGroup();
+ status = cTrack->start(track, bufferGroup->wrap());
+ ASSERT_EQ(OK, (media_status_t)status) << "Failed to start the track";
+ MediaBufferHelper *buffer = nullptr;
+ status = track->read(&buffer);
+ if (buffer) {
+ ALOGV("buffer->data %p buffer->size() %zu buffer->range_length() %zu",
+ buffer->data(), buffer->size(), buffer->range_length());
+ buffer->release();
+ }
+ status = cTrack->stop(track);
+ ASSERT_EQ(OK, status) << "Failed to stop the track";
+ delete bufferGroup;
+ delete track;
+ }
+ }
+}
+
+TEST_P(ExtractorUnitTest, SeekTest) {
+ // Both Flac and Wav extractor can give samples from any pts and mark the given sample as
+ // sync frame. So, this seek test is not applicable to FLAC and WAV extractors
+ if (mDisableTest || mExtractorName == FLAC || mExtractorName == WAV) return;
+
+ ALOGV("Validates %s Extractor behaviour for different seek modes", GetParam().first.c_str());
+ string inputFileName = gEnv->getRes() + GetParam().second;
+
+ int32_t status = setDataSource(inputFileName);
+ ASSERT_EQ(status, 0) << "SetDataSource failed for" << GetParam().first << "extractor";
+
+ status = createExtractor();
+ ASSERT_EQ(status, 0) << "Extractor creation failed for" << GetParam().first << "extractor";
+
+ int32_t numTracks = mExtractor->countTracks();
+ ASSERT_GT(numTracks, 0) << "Extractor didn't find any track for the given clip";
+
+ uint32_t seekFlag = mExtractor->flags();
+ if (!(seekFlag & MediaExtractorPluginHelper::CAN_SEEK)) {
+ cout << "[ WARN ] Test Skipped. " << GetParam().first
+ << " Extractor doesn't support seek\n";
+ return;
+ }
+
+ vector<int64_t> seekablePoints;
+ for (int32_t idx = 0; idx < numTracks; idx++) {
+ MediaTrackHelper *track = mExtractor->getTrack(idx);
+ ASSERT_NE(track, nullptr) << "Failed to get track for index " << idx;
+
+ CMediaTrack *cTrack = wrap(track);
+ ASSERT_NE(cTrack, nullptr) << "Failed to get track wrapper for index " << idx;
+
+ // Get all the seekable points of a given input
+ MediaBufferGroup *bufferGroup = new MediaBufferGroup();
+ status = cTrack->start(track, bufferGroup->wrap());
+ ASSERT_EQ(OK, (media_status_t)status) << "Failed to start the track";
+ getSeekablePoints(seekablePoints, track);
+ ASSERT_GT(seekablePoints.size(), 0)
+ << "Failed to get seekable points for " << GetParam().first << " extractor";
+
+ AMediaFormat *trackFormat = AMediaFormat_new();
+ ASSERT_NE(trackFormat, nullptr) << "AMediaFormat_new returned null format";
+ status = track->getFormat(trackFormat);
+ ASSERT_EQ(OK, (media_status_t)status) << "Failed to get track meta data";
+
+ bool isOpus = false;
+ const char *mime;
+ AMediaFormat_getString(trackFormat, AMEDIAFORMAT_KEY_MIME, &mime);
+ if (!strcmp(mime, "audio/opus")) isOpus = true;
+ AMediaFormat_delete(trackFormat);
+
+ int32_t seekIdx = 0;
+ size_t seekablePointsSize = seekablePoints.size();
+ for (int32_t mode = CMediaTrackReadOptions::SEEK_PREVIOUS_SYNC;
+ mode <= CMediaTrackReadOptions::SEEK_CLOSEST; mode++) {
+ for (int32_t seekCount = 0; seekCount < kMaxCount; seekCount++) {
+ seekIdx = rand() % seekablePointsSize + 1;
+ if (seekIdx >= seekablePointsSize) seekIdx = seekablePointsSize - 1;
+
+ int64_t seekToTimeStamp = seekablePoints[seekIdx];
+ if (seekablePointsSize > 1) {
+ int64_t prevTimeStamp = seekablePoints[seekIdx - 1];
+ seekToTimeStamp = seekToTimeStamp - ((seekToTimeStamp - prevTimeStamp) >> 3);
+ }
+
+ // Opus has a seekPreRollUs. TimeStamp returned by the
+ // extractor is calculated based on (seekPts - seekPreRollUs).
+ // So we add the preRoll value to the timeStamp we want to seek to.
+ if (isOpus) {
+ seekToTimeStamp += kOpusSeekPreRollUs;
+ }
+
+ MediaTrackHelper::ReadOptions *options = new MediaTrackHelper::ReadOptions(
+ mode | CMediaTrackReadOptions::SEEK, seekToTimeStamp);
+ ASSERT_NE(options, nullptr) << "Cannot create read option";
+
+ MediaBufferHelper *buffer = nullptr;
+ status = track->read(&buffer, options);
+ if (status == AMEDIA_ERROR_END_OF_STREAM) {
+ delete options;
+ continue;
+ }
+ if (buffer) {
+ AMediaFormat *metaData = buffer->meta_data();
+ int64_t timeStamp;
+ AMediaFormat_getInt64(metaData, AMEDIAFORMAT_KEY_TIME_US, &timeStamp);
+ buffer->release();
+
+ // CMediaTrackReadOptions::SEEK is 8. Using mask 0111b to get true modes
+ switch (mode & 0x7) {
+ case CMediaTrackReadOptions::SEEK_PREVIOUS_SYNC:
+ if (seekablePointsSize == 1) {
+ EXPECT_EQ(timeStamp, seekablePoints[seekIdx]);
+ } else {
+ EXPECT_EQ(timeStamp, seekablePoints[seekIdx - 1]);
+ }
+ break;
+ case CMediaTrackReadOptions::SEEK_NEXT_SYNC:
+ case CMediaTrackReadOptions::SEEK_CLOSEST_SYNC:
+ case CMediaTrackReadOptions::SEEK_CLOSEST:
+ EXPECT_EQ(timeStamp, seekablePoints[seekIdx]);
+ break;
+ default:
+ break;
+ }
+ }
+ delete options;
+ }
+ }
+ status = cTrack->stop(track);
+ ASSERT_EQ(OK, status) << "Failed to stop the track";
+ delete bufferGroup;
+ delete track;
+ }
+ seekablePoints.clear();
+}
+
+// TODO: (b/145332185)
+// Add MIDI inputs
+INSTANTIATE_TEST_SUITE_P(ExtractorUnitTestAll, ExtractorUnitTest,
+ ::testing::Values(make_pair("aac", "loudsoftaac.aac"),
+ make_pair("amr", "testamr.amr"),
+ make_pair("amr", "amrwb.wav"),
+ make_pair("ogg", "john_cage.ogg"),
+ make_pair("wav", "monotestgsm.wav"),
+ make_pair("mpeg2ts", "segment000001.ts"),
+ make_pair("flac", "sinesweepflac.flac"),
+ make_pair("ogg", "testopus.opus"),
+ make_pair("mkv", "sinesweepvorbis.mkv"),
+ make_pair("mpeg4", "sinesweepoggmp4.mp4"),
+ make_pair("mp3", "sinesweepmp3lame.mp3"),
+ make_pair("mkv", "swirl_144x136_vp9.webm"),
+ make_pair("mkv", "swirl_144x136_vp8.webm"),
+ make_pair("mpeg2ps", "swirl_144x136_mpeg2.mpg"),
+ make_pair("mpeg4", "swirl_132x130_mpeg4.mp4")));
+
+int main(int argc, char **argv) {
+ gEnv = new ExtractorUnitTestEnvironment();
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = gEnv->initFromOptions(argc, argv);
+ if (status == 0) {
+ status = RUN_ALL_TESTS();
+ ALOGV("Test result = %d\n", status);
+ }
+ return status;
+}
diff --git a/media/extractors/tests/ExtractorUnitTestEnvironment.h b/media/extractors/tests/ExtractorUnitTestEnvironment.h
new file mode 100644
index 0000000..fce8fc2
--- /dev/null
+++ b/media/extractors/tests/ExtractorUnitTestEnvironment.h
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#ifndef __EXTRACTOR_UNIT_TEST_ENVIRONMENT_H__
+#define __EXTRACTOR_UNIT_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class ExtractorUnitTestEnvironment : public ::testing::Environment {
+ public:
+ ExtractorUnitTestEnvironment() : res("/data/local/tmp/") {}
+
+ // Parses the command line arguments
+ int initFromOptions(int argc, char **argv);
+
+ void setRes(const char *_res) { res = _res; }
+
+ const string getRes() const { return res; }
+
+ private:
+ string res;
+};
+
+int ExtractorUnitTestEnvironment::initFromOptions(int argc, char **argv) {
+ static struct option options[] = {{"res", required_argument, 0, 'P'}, {0, 0, 0, 0}};
+
+ while (true) {
+ int index = 0;
+ int c = getopt_long(argc, argv, "P:", options, &index);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'P':
+ setRes(optarg);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (optind < argc) {
+ fprintf(stderr,
+ "unrecognized option: %s\n\n"
+ "usage: %s <gtest options> <test options>\n\n"
+ "test options are:\n\n"
+ "-P, --path: Resource files directory location\n",
+ argv[optind ?: 1], argv[0]);
+ return 2;
+ }
+ return 0;
+}
+
+#endif // __EXTRACTOR_UNIT_TEST_ENVIRONMENT_H__
diff --git a/media/extractors/tests/README.md b/media/extractors/tests/README.md
new file mode 100644
index 0000000..69538b6
--- /dev/null
+++ b/media/extractors/tests/README.md
@@ -0,0 +1,39 @@
+## Media Testing ##
+---
+#### Extractor :
+The Extractor Test Suite validates the extractors available in the device.
+
+Run the following steps to build the test suite:
+```
+m ExtractorUnitTest
+```
+
+The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/
+
+The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/
+
+To test 64-bit binary push binaries from nativetest64.
+```
+adb push ${OUT}/data/nativetest64/ExtractorUnitTest/ExtractorUnitTest /data/local/tmp/
+```
+
+To test 32-bit binary push binaries from nativetest.
+```
+adb push ${OUT}/data/nativetest/ExtractorUnitTest/ExtractorUnitTest /data/local/tmp/
+```
+
+The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/extractors/tests/extractor.zip). Download, unzip and push these files into device for testing.
+
+```
+adb push extractor /data/local/tmp/
+```
+
+usage: ExtractorUnitTest -P \<path_to_folder\>
+```
+adb shell /data/local/tmp/ExtractorUnitTest -P /data/local/tmp/extractor/
+```
+Alternatively, the test can also be run using atest command.
+
+```
+atest ExtractorUnitTest -- --enable-module-dynamic-download=true
+```
diff --git a/media/extractors/wav/Android.bp b/media/extractors/wav/Android.bp
index 7e89271..8ce5c3f 100644
--- a/media/extractors/wav/Android.bp
+++ b/media/extractors/wav/Android.bp
@@ -1,4 +1,7 @@
-cc_library_shared {
+cc_library {
+ name: "libwavextractor",
+
+ defaults: ["extractor-defaults"],
srcs: ["WAVExtractor.cpp"],
@@ -8,8 +11,6 @@
shared_libs: [
"libbinder_ndk",
- "liblog",
- "libmediandk",
],
static_libs: [
@@ -17,25 +18,4 @@
"libfifo",
"libstagefright_foundation",
],
-
- name: "libwavextractor",
- relative_install_path: "extractors",
-
- compile_multilib: "first",
-
- cflags: [
- "-Werror",
- "-Wall",
- "-fvisibility=hidden",
- ],
- version_script: "exports.lds",
-
- sanitize: {
- cfi: true,
- misc_undefined: [
- "unsigned-integer-overflow",
- "signed-integer-overflow",
- ],
- },
-
}
diff --git a/media/libaaudio/Android.bp b/media/libaaudio/Android.bp
index 16958f9..140052f 100644
--- a/media/libaaudio/Android.bp
+++ b/media/libaaudio/Android.bp
@@ -24,7 +24,7 @@
ndk_library {
name: "libaaudio",
// deliberately includes symbols from AAudioTesting.h
- symbol_file: "libaaudio.map.txt",
+ symbol_file: "src/libaaudio.map.txt",
first_version: "26",
unversioned_until: "current",
}
@@ -32,6 +32,5 @@
cc_library_headers {
name: "libaaudio_headers",
export_include_dirs: ["include"],
- version_script: "libaaudio.map.txt",
}
diff --git a/media/libaaudio/examples/input_monitor/Android.bp b/media/libaaudio/examples/input_monitor/Android.bp
index 5d399b5..d8c5843 100644
--- a/media/libaaudio/examples/input_monitor/Android.bp
+++ b/media/libaaudio/examples/input_monitor/Android.bp
@@ -5,7 +5,6 @@
cflags: ["-Wall", "-Werror"],
shared_libs: ["libaaudio"],
header_libs: ["libaaudio_example_utils"],
- pack_relocations: false,
}
cc_test {
@@ -15,5 +14,4 @@
cflags: ["-Wall", "-Werror"],
shared_libs: ["libaaudio"],
header_libs: ["libaaudio_example_utils"],
- pack_relocations: false,
}
diff --git a/media/libaaudio/examples/loopback/Android.bp b/media/libaaudio/examples/loopback/Android.bp
index 53e5020..5b7d956 100644
--- a/media/libaaudio/examples/loopback/Android.bp
+++ b/media/libaaudio/examples/loopback/Android.bp
@@ -9,5 +9,4 @@
"libaudioutils",
],
header_libs: ["libaaudio_example_utils"],
- pack_relocations: false,
}
diff --git a/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h b/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
deleted file mode 100644
index 8eb70b1..0000000
--- a/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
+++ /dev/null
@@ -1,1114 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-/**
- * Tools for measuring latency and for detecting glitches.
- * These classes are pure math and can be used with any audio system.
- */
-
-#ifndef AAUDIO_EXAMPLES_LOOPBACK_ANALYSER_H
-#define AAUDIO_EXAMPLES_LOOPBACK_ANALYSER_H
-
-#include <algorithm>
-#include <assert.h>
-#include <cctype>
-#include <math.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <audio_utils/sndfile.h>
-
-// Tag for machine readable results as property = value pairs
-#define LOOPBACK_RESULT_TAG "RESULT: "
-
-constexpr int32_t kDefaultSampleRate = 48000;
-constexpr int32_t kMillisPerSecond = 1000;
-constexpr int32_t kMinLatencyMillis = 4; // arbitrary and very low
-constexpr int32_t kMaxLatencyMillis = 400; // arbitrary and generous
-constexpr double kMaxEchoGain = 10.0; // based on experiments, otherwise too noisy
-constexpr double kMinimumConfidence = 0.5;
-
-static void printAudioScope(float sample) {
- const int maxStars = 80; // arbitrary, fits on one line
- char c = '*';
- if (sample < -1.0) {
- sample = -1.0;
- c = '$';
- } else if (sample > 1.0) {
- sample = 1.0;
- c = '$';
- }
- int numSpaces = (int) (((sample + 1.0) * 0.5) * maxStars);
- for (int i = 0; i < numSpaces; i++) {
- putchar(' ');
- }
- printf("%c\n", c);
-}
-
-/*
-
-FIR filter designed with
-http://t-filter.appspot.com
-
-sampling frequency: 48000 Hz
-
-* 0 Hz - 8000 Hz
- gain = 1.2
- desired ripple = 5 dB
- actual ripple = 5.595266169703693 dB
-
-* 12000 Hz - 20000 Hz
- gain = 0
- desired attenuation = -40 dB
- actual attenuation = -37.58691566571914 dB
-
-*/
-
-#define FILTER_TAP_NUM 11
-
-static const float sFilterTaps8000[FILTER_TAP_NUM] = {
- -0.05944219353343189f,
- -0.07303434839503208f,
- -0.037690487672689066f,
- 0.1870480506596512f,
- 0.3910337357836833f,
- 0.5333672385425637f,
- 0.3910337357836833f,
- 0.1870480506596512f,
- -0.037690487672689066f,
- -0.07303434839503208f,
- -0.05944219353343189f
-};
-
-class LowPassFilter {
-public:
-
- /*
- * Filter one input sample.
- * @return filtered output
- */
- float filter(float input) {
- float output = 0.0f;
- mX[mCursor] = input;
- // Index backwards over x.
- int xIndex = mCursor + FILTER_TAP_NUM;
- // Write twice so we avoid having to wrap in the middle of the convolution.
- mX[xIndex] = input;
- for (int i = 0; i < FILTER_TAP_NUM; i++) {
- output += sFilterTaps8000[i] * mX[xIndex--];
- }
- if (++mCursor >= FILTER_TAP_NUM) {
- mCursor = 0;
- }
- return output;
- }
-
- /**
- * @return true if PASSED
- */
- bool test() {
- // Measure the impulse of the filter at different phases so we exercise
- // all the wraparound cases in the FIR.
- for (int offset = 0; offset < (FILTER_TAP_NUM * 2); offset++ ) {
- // printf("LowPassFilter: cursor = %d\n", mCursor);
- // Offset by one each time.
- if (filter(0.0f) != 0.0f) {
- printf("ERROR: filter should return 0.0 before impulse response\n");
- return false;
- }
- for (int i = 0; i < FILTER_TAP_NUM; i++) {
- float output = filter((i == 0) ? 1.0f : 0.0f); // impulse
- if (output != sFilterTaps8000[i]) {
- printf("ERROR: filter should return impulse response\n");
- return false;
- }
- }
- for (int i = 0; i < FILTER_TAP_NUM; i++) {
- if (filter(0.0f) != 0.0f) {
- printf("ERROR: filter should return 0.0 after impulse response\n");
- return false;
- }
- }
- }
- return true;
- }
-
-private:
- float mX[FILTER_TAP_NUM * 2]{}; // twice as big as needed to avoid wrapping
- int32_t mCursor = 0;
-};
-
-// A narrow impulse seems to have better immunity against over estimating the
-// latency due to detecting subharmonics by the auto-correlator.
-static const float s_Impulse[] = {
- 0.0f, 0.0f, 0.0f, 0.0f, 0.3f, // silence on each side of the impulse
- 0.99f, 0.0f, -0.99f, // bipolar with one zero crossing in middle
- -0.3f, 0.0f, 0.0f, 0.0f, 0.0f
-};
-
-constexpr int32_t kImpulseSizeInFrames = (int32_t)(sizeof(s_Impulse) / sizeof(s_Impulse[0]));
-
-class PseudoRandom {
-public:
- PseudoRandom() {}
- PseudoRandom(int64_t seed)
- : mSeed(seed)
- {}
-
- /**
- * Returns the next random double from -1.0 to 1.0
- *
- * @return value from -1.0 to 1.0
- */
- double nextRandomDouble() {
- return nextRandomInteger() * (0.5 / (((int32_t)1) << 30));
- }
-
- /** Calculate random 32 bit number using linear-congruential method. */
- int32_t nextRandomInteger() {
- // Use values for 64-bit sequence from MMIX by Donald Knuth.
- mSeed = (mSeed * (int64_t)6364136223846793005) + (int64_t)1442695040888963407;
- return (int32_t) (mSeed >> 32); // The higher bits have a longer sequence.
- }
-
-private:
- int64_t mSeed = 99887766;
-};
-
-
-typedef struct LatencyReport_s {
- double latencyInFrames;
- double confidence;
-} LatencyReport;
-
-static double calculateCorrelation(const float *a,
- const float *b,
- int windowSize)
-{
- double correlation = 0.0;
- double sumProducts = 0.0;
- double sumSquares = 0.0;
-
- // Correlate a against b.
- for (int i = 0; i < windowSize; i++) {
- float s1 = a[i];
- float s2 = b[i];
- // Use a normalized cross-correlation.
- sumProducts += s1 * s2;
- sumSquares += ((s1 * s1) + (s2 * s2));
- }
-
- if (sumSquares >= 0.00000001) {
- correlation = (float) (2.0 * sumProducts / sumSquares);
- }
- return correlation;
-}
-
-static int measureLatencyFromEchos(const float *data,
- int32_t numFloats,
- int32_t sampleRate,
- LatencyReport *report) {
- // Allocate results array
- const int minReasonableLatencyFrames = sampleRate * kMinLatencyMillis / kMillisPerSecond;
- const int maxReasonableLatencyFrames = sampleRate * kMaxLatencyMillis / kMillisPerSecond;
- int32_t maxCorrelationSize = maxReasonableLatencyFrames * 3;
- int numCorrelations = std::min(numFloats, maxCorrelationSize);
- float *correlations = new float[numCorrelations]{};
- float *harmonicSums = new float[numCorrelations]{};
-
- // Perform sliding auto-correlation.
- // Skip first frames to avoid huge peak at zero offset.
- for (int i = minReasonableLatencyFrames; i < numCorrelations; i++) {
- int32_t remaining = numFloats - i;
- float correlation = (float) calculateCorrelation(&data[i], data, remaining);
- correlations[i] = correlation;
- // printf("correlation[%d] = %f\n", ic, correlation);
- }
-
- // Apply a technique similar to Harmonic Product Spectrum Analysis to find echo fundamental.
- // Add higher harmonics mapped onto lower harmonics. This reinforces the "fundamental" echo.
- const int numEchoes = 8;
- for (int partial = 1; partial < numEchoes; partial++) {
- for (int i = minReasonableLatencyFrames; i < numCorrelations; i++) {
- harmonicSums[i / partial] += correlations[i] / partial;
- }
- }
-
- // Find highest peak in correlation array.
- float maxCorrelation = 0.0;
- int peakIndex = 0;
- for (int i = 0; i < numCorrelations; i++) {
- if (harmonicSums[i] > maxCorrelation) {
- maxCorrelation = harmonicSums[i];
- peakIndex = i;
- // printf("maxCorrelation = %f at %d\n", maxCorrelation, peakIndex);
- }
- }
- report->latencyInFrames = peakIndex;
-/*
- {
- int32_t topPeak = peakIndex * 7 / 2;
- for (int i = 0; i < topPeak; i++) {
- float sample = harmonicSums[i];
- printf("%4d: %7.5f ", i, sample);
- printAudioScope(sample);
- }
- }
-*/
-
- // Calculate confidence.
- if (maxCorrelation < 0.001) {
- report->confidence = 0.0;
- } else {
- // Compare peak to average value around peak.
- int32_t numSamples = std::min(numCorrelations, peakIndex * 2);
- if (numSamples <= 0) {
- report->confidence = 0.0;
- } else {
- double sum = 0.0;
- for (int i = 0; i < numSamples; i++) {
- sum += harmonicSums[i];
- }
- const double average = sum / numSamples;
- const double ratio = average / maxCorrelation; // will be < 1.0
- report->confidence = 1.0 - sqrt(ratio);
- }
- }
-
- delete[] correlations;
- delete[] harmonicSums;
- return 0;
-}
-
-class AudioRecording
-{
-public:
- AudioRecording() {
- }
- ~AudioRecording() {
- delete[] mData;
- }
-
- void allocate(int maxFrames) {
- delete[] mData;
- mData = new float[maxFrames];
- mMaxFrames = maxFrames;
- }
-
- // Write SHORT data from the first channel.
- int32_t write(int16_t *inputData, int32_t inputChannelCount, int32_t numFrames) {
- // stop at end of buffer
- if ((mFrameCounter + numFrames) > mMaxFrames) {
- numFrames = mMaxFrames - mFrameCounter;
- }
- for (int i = 0; i < numFrames; i++) {
- mData[mFrameCounter++] = inputData[i * inputChannelCount] * (1.0f / 32768);
- }
- return numFrames;
- }
-
- // Write FLOAT data from the first channel.
- int32_t write(float *inputData, int32_t inputChannelCount, int32_t numFrames) {
- // stop at end of buffer
- if ((mFrameCounter + numFrames) > mMaxFrames) {
- numFrames = mMaxFrames - mFrameCounter;
- }
- for (int i = 0; i < numFrames; i++) {
- mData[mFrameCounter++] = inputData[i * inputChannelCount];
- }
- return numFrames;
- }
-
- int32_t size() {
- return mFrameCounter;
- }
-
- float *getData() {
- return mData;
- }
-
- void setSampleRate(int32_t sampleRate) {
- mSampleRate = sampleRate;
- }
-
- int32_t getSampleRate() {
- return mSampleRate;
- }
-
- int save(const char *fileName, bool writeShorts = true) {
- SNDFILE *sndFile = nullptr;
- int written = 0;
- SF_INFO info = {
- .frames = mFrameCounter,
- .samplerate = mSampleRate,
- .channels = 1,
- .format = SF_FORMAT_WAV | (writeShorts ? SF_FORMAT_PCM_16 : SF_FORMAT_FLOAT)
- };
-
- sndFile = sf_open(fileName, SFM_WRITE, &info);
- if (sndFile == nullptr) {
- printf("AudioRecording::save(%s) failed to open file\n", fileName);
- return -errno;
- }
-
- written = sf_writef_float(sndFile, mData, mFrameCounter);
-
- sf_close(sndFile);
- return written;
- }
-
- int load(const char *fileName) {
- SNDFILE *sndFile = nullptr;
- SF_INFO info;
-
- sndFile = sf_open(fileName, SFM_READ, &info);
- if (sndFile == nullptr) {
- printf("AudioRecording::load(%s) failed to open file\n", fileName);
- return -errno;
- }
-
- assert(info.channels == 1);
- assert(info.format == SF_FORMAT_FLOAT);
-
- setSampleRate(info.samplerate);
- allocate(info.frames);
- mFrameCounter = sf_readf_float(sndFile, mData, info.frames);
-
- sf_close(sndFile);
- return mFrameCounter;
- }
-
- /**
- * Square the samples so they are all positive and so the peaks are emphasized.
- */
- void square() {
- for (int i = 0; i < mFrameCounter; i++) {
- const float sample = mData[i];
- mData[i] = sample * sample;
- }
- }
-
- /**
- * Low pass filter the recording using a simple FIR filter.
- * Note that the lowpass filter cutoff tracks the sample rate.
- * That is OK because the impulse width is a fixed number of samples.
- */
- void lowPassFilter() {
- for (int i = 0; i < mFrameCounter; i++) {
- mData[i] = mLowPassFilter.filter(mData[i]);
- }
- }
-
- /**
- * Remove DC offset using a one-pole one-zero IIR filter.
- */
- void dcBlocker() {
- const float R = 0.996; // narrow notch at zero Hz
- float x1 = 0.0;
- float y1 = 0.0;
- for (int i = 0; i < mFrameCounter; i++) {
- const float x = mData[i];
- const float y = x - x1 + (R * y1);
- mData[i] = y;
- y1 = y;
- x1 = x;
- }
- }
-
-private:
- float *mData = nullptr;
- int32_t mFrameCounter = 0;
- int32_t mMaxFrames = 0;
- int32_t mSampleRate = kDefaultSampleRate; // common default
- LowPassFilter mLowPassFilter;
-};
-
-// ====================================================================================
-class LoopbackProcessor {
-public:
- virtual ~LoopbackProcessor() = default;
-
-
- enum process_result {
- PROCESS_RESULT_OK,
- PROCESS_RESULT_GLITCH
- };
-
- virtual void reset() {}
-
- virtual process_result process(float *inputData, int inputChannelCount,
- float *outputData, int outputChannelCount,
- int numFrames) = 0;
-
-
- virtual void report() = 0;
-
- virtual void printStatus() {};
-
- int32_t getResult() {
- return mResult;
- }
-
- void setResult(int32_t result) {
- mResult = result;
- }
-
- virtual bool isDone() {
- return false;
- }
-
- virtual int save(const char *fileName) {
- (void) fileName;
- return AAUDIO_ERROR_UNIMPLEMENTED;
- }
-
- virtual int load(const char *fileName) {
- (void) fileName;
- return AAUDIO_ERROR_UNIMPLEMENTED;
- }
-
- virtual void setSampleRate(int32_t sampleRate) {
- mSampleRate = sampleRate;
- }
-
- int32_t getSampleRate() {
- return mSampleRate;
- }
-
- // Measure peak amplitude of buffer.
- static float measurePeakAmplitude(float *inputData, int inputChannelCount, int numFrames) {
- float peak = 0.0f;
- for (int i = 0; i < numFrames; i++) {
- const float pos = fabs(*inputData);
- if (pos > peak) {
- peak = pos;
- }
- inputData += inputChannelCount;
- }
- return peak;
- }
-
-
-private:
- int32_t mSampleRate = kDefaultSampleRate;
- int32_t mResult = 0;
-};
-
-class PeakDetector {
-public:
- float process(float input) {
- float output = mPrevious * mDecay;
- if (input > output) {
- output = input;
- }
- mPrevious = output;
- return output;
- }
-
-private:
- float mDecay = 0.99f;
- float mPrevious = 0.0f;
-};
-
-// ====================================================================================
-/**
- * Measure latency given a loopback stream data.
- * Uses a state machine to cycle through various stages including:
- *
- */
-class EchoAnalyzer : public LoopbackProcessor {
-public:
-
- EchoAnalyzer() : LoopbackProcessor() {
- mAudioRecording.allocate(2 * getSampleRate());
- mAudioRecording.setSampleRate(getSampleRate());
- }
-
- void setSampleRate(int32_t sampleRate) override {
- LoopbackProcessor::setSampleRate(sampleRate);
- mAudioRecording.setSampleRate(sampleRate);
- }
-
- void reset() override {
- mDownCounter = getSampleRate() / 2;
- mLoopCounter = 0;
- mMeasuredLoopGain = 0.0f;
- mEchoGain = 1.0f;
- mState = STATE_INITIAL_SILENCE;
- }
-
- virtual bool isDone() {
- return mState == STATE_DONE || mState == STATE_FAILED;
- }
-
- void setGain(float gain) {
- mEchoGain = gain;
- }
-
- float getGain() {
- return mEchoGain;
- }
-
- bool testLowPassFilter() {
- LowPassFilter filter;
- return filter.test();
- }
-
- void report() override {
- printf("EchoAnalyzer ---------------\n");
- if (getResult() != 0) {
- printf(LOOPBACK_RESULT_TAG "result = %d\n", getResult());
- return;
- }
-
- // printf("LowPassFilter test %s\n", testLowPassFilter() ? "PASSED" : "FAILED");
-
- printf(LOOPBACK_RESULT_TAG "measured.gain = %8f\n", mMeasuredLoopGain);
- printf(LOOPBACK_RESULT_TAG "echo.gain = %8f\n", mEchoGain);
- printf(LOOPBACK_RESULT_TAG "test.state = %8d\n", mState);
- printf(LOOPBACK_RESULT_TAG "test.state.name = %8s\n", convertStateToText(mState));
-
- if (mState == STATE_WAITING_FOR_SILENCE) {
- printf("WARNING - Stuck waiting for silence. Input may be too noisy!\n");
- setResult(ERROR_NOISY);
- } else if (mMeasuredLoopGain >= 0.9999) {
- printf(" ERROR - clipping, turn down volume slightly\n");
- setResult(ERROR_CLIPPING);
- } else if (mState != STATE_DONE && mState != STATE_GATHERING_ECHOS) {
- printf("WARNING - Bad state. Check volume on device.\n");
- setResult(ERROR_INVALID_STATE);
- } else {
- // Cleanup the signal to improve the auto-correlation.
- mAudioRecording.dcBlocker();
- mAudioRecording.square();
- mAudioRecording.lowPassFilter();
-
- printf("Please wait several seconds for auto-correlation to complete.\n");
- measureLatencyFromEchos(mAudioRecording.getData(),
- mAudioRecording.size(),
- getSampleRate(),
- &mLatencyReport);
-
- double latencyMillis = kMillisPerSecond * (double) mLatencyReport.latencyInFrames
- / getSampleRate();
- printf(LOOPBACK_RESULT_TAG "latency.frames = %8.2f\n",
- mLatencyReport.latencyInFrames);
- printf(LOOPBACK_RESULT_TAG "latency.msec = %8.2f\n",
- latencyMillis);
- printf(LOOPBACK_RESULT_TAG "latency.confidence = %8.6f\n",
- mLatencyReport.confidence);
- if (mLatencyReport.confidence < kMinimumConfidence) {
- printf(" ERROR - confidence too low!\n");
- setResult(ERROR_CONFIDENCE);
- }
- }
- }
-
- void printStatus() override {
- printf("st = %d, echo gain = %f ", mState, mEchoGain);
- }
-
- void sendImpulses(float *outputData, int outputChannelCount, int numFrames) {
- while (numFrames-- > 0) {
- float sample = s_Impulse[mSampleIndex++];
- if (mSampleIndex >= kImpulseSizeInFrames) {
- mSampleIndex = 0;
- }
-
- *outputData = sample;
- outputData += outputChannelCount;
- }
- }
-
- void sendOneImpulse(float *outputData, int outputChannelCount) {
- mSampleIndex = 0;
- sendImpulses(outputData, outputChannelCount, kImpulseSizeInFrames);
- }
-
- // @return number of frames for a typical block of processing
- int32_t getBlockFrames() {
- return getSampleRate() / 8;
- }
-
- process_result process(float *inputData, int inputChannelCount,
- float *outputData, int outputChannelCount,
- int numFrames) override {
- int channelsValid = std::min(inputChannelCount, outputChannelCount);
- float peak = 0.0f;
- int numWritten;
- int numSamples;
-
- echo_state nextState = mState;
-
- switch (mState) {
- case STATE_INITIAL_SILENCE:
- // Output silence at the beginning.
- numSamples = numFrames * outputChannelCount;
- for (int i = 0; i < numSamples; i++) {
- outputData[i] = 0;
- }
- mDownCounter -= numFrames;
- if (mDownCounter <= 0) {
- nextState = STATE_MEASURING_GAIN;
- //printf("%5d: switch to STATE_MEASURING_GAIN\n", mLoopCounter);
- mDownCounter = getBlockFrames() * 2;
- }
- break;
-
- case STATE_MEASURING_GAIN:
- sendImpulses(outputData, outputChannelCount, numFrames);
- peak = measurePeakAmplitude(inputData, inputChannelCount, numFrames);
- // If we get several in a row then go to next state.
- if (peak > mPulseThreshold) {
- mDownCounter -= numFrames;
- if (mDownCounter <= 0) {
- //printf("%5d: switch to STATE_WAITING_FOR_SILENCE, measured peak = %f\n",
- // mLoopCounter, peak);
- mDownCounter = getBlockFrames();
- mMeasuredLoopGain = peak; // assumes original pulse amplitude is one
- mSilenceThreshold = peak * 0.1; // scale silence to measured pulse
- // Calculate gain that will give us a nice decaying echo.
- mEchoGain = mDesiredEchoGain / mMeasuredLoopGain;
- if (mEchoGain > kMaxEchoGain) {
- printf("ERROR - loop gain too low. Increase the volume.\n");
- nextState = STATE_FAILED;
- } else {
- nextState = STATE_WAITING_FOR_SILENCE;
- }
- }
- } else if (numFrames > kImpulseSizeInFrames){ // ignore short callbacks
- mDownCounter = getBlockFrames();
- }
- break;
-
- case STATE_WAITING_FOR_SILENCE:
- // Output silence and wait for the echos to die down.
- numSamples = numFrames * outputChannelCount;
- for (int i = 0; i < numSamples; i++) {
- outputData[i] = 0;
- }
- peak = measurePeakAmplitude(inputData, inputChannelCount, numFrames);
- // If we get several in a row then go to next state.
- if (peak < mSilenceThreshold) {
- mDownCounter -= numFrames;
- if (mDownCounter <= 0) {
- nextState = STATE_SENDING_PULSE;
- //printf("%5d: switch to STATE_SENDING_PULSE\n", mLoopCounter);
- mDownCounter = getBlockFrames();
- }
- } else {
- mDownCounter = getBlockFrames();
- }
- break;
-
- case STATE_SENDING_PULSE:
- mAudioRecording.write(inputData, inputChannelCount, numFrames);
- sendOneImpulse(outputData, outputChannelCount);
- nextState = STATE_GATHERING_ECHOS;
- //printf("%5d: switch to STATE_GATHERING_ECHOS\n", mLoopCounter);
- break;
-
- case STATE_GATHERING_ECHOS:
- numWritten = mAudioRecording.write(inputData, inputChannelCount, numFrames);
- peak = measurePeakAmplitude(inputData, inputChannelCount, numFrames);
- if (peak > mMeasuredLoopGain) {
- mMeasuredLoopGain = peak; // AGC might be raising gain so adjust it on the fly.
- // Recalculate gain that will give us a nice decaying echo.
- mEchoGain = mDesiredEchoGain / mMeasuredLoopGain;
- }
- // Echo input to output.
- for (int i = 0; i < numFrames; i++) {
- int ic;
- for (ic = 0; ic < channelsValid; ic++) {
- outputData[ic] = inputData[ic] * mEchoGain;
- }
- for (; ic < outputChannelCount; ic++) {
- outputData[ic] = 0;
- }
- inputData += inputChannelCount;
- outputData += outputChannelCount;
- }
- if (numWritten < numFrames) {
- nextState = STATE_DONE;
- }
- break;
-
- case STATE_DONE:
- case STATE_FAILED:
- default:
- break;
- }
-
- mState = nextState;
- mLoopCounter++;
- return PROCESS_RESULT_OK;
- }
-
- int save(const char *fileName) override {
- return mAudioRecording.save(fileName);
- }
-
- int load(const char *fileName) override {
- int result = mAudioRecording.load(fileName);
- setSampleRate(mAudioRecording.getSampleRate());
- mState = STATE_DONE;
- return result;
- }
-
-private:
-
- enum error_code {
- ERROR_OK = 0,
- ERROR_NOISY = -99,
- ERROR_CLIPPING,
- ERROR_CONFIDENCE,
- ERROR_INVALID_STATE
- };
-
- enum echo_state {
- STATE_INITIAL_SILENCE,
- STATE_MEASURING_GAIN,
- STATE_WAITING_FOR_SILENCE,
- STATE_SENDING_PULSE,
- STATE_GATHERING_ECHOS,
- STATE_DONE,
- STATE_FAILED
- };
-
- const char *convertStateToText(echo_state state) {
- const char *result = "Unknown";
- switch(state) {
- case STATE_INITIAL_SILENCE:
- result = "INIT";
- break;
- case STATE_MEASURING_GAIN:
- result = "GAIN";
- break;
- case STATE_WAITING_FOR_SILENCE:
- result = "SILENCE";
- break;
- case STATE_SENDING_PULSE:
- result = "PULSE";
- break;
- case STATE_GATHERING_ECHOS:
- result = "ECHOS";
- break;
- case STATE_DONE:
- result = "DONE";
- break;
- case STATE_FAILED:
- result = "FAILED";
- break;
- }
- return result;
- }
-
-
- int32_t mDownCounter = 500;
- int32_t mLoopCounter = 0;
- int32_t mSampleIndex = 0;
- float mPulseThreshold = 0.02f;
- float mSilenceThreshold = 0.002f;
- float mMeasuredLoopGain = 0.0f;
- float mDesiredEchoGain = 0.95f;
- float mEchoGain = 1.0f;
- echo_state mState = STATE_INITIAL_SILENCE;
-
- AudioRecording mAudioRecording; // contains only the input after the gain detection burst
- LatencyReport mLatencyReport;
- // PeakDetector mPeakDetector;
-};
-
-
-// ====================================================================================
-/**
- * Output a steady sinewave and analyze the return signal.
- *
- * Use a cosine transform to measure the predicted magnitude and relative phase of the
- * looped back sine wave. Then generate a predicted signal and compare with the actual signal.
- */
-class SineAnalyzer : public LoopbackProcessor {
-public:
-
- void report() override {
- printf("SineAnalyzer ------------------\n");
- printf(LOOPBACK_RESULT_TAG "peak.amplitude = %8f\n", mPeakAmplitude);
- printf(LOOPBACK_RESULT_TAG "sine.magnitude = %8f\n", mMagnitude);
- printf(LOOPBACK_RESULT_TAG "peak.noise = %8f\n", mPeakNoise);
- printf(LOOPBACK_RESULT_TAG "rms.noise = %8f\n", mRootMeanSquareNoise);
- float amplitudeRatio = mMagnitude / mPeakNoise;
- float signalToNoise = amplitudeRatio * amplitudeRatio;
- printf(LOOPBACK_RESULT_TAG "signal.to.noise = %8.2f\n", signalToNoise);
- float signalToNoiseDB = 10.0 * log(signalToNoise);
- printf(LOOPBACK_RESULT_TAG "signal.to.noise.db = %8.2f\n", signalToNoiseDB);
- if (signalToNoiseDB < MIN_SNRATIO_DB) {
- printf("ERROR - signal to noise ratio is too low! < %d dB. Adjust volume.\n", MIN_SNRATIO_DB);
- setResult(ERROR_NOISY);
- }
- printf(LOOPBACK_RESULT_TAG "frames.accumulated = %8d\n", mFramesAccumulated);
- printf(LOOPBACK_RESULT_TAG "sine.period = %8d\n", mSinePeriod);
- printf(LOOPBACK_RESULT_TAG "test.state = %8d\n", mState);
- printf(LOOPBACK_RESULT_TAG "frame.count = %8d\n", mFrameCounter);
- // Did we ever get a lock?
- bool gotLock = (mState == STATE_LOCKED) || (mGlitchCount > 0);
- if (!gotLock) {
- printf("ERROR - failed to lock on reference sine tone\n");
- setResult(ERROR_NO_LOCK);
- } else {
- // Only print if meaningful.
- printf(LOOPBACK_RESULT_TAG "glitch.count = %8d\n", mGlitchCount);
- printf(LOOPBACK_RESULT_TAG "max.glitch = %8f\n", mMaxGlitchDelta);
- if (mGlitchCount > 0) {
- printf("ERROR - number of glitches > 0\n");
- setResult(ERROR_GLITCHES);
- }
- }
- }
-
- void printStatus() override {
- printf("st = %d, #gl = %3d,", mState, mGlitchCount);
- }
-
- double calculateMagnitude(double *phasePtr = NULL) {
- if (mFramesAccumulated == 0) {
- return 0.0;
- }
- double sinMean = mSinAccumulator / mFramesAccumulated;
- double cosMean = mCosAccumulator / mFramesAccumulated;
- double magnitude = 2.0 * sqrt( (sinMean * sinMean) + (cosMean * cosMean ));
- if( phasePtr != NULL )
- {
- double phase = M_PI_2 - atan2( sinMean, cosMean );
- *phasePtr = phase;
- }
- return magnitude;
- }
-
- /**
- * @param inputData contains microphone data with sine signal feedback
- * @param outputData contains the reference sine wave
- */
- process_result process(float *inputData, int inputChannelCount,
- float *outputData, int outputChannelCount,
- int numFrames) override {
- process_result result = PROCESS_RESULT_OK;
- mProcessCount++;
-
- float peak = measurePeakAmplitude(inputData, inputChannelCount, numFrames);
- if (peak > mPeakAmplitude) {
- mPeakAmplitude = peak;
- }
-
- for (int i = 0; i < numFrames; i++) {
- bool sineEnabled = true;
- float sample = inputData[i * inputChannelCount];
-
- float sinOut = sinf(mPhase);
-
- switch (mState) {
- case STATE_IDLE:
- sineEnabled = false;
- mDownCounter--;
- if (mDownCounter <= 0) {
- mState = STATE_MEASURE_NOISE;
- mDownCounter = NOISE_FRAME_COUNT;
- }
- break;
- case STATE_MEASURE_NOISE:
- sineEnabled = false;
- mPeakNoise = std::max(abs(sample), mPeakNoise);
- mNoiseSumSquared += sample * sample;
- mDownCounter--;
- if (mDownCounter <= 0) {
- mState = STATE_WAITING_FOR_SIGNAL;
- mRootMeanSquareNoise = sqrt(mNoiseSumSquared / NOISE_FRAME_COUNT);
- mTolerance = std::max(MIN_TOLERANCE, mPeakNoise * 2.0f);
- mPhase = 0.0; // prevent spike at start
- }
- break;
-
- case STATE_IMMUNE:
- mDownCounter--;
- if (mDownCounter <= 0) {
- mState = STATE_WAITING_FOR_SIGNAL;
- }
- break;
-
- case STATE_WAITING_FOR_SIGNAL:
- if (peak > mThreshold) {
- mState = STATE_WAITING_FOR_LOCK;
- //printf("%5d: switch to STATE_WAITING_FOR_LOCK\n", mFrameCounter);
- resetAccumulator();
- }
- break;
-
- case STATE_WAITING_FOR_LOCK:
- mSinAccumulator += sample * sinOut;
- mCosAccumulator += sample * cosf(mPhase);
- mFramesAccumulated++;
- // Must be a multiple of the period or the calculation will not be accurate.
- if (mFramesAccumulated == mSinePeriod * PERIODS_NEEDED_FOR_LOCK) {
- mPhaseOffset = 0.0;
- mMagnitude = calculateMagnitude(&mPhaseOffset);
- if (mMagnitude > mThreshold) {
- if (fabs(mPreviousPhaseOffset - mPhaseOffset) < 0.001) {
- mState = STATE_LOCKED;
- //printf("%5d: switch to STATE_LOCKED\n", mFrameCounter);
- }
- mPreviousPhaseOffset = mPhaseOffset;
- }
- resetAccumulator();
- }
- break;
-
- case STATE_LOCKED: {
- // Predict next sine value
- float predicted = sinf(mPhase + mPhaseOffset) * mMagnitude;
- // printf(" predicted = %f, actual = %f\n", predicted, sample);
-
- float diff = predicted - sample;
- float absDiff = fabs(diff);
- mMaxGlitchDelta = std::max(mMaxGlitchDelta, absDiff);
- if (absDiff > mTolerance) {
- mGlitchCount++;
- result = PROCESS_RESULT_GLITCH;
- //printf("%5d: Got a glitch # %d, predicted = %f, actual = %f\n",
- // mFrameCounter, mGlitchCount, predicted, sample);
- mState = STATE_IMMUNE;
- mDownCounter = mSinePeriod * PERIODS_IMMUNE;
- }
-
- // Track incoming signal and slowly adjust magnitude to account
- // for drift in the DRC or AGC.
- mSinAccumulator += sample * sinOut;
- mCosAccumulator += sample * cosf(mPhase);
- mFramesAccumulated++;
- // Must be a multiple of the period or the calculation will not be accurate.
- if (mFramesAccumulated == mSinePeriod) {
- const double coefficient = 0.1;
- double phaseOffset = 0.0;
- double magnitude = calculateMagnitude(&phaseOffset);
- // One pole averaging filter.
- mMagnitude = (mMagnitude * (1.0 - coefficient)) + (magnitude * coefficient);
- resetAccumulator();
- }
- } break;
- }
-
- float output = 0.0f;
- // Output sine wave so we can measure it.
- if (sineEnabled) {
- output = (sinOut * mOutputAmplitude)
- + (mWhiteNoise.nextRandomDouble() * mNoiseAmplitude);
- // printf("%5d: sin(%f) = %f, %f\n", i, mPhase, sinOut, mPhaseIncrement);
- // advance and wrap phase
- mPhase += mPhaseIncrement;
- if (mPhase > M_PI) {
- mPhase -= (2.0 * M_PI);
- }
- }
- outputData[i * outputChannelCount] = output;
-
-
- mFrameCounter++;
- }
- return result;
- }
-
- void resetAccumulator() {
- mFramesAccumulated = 0;
- mSinAccumulator = 0.0;
- mCosAccumulator = 0.0;
- }
-
- void reset() override {
- mGlitchCount = 0;
- mState = STATE_IDLE;
- mDownCounter = IDLE_FRAME_COUNT;
- mPhaseIncrement = 2.0 * M_PI / mSinePeriod;
- printf("phaseInc = %f for period %d\n", mPhaseIncrement, mSinePeriod);
- resetAccumulator();
- mProcessCount = 0;
- mPeakNoise = 0.0f;
- mNoiseSumSquared = 0.0;
- mRootMeanSquareNoise = 0.0;
- mPhase = 0.0f;
- mMaxGlitchDelta = 0.0;
- }
-
-private:
-
- enum error_code {
- OK,
- ERROR_NO_LOCK = -80,
- ERROR_GLITCHES,
- ERROR_NOISY
- };
-
- enum sine_state_t {
- STATE_IDLE,
- STATE_MEASURE_NOISE,
- STATE_IMMUNE,
- STATE_WAITING_FOR_SIGNAL,
- STATE_WAITING_FOR_LOCK,
- STATE_LOCKED
- };
-
- enum constants {
- // Arbitrary durations, assuming 48000 Hz
- IDLE_FRAME_COUNT = 48 * 100,
- NOISE_FRAME_COUNT = 48 * 600,
- PERIODS_NEEDED_FOR_LOCK = 8,
- PERIODS_IMMUNE = 2,
- MIN_SNRATIO_DB = 65
- };
-
- static constexpr float MIN_TOLERANCE = 0.01;
-
- int mSinePeriod = 79;
- double mPhaseIncrement = 0.0;
- double mPhase = 0.0;
- double mPhaseOffset = 0.0;
- double mPreviousPhaseOffset = 0.0;
- double mMagnitude = 0.0;
- double mThreshold = 0.005;
- double mTolerance = MIN_TOLERANCE;
- int32_t mFramesAccumulated = 0;
- int32_t mProcessCount = 0;
- double mSinAccumulator = 0.0;
- double mCosAccumulator = 0.0;
- float mMaxGlitchDelta = 0.0f;
- int32_t mGlitchCount = 0;
- double mPeakAmplitude = 0.0;
- int mDownCounter = IDLE_FRAME_COUNT;
- int32_t mFrameCounter = 0;
- float mOutputAmplitude = 0.75;
-
- // measure background noise
- float mPeakNoise = 0.0f;
- double mNoiseSumSquared = 0.0;
- double mRootMeanSquareNoise = 0.0;
-
- PseudoRandom mWhiteNoise;
- float mNoiseAmplitude = 0.00; // Used to experiment with warbling caused by DRC.
-
- sine_state_t mState = STATE_IDLE;
-};
-
-#undef LOOPBACK_RESULT_TAG
-
-#endif /* AAUDIO_EXAMPLES_LOOPBACK_ANALYSER_H */
diff --git a/media/libaaudio/examples/loopback/src/analyzer/GlitchAnalyzer.h b/media/libaaudio/examples/loopback/src/analyzer/GlitchAnalyzer.h
new file mode 100644
index 0000000..04435d1
--- /dev/null
+++ b/media/libaaudio/examples/loopback/src/analyzer/GlitchAnalyzer.h
@@ -0,0 +1,445 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANALYZER_GLITCH_ANALYZER_H
+#define ANALYZER_GLITCH_ANALYZER_H
+
+#include <algorithm>
+#include <cctype>
+#include <iomanip>
+#include <iostream>
+
+#include "LatencyAnalyzer.h"
+#include "PseudoRandom.h"
+
+/**
+ * Output a steady sine wave and analyze the return signal.
+ *
+ * Use a cosine transform to measure the predicted magnitude and relative phase of the
+ * looped back sine wave. Then generate a predicted signal and compare with the actual signal.
+ */
+class GlitchAnalyzer : public LoopbackProcessor {
+public:
+
+ int32_t getState() const {
+ return mState;
+ }
+
+ double getPeakAmplitude() const {
+ return mPeakFollower.getLevel();
+ }
+
+ double getTolerance() {
+ return mTolerance;
+ }
+
+ void setTolerance(double tolerance) {
+ mTolerance = tolerance;
+ mScaledTolerance = mMagnitude * mTolerance;
+ }
+
+ void setMagnitude(double magnitude) {
+ mMagnitude = magnitude;
+ mScaledTolerance = mMagnitude * mTolerance;
+ }
+
+ int32_t getGlitchCount() const {
+ return mGlitchCount;
+ }
+
+ int32_t getStateFrameCount(int state) const {
+ return mStateFrameCounters[state];
+ }
+
+ double getSignalToNoiseDB() {
+ static const double threshold = 1.0e-14;
+ if (mMeanSquareSignal < threshold || mMeanSquareNoise < threshold) {
+ return 0.0;
+ } else {
+ double signalToNoise = mMeanSquareSignal / mMeanSquareNoise; // power ratio
+ double signalToNoiseDB = 10.0 * log(signalToNoise);
+ if (signalToNoiseDB < MIN_SNR_DB) {
+ ALOGD("ERROR - signal to noise ratio is too low! < %d dB. Adjust volume.",
+ MIN_SNR_DB);
+ setResult(ERROR_VOLUME_TOO_LOW);
+ }
+ return signalToNoiseDB;
+ }
+ }
+
+ std::string analyze() override {
+ std::stringstream report;
+ report << "GlitchAnalyzer ------------------\n";
+ report << LOOPBACK_RESULT_TAG "peak.amplitude = " << std::setw(8)
+ << getPeakAmplitude() << "\n";
+ report << LOOPBACK_RESULT_TAG "sine.magnitude = " << std::setw(8)
+ << mMagnitude << "\n";
+ report << LOOPBACK_RESULT_TAG "rms.noise = " << std::setw(8)
+ << mMeanSquareNoise << "\n";
+ report << LOOPBACK_RESULT_TAG "signal.to.noise.db = " << std::setw(8)
+ << getSignalToNoiseDB() << "\n";
+ report << LOOPBACK_RESULT_TAG "frames.accumulated = " << std::setw(8)
+ << mFramesAccumulated << "\n";
+ report << LOOPBACK_RESULT_TAG "sine.period = " << std::setw(8)
+ << mSinePeriod << "\n";
+ report << LOOPBACK_RESULT_TAG "test.state = " << std::setw(8)
+ << mState << "\n";
+ report << LOOPBACK_RESULT_TAG "frame.count = " << std::setw(8)
+ << mFrameCounter << "\n";
+ // Did we ever get a lock?
+ bool gotLock = (mState == STATE_LOCKED) || (mGlitchCount > 0);
+ if (!gotLock) {
+ report << "ERROR - failed to lock on reference sine tone.\n";
+ setResult(ERROR_NO_LOCK);
+ } else {
+ // Only print if meaningful.
+ report << LOOPBACK_RESULT_TAG "glitch.count = " << std::setw(8)
+ << mGlitchCount << "\n";
+ report << LOOPBACK_RESULT_TAG "max.glitch = " << std::setw(8)
+ << mMaxGlitchDelta << "\n";
+ if (mGlitchCount > 0) {
+ report << "ERROR - number of glitches > 0\n";
+ setResult(ERROR_GLITCHES);
+ }
+ }
+ return report.str();
+ }
+
+ void printStatus() override {
+ ALOGD("st = %d, #gl = %3d,", mState, mGlitchCount);
+ }
+ /**
+ * Calculate the magnitude of the component of the input signal
+ * that matches the analysis frequency.
+ * Also calculate the phase that we can use to create a
+ * signal that matches that component.
+ * The phase will be between -PI and +PI.
+ */
+ double calculateMagnitude(double *phasePtr = nullptr) {
+ if (mFramesAccumulated == 0) {
+ return 0.0;
+ }
+ double sinMean = mSinAccumulator / mFramesAccumulated;
+ double cosMean = mCosAccumulator / mFramesAccumulated;
+ double magnitude = 2.0 * sqrt((sinMean * sinMean) + (cosMean * cosMean));
+ if (phasePtr != nullptr) {
+ double phase = M_PI_2 - atan2(sinMean, cosMean);
+ *phasePtr = phase;
+ }
+ return magnitude;
+ }
+
+ /**
+ * @param frameData contains microphone data with sine signal feedback
+ * @param channelCount
+ */
+ result_code processInputFrame(float *frameData, int /* channelCount */) override {
+ result_code result = RESULT_OK;
+
+ float sample = frameData[0];
+ float peak = mPeakFollower.process(sample);
+
+ // Force a periodic glitch to test the detector!
+ if (mForceGlitchDuration > 0) {
+ if (mForceGlitchCounter == 0) {
+ ALOGE("%s: force a glitch!!", __func__);
+ mForceGlitchCounter = getSampleRate();
+ } else if (mForceGlitchCounter <= mForceGlitchDuration) {
+ // Force an abrupt offset.
+ sample += (sample > 0.0) ? -0.5f : 0.5f;
+ }
+ --mForceGlitchCounter;
+ }
+
+ mStateFrameCounters[mState]++; // count how many frames we are in each state
+
+ switch (mState) {
+ case STATE_IDLE:
+ mDownCounter--;
+ if (mDownCounter <= 0) {
+ mState = STATE_IMMUNE;
+ mDownCounter = IMMUNE_FRAME_COUNT;
+ mInputPhase = 0.0; // prevent spike at start
+ mOutputPhase = 0.0;
+ }
+ break;
+
+ case STATE_IMMUNE:
+ mDownCounter--;
+ if (mDownCounter <= 0) {
+ mState = STATE_WAITING_FOR_SIGNAL;
+ }
+ break;
+
+ case STATE_WAITING_FOR_SIGNAL:
+ if (peak > mThreshold) {
+ mState = STATE_WAITING_FOR_LOCK;
+ //ALOGD("%5d: switch to STATE_WAITING_FOR_LOCK", mFrameCounter);
+ resetAccumulator();
+ }
+ break;
+
+ case STATE_WAITING_FOR_LOCK:
+ mSinAccumulator += sample * sinf(mInputPhase);
+ mCosAccumulator += sample * cosf(mInputPhase);
+ mFramesAccumulated++;
+ // Must be a multiple of the period or the calculation will not be accurate.
+ if (mFramesAccumulated == mSinePeriod * PERIODS_NEEDED_FOR_LOCK) {
+ double phaseOffset = 0.0;
+ setMagnitude(calculateMagnitude(&phaseOffset));
+// ALOGD("%s() mag = %f, offset = %f, prev = %f",
+// __func__, mMagnitude, mPhaseOffset, mPreviousPhaseOffset);
+ if (mMagnitude > mThreshold) {
+ if (abs(phaseOffset) < kMaxPhaseError) {
+ mState = STATE_LOCKED;
+// ALOGD("%5d: switch to STATE_LOCKED", mFrameCounter);
+ }
+ // Adjust mInputPhase to match measured phase
+ mInputPhase += phaseOffset;
+ }
+ resetAccumulator();
+ }
+ incrementInputPhase();
+ break;
+
+ case STATE_LOCKED: {
+ // Predict next sine value
+ double predicted = sinf(mInputPhase) * mMagnitude;
+ double diff = predicted - sample;
+ double absDiff = fabs(diff);
+ mMaxGlitchDelta = std::max(mMaxGlitchDelta, absDiff);
+ if (absDiff > mScaledTolerance) {
+ result = ERROR_GLITCHES;
+ onGlitchStart();
+// LOGI("diff glitch detected, absDiff = %g", absDiff);
+ } else {
+ mSumSquareSignal += predicted * predicted;
+ mSumSquareNoise += diff * diff;
+ // Track incoming signal and slowly adjust magnitude to account
+ // for drift in the DRC or AGC.
+ mSinAccumulator += sample * sinf(mInputPhase);
+ mCosAccumulator += sample * cosf(mInputPhase);
+ mFramesAccumulated++;
+ // Must be a multiple of the period or the calculation will not be accurate.
+ if (mFramesAccumulated == mSinePeriod) {
+ const double coefficient = 0.1;
+ double phaseOffset = 0.0;
+ double magnitude = calculateMagnitude(&phaseOffset);
+ // One pole averaging filter.
+ setMagnitude((mMagnitude * (1.0 - coefficient)) + (magnitude * coefficient));
+
+ mMeanSquareNoise = mSumSquareNoise * mInverseSinePeriod;
+ mMeanSquareSignal = mSumSquareSignal * mInverseSinePeriod;
+ resetAccumulator();
+
+ if (abs(phaseOffset) > kMaxPhaseError) {
+ result = ERROR_GLITCHES;
+ onGlitchStart();
+ ALOGD("phase glitch detected, phaseOffset = %g", phaseOffset);
+ } else if (mMagnitude < mThreshold) {
+ result = ERROR_GLITCHES;
+ onGlitchStart();
+ ALOGD("magnitude glitch detected, mMagnitude = %g", mMagnitude);
+ }
+ }
+ }
+ incrementInputPhase();
+ } break;
+
+ case STATE_GLITCHING: {
+ // Predict next sine value
+ mGlitchLength++;
+ double predicted = sinf(mInputPhase) * mMagnitude;
+ double diff = predicted - sample;
+ double absDiff = fabs(diff);
+ mMaxGlitchDelta = std::max(mMaxGlitchDelta, absDiff);
+ if (absDiff < mScaledTolerance) { // close enough?
+ // If we get a full sine period of non-glitch samples in a row then consider the glitch over.
+ // We don't want to just consider a zero crossing the end of a glitch.
+ if (mNonGlitchCount++ > mSinePeriod) {
+ onGlitchEnd();
+ }
+ } else {
+ mNonGlitchCount = 0;
+ if (mGlitchLength > (4 * mSinePeriod)) {
+ relock();
+ }
+ }
+ incrementInputPhase();
+ } break;
+
+ case NUM_STATES: // not a real state
+ break;
+ }
+
+ mFrameCounter++;
+
+ return result;
+ }
+
+ // advance and wrap phase
+ void incrementInputPhase() {
+ mInputPhase += mPhaseIncrement;
+ if (mInputPhase > M_PI) {
+ mInputPhase -= (2.0 * M_PI);
+ }
+ }
+
+ // advance and wrap phase
+ void incrementOutputPhase() {
+ mOutputPhase += mPhaseIncrement;
+ if (mOutputPhase > M_PI) {
+ mOutputPhase -= (2.0 * M_PI);
+ }
+ }
+
+ /**
+ * @param frameData upon return, contains the reference sine wave
+ * @param channelCount
+ */
+ result_code processOutputFrame(float *frameData, int channelCount) override {
+ float output = 0.0f;
+ // Output sine wave so we can measure it.
+ if (mState != STATE_IDLE) {
+ float sinOut = sinf(mOutputPhase);
+ incrementOutputPhase();
+ output = (sinOut * mOutputAmplitude)
+ + (mWhiteNoise.nextRandomDouble() * kNoiseAmplitude);
+ // ALOGD("sin(%f) = %f, %f\n", mOutputPhase, sinOut, mPhaseIncrement);
+ }
+ frameData[0] = output;
+ for (int i = 1; i < channelCount; i++) {
+ frameData[i] = 0.0f;
+ }
+ return RESULT_OK;
+ }
+
+ void onGlitchStart() {
+ mGlitchCount++;
+// ALOGD("%5d: STARTED a glitch # %d", mFrameCounter, mGlitchCount);
+ mState = STATE_GLITCHING;
+ mGlitchLength = 1;
+ mNonGlitchCount = 0;
+ }
+
+ void onGlitchEnd() {
+// ALOGD("%5d: ENDED a glitch # %d, length = %d", mFrameCounter, mGlitchCount, mGlitchLength);
+ mState = STATE_LOCKED;
+ resetAccumulator();
+ }
+
+ // reset the sine wave detector
+ void resetAccumulator() {
+ mFramesAccumulated = 0;
+ mSinAccumulator = 0.0;
+ mCosAccumulator = 0.0;
+ mSumSquareSignal = 0.0;
+ mSumSquareNoise = 0.0;
+ }
+
+ void relock() {
+// ALOGD("relock: %d because of a very long %d glitch", mFrameCounter, mGlitchLength);
+ mState = STATE_WAITING_FOR_LOCK;
+ resetAccumulator();
+ }
+
+ void reset() override {
+ LoopbackProcessor::reset();
+ mState = STATE_IDLE;
+ mDownCounter = IDLE_FRAME_COUNT;
+ resetAccumulator();
+ }
+
+ void prepareToTest() override {
+ LoopbackProcessor::prepareToTest();
+ mSinePeriod = getSampleRate() / kTargetGlitchFrequency;
+ mOutputPhase = 0.0f;
+ mInverseSinePeriod = 1.0 / mSinePeriod;
+ mPhaseIncrement = 2.0 * M_PI * mInverseSinePeriod;
+ mGlitchCount = 0;
+ mMaxGlitchDelta = 0.0;
+ for (int i = 0; i < NUM_STATES; i++) {
+ mStateFrameCounters[i] = 0;
+ }
+ }
+
+private:
+
+ // These must match the values in GlitchActivity.java
+ enum sine_state_t {
+ STATE_IDLE, // beginning
+ STATE_IMMUNE, // ignoring input, waiting fo HW to settle
+ STATE_WAITING_FOR_SIGNAL, // looking for a loud signal
+ STATE_WAITING_FOR_LOCK, // trying to lock onto the phase of the sine
+ STATE_LOCKED, // locked on the sine wave, looking for glitches
+ STATE_GLITCHING, // locked on the sine wave but glitching
+ NUM_STATES
+ };
+
+ enum constants {
+ // Arbitrary durations, assuming 48000 Hz
+ IDLE_FRAME_COUNT = 48 * 100,
+ IMMUNE_FRAME_COUNT = 48 * 100,
+ PERIODS_NEEDED_FOR_LOCK = 8,
+ MIN_SNR_DB = 65
+ };
+
+ static constexpr float kNoiseAmplitude = 0.00; // Used to experiment with warbling caused by DRC.
+ static constexpr int kTargetGlitchFrequency = 607;
+ static constexpr double kMaxPhaseError = M_PI * 0.05;
+
+ float mTolerance = 0.10; // scaled from 0.0 to 1.0
+ double mThreshold = 0.005;
+ int mSinePeriod = 1; // this will be set before use
+ double mInverseSinePeriod = 1.0;
+
+ int32_t mStateFrameCounters[NUM_STATES];
+
+ double mPhaseIncrement = 0.0;
+ double mInputPhase = 0.0;
+ double mOutputPhase = 0.0;
+ double mMagnitude = 0.0;
+ int32_t mFramesAccumulated = 0;
+ double mSinAccumulator = 0.0;
+ double mCosAccumulator = 0.0;
+ double mMaxGlitchDelta = 0.0;
+ int32_t mGlitchCount = 0;
+ int32_t mNonGlitchCount = 0;
+ int32_t mGlitchLength = 0;
+ // This is used for processing every frame so we cache it here.
+ double mScaledTolerance = 0.0;
+ int mDownCounter = IDLE_FRAME_COUNT;
+ int32_t mFrameCounter = 0;
+ double mOutputAmplitude = 0.75;
+
+ int32_t mForceGlitchDuration = 0; // if > 0 then force a glitch for debugging
+ int32_t mForceGlitchCounter = 4 * 48000; // count down and trigger at zero
+
+ // measure background noise continuously as a deviation from the expected signal
+ double mSumSquareSignal = 0.0;
+ double mSumSquareNoise = 0.0;
+ double mMeanSquareSignal = 0.0;
+ double mMeanSquareNoise = 0.0;
+
+ PeakDetector mPeakFollower;
+
+ PseudoRandom mWhiteNoise;
+
+ sine_state_t mState = STATE_IDLE;
+};
+
+
+#endif //ANALYZER_GLITCH_ANALYZER_H
diff --git a/media/libaaudio/examples/loopback/src/analyzer/LatencyAnalyzer.h b/media/libaaudio/examples/loopback/src/analyzer/LatencyAnalyzer.h
new file mode 100644
index 0000000..e506791
--- /dev/null
+++ b/media/libaaudio/examples/loopback/src/analyzer/LatencyAnalyzer.h
@@ -0,0 +1,606 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+/**
+ * Tools for measuring latency and for detecting glitches.
+ * These classes are pure math and can be used with any audio system.
+ */
+
+#ifndef ANALYZER_LATENCY_ANALYZER_H
+#define ANALYZER_LATENCY_ANALYZER_H
+
+#include <algorithm>
+#include <assert.h>
+#include <cctype>
+#include <iomanip>
+#include <iostream>
+#include <math.h>
+#include <memory>
+#include <sstream>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <vector>
+
+#include "PeakDetector.h"
+#include "PseudoRandom.h"
+#include "RandomPulseGenerator.h"
+
+// This is used when the code is in Oboe.
+#ifndef ALOGD
+#define ALOGD printf
+#define ALOGE printf
+#define ALOGW printf
+#endif
+
+#define LOOPBACK_RESULT_TAG "RESULT: "
+
+static constexpr int32_t kDefaultSampleRate = 48000;
+static constexpr int32_t kMillisPerSecond = 1000;
+static constexpr int32_t kMaxLatencyMillis = 700; // arbitrary and generous
+static constexpr double kMinimumConfidence = 0.2;
+
+struct LatencyReport {
+ int32_t latencyInFrames = 0.0;
+ double confidence = 0.0;
+
+ void reset() {
+ latencyInFrames = 0;
+ confidence = 0.0;
+ }
+};
+
+// Calculate a normalized cross correlation.
+static double calculateNormalizedCorrelation(const float *a,
+ const float *b,
+ int windowSize) {
+ double correlation = 0.0;
+ double sumProducts = 0.0;
+ double sumSquares = 0.0;
+
+ // Correlate a against b.
+ for (int i = 0; i < windowSize; i++) {
+ float s1 = a[i];
+ float s2 = b[i];
+ // Use a normalized cross-correlation.
+ sumProducts += s1 * s2;
+ sumSquares += ((s1 * s1) + (s2 * s2));
+ }
+
+ if (sumSquares >= 1.0e-9) {
+ correlation = 2.0 * sumProducts / sumSquares;
+ }
+ return correlation;
+}
+
+static double calculateRootMeanSquare(float *data, int32_t numSamples) {
+ double sum = 0.0;
+ for (int32_t i = 0; i < numSamples; i++) {
+ float sample = data[i];
+ sum += sample * sample;
+ }
+ return sqrt(sum / numSamples);
+}
+
+/**
+ * Monophonic recording with processing.
+ */
+class AudioRecording
+{
+public:
+
+ void allocate(int maxFrames) {
+ mData = std::make_unique<float[]>(maxFrames);
+ mMaxFrames = maxFrames;
+ }
+
+ // Write SHORT data from the first channel.
+ int32_t write(int16_t *inputData, int32_t inputChannelCount, int32_t numFrames) {
+ // stop at end of buffer
+ if ((mFrameCounter + numFrames) > mMaxFrames) {
+ numFrames = mMaxFrames - mFrameCounter;
+ }
+ for (int i = 0; i < numFrames; i++) {
+ mData[mFrameCounter++] = inputData[i * inputChannelCount] * (1.0f / 32768);
+ }
+ return numFrames;
+ }
+
+ // Write FLOAT data from the first channel.
+ int32_t write(float *inputData, int32_t inputChannelCount, int32_t numFrames) {
+ // stop at end of buffer
+ if ((mFrameCounter + numFrames) > mMaxFrames) {
+ numFrames = mMaxFrames - mFrameCounter;
+ }
+ for (int i = 0; i < numFrames; i++) {
+ mData[mFrameCounter++] = inputData[i * inputChannelCount];
+ }
+ return numFrames;
+ }
+
+ // Write FLOAT data from the first channel.
+ int32_t write(float sample) {
+ // stop at end of buffer
+ if (mFrameCounter < mMaxFrames) {
+ mData[mFrameCounter++] = sample;
+ return 1;
+ }
+ return 0;
+ }
+
+ void clear() {
+ mFrameCounter = 0;
+ }
+ int32_t size() const {
+ return mFrameCounter;
+ }
+
+ bool isFull() const {
+ return mFrameCounter >= mMaxFrames;
+ }
+
+ float *getData() const {
+ return mData.get();
+ }
+
+ void setSampleRate(int32_t sampleRate) {
+ mSampleRate = sampleRate;
+ }
+
+ int32_t getSampleRate() const {
+ return mSampleRate;
+ }
+
+ /**
+ * Square the samples so they are all positive and so the peaks are emphasized.
+ */
+ void square() {
+ float *x = mData.get();
+ for (int i = 0; i < mFrameCounter; i++) {
+ x[i] *= x[i];
+ }
+ }
+
+ /**
+ * Amplify a signal so that the peak matches the specified target.
+ *
+ * @param target final max value
+ * @return gain applied to signal
+ */
+ float normalize(float target) {
+ float maxValue = 1.0e-9f;
+ for (int i = 0; i < mFrameCounter; i++) {
+ maxValue = std::max(maxValue, abs(mData[i]));
+ }
+ float gain = target / maxValue;
+ for (int i = 0; i < mFrameCounter; i++) {
+ mData[i] *= gain;
+ }
+ return gain;
+ }
+
+private:
+ std::unique_ptr<float[]> mData;
+ int32_t mFrameCounter = 0;
+ int32_t mMaxFrames = 0;
+ int32_t mSampleRate = kDefaultSampleRate; // common default
+};
+
+static int measureLatencyFromPulse(AudioRecording &recorded,
+ AudioRecording &pulse,
+ LatencyReport *report) {
+
+ report->latencyInFrames = 0;
+ report->confidence = 0.0;
+
+ int numCorrelations = recorded.size() - pulse.size();
+ if (numCorrelations < 10) {
+ ALOGE("%s() recording too small = %d frames\n", __func__, recorded.size());
+ return -1;
+ }
+ std::unique_ptr<float[]> correlations= std::make_unique<float[]>(numCorrelations);
+
+ // Correlate pulse against the recorded data.
+ for (int i = 0; i < numCorrelations; i++) {
+ float correlation = (float) calculateNormalizedCorrelation(&recorded.getData()[i],
+ &pulse.getData()[0],
+ pulse.size());
+ correlations[i] = correlation;
+ }
+
+ // Find highest peak in correlation array.
+ float peakCorrelation = 0.0;
+ int peakIndex = -1;
+ for (int i = 0; i < numCorrelations; i++) {
+ float value = abs(correlations[i]);
+ if (value > peakCorrelation) {
+ peakCorrelation = value;
+ peakIndex = i;
+ }
+ }
+ if (peakIndex < 0) {
+ ALOGE("%s() no signal for correlation\n", __func__);
+ return -2;
+ }
+
+ report->latencyInFrames = peakIndex;
+ report->confidence = peakCorrelation;
+
+ return 0;
+}
+
+// ====================================================================================
+class LoopbackProcessor {
+public:
+ virtual ~LoopbackProcessor() = default;
+
+ enum result_code {
+ RESULT_OK = 0,
+ ERROR_NOISY = -99,
+ ERROR_VOLUME_TOO_LOW,
+ ERROR_VOLUME_TOO_HIGH,
+ ERROR_CONFIDENCE,
+ ERROR_INVALID_STATE,
+ ERROR_GLITCHES,
+ ERROR_NO_LOCK
+ };
+
+ virtual void prepareToTest() {
+ reset();
+ }
+
+ virtual void reset() {
+ mResult = 0;
+ mResetCount++;
+ }
+
+ virtual result_code processInputFrame(float *frameData, int channelCount) = 0;
+ virtual result_code processOutputFrame(float *frameData, int channelCount) = 0;
+
+ void process(float *inputData, int inputChannelCount, int numInputFrames,
+ float *outputData, int outputChannelCount, int numOutputFrames) {
+ int numBoth = std::min(numInputFrames, numOutputFrames);
+ // Process one frame at a time.
+ for (int i = 0; i < numBoth; i++) {
+ processInputFrame(inputData, inputChannelCount);
+ inputData += inputChannelCount;
+ processOutputFrame(outputData, outputChannelCount);
+ outputData += outputChannelCount;
+ }
+ // If there is more input than output.
+ for (int i = numBoth; i < numInputFrames; i++) {
+ processInputFrame(inputData, inputChannelCount);
+ inputData += inputChannelCount;
+ }
+ // If there is more output than input.
+ for (int i = numBoth; i < numOutputFrames; i++) {
+ processOutputFrame(outputData, outputChannelCount);
+ outputData += outputChannelCount;
+ }
+ }
+
+ virtual std::string analyze() = 0;
+
+ virtual void printStatus() {};
+
+ int32_t getResult() {
+ return mResult;
+ }
+
+ void setResult(int32_t result) {
+ mResult = result;
+ }
+
+ virtual bool isDone() {
+ return false;
+ }
+
+ virtual int save(const char *fileName) {
+ (void) fileName;
+ return -1;
+ }
+
+ virtual int load(const char *fileName) {
+ (void) fileName;
+ return -1;
+ }
+
+ virtual void setSampleRate(int32_t sampleRate) {
+ mSampleRate = sampleRate;
+ }
+
+ int32_t getSampleRate() const {
+ return mSampleRate;
+ }
+
+ int32_t getResetCount() const {
+ return mResetCount;
+ }
+
+ /** Called when not enough input frames could be read after synchronization.
+ */
+ virtual void onInsufficientRead() {
+ reset();
+ }
+
+protected:
+ int32_t mResetCount = 0;
+
+private:
+ int32_t mSampleRate = kDefaultSampleRate;
+ int32_t mResult = 0;
+};
+
+class LatencyAnalyzer : public LoopbackProcessor {
+public:
+
+ LatencyAnalyzer() : LoopbackProcessor() {}
+ virtual ~LatencyAnalyzer() = default;
+
+ virtual int32_t getProgress() const = 0;
+
+ virtual int getState() = 0;
+
+ // @return latency in frames
+ virtual int32_t getMeasuredLatency() = 0;
+
+ virtual double getMeasuredConfidence() = 0;
+
+ virtual double getBackgroundRMS() = 0;
+
+ virtual double getSignalRMS() = 0;
+
+};
+
+// ====================================================================================
+/**
+ * Measure latency given a loopback stream data.
+ * Use an encoded bit train as the sound source because it
+ * has an unambiguous correlation value.
+ * Uses a state machine to cycle through various stages.
+ *
+ */
+class PulseLatencyAnalyzer : public LatencyAnalyzer {
+public:
+
+ PulseLatencyAnalyzer() : LatencyAnalyzer() {
+ int32_t maxLatencyFrames = getSampleRate() * kMaxLatencyMillis / kMillisPerSecond;
+ int32_t numPulseBits = getSampleRate() * kPulseLengthMillis
+ / (kFramesPerEncodedBit * kMillisPerSecond);
+ int32_t pulseLength = numPulseBits * kFramesPerEncodedBit;
+ mFramesToRecord = pulseLength + maxLatencyFrames;
+ mAudioRecording.allocate(mFramesToRecord);
+ mAudioRecording.setSampleRate(getSampleRate());
+ generateRandomPulse(pulseLength);
+ }
+
+ void generateRandomPulse(int32_t pulseLength) {
+ mPulse.allocate(pulseLength);
+ RandomPulseGenerator pulser(kFramesPerEncodedBit);
+ for (int i = 0; i < pulseLength; i++) {
+ mPulse.write(pulser.nextFloat());
+ }
+ }
+
+ int getState() override {
+ return mState;
+ }
+
+ void setSampleRate(int32_t sampleRate) override {
+ LoopbackProcessor::setSampleRate(sampleRate);
+ mAudioRecording.setSampleRate(sampleRate);
+ }
+
+ void reset() override {
+ LoopbackProcessor::reset();
+ mDownCounter = getSampleRate() / 2;
+ mLoopCounter = 0;
+
+ mPulseCursor = 0;
+ mBackgroundSumSquare = 0.0f;
+ mBackgroundSumCount = 0;
+ mBackgroundRMS = 0.0f;
+ mSignalRMS = 0.0f;
+
+ mState = STATE_MEASURE_BACKGROUND;
+ mAudioRecording.clear();
+ mLatencyReport.reset();
+ }
+
+ bool hasEnoughData() {
+ return mAudioRecording.isFull();
+ }
+
+ bool isDone() override {
+ return mState == STATE_DONE;
+ }
+
+ int32_t getProgress() const override {
+ return mAudioRecording.size();
+ }
+
+ std::string analyze() override {
+ std::stringstream report;
+ report << "PulseLatencyAnalyzer ---------------\n";
+ report << LOOPBACK_RESULT_TAG "test.state = "
+ << std::setw(8) << mState << "\n";
+ report << LOOPBACK_RESULT_TAG "test.state.name = "
+ << convertStateToText(mState) << "\n";
+ report << LOOPBACK_RESULT_TAG "background.rms = "
+ << std::setw(8) << mBackgroundRMS << "\n";
+
+ int32_t newResult = RESULT_OK;
+ if (mState != STATE_GOT_DATA) {
+ report << "WARNING - Bad state. Check volume on device.\n";
+ // setResult(ERROR_INVALID_STATE);
+ } else {
+ float gain = mAudioRecording.normalize(1.0f);
+ measureLatencyFromPulse(mAudioRecording,
+ mPulse,
+ &mLatencyReport);
+
+ if (mLatencyReport.confidence < kMinimumConfidence) {
+ report << " ERROR - confidence too low!";
+ newResult = ERROR_CONFIDENCE;
+ } else {
+ mSignalRMS = calculateRootMeanSquare(
+ &mAudioRecording.getData()[mLatencyReport.latencyInFrames], mPulse.size())
+ / gain;
+ }
+ double latencyMillis = kMillisPerSecond * (double) mLatencyReport.latencyInFrames
+ / getSampleRate();
+ report << LOOPBACK_RESULT_TAG "latency.frames = " << std::setw(8)
+ << mLatencyReport.latencyInFrames << "\n";
+ report << LOOPBACK_RESULT_TAG "latency.msec = " << std::setw(8)
+ << latencyMillis << "\n";
+ report << LOOPBACK_RESULT_TAG "latency.confidence = " << std::setw(8)
+ << mLatencyReport.confidence << "\n";
+ }
+ mState = STATE_DONE;
+ if (getResult() == RESULT_OK) {
+ setResult(newResult);
+ }
+
+ return report.str();
+ }
+
+ int32_t getMeasuredLatency() override {
+ return mLatencyReport.latencyInFrames;
+ }
+
+ double getMeasuredConfidence() override {
+ return mLatencyReport.confidence;
+ }
+
+ double getBackgroundRMS() override {
+ return mBackgroundRMS;
+ }
+
+ double getSignalRMS() override {
+ return mSignalRMS;
+ }
+
+ void printStatus() override {
+ ALOGD("st = %d", mState);
+ }
+
+ result_code processInputFrame(float *frameData, int channelCount) override {
+ echo_state nextState = mState;
+ mLoopCounter++;
+
+ switch (mState) {
+ case STATE_MEASURE_BACKGROUND:
+ // Measure background RMS on channel 0
+ mBackgroundSumSquare += frameData[0] * frameData[0];
+ mBackgroundSumCount++;
+ mDownCounter--;
+ if (mDownCounter <= 0) {
+ mBackgroundRMS = sqrtf(mBackgroundSumSquare / mBackgroundSumCount);
+ nextState = STATE_IN_PULSE;
+ mPulseCursor = 0;
+ }
+ break;
+
+ case STATE_IN_PULSE:
+ // Record input until the mAudioRecording is full.
+ mAudioRecording.write(frameData, channelCount, 1);
+ if (hasEnoughData()) {
+ nextState = STATE_GOT_DATA;
+ }
+ break;
+
+ case STATE_GOT_DATA:
+ case STATE_DONE:
+ default:
+ break;
+ }
+
+ mState = nextState;
+ return RESULT_OK;
+ }
+
+ result_code processOutputFrame(float *frameData, int channelCount) override {
+ switch (mState) {
+ case STATE_IN_PULSE:
+ if (mPulseCursor < mPulse.size()) {
+ float pulseSample = mPulse.getData()[mPulseCursor++];
+ for (int i = 0; i < channelCount; i++) {
+ frameData[i] = pulseSample;
+ }
+ } else {
+ for (int i = 0; i < channelCount; i++) {
+ frameData[i] = 0;
+ }
+ }
+ break;
+
+ case STATE_MEASURE_BACKGROUND:
+ case STATE_GOT_DATA:
+ case STATE_DONE:
+ default:
+ for (int i = 0; i < channelCount; i++) {
+ frameData[i] = 0.0f; // silence
+ }
+ break;
+ }
+
+ return RESULT_OK;
+ }
+
+private:
+
+ enum echo_state {
+ STATE_MEASURE_BACKGROUND,
+ STATE_IN_PULSE,
+ STATE_GOT_DATA, // must match RoundTripLatencyActivity.java
+ STATE_DONE,
+ };
+
+ const char *convertStateToText(echo_state state) {
+ switch (state) {
+ case STATE_MEASURE_BACKGROUND:
+ return "INIT";
+ case STATE_IN_PULSE:
+ return "PULSE";
+ case STATE_GOT_DATA:
+ return "GOT_DATA";
+ case STATE_DONE:
+ return "DONE";
+ }
+ return "UNKNOWN";
+ }
+
+ int32_t mDownCounter = 500;
+ int32_t mLoopCounter = 0;
+ echo_state mState = STATE_MEASURE_BACKGROUND;
+
+ static constexpr int32_t kFramesPerEncodedBit = 8; // multiple of 2
+ static constexpr int32_t kPulseLengthMillis = 500;
+
+ AudioRecording mPulse;
+ int32_t mPulseCursor = 0;
+
+ double mBackgroundSumSquare = 0.0;
+ int32_t mBackgroundSumCount = 0;
+ double mBackgroundRMS = 0.0;
+ double mSignalRMS = 0.0;
+ int32_t mFramesToRecord = 0;
+
+ AudioRecording mAudioRecording; // contains only the input after starting the pulse
+ LatencyReport mLatencyReport;
+};
+
+#endif // ANALYZER_LATENCY_ANALYZER_H
diff --git a/media/libaaudio/examples/loopback/src/analyzer/ManchesterEncoder.h b/media/libaaudio/examples/loopback/src/analyzer/ManchesterEncoder.h
new file mode 100644
index 0000000..0a4bd5b
--- /dev/null
+++ b/media/libaaudio/examples/loopback/src/analyzer/ManchesterEncoder.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef ANALYZER_MANCHESTER_ENCODER_H
+#define ANALYZER_MANCHESTER_ENCODER_H
+
+#include <cstdint>
+
+/**
+ * Encode bytes using Manchester Coding scheme.
+ *
+ * Manchester Code is self clocking.
+ * There is a transition in the middle of every bit.
+ * Zero is high then low.
+ * One is low then high.
+ *
+ * This avoids having long DC sections that would droop when
+ * passed though analog circuits with AC coupling.
+ *
+ * IEEE 802.3 compatible.
+ */
+
+class ManchesterEncoder {
+public:
+ ManchesterEncoder(int samplesPerPulse)
+ : mSamplesPerPulse(samplesPerPulse)
+ , mSamplesPerPulseHalf(samplesPerPulse / 2)
+ , mCursor(samplesPerPulse) {
+ }
+
+ virtual ~ManchesterEncoder() = default;
+
+ /**
+ * This will be called when the next byte is needed.
+ * @return
+ */
+ virtual uint8_t onNextByte() = 0;
+
+ /**
+ * Generate the next floating point sample.
+ * @return
+ */
+ virtual float nextFloat() {
+ advanceSample();
+ if (mCurrentBit) {
+ return (mCursor < mSamplesPerPulseHalf) ? -1.0f : 1.0f; // one
+ } else {
+ return (mCursor < mSamplesPerPulseHalf) ? 1.0f : -1.0f; // zero
+ }
+ }
+
+protected:
+ /**
+ * This will be called when a new bit is ready to be encoded.
+ * It can be used to prepare the encoded samples.
+ * @param current
+ */
+ virtual void onNextBit(bool /* current */) {};
+
+ void advanceSample() {
+ // Are we ready for a new bit?
+ if (++mCursor >= mSamplesPerPulse) {
+ mCursor = 0;
+ if (mBitsLeft == 0) {
+ mCurrentByte = onNextByte();
+ mBitsLeft = 8;
+ }
+ --mBitsLeft;
+ mCurrentBit = (mCurrentByte >> mBitsLeft) & 1;
+ onNextBit(mCurrentBit);
+ }
+ }
+
+ bool getCurrentBit() {
+ return mCurrentBit;
+ }
+
+ const int mSamplesPerPulse;
+ const int mSamplesPerPulseHalf;
+ int mCursor;
+ int mBitsLeft = 0;
+ uint8_t mCurrentByte = 0;
+ bool mCurrentBit = false;
+};
+#endif //ANALYZER_MANCHESTER_ENCODER_H
diff --git a/media/libaaudio/examples/loopback/src/analyzer/PeakDetector.h b/media/libaaudio/examples/loopback/src/analyzer/PeakDetector.h
new file mode 100644
index 0000000..4b3b4e7
--- /dev/null
+++ b/media/libaaudio/examples/loopback/src/analyzer/PeakDetector.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANALYZER_PEAK_DETECTOR_H
+#define ANALYZER_PEAK_DETECTOR_H
+
+#include <math.h>
+
+/**
+ * Measure a peak envelope by rising with the peaks,
+ * and decaying exponentially after each peak.
+ * The absolute value of the input signal is used.
+ */
+class PeakDetector {
+public:
+
+ void reset() {
+ mLevel = 0.0;
+ }
+
+ double process(double input) {
+ mLevel *= mDecay; // exponential decay
+ input = fabs(input);
+ // never fall below the input signal
+ if (input > mLevel) {
+ mLevel = input;
+ }
+ return mLevel;
+ }
+
+ double getLevel() const {
+ return mLevel;
+ }
+
+ double getDecay() const {
+ return mDecay;
+ }
+
+ /**
+ * Multiply the level by this amount on every iteration.
+ * This provides an exponential decay curve.
+ * A value just under 1.0 is best, for example, 0.99;
+ * @param decay scale level for each input
+ */
+ void setDecay(double decay) {
+ mDecay = decay;
+ }
+
+private:
+ static constexpr double kDefaultDecay = 0.99f;
+
+ double mLevel = 0.0;
+ double mDecay = kDefaultDecay;
+};
+#endif //ANALYZER_PEAK_DETECTOR_H
diff --git a/media/libaaudio/examples/loopback/src/analyzer/PseudoRandom.h b/media/libaaudio/examples/loopback/src/analyzer/PseudoRandom.h
new file mode 100644
index 0000000..1c4938c
--- /dev/null
+++ b/media/libaaudio/examples/loopback/src/analyzer/PseudoRandom.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef ANALYZER_PSEUDORANDOM_H
+#define ANALYZER_PSEUDORANDOM_H
+
+#include <cctype>
+
+class PseudoRandom {
+public:
+ PseudoRandom(int64_t seed = 99887766)
+ : mSeed(seed)
+ {}
+
+ /**
+ * Returns the next random double from -1.0 to 1.0
+ *
+ * @return value from -1.0 to 1.0
+ */
+ double nextRandomDouble() {
+ return nextRandomInteger() * (0.5 / (((int32_t)1) << 30));
+ }
+
+ /** Calculate random 32 bit number using linear-congruential method
+ * with known real-time performance.
+ */
+ int32_t nextRandomInteger() {
+#if __has_builtin(__builtin_mul_overflow) && __has_builtin(__builtin_add_overflow)
+ int64_t prod;
+ // Use values for 64-bit sequence from MMIX by Donald Knuth.
+ __builtin_mul_overflow(mSeed, (int64_t)6364136223846793005, &prod);
+ __builtin_add_overflow(prod, (int64_t)1442695040888963407, &mSeed);
+#else
+ mSeed = (mSeed * (int64_t)6364136223846793005) + (int64_t)1442695040888963407;
+#endif
+ return (int32_t) (mSeed >> 32); // The higher bits have a longer sequence.
+ }
+
+private:
+ int64_t mSeed;
+};
+
+#endif //ANALYZER_PSEUDORANDOM_H
diff --git a/media/libaaudio/examples/loopback/src/analyzer/RandomPulseGenerator.h b/media/libaaudio/examples/loopback/src/analyzer/RandomPulseGenerator.h
new file mode 100644
index 0000000..030050b
--- /dev/null
+++ b/media/libaaudio/examples/loopback/src/analyzer/RandomPulseGenerator.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANALYZER_RANDOM_PULSE_GENERATOR_H
+#define ANALYZER_RANDOM_PULSE_GENERATOR_H
+
+#include <stdlib.h>
+#include "RoundedManchesterEncoder.h"
+
+/**
+ * Encode random ones and zeros using Manchester Code per IEEE 802.3.
+ */
+class RandomPulseGenerator : public RoundedManchesterEncoder {
+public:
+ RandomPulseGenerator(int samplesPerPulse)
+ : RoundedManchesterEncoder(samplesPerPulse) {
+ }
+
+ virtual ~RandomPulseGenerator() = default;
+
+ /**
+ * This will be called when the next byte is needed.
+ * @return random byte
+ */
+ uint8_t onNextByte() override {
+ return static_cast<uint8_t>(rand());
+ }
+};
+
+#endif //ANALYZER_RANDOM_PULSE_GENERATOR_H
diff --git a/media/libaaudio/examples/loopback/src/analyzer/RoundedManchesterEncoder.h b/media/libaaudio/examples/loopback/src/analyzer/RoundedManchesterEncoder.h
new file mode 100644
index 0000000..f2eba84
--- /dev/null
+++ b/media/libaaudio/examples/loopback/src/analyzer/RoundedManchesterEncoder.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef ANALYZER_ROUNDED_MANCHESTER_ENCODER_H
+#define ANALYZER_ROUNDED_MANCHESTER_ENCODER_H
+
+#include <math.h>
+#include <memory.h>
+#include <stdlib.h>
+#include "ManchesterEncoder.h"
+
+/**
+ * Encode bytes using Manchester Code.
+ * Round the edges using a half cosine to reduce ringing caused by a hard edge.
+ */
+
+class RoundedManchesterEncoder : public ManchesterEncoder {
+public:
+ RoundedManchesterEncoder(int samplesPerPulse)
+ : ManchesterEncoder(samplesPerPulse) {
+ int rampSize = samplesPerPulse / 4;
+ mZeroAfterZero = std::make_unique<float[]>(samplesPerPulse);
+ mZeroAfterOne = std::make_unique<float[]>(samplesPerPulse);
+
+ int sampleIndex = 0;
+ for (int rampIndex = 0; rampIndex < rampSize; rampIndex++) {
+ float phase = (rampIndex + 1) * M_PI / rampSize;
+ float sample = -cosf(phase);
+ mZeroAfterZero[sampleIndex] = sample;
+ mZeroAfterOne[sampleIndex] = 1.0f;
+ sampleIndex++;
+ }
+ for (int rampIndex = 0; rampIndex < rampSize; rampIndex++) {
+ mZeroAfterZero[sampleIndex] = 1.0f;
+ mZeroAfterOne[sampleIndex] = 1.0f;
+ sampleIndex++;
+ }
+ for (int rampIndex = 0; rampIndex < rampSize; rampIndex++) {
+ float phase = (rampIndex + 1) * M_PI / rampSize;
+ float sample = cosf(phase);
+ mZeroAfterZero[sampleIndex] = sample;
+ mZeroAfterOne[sampleIndex] = sample;
+ sampleIndex++;
+ }
+ for (int rampIndex = 0; rampIndex < rampSize; rampIndex++) {
+ mZeroAfterZero[sampleIndex] = -1.0f;
+ mZeroAfterOne[sampleIndex] = -1.0f;
+ sampleIndex++;
+ }
+ }
+
+ void onNextBit(bool current) override {
+ // Do we need to use the rounded edge?
+ mCurrentSamples = (current ^ mPreviousBit)
+ ? mZeroAfterOne.get()
+ : mZeroAfterZero.get();
+ mPreviousBit = current;
+ }
+
+ float nextFloat() override {
+ advanceSample();
+ float output = mCurrentSamples[mCursor];
+ if (getCurrentBit()) output = -output;
+ return output;
+ }
+
+private:
+
+ bool mPreviousBit = false;
+ float *mCurrentSamples = nullptr;
+ std::unique_ptr<float[]> mZeroAfterZero;
+ std::unique_ptr<float[]> mZeroAfterOne;
+};
+
+#endif //ANALYZER_ROUNDED_MANCHESTER_ENCODER_H
diff --git a/media/libaaudio/examples/loopback/src/loopback.cpp b/media/libaaudio/examples/loopback/src/loopback.cpp
index 49d921f..0d2ec70 100644
--- a/media/libaaudio/examples/loopback/src/loopback.cpp
+++ b/media/libaaudio/examples/loopback/src/loopback.cpp
@@ -20,6 +20,8 @@
#include <assert.h>
#include <cctype>
#include <errno.h>
+#include <iomanip>
+#include <iostream>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
@@ -33,7 +35,9 @@
#include "AAudioSimplePlayer.h"
#include "AAudioSimpleRecorder.h"
#include "AAudioExampleUtils.h"
-#include "LoopbackAnalyzer.h"
+
+#include "analyzer/GlitchAnalyzer.h"
+#include "analyzer/LatencyAnalyzer.h"
#include "../../utils/AAudioExampleUtils.h"
// V0.4.00 = rectify and low-pass filter the echos, auto-correlate entire echo
@@ -41,7 +45,8 @@
// fix -n option to set output buffer for -tm
// plot first glitch
// V0.4.02 = allow -n0 for minimal buffer size
-#define APP_VERSION "0.4.02"
+// V0.5.00 = use latency analyzer from OboeTester, uses random noise for latency
+#define APP_VERSION "0.5.00"
// Tag for machine readable results as property = value pairs
#define RESULT_TAG "RESULT: "
@@ -57,6 +62,20 @@
constexpr int kDefaultHangTimeMillis = 50;
constexpr int kMaxGlitchEventsToSave = 32;
+static void printAudioScope(float sample) {
+ const int maxStars = 80; // arbitrary, fits on one line
+ char c = '*';
+ if (sample < -1.0) {
+ sample = -1.0;
+ c = '$';
+ } else if (sample > 1.0) {
+ sample = 1.0;
+ c = '$';
+ }
+ int numSpaces = (int) (((sample + 1.0) * 0.5) * maxStars);
+ printf("%*c%c\n", numSpaces, ' ', c);
+}
+
struct LoopbackData {
AAudioStream *inputStream = nullptr;
AAudioStream *outputStream = nullptr;
@@ -83,8 +102,8 @@
aaudio_result_t inputError = AAUDIO_OK;
aaudio_result_t outputError = AAUDIO_OK;
- SineAnalyzer sineAnalyzer;
- EchoAnalyzer echoAnalyzer;
+ GlitchAnalyzer sineAnalyzer;
+ PulseLatencyAnalyzer echoAnalyzer;
AudioRecording audioRecording;
LoopbackProcessor *loopbackProcessor;
@@ -254,17 +273,18 @@
}
// Analyze the data.
- LoopbackProcessor::process_result procResult = myData->loopbackProcessor->process(myData->inputFloatData,
+ myData->loopbackProcessor->process(myData->inputFloatData,
myData->actualInputChannelCount,
+ numFrames,
outputData,
myData->actualOutputChannelCount,
numFrames);
-
- if (procResult == LoopbackProcessor::PROCESS_RESULT_GLITCH) {
- if (myData->numGlitchEvents < kMaxGlitchEventsToSave) {
- myData->glitchFrames[myData->numGlitchEvents++] = myData->audioRecording.size();
- }
- }
+//
+// if (procResult == LoopbackProcessor::PROCESS_RESULT_GLITCH) {
+// if (myData->numGlitchEvents < kMaxGlitchEventsToSave) {
+// myData->glitchFrames[myData->numGlitchEvents++] = myData->audioRecording.size();
+// }
+// }
// Save for later.
myData->audioRecording.write(myData->inputFloatData,
@@ -283,8 +303,8 @@
}
static void MyErrorCallbackProc(
- AAudioStream *stream __unused,
- void *userData __unused,
+ AAudioStream * /* stream */,
+ void * userData,
aaudio_result_t error) {
printf("Error Callback, error: %d\n",(int)error);
LoopbackData *myData = (LoopbackData *) userData;
@@ -305,8 +325,8 @@
printf(" l for _LATENCY\n");
printf(" p for _POWER_SAVING\n");
printf(" -t{test} select test mode\n");
- printf(" m for sine magnitude\n");
- printf(" e for echo latency (default)\n");
+ printf(" g for Glitch detection\n");
+ printf(" l for round trip Latency (default)\n");
printf(" f for file latency, analyzes %s\n\n", FILENAME_ECHOS);
printf(" -X use EXCLUSIVE mode for input\n");
printf("Example: aaudio_loopback -n2 -pl -Pl -x\n");
@@ -333,20 +353,22 @@
}
enum {
- TEST_SINE_MAGNITUDE = 0,
- TEST_ECHO_LATENCY,
+ TEST_GLITCHES = 0,
+ TEST_LATENCY,
TEST_FILE_LATENCY,
};
static int parseTestMode(char c) {
- int testMode = TEST_ECHO_LATENCY;
+ int testMode = TEST_LATENCY;
c = tolower(c);
switch (c) {
- case 'm':
- testMode = TEST_SINE_MAGNITUDE;
+ case 'm': // deprecated
+ case 'g':
+ testMode = TEST_GLITCHES;
break;
- case 'e':
- testMode = TEST_ECHO_LATENCY;
+ case 'e': // deprecated
+ case 'l':
+ testMode = TEST_LATENCY;
break;
case 'f':
testMode = TEST_FILE_LATENCY;
@@ -408,9 +430,10 @@
int32_t actualSampleRate = 0;
int written = 0;
- int testMode = TEST_ECHO_LATENCY;
+ int testMode = TEST_LATENCY;
double gain = 1.0;
int hangTimeMillis = 0;
+ std::string report;
// Make printf print immediately so that debug info is not stuck
// in a buffer if we hang or crash.
@@ -488,22 +511,21 @@
int32_t requestedOutputBursts = argParser.getNumberOfBursts();
switch(testMode) {
- case TEST_SINE_MAGNITUDE:
+ case TEST_GLITCHES:
loopbackData.loopbackProcessor = &loopbackData.sineAnalyzer;
break;
- case TEST_ECHO_LATENCY:
- loopbackData.echoAnalyzer.setGain(gain);
+ case TEST_LATENCY:
+ // TODO loopbackData.echoAnalyzer.setGain(gain);
loopbackData.loopbackProcessor = &loopbackData.echoAnalyzer;
break;
case TEST_FILE_LATENCY: {
- loopbackData.echoAnalyzer.setGain(gain);
-
+ // TODO loopbackData.echoAnalyzer.setGain(gain);
loopbackData.loopbackProcessor = &loopbackData.echoAnalyzer;
int read = loopbackData.loopbackProcessor->load(FILENAME_ECHOS);
printf("main() read %d mono samples from %s on Android device, rate = %d\n",
read, FILENAME_ECHOS,
loopbackData.loopbackProcessor->getSampleRate());
- loopbackData.loopbackProcessor->report();
+ std::cout << loopbackData.loopbackProcessor->analyze();
goto report_result;
}
break;
@@ -557,7 +579,7 @@
int32_t actualCapacity = AAudioStream_getBufferCapacityInFrames(inputStream);
(void) AAudioStream_setBufferSizeInFrames(inputStream, actualCapacity);
- if (testMode == TEST_SINE_MAGNITUDE
+ if (testMode == TEST_GLITCHES
&& requestedOutputBursts == AAUDIO_UNSPECIFIED) {
result = AAudioStream_setBufferSizeInFrames(outputStream, actualCapacity);
if (result < 0) {
@@ -594,10 +616,10 @@
loopbackData.inputFloatData = new float[loopbackData.inputFramesMaximum *
loopbackData.actualInputChannelCount]{};
- loopbackData.loopbackProcessor->reset();
-
loopbackData.hangTimeMillis = hangTimeMillis;
+ loopbackData.loopbackProcessor->prepareToTest();
+
// Start OUTPUT first so INPUT does not overflow.
result = player.start();
if (result != AAUDIO_OK) {
@@ -669,7 +691,8 @@
printf("input error = %d = %s\n",
loopbackData.inputError, AAudio_convertResultToText(loopbackData.inputError));
-
+/*
+ // TODO Restore this code some day if we want to save files.
written = loopbackData.loopbackProcessor->save(FILENAME_ECHOS);
if (written > 0) {
printf("main() wrote %8d mono samples to \"%s\" on Android device\n",
@@ -681,9 +704,9 @@
printf("main() wrote %8d mono samples to \"%s\" on Android device\n",
written, FILENAME_ALL);
}
-
+*/
if (loopbackData.inputError == AAUDIO_OK) {
- if (testMode == TEST_SINE_MAGNITUDE) {
+ if (testMode == TEST_GLITCHES) {
if (loopbackData.numGlitchEvents > 0) {
// Graph around the first glitch if there is one.
const int32_t start = loopbackData.glitchFrames[0] - 8;
@@ -697,7 +720,8 @@
}
}
- loopbackData.loopbackProcessor->report();
+ std::cout << "Please wait several seconds for analysis to complete.\n";
+ std::cout << loopbackData.loopbackProcessor->analyze();
}
{
diff --git a/media/libaaudio/examples/utils/AAudioArgsParser.h b/media/libaaudio/examples/utils/AAudioArgsParser.h
index 9115778..4bba436 100644
--- a/media/libaaudio/examples/utils/AAudioArgsParser.h
+++ b/media/libaaudio/examples/utils/AAudioArgsParser.h
@@ -38,12 +38,15 @@
aaudio_input_preset_t inputPreset) = nullptr;
static void (*s_setAllowedCapturePolicy)(AAudioStreamBuilder* builder,
aaudio_allowed_capture_policy_t usage) = nullptr;
+static void (*s_setPrivacySensitive)(AAudioStreamBuilder* builder,
+ bool privacySensitive) = nullptr;
static bool s_loadAttempted = false;
static aaudio_usage_t (*s_getUsage)(AAudioStream *stream) = nullptr;
static aaudio_content_type_t (*s_getContentType)(AAudioStream *stream) = nullptr;
static aaudio_input_preset_t (*s_getInputPreset)(AAudioStream *stream) = nullptr;
static aaudio_allowed_capture_policy_t (*s_getAllowedCapturePolicy)(AAudioStream *stream) = nullptr;
+static bool (*s_isPrivacySensitive)(AAudioStream *stream) = nullptr;
// Link to test functions in shared library.
static void loadFutureFunctions() {
@@ -68,6 +71,10 @@
dlsym(handle, "AAudioStreamBuilder_setAllowedCapturePolicy");
if (s_setAllowedCapturePolicy == nullptr) goto error;
+ s_setPrivacySensitive = (void (*)(AAudioStreamBuilder *, bool))
+ dlsym(handle, "AAudioStreamBuilder_setPrivacySensitive");
+ if (s_setPrivacySensitive == nullptr) goto error;
+
s_getUsage = (aaudio_usage_t (*)(AAudioStream *))
dlsym(handle, "AAudioStream_getUsage");
if (s_getUsage == nullptr) goto error;
@@ -83,6 +90,10 @@
s_getAllowedCapturePolicy = (aaudio_input_preset_t (*)(AAudioStream *))
dlsym(handle, "AAudioStream_getAllowedCapturePolicy");
if (s_getAllowedCapturePolicy == nullptr) goto error;
+
+ s_isPrivacySensitive = (bool (*)(AAudioStream *))
+ dlsym(handle, "AAudioStream_isPrivacySensitive");
+ if (s_isPrivacySensitive == nullptr) goto error;
}
return;
@@ -91,9 +102,11 @@
s_setUsage = nullptr;
s_setContentType = nullptr;
s_setInputPreset = nullptr;
+ s_setPrivacySensitive = nullptr;
s_getUsage = nullptr;
s_getContentType = nullptr;
s_getInputPreset = nullptr;
+ s_isPrivacySensitive = nullptr;
dlclose(handle);
return;
}
@@ -211,6 +224,14 @@
mFramesPerCallback = size;
}
+ int32_t isPrivacySensitive() const {
+ return mPrivacySensitive;
+ }
+
+ void setPrivacySensitive(int32_t privacySensitive) {
+ mPrivacySensitive = privacySensitive;
+ }
+
/**
* Apply these parameters to a stream builder.
* @param builder
@@ -234,12 +255,12 @@
}
if (s_setContentType != nullptr) {
s_setContentType(builder, mContentType);
- } else if (mUsage != AAUDIO_UNSPECIFIED){
+ } else if (mContentType != AAUDIO_UNSPECIFIED){
printf("WARNING: setContentType not supported");
}
if (s_setInputPreset != nullptr) {
s_setInputPreset(builder, mInputPreset);
- } else if (mUsage != AAUDIO_UNSPECIFIED){
+ } else if (mInputPreset != AAUDIO_UNSPECIFIED){
printf("WARNING: setInputPreset not supported");
}
@@ -249,6 +270,15 @@
} else if (mAllowedCapturePolicy != AAUDIO_UNSPECIFIED){
printf("WARNING: setAllowedCapturePolicy not supported");
}
+
+ if (mPrivacySensitive != PRIVACY_SENSITIVE_DEFAULT) {
+ if (s_setPrivacySensitive != nullptr) {
+ s_setPrivacySensitive(builder,
+ mPrivacySensitive == PRIVACY_SENSITIVE_ENABLED);
+ } else {
+ printf("WARNING: setPrivacySensitive not supported");
+ }
+ }
}
static constexpr int32_t kDefaultNumberOfBursts = 2;
@@ -270,6 +300,13 @@
int32_t mNumberOfBursts = kDefaultNumberOfBursts;
int32_t mFramesPerCallback = AAUDIO_UNSPECIFIED;
+
+ enum {
+ PRIVACY_SENSITIVE_DEFAULT = -1,
+ PRIVACY_SENSITIVE_DISABLED = 0,
+ PRIVACY_SENSITIVE_ENABLED = 1,
+ };
+ int32_t mPrivacySensitive = PRIVACY_SENSITIVE_DEFAULT;
};
class AAudioArgsParser : public AAudioParameters {
@@ -341,6 +378,9 @@
case 'z':
setFramesPerCallback(atoi(&arg[2]));
break;
+ case 'S':
+ setPrivacySensitive(atoi(&arg[2]));
+ break;
default:
unrecognized = true;
break;
@@ -399,6 +439,9 @@
printf(" -x to use EXCLUSIVE mode\n");
printf(" -y{contentType} eg. 1 for AAUDIO_CONTENT_TYPE_SPEECH\n");
printf(" -z{callbackSize} or block size, in frames, default = 0\n");
+ printf(" -S{0|1} set privacy Sensitive enabled or disabled\n");
+ printf(" 0 = disabled\n");
+ printf(" 1 = enabled\n");
}
static aaudio_performance_mode_t parseAllowedCapturePolicy(char c) {
@@ -506,10 +549,15 @@
getContentType(), s_getContentType(stream));
}
- if (AAudioStream_getDirection(stream) == AAUDIO_DIRECTION_INPUT
- && s_getInputPreset != nullptr) {
+ if (AAudioStream_getDirection(stream) == AAUDIO_DIRECTION_INPUT) {
+ if (s_getInputPreset != nullptr) {
printf(" InputPreset: requested = %d, actual = %d\n",
getInputPreset(), s_getInputPreset(stream));
+ }
+ if (s_isPrivacySensitive != nullptr) {
+ printf(" Privacy Sensitive: requested = %d, actual = %d\n",
+ isPrivacySensitive(), s_isPrivacySensitive(stream));
+ }
}
printf(" Is MMAP used? %s\n", AAudioStream_isMMapUsed(stream)
diff --git a/media/libaaudio/examples/write_sine/Android.bp b/media/libaaudio/examples/write_sine/Android.bp
index cc80861..aa25e67 100644
--- a/media/libaaudio/examples/write_sine/Android.bp
+++ b/media/libaaudio/examples/write_sine/Android.bp
@@ -4,7 +4,6 @@
cflags: ["-Wall", "-Werror"],
shared_libs: ["libaaudio"],
header_libs: ["libaaudio_example_utils"],
- pack_relocations: false,
}
cc_test {
@@ -13,5 +12,4 @@
cflags: ["-Wall", "-Werror"],
shared_libs: ["libaaudio"],
header_libs: ["libaaudio_example_utils"],
- pack_relocations: false,
}
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index ee5d089..edc09a9 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -227,6 +227,8 @@
};
typedef int32_t aaudio_performance_mode_t;
+#define AAUDIO_SYSTEM_USAGE_OFFSET 1000
+
/**
* The USAGE attribute expresses "why" you are playing a sound, what is this sound used for.
* This information is used by certain platforms or routing policies
@@ -297,7 +299,31 @@
/**
* Use this for audio responses to user queries, audio instructions or help utterances.
*/
- AAUDIO_USAGE_ASSISTANT = 16
+ AAUDIO_USAGE_ASSISTANT = 16,
+
+ /**
+ * Use this in case of playing sounds in an emergency.
+ * Privileged MODIFY_AUDIO_ROUTING permission required.
+ */
+ AAUDIO_SYSTEM_USAGE_EMERGENCY = AAUDIO_SYSTEM_USAGE_OFFSET,
+
+ /**
+ * Use this for safety sounds and alerts, for example backup camera obstacle detection.
+ * Privileged MODIFY_AUDIO_ROUTING permission required.
+ */
+ AAUDIO_SYSTEM_USAGE_SAFETY = AAUDIO_SYSTEM_USAGE_OFFSET + 1,
+
+ /**
+ * Use this for vehicle status alerts and information, for example the check engine light.
+ * Privileged MODIFY_AUDIO_ROUTING permission required.
+ */
+ AAUDIO_SYSTEM_USAGE_VEHICLE_STATUS = AAUDIO_SYSTEM_USAGE_OFFSET + 2,
+
+ /**
+ * Use this for traffic announcements, etc.
+ * Privileged MODIFY_AUDIO_ROUTING permission required.
+ */
+ AAUDIO_SYSTEM_USAGE_ANNOUNCEMENT = AAUDIO_SYSTEM_USAGE_OFFSET + 3,
};
typedef int32_t aaudio_usage_t;
@@ -472,6 +498,8 @@
* This is intended for developers to use when debugging.
* It is not for display to users.
*
+ * Available since API level 26.
+ *
* @return pointer to a text representation of an AAudio result code.
*/
AAUDIO_API const char * AAudio_convertResultToText(aaudio_result_t returnCode) __INTRODUCED_IN(26);
@@ -482,6 +510,8 @@
* This is intended for developers to use when debugging.
* It is not for display to users.
*
+ * Available since API level 26.
+ *
* @return pointer to a text representation of an AAudio state.
*/
AAUDIO_API const char * AAudio_convertStreamStateToText(aaudio_stream_state_t state)
@@ -502,6 +532,8 @@
* chosen by the device when it is opened.
*
* AAudioStreamBuilder_delete() must be called when you are done using the builder.
+ *
+ * Available since API level 26.
*/
AAUDIO_API aaudio_result_t AAudio_createStreamBuilder(AAudioStreamBuilder** builder)
__INTRODUCED_IN(26);
@@ -513,6 +545,8 @@
* The default, if you do not call this function, is {@link #AAUDIO_UNSPECIFIED},
* in which case the primary device will be used.
*
+ * Available since API level 26.
+ *
* @param builder reference provided by AAudio_createStreamBuilder()
* @param deviceId device identifier or {@link #AAUDIO_UNSPECIFIED}
*/
@@ -530,6 +564,8 @@
* If an exact value is specified then an opened stream will use that value.
* If a stream cannot be opened with the specified value then the open will fail.
*
+ * Available since API level 26.
+ *
* @param builder reference provided by AAudio_createStreamBuilder()
* @param sampleRate frames per second. Common rates include 44100 and 48000 Hz.
*/
@@ -547,6 +583,8 @@
* If an exact value is specified then an opened stream will use that value.
* If a stream cannot be opened with the specified value then the open will fail.
*
+ * Available since API level 26.
+ *
* @param builder reference provided by AAudio_createStreamBuilder()
* @param channelCount Number of channels desired.
*/
@@ -556,6 +594,8 @@
/**
* Identical to AAudioStreamBuilder_setChannelCount().
*
+ * Available since API level 26.
+ *
* @param builder reference provided by AAudio_createStreamBuilder()
* @param samplesPerFrame Number of samples in a frame.
*/
@@ -573,6 +613,8 @@
* If an exact value is specified then an opened stream will use that value.
* If a stream cannot be opened with the specified value then the open will fail.
*
+ * Available since API level 26.
+ *
* @param builder reference provided by AAudio_createStreamBuilder()
* @param format common formats are {@link #AAUDIO_FORMAT_PCM_FLOAT} and
* {@link #AAUDIO_FORMAT_PCM_I16}.
@@ -588,6 +630,8 @@
* The requested sharing mode may not be available.
* The application can query for the actual mode after the stream is opened.
*
+ * Available since API level 26.
+ *
* @param builder reference provided by AAudio_createStreamBuilder()
* @param sharingMode {@link #AAUDIO_SHARING_MODE_SHARED} or {@link #AAUDIO_SHARING_MODE_EXCLUSIVE}
*/
@@ -599,6 +643,8 @@
*
* The default, if you do not call this function, is {@link #AAUDIO_DIRECTION_OUTPUT}.
*
+ * Available since API level 26.
+ *
* @param builder reference provided by AAudio_createStreamBuilder()
* @param direction {@link #AAUDIO_DIRECTION_OUTPUT} or {@link #AAUDIO_DIRECTION_INPUT}
*/
@@ -611,6 +657,8 @@
*
* The default, if you do not call this function, is {@link #AAUDIO_UNSPECIFIED}.
*
+ * Available since API level 26.
+ *
* @param builder reference provided by AAudio_createStreamBuilder()
* @param numFrames the desired buffer capacity in frames or {@link #AAUDIO_UNSPECIFIED}
*/
@@ -629,6 +677,8 @@
* You can call AAudioStream_getPerformanceMode()
* to find out the final mode for the stream.
*
+ * Available since API level 26.
+ *
* @param builder reference provided by AAudio_createStreamBuilder()
* @param mode the desired performance mode, eg. {@link #AAUDIO_PERFORMANCE_MODE_LOW_LATENCY}
*/
@@ -644,7 +694,7 @@
*
* The default, if you do not call this function, is {@link #AAUDIO_USAGE_MEDIA}.
*
- * Added in API level 28.
+ * Available since API level 28.
*
* @param builder reference provided by AAudio_createStreamBuilder()
* @param usage the desired usage, eg. {@link #AAUDIO_USAGE_GAME}
@@ -661,7 +711,7 @@
*
* The default, if you do not call this function, is {@link #AAUDIO_CONTENT_TYPE_MUSIC}.
*
- * Added in API level 28.
+ * Available since API level 28.
*
* @param builder reference provided by AAudio_createStreamBuilder()
* @param contentType the type of audio data, eg. {@link #AAUDIO_CONTENT_TYPE_SPEECH}
@@ -681,7 +731,7 @@
* That is because VOICE_RECOGNITION is the preset with the lowest latency
* on many platforms.
*
- * Added in API level 28.
+ * Available since API level 28.
*
* @param builder reference provided by AAudio_createStreamBuilder()
* @param inputPreset the desired configuration for recording
@@ -697,10 +747,10 @@
* Note that an application can also set its global policy, in which case the most restrictive
* policy is always applied. See {@link android.media.AudioAttributes#setAllowedCapturePolicy(int)}
*
- * Added in API level 29.
+ * Available since API level 29.
*
* @param builder reference provided by AAudio_createStreamBuilder()
- * @param inputPreset the desired level of opt-out from being captured.
+ * @param capturePolicy the desired level of opt-out from being captured.
*/
AAUDIO_API void AAudioStreamBuilder_setAllowedCapturePolicy(AAudioStreamBuilder* builder,
aaudio_allowed_capture_policy_t capturePolicy) __INTRODUCED_IN(29);
@@ -727,7 +777,7 @@
*
* Allocated session IDs will always be positive and nonzero.
*
- * Added in API level 28.
+ * Available since API level 28.
*
* @param builder reference provided by AAudio_createStreamBuilder()
* @param sessionId an allocated sessionID or {@link #AAUDIO_SESSION_ID_ALLOCATE}
@@ -735,6 +785,28 @@
AAUDIO_API void AAudioStreamBuilder_setSessionId(AAudioStreamBuilder* builder,
aaudio_session_id_t sessionId) __INTRODUCED_IN(28);
+
+/** Indicates whether this input stream must be marked as privacy sensitive or not.
+ *
+ * When true, this input stream is privacy sensitive and any concurrent capture
+ * is not permitted.
+ *
+ * This is off (false) by default except when the input preset is {@link #AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION}
+ * or {@link #AAUDIO_INPUT_PRESET_CAMCORDER}.
+ *
+ * Always takes precedence over default from input preset when set explicitly.
+ *
+ * Only relevant if the stream direction is {@link #AAUDIO_DIRECTION_INPUT}.
+ *
+ * Added in API level 30.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder()
+ * @param privacySensitive true if capture from this stream must be marked as privacy sensitive,
+ * false otherwise.
+ */
+AAUDIO_API void AAudioStreamBuilder_setPrivacySensitive(AAudioStreamBuilder* builder,
+ bool privacySensitive) __INTRODUCED_IN(30);
+
/**
* Return one of these values from the data callback function.
*/
@@ -826,6 +898,8 @@
*
* Note that the AAudio callbacks will never be called simultaneously from multiple threads.
*
+ * Available since API level 26.
+ *
* @param builder reference provided by AAudio_createStreamBuilder()
* @param callback pointer to a function that will process audio data.
* @param userData pointer to an application data structure that will be passed
@@ -854,6 +928,8 @@
* If you do call this function then the requested size should be less than
* half the buffer capacity, to allow double buffering.
*
+ * Available since API level 26.
+ *
* @param builder reference provided by AAudio_createStreamBuilder()
* @param numFrames the desired buffer size in frames or {@link #AAUDIO_UNSPECIFIED}
*/
@@ -905,6 +981,8 @@
*
* Note that the AAudio callbacks will never be called simultaneously from multiple threads.
*
+ * Available since API level 26.
+ *
* @param builder reference provided by AAudio_createStreamBuilder()
* @param callback pointer to a function that will be called if an error occurs.
* @param userData pointer to an application data structure that will be passed
@@ -919,6 +997,8 @@
* AAudioStream_close() must be called when finished with the stream to recover
* the memory and to free the associated resources.
*
+ * Available since API level 26.
+ *
* @param builder reference provided by AAudio_createStreamBuilder()
* @param stream pointer to a variable to receive the new stream reference
* @return {@link #AAUDIO_OK} or a negative error.
@@ -929,6 +1009,8 @@
/**
* Delete the resources associated with the StreamBuilder.
*
+ * Available since API level 26.
+ *
* @param builder reference provided by AAudio_createStreamBuilder()
* @return {@link #AAUDIO_OK} or a negative error.
*/
@@ -939,8 +1021,30 @@
// Stream Control
// ============================================================
+#if __ANDROID_API__ >= 30
/**
- * Free the resources associated with a stream created by AAudioStreamBuilder_openStream()
+ * Free the audio resources associated with a stream created by
+ * AAudioStreamBuilder_openStream().
+ * AAudioStream_close() should be called at some point after calling
+ * this function.
+ *
+ * After this call, the stream will be in {@link #AAUDIO_STREAM_STATE_CLOSING}
+ *
+ * This function is useful if you want to release the audio resources immediately,
+ * but still allow queries to the stream to occur from other threads. This often
+ * happens if you are monitoring stream progress from a UI thread.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return {@link #AAUDIO_OK} or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStream_release(AAudioStream* stream) __INTRODUCED_IN(30);
+#endif // __ANDROID_API__
+
+/**
+ * Delete the internal data structures associated with the stream created
+ * by AAudioStreamBuilder_openStream().
+ *
+ * If AAudioStream_release() has not been called then it will be called automatically.
*
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return {@link #AAUDIO_OK} or a negative error.
@@ -954,6 +1058,8 @@
* After this call the state will be in {@link #AAUDIO_STREAM_STATE_STARTING} or
* {@link #AAUDIO_STREAM_STATE_STARTED}.
*
+ * Available since API level 26.
+ *
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return {@link #AAUDIO_OK} or a negative error.
*/
@@ -969,6 +1075,8 @@
* This will return {@link #AAUDIO_ERROR_UNIMPLEMENTED} for input streams.
* For input streams use AAudioStream_requestStop().
*
+ * Available since API level 26.
+ *
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return {@link #AAUDIO_OK} or a negative error.
*/
@@ -984,6 +1092,8 @@
*
* This will return {@link #AAUDIO_ERROR_UNIMPLEMENTED} for input streams.
*
+ * Available since API level 26.
+ *
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return {@link #AAUDIO_OK} or a negative error.
*/
@@ -995,6 +1105,8 @@
* After this call the state will be in {@link #AAUDIO_STREAM_STATE_STOPPING} or
* {@link #AAUDIO_STREAM_STATE_STOPPED}.
*
+ * Available since API level 26.
+ *
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return {@link #AAUDIO_OK} or a negative error.
*/
@@ -1008,6 +1120,8 @@
* call AAudioStream_waitForStateChange() with currentState
* set to {@link #AAUDIO_STREAM_STATE_UNKNOWN} and a zero timeout.
*
+ * Available since API level 26.
+ *
* @param stream reference provided by AAudioStreamBuilder_openStream()
*/
AAUDIO_API aaudio_stream_state_t AAudioStream_getState(AAudioStream* stream) __INTRODUCED_IN(26);
@@ -1028,6 +1142,8 @@
* }
* </code></pre>
*
+ * Available since API level 26.
+ *
* @param stream A reference provided by AAudioStreamBuilder_openStream()
* @param inputState The state we want to avoid.
* @param nextState Pointer to a variable that will be set to the new state.
@@ -1056,6 +1172,8 @@
*
* If the call times out then zero or a partial frame count will be returned.
*
+ * Available since API level 26.
+ *
* @param stream A stream created using AAudioStreamBuilder_openStream().
* @param buffer The address of the first sample.
* @param numFrames Number of frames to read. Only complete frames will be written.
@@ -1079,6 +1197,8 @@
*
* If the call times out then zero or a partial frame count will be returned.
*
+ * Available since API level 26.
+ *
* @param stream A stream created using AAudioStreamBuilder_openStream().
* @param buffer The address of the first sample.
* @param numFrames Number of frames to write. Only complete frames will be written.
@@ -1104,6 +1224,8 @@
* You can check the return value or call AAudioStream_getBufferSizeInFrames()
* to see what the actual final size is.
*
+ * Available since API level 26.
+ *
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @param numFrames requested number of frames that can be filled without blocking
* @return actual buffer size in frames or a negative error
@@ -1114,6 +1236,8 @@
/**
* Query the maximum number of frames that can be filled without blocking.
*
+ * Available since API level 26.
+ *
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return buffer size in frames.
*/
@@ -1129,6 +1253,8 @@
* For some endpoints, the burst size can vary dynamically.
* But these tend to be devices with high latency.
*
+ * Available since API level 26.
+ *
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return burst size
*/
@@ -1137,6 +1263,8 @@
/**
* Query maximum buffer capacity in frames.
*
+ * Available since API level 26.
+ *
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return buffer capacity in frames
*/
@@ -1158,6 +1286,8 @@
* {@link #AAUDIO_UNSPECIFIED} indicates that the callback buffer size for this stream
* may vary from one dataProc callback to the next.
*
+ * Available since API level 26.
+ *
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return callback buffer size in frames or {@link #AAUDIO_UNSPECIFIED}
*/
@@ -1175,12 +1305,16 @@
* Note that some INPUT devices may not support this function.
* In that case a 0 will always be returned.
*
+ * Available since API level 26.
+ *
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return the underrun or overrun count
*/
AAUDIO_API int32_t AAudioStream_getXRunCount(AAudioStream* stream) __INTRODUCED_IN(26);
/**
+ * Available since API level 26.
+ *
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return actual sample rate
*/
@@ -1190,6 +1324,8 @@
* A stream has one or more channels of data.
* A frame will contain one sample for each channel.
*
+ * Available since API level 26.
+ *
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return actual number of channels
*/
@@ -1198,18 +1334,24 @@
/**
* Identical to AAudioStream_getChannelCount().
*
+ * Available since API level 26.
+ *
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return actual number of samples frame
*/
AAUDIO_API int32_t AAudioStream_getSamplesPerFrame(AAudioStream* stream) __INTRODUCED_IN(26);
/**
+ * Available since API level 26.
+ *
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return actual device ID
*/
AAUDIO_API int32_t AAudioStream_getDeviceId(AAudioStream* stream) __INTRODUCED_IN(26);
/**
+ * Available since API level 26.
+ *
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return actual data format
*/
@@ -1217,6 +1359,9 @@
/**
* Provide actual sharing mode.
+ *
+ * Available since API level 26.
+ *
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return actual sharing mode
*/
@@ -1226,12 +1371,16 @@
/**
* Get the performance mode used by the stream.
*
+ * Available since API level 26.
+ *
* @param stream reference provided by AAudioStreamBuilder_openStream()
*/
AAUDIO_API aaudio_performance_mode_t AAudioStream_getPerformanceMode(AAudioStream* stream)
__INTRODUCED_IN(26);
/**
+ * Available since API level 26.
+ *
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return direction
*/
@@ -1245,6 +1394,8 @@
*
* The frame position is monotonically increasing.
*
+ * Available since API level 26.
+ *
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return frames written
*/
@@ -1258,6 +1409,8 @@
*
* The frame position is monotonically increasing.
*
+ * Available since API level 26.
+ *
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return frames read
*/
@@ -1281,7 +1434,7 @@
*
* The sessionID for a stream should not change once the stream has been opened.
*
- * Added in API level 28.
+ * Available since API level 28.
*
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return session ID or {@link #AAUDIO_SESSION_ID_NONE}
@@ -1304,6 +1457,8 @@
*
* The position and time passed back are monotonically increasing.
*
+ * Available since API level 26.
+ *
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @param clockid CLOCK_MONOTONIC or CLOCK_BOOTTIME
* @param framePosition pointer to a variable to receive the position
@@ -1316,7 +1471,7 @@
/**
* Return the use case for the stream.
*
- * Added in API level 28.
+ * Available since API level 28.
*
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return frames read
@@ -1326,7 +1481,7 @@
/**
* Return the content type for the stream.
*
- * Added in API level 28.
+ * Available since API level 28.
*
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return content type, for example {@link #AAUDIO_CONTENT_TYPE_MUSIC}
@@ -1337,7 +1492,7 @@
/**
* Return the input preset for the stream.
*
- * Added in API level 28.
+ * Available since API level 28.
*
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return input preset, for example {@link #AAUDIO_INPUT_PRESET_CAMCORDER}
@@ -1349,7 +1504,7 @@
* Return the policy that determines whether the audio may or may not be captured
* by other apps or the system.
*
- * Added in API level 29.
+ * Available since API level 29.
*
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return the allowed capture policy, for example {@link #AAUDIO_ALLOW_CAPTURE_BY_ALL}
@@ -1357,6 +1512,20 @@
AAUDIO_API aaudio_allowed_capture_policy_t AAudioStream_getAllowedCapturePolicy(
AAudioStream* stream) __INTRODUCED_IN(29);
+
+/**
+ * Return whether this input stream is marked as privacy sensitive or not.
+ *
+ * See {@link #AAudioStreamBuilder_setPrivacySensitive()}.
+ *
+ * Added in API level 30.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return true if privacy sensitive, false otherwise
+ */
+AAUDIO_API bool AAudioStream_isPrivacySensitive(AAudioStream* stream)
+ __INTRODUCED_IN(30);
+
#ifdef __cplusplus
}
#endif
diff --git a/media/libaaudio/libaaudio.map.txt b/media/libaaudio/libaaudio.map.txt
deleted file mode 100644
index a87ede3..0000000
--- a/media/libaaudio/libaaudio.map.txt
+++ /dev/null
@@ -1,61 +0,0 @@
-LIBAAUDIO {
- global:
- AAudio_convertResultToText;
- AAudio_convertStreamStateToText;
- AAudio_createStreamBuilder;
- AAudio_getMMapPolicy;
- AAudio_setMMapPolicy;
- AAudioStreamBuilder_setPerformanceMode;
- AAudioStreamBuilder_setDeviceId;
- AAudioStreamBuilder_setDataCallback;
- AAudioStreamBuilder_setErrorCallback;
- AAudioStreamBuilder_setFramesPerDataCallback;
- AAudioStreamBuilder_setSampleRate;
- AAudioStreamBuilder_setSamplesPerFrame;
- AAudioStreamBuilder_setChannelCount;
- AAudioStreamBuilder_setFormat;
- AAudioStreamBuilder_setSharingMode;
- AAudioStreamBuilder_setDirection;
- AAudioStreamBuilder_setBufferCapacityInFrames;
- AAudioStreamBuilder_setUsage; # introduced=28
- AAudioStreamBuilder_setContentType; # introduced=28
- AAudioStreamBuilder_setInputPreset; # introduced=28
- AAudioStreamBuilder_setAllowedCapturePolicy; # introduced=29
- AAudioStreamBuilder_setSessionId; # introduced=28
- AAudioStreamBuilder_openStream;
- AAudioStreamBuilder_delete;
- AAudioStream_close;
- AAudioStream_requestStart;
- AAudioStream_requestPause;
- AAudioStream_requestFlush;
- AAudioStream_requestStop;
- AAudioStream_getState;
- AAudioStream_waitForStateChange;
- AAudioStream_read;
- AAudioStream_write;
- AAudioStream_setBufferSizeInFrames;
- AAudioStream_getBufferSizeInFrames;
- AAudioStream_getFramesPerDataCallback;
- AAudioStream_getFramesPerBurst;
- AAudioStream_getBufferCapacityInFrames;
- AAudioStream_getXRunCount;
- AAudioStream_getSampleRate;
- AAudioStream_getSamplesPerFrame;
- AAudioStream_getChannelCount;
- AAudioStream_getPerformanceMode;
- AAudioStream_getDeviceId;
- AAudioStream_getFormat;
- AAudioStream_getSharingMode;
- AAudioStream_getDirection;
- AAudioStream_getUsage; # introduced=28
- AAudioStream_getContentType; # introduced=28
- AAudioStream_getInputPreset; # introduced=28
- AAudioStream_getAllowedCapturePolicy; # introduced=29
- AAudioStream_getFramesWritten;
- AAudioStream_getFramesRead;
- AAudioStream_getSessionId; # introduced=28
- AAudioStream_getTimestamp;
- AAudioStream_isMMapUsed;
- local:
- *;
-};
diff --git a/media/libaaudio/src/Android.bp b/media/libaaudio/src/Android.bp
index 4090286..901c28f 100644
--- a/media/libaaudio/src/Android.bp
+++ b/media/libaaudio/src/Android.bp
@@ -10,14 +10,87 @@
"legacy",
"utility",
],
- export_include_dirs: ["."],
- header_libs: ["libaaudio_headers"],
+ header_libs: [
+ "libaaudio_headers",
+ ],
export_header_lib_headers: ["libaaudio_headers"],
+ version_script: "libaaudio.map.txt",
srcs: [
+ "core/AAudioAudio.cpp",
+ ],
+
+ cflags: [
+ "-Wno-unused-parameter",
+ "-Wall",
+ "-Werror",
+
+ // By default, all symbols are hidden.
+ // "-fvisibility=hidden",
+ // AAUDIO_API is used to explicitly export a function or a variable as a visible symbol.
+ "-DAAUDIO_API=__attribute__((visibility(\"default\")))",
+ ],
+
+ shared_libs: [
+ "libaaudio_internal",
+ "libaudioclient",
+ "libaudioutils",
+ "liblog",
+ "libcutils",
+ "libutils",
+ "libbinder",
+ ],
+
+ sanitize: {
+ integer_overflow: true,
+ misc_undefined: ["bounds"],
+ },
+
+ stubs: {
+ symbol_file: "libaaudio.map.txt",
+ versions: ["28"],
+ },
+}
+
+cc_library {
+ name: "libaaudio_internal",
+
+ local_include_dirs: [
+ "binding",
+ "client",
+ "core",
+ "fifo",
+ "legacy",
+ "utility",
+ ],
+
+ export_include_dirs: ["."],
+ header_libs: [
+ "libaaudio_headers",
+ "libmedia_headers",
+ "libmediametrics_headers",
+ ],
+ export_header_lib_headers: ["libaaudio_headers"],
+
+ shared_libs: [
+ "libaudioclient",
+ "libaudioutils",
+ "liblog",
+ "libcutils",
+ "libutils",
+ "libbinder",
+ ],
+
+ cflags: [
+ "-Wno-unused-parameter",
+ "-Wall",
+ "-Werror",
+ ],
+
+ srcs: [
+ "core/AudioGlobal.cpp",
"core/AudioStream.cpp",
"core/AudioStreamBuilder.cpp",
- "core/AAudioAudio.cpp",
"core/AAudioStreamParameters.cpp",
"legacy/AudioStreamLegacy.cpp",
"legacy/AudioStreamRecord.cpp",
@@ -54,25 +127,8 @@
"flowgraph/SourceI16.cpp",
"flowgraph/SourceI24.cpp",
],
-
- cflags: [
- "-Wno-unused-parameter",
- "-Wall",
- "-Werror",
-
- // By default, all symbols are hidden.
- // "-fvisibility=hidden",
- // AAUDIO_API is used to explicitly export a function or a variable as a visible symbol.
- "-DAAUDIO_API=__attribute__((visibility(\"default\")))",
- ],
-
- shared_libs: [
- "libaudioclient",
- "libaudioutils",
- "liblog",
- "libcutils",
- "libutils",
- "libbinder",
- "libaudiomanager",
- ],
+ sanitize: {
+ integer_overflow: true,
+ misc_undefined: ["bounds"],
+ },
}
diff --git a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
index a987fab..b785f88 100644
--- a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
@@ -66,6 +66,8 @@
if (status != NO_ERROR) goto error;
status = parcel->writeInt32(getSessionId());
if (status != NO_ERROR) goto error;
+ status = parcel->writeInt32(isPrivacySensitive() ? 1 : 0);
+ if (status != NO_ERROR) goto error;
return NO_ERROR;
error:
ALOGE("%s(): write failed = %d", __func__, status);
@@ -111,7 +113,9 @@
status = parcel->readInt32(&value);
if (status != NO_ERROR) goto error;
setSessionId(value);
-
+ status = parcel->readInt32(&value);
+ if (status != NO_ERROR) goto error;
+ setPrivacySensitive(value == 1);
return NO_ERROR;
error:
ALOGE("%s(): read failed = %d", __func__, status);
diff --git a/media/libaaudio/src/binding/IAAudioService.cpp b/media/libaaudio/src/binding/IAAudioService.cpp
index 97ad2b0..e017b3a 100644
--- a/media/libaaudio/src/binding/IAAudioService.cpp
+++ b/media/libaaudio/src/binding/IAAudioService.cpp
@@ -237,12 +237,12 @@
status_t BnAAudioService::onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags) {
- aaudio_handle_t streamHandle;
+ aaudio_handle_t streamHandle = 0;
aaudio::AAudioStreamRequest request;
aaudio::AAudioStreamConfiguration configuration;
- pid_t tid;
- int64_t nanoseconds;
- aaudio_result_t result;
+ pid_t tid = 0;
+ int64_t nanoseconds = 0;
+ aaudio_result_t result = AAUDIO_OK;
status_t status = NO_ERROR;
ALOGV("BnAAudioService::onTransact(%i) %i", code, flags);
@@ -285,7 +285,11 @@
case CLOSE_STREAM: {
CHECK_INTERFACE(IAAudioService, data, reply);
- data.readInt32(&streamHandle);
+ status = data.readInt32(&streamHandle);
+ if (status != NO_ERROR) {
+ ALOGE("BnAAudioService::%s(CLOSE_STREAM) streamHandle failed!", __func__);
+ return status;
+ }
result = closeStream(streamHandle);
//ALOGD("BnAAudioService::onTransact CLOSE_STREAM 0x%08X, result = %d",
// streamHandle, result);
@@ -297,6 +301,7 @@
CHECK_INTERFACE(IAAudioService, data, reply);
status = data.readInt32(&streamHandle);
if (status != NO_ERROR) {
+ ALOGE("BnAAudioService::%s(GET_STREAM_DESCRIPTION) streamHandle failed!", __func__);
return status;
}
aaudio::AudioEndpointParcelable parcelable;
@@ -313,7 +318,11 @@
case START_STREAM: {
CHECK_INTERFACE(IAAudioService, data, reply);
- data.readInt32(&streamHandle);
+ status = data.readInt32(&streamHandle);
+ if (status != NO_ERROR) {
+ ALOGE("BnAAudioService::%s(START_STREAM) streamHandle failed!", __func__);
+ return status;
+ }
result = startStream(streamHandle);
ALOGV("BnAAudioService::onTransact START_STREAM 0x%08X, result = %d",
streamHandle, result);
@@ -323,7 +332,11 @@
case PAUSE_STREAM: {
CHECK_INTERFACE(IAAudioService, data, reply);
- data.readInt32(&streamHandle);
+ status = data.readInt32(&streamHandle);
+ if (status != NO_ERROR) {
+ ALOGE("BnAAudioService::%s(PAUSE_STREAM) streamHandle failed!", __func__);
+ return status;
+ }
result = pauseStream(streamHandle);
ALOGV("BnAAudioService::onTransact PAUSE_STREAM 0x%08X, result = %d",
streamHandle, result);
@@ -333,7 +346,11 @@
case STOP_STREAM: {
CHECK_INTERFACE(IAAudioService, data, reply);
- data.readInt32(&streamHandle);
+ status = data.readInt32(&streamHandle);
+ if (status != NO_ERROR) {
+ ALOGE("BnAAudioService::%s(STOP_STREAM) streamHandle failed!", __func__);
+ return status;
+ }
result = stopStream(streamHandle);
ALOGV("BnAAudioService::onTransact STOP_STREAM 0x%08X, result = %d",
streamHandle, result);
@@ -343,7 +360,11 @@
case FLUSH_STREAM: {
CHECK_INTERFACE(IAAudioService, data, reply);
- data.readInt32(&streamHandle);
+ status = data.readInt32(&streamHandle);
+ if (status != NO_ERROR) {
+ ALOGE("BnAAudioService::%s(FLUSH_STREAM) streamHandle failed!", __func__);
+ return status;
+ }
result = flushStream(streamHandle);
ALOGV("BnAAudioService::onTransact FLUSH_STREAM 0x%08X, result = %d",
streamHandle, result);
@@ -353,20 +374,40 @@
case REGISTER_AUDIO_THREAD: {
CHECK_INTERFACE(IAAudioService, data, reply);
- data.readInt32(&streamHandle);
- data.readInt32(&tid);
- data.readInt64(&nanoseconds);
+ status = data.readInt32(&streamHandle);
+ if (status != NO_ERROR) {
+ ALOGE("BnAAudioService::%s(REGISTER_AUDIO_THREAD) streamHandle failed!", __func__);
+ return status;
+ }
+ status = data.readInt32(&tid);
+ if (status != NO_ERROR) {
+ ALOGE("BnAAudioService::%s(REGISTER_AUDIO_THREAD) tid failed!", __func__);
+ return status;
+ }
+ status = data.readInt64(&nanoseconds);
+ if (status != NO_ERROR) {
+ ALOGE("BnAAudioService::%s(REGISTER_AUDIO_THREAD) nanoseconds failed!", __func__);
+ return status;
+ }
result = registerAudioThread(streamHandle, tid, nanoseconds);
- ALOGV("BnAAudioService::onTransact REGISTER_AUDIO_THREAD 0x%08X, result = %d",
- streamHandle, result);
+ ALOGV("BnAAudioService::%s(REGISTER_AUDIO_THREAD) 0x%08X, result = %d",
+ __func__, streamHandle, result);
reply->writeInt32(result);
return NO_ERROR;
} break;
case UNREGISTER_AUDIO_THREAD: {
CHECK_INTERFACE(IAAudioService, data, reply);
- data.readInt32(&streamHandle);
- data.readInt32(&tid);
+ status = data.readInt32(&streamHandle);
+ if (status != NO_ERROR) {
+ ALOGE("BnAAudioService::%s(UNREGISTER_AUDIO_THREAD) streamHandle failed!", __func__);
+ return status;
+ }
+ status = data.readInt32(&tid);
+ if (status != NO_ERROR) {
+ ALOGE("BnAAudioService::%s(UNREGISTER_AUDIO_THREAD) tid failed!", __func__);
+ return status;
+ }
result = unregisterAudioThread(streamHandle, tid);
ALOGV("BnAAudioService::onTransact UNREGISTER_AUDIO_THREAD 0x%08X, result = %d",
streamHandle, result);
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 52eadd4..b6548e6 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -116,6 +116,7 @@
request.getConfiguration().setUsage(getUsage());
request.getConfiguration().setContentType(getContentType());
request.getConfiguration().setInputPreset(getInputPreset());
+ request.getConfiguration().setPrivacySensitive(isPrivacySensitive());
request.getConfiguration().setBufferCapacity(builder.getBufferCapacity());
@@ -232,23 +233,42 @@
mCallbackBuffer = new uint8_t[callbackBufferSize];
}
+ // For debugging and analyzing the distribution of MMAP timestamps.
+ // For OUTPUT, use a NEGATIVE offset to move the CPU writes further BEFORE the HW reads.
+ // For INPUT, use a POSITIVE offset to move the CPU reads further AFTER the HW writes.
+ // You can use this offset to reduce glitching.
+ // You can also use this offset to force glitching. By iterating over multiple
+ // values you can reveal the distribution of the hardware timing jitter.
+ if (mAudioEndpoint.isFreeRunning()) { // MMAP?
+ int32_t offsetMicros = (getDirection() == AAUDIO_DIRECTION_OUTPUT)
+ ? AAudioProperty_getOutputMMapOffsetMicros()
+ : AAudioProperty_getInputMMapOffsetMicros();
+ // This log is used to debug some tricky glitch issues. Please leave.
+ ALOGD_IF(offsetMicros, "%s() - %s mmap offset = %d micros",
+ __func__,
+ (getDirection() == AAUDIO_DIRECTION_OUTPUT) ? "output" : "input",
+ offsetMicros);
+ mTimeOffsetNanos = offsetMicros * AAUDIO_NANOS_PER_MICROSECOND;
+ }
+
+ setBufferSize(capacity / 2); // Default buffer size to match Q
+
setState(AAUDIO_STREAM_STATE_OPEN);
return result;
error:
- close();
+ releaseCloseFinal();
return result;
}
// This must be called under mStreamLock.
-aaudio_result_t AudioStreamInternal::close() {
+aaudio_result_t AudioStreamInternal::release_l() {
aaudio_result_t result = AAUDIO_OK;
ALOGV("%s(): mServiceStreamHandle = 0x%08X", __func__, mServiceStreamHandle);
if (mServiceStreamHandle != AAUDIO_HANDLE_INVALID) {
- // Don't close a stream while it is running.
aaudio_stream_state_t currentState = getState();
- // Don't close a stream while it is running. Stop it first.
+ // Don't release a stream while it is running. Stop it first.
// If DISCONNECTED then we should still try to stop in case the
// error callback is still running.
if (isActive() || currentState == AAUDIO_STREAM_STATE_DISCONNECTED) {
@@ -261,10 +281,8 @@
mServiceInterface.closeStream(serviceStreamHandle);
delete[] mCallbackBuffer;
mCallbackBuffer = nullptr;
-
- setState(AAUDIO_STREAM_STATE_CLOSED);
result = mEndPointParcelable.close();
- aaudio_result_t result2 = AudioStream::close();
+ aaudio_result_t result2 = AudioStream::release_l();
return (result != AAUDIO_OK) ? result : result2;
} else {
return AAUDIO_ERROR_INVALID_HANDLE;
@@ -478,7 +496,8 @@
#if LOG_TIMESTAMPS
logTimestamp(*message);
#endif
- processTimestamp(message->timestamp.position, message->timestamp.timestamp);
+ processTimestamp(message->timestamp.position,
+ message->timestamp.timestamp + mTimeOffsetNanos);
return AAUDIO_OK;
}
@@ -634,7 +653,7 @@
// Should we block?
if (timeoutNanoseconds == 0) {
break; // don't block
- } else if (framesLeft > 0) {
+ } else if (wakeTimeNanos != 0) {
if (!mAudioEndpoint.isFreeRunning()) {
// If there is software on the other end of the FIFO then it may get delayed.
// So wake up just a little after we expect it to be ready.
@@ -693,37 +712,39 @@
aaudio_result_t AudioStreamInternal::setBufferSize(int32_t requestedFrames) {
int32_t adjustedFrames = requestedFrames;
- int32_t actualFrames = 0;
- int32_t maximumSize = getBufferCapacity();
+ const int32_t maximumSize = getBufferCapacity() - mFramesPerBurst;
+ // The buffer size can be set to zero.
+ // This means that the callback may be called when the internal buffer becomes empty.
+ // This will be fine on some devices in ideal circumstances and will result in the
+ // lowest possible latency.
+ // If there are glitches then they should be detected as XRuns and the size can be increased.
+ static const int32_t minimumSize = 0;
// Clip to minimum size so that rounding up will work better.
- if (adjustedFrames < 1) {
- adjustedFrames = 1;
- }
+ adjustedFrames = std::max(minimumSize, adjustedFrames);
- if (adjustedFrames > maximumSize) {
- // Clip to maximum size.
+ // Prevent arithmetic overflow by clipping before we round.
+ if (adjustedFrames >= maximumSize) {
adjustedFrames = maximumSize;
} else {
// Round to the next highest burst size.
int32_t numBursts = (adjustedFrames + mFramesPerBurst - 1) / mFramesPerBurst;
adjustedFrames = numBursts * mFramesPerBurst;
- // Rounding may have gone above maximum.
- if (adjustedFrames > maximumSize) {
- adjustedFrames = maximumSize;
- }
}
- aaudio_result_t result = mAudioEndpoint.setBufferSizeInFrames(adjustedFrames, &actualFrames);
- if (result < 0) {
- return result;
- } else {
- return (aaudio_result_t) actualFrames;
- }
+ // Clip against the actual size from the endpoint.
+ int32_t actualFrames = 0;
+ mAudioEndpoint.setBufferSizeInFrames(maximumSize, &actualFrames);
+ // actualFrames should be <= maximumSize
+ adjustedFrames = std::min(actualFrames, adjustedFrames);
+
+ mBufferSizeInFrames = adjustedFrames;
+ ALOGV("%s(%d) returns %d", __func__, requestedFrames, adjustedFrames);
+ return (aaudio_result_t) adjustedFrames;
}
int32_t AudioStreamInternal::getBufferSize() const {
- return mAudioEndpoint.getBufferSizeInFrames();
+ return mBufferSizeInFrames;
}
int32_t AudioStreamInternal::getBufferCapacity() const {
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index 86c4698..8843a8a 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -58,7 +58,7 @@
aaudio_result_t open(const AudioStreamBuilder &builder) override;
- aaudio_result_t close() override;
+ aaudio_result_t release_l() override;
aaudio_result_t setBufferSize(int32_t requestedFrames) override;
@@ -194,6 +194,7 @@
// By delaying slightly we can avoid waking up before other side is ready.
const int32_t mWakeupDelayNanos; // delay past typical wakeup jitter
const int32_t mMinimumSleepNanos; // minimum sleep while polling
+ int32_t mTimeOffsetNanos = 0; // add to time part of an MMAP timestamp
AudioEndpointParcelable mEndPointParcelable; // description of the buffers filled by service
EndpointDescriptor mEndpointDescriptor; // buffer description with resolved addresses
@@ -203,6 +204,9 @@
// Sometimes the hardware is operating with a different channel count from the app.
// Then we require conversion in AAudio.
int32_t mDeviceChannelCount = 0;
+
+ int32_t mBufferSizeInFrames = 0; // local threshold to control latency
+
};
} /* namespace aaudio */
diff --git a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
index 366cc87..9684ee4 100644
--- a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
@@ -106,9 +106,10 @@
mNeedCatchUp.acknowledge();
}
- // If the write index passed the read index then consider it an overrun.
+ // If the capture buffer is full beyond capacity then consider it an overrun.
// For shared streams, the xRunCount is passed up from the service.
- if (mAudioEndpoint.isFreeRunning() && mAudioEndpoint.getEmptyFramesAvailable() < 0) {
+ if (mAudioEndpoint.isFreeRunning()
+ && mAudioEndpoint.getFullFramesAvailable() > mAudioEndpoint.getBufferCapacityInFrames()) {
mXRunCount++;
if (ATRACE_ENABLED()) {
ATRACE_INT("aaOverRuns", mXRunCount);
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index b8ef247..536009a 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -49,7 +49,7 @@
getDeviceChannelCount());
if (result != AAUDIO_OK) {
- close();
+ releaseCloseFinal();
}
// Sample rate is constrained to common values by now and should not overflow.
int32_t numFrames = kRampMSec * getSampleRate() / AAUDIO_MILLIS_PER_SECOND;
@@ -167,8 +167,10 @@
ATRACE_INT("aaWrote", framesWritten);
}
+ // Sleep if there is too much data in the buffer.
// Calculate an ideal time to wake up.
- if (wakeTimePtr != nullptr && framesWritten >= 0) {
+ if (wakeTimePtr != nullptr
+ && (mAudioEndpoint.getFullFramesAvailable() >= getBufferSize())) {
// By default wake up a few milliseconds from now. // TODO review
int64_t wakeTime = currentNanoTime + (1 * AAUDIO_NANOS_PER_MILLISECOND);
aaudio_stream_state_t state = getState();
@@ -184,14 +186,10 @@
break;
case AAUDIO_STREAM_STATE_STARTED:
{
- // When do we expect the next read burst to occur?
-
- // Calculate frame position based off of the writeCounter because
- // the readCounter might have just advanced in the background,
- // causing us to sleep until a later burst.
- int64_t nextPosition = mAudioEndpoint.getDataWriteCounter() + mFramesPerBurst
- - mAudioEndpoint.getBufferSizeInFrames();
- wakeTime = mClockModel.convertPositionToTime(nextPosition);
+ // Sleep until the readCounter catches up and we only have
+ // the getBufferSize() frames of data sitting in the buffer.
+ int64_t nextReadPosition = mAudioEndpoint.getDataWriteCounter() - getBufferSize();
+ wakeTime = mClockModel.convertPositionToTime(nextReadPosition);
}
break;
default:
diff --git a/media/libaaudio/src/client/IsochronousClockModel.cpp b/media/libaaudio/src/client/IsochronousClockModel.cpp
index 9abdf53..bd46d05 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.cpp
+++ b/media/libaaudio/src/client/IsochronousClockModel.cpp
@@ -18,22 +18,43 @@
//#define LOG_NDEBUG 0
#include <log/log.h>
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
#include <stdint.h>
#include <algorithm>
#include "utility/AudioClock.h"
+#include "utility/AAudioUtilities.h"
#include "IsochronousClockModel.h"
using namespace aaudio;
+using namespace android::audio_utils;
+
+#ifndef ICM_LOG_DRIFT
+#define ICM_LOG_DRIFT 0
+#endif // ICM_LOG_DRIFT
+
+// To enable the timestamp histogram, enter this before opening the stream:
+// adb root
+// adb shell setprop aaudio.log_mask 1
+// A histogram of the lateness of the timestamps will be cleared when the stream is started.
+// It will be updated when the model is stable and receives a timestamp,
+// and dumped to the log when the stream is stopped.
+
IsochronousClockModel::IsochronousClockModel()
: mMarkerFramePosition(0)
, mMarkerNanoTime(0)
, mSampleRate(48000)
- , mFramesPerBurst(64)
+ , mFramesPerBurst(48)
, mMaxMeasuredLatenessNanos(0)
+ , mLatenessForDriftNanos(kInitialLatenessForDriftNanos)
, mState(STATE_STOPPED)
{
+ if ((AAudioProperty_getLogMask() & AAUDIO_LOG_CLOCK_MODEL_HISTOGRAM) != 0) {
+ mHistogramMicros = std::make_unique<Histogram>(kHistogramBinCount,
+ kHistogramBinWidthMicros);
+ }
}
IsochronousClockModel::~IsochronousClockModel() {
@@ -49,6 +70,9 @@
ALOGV("start(nanos = %lld)\n", (long long) nanoTime);
mMarkerNanoTime = nanoTime;
mState = STATE_STARTING;
+ if (mHistogramMicros) {
+ mHistogramMicros->clear();
+ }
}
void IsochronousClockModel::stop(int64_t nanoTime) {
@@ -58,6 +82,9 @@
setPositionAndTime(convertTimeToPosition(nanoTime), nanoTime);
// TODO should we set position?
mState = STATE_STOPPED;
+ if (mHistogramMicros) {
+ dumpHistogram();
+ }
}
bool IsochronousClockModel::isStarting() const {
@@ -90,6 +117,7 @@
// ALOGD("processTimestamp() - mSampleRate = %d", mSampleRate);
// ALOGD("processTimestamp() - mState = %d", mState);
+ int64_t latenessNanos = nanosDelta - expectedNanosDelta;
switch (mState) {
case STATE_STOPPED:
break;
@@ -99,7 +127,7 @@
break;
case STATE_SYNCING:
// This will handle a burst of rapid transfer at the beginning.
- if (nanosDelta < expectedNanosDelta) {
+ if (latenessNanos < 0) {
setPositionAndTime(framePosition, nanoTime);
} else {
// ALOGD("processTimestamp() - advance to STATE_RUNNING");
@@ -107,65 +135,67 @@
}
break;
case STATE_RUNNING:
- if (nanosDelta < expectedNanosDelta) {
+ if (mHistogramMicros) {
+ mHistogramMicros->add(latenessNanos / AAUDIO_NANOS_PER_MICROSECOND);
+ }
+ // Modify estimated position based on lateness.
+ // This affects the "early" side of the window, which controls output glitches.
+ if (latenessNanos < 0) {
// Earlier than expected timestamp.
// This data is probably more accurate, so use it.
// Or we may be drifting due to a fast HW clock.
- //int microsDelta = (int) (nanosDelta / 1000);
- //int expectedMicrosDelta = (int) (expectedNanosDelta / 1000);
- //ALOGD("%s() - STATE_RUNNING - #%d, %4d micros EARLY",
- //__func__, mTimestampCount, expectedMicrosDelta - microsDelta);
-
setPositionAndTime(framePosition, nanoTime);
- } else if (nanosDelta > (expectedNanosDelta + (2 * mBurstPeriodNanos))) {
- // In this case we do not update mMaxMeasuredLatenessNanos because it
- // would force it too high.
- // mMaxMeasuredLatenessNanos should range from 1 to 2 * mBurstPeriodNanos
- //int32_t measuredLatenessNanos = (int32_t)(nanosDelta - expectedNanosDelta);
- //ALOGD("%s() - STATE_RUNNING - #%d, lateness %d - max %d = %4d micros VERY LATE",
- //__func__,
- //mTimestampCount,
- //measuredLatenessNanos / 1000,
- //mMaxMeasuredLatenessNanos / 1000,
- //(measuredLatenessNanos - mMaxMeasuredLatenessNanos) / 1000
- //);
-
- // This typically happens when we are modelling a service instead of a DSP.
- setPositionAndTime(framePosition, nanoTime - (2 * mBurstPeriodNanos));
- } else if (nanosDelta > (expectedNanosDelta + mMaxMeasuredLatenessNanos)) {
- //int32_t previousLatenessNanos = mMaxMeasuredLatenessNanos;
- mMaxMeasuredLatenessNanos = (int32_t)(nanosDelta - expectedNanosDelta);
-
- //ALOGD("%s() - STATE_RUNNING - #%d, newmax %d - oldmax %d = %4d micros LATE",
- //__func__,
- //mTimestampCount,
- //mMaxMeasuredLatenessNanos / 1000,
- //previousLatenessNanos / 1000,
- //(mMaxMeasuredLatenessNanos - previousLatenessNanos) / 1000
- //);
-
- // When we are late, it may be because of preemption in the kernel,
+#if ICM_LOG_DRIFT
+ int earlyDeltaMicros = (int) ((expectedNanosDelta - nanosDelta)/ 1000);
+ ALOGD("%s() - STATE_RUNNING - #%d, %4d micros EARLY",
+ __func__, mTimestampCount, earlyDeltaMicros);
+#endif
+ } else if (latenessNanos > mLatenessForDriftNanos) {
+ // When we are on the late side, it may be because of preemption in the kernel,
// or timing jitter caused by resampling in the DSP,
// or we may be drifting due to a slow HW clock.
// We add slight drift value just in case there is actual long term drift
// forward caused by a slower clock.
// If the clock is faster than the model will get pushed earlier
- // by the code in the preceding branch.
+ // by the code in the earlier branch.
// The two opposing forces should allow the model to track the real clock
// over a long time.
int64_t driftingTime = mMarkerNanoTime + expectedNanosDelta + kDriftNanos;
setPositionAndTime(framePosition, driftingTime);
- //ALOGD("%s() - #%d, max lateness = %d micros",
- //__func__,
- //mTimestampCount,
- //(int) (mMaxMeasuredLatenessNanos / 1000));
+#if ICM_LOG_DRIFT
+ ALOGD("%s() - STATE_RUNNING - #%d, DRIFT, lateness = %d micros",
+ __func__,
+ mTimestampCount,
+ (int) (latenessNanos / 1000));
+#endif
+ }
+
+ // Modify mMaxMeasuredLatenessNanos.
+ // This affects the "late" side of the window, which controls input glitches.
+ if (latenessNanos > mMaxMeasuredLatenessNanos) { // increase
+#if ICM_LOG_DRIFT
+ ALOGD("%s() - STATE_RUNNING - #%d, newmax %d - oldmax %d = %4d micros LATE",
+ __func__,
+ mTimestampCount,
+ (int) (latenessNanos / 1000),
+ mMaxMeasuredLatenessNanos / 1000,
+ (int) ((latenessNanos - mMaxMeasuredLatenessNanos) / 1000)
+ );
+#endif
+ mMaxMeasuredLatenessNanos = (int32_t) latenessNanos;
+ // Calculate upper region that will trigger a drift forwards.
+ mLatenessForDriftNanos = mMaxMeasuredLatenessNanos - (mMaxMeasuredLatenessNanos >> 4);
+ } else { // decrease
+ // If these is an outlier in lateness then mMaxMeasuredLatenessNanos can go high
+ // and stay there. So we slowly reduce mMaxMeasuredLatenessNanos for better
+ // long term stability. The two opposing forces will keep mMaxMeasuredLatenessNanos
+ // within a reasonable range.
+ mMaxMeasuredLatenessNanos -= kDriftNanos;
}
break;
default:
break;
}
-
-// ALOGD("processTimestamp() - mState = %d", mState);
}
void IsochronousClockModel::setSampleRate(int32_t sampleRate) {
@@ -181,9 +211,6 @@
// Update expected lateness based on sampleRate and framesPerBurst
void IsochronousClockModel::update() {
mBurstPeriodNanos = convertDeltaPositionToTime(mFramesPerBurst); // uses mSampleRate
- // Timestamps may be late by up to a burst because we are randomly sampling the time period
- // after the DSP position is actually updated.
- mMaxMeasuredLatenessNanos = mBurstPeriodNanos;
}
int64_t IsochronousClockModel::convertDeltaPositionToTime(int64_t framesDelta) const {
@@ -227,9 +254,7 @@
}
int32_t IsochronousClockModel::getLateTimeOffsetNanos() const {
- // This will never be < 0 because mMaxLatenessNanos starts at
- // mBurstPeriodNanos and only gets bigger.
- return (mMaxMeasuredLatenessNanos - mBurstPeriodNanos) + kExtraLatenessNanos;
+ return mMaxMeasuredLatenessNanos + kExtraLatenessNanos;
}
int64_t IsochronousClockModel::convertPositionToLatestTime(int64_t framePosition) const {
@@ -241,10 +266,19 @@
}
void IsochronousClockModel::dump() const {
- ALOGD("mMarkerFramePosition = %lld", (long long) mMarkerFramePosition);
- ALOGD("mMarkerNanoTime = %lld", (long long) mMarkerNanoTime);
+ ALOGD("mMarkerFramePosition = %" PRIu64, mMarkerFramePosition);
+ ALOGD("mMarkerNanoTime = %" PRIu64, mMarkerNanoTime);
ALOGD("mSampleRate = %6d", mSampleRate);
ALOGD("mFramesPerBurst = %6d", mFramesPerBurst);
ALOGD("mMaxMeasuredLatenessNanos = %6d", mMaxMeasuredLatenessNanos);
ALOGD("mState = %6d", mState);
}
+
+void IsochronousClockModel::dumpHistogram() const {
+ if (!mHistogramMicros) return;
+ std::istringstream istr(mHistogramMicros->dump());
+ std::string line;
+ while (std::getline(istr, line)) {
+ ALOGD("lateness, %s", line.c_str());
+ }
+}
diff --git a/media/libaaudio/src/client/IsochronousClockModel.h b/media/libaaudio/src/client/IsochronousClockModel.h
index 582bf4e..40f066b 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.h
+++ b/media/libaaudio/src/client/IsochronousClockModel.h
@@ -18,6 +18,9 @@
#define ANDROID_AAUDIO_ISOCHRONOUS_CLOCK_MODEL_H
#include <stdint.h>
+
+#include <audio_utils/Histogram.h>
+
#include "utility/AudioClock.h"
namespace aaudio {
@@ -122,6 +125,8 @@
void dump() const;
+ void dumpHistogram() const;
+
private:
int32_t getLateTimeOffsetNanos() const;
@@ -134,21 +139,30 @@
};
// Amount of time to drift forward when we get a late timestamp.
- // This value was calculated to allow tracking of a clock with 50 ppm error.
- static constexpr int32_t kDriftNanos = 10 * 1000;
- // TODO review value of kExtraLatenessNanos
+ static constexpr int32_t kDriftNanos = 1 * 1000;
+ // Safety margin to add to the late edge of the timestamp window.
static constexpr int32_t kExtraLatenessNanos = 100 * 1000;
+ // Initial small threshold for causing a drift later in time.
+ static constexpr int32_t kInitialLatenessForDriftNanos = 10 * 1000;
- int64_t mMarkerFramePosition;
- int64_t mMarkerNanoTime;
+ static constexpr int32_t kHistogramBinWidthMicros = 50;
+ static constexpr int32_t kHistogramBinCount = 128;
+
+ int64_t mMarkerFramePosition; // Estimated HW position.
+ int64_t mMarkerNanoTime; // Estimated HW time.
int32_t mSampleRate;
- int32_t mFramesPerBurst;
- int32_t mBurstPeriodNanos;
+ int32_t mFramesPerBurst; // number of frames transferred at one time.
+ int32_t mBurstPeriodNanos; // Time between HW bursts.
// Includes mBurstPeriodNanos because we sample randomly over time.
int32_t mMaxMeasuredLatenessNanos;
- clock_model_state_t mState;
+ // Threshold for lateness that triggers a drift later in time.
+ int32_t mLatenessForDriftNanos;
+ clock_model_state_t mState; // State machine handles startup sequence.
- int32_t mTimestampCount = 0;
+ int32_t mTimestampCount = 0; // For logging.
+
+ // distribution of timestamps relative to earliest
+ std::unique_ptr<android::audio_utils::Histogram> mHistogramMicros;
void update();
};
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index 44d5122..8965875 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -25,8 +25,8 @@
#include <aaudio/AAudio.h>
#include <aaudio/AAudioTesting.h>
-
#include "AudioClock.h"
+#include "AudioGlobal.h"
#include "AudioStreamBuilder.h"
#include "AudioStream.h"
#include "binding/AAudioCommon.h"
@@ -45,63 +45,14 @@
return AAUDIO_ERROR_NULL; \
}
-#define AAUDIO_CASE_ENUM(name) case name: return #name
-
AAUDIO_API const char * AAudio_convertResultToText(aaudio_result_t returnCode) {
- switch (returnCode) {
- AAUDIO_CASE_ENUM(AAUDIO_OK);
- AAUDIO_CASE_ENUM(AAUDIO_ERROR_DISCONNECTED);
- AAUDIO_CASE_ENUM(AAUDIO_ERROR_ILLEGAL_ARGUMENT);
- // reserved
- AAUDIO_CASE_ENUM(AAUDIO_ERROR_INTERNAL);
- AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_STATE);
- // reserved
- // reserved
- AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_HANDLE);
- // reserved
- AAUDIO_CASE_ENUM(AAUDIO_ERROR_UNIMPLEMENTED);
- AAUDIO_CASE_ENUM(AAUDIO_ERROR_UNAVAILABLE);
- AAUDIO_CASE_ENUM(AAUDIO_ERROR_NO_FREE_HANDLES);
- AAUDIO_CASE_ENUM(AAUDIO_ERROR_NO_MEMORY);
- AAUDIO_CASE_ENUM(AAUDIO_ERROR_NULL);
- AAUDIO_CASE_ENUM(AAUDIO_ERROR_TIMEOUT);
- AAUDIO_CASE_ENUM(AAUDIO_ERROR_WOULD_BLOCK);
- AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_FORMAT);
- AAUDIO_CASE_ENUM(AAUDIO_ERROR_OUT_OF_RANGE);
- AAUDIO_CASE_ENUM(AAUDIO_ERROR_NO_SERVICE);
- AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_RATE);
- }
- return "Unrecognized AAudio error.";
+ return AudioGlobal_convertResultToText(returnCode);
}
AAUDIO_API const char * AAudio_convertStreamStateToText(aaudio_stream_state_t state) {
- switch (state) {
- AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_UNINITIALIZED);
- AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_UNKNOWN);
- AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_OPEN);
- AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_STARTING);
- AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_STARTED);
- AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_PAUSING);
- AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_PAUSED);
- AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_FLUSHING);
- AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_FLUSHED);
- AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_STOPPING);
- AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_STOPPED);
- AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_DISCONNECTED);
- AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_CLOSING);
- AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_CLOSED);
- }
- return "Unrecognized AAudio state.";
+ return AudioGlobal_convertStreamStateToText(state);
}
-#undef AAUDIO_CASE_ENUM
-
-
-/******************************************
- * Static globals.
- */
-static aaudio_policy_t s_MMapPolicy = AAUDIO_UNSPECIFIED;
-
static AudioStream *convertAAudioStreamToAudioStream(AAudioStream* stream)
{
return (AudioStream*) stream;
@@ -197,6 +148,12 @@
streamBuilder->setInputPreset(inputPreset);
}
+AAUDIO_API void AAudioStreamBuilder_setPrivacySensitive(AAudioStreamBuilder* builder,
+ bool privacySensitive) {
+ AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
+ streamBuilder->setPrivacySensitiveRequest(privacySensitive);
+}
+
AAUDIO_API void AAudioStreamBuilder_setBufferCapacityInFrames(AAudioStreamBuilder* builder,
int32_t frames)
{
@@ -273,21 +230,42 @@
return AAUDIO_ERROR_NULL;
}
-AAUDIO_API aaudio_result_t AAudioStream_close(AAudioStream* stream)
-{
+AAUDIO_API aaudio_result_t AAudioStream_release(AAudioStream* stream) {
aaudio_result_t result = AAUDIO_ERROR_NULL;
- AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+ AudioStream* audioStream = convertAAudioStreamToAudioStream(stream);
if (audioStream != nullptr) {
aaudio_stream_id_t id = audioStream->getId();
ALOGD("%s(s#%u) called ---------------", __func__, id);
- result = audioStream->safeClose();
- // Close will only fail if called illegally, for example, from a callback.
+ result = audioStream->safeRelease();
+ // safeRelease() will only fail if called illegally, for example, from a callback.
+ // That would result in the release of an active stream, which would cause a crash.
+ if (result != AAUDIO_OK) {
+ ALOGW("%s(s#%u) failed. Release it from another thread.",
+ __func__, id);
+ }
+ ALOGD("%s(s#%u) returned %d %s ---------", __func__,
+ id, result, AAudio_convertResultToText(result));
+ }
+ return result;
+}
+
+AAUDIO_API aaudio_result_t AAudioStream_close(AAudioStream* stream) {
+ aaudio_result_t result = AAUDIO_ERROR_NULL;
+ AudioStream* audioStream = convertAAudioStreamToAudioStream(stream);
+ if (audioStream != nullptr) {
+ aaudio_stream_id_t id = audioStream->getId();
+ ALOGD("%s(s#%u) called ---------------", __func__, id);
+ result = audioStream->safeRelease();
+ // safeRelease will only fail if called illegally, for example, from a callback.
// That would result in deleting an active stream, which would cause a crash.
- if (result == AAUDIO_OK) {
- audioStream->unregisterPlayerBase();
- delete audioStream;
+ if (result != AAUDIO_OK) {
+ ALOGW("%s(s#%u) failed. Close it from another thread.",
+ __func__, id);
} else {
- ALOGW("%s attempt to close failed. Close it from another thread.", __func__);
+ audioStream->unregisterPlayerBase();
+ // Mark CLOSED to keep destructors from asserting.
+ audioStream->closeFinal();
+ delete audioStream;
}
ALOGD("%s(s#%u) returned %d ---------", __func__, id, result);
}
@@ -543,23 +521,11 @@
}
AAUDIO_API aaudio_policy_t AAudio_getMMapPolicy() {
- return s_MMapPolicy;
+ return AudioGlobal_getMMapPolicy();
}
AAUDIO_API aaudio_result_t AAudio_setMMapPolicy(aaudio_policy_t policy) {
- aaudio_result_t result = AAUDIO_OK;
- switch(policy) {
- case AAUDIO_UNSPECIFIED:
- case AAUDIO_POLICY_NEVER:
- case AAUDIO_POLICY_AUTO:
- case AAUDIO_POLICY_ALWAYS:
- s_MMapPolicy = policy;
- break;
- default:
- result = AAUDIO_ERROR_ILLEGAL_ARGUMENT;
- break;
- }
- return result;
+ return AudioGlobal_setMMapPolicy(policy);
}
AAUDIO_API bool AAudioStream_isMMapUsed(AAudioStream* stream)
@@ -567,3 +533,9 @@
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
return audioStream->isMMap();
}
+
+AAUDIO_API bool AAudioStream_isPrivacySensitive(AAudioStream* stream)
+{
+ AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+ return audioStream->isPrivacySensitive();
+}
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.cpp b/media/libaaudio/src/core/AAudioStreamParameters.cpp
index c9711da..5f45261 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.cpp
+++ b/media/libaaudio/src/core/AAudioStreamParameters.cpp
@@ -47,6 +47,7 @@
mContentType = other.mContentType;
mInputPreset = other.mInputPreset;
mAllowedCapturePolicy = other.mAllowedCapturePolicy;
+ mIsPrivacySensitive = other.mIsPrivacySensitive;
}
static aaudio_result_t isFormatValid(audio_format_t format) {
@@ -132,6 +133,10 @@
case AAUDIO_USAGE_ASSISTANCE_SONIFICATION:
case AAUDIO_USAGE_GAME:
case AAUDIO_USAGE_ASSISTANT:
+ case AAUDIO_SYSTEM_USAGE_EMERGENCY:
+ case AAUDIO_SYSTEM_USAGE_SAFETY:
+ case AAUDIO_SYSTEM_USAGE_VEHICLE_STATUS:
+ case AAUDIO_SYSTEM_USAGE_ANNOUNCEMENT:
break; // valid
default:
ALOGD("usage not valid = %d", mUsage);
@@ -195,4 +200,5 @@
ALOGD("mContentType = %6d", mContentType);
ALOGD("mInputPreset = %6d", mInputPreset);
ALOGD("mAllowedCapturePolicy = %6d", mAllowedCapturePolicy);
+ ALOGD("mIsPrivacySensitive = %s", mIsPrivacySensitive ? "true" : "false");
}
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.h b/media/libaaudio/src/core/AAudioStreamParameters.h
index 2e21a8d..3e65b37 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.h
+++ b/media/libaaudio/src/core/AAudioStreamParameters.h
@@ -128,6 +128,14 @@
mSessionId = sessionId;
}
+ bool isPrivacySensitive() const {
+ return mIsPrivacySensitive;
+ }
+
+ void setPrivacySensitive(bool privacySensitive) {
+ mIsPrivacySensitive = privacySensitive;
+ }
+
/**
* @return bytes per frame of getFormat()
*/
@@ -158,6 +166,7 @@
int32_t mBufferCapacity = AAUDIO_UNSPECIFIED;
aaudio_allowed_capture_policy_t mAllowedCapturePolicy = AAUDIO_UNSPECIFIED;
aaudio_session_id_t mSessionId = AAUDIO_SESSION_ID_NONE;
+ bool mIsPrivacySensitive = false;
};
} /* namespace aaudio */
diff --git a/media/libaaudio/src/core/AudioGlobal.cpp b/media/libaaudio/src/core/AudioGlobal.cpp
new file mode 100644
index 0000000..d299761
--- /dev/null
+++ b/media/libaaudio/src/core/AudioGlobal.cpp
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+#include <aaudio/AAudio.h>
+#include <aaudio/AAudioTesting.h>
+
+#include "AudioGlobal.h"
+
+/******************************************
+ * Static globals.
+ */
+namespace aaudio {
+
+static aaudio_policy_t g_MMapPolicy = AAUDIO_UNSPECIFIED;
+
+aaudio_policy_t AudioGlobal_getMMapPolicy() {
+ return g_MMapPolicy;
+}
+
+aaudio_result_t AudioGlobal_setMMapPolicy(aaudio_policy_t policy) {
+ aaudio_result_t result = AAUDIO_OK;
+ switch(policy) {
+ case AAUDIO_UNSPECIFIED:
+ case AAUDIO_POLICY_NEVER:
+ case AAUDIO_POLICY_AUTO:
+ case AAUDIO_POLICY_ALWAYS:
+ g_MMapPolicy = policy;
+ break;
+ default:
+ result = AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+ break;
+ }
+ return result;
+}
+
+#define AAUDIO_CASE_ENUM(name) case name: return #name
+
+const char* AudioGlobal_convertResultToText(aaudio_result_t returnCode) {
+ switch (returnCode) {
+ AAUDIO_CASE_ENUM(AAUDIO_OK);
+ AAUDIO_CASE_ENUM(AAUDIO_ERROR_DISCONNECTED);
+ AAUDIO_CASE_ENUM(AAUDIO_ERROR_ILLEGAL_ARGUMENT);
+ // reserved
+ AAUDIO_CASE_ENUM(AAUDIO_ERROR_INTERNAL);
+ AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_STATE);
+ // reserved
+ // reserved
+ AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_HANDLE);
+ // reserved
+ AAUDIO_CASE_ENUM(AAUDIO_ERROR_UNIMPLEMENTED);
+ AAUDIO_CASE_ENUM(AAUDIO_ERROR_UNAVAILABLE);
+ AAUDIO_CASE_ENUM(AAUDIO_ERROR_NO_FREE_HANDLES);
+ AAUDIO_CASE_ENUM(AAUDIO_ERROR_NO_MEMORY);
+ AAUDIO_CASE_ENUM(AAUDIO_ERROR_NULL);
+ AAUDIO_CASE_ENUM(AAUDIO_ERROR_TIMEOUT);
+ AAUDIO_CASE_ENUM(AAUDIO_ERROR_WOULD_BLOCK);
+ AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_FORMAT);
+ AAUDIO_CASE_ENUM(AAUDIO_ERROR_OUT_OF_RANGE);
+ AAUDIO_CASE_ENUM(AAUDIO_ERROR_NO_SERVICE);
+ AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_RATE);
+ }
+ return "Unrecognized AAudio error.";
+}
+
+const char* AudioGlobal_convertStreamStateToText(aaudio_stream_state_t state) {
+ switch (state) {
+ AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_UNINITIALIZED);
+ AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_UNKNOWN);
+ AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_OPEN);
+ AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_STARTING);
+ AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_STARTED);
+ AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_PAUSING);
+ AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_PAUSED);
+ AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_FLUSHING);
+ AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_FLUSHED);
+ AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_STOPPING);
+ AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_STOPPED);
+ AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_CLOSING);
+ AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_CLOSED);
+ AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_DISCONNECTED);
+ }
+ return "Unrecognized AAudio state.";
+}
+
+#undef AAUDIO_CASE_ENUM
+
+} // namespace aaudio
diff --git a/media/libaaudio/src/core/AudioGlobal.h b/media/libaaudio/src/core/AudioGlobal.h
new file mode 100644
index 0000000..312cef2
--- /dev/null
+++ b/media/libaaudio/src/core/AudioGlobal.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 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.
+ */
+#ifndef AAUDIO_AUDIOGLOBAL_H
+#define AAUDIO_AUDIOGLOBAL_H
+
+#include <aaudio/AAudio.h>
+#include <aaudio/AAudioTesting.h>
+
+
+namespace aaudio {
+
+aaudio_policy_t AudioGlobal_getMMapPolicy();
+aaudio_result_t AudioGlobal_setMMapPolicy(aaudio_policy_t policy);
+
+const char* AudioGlobal_convertResultToText(aaudio_result_t returnCode);
+const char* AudioGlobal_convertStreamStateToText(aaudio_stream_state_t state);
+
+}
+
+#endif // AAUDIO_AUDIOGLOBAL_H
+
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index f5c97d8..f51db70 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -25,8 +25,9 @@
#include "AudioStreamBuilder.h"
#include "AudioStream.h"
#include "AudioClock.h"
+#include "AudioGlobal.h"
-using namespace aaudio;
+namespace aaudio {
// Sequential number assigned to streams solely for debugging purposes.
@@ -51,7 +52,7 @@
|| getState() == AAUDIO_STREAM_STATE_UNINITIALIZED
|| getState() == AAUDIO_STREAM_STATE_DISCONNECTED),
"~AudioStream() - still in use, state = %s",
- AAudio_convertStreamStateToText(getState()));
+ AudioGlobal_convertStreamStateToText(getState()));
mPlayerBase->clearParentReference(); // remove reference to this AudioStream
}
@@ -90,6 +91,7 @@
if (mAllowedCapturePolicy == AAUDIO_UNSPECIFIED) {
mAllowedCapturePolicy = AAUDIO_ALLOW_CAPTURE_BY_ALL;
}
+ mIsPrivacySensitive = builder.isPrivacySensitive();
// callbacks
mFramesPerDataCallback = builder.getFramesPerDataCallback();
@@ -155,7 +157,7 @@
case AAUDIO_STREAM_STATE_CLOSED:
default:
ALOGW("safePause() stream not running, state = %s",
- AAudio_convertStreamStateToText(getState()));
+ AudioGlobal_convertStreamStateToText(getState()));
return AAUDIO_ERROR_INVALID_STATE;
}
@@ -240,32 +242,36 @@
case AAUDIO_STREAM_STATE_CLOSED:
default:
ALOGW("%s() stream not running, state = %s", __func__,
- AAudio_convertStreamStateToText(getState()));
+ AudioGlobal_convertStreamStateToText(getState()));
return AAUDIO_ERROR_INVALID_STATE;
}
return requestStop();
}
-aaudio_result_t AudioStream::safeClose() {
- // This get temporarily unlocked in the close when joining callback threads.
+aaudio_result_t AudioStream::safeRelease() {
+ // This get temporarily unlocked in the release() when joining callback threads.
std::lock_guard<std::mutex> lock(mStreamLock);
if (collidesWithCallback()) {
ALOGE("%s cannot be called from a callback!", __func__);
return AAUDIO_ERROR_INVALID_STATE;
}
- return close();
+ if (getState() == AAUDIO_STREAM_STATE_CLOSING) {
+ return AAUDIO_OK;
+ }
+ return release_l();
}
void AudioStream::setState(aaudio_stream_state_t state) {
- ALOGV("%s(%d) from %d to %d", __func__, getId(), mState, state);
+ ALOGD("%s(s#%d) from %d to %d", __func__, getId(), mState, state);
// CLOSED is a final state
if (mState == AAUDIO_STREAM_STATE_CLOSED) {
ALOGE("%s(%d) tried to set to %d but already CLOSED", __func__, getId(), state);
- // Once DISCONNECTED, we can only move to CLOSED state.
+ // Once DISCONNECTED, we can only move to CLOSING or CLOSED state.
} else if (mState == AAUDIO_STREAM_STATE_DISCONNECTED
- && state != AAUDIO_STREAM_STATE_CLOSED) {
+ && !(state == AAUDIO_STREAM_STATE_CLOSING
+ || state == AAUDIO_STREAM_STATE_CLOSED)) {
ALOGE("%s(%d) tried to set to %d but already DISCONNECTED", __func__, getId(), state);
} else {
@@ -488,3 +494,5 @@
void AudioStream::MyPlayerBase::destroy() {
unregisterWithAudioManager();
}
+
+} // namespace aaudio
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index 044c979..9bda41b 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -115,13 +115,32 @@
virtual aaudio_result_t open(const AudioStreamBuilder& builder);
/**
- * Close the stream and deallocate any resources from the open() call.
- * It is safe to call close() multiple times.
+ * Free any hardware or system resources from the open() call.
+ * It is safe to call release_l() multiple times.
*/
- virtual aaudio_result_t close() {
+ virtual aaudio_result_t release_l() {
+ setState(AAUDIO_STREAM_STATE_CLOSING);
return AAUDIO_OK;
}
+ aaudio_result_t closeFinal() {
+ // State is checked by destructor.
+ setState(AAUDIO_STREAM_STATE_CLOSED);
+ return AAUDIO_OK;
+ }
+
+ /**
+ * Release then close the stream.
+ * @return AAUDIO_OK or negative error.
+ */
+ aaudio_result_t releaseCloseFinal() {
+ aaudio_result_t result = release_l(); // TODO review locking
+ if (result == AAUDIO_OK) {
+ result = closeFinal();
+ }
+ return result;
+ }
+
// This is only used to identify a stream in the logs without
// revealing any pointers.
aaudio_stream_id_t getId() {
@@ -234,6 +253,10 @@
return mSessionId;
}
+ bool isPrivacySensitive() const {
+ return mIsPrivacySensitive;
+ }
+
/**
* This is only valid after setSamplesPerFrame() and setFormat() have been called.
*/
@@ -369,7 +392,7 @@
*/
aaudio_result_t systemStopFromCallback();
- aaudio_result_t safeClose();
+ aaudio_result_t safeRelease();
protected:
@@ -543,6 +566,13 @@
mAllowedCapturePolicy = policy;
}
+ /**
+ * This should not be called after the open() call.
+ */
+ void setPrivacySensitive(bool privacySensitive) {
+ mIsPrivacySensitive = privacySensitive;
+ }
+
private:
aaudio_result_t safeStop();
@@ -565,6 +595,7 @@
aaudio_content_type_t mContentType = AAUDIO_UNSPECIFIED;
aaudio_input_preset_t mInputPreset = AAUDIO_UNSPECIFIED;
aaudio_allowed_capture_policy_t mAllowedCapturePolicy = AAUDIO_ALLOW_CAPTURE_BY_ALL;
+ bool mIsPrivacySensitive = false;
int32_t mSessionId = AAUDIO_UNSPECIFIED;
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index 08f4958..3a1e1c9 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -27,6 +27,7 @@
#include "binding/AAudioBinderClient.h"
#include "client/AudioStreamInternalCapture.h"
#include "client/AudioStreamInternalPlay.h"
+#include "core/AudioGlobal.h"
#include "core/AudioStream.h"
#include "core/AudioStreamBuilder.h"
#include "legacy/AudioStreamRecord.h"
@@ -112,7 +113,7 @@
}
// The API setting is the highest priority.
- aaudio_policy_t mmapPolicy = AAudio_getMMapPolicy();
+ aaudio_policy_t mmapPolicy = AudioGlobal_getMMapPolicy();
// If not specified then get from a system property.
if (mmapPolicy == AAUDIO_UNSPECIFIED) {
mmapPolicy = AAudioProperty_getMMapPolicy();
@@ -141,14 +142,14 @@
// TODO Support other performance settings in MMAP mode.
// Disable MMAP if low latency not requested.
if (getPerformanceMode() != AAUDIO_PERFORMANCE_MODE_LOW_LATENCY) {
- ALOGD("%s() MMAP not available because AAUDIO_PERFORMANCE_MODE_LOW_LATENCY not used.",
+ ALOGD("%s() MMAP not used because AAUDIO_PERFORMANCE_MODE_LOW_LATENCY not requested.",
__func__);
allowMMap = false;
}
// SessionID and Effects are only supported in Legacy mode.
if (getSessionId() != AAUDIO_SESSION_ID_NONE) {
- ALOGD("%s() MMAP not available because sessionId used.", __func__);
+ ALOGD("%s() MMAP not used because sessionId specified.", __func__);
allowMMap = false;
}
@@ -157,6 +158,19 @@
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
}
+ setPrivacySensitive(false);
+ if (mPrivacySensitiveReq == PRIVACY_SENSITIVE_DEFAULT) {
+ // When not explicitly requested, set privacy sensitive mode according to input preset:
+ // communication and camcorder captures are considered privacy sensitive by default.
+ aaudio_input_preset_t preset = getInputPreset();
+ if (preset == AAUDIO_INPUT_PRESET_CAMCORDER
+ || preset == AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION) {
+ setPrivacySensitive(true);
+ }
+ } else if (mPrivacySensitiveReq == PRIVACY_SENSITIVE_ENABLED) {
+ setPrivacySensitive(true);
+ }
+
result = builder_createStream(getDirection(), sharingMode, allowMMap, &audioStream);
if (result == AAUDIO_OK) {
// Open the stream using the parameters from the builder.
@@ -256,4 +270,5 @@
mFramesPerDataCallback);
ALOGI("usage = %6d, contentType = %d, inputPreset = %d, allowedCapturePolicy = %d",
getUsage(), getContentType(), getInputPreset(), getAllowedCapturePolicy());
+ ALOGI("privacy sensitive = %s", isPrivacySensitive() ? "true" : "false");
}
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.h b/media/libaaudio/src/core/AudioStreamBuilder.h
index 8149af2..d5fb80d 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.h
+++ b/media/libaaudio/src/core/AudioStreamBuilder.h
@@ -98,6 +98,12 @@
return this;
}
+ AudioStreamBuilder* setPrivacySensitiveRequest(bool privacySensitive) {
+ mPrivacySensitiveReq =
+ privacySensitive ? PRIVACY_SENSITIVE_ENABLED : PRIVACY_SENSITIVE_DISABLED;
+ return this;
+ }
+
aaudio_result_t build(AudioStream **streamPtr);
virtual aaudio_result_t validate() const override;
@@ -114,6 +120,14 @@
AAudioStream_errorCallback mErrorCallbackProc = nullptr;
void *mErrorCallbackUserData = nullptr;
+
+ enum {
+ PRIVACY_SENSITIVE_DEFAULT = -1,
+ PRIVACY_SENSITIVE_DISABLED = 0,
+ PRIVACY_SENSITIVE_ENABLED = 1,
+ };
+ typedef int32_t privacy_sensitive_t;
+ privacy_sensitive_t mPrivacySensitiveReq = PRIVACY_SENSITIVE_DEFAULT;
};
} /* namespace aaudio */
diff --git a/media/libaaudio/src/fifo/FifoControllerBase.cpp b/media/libaaudio/src/fifo/FifoControllerBase.cpp
index 66e247f..1dece0e 100644
--- a/media/libaaudio/src/fifo/FifoControllerBase.cpp
+++ b/media/libaaudio/src/fifo/FifoControllerBase.cpp
@@ -33,7 +33,9 @@
}
fifo_frames_t FifoControllerBase::getFullFramesAvailable() {
- return (fifo_frames_t) (getWriteCounter() - getReadCounter());
+ fifo_frames_t temp = 0;
+ __builtin_sub_overflow(getWriteCounter(), getReadCounter(), &temp);
+ return temp;
}
fifo_frames_t FifoControllerBase::getReadIndex() {
@@ -42,7 +44,9 @@
}
void FifoControllerBase::advanceReadIndex(fifo_frames_t numFrames) {
- setReadCounter(getReadCounter() + numFrames);
+ fifo_counter_t temp = 0;
+ __builtin_add_overflow(getReadCounter(), numFrames, &temp);
+ setReadCounter(temp);
}
fifo_frames_t FifoControllerBase::getEmptyFramesAvailable() {
@@ -55,7 +59,9 @@
}
void FifoControllerBase::advanceWriteIndex(fifo_frames_t numFrames) {
- setWriteCounter(getWriteCounter() + numFrames);
+ fifo_counter_t temp = 0;
+ __builtin_add_overflow(getWriteCounter(), numFrames, &temp);
+ setWriteCounter(temp);
}
void FifoControllerBase::setThreshold(fifo_frames_t threshold) {
diff --git a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
index 91d2eff..abc3239 100644
--- a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
@@ -72,7 +72,7 @@
// Implement FixedBlockProcessor
int32_t AudioStreamLegacy::onProcessFixedBlock(uint8_t *buffer, int32_t numBytes) {
- int32_t numFrames = numBytes / getBytesPerDeviceFrame();
+ int32_t numFrames = numBytes / mBlockAdapterBytesPerFrame;
return (int32_t) callDataCallbackFrames(buffer, numFrames);
}
diff --git a/media/libaaudio/src/legacy/AudioStreamLegacy.h b/media/libaaudio/src/legacy/AudioStreamLegacy.h
index 8e78554..da9205f 100644
--- a/media/libaaudio/src/legacy/AudioStreamLegacy.h
+++ b/media/libaaudio/src/legacy/AudioStreamLegacy.h
@@ -133,6 +133,7 @@
MonotonicCounter mTimestampPosition;
FixedBlockAdapter *mBlockAdapter = nullptr;
+ int32_t mBlockAdapterBytesPerFrame = 0;
aaudio_wrapping_frames_t mPositionWhenStarting = 0;
int32_t mCallbackBufferSize = 0;
const android::sp<StreamDeviceCallback> mDeviceCallback;
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index 71efc30..904edd1 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -142,11 +142,13 @@
const audio_source_t source =
AAudioConvert_inputPresetToAudioSource(builder.getInputPreset());
+ const audio_flags_mask_t attrFlags =
+ AAudioConvert_privacySensitiveToAudioFlagsMask(builder.isPrivacySensitive());
const audio_attributes_t attributes = {
.content_type = contentType,
.usage = AUDIO_USAGE_UNKNOWN, // only used for output
.source = source,
- .flags = AUDIO_FLAG_NONE, // Different than the AUDIO_INPUT_FLAGS
+ .flags = attrFlags, // Different than the AUDIO_INPUT_FLAGS
.tags = ""
};
@@ -180,7 +182,7 @@
// Did we get a valid track?
status_t status = mAudioRecord->initCheck();
if (status != OK) {
- close();
+ releaseCloseFinal();
ALOGE("open(), initCheck() returned %d", status);
return AAudioConvert_androidToAAudioResult(status);
}
@@ -211,7 +213,10 @@
// We may need to pass the data through a block size adapter to guarantee constant size.
if (mCallbackBufferSize != AAUDIO_UNSPECIFIED) {
- int callbackSizeBytes = getBytesPerFrame() * mCallbackBufferSize;
+ // The block adapter runs before the format conversion.
+ // So we need to use the device frame size.
+ mBlockAdapterBytesPerFrame = getBytesPerDeviceFrame();
+ int callbackSizeBytes = mBlockAdapterBytesPerFrame * mCallbackBufferSize;
mFixedBlockWriter.open(callbackSizeBytes);
mBlockAdapter = &mFixedBlockWriter;
} else {
@@ -276,16 +281,17 @@
return AAUDIO_OK;
}
-aaudio_result_t AudioStreamRecord::close()
-{
- // TODO add close() or release() to AudioRecord API then call it from here
- if (getState() != AAUDIO_STREAM_STATE_CLOSED) {
+aaudio_result_t AudioStreamRecord::release_l() {
+ // TODO add close() or release() to AudioFlinger's AudioRecord API.
+ // Then call it from here
+ if (getState() != AAUDIO_STREAM_STATE_CLOSING) {
mAudioRecord->removeAudioDeviceCallback(mDeviceCallback);
mAudioRecord.clear();
- setState(AAUDIO_STREAM_STATE_CLOSED);
+ mFixedBlockWriter.close();
+ return AudioStream::release_l();
+ } else {
+ return AAUDIO_OK; // already released
}
- mFixedBlockWriter.close();
- return AudioStream::close();
}
const void * AudioStreamRecord::maybeConvertDeviceData(const void *audioData, int32_t numFrames) {
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.h b/media/libaaudio/src/legacy/AudioStreamRecord.h
index 2f41d34..c5944c7 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.h
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.h
@@ -38,7 +38,7 @@
virtual ~AudioStreamRecord();
aaudio_result_t open(const AudioStreamBuilder & builder) override;
- aaudio_result_t close() override;
+ aaudio_result_t release_l() override;
aaudio_result_t requestStart() override;
aaudio_result_t requestStop() override;
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 094cdd1..d54d043 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -176,7 +176,7 @@
// Did we get a valid track?
status_t status = mAudioTrack->initCheck();
if (status != NO_ERROR) {
- close();
+ releaseCloseFinal();
ALOGE("open(), initCheck() returned %d", status);
return AAudioConvert_androidToAAudioResult(status);
}
@@ -196,7 +196,10 @@
// We may need to pass the data through a block size adapter to guarantee constant size.
if (mCallbackBufferSize != AAUDIO_UNSPECIFIED) {
- int callbackSizeBytes = getBytesPerFrame() * mCallbackBufferSize;
+ // This may need to change if we add format conversion before
+ // the block size adaptation.
+ mBlockAdapterBytesPerFrame = getBytesPerFrame();
+ int callbackSizeBytes = mBlockAdapterBytesPerFrame * mCallbackBufferSize;
mFixedBlockReader.open(callbackSizeBytes);
mBlockAdapter = &mFixedBlockReader;
} else {
@@ -239,14 +242,18 @@
return AAUDIO_OK;
}
-aaudio_result_t AudioStreamTrack::close()
-{
- if (getState() != AAUDIO_STREAM_STATE_CLOSED) {
+aaudio_result_t AudioStreamTrack::release_l() {
+ if (getState() != AAUDIO_STREAM_STATE_CLOSING) {
mAudioTrack->removeAudioDeviceCallback(mDeviceCallback);
- setState(AAUDIO_STREAM_STATE_CLOSED);
+ // TODO Investigate why clear() causes a hang in test_various.cpp
+ // if I call close() from a data callback.
+ // But the same thing in AudioRecord is OK!
+ // mAudioTrack.clear();
+ mFixedBlockReader.close();
+ return AudioStream::release_l();
+ } else {
+ return AAUDIO_OK; // already released
}
- mFixedBlockReader.close();
- return AAUDIO_OK;
}
void AudioStreamTrack::processCallback(int event, void *info) {
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.h b/media/libaaudio/src/legacy/AudioStreamTrack.h
index 68608de..550f693 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.h
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.h
@@ -41,7 +41,7 @@
aaudio_result_t open(const AudioStreamBuilder & builder) override;
- aaudio_result_t close() override;
+ aaudio_result_t release_l() override;
aaudio_result_t requestStart() override;
aaudio_result_t requestPause() override;
diff --git a/media/libaaudio/src/libaaudio.map.txt b/media/libaaudio/src/libaaudio.map.txt
new file mode 100644
index 0000000..2e00aa5
--- /dev/null
+++ b/media/libaaudio/src/libaaudio.map.txt
@@ -0,0 +1,64 @@
+LIBAAUDIO {
+ global:
+ AAudio_convertResultToText;
+ AAudio_convertStreamStateToText;
+ AAudio_createStreamBuilder;
+ AAudio_getMMapPolicy;
+ AAudio_setMMapPolicy;
+ AAudioStreamBuilder_setPerformanceMode;
+ AAudioStreamBuilder_setDeviceId;
+ AAudioStreamBuilder_setDataCallback;
+ AAudioStreamBuilder_setErrorCallback;
+ AAudioStreamBuilder_setFramesPerDataCallback;
+ AAudioStreamBuilder_setSampleRate;
+ AAudioStreamBuilder_setSamplesPerFrame;
+ AAudioStreamBuilder_setChannelCount;
+ AAudioStreamBuilder_setFormat;
+ AAudioStreamBuilder_setSharingMode;
+ AAudioStreamBuilder_setDirection;
+ AAudioStreamBuilder_setBufferCapacityInFrames;
+ AAudioStreamBuilder_setUsage; # introduced=28
+ AAudioStreamBuilder_setContentType; # introduced=28
+ AAudioStreamBuilder_setInputPreset; # introduced=28
+ AAudioStreamBuilder_setAllowedCapturePolicy; # introduced=29
+ AAudioStreamBuilder_setSessionId; # introduced=28
+ AAudioStreamBuilder_setPrivacySensitive; # introduced=30
+ AAudioStreamBuilder_openStream;
+ AAudioStreamBuilder_delete;
+ AAudioStream_close;
+ AAudioStream_requestStart;
+ AAudioStream_requestPause;
+ AAudioStream_requestFlush;
+ AAudioStream_requestStop;
+ AAudioStream_getState;
+ AAudioStream_waitForStateChange;
+ AAudioStream_read;
+ AAudioStream_write;
+ AAudioStream_setBufferSizeInFrames;
+ AAudioStream_getBufferSizeInFrames;
+ AAudioStream_getFramesPerDataCallback;
+ AAudioStream_getFramesPerBurst;
+ AAudioStream_getBufferCapacityInFrames;
+ AAudioStream_getXRunCount;
+ AAudioStream_getSampleRate;
+ AAudioStream_getSamplesPerFrame;
+ AAudioStream_getChannelCount;
+ AAudioStream_getPerformanceMode;
+ AAudioStream_getDeviceId;
+ AAudioStream_getFormat;
+ AAudioStream_getSharingMode;
+ AAudioStream_getDirection;
+ AAudioStream_getUsage; # introduced=28
+ AAudioStream_getContentType; # introduced=28
+ AAudioStream_getInputPreset; # introduced=28
+ AAudioStream_getAllowedCapturePolicy; # introduced=29
+ AAudioStream_getFramesWritten;
+ AAudioStream_getFramesRead;
+ AAudioStream_getSessionId; # introduced=28
+ AAudioStream_getTimestamp;
+ AAudioStream_isMMapUsed;
+ AAudioStream_isPrivacySensitive; # introduced=30
+ AAudioStream_release; # introduced=30
+ local:
+ *;
+};
diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp
index 96ed56a..9007b10 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.cpp
+++ b/media/libaaudio/src/utility/AAudioUtilities.cpp
@@ -24,6 +24,7 @@
#include <utils/Errors.h>
#include "aaudio/AAudio.h"
+#include "core/AudioGlobal.h"
#include <aaudio/AAudioTesting.h>
#include <math.h>
#include <system/audio-base.h>
@@ -182,6 +183,10 @@
STATIC_ASSERT(AAUDIO_USAGE_ASSISTANCE_SONIFICATION == AUDIO_USAGE_ASSISTANCE_SONIFICATION);
STATIC_ASSERT(AAUDIO_USAGE_GAME == AUDIO_USAGE_GAME);
STATIC_ASSERT(AAUDIO_USAGE_ASSISTANT == AUDIO_USAGE_ASSISTANT);
+ STATIC_ASSERT(AAUDIO_SYSTEM_USAGE_EMERGENCY == AUDIO_USAGE_EMERGENCY);
+ STATIC_ASSERT(AAUDIO_SYSTEM_USAGE_SAFETY == AUDIO_USAGE_SAFETY);
+ STATIC_ASSERT(AAUDIO_SYSTEM_USAGE_VEHICLE_STATUS == AUDIO_USAGE_VEHICLE_STATUS);
+ STATIC_ASSERT(AAUDIO_SYSTEM_USAGE_ANNOUNCEMENT == AUDIO_USAGE_ANNOUNCEMENT);
if (usage == AAUDIO_UNSPECIFIED) {
usage = AAUDIO_USAGE_MEDIA;
}
@@ -233,6 +238,11 @@
}
}
+audio_flags_mask_t AAudioConvert_privacySensitiveToAudioFlagsMask(
+ bool privacySensitive) {
+ return privacySensitive ? AUDIO_FLAG_CAPTURE_PRIVATE : AUDIO_FLAG_NONE;
+}
+
int32_t AAudioConvert_framesToBytes(int32_t numFrames,
int32_t bytesPerFrame,
int32_t *sizeInBytes) {
@@ -334,6 +344,34 @@
return prop;
}
+static int32_t AAudioProperty_getMMapOffsetMicros(const char *functionName,
+ const char *propertyName) {
+ const int32_t minMicros = -20000; // arbitrary
+ const int32_t defaultMicros = 0; // arbitrary
+ const int32_t maxMicros = 20000; // arbitrary
+ int32_t prop = property_get_int32(propertyName, defaultMicros);
+ if (prop < minMicros) {
+ ALOGW("%s: clipped %d to %d", functionName, prop, minMicros);
+ prop = minMicros;
+ } else if (prop > maxMicros) {
+ ALOGW("%s: clipped %d to %d", functionName, prop, minMicros);
+ prop = maxMicros;
+ }
+ return prop;
+}
+
+int32_t AAudioProperty_getInputMMapOffsetMicros() {
+ return AAudioProperty_getMMapOffsetMicros(__func__, AAUDIO_PROP_INPUT_MMAP_OFFSET_USEC);
+}
+
+int32_t AAudioProperty_getOutputMMapOffsetMicros() {
+ return AAudioProperty_getMMapOffsetMicros(__func__, AAUDIO_PROP_OUTPUT_MMAP_OFFSET_USEC);
+}
+
+int32_t AAudioProperty_getLogMask() {
+ return property_get_int32(AAUDIO_PROP_LOG_MASK, 0);
+}
+
aaudio_result_t AAudio_isFlushAllowed(aaudio_stream_state_t state) {
aaudio_result_t result = AAUDIO_OK;
switch (state) {
@@ -355,7 +393,7 @@
case AAUDIO_STREAM_STATE_DISCONNECTED:
default:
ALOGE("can only flush stream when PAUSED, OPEN or STOPPED, state = %s",
- AAudio_convertStreamStateToText(state));
+ aaudio::AudioGlobal_convertStreamStateToText(state));
result = AAUDIO_ERROR_INVALID_STATE;
break;
}
diff --git a/media/libaaudio/src/utility/AAudioUtilities.h b/media/libaaudio/src/utility/AAudioUtilities.h
index 76d0457..d2e4805 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.h
+++ b/media/libaaudio/src/utility/AAudioUtilities.h
@@ -92,33 +92,31 @@
audio_flags_mask_t AAudioConvert_allowCapturePolicyToAudioFlagsMask(
aaudio_allowed_capture_policy_t policy);
-// Note that this code may be replaced by Settings or by some other system configuration tool.
+audio_flags_mask_t AAudioConvert_privacySensitiveToAudioFlagsMask(
+ bool privacySensitive);
-#define AAUDIO_PROP_MMAP_POLICY "aaudio.mmap_policy"
+// Note that this code may be replaced by Settings or by some other system configuration tool.
/**
* Read system property.
* @return AAUDIO_UNSPECIFIED, AAUDIO_POLICY_NEVER or AAUDIO_POLICY_AUTO or AAUDIO_POLICY_ALWAYS
*/
int32_t AAudioProperty_getMMapPolicy();
-
-#define AAUDIO_PROP_MMAP_EXCLUSIVE_POLICY "aaudio.mmap_exclusive_policy"
+#define AAUDIO_PROP_MMAP_POLICY "aaudio.mmap_policy"
/**
* Read system property.
* @return AAUDIO_UNSPECIFIED, AAUDIO_POLICY_NEVER or AAUDIO_POLICY_AUTO or AAUDIO_POLICY_ALWAYS
*/
int32_t AAudioProperty_getMMapExclusivePolicy();
-
-#define AAUDIO_PROP_MIXER_BURSTS "aaudio.mixer_bursts"
+#define AAUDIO_PROP_MMAP_EXCLUSIVE_POLICY "aaudio.mmap_exclusive_policy"
/**
* Read system property.
* @return number of bursts per AAudio service mixer cycle
*/
int32_t AAudioProperty_getMixerBursts();
-
-#define AAUDIO_PROP_HW_BURST_MIN_USEC "aaudio.hw_burst_min_usec"
+#define AAUDIO_PROP_MIXER_BURSTS "aaudio.mixer_bursts"
/**
* Read a system property that specifies the number of extra microseconds that a thread
@@ -130,7 +128,6 @@
* @return number of microseconds to delay the wakeup.
*/
int32_t AAudioProperty_getWakeupDelayMicros();
-
#define AAUDIO_PROP_WAKEUP_DELAY_USEC "aaudio.wakeup_delay_usec"
/**
@@ -139,7 +136,6 @@
* @return minimum number of microseconds to sleep.
*/
int32_t AAudioProperty_getMinimumSleepMicros();
-
#define AAUDIO_PROP_MINIMUM_SLEEP_USEC "aaudio.minimum_sleep_usec"
/**
@@ -153,7 +149,35 @@
* @return minimum number of microseconds for a MMAP HW burst
*/
int32_t AAudioProperty_getHardwareBurstMinMicros();
+#define AAUDIO_PROP_HW_BURST_MIN_USEC "aaudio.hw_burst_min_usec"
+/**
+ * Read a system property that specifies an offset that will be added to MMAP timestamps.
+ * This can be used to correct bias in the timestamp.
+ * It can also be used to analyze the time distribution of the timestamp
+ * by progressively modifying the offset and listening for glitches.
+ *
+ * @return number of microseconds to offset the time part of an MMAP timestamp
+ */
+int32_t AAudioProperty_getInputMMapOffsetMicros();
+#define AAUDIO_PROP_INPUT_MMAP_OFFSET_USEC "aaudio.in_mmap_offset_usec"
+
+int32_t AAudioProperty_getOutputMMapOffsetMicros();
+#define AAUDIO_PROP_OUTPUT_MMAP_OFFSET_USEC "aaudio.out_mmap_offset_usec"
+
+// These are powers of two that can be combined as a bit mask.
+// AAUDIO_LOG_CLOCK_MODEL_HISTOGRAM must be enabled before the stream is opened.
+#define AAUDIO_LOG_CLOCK_MODEL_HISTOGRAM 1
+#define AAUDIO_LOG_RESERVED_2 2
+#define AAUDIO_LOG_RESERVED_4 4
+#define AAUDIO_LOG_RESERVED_8 8
+
+/**
+ * Use a mask to enable various logs in AAudio.
+ * @return mask that enables various AAudio logs, such as AAUDIO_LOG_CLOCK_MODEL_HISTOGRAM
+ */
+int32_t AAudioProperty_getLogMask();
+#define AAUDIO_PROP_LOG_MASK "aaudio.log_mask"
/**
* Is flush allowed for the given state?
diff --git a/media/libaaudio/src/utility/FixedBlockAdapter.cpp b/media/libaaudio/src/utility/FixedBlockAdapter.cpp
index 63495f0..b55f827 100644
--- a/media/libaaudio/src/utility/FixedBlockAdapter.cpp
+++ b/media/libaaudio/src/utility/FixedBlockAdapter.cpp
@@ -18,22 +18,17 @@
#include "FixedBlockAdapter.h"
-FixedBlockAdapter::~FixedBlockAdapter() {
- close();
-}
-
int32_t FixedBlockAdapter::open(int32_t bytesPerFixedBlock)
{
mSize = bytesPerFixedBlock;
- mStorage = new uint8_t[bytesPerFixedBlock];
+ mStorage = std::make_unique<uint8_t[]>(bytesPerFixedBlock);
mPosition = 0;
return 0;
}
int32_t FixedBlockAdapter::close()
{
- delete[] mStorage;
- mStorage = nullptr;
+ mStorage.reset();
mSize = 0;
mPosition = 0;
return 0;
diff --git a/media/libaaudio/src/utility/FixedBlockAdapter.h b/media/libaaudio/src/utility/FixedBlockAdapter.h
index 7008b25..4dc7e68 100644
--- a/media/libaaudio/src/utility/FixedBlockAdapter.h
+++ b/media/libaaudio/src/utility/FixedBlockAdapter.h
@@ -17,6 +17,7 @@
#ifndef AAUDIO_FIXED_BLOCK_ADAPTER_H
#define AAUDIO_FIXED_BLOCK_ADAPTER_H
+#include <memory>
#include <stdio.h>
/**
@@ -37,7 +38,7 @@
FixedBlockAdapter(FixedBlockProcessor &fixedBlockProcessor)
: mFixedBlockProcessor(fixedBlockProcessor) {}
- virtual ~FixedBlockAdapter();
+ virtual ~FixedBlockAdapter() = default;
/**
* Allocate internal resources needed for buffering data.
@@ -63,7 +64,7 @@
protected:
FixedBlockProcessor &mFixedBlockProcessor;
- uint8_t *mStorage = nullptr; // Store data here while assembling buffers.
+ std::unique_ptr<uint8_t[]> mStorage; // Store data here while assembling buffers.
int32_t mSize = 0; // Size in bytes of the fixed size buffer.
int32_t mPosition = 0; // Offset of the last byte read or written.
};
diff --git a/media/libaaudio/src/utility/FixedBlockReader.cpp b/media/libaaudio/src/utility/FixedBlockReader.cpp
index 21ea70e..7931fa0 100644
--- a/media/libaaudio/src/utility/FixedBlockReader.cpp
+++ b/media/libaaudio/src/utility/FixedBlockReader.cpp
@@ -39,7 +39,7 @@
if (bytesToRead > dataAvailable) {
bytesToRead = dataAvailable;
}
- memcpy(buffer, mStorage + mPosition, bytesToRead);
+ memcpy(buffer, &mStorage[mPosition], bytesToRead);
mPosition += bytesToRead;
return bytesToRead;
}
@@ -60,7 +60,7 @@
bytesLeft -= mSize;
} else {
// Just need a partial block so we have to use storage.
- result = mFixedBlockProcessor.onProcessFixedBlock(mStorage, mSize);
+ result = mFixedBlockProcessor.onProcessFixedBlock(mStorage.get(), mSize);
mPosition = 0;
}
}
diff --git a/media/libaaudio/src/utility/FixedBlockWriter.cpp b/media/libaaudio/src/utility/FixedBlockWriter.cpp
index 2ce8046..afb83c1 100644
--- a/media/libaaudio/src/utility/FixedBlockWriter.cpp
+++ b/media/libaaudio/src/utility/FixedBlockWriter.cpp
@@ -30,7 +30,7 @@
if (bytesToStore > roomAvailable) {
bytesToStore = roomAvailable;
}
- memcpy(mStorage + mPosition, buffer, bytesToStore);
+ memcpy(&mStorage[mPosition], buffer, bytesToStore);
mPosition += bytesToStore;
return bytesToStore;
}
@@ -46,7 +46,7 @@
bytesLeft -= bytesWritten;
// If storage full then flush it out
if (mPosition == mSize) {
- result = mFixedBlockProcessor.onProcessFixedBlock(mStorage, mSize);
+ result = mFixedBlockProcessor.onProcessFixedBlock(mStorage.get(), mSize);
mPosition = 0;
}
}
diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
index 6101e99..73fd896 100644
--- a/media/libaaudio/tests/Android.bp
+++ b/media/libaaudio/tests/Android.bp
@@ -11,7 +11,7 @@
defaults: ["libaaudio_tests_defaults"],
srcs: ["test_marshalling.cpp"],
shared_libs: [
- "libaaudio",
+ "libaaudio_internal",
"libbinder",
"libcutils",
"libutils",
@@ -23,7 +23,7 @@
defaults: ["libaaudio_tests_defaults"],
srcs: ["test_clock_model.cpp"],
shared_libs: [
- "libaaudio",
+ "libaaudio_internal",
"libaudioutils",
"libcutils",
"libutils",
@@ -34,7 +34,7 @@
name: "test_block_adapter",
defaults: ["libaaudio_tests_defaults"],
srcs: ["test_block_adapter.cpp"],
- shared_libs: ["libaaudio"],
+ shared_libs: ["libaaudio_internal"],
}
cc_test {
@@ -170,7 +170,7 @@
name: "test_atomic_fifo",
defaults: ["libaaudio_tests_defaults"],
srcs: ["test_atomic_fifo.cpp"],
- shared_libs: ["libaaudio"],
+ shared_libs: ["libaaudio_internal"],
}
cc_test {
@@ -178,7 +178,7 @@
defaults: ["libaaudio_tests_defaults"],
srcs: ["test_flowgraph.cpp"],
shared_libs: [
- "libaaudio",
+ "libaaudio_internal",
"libbinder",
"libcutils",
"libutils",
@@ -215,3 +215,14 @@
srcs: ["test_full_queue.cpp"],
shared_libs: ["libaaudio"],
}
+
+cc_test {
+ name: "test_histogram",
+ defaults: ["libaaudio_tests_defaults"],
+ srcs: ["test_histogram.cpp"],
+ shared_libs: [
+ "libaudioutils",
+ "libcutils",
+ "libutils",
+ ],
+}
diff --git a/media/libaaudio/tests/test_attributes.cpp b/media/libaaudio/tests/test_attributes.cpp
index 32ee2a3..d540866 100644
--- a/media/libaaudio/tests/test_attributes.cpp
+++ b/media/libaaudio/tests/test_attributes.cpp
@@ -33,6 +33,7 @@
aaudio_content_type_t contentType,
aaudio_input_preset_t preset = DONT_SET,
aaudio_allowed_capture_policy_t capturePolicy = DONT_SET,
+ int privacyMode = DONT_SET,
aaudio_direction_t direction = AAUDIO_DIRECTION_OUTPUT) {
float *buffer = new float[kNumFrames * kChannelCount];
@@ -60,6 +61,9 @@
if (capturePolicy != DONT_SET) {
AAudioStreamBuilder_setAllowedCapturePolicy(aaudioBuilder, capturePolicy);
}
+ if (privacyMode != DONT_SET) {
+ AAudioStreamBuilder_setPrivacySensitive(aaudioBuilder, (bool)privacyMode);
+ }
// Create an AAudioStream using the Builder.
ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream));
@@ -90,6 +94,13 @@
: preset;
EXPECT_EQ(expectedCapturePolicy, AAudioStream_getAllowedCapturePolicy(aaudioStream));
+ bool expectedPrivacyMode =
+ (privacyMode == DONT_SET) ?
+ ((preset == AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION
+ || preset == AAUDIO_INPUT_PRESET_CAMCORDER) ? true : false) :
+ privacyMode;
+ EXPECT_EQ(expectedPrivacyMode, AAudioStream_isPrivacySensitive(aaudioStream));
+
EXPECT_EQ(AAUDIO_OK, AAudioStream_requestStart(aaudioStream));
if (direction == AAUDIO_DIRECTION_INPUT) {
@@ -120,7 +131,11 @@
AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
AAUDIO_USAGE_ASSISTANCE_SONIFICATION,
AAUDIO_USAGE_GAME,
- AAUDIO_USAGE_ASSISTANT
+ AAUDIO_USAGE_ASSISTANT,
+ AAUDIO_SYSTEM_USAGE_EMERGENCY,
+ AAUDIO_SYSTEM_USAGE_SAFETY,
+ AAUDIO_SYSTEM_USAGE_VEHICLE_STATUS,
+ AAUDIO_SYSTEM_USAGE_ANNOUNCEMENT
};
static const aaudio_content_type_t sContentypes[] = {
@@ -151,6 +166,12 @@
AAUDIO_ALLOW_CAPTURE_BY_NONE,
};
+static const int sPrivacyModes[] = {
+ DONT_SET,
+ false,
+ true,
+};
+
static void checkAttributesUsage(aaudio_performance_mode_t perfMode) {
for (aaudio_usage_t usage : sUsages) {
checkAttributes(perfMode, usage, DONT_SET);
@@ -170,6 +191,7 @@
DONT_SET,
inputPreset,
DONT_SET,
+ DONT_SET,
AAUDIO_DIRECTION_INPUT);
}
}
@@ -185,6 +207,18 @@
}
}
+static void checkAttributesPrivacySensitive(aaudio_performance_mode_t perfMode) {
+ for (int privacyMode : sPrivacyModes) {
+ checkAttributes(perfMode,
+ DONT_SET,
+ DONT_SET,
+ DONT_SET,
+ DONT_SET,
+ privacyMode,
+ AAUDIO_DIRECTION_INPUT);
+ }
+}
+
TEST(test_attributes, aaudio_usage_perfnone) {
checkAttributesUsage(AAUDIO_PERFORMANCE_MODE_NONE);
}
@@ -216,3 +250,7 @@
TEST(test_attributes, aaudio_allowed_capture_policy_lowlat) {
checkAttributesAllowedCapturePolicy(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
}
+
+TEST(test_attributes, aaudio_allowed_privacy_sensitive_lowlat) {
+ checkAttributesPrivacySensitive(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
+}
diff --git a/media/libaaudio/tests/test_histogram.cpp b/media/libaaudio/tests/test_histogram.cpp
new file mode 100644
index 0000000..431373d
--- /dev/null
+++ b/media/libaaudio/tests/test_histogram.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright 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 Histogram
+ */
+
+#include <iostream>
+
+#include <gtest/gtest.h>
+
+#include <audio_utils/Histogram.h>
+
+using namespace android::audio_utils;
+
+static constexpr int32_t kBinWidth = 10;
+static constexpr int32_t kNumBins = 20;
+
+TEST(test_histogram, module_sinki16) {
+ Histogram histogram(kNumBins, kBinWidth);
+ ASSERT_EQ(kNumBins, histogram.getNumBinsInRange());
+
+ // Is it clear initially?
+ for (int i = 0; i < kNumBins; i++) {
+ ASSERT_EQ(0, histogram.getCount(i));
+ }
+ ASSERT_EQ(0, histogram.getCountBelowRange());
+ ASSERT_EQ(0, histogram.getCountAboveRange());
+ ASSERT_EQ(0, histogram.getCount());
+
+ // Add some items.
+ histogram.add(27);
+ histogram.add(53);
+ histogram.add(171);
+ histogram.add(23);
+
+ // Did they count correctly.
+ ASSERT_EQ(2, histogram.getCount(2)); // For items 27 and 23
+ ASSERT_EQ(3, histogram.getLastItemNumber(2)); // Item 23 was the 0,1,2,3th item added.
+ ASSERT_EQ(1, histogram.getCount(5)); // For item 53
+ ASSERT_EQ(1, histogram.getLastItemNumber(5)); // item 53 was the second item added.
+ ASSERT_EQ(1, histogram.getCount(17)); // For item 171
+ ASSERT_EQ(4, histogram.getCount()); // A total of four items were added.
+
+ // Add values out of range.
+ histogram.add(-5);
+ ASSERT_EQ(1, histogram.getCountBelowRange()); // -5 is below zero.
+ ASSERT_EQ(0, histogram.getCountAboveRange());
+ ASSERT_EQ(5, histogram.getCount());
+
+ histogram.add(200);
+ ASSERT_EQ(1, histogram.getCountBelowRange());
+ ASSERT_EQ(1, histogram.getCountAboveRange()); // 200 is above top bin
+ ASSERT_EQ(6, histogram.getCount());
+
+ // Try to read values out of range. Should not crash.
+ // Legal index range is 0 to numBins-1
+ histogram.add(-1);
+ histogram.add(kNumBins);
+ ASSERT_EQ(0, histogram.getCount(-1)); // edge
+ ASSERT_EQ(0, histogram.getCount(kNumBins)); // edge
+ ASSERT_EQ(0, histogram.getCount(-1234)); // extreme
+ ASSERT_EQ(0, histogram.getCount(98765)); // extreme
+ ASSERT_EQ(0, histogram.getLastItemNumber(-1));
+ ASSERT_EQ(0, histogram.getLastItemNumber(kNumBins));
+
+ // Clear all the counts.
+ histogram.clear();
+ // Is it clear?
+ for (int i = 0; i < kNumBins; i++) {
+ ASSERT_EQ(0, histogram.getCount(i));
+ }
+ ASSERT_EQ(0, histogram.getCountBelowRange());
+ ASSERT_EQ(0, histogram.getCountAboveRange());
+ ASSERT_EQ(0, histogram.getCount());
+}
diff --git a/media/libaaudio/tests/test_various.cpp b/media/libaaudio/tests/test_various.cpp
index 4b065c9..5bb1046 100644
--- a/media/libaaudio/tests/test_various.cpp
+++ b/media/libaaudio/tests/test_various.cpp
@@ -40,10 +40,62 @@
return AAUDIO_CALLBACK_RESULT_CONTINUE;
}
-// Test AAudioStream_setBufferSizeInFrames()
-
constexpr int64_t NANOS_PER_MILLISECOND = 1000 * 1000;
+void checkReleaseThenClose(aaudio_performance_mode_t perfMode,
+ aaudio_sharing_mode_t sharingMode) {
+ AAudioStreamBuilder* aaudioBuilder = nullptr;
+ AAudioStream* aaudioStream = nullptr;
+
+ // Use an AAudioStreamBuilder to contain requested parameters.
+ ASSERT_EQ(AAUDIO_OK, AAudio_createStreamBuilder(&aaudioBuilder));
+
+ // Request stream properties.
+ AAudioStreamBuilder_setDataCallback(aaudioBuilder,
+ NoopDataCallbackProc,
+ nullptr);
+ AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, perfMode);
+ AAudioStreamBuilder_setSharingMode(aaudioBuilder, sharingMode);
+
+ // Create an AAudioStream using the Builder.
+ ASSERT_EQ(AAUDIO_OK,
+ AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream));
+ AAudioStreamBuilder_delete(aaudioBuilder);
+
+ ASSERT_EQ(AAUDIO_OK, AAudioStream_requestStart(aaudioStream));
+
+ sleep(1);
+
+ EXPECT_EQ(AAUDIO_OK, AAudioStream_requestStop(aaudioStream));
+
+ EXPECT_EQ(AAUDIO_OK, AAudioStream_release(aaudioStream));
+ aaudio_stream_state_t state = AAudioStream_getState(aaudioStream);
+ EXPECT_EQ(AAUDIO_STREAM_STATE_CLOSING, state);
+
+ // We should be able to call this again without crashing.
+ EXPECT_EQ(AAUDIO_OK, AAudioStream_release(aaudioStream));
+ state = AAudioStream_getState(aaudioStream);
+ EXPECT_EQ(AAUDIO_STREAM_STATE_CLOSING, state);
+
+ EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream));
+}
+
+TEST(test_various, aaudio_release_close_none) {
+ checkReleaseThenClose(AAUDIO_PERFORMANCE_MODE_NONE,
+ AAUDIO_SHARING_MODE_SHARED);
+ // No EXCLUSIVE streams with MODE_NONE.
+}
+
+TEST(test_various, aaudio_release_close_low_shared) {
+ checkReleaseThenClose(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+ AAUDIO_SHARING_MODE_SHARED);
+}
+
+TEST(test_various, aaudio_release_close_low_exclusive) {
+ checkReleaseThenClose(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+ AAUDIO_SHARING_MODE_EXCLUSIVE);
+}
+
enum FunctionToCall {
CALL_START, CALL_STOP, CALL_PAUSE, CALL_FLUSH
};
@@ -441,7 +493,7 @@
bufferCapacity, bufferCapacity % framesPerBurst);
actualSize = AAudioStream_setBufferSizeInFrames(aaudioStream, 0);
- EXPECT_GT(actualSize, 0);
+ EXPECT_GE(actualSize, 0); // 0 is legal in R
EXPECT_LE(actualSize, bufferCapacity);
actualSize = AAudioStream_setBufferSizeInFrames(aaudioStream, 2 * framesPerBurst);
@@ -469,7 +521,7 @@
EXPECT_LE(actualSize, bufferCapacity);
actualSize = AAudioStream_setBufferSizeInFrames(aaudioStream, INT32_MIN);
- EXPECT_GT(actualSize, 0);
+ EXPECT_GE(actualSize, 0); // 0 is legal in R
EXPECT_LE(actualSize, bufferCapacity);
AAudioStream_close(aaudioStream);
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 03bd6ce..65afc8d 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -1,7 +1,15 @@
cc_library_headers {
name: "libaudioclient_headers",
vendor_available: true,
- export_include_dirs: ["include"],
+ header_libs: [
+ "libaudiofoundation_headers",
+ ],
+ export_include_dirs: [
+ "include",
+ ],
+ export_header_lib_headers: [
+ "libaudiofoundation_headers",
+ ],
}
cc_library_shared {
@@ -13,6 +21,7 @@
"AudioVolumeGroup.cpp",
],
shared_libs: [
+ "libaudiofoundation",
"libaudioutils",
"libbinder",
"libcutils",
@@ -42,7 +51,8 @@
// AIDL files for audioclient interfaces
// The headers for these interfaces will be available to any modules that
// include libaudioclient, at the path "aidl/package/path/BnFoo.h"
- "aidl/android/media/IAudioRecord.aidl",
+ ":libaudioclient_aidl_callback",
+ ":libaudioclient_aidl_private",
":libaudioclient_aidl",
"AudioEffect.cpp",
@@ -63,6 +73,7 @@
"TrackPlayerBase.cpp",
],
shared_libs: [
+ "libaudiofoundation",
"libaudioutils",
"libaudiopolicy",
"libaudiomanager",
@@ -80,10 +91,16 @@
],
export_shared_lib_headers: ["libbinder"],
- local_include_dirs: ["include/media", "aidl"],
+ include_dirs: [
+ "frameworks/av/media/libnbaio/include_mono/",
+ ],
+ local_include_dirs: [
+ "include/media", "aidl"
+ ],
header_libs: [
"libaudioclient_headers",
"libbase_headers",
+ "libmedia_headers",
],
export_header_lib_headers: ["libaudioclient_headers"],
@@ -110,4 +127,24 @@
srcs: [
"aidl/android/media/IPlayer.aidl",
],
+ path: "aidl",
+}
+
+// Used to strip the "aidl/" from the path, so the build system can predict the
+// output filename.
+filegroup {
+ name: "libaudioclient_aidl_private",
+ srcs: [
+ "aidl/android/media/IAudioRecord.aidl",
+ ],
+ path: "aidl",
+}
+
+// AIDL interface for audio track callback
+filegroup {
+ name: "libaudioclient_aidl_callback",
+ srcs: [
+ "aidl/android/media/IAudioTrackCallback.aidl",
+ ],
+ path: "aidl",
}
diff --git a/media/libaudioclient/AudioEffect.cpp b/media/libaudioclient/AudioEffect.cpp
index cf11936..c183ab0 100644
--- a/media/libaudioclient/AudioEffect.cpp
+++ b/media/libaudioclient/AudioEffect.cpp
@@ -36,7 +36,7 @@
// ---------------------------------------------------------------------------
AudioEffect::AudioEffect(const String16& opPackageName)
- : mStatus(NO_INIT), mOpPackageName(opPackageName)
+ : mStatus(NO_INIT), mProbe(false), mOpPackageName(opPackageName)
{
}
@@ -48,12 +48,14 @@
effect_callback_t cbf,
void* user,
audio_session_t sessionId,
- audio_io_handle_t io
+ audio_io_handle_t io,
+ const AudioDeviceTypeAddr& device,
+ bool probe
)
- : mStatus(NO_INIT), mOpPackageName(opPackageName)
+ : mStatus(NO_INIT), mProbe(false), mOpPackageName(opPackageName)
{
AutoMutex lock(mConstructLock);
- mStatus = set(type, uuid, priority, cbf, user, sessionId, io);
+ mStatus = set(type, uuid, priority, cbf, user, sessionId, io, device, probe);
}
AudioEffect::AudioEffect(const char *typeStr,
@@ -63,9 +65,11 @@
effect_callback_t cbf,
void* user,
audio_session_t sessionId,
- audio_io_handle_t io
+ audio_io_handle_t io,
+ const AudioDeviceTypeAddr& device,
+ bool probe
)
- : mStatus(NO_INIT), mOpPackageName(opPackageName)
+ : mStatus(NO_INIT), mProbe(false), mOpPackageName(opPackageName)
{
effect_uuid_t type;
effect_uuid_t *pType = NULL;
@@ -87,7 +91,7 @@
}
AutoMutex lock(mConstructLock);
- mStatus = set(pType, pUuid, priority, cbf, user, sessionId, io);
+ mStatus = set(pType, pUuid, priority, cbf, user, sessionId, io, device, probe);
}
status_t AudioEffect::set(const effect_uuid_t *type,
@@ -96,7 +100,9 @@
effect_callback_t cbf,
void* user,
audio_session_t sessionId,
- audio_io_handle_t io)
+ audio_io_handle_t io,
+ const AudioDeviceTypeAddr& device,
+ bool probe)
{
sp<IEffect> iEffect;
sp<IMemory> cblk;
@@ -109,6 +115,10 @@
return INVALID_OPERATION;
}
+ if (sessionId == AUDIO_SESSION_DEVICE && io != AUDIO_IO_HANDLE_NONE) {
+ ALOGW("IO handle should not be specified for device effect");
+ return BAD_VALUE;
+ }
const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
if (audioFlinger == 0) {
ALOGE("set(): Could not get audioflinger");
@@ -119,7 +129,7 @@
ALOGW("Must specify at least type or uuid");
return BAD_VALUE;
}
-
+ mProbe = probe;
mPriority = priority;
mCbf = cbf;
mUserData = user;
@@ -131,18 +141,22 @@
mIEffectClient = new EffectClient(this);
mClientPid = IPCThreadState::self()->getCallingPid();
+ mClientUid = IPCThreadState::self()->getCallingUid();
iEffect = audioFlinger->createEffect((effect_descriptor_t *)&mDescriptor,
- mIEffectClient, priority, io, mSessionId, mOpPackageName, mClientPid,
- &mStatus, &mId, &enabled);
+ mIEffectClient, priority, io, mSessionId, device, mOpPackageName, mClientPid,
+ probe, &mStatus, &mId, &enabled);
- if (iEffect == 0 || (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS)) {
+ // In probe mode, we stop here and return the status: the IEffect interface to
+ // audio flinger will not be retained. initCheck() will return the creation status
+ // but all other APIs will return invalid operation.
+ if (probe || iEffect == 0 || (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS)) {
char typeBuffer[64], uuidBuffer[64];
guidToString(type, typeBuffer, sizeof(typeBuffer));
guidToString(uuid, uuidBuffer, sizeof(uuidBuffer));
- ALOGE("set(): AudioFlinger could not create effect %s / %s, status: %d",
+ ALOGE_IF(!probe, "set(): AudioFlinger could not create effect %s / %s, status: %d",
typeBuffer, uuidBuffer, mStatus);
- if (iEffect == 0) {
+ if (!probe && iEffect == 0) {
mStatus = NO_INIT;
}
return mStatus;
@@ -159,7 +173,11 @@
mIEffect = iEffect;
mCblkMemory = cblk;
- mCblk = static_cast<effect_param_cblk_t*>(cblk->pointer());
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
+ mCblk = static_cast<effect_param_cblk_t*>(cblk->unsecurePointer());
int bufOffset = ((sizeof(effect_param_cblk_t) - 1) / sizeof(int) + 1) * sizeof(int);
mCblk->buffer = (uint8_t *)mCblk + bufOffset;
@@ -167,8 +185,8 @@
ALOGV("set() %p OK effect: %s id: %d status %d enabled %d pid %d", this, mDescriptor.name, mId,
mStatus, mEnabled, mClientPid);
- if (mSessionId > AUDIO_SESSION_OUTPUT_MIX) {
- AudioSystem::acquireAudioSessionId(mSessionId, mClientPid);
+ if (!audio_is_global_session(mSessionId)) {
+ AudioSystem::acquireAudioSessionId(mSessionId, mClientPid, mClientUid);
}
return mStatus;
@@ -179,8 +197,8 @@
{
ALOGV("Destructor %p", this);
- if (mStatus == NO_ERROR || mStatus == ALREADY_EXISTS) {
- if (mSessionId > AUDIO_SESSION_OUTPUT_MIX) {
+ if (!mProbe && (mStatus == NO_ERROR || mStatus == ALREADY_EXISTS)) {
+ if (!audio_is_global_session(mSessionId)) {
AudioSystem::releaseAudioSessionId(mSessionId, mClientPid);
}
if (mIEffect != NULL) {
@@ -189,9 +207,9 @@
}
mIEffect.clear();
mCblkMemory.clear();
- mIEffectClient.clear();
- IPCThreadState::self()->flushCommands();
}
+ mIEffectClient.clear();
+ IPCThreadState::self()->flushCommands();
}
@@ -214,6 +232,9 @@
status_t AudioEffect::setEnabled(bool enabled)
{
+ if (mProbe) {
+ return INVALID_OPERATION;
+ }
if (mStatus != NO_ERROR) {
return (mStatus == ALREADY_EXISTS) ? (status_t) INVALID_OPERATION : mStatus;
}
@@ -242,6 +263,9 @@
uint32_t *replySize,
void *replyData)
{
+ if (mProbe) {
+ return INVALID_OPERATION;
+ }
if (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS) {
ALOGV("command() bad status %d", mStatus);
return mStatus;
@@ -275,6 +299,9 @@
status_t AudioEffect::setParameter(effect_param_t *param)
{
+ if (mProbe) {
+ return INVALID_OPERATION;
+ }
if (mStatus != NO_ERROR) {
return (mStatus == ALREADY_EXISTS) ? (status_t) INVALID_OPERATION : mStatus;
}
@@ -295,6 +322,9 @@
status_t AudioEffect::setParameterDeferred(effect_param_t *param)
{
+ if (mProbe) {
+ return INVALID_OPERATION;
+ }
if (mStatus != NO_ERROR) {
return (mStatus == ALREADY_EXISTS) ? (status_t) INVALID_OPERATION : mStatus;
}
@@ -321,6 +351,9 @@
status_t AudioEffect::setParameterCommit()
{
+ if (mProbe) {
+ return INVALID_OPERATION;
+ }
if (mStatus != NO_ERROR) {
return (mStatus == ALREADY_EXISTS) ? (status_t) INVALID_OPERATION : mStatus;
}
@@ -335,6 +368,9 @@
status_t AudioEffect::getParameter(effect_param_t *param)
{
+ if (mProbe) {
+ return INVALID_OPERATION;
+ }
if (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS) {
return mStatus;
}
diff --git a/media/libaudioclient/AudioPolicy.cpp b/media/libaudioclient/AudioPolicy.cpp
index 3cdf095..0522099 100644
--- a/media/libaudioclient/AudioPolicy.cpp
+++ b/media/libaudioclient/AudioPolicy.cpp
@@ -22,22 +22,6 @@
namespace android {
//
-// AudioDeviceTypeAddr implementation
-//
-status_t AudioDeviceTypeAddr::readFromParcel(Parcel *parcel) {
- mType = (audio_devices_t) parcel->readInt32();
- mAddress = parcel->readString8();
- return NO_ERROR;
-}
-
-status_t AudioDeviceTypeAddr::writeToParcel(Parcel *parcel) const {
- parcel->writeInt32((int32_t) mType);
- parcel->writeString8(mAddress);
- return NO_ERROR;
-}
-
-
-//
// AudioMixMatchCriterion implementation
//
AudioMixMatchCriterion::AudioMixMatchCriterion(audio_usage_t usage,
@@ -69,6 +53,10 @@
case RULE_EXCLUDE_UID:
mValue.mUid = (uid_t) parcel->readInt32();
break;
+ case RULE_MATCH_USERID:
+ case RULE_EXCLUDE_USERID:
+ mValue.mUserId = (int) parcel->readInt32();
+ break;
default:
ALOGE("Trying to build AudioMixMatchCriterion from unknown rule %d", mRule);
return BAD_VALUE;
@@ -98,6 +86,7 @@
mDeviceAddress = parcel->readString8();
mCbFlags = (uint32_t)parcel->readInt32();
mAllowPrivilegedPlaybackCapture = parcel->readBool();
+ mVoiceCommunicationCaptureAllowed = parcel->readBool();
size_t size = (size_t)parcel->readInt32();
if (size > MAX_CRITERIA_PER_MIX) {
size = MAX_CRITERIA_PER_MIX;
@@ -122,6 +111,7 @@
parcel->writeString8(mDeviceAddress);
parcel->writeInt32(mCbFlags);
parcel->writeBool(mAllowPrivilegedPlaybackCapture);
+ parcel->writeBool(mVoiceCommunicationCaptureAllowed);
size_t size = mCriteria.size();
if (size > MAX_CRITERIA_PER_MIX) {
size = MAX_CRITERIA_PER_MIX;
@@ -179,6 +169,40 @@
return false;
}
+void AudioMix::setExcludeUserId(int userId) const {
+ AudioMixMatchCriterion crit;
+ crit.mRule = RULE_EXCLUDE_USERID;
+ crit.mValue.mUserId = userId;
+ mCriteria.add(crit);
+}
+
+void AudioMix::setMatchUserId(int userId) const {
+ AudioMixMatchCriterion crit;
+ crit.mRule = RULE_MATCH_USERID;
+ crit.mValue.mUserId = userId;
+ mCriteria.add(crit);
+}
+
+bool AudioMix::hasUserIdRule(bool match, int userId) const {
+ const uint32_t rule = match ? RULE_MATCH_USERID : RULE_EXCLUDE_USERID;
+ for (size_t i = 0; i < mCriteria.size(); i++) {
+ if (mCriteria[i].mRule == rule
+ && mCriteria[i].mValue.mUserId == userId) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AudioMix::hasMatchUserIdRule() const {
+ for (size_t i = 0; i < mCriteria.size(); i++) {
+ if (mCriteria[i].mRule == RULE_MATCH_USERID) {
+ return true;
+ }
+ }
+ return false;
+}
+
bool AudioMix::isDeviceAffinityCompatible() const {
return ((mMixType == MIX_TYPE_PLAYERS)
&& (mRouteFlags == MIX_ROUTE_FLAG_RENDER));
diff --git a/media/libaudioclient/AudioProductStrategy.cpp b/media/libaudioclient/AudioProductStrategy.cpp
index 0e1dfac..cff72fd 100644
--- a/media/libaudioclient/AudioProductStrategy.cpp
+++ b/media/libaudioclient/AudioProductStrategy.cpp
@@ -70,6 +70,7 @@
return NO_ERROR;
}
+// Keep in sync with android/media/audiopolicy/AudioProductStrategy#attributeMatches
bool AudioProductStrategy::attributesMatches(const audio_attributes_t refAttributes,
const audio_attributes_t clientAttritubes)
{
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index a1b04ca..f9d1798 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -32,7 +32,7 @@
#include <private/media/AudioTrackShared.h>
#include <processgroup/sched_policy.h>
#include <media/IAudioFlinger.h>
-#include <media/MediaAnalyticsItem.h>
+#include <media/MediaMetricsItem.h>
#include <media/TypeConverter.h>
#define WAIT_PERIOD_MS 10
@@ -79,37 +79,41 @@
#define MM_PREFIX "android.media.audiorecord." // avoid cut-n-paste errors.
// Java API 28 entries, do not change.
- mAnalyticsItem->setCString(MM_PREFIX "encoding", toString(record->mFormat).c_str());
- mAnalyticsItem->setCString(MM_PREFIX "source", toString(record->mAttributes.source).c_str());
- mAnalyticsItem->setInt32(MM_PREFIX "latency", (int32_t)record->mLatency); // bad estimate.
- mAnalyticsItem->setInt32(MM_PREFIX "samplerate", (int32_t)record->mSampleRate);
- mAnalyticsItem->setInt32(MM_PREFIX "channels", (int32_t)record->mChannelCount);
+ mMetricsItem->setCString(MM_PREFIX "encoding", toString(record->mFormat).c_str());
+ mMetricsItem->setCString(MM_PREFIX "source", toString(record->mAttributes.source).c_str());
+ mMetricsItem->setInt32(MM_PREFIX "latency", (int32_t)record->mLatency); // bad estimate.
+ mMetricsItem->setInt32(MM_PREFIX "samplerate", (int32_t)record->mSampleRate);
+ mMetricsItem->setInt32(MM_PREFIX "channels", (int32_t)record->mChannelCount);
// Non-API entries, these can change.
- mAnalyticsItem->setInt32(MM_PREFIX "portId", (int32_t)record->mPortId);
- mAnalyticsItem->setInt32(MM_PREFIX "frameCount", (int32_t)record->mFrameCount);
- mAnalyticsItem->setCString(MM_PREFIX "attributes", toString(record->mAttributes).c_str());
- mAnalyticsItem->setInt64(MM_PREFIX "channelMask", (int64_t)record->mChannelMask);
+ mMetricsItem->setInt32(MM_PREFIX "portId", (int32_t)record->mPortId);
+ mMetricsItem->setInt32(MM_PREFIX "frameCount", (int32_t)record->mFrameCount);
+ mMetricsItem->setCString(MM_PREFIX "attributes", toString(record->mAttributes).c_str());
+ mMetricsItem->setInt64(MM_PREFIX "channelMask", (int64_t)record->mChannelMask);
// log total duration recording, including anything currently running.
int64_t activeNs = 0;
if (mStartedNs != 0) {
activeNs = systemTime() - mStartedNs;
}
- mAnalyticsItem->setDouble(MM_PREFIX "durationMs", (mDurationNs + activeNs) * 1e-6);
- mAnalyticsItem->setInt64(MM_PREFIX "startCount", (int64_t)mCount);
+ mMetricsItem->setDouble(MM_PREFIX "durationMs", (mDurationNs + activeNs) * 1e-6);
+ mMetricsItem->setInt64(MM_PREFIX "startCount", (int64_t)mCount);
if (mLastError != NO_ERROR) {
- mAnalyticsItem->setInt32(MM_PREFIX "lastError.code", (int32_t)mLastError);
- mAnalyticsItem->setCString(MM_PREFIX "lastError.at", mLastErrorFunc.c_str());
+ mMetricsItem->setInt32(MM_PREFIX "lastError.code", (int32_t)mLastError);
+ mMetricsItem->setCString(MM_PREFIX "lastError.at", mLastErrorFunc.c_str());
}
}
+static const char *stateToString(bool active) {
+ return active ? "ACTIVE" : "STOPPED";
+}
+
// hand the user a snapshot of the metrics.
-status_t AudioRecord::getMetrics(MediaAnalyticsItem * &item)
+status_t AudioRecord::getMetrics(mediametrics::Item * &item)
{
mMediaMetrics.gather(this);
- MediaAnalyticsItem *tmp = mMediaMetrics.dup();
+ mediametrics::Item *tmp = mMediaMetrics.dup();
if (tmp == nullptr) {
return BAD_VALUE;
}
@@ -164,6 +168,11 @@
{
mMediaMetrics.gather(this);
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_DTOR)
+ .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)mStatus)
+ .record();
+
if (mStatus == NO_ERROR) {
// Make sure that callback function exits in the case where
// it is looping on buffer empty condition in obtainBuffer().
@@ -186,7 +195,7 @@
IPCThreadState::self()->flushCommands();
ALOGV("%s(%d): releasing session id %d",
__func__, mPortId, mSessionId);
- AudioSystem::releaseAudioSessionId(mSessionId, -1 /*pid*/);
+ AudioSystem::releaseAudioSessionId(mSessionId, mClientPid);
}
}
@@ -262,8 +271,12 @@
}
if (pAttributes == NULL) {
- memset(&mAttributes, 0, sizeof(audio_attributes_t));
+ mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
mAttributes.source = inputSource;
+ if (inputSource == AUDIO_SOURCE_VOICE_COMMUNICATION
+ || inputSource == AUDIO_SOURCE_CAMCORDER) {
+ mAttributes.flags |= AUDIO_FLAG_CAPTURE_PRIVATE;
+ }
} else {
// stream type shouldn't be looked at, this track has audio attributes
memcpy(&mAttributes, pAttributes, sizeof(audio_attributes_t));
@@ -357,7 +370,7 @@
mMarkerReached = false;
mNewPosition = 0;
mUpdatePeriod = 0;
- AudioSystem::acquireAudioSessionId(mSessionId, -1);
+ AudioSystem::acquireAudioSessionId(mSessionId, mClientPid, mClientUid);
mSequence = 1;
mObservedSequence = mSequence;
mInOverrun = false;
@@ -376,11 +389,21 @@
status_t AudioRecord::start(AudioSystem::sync_event_t event, audio_session_t triggerSession)
{
+ const int64_t beginNs = systemTime();
ALOGV("%s(%d): sync event %d trigger session %d", __func__, mPortId, event, triggerSession);
-
AutoMutex lock(mLock);
+
+ status_t status = NO_ERROR;
+ mediametrics::Defer([&] {
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_START)
+ .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
+ .set(AMEDIAMETRICS_PROP_STATE, stateToString(mActive))
+ .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)status)
+ .record(); });
+
if (mActive) {
- return NO_ERROR;
+ return status;
}
// discard data in buffer
@@ -405,7 +428,6 @@
// mActive is checked by restoreRecord_l
mActive = true;
- status_t status = NO_ERROR;
if (!(flags & CBLK_INVALID)) {
status = mAudioRecord->start(event, triggerSession).transactionError();
if (status == DEAD_OBJECT) {
@@ -443,7 +465,15 @@
void AudioRecord::stop()
{
+ const int64_t beginNs = systemTime();
AutoMutex lock(mLock);
+ mediametrics::Defer([&] {
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_STOP)
+ .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
+ .set(AMEDIAMETRICS_PROP_STATE, stateToString(mActive))
+ .record(); });
+
ALOGV("%s(%d): mActive:%d\n", __func__, mPortId, mActive);
if (!mActive) {
return;
@@ -659,6 +689,7 @@
// must be called with mLock held
status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch, const String16& opPackageName)
{
+ const int64_t beginNs = systemTime();
const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
IAudioFlinger::CreateRecordInput input;
IAudioFlinger::CreateRecordOutput output;
@@ -759,7 +790,11 @@
status = NO_INIT;
goto exit;
}
- iMemPointer = output.cblk ->pointer();
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
+ iMemPointer = output.cblk ->unsecurePointer();
if (iMemPointer == NULL) {
ALOGE("%s(%d): Could not get control block pointer", __func__, mPortId);
status = NO_INIT;
@@ -774,7 +809,11 @@
if (output.buffers == 0) {
buffers = cblk + 1;
} else {
- buffers = output.buffers->pointer();
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
+ buffers = output.buffers->unsecurePointer();
if (buffers == NULL) {
ALOGE("%s(%d): Could not get buffer pointer", __func__, mPortId);
status = NO_INIT;
@@ -837,6 +876,29 @@
mDeathNotifier = new DeathNotifier(this);
IInterface::asBinder(mAudioRecord)->linkToDeath(mDeathNotifier, this);
+ mMetricsId = std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD) + std::to_string(mPortId);
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE)
+ .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
+ // the following are immutable (at least until restore)
+ .set(AMEDIAMETRICS_PROP_FLAGS, (int32_t)mFlags)
+ .set(AMEDIAMETRICS_PROP_ORIGINALFLAGS, (int32_t)mOrigFlags)
+ .set(AMEDIAMETRICS_PROP_SESSIONID, (int32_t)mSessionId)
+ .set(AMEDIAMETRICS_PROP_TRACKID, mPortId)
+ .set(AMEDIAMETRICS_PROP_SOURCE, toString(mAttributes.source).c_str())
+ .set(AMEDIAMETRICS_PROP_THREADID, (int32_t)output.inputId)
+ .set(AMEDIAMETRICS_PROP_SELECTEDDEVICEID, (int32_t)mSelectedDeviceId)
+ .set(AMEDIAMETRICS_PROP_ROUTEDDEVICEID, (int32_t)mRoutedDeviceId)
+ .set(AMEDIAMETRICS_PROP_ENCODING, toString(mFormat).c_str())
+ .set(AMEDIAMETRICS_PROP_CHANNELMASK, (int32_t)mChannelMask)
+ .set(AMEDIAMETRICS_PROP_FRAMECOUNT, (int32_t)mFrameCount)
+ .set(AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)mSampleRate)
+ // the following are NOT immutable
+ .set(AMEDIAMETRICS_PROP_STATE, stateToString(mActive))
+ .set(AMEDIAMETRICS_PROP_SELECTEDMICDIRECTION, (int32_t)mSelectedMicDirection)
+ .set(AMEDIAMETRICS_PROP_SELECTEDMICFIELDDIRECTION, (double)mSelectedMicFieldDimension)
+ .record();
+
exit:
mStatus = status;
// sp<IAudioTrack> track destructor will cause releaseOutput() to be called by AudioFlinger
@@ -884,7 +946,6 @@
{
// previous and new IAudioRecord sequence numbers are used to detect track re-creation
uint32_t oldSequence = 0;
- uint32_t newSequence;
Proxy::Buffer buffer;
status_t status = NO_ERROR;
@@ -902,7 +963,7 @@
// start of lock scope
AutoMutex lock(mLock);
- newSequence = mSequence;
+ uint32_t newSequence = mSequence;
// did previous obtainBuffer() fail due to media server death or voluntary invalidation?
if (status == DEAD_OBJECT) {
// re-create track, unless someone else has already done so
@@ -939,6 +1000,7 @@
audioBuffer->frameCount = buffer.mFrameCount;
audioBuffer->size = buffer.mFrameCount * mFrameSize;
audioBuffer->raw = buffer.mRaw;
+ audioBuffer->sequence = oldSequence;
if (nonContig != NULL) {
*nonContig = buffer.mNonContig;
}
@@ -959,6 +1021,12 @@
buffer.mRaw = audioBuffer->raw;
AutoMutex lock(mLock);
+ if (audioBuffer->sequence != mSequence) {
+ // This Buffer came from a different IAudioRecord instance, so ignore the releaseBuffer
+ ALOGD("%s is no-op due to IAudioRecord sequence mismatch %u != %u",
+ __func__, audioBuffer->sequence, mSequence);
+ return;
+ }
mInOverrun = false;
mProxy->releaseBuffer(&buffer);
@@ -1270,6 +1338,17 @@
status_t AudioRecord::restoreRecord_l(const char *from)
{
+ status_t result = NO_ERROR; // logged: make sure to set this before returning.
+ const int64_t beginNs = systemTime();
+ mediametrics::Defer([&] {
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_RESTORE)
+ .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
+ .set(AMEDIAMETRICS_PROP_STATE, stateToString(mActive))
+ .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)result)
+ .set(AMEDIAMETRICS_PROP_WHERE, from)
+ .record(); });
+
ALOGW("%s(%d): dead IAudioRecord, creating a new one from %s()", __func__, mPortId, from);
++mSequence;
@@ -1288,7 +1367,7 @@
// It will also delete the strong references on previous IAudioRecord and IMemory
Modulo<uint32_t> position(mProxy->getPosition());
mNewPosition = position + mUpdatePeriod;
- status_t result = createRecord_l(position, mOpPackageName);
+ result = createRecord_l(position, mOpPackageName);
if (result == NO_ERROR) {
if (mActive) {
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 02dc516..f030ab0 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -36,10 +36,11 @@
// client singleton for AudioFlinger binder interface
Mutex AudioSystem::gLock;
+Mutex AudioSystem::gLockErrorCallbacks;
Mutex AudioSystem::gLockAPS;
sp<IAudioFlinger> AudioSystem::gAudioFlinger;
sp<AudioSystem::AudioFlingerClient> AudioSystem::gAudioFlingerClient;
-audio_error_callback AudioSystem::gAudioErrorCallback = NULL;
+std::set<audio_error_callback> AudioSystem::gAudioErrorCallbacks;
dynamic_policy_callback AudioSystem::gDynPolicyCallback = NULL;
record_config_callback AudioSystem::gRecordConfigCallback = NULL;
@@ -63,9 +64,7 @@
if (gAudioFlingerClient == NULL) {
gAudioFlingerClient = new AudioFlingerClient();
} else {
- if (gAudioErrorCallback) {
- gAudioErrorCallback(NO_ERROR);
- }
+ reportError(NO_ERROR);
}
binder->linkToDeath(gAudioFlingerClient);
gAudioFlinger = interface_cast<IAudioFlinger>(binder);
@@ -434,11 +433,11 @@
return af->newAudioUniqueId(use);
}
-void AudioSystem::acquireAudioSessionId(audio_session_t audioSession, pid_t pid)
+void AudioSystem::acquireAudioSessionId(audio_session_t audioSession, pid_t pid, uid_t uid)
{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af != 0) {
- af->acquireAudioSessionId(audioSession, pid);
+ af->acquireAudioSessionId(audioSession, pid, uid);
}
}
@@ -500,19 +499,16 @@
void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who __unused)
{
- audio_error_callback cb = NULL;
{
Mutex::Autolock _l(AudioSystem::gLock);
AudioSystem::gAudioFlinger.clear();
- cb = gAudioErrorCallback;
}
// clear output handles and stream to output map caches
clearIoCache();
- if (cb) {
- cb(DEAD_OBJECT);
- }
+ reportError(DEAD_OBJECT);
+
ALOGW("AudioFlinger server died!");
}
@@ -717,10 +713,23 @@
return NO_ERROR;
}
-/* static */ void AudioSystem::setErrorCallback(audio_error_callback cb)
+/* static */ uintptr_t AudioSystem::addErrorCallback(audio_error_callback cb)
{
- Mutex::Autolock _l(gLock);
- gAudioErrorCallback = cb;
+ Mutex::Autolock _l(gLockErrorCallbacks);
+ gAudioErrorCallbacks.insert(cb);
+ return reinterpret_cast<uintptr_t>(cb);
+}
+
+/* static */ void AudioSystem::removeErrorCallback(uintptr_t cb) {
+ Mutex::Autolock _l(gLockErrorCallbacks);
+ gAudioErrorCallbacks.erase(reinterpret_cast<audio_error_callback>(cb));
+}
+
+/* static */ void AudioSystem::reportError(status_t err) {
+ Mutex::Autolock _l(gLockErrorCallbacks);
+ for (auto callback : gAudioErrorCallbacks) {
+ callback(err);
+ }
}
/*static*/ void AudioSystem::setDynPolicyCallback(dynamic_policy_callback cb)
@@ -783,6 +792,13 @@
// ---------------------------------------------------------------------------
+void AudioSystem::onNewAudioModulesAvailable()
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return;
+ aps->onNewAudioModulesAvailable();
+}
+
status_t AudioSystem::setDeviceConnectionState(audio_devices_t device,
audio_policy_dev_state_t state,
const char *device_address,
@@ -833,13 +849,13 @@
return aps->handleDeviceConfigChange(device, address, name, encodedFormat);
}
-status_t AudioSystem::setPhoneState(audio_mode_t state)
+status_t AudioSystem::setPhoneState(audio_mode_t state, uid_t uid)
{
if (uint32_t(state) >= AUDIO_MODE_CNT) return BAD_VALUE;
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return PERMISSION_DENIED;
- return aps->setPhoneState(state);
+ return aps->setPhoneState(state, uid);
}
status_t AudioSystem::setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config)
@@ -870,6 +886,7 @@
audio_stream_type_t *stream,
pid_t pid,
uid_t uid,
+ const String16& opPackageName,
const audio_config_t *config,
audio_output_flags_t flags,
audio_port_handle_t *selectedDeviceId,
@@ -879,7 +896,7 @@
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return NO_INIT;
return aps->getOutputForAttr(attr, output, session, stream, pid, uid,
- config,
+ opPackageName, config,
flags, selectedDeviceId, portId, secondaryOutputs);
}
@@ -1017,6 +1034,16 @@
return aps->getDevicesForStream(stream);
}
+status_t AudioSystem::getDevicesForAttributes(const AudioAttributes &aa,
+ AudioDeviceTypeAddrVector *devices) {
+ if (devices == nullptr) {
+ return BAD_VALUE;
+ }
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->getDevicesForAttributes(aa, devices);
+}
+
audio_io_handle_t AudioSystem::getOutputForEffect(const effect_descriptor_t *desc)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
@@ -1123,6 +1150,12 @@
}
}
+status_t AudioSystem::setSupportedSystemUsages(const std::vector<audio_usage_t>& systemUsages) {
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == nullptr) return PERMISSION_DENIED;
+ return aps->setSupportedSystemUsages(systemUsages);
+}
+
status_t AudioSystem::setAllowedCapturePolicy(uid_t uid, audio_flags_mask_t flags) {
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == nullptr) return PERMISSION_DENIED;
@@ -1334,6 +1367,21 @@
return aps->removeUidDeviceAffinities(uid);
}
+status_t AudioSystem::setUserIdDeviceAffinities(int userId,
+ const Vector<AudioDeviceTypeAddr>& devices)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->setUserIdDeviceAffinities(userId, devices);
+}
+
+status_t AudioSystem::removeUserIdDeviceAffinities(int userId)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->removeUserIdDeviceAffinities(userId);
+}
+
status_t AudioSystem::startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
audio_port_handle_t *portId)
@@ -1392,6 +1440,12 @@
return af->getMicrophones(microphones);
}
+status_t AudioSystem::setAudioHalPids(const std::vector<pid_t>& pids) {
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == nullptr) return PERMISSION_DENIED;
+ return af->setAudioHalPids(pids);
+}
+
status_t AudioSystem::getSurroundFormats(unsigned int *numSurroundFormats,
audio_format_t *surroundFormats,
bool *surroundFormatsEnabled,
@@ -1485,7 +1539,14 @@
}
}
}
- ALOGE("invalid attributes %s when converting to stream", toString(attr).c_str());
+ switch (attr.usage) {
+ case AUDIO_USAGE_VIRTUAL_SOURCE:
+ // virtual source is not expected to have an associated product strategy
+ break;
+ default:
+ ALOGE("invalid attributes %s when converting to stream", toString(attr).c_str());
+ break;
+ }
return AUDIO_STREAM_MUSIC;
}
@@ -1519,6 +1580,42 @@
return aps->setRttEnabled(enabled);
}
+bool AudioSystem::isCallScreenModeSupported()
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return false;
+ return aps->isCallScreenModeSupported();
+}
+
+status_t AudioSystem::setPreferredDeviceForStrategy(product_strategy_t strategy,
+ const AudioDeviceTypeAddr &device)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) {
+ return PERMISSION_DENIED;
+ }
+ return aps->setPreferredDeviceForStrategy(strategy, device);
+}
+
+status_t AudioSystem::removePreferredDeviceForStrategy(product_strategy_t strategy)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) {
+ return PERMISSION_DENIED;
+ }
+ return aps->removePreferredDeviceForStrategy(strategy);
+}
+
+status_t AudioSystem::getPreferredDeviceForStrategy(product_strategy_t strategy,
+ AudioDeviceTypeAddr &device)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) {
+ return PERMISSION_DENIED;
+ }
+ return aps->getPreferredDeviceForStrategy(strategy, device);
+}
+
// ---------------------------------------------------------------------------
int AudioSystem::AudioPolicyServiceClient::addAudioPortCallback(
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 4a80cd3..2f95886 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -35,7 +35,7 @@
#include <media/AudioParameter.h>
#include <media/AudioResamplerPublic.h>
#include <media/AudioSystem.h>
-#include <media/MediaAnalyticsItem.h>
+#include <media/MediaMetricsItem.h>
#include <media/TypeConverter.h>
#define WAIT_PERIOD_MS 10
@@ -183,26 +183,26 @@
#define MM_PREFIX "android.media.audiotrack." // avoid cut-n-paste errors.
// Java API 28 entries, do not change.
- mAnalyticsItem->setCString(MM_PREFIX "streamtype", toString(track->streamType()).c_str());
- mAnalyticsItem->setCString(MM_PREFIX "type",
+ mMetricsItem->setCString(MM_PREFIX "streamtype", toString(track->streamType()).c_str());
+ mMetricsItem->setCString(MM_PREFIX "type",
toString(track->mAttributes.content_type).c_str());
- mAnalyticsItem->setCString(MM_PREFIX "usage", toString(track->mAttributes.usage).c_str());
+ mMetricsItem->setCString(MM_PREFIX "usage", toString(track->mAttributes.usage).c_str());
// Non-API entries, these can change due to a Java string mistake.
- mAnalyticsItem->setInt32(MM_PREFIX "sampleRate", (int32_t)track->mSampleRate);
- mAnalyticsItem->setInt64(MM_PREFIX "channelMask", (int64_t)track->mChannelMask);
+ mMetricsItem->setInt32(MM_PREFIX "sampleRate", (int32_t)track->mSampleRate);
+ mMetricsItem->setInt64(MM_PREFIX "channelMask", (int64_t)track->mChannelMask);
// Non-API entries, these can change.
- mAnalyticsItem->setInt32(MM_PREFIX "portId", (int32_t)track->mPortId);
- mAnalyticsItem->setCString(MM_PREFIX "encoding", toString(track->mFormat).c_str());
- mAnalyticsItem->setInt32(MM_PREFIX "frameCount", (int32_t)track->mFrameCount);
- mAnalyticsItem->setCString(MM_PREFIX "attributes", toString(track->mAttributes).c_str());
+ mMetricsItem->setInt32(MM_PREFIX "portId", (int32_t)track->mPortId);
+ mMetricsItem->setCString(MM_PREFIX "encoding", toString(track->mFormat).c_str());
+ mMetricsItem->setInt32(MM_PREFIX "frameCount", (int32_t)track->mFrameCount);
+ mMetricsItem->setCString(MM_PREFIX "attributes", toString(track->mAttributes).c_str());
}
// hand the user a snapshot of the metrics.
-status_t AudioTrack::getMetrics(MediaAnalyticsItem * &item)
+status_t AudioTrack::getMetrics(mediametrics::Item * &item)
{
mMediaMetrics.gather(this);
- MediaAnalyticsItem *tmp = mMediaMetrics.dup();
+ mediametrics::Item *tmp = mMediaMetrics.dup();
if (tmp == nullptr) {
return BAD_VALUE;
}
@@ -217,7 +217,8 @@
mPreviousSchedulingGroup(SP_DEFAULT),
mPausedPosition(0),
mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
- mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE)
+ mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE),
+ mAudioTrackCallback(new AudioTrackCallback())
{
mAttributes.content_type = AUDIO_CONTENT_TYPE_UNKNOWN;
mAttributes.usage = AUDIO_USAGE_UNKNOWN;
@@ -248,7 +249,8 @@
mState(STATE_STOPPED),
mPreviousPriority(ANDROID_PRIORITY_NORMAL),
mPreviousSchedulingGroup(SP_DEFAULT),
- mPausedPosition(0)
+ mPausedPosition(0),
+ mAudioTrackCallback(new AudioTrackCallback())
{
mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
@@ -281,7 +283,8 @@
mPreviousPriority(ANDROID_PRIORITY_NORMAL),
mPreviousSchedulingGroup(SP_DEFAULT),
mPausedPosition(0),
- mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE)
+ mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
+ mAudioTrackCallback(new AudioTrackCallback())
{
mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
@@ -296,6 +299,12 @@
// pull together the numbers, before we clean up our structures
mMediaMetrics.gather(this);
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_DTOR)
+ .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
+ .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)mStatus)
+ .record();
+
if (mStatus == NO_ERROR) {
// Make sure that callback function exits in the case where
// it is looping on buffer full condition in obtainBuffer().
@@ -406,7 +415,7 @@
mDoNotReconnect = doNotReconnect;
ALOGV_IF(sharedBuffer != 0, "%s(): sharedBuffer: %p, size: %zu",
- __func__, sharedBuffer->pointer(), sharedBuffer->size());
+ __func__, sharedBuffer->unsecurePointer(), sharedBuffer->size());
ALOGV("%s(): streamType %d frameCount %zu flags %04x",
__func__, streamType, frameCount, flags);
@@ -599,7 +608,7 @@
mReleased = 0;
mStartNs = 0;
mStartFromZeroUs = 0;
- AudioSystem::acquireAudioSessionId(mSessionId, mClientPid);
+ AudioSystem::acquireAudioSessionId(mSessionId, mClientPid, mClientUid);
mSequence = 1;
mObservedSequence = mSequence;
mInUnderrun = false;
@@ -626,11 +635,23 @@
status_t AudioTrack::start()
{
+ const int64_t beginNs = systemTime();
AutoMutex lock(mLock);
+
+ status_t status = NO_ERROR; // logged: make sure to set this before returning.
+ mediametrics::Defer([&] {
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_START)
+ .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
+ .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
+ .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)status)
+ .record(); });
+
ALOGV("%s(%d): prior state:%s", __func__, mPortId, stateToString(mState));
if (mState == STATE_ACTIVE) {
- return INVALID_OPERATION;
+ status = INVALID_OPERATION;
+ return status;
}
mInUnderrun = true;
@@ -703,7 +724,6 @@
mNewPosition = mPosition + mUpdatePeriod;
int32_t flags = android_atomic_and(~(CBLK_STREAM_END_DONE | CBLK_DISABLED), &mCblk->mFlags);
- status_t status = NO_ERROR;
if (!(flags & CBLK_INVALID)) {
status = mAudioTrack->start();
if (status == DEAD_OBJECT) {
@@ -749,7 +769,16 @@
void AudioTrack::stop()
{
+ const int64_t beginNs = systemTime();
+
AutoMutex lock(mLock);
+ mediametrics::Defer([&]() {
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_STOP)
+ .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
+ .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
+ .record(); });
+
ALOGV("%s(%d): prior state:%s", __func__, mPortId, stateToString(mState));
if (mState != STATE_ACTIVE && mState != STATE_PAUSED) {
@@ -801,7 +830,15 @@
void AudioTrack::flush()
{
+ const int64_t beginNs = systemTime();
AutoMutex lock(mLock);
+ mediametrics::Defer([&]() {
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_FLUSH)
+ .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
+ .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
+ .record(); });
+
ALOGV("%s(%d): prior state:%s", __func__, mPortId, stateToString(mState));
if (mSharedBuffer != 0) {
@@ -834,7 +871,15 @@
void AudioTrack::pause()
{
+ const int64_t beginNs = systemTime();
AutoMutex lock(mLock);
+ mediametrics::Defer([&]() {
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_PAUSE)
+ .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
+ .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
+ .record(); });
+
ALOGV("%s(%d): prior state:%s", __func__, mPortId, stateToString(mState));
if (mState == STATE_ACTIVE) {
@@ -876,6 +921,12 @@
return BAD_VALUE;
}
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOLUME)
+ .set(AMEDIAMETRICS_PROP_VOLUME_LEFT, (double)left)
+ .set(AMEDIAMETRICS_PROP_VOLUME_RIGHT, (double)right)
+ .record();
+
AutoMutex lock(mLock);
mVolume[AUDIO_INTERLEAVE_LEFT] = left;
mVolume[AUDIO_INTERLEAVE_RIGHT] = right;
@@ -1027,6 +1078,20 @@
//set effective rates
mProxy->setPlaybackRate(playbackRateTemp);
mProxy->setSampleRate(effectiveRate); // FIXME: not quite "atomic" with setPlaybackRate
+
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_SETPLAYBACKPARAM)
+ .set(AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)mSampleRate)
+ .set(AMEDIAMETRICS_PROP_PLAYBACK_SPEED, (double)mPlaybackRate.mSpeed)
+ .set(AMEDIAMETRICS_PROP_PLAYBACK_PITCH, (double)mPlaybackRate.mPitch)
+ .set(AMEDIAMETRICS_PROP_PREFIX_EFFECTIVE
+ AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)effectiveRate)
+ .set(AMEDIAMETRICS_PROP_PREFIX_EFFECTIVE
+ AMEDIAMETRICS_PROP_PLAYBACK_SPEED, (double)playbackRateTemp.mSpeed)
+ .set(AMEDIAMETRICS_PROP_PREFIX_EFFECTIVE
+ AMEDIAMETRICS_PROP_PLAYBACK_PITCH, (double)playbackRateTemp.mPitch)
+ .record();
+
return NO_ERROR;
}
@@ -1465,6 +1530,7 @@
input.notificationFrameCount = mNotificationFramesReq;
input.selectedDeviceId = mSelectedDeviceId;
input.sessionId = mSessionId;
+ input.audioTrackCallback = mAudioTrackCallback;
IAudioFlinger::CreateTrackOutput output;
@@ -1508,7 +1574,11 @@
status = NO_INIT;
goto exit;
}
- void *iMemPointer = iMem->pointer();
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
+ void *iMemPointer = iMem->unsecurePointer();
if (iMemPointer == NULL) {
ALOGE("%s(%d): Could not get control block pointer", __func__, mPortId);
status = NO_INIT;
@@ -1563,7 +1633,11 @@
if (mSharedBuffer == 0) {
buffers = cblk + 1;
} else {
- buffers = mSharedBuffer->pointer();
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
+ buffers = mSharedBuffer->unsecurePointer();
if (buffers == NULL) {
ALOGE("%s(%d): Could not get buffer pointer", __func__, mPortId);
status = NO_INIT;
@@ -1610,6 +1684,48 @@
mDeathNotifier = new DeathNotifier(this);
IInterface::asBinder(mAudioTrack)->linkToDeath(mDeathNotifier, this);
+ // This is the first log sent from the AudioTrack client.
+ // The creation of the audio track by AudioFlinger (in the code above)
+ // is the first log of the AudioTrack and must be present before
+ // any AudioTrack client logs will be accepted.
+ mMetricsId = std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK) + std::to_string(mPortId);
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE)
+ // the following are immutable
+ .set(AMEDIAMETRICS_PROP_FLAGS, (int32_t)mFlags)
+ .set(AMEDIAMETRICS_PROP_ORIGINALFLAGS, (int32_t)mOrigFlags)
+ .set(AMEDIAMETRICS_PROP_SESSIONID, (int32_t)mSessionId)
+ .set(AMEDIAMETRICS_PROP_TRACKID, mPortId) // dup from key
+ .set(AMEDIAMETRICS_PROP_STREAMTYPE, toString(mStreamType).c_str())
+ .set(AMEDIAMETRICS_PROP_CONTENTTYPE, toString(mAttributes.content_type).c_str())
+ .set(AMEDIAMETRICS_PROP_USAGE, toString(mAttributes.usage).c_str())
+ .set(AMEDIAMETRICS_PROP_THREADID, (int32_t)output.outputId)
+ .set(AMEDIAMETRICS_PROP_SELECTEDDEVICEID, (int32_t)mSelectedDeviceId)
+ .set(AMEDIAMETRICS_PROP_ROUTEDDEVICEID, (int32_t)mRoutedDeviceId)
+ .set(AMEDIAMETRICS_PROP_ENCODING, toString(mFormat).c_str())
+ .set(AMEDIAMETRICS_PROP_CHANNELMASK, (int32_t)mChannelMask)
+ .set(AMEDIAMETRICS_PROP_FRAMECOUNT, (int32_t)mFrameCount)
+ // the following are NOT immutable
+ .set(AMEDIAMETRICS_PROP_VOLUME_LEFT, (double)mVolume[AUDIO_INTERLEAVE_LEFT])
+ .set(AMEDIAMETRICS_PROP_VOLUME_RIGHT, (double)mVolume[AUDIO_INTERLEAVE_RIGHT])
+ .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
+ .set(AMEDIAMETRICS_PROP_AUXEFFECTID, (int32_t)mAuxEffectId)
+ .set(AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)mSampleRate)
+ .set(AMEDIAMETRICS_PROP_PLAYBACK_SPEED, (double)mPlaybackRate.mSpeed)
+ .set(AMEDIAMETRICS_PROP_PLAYBACK_PITCH, (double)mPlaybackRate.mPitch)
+ .set(AMEDIAMETRICS_PROP_PREFIX_EFFECTIVE
+ AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)effectiveSampleRate)
+ .set(AMEDIAMETRICS_PROP_PREFIX_EFFECTIVE
+ AMEDIAMETRICS_PROP_PLAYBACK_SPEED, (double)effectiveSpeed)
+ .set(AMEDIAMETRICS_PROP_PREFIX_EFFECTIVE
+ AMEDIAMETRICS_PROP_PLAYBACK_PITCH, (double)effectivePitch)
+ .record();
+
+ // mSendLevel
+ // mReqFrameCount?
+ // mNotificationFramesAct, mNotificationFramesReq, mNotificationsPerBufferReq
+ // mLatency, mAfLatency, mAfFrameCount, mAfSampleRate
+
}
exit:
@@ -1665,7 +1781,6 @@
{
// previous and new IAudioTrack sequence numbers are used to detect track re-creation
uint32_t oldSequence = 0;
- uint32_t newSequence;
Proxy::Buffer buffer;
status_t status = NO_ERROR;
@@ -1682,7 +1797,7 @@
{ // start of lock scope
AutoMutex lock(mLock);
- newSequence = mSequence;
+ uint32_t newSequence = mSequence;
// did previous obtainBuffer() fail due to media server death or voluntary invalidation?
if (status == DEAD_OBJECT) {
// re-create track, unless someone else has already done so
@@ -1729,6 +1844,7 @@
audioBuffer->frameCount = buffer.mFrameCount;
audioBuffer->size = buffer.mFrameCount * mFrameSize;
audioBuffer->raw = buffer.mRaw;
+ audioBuffer->sequence = oldSequence;
if (nonContig != NULL) {
*nonContig = buffer.mNonContig;
}
@@ -1752,6 +1868,12 @@
buffer.mRaw = audioBuffer->raw;
AutoMutex lock(mLock);
+ if (audioBuffer->sequence != mSequence) {
+ // This Buffer came from a different IAudioTrack instance, so ignore the releaseBuffer
+ ALOGD("%s is no-op due to IAudioTrack sequence mismatch %u != %u",
+ __func__, audioBuffer->sequence, mSequence);
+ return;
+ }
mReleased += stepCount;
mInUnderrun = false;
mProxy->releaseBuffer(&buffer);
@@ -2286,6 +2408,17 @@
status_t AudioTrack::restoreTrack_l(const char *from)
{
+ status_t result = NO_ERROR; // logged: make sure to set this before returning.
+ const int64_t beginNs = systemTime();
+ mediametrics::Defer([&] {
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_RESTORE)
+ .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
+ .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
+ .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)result)
+ .set(AMEDIAMETRICS_PROP_WHERE, from)
+ .record(); });
+
ALOGW("%s(%d): dead IAudioTrack, %s, creating a new one from %s()",
__func__, mPortId, isOffloadedOrDirect_l() ? "Offloaded or Direct" : "PCM", from);
++mSequence;
@@ -2297,7 +2430,8 @@
if (isOffloadedOrDirect_l() || mDoNotReconnect) {
// FIXME re-creation of offloaded and direct tracks is not yet implemented;
// reconsider enabling for linear PCM encodings when position can be preserved.
- return DEAD_OBJECT;
+ result = DEAD_OBJECT;
+ return result;
}
// Save so we can return count since creation.
@@ -2328,7 +2462,7 @@
// following member variables: mAudioTrack, mCblkMemory and mCblk.
// It will also delete the strong references on previous IAudioTrack and IMemory.
// If a new IAudioTrack cannot be created, the previous (dead) instance will be left intact.
- status_t result = createTrack_l();
+ result = createTrack_l();
if (result == NO_ERROR) {
// take the frames that will be lost by track recreation into account in saved position
@@ -3246,4 +3380,23 @@
mPausedNs = ns;
}
+binder::Status AudioTrack::AudioTrackCallback::onCodecFormatChanged(
+ const std::vector<uint8_t>& audioMetadata)
+{
+ AutoMutex _l(mAudioTrackCbLock);
+ sp<media::IAudioTrackCallback> callback = mCallback.promote();
+ if (callback.get() != nullptr) {
+ callback->onCodecFormatChanged(audioMetadata);
+ } else {
+ mCallback.clear();
+ }
+ return binder::Status::ok();
+}
+
+void AudioTrack::AudioTrackCallback::setAudioTrackCallback(
+ const sp<media::IAudioTrackCallback> &callback) {
+ AutoMutex lock(mAudioTrackCbLock);
+ mCallback = callback;
+}
+
} // namespace android
diff --git a/media/libaudioclient/AudioTrackShared.cpp b/media/libaudioclient/AudioTrackShared.cpp
index ee6c335..f1f8f9c 100644
--- a/media/libaudioclient/AudioTrackShared.cpp
+++ b/media/libaudioclient/AudioTrackShared.cpp
@@ -984,8 +984,9 @@
// ---------------------------------------------------------------------------
StaticAudioTrackServerProxy::StaticAudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers,
- size_t frameCount, size_t frameSize)
- : AudioTrackServerProxy(cblk, buffers, frameCount, frameSize),
+ size_t frameCount, size_t frameSize, uint32_t sampleRate)
+ : AudioTrackServerProxy(cblk, buffers, frameCount, frameSize, false /*clientInServer*/,
+ sampleRate),
mObserver(&cblk->u.mStatic.mSingleStateQueue),
mPosLoopMutator(&cblk->u.mStatic.mPosLoopQueue),
mFramesReadySafe(frameCount), mFramesReady(frameCount),
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index efa0512..16d2232 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -24,8 +24,8 @@
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
-#include <media/TimeCheck.h>
#include <mediautils/ServiceUtilities.h>
+#include <mediautils/TimeCheck.h>
#include "IAudioFlinger.h"
namespace android {
@@ -90,10 +90,12 @@
SET_MASTER_BALANCE,
GET_MASTER_BALANCE,
SET_EFFECT_SUSPENDED,
+ SET_AUDIO_HAL_PIDS
};
#define MAX_ITEMS_PER_LIST 1024
+
class BpAudioFlinger : public BpInterface<IAudioFlinger>
{
public:
@@ -340,11 +342,11 @@
return reply.readInt32();
}
- virtual void setRecordSilenced(uid_t uid, bool silenced)
+ virtual void setRecordSilenced(audio_port_handle_t portId, bool silenced)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- data.writeInt32(uid);
+ data.writeInt32(portId);
data.writeInt32(silenced ? 1 : 0);
remote()->transact(SET_RECORD_SILENCED, data, &reply);
}
@@ -392,20 +394,18 @@
virtual status_t openOutput(audio_module_handle_t module,
audio_io_handle_t *output,
audio_config_t *config,
- audio_devices_t *devices,
- const String8& address,
+ const sp<DeviceDescriptorBase>& device,
uint32_t *latencyMs,
audio_output_flags_t flags)
{
- if (output == NULL || config == NULL || devices == NULL || latencyMs == NULL) {
+ if (output == nullptr || config == nullptr || device == nullptr || latencyMs == nullptr) {
return BAD_VALUE;
}
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.writeInt32(module);
data.write(config, sizeof(audio_config_t));
- data.writeInt32(*devices);
- data.writeString8(address);
+ data.writeParcelable(*device);
data.writeInt32((int32_t) flags);
status_t status = remote()->transact(OPEN_OUTPUT, data, &reply);
if (status != NO_ERROR) {
@@ -420,7 +420,6 @@
*output = (audio_io_handle_t)reply.readInt32();
ALOGV("openOutput() returned output, %d", *output);
reply.read(config, sizeof(audio_config_t));
- *devices = (audio_devices_t)reply.readInt32();
*latencyMs = reply.readInt32();
return NO_ERROR;
}
@@ -572,12 +571,13 @@
return id;
}
- virtual void acquireAudioSessionId(audio_session_t audioSession, int pid)
+ void acquireAudioSessionId(audio_session_t audioSession, pid_t pid, uid_t uid) override
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.writeInt32(audioSession);
- data.writeInt32(pid);
+ data.writeInt32((int32_t)pid);
+ data.writeInt32((int32_t)uid);
remote()->transact(ACQUIRE_AUDIO_SESSION_ID, data, &reply);
}
@@ -659,20 +659,21 @@
int32_t priority,
audio_io_handle_t output,
audio_session_t sessionId,
+ const AudioDeviceTypeAddr& device,
const String16& opPackageName,
pid_t pid,
+ bool probe,
status_t *status,
int *id,
int *enabled)
{
Parcel data, reply;
sp<IEffect> effect;
-
if (pDesc == NULL) {
if (status != NULL) {
*status = BAD_VALUE;
}
- return effect;
+ return nullptr;
}
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
@@ -681,8 +682,15 @@
data.writeInt32(priority);
data.writeInt32((int32_t) output);
data.writeInt32(sessionId);
+ if (data.writeParcelable(device) != NO_ERROR) {
+ if (status != NULL) {
+ *status = NO_INIT;
+ }
+ return nullptr;
+ }
data.writeString16(opPackageName);
data.writeInt32((int32_t) pid);
+ data.writeInt32(probe ? 1 : 0);
status_t lStatus = remote()->transact(CREATE_EFFECT, data, &reply);
if (lStatus != NO_ERROR) {
@@ -903,6 +911,20 @@
status = reply.readParcelableVector(microphones);
return status;
}
+ virtual status_t setAudioHalPids(const std::vector<pid_t>& pids)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(pids.size());
+ for (auto pid : pids) {
+ data.writeInt32(pid);
+ }
+ status_t status = remote()->transact(SET_AUDIO_HAL_PIDS, data, &reply);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ return static_cast <status_t> (reply.readInt32());
+ }
};
IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger");
@@ -958,7 +980,8 @@
case SET_MODE:
case SET_MIC_MUTE:
case SET_LOW_RAM_DEVICE:
- case SYSTEM_READY: {
+ case SYSTEM_READY:
+ case SET_AUDIO_HAL_PIDS: {
if (!isServiceUid(IPCThreadState::self()->getCallingUid())) {
ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
__func__, code, IPCThreadState::self()->getCallingPid(),
@@ -1156,11 +1179,9 @@
} break;
case SET_RECORD_SILENCED: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- uid_t uid = data.readInt32();
- audio_source_t source;
- data.read(&source, sizeof(audio_source_t));
+ audio_port_handle_t portId = data.readInt32();
bool silenced = data.readInt32() == 1;
- setRecordSilenced(uid, silenced);
+ setRecordSilenced(portId, silenced);
return NO_ERROR;
} break;
case SET_PARAMETERS: {
@@ -1200,19 +1221,21 @@
if (data.read(&config, sizeof(audio_config_t)) != NO_ERROR) {
ALOGE("b/23905951");
}
- audio_devices_t devices = (audio_devices_t)data.readInt32();
- String8 address(data.readString8());
+ sp<DeviceDescriptorBase> device = new DeviceDescriptorBase(AUDIO_DEVICE_NONE);
+ status_t status = NO_ERROR;
+ if ((status = data.readParcelable(device.get())) != NO_ERROR) {
+ reply->writeInt32((int32_t)status);
+ return NO_ERROR;
+ }
audio_output_flags_t flags = (audio_output_flags_t) data.readInt32();
uint32_t latencyMs = 0;
audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
- status_t status = openOutput(module, &output, &config,
- &devices, address, &latencyMs, flags);
+ status = openOutput(module, &output, &config, device, &latencyMs, flags);
ALOGV("OPEN_OUTPUT output, %d", output);
reply->writeInt32((int32_t)status);
if (status == NO_ERROR) {
reply->writeInt32((int32_t)output);
reply->write(&config, sizeof(audio_config_t));
- reply->writeInt32(devices);
reply->writeInt32(latencyMs);
}
return NO_ERROR;
@@ -1306,8 +1329,9 @@
case ACQUIRE_AUDIO_SESSION_ID: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
audio_session_t audioSession = (audio_session_t) data.readInt32();
- int pid = data.readInt32();
- acquireAudioSessionId(audioSession, pid);
+ const pid_t pid = (pid_t)data.readInt32();
+ const uid_t uid = (uid_t)data.readInt32();
+ acquireAudioSessionId(audioSession, pid, uid);
return NO_ERROR;
} break;
case RELEASE_AUDIO_SESSION_ID: {
@@ -1366,15 +1390,20 @@
int32_t priority = data.readInt32();
audio_io_handle_t output = (audio_io_handle_t) data.readInt32();
audio_session_t sessionId = (audio_session_t) data.readInt32();
+ AudioDeviceTypeAddr device;
+ status_t status = NO_ERROR;
+ if ((status = data.readParcelable(&device)) != NO_ERROR) {
+ return status;
+ }
const String16 opPackageName = data.readString16();
pid_t pid = (pid_t)data.readInt32();
+ bool probe = data.readInt32() == 1;
- status_t status = NO_ERROR;
int id = 0;
int enabled = 0;
- sp<IEffect> effect = createEffect(&desc, client, priority, output, sessionId,
- opPackageName, pid, &status, &id, &enabled);
+ sp<IEffect> effect = createEffect(&desc, client, priority, output, sessionId, device,
+ opPackageName, pid, probe, &status, &id, &enabled);
reply->writeInt32(status);
reply->writeInt32(id);
reply->writeInt32(enabled);
@@ -1547,6 +1576,31 @@
}
return NO_ERROR;
}
+ case SET_AUDIO_HAL_PIDS: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ std::vector<pid_t> pids;
+ int32_t size;
+ status_t status = data.readInt32(&size);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ if (size < 0) {
+ return BAD_VALUE;
+ }
+ if (size > MAX_ITEMS_PER_LIST) {
+ size = MAX_ITEMS_PER_LIST;
+ }
+ for (int32_t i = 0; i < size; i++) {
+ int32_t pid;
+ status = data.readInt32(&pid);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ pids.push_back(pid);
+ }
+ reply->writeInt32(setAudioHalPids(pids));
+ return NO_ERROR;
+ }
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index 2fb9491..f1213a3 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -26,8 +26,8 @@
#include <binder/Parcel.h>
#include <media/AudioEffect.h>
#include <media/IAudioPolicyService.h>
-#include <media/TimeCheck.h>
#include <mediautils/ServiceUtilities.h>
+#include <mediautils/TimeCheck.h>
#include <system/audio.h>
namespace android {
@@ -97,14 +97,23 @@
IS_HAPTIC_PLAYBACK_SUPPORTED,
SET_UID_DEVICE_AFFINITY,
REMOVE_UID_DEVICE_AFFINITY,
+ SET_USERID_DEVICE_AFFINITY,
+ REMOVE_USERID_DEVICE_AFFINITY,
GET_OFFLOAD_FORMATS_A2DP,
LIST_AUDIO_PRODUCT_STRATEGIES,
GET_STRATEGY_FOR_ATTRIBUTES,
LIST_AUDIO_VOLUME_GROUPS,
GET_VOLUME_GROUP_FOR_ATTRIBUTES,
+ SET_SUPPORTED_SYSTEM_USAGES,
SET_ALLOWED_CAPTURE_POLICY,
MOVE_EFFECTS_TO_IO,
- SET_RTT_ENABLED
+ SET_RTT_ENABLED,
+ IS_CALL_SCREEN_MODE_SUPPORTED,
+ SET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY,
+ REMOVE_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY,
+ GET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY,
+ GET_DEVICES_FOR_ATTRIBUTES,
+ AUDIO_MODULES_UPDATED, // oneway
};
#define MAX_ITEMS_PER_LIST 1024
@@ -162,11 +171,12 @@
return static_cast <status_t> (reply.readInt32());
}
- virtual status_t setPhoneState(audio_mode_t state)
+ virtual status_t setPhoneState(audio_mode_t state, uid_t uid)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
data.writeInt32(state);
+ data.writeInt32(uid);
remote()->transact(SET_PHONE_STATE, data, &reply);
return static_cast <status_t> (reply.readInt32());
}
@@ -205,6 +215,7 @@
audio_stream_type_t *stream,
pid_t pid,
uid_t uid,
+ const String16& opPackageName,
const audio_config_t *config,
audio_output_flags_t flags,
audio_port_handle_t *selectedDeviceId,
@@ -243,6 +254,7 @@
}
data.writeInt32(pid);
data.writeInt32(uid);
+ data.writeString16(opPackageName);
data.write(config, sizeof(audio_config_t));
data.writeInt32(static_cast <uint32_t>(flags));
data.writeInt32(*selectedDeviceId);
@@ -327,6 +339,7 @@
ALOGE("getInputForAttr NULL portId - shouldn't happen");
return BAD_VALUE;
}
+
data.write(attr, sizeof(audio_attributes_t));
data.writeInt32(*input);
data.writeInt32(riid);
@@ -617,6 +630,20 @@
return status;
}
+ status_t setSupportedSystemUsages(const std::vector<audio_usage_t>& systemUsages) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(systemUsages.size());
+ for (auto systemUsage : systemUsages) {
+ data.writeInt32(systemUsage);
+ }
+ status_t status = remote()->transact(SET_SUPPORTED_SYSTEM_USAGES, data, &reply);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ return static_cast <status_t> (reply.readInt32());
+ }
+
status_t setAllowedCapturePolicy(uid_t uid, audio_flags_mask_t flags) override {
Parcel data, reply;
data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
@@ -1176,6 +1203,52 @@
return status;
}
+ virtual status_t setUserIdDeviceAffinities(int userId,
+ const Vector<AudioDeviceTypeAddr>& devices)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+
+ data.writeInt32((int32_t) userId);
+ size_t size = devices.size();
+ size_t sizePosition = data.dataPosition();
+ data.writeInt32((int32_t) size);
+ size_t finalSize = size;
+ for (size_t i = 0; i < size; i++) {
+ size_t position = data.dataPosition();
+ if (devices[i].writeToParcel(&data) != NO_ERROR) {
+ data.setDataPosition(position);
+ finalSize--;
+ }
+ }
+ if (size != finalSize) {
+ size_t position = data.dataPosition();
+ data.setDataPosition(sizePosition);
+ data.writeInt32(finalSize);
+ data.setDataPosition(position);
+ }
+
+ status_t status = remote()->transact(SET_USERID_DEVICE_AFFINITY, data, &reply);
+ if (status == NO_ERROR) {
+ status = (status_t)reply.readInt32();
+ }
+ return status;
+ }
+
+ virtual status_t removeUserIdDeviceAffinities(int userId) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+
+ data.writeInt32((int32_t) userId);
+
+ status_t status =
+ remote()->transact(REMOVE_USERID_DEVICE_AFFINITY, data, &reply);
+ if (status == NO_ERROR) {
+ status = (status_t) reply.readInt32();
+ }
+ return status;
+ }
+
virtual status_t listAudioProductStrategies(AudioProductStrategyVector &strategies)
{
Parcel data, reply;
@@ -1284,6 +1357,108 @@
}
return static_cast<status_t>(reply.readInt32());
}
+
+ virtual bool isCallScreenModeSupported()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ status_t status = remote()->transact(IS_CALL_SCREEN_MODE_SUPPORTED, data, &reply);
+ if (status != NO_ERROR) {
+ return false;
+ }
+ return reply.readBool();
+ }
+
+ virtual status_t setPreferredDeviceForStrategy(product_strategy_t strategy,
+ const AudioDeviceTypeAddr &device)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeUint32(static_cast<uint32_t>(strategy));
+ status_t status = device.writeToParcel(&data);
+ if (status != NO_ERROR) {
+ return BAD_VALUE;
+ }
+ status = remote()->transact(SET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY,
+ data, &reply);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ return static_cast<status_t>(reply.readInt32());
+ }
+
+ virtual status_t removePreferredDeviceForStrategy(product_strategy_t strategy)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeUint32(static_cast<uint32_t>(strategy));
+ status_t status = remote()->transact(REMOVE_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY,
+ data, &reply);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ return static_cast<status_t>(reply.readInt32());
+ }
+
+ virtual status_t getPreferredDeviceForStrategy(product_strategy_t strategy,
+ AudioDeviceTypeAddr &device)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeUint32(static_cast<uint32_t>(strategy));
+ status_t status = remote()->transact(GET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY,
+ data, &reply);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ status = device.readFromParcel(&reply);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ return static_cast<status_t>(reply.readInt32());
+ }
+
+ virtual status_t getDevicesForAttributes(const AudioAttributes &aa,
+ AudioDeviceTypeAddrVector *devices) const
+ {
+ if (devices == nullptr) {
+ return BAD_VALUE;
+ }
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ status_t status = aa.writeToParcel(&data);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ status = remote()->transact(GET_DEVICES_FOR_ATTRIBUTES, data, &reply);
+ if (status != NO_ERROR) {
+ // transaction failed, return error
+ return status;
+ }
+ status = static_cast<status_t>(reply.readInt32());
+ if (status != NO_ERROR) {
+ // APM method call failed, return error
+ return status;
+ }
+
+ const size_t numberOfDevices = (size_t)reply.readInt32();
+ for (size_t i = 0; i < numberOfDevices; i++) {
+ AudioDeviceTypeAddr device;
+ if (device.readFromParcel((Parcel*)&reply) == NO_ERROR) {
+ devices->push_back(device);
+ } else {
+ return FAILED_TRANSACTION;
+ }
+ }
+ return NO_ERROR;
+ }
+
+ virtual void onNewAudioModulesAvailable()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ remote()->transact(AUDIO_MODULES_UPDATED, data, &reply, IBinder::FLAG_ONEWAY);
+ }
};
IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService");
@@ -1307,8 +1482,6 @@
case UNREGISTER_EFFECT:
case SET_EFFECT_ENABLED:
case GET_OUTPUT_FOR_ATTR:
- case ACQUIRE_SOUNDTRIGGER_SESSION:
- case RELEASE_SOUNDTRIGGER_SESSION:
case MOVE_EFFECTS_TO_IO:
ALOGW("%s: transaction %d received from PID %d",
__func__, code, IPCThreadState::self()->getCallingPid());
@@ -1343,11 +1516,22 @@
case SET_A11Y_SERVICES_UIDS:
case SET_UID_DEVICE_AFFINITY:
case REMOVE_UID_DEVICE_AFFINITY:
+ case SET_USERID_DEVICE_AFFINITY:
+ case REMOVE_USERID_DEVICE_AFFINITY:
case GET_OFFLOAD_FORMATS_A2DP:
case LIST_AUDIO_VOLUME_GROUPS:
case GET_VOLUME_GROUP_FOR_ATTRIBUTES:
+ case ACQUIRE_SOUNDTRIGGER_SESSION:
+ case RELEASE_SOUNDTRIGGER_SESSION:
case SET_RTT_ENABLED:
- case SET_ALLOWED_CAPTURE_POLICY: {
+ case IS_CALL_SCREEN_MODE_SUPPORTED:
+ case SET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY:
+ case SET_SUPPORTED_SYSTEM_USAGES:
+ case REMOVE_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY:
+ case GET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY:
+ case GET_DEVICES_FOR_ATTRIBUTES:
+ case SET_ALLOWED_CAPTURE_POLICY:
+ case AUDIO_MODULES_UPDATED: {
if (!isServiceUid(IPCThreadState::self()->getCallingUid())) {
ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
__func__, code, IPCThreadState::self()->getCallingPid(),
@@ -1424,7 +1608,8 @@
case SET_PHONE_STATE: {
CHECK_INTERFACE(IAudioPolicyService, data, reply);
reply->writeInt32(static_cast <uint32_t>(setPhoneState(
- (audio_mode_t) data.readInt32())));
+ (audio_mode_t) data.readInt32(),
+ (uid_t) data.readInt32())));
return NO_ERROR;
} break;
@@ -1471,6 +1656,11 @@
}
pid_t pid = (pid_t)data.readInt32();
uid_t uid = (uid_t)data.readInt32();
+ String16 opPackageName;
+ status = data.readString16(&opPackageName);
+ if (status != NO_ERROR) {
+ return status;
+ }
audio_config_t config;
memset(&config, 0, sizeof(audio_config_t));
data.read(&config, sizeof(audio_config_t));
@@ -1482,7 +1672,7 @@
std::vector<audio_io_handle_t> secondaryOutputs;
status = getOutputForAttr(&attr,
&output, session, &stream, pid, uid,
- &config,
+ opPackageName, &config,
flags, &selectedDeviceId, &portId, &secondaryOutputs);
reply->writeInt32(status);
status = reply->write(&attr, sizeof(audio_attributes_t));
@@ -1960,8 +2150,6 @@
case ACQUIRE_SOUNDTRIGGER_SESSION: {
CHECK_INTERFACE(IAudioPolicyService, data, reply);
- sp<IAudioPolicyServiceClient> client = interface_cast<IAudioPolicyServiceClient>(
- data.readStrongBinder());
audio_session_t session = AUDIO_SESSION_NONE;
audio_io_handle_t ioHandle = AUDIO_IO_HANDLE_NONE;
audio_devices_t device = AUDIO_DEVICE_NONE;
@@ -1977,8 +2165,6 @@
case RELEASE_SOUNDTRIGGER_SESSION: {
CHECK_INTERFACE(IAudioPolicyService, data, reply);
- sp<IAudioPolicyServiceClient> client = interface_cast<IAudioPolicyServiceClient>(
- data.readStrongBinder());
audio_session_t session = (audio_session_t)data.readInt32();
status_t status = releaseSoundTriggerSession(session);
reply->writeInt32(status);
@@ -2238,7 +2424,6 @@
reply->writeBool(isSupported);
return NO_ERROR;
}
-
case SET_UID_DEVICE_AFFINITY: {
CHECK_INTERFACE(IAudioPolicyService, data, reply);
const uid_t uid = (uid_t) data.readInt32();
@@ -2263,6 +2448,30 @@
return NO_ERROR;
}
+ case SET_USERID_DEVICE_AFFINITY: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ const int userId = (int) data.readInt32();
+ Vector<AudioDeviceTypeAddr> devices;
+ size_t size = (size_t)data.readInt32();
+ for (size_t i = 0; i < size; i++) {
+ AudioDeviceTypeAddr device;
+ if (device.readFromParcel((Parcel*)&data) == NO_ERROR) {
+ devices.add(device);
+ }
+ }
+ status_t status = setUserIdDeviceAffinities(userId, devices);
+ reply->writeInt32(status);
+ return NO_ERROR;
+ }
+
+ case REMOVE_USERID_DEVICE_AFFINITY: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ const int userId = (int) data.readInt32();
+ status_t status = removeUserIdDeviceAffinities(userId);
+ reply->writeInt32(status);
+ return NO_ERROR;
+ }
+
case LIST_AUDIO_PRODUCT_STRATEGIES: {
CHECK_INTERFACE(IAudioPolicyService, data, reply);
AudioProductStrategyVector strategies;
@@ -2343,16 +2552,46 @@
if (status != NO_ERROR) {
return status;
}
+
volume_group_t group;
status = getVolumeGroupFromAudioAttributes(attributes, group);
- reply->writeInt32(status);
if (status != NO_ERROR) {
return NO_ERROR;
}
+
+ reply->writeInt32(status);
reply->writeUint32(static_cast<int>(group));
return NO_ERROR;
}
+ case SET_SUPPORTED_SYSTEM_USAGES: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ std::vector<audio_usage_t> systemUsages;
+
+ int32_t size;
+ status_t status = data.readInt32(&size);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ if (size > MAX_ITEMS_PER_LIST) {
+ size = MAX_ITEMS_PER_LIST;
+ }
+
+ for (int32_t i = 0; i < size; i++) {
+ int32_t systemUsageInt;
+ status = data.readInt32(&systemUsageInt);
+ if (status != NO_ERROR) {
+ return status;
+ }
+
+ audio_usage_t systemUsage = static_cast<audio_usage_t>(systemUsageInt);
+ systemUsages.push_back(systemUsage);
+ }
+ status = setSupportedSystemUsages(systemUsages);
+ reply->writeInt32(static_cast <int32_t>(status));
+ return NO_ERROR;
+ }
+
case SET_ALLOWED_CAPTURE_POLICY: {
CHECK_INTERFACE(IAudioPolicyService, data, reply);
uid_t uid = data.readInt32();
@@ -2370,6 +2609,84 @@
return NO_ERROR;
}
+ case IS_CALL_SCREEN_MODE_SUPPORTED: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ bool isAvailable = isCallScreenModeSupported();
+ reply->writeBool(isAvailable);
+ return NO_ERROR;
+ }
+
+ case SET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ product_strategy_t strategy = (product_strategy_t) data.readUint32();
+ AudioDeviceTypeAddr device;
+ status_t status = device.readFromParcel((Parcel*)&data);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ status = setPreferredDeviceForStrategy(strategy, device);
+ reply->writeInt32(status);
+ return NO_ERROR;
+ }
+
+ case REMOVE_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ product_strategy_t strategy = (product_strategy_t) data.readUint32();
+ status_t status = removePreferredDeviceForStrategy(strategy);
+ reply->writeInt32(status);
+ return NO_ERROR;
+ }
+
+ case GET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ product_strategy_t strategy = (product_strategy_t) data.readUint32();
+ AudioDeviceTypeAddr device;
+ status_t status = getPreferredDeviceForStrategy(strategy, device);
+ status_t marshall_status = device.writeToParcel(reply);
+ if (marshall_status != NO_ERROR) {
+ return marshall_status;
+ }
+ reply->writeInt32(status);
+ return NO_ERROR;
+ }
+
+ case GET_DEVICES_FOR_ATTRIBUTES: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ AudioAttributes attributes;
+ status_t status = attributes.readFromParcel(&data);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ AudioDeviceTypeAddrVector devices;
+ status = getDevicesForAttributes(attributes.getAttributes(), &devices);
+ // reply data formatted as:
+ // - (int32) method call result from APM
+ // - (int32) number of devices (n) if method call returned NO_ERROR
+ // - n AudioDeviceTypeAddr if method call returned NO_ERROR
+ reply->writeInt32(status);
+ if (status != NO_ERROR) {
+ return NO_ERROR;
+ }
+ status = reply->writeInt32(devices.size());
+ if (status != NO_ERROR) {
+ return status;
+ }
+ for (const auto& device : devices) {
+ status = device.writeToParcel(reply);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ }
+
+ return NO_ERROR;
+ }
+
+ case AUDIO_MODULES_UPDATED: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ onNewAudioModulesAvailable();
+ return NO_ERROR;
+ } break;
+
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/media/libaudioclient/IAudioTrack.cpp b/media/libaudioclient/IAudioTrack.cpp
index 83a568a..6219e7a 100644
--- a/media/libaudioclient/IAudioTrack.cpp
+++ b/media/libaudioclient/IAudioTrack.cpp
@@ -62,7 +62,7 @@
status_t status = remote()->transact(GET_CBLK, data, &reply);
if (status == NO_ERROR) {
cblk = interface_cast<IMemory>(reply.readStrongBinder());
- if (cblk != 0 && cblk->pointer() == NULL) {
+ if (cblk != 0 && cblk->unsecurePointer() == NULL) {
cblk.clear();
}
}
diff --git a/media/libaudioclient/IEffect.cpp b/media/libaudioclient/IEffect.cpp
index ce72dae..5d47dff 100644
--- a/media/libaudioclient/IEffect.cpp
+++ b/media/libaudioclient/IEffect.cpp
@@ -122,7 +122,7 @@
status_t status = remote()->transact(GET_CBLK, data, &reply);
if (status == NO_ERROR) {
cblk = interface_cast<IMemory>(reply.readStrongBinder());
- if (cblk != 0 && cblk->pointer() == NULL) {
+ if (cblk != 0 && cblk->unsecurePointer() == NULL) {
cblk.clear();
}
}
diff --git a/media/libaudioclient/aidl/android/media/IAudioTrackCallback.aidl b/media/libaudioclient/aidl/android/media/IAudioTrackCallback.aidl
new file mode 100644
index 0000000..21553b5
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/IAudioTrackCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+/**
+ * @hide
+ */
+interface IAudioTrackCallback {
+ oneway void onCodecFormatChanged(in byte[] audioMetadata);
+}
diff --git a/media/libaudioclient/include/media/AudioEffect.h b/media/libaudioclient/include/media/AudioEffect.h
index 6bd4137..cb76252 100644
--- a/media/libaudioclient/include/media/AudioEffect.h
+++ b/media/libaudioclient/include/media/AudioEffect.h
@@ -362,17 +362,25 @@
* (AudioTrack or MediaPLayer) within the same audio session.
* io: HAL audio output or input stream to which this effect must be attached. Leave at 0 for
* automatic output selection by AudioFlinger.
+ * device: An audio device descriptor. Only used when "sessionID" is AUDIO_SESSION_DEVICE.
+ * Specifies the audio device type and address the effect must be attached to.
+ * If "sessionID" is AUDIO_SESSION_DEVICE then "io" must be AUDIO_IO_HANDLE_NONE.
+ * probe: true if created in a degraded mode to only verify if effect creation is possible.
+ * In this mode, no IEffect interface to AudioFlinger is created and all actions
+ * besides getters implemented in client AudioEffect object are no ops
+ * after effect creation.
*/
AudioEffect(const effect_uuid_t *type,
const String16& opPackageName,
const effect_uuid_t *uuid = NULL,
- int32_t priority = 0,
- effect_callback_t cbf = NULL,
- void* user = NULL,
- audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX,
- audio_io_handle_t io = AUDIO_IO_HANDLE_NONE
- );
+ int32_t priority = 0,
+ effect_callback_t cbf = NULL,
+ void* user = NULL,
+ audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX,
+ audio_io_handle_t io = AUDIO_IO_HANDLE_NONE,
+ const AudioDeviceTypeAddr& device = {},
+ bool probe = false);
/* Constructor.
* Same as above but with type and uuid specified by character strings
@@ -384,8 +392,9 @@
effect_callback_t cbf = NULL,
void* user = NULL,
audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX,
- audio_io_handle_t io = AUDIO_IO_HANDLE_NONE
- );
+ audio_io_handle_t io = AUDIO_IO_HANDLE_NONE,
+ const AudioDeviceTypeAddr& device = {},
+ bool probe = false);
/* Terminates the AudioEffect and unregisters it from AudioFlinger.
* The effect engine is also destroyed if this AudioEffect was the last controlling
@@ -406,8 +415,9 @@
effect_callback_t cbf = NULL,
void* user = NULL,
audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX,
- audio_io_handle_t io = AUDIO_IO_HANDLE_NONE
- );
+ audio_io_handle_t io = AUDIO_IO_HANDLE_NONE,
+ const AudioDeviceTypeAddr& device = {},
+ bool probe = false);
/* Result of constructing the AudioEffect. This must be checked
* before using any AudioEffect API.
@@ -541,6 +551,8 @@
audio_session_t mSessionId; // audio session ID
int32_t mPriority; // priority for effect control
status_t mStatus; // effect status
+ bool mProbe; // effect created in probe mode: all commands
+ // are no ops because mIEffect is NULL
effect_callback_t mCbf; // callback function for status, control and
// parameter changes notifications
void* mUserData; // client context for callback function
@@ -633,7 +645,8 @@
sp<EffectClient> mIEffectClient; // IEffectClient implementation
sp<IMemory> mCblkMemory; // shared memory for deferred parameter setting
effect_param_cblk_t* mCblk; // control block for deferred parameter setting
- pid_t mClientPid;
+ pid_t mClientPid = (pid_t)-1;
+ uid_t mClientUid = (uid_t)-1;
};
diff --git a/media/libaudioclient/include/media/AudioMixer.h b/media/libaudioclient/include/media/AudioMixer.h
deleted file mode 100644
index 783eef3..0000000
--- a/media/libaudioclient/include/media/AudioMixer.h
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef ANDROID_AUDIO_MIXER_H
-#define ANDROID_AUDIO_MIXER_H
-
-#include <map>
-#include <pthread.h>
-#include <sstream>
-#include <stdint.h>
-#include <sys/types.h>
-#include <unordered_map>
-#include <vector>
-
-#include <android/os/IExternalVibratorService.h>
-#include <media/AudioBufferProvider.h>
-#include <media/AudioResampler.h>
-#include <media/AudioResamplerPublic.h>
-#include <media/BufferProviders.h>
-#include <system/audio.h>
-#include <utils/Compat.h>
-#include <utils/threads.h>
-
-// FIXME This is actually unity gain, which might not be max in future, expressed in U.12
-#define MAX_GAIN_INT AudioMixer::UNITY_GAIN_INT
-
-// This must match frameworks/av/services/audioflinger/Configuration.h
-#define FLOAT_AUX
-
-namespace android {
-
-namespace NBLog {
-class Writer;
-} // namespace NBLog
-
-// ----------------------------------------------------------------------------
-
-class AudioMixer
-{
-public:
- // Do not change these unless underlying code changes.
- // This mixer has a hard-coded upper limit of 8 channels for output.
- static constexpr uint32_t MAX_NUM_CHANNELS = FCC_8;
- static constexpr uint32_t MAX_NUM_VOLUMES = FCC_2; // stereo volume only
- // maximum number of channels supported for the content
- static const uint32_t MAX_NUM_CHANNELS_TO_DOWNMIX = AUDIO_CHANNEL_COUNT_MAX;
-
- static const uint16_t UNITY_GAIN_INT = 0x1000;
- static const CONSTEXPR float UNITY_GAIN_FLOAT = 1.0f;
-
- enum { // names
- // setParameter targets
- TRACK = 0x3000,
- RESAMPLE = 0x3001,
- RAMP_VOLUME = 0x3002, // ramp to new volume
- VOLUME = 0x3003, // don't ramp
- TIMESTRETCH = 0x3004,
-
- // set Parameter names
- // for target TRACK
- CHANNEL_MASK = 0x4000,
- FORMAT = 0x4001,
- MAIN_BUFFER = 0x4002,
- AUX_BUFFER = 0x4003,
- DOWNMIX_TYPE = 0X4004,
- MIXER_FORMAT = 0x4005, // AUDIO_FORMAT_PCM_(FLOAT|16_BIT)
- MIXER_CHANNEL_MASK = 0x4006, // Channel mask for mixer output
- // for haptic
- HAPTIC_ENABLED = 0x4007, // Set haptic data from this track should be played or not.
- HAPTIC_INTENSITY = 0x4008, // Set the intensity to play haptic data.
- // for target RESAMPLE
- SAMPLE_RATE = 0x4100, // Configure sample rate conversion on this track name;
- // parameter 'value' is the new sample rate in Hz.
- // Only creates a sample rate converter the first time that
- // the track sample rate is different from the mix sample rate.
- // If the new sample rate is the same as the mix sample rate,
- // and a sample rate converter already exists,
- // then the sample rate converter remains present but is a no-op.
- RESET = 0x4101, // Reset sample rate converter without changing sample rate.
- // This clears out the resampler's input buffer.
- REMOVE = 0x4102, // Remove the sample rate converter on this track name;
- // the track is restored to the mix sample rate.
- // for target RAMP_VOLUME and VOLUME (8 channels max)
- // FIXME use float for these 3 to improve the dynamic range
- VOLUME0 = 0x4200,
- VOLUME1 = 0x4201,
- AUXLEVEL = 0x4210,
- // for target TIMESTRETCH
- PLAYBACK_RATE = 0x4300, // Configure timestretch on this track name;
- // parameter 'value' is a pointer to the new playback rate.
- };
-
- typedef enum { // Haptic intensity, should keep consistent with VibratorService
- HAPTIC_SCALE_MUTE = os::IExternalVibratorService::SCALE_MUTE,
- HAPTIC_SCALE_VERY_LOW = os::IExternalVibratorService::SCALE_VERY_LOW,
- HAPTIC_SCALE_LOW = os::IExternalVibratorService::SCALE_LOW,
- HAPTIC_SCALE_NONE = os::IExternalVibratorService::SCALE_NONE,
- HAPTIC_SCALE_HIGH = os::IExternalVibratorService::SCALE_HIGH,
- HAPTIC_SCALE_VERY_HIGH = os::IExternalVibratorService::SCALE_VERY_HIGH,
- } haptic_intensity_t;
- static constexpr float HAPTIC_SCALE_VERY_LOW_RATIO = 2.0f / 3.0f;
- static constexpr float HAPTIC_SCALE_LOW_RATIO = 3.0f / 4.0f;
- static const constexpr float HAPTIC_MAX_AMPLITUDE_FLOAT = 1.0f;
-
- static inline bool isValidHapticIntensity(haptic_intensity_t hapticIntensity) {
- switch (hapticIntensity) {
- case HAPTIC_SCALE_MUTE:
- case HAPTIC_SCALE_VERY_LOW:
- case HAPTIC_SCALE_LOW:
- case HAPTIC_SCALE_NONE:
- case HAPTIC_SCALE_HIGH:
- case HAPTIC_SCALE_VERY_HIGH:
- return true;
- default:
- return false;
- }
- }
-
- AudioMixer(size_t frameCount, uint32_t sampleRate)
- : mSampleRate(sampleRate)
- , mFrameCount(frameCount) {
- pthread_once(&sOnceControl, &sInitRoutine);
- }
-
- // Create a new track in the mixer.
- //
- // \param name a unique user-provided integer associated with the track.
- // If name already exists, the function will abort.
- // \param channelMask output channel mask.
- // \param format PCM format
- // \param sessionId Session id for the track. Tracks with the same
- // session id will be submixed together.
- //
- // \return OK on success.
- // BAD_VALUE if the format does not satisfy isValidFormat()
- // or the channelMask does not satisfy isValidChannelMask().
- status_t create(
- int name, audio_channel_mask_t channelMask, audio_format_t format, int sessionId);
-
- bool exists(int name) const {
- return mTracks.count(name) > 0;
- }
-
- // Free an allocated track by name.
- void destroy(int name);
-
- // Enable or disable an allocated track by name
- void enable(int name);
- void disable(int name);
-
- void setParameter(int name, int target, int param, void *value);
-
- void setBufferProvider(int name, AudioBufferProvider* bufferProvider);
-
- void process() {
- for (const auto &pair : mTracks) {
- // Clear contracted buffer before processing if contracted channels are saved
- const std::shared_ptr<Track> &t = pair.second;
- if (t->mKeepContractedChannels) {
- t->clearContractedBuffer();
- }
- }
- (this->*mHook)();
- processHapticData();
- }
-
- size_t getUnreleasedFrames(int name) const;
-
- std::string trackNames() const {
- std::stringstream ss;
- for (const auto &pair : mTracks) {
- ss << pair.first << " ";
- }
- return ss.str();
- }
-
- void setNBLogWriter(NBLog::Writer *logWriter) {
- mNBLogWriter = logWriter;
- }
-
- static inline bool isValidFormat(audio_format_t format) {
- switch (format) {
- case AUDIO_FORMAT_PCM_8_BIT:
- case AUDIO_FORMAT_PCM_16_BIT:
- case AUDIO_FORMAT_PCM_24_BIT_PACKED:
- case AUDIO_FORMAT_PCM_32_BIT:
- case AUDIO_FORMAT_PCM_FLOAT:
- return true;
- default:
- return false;
- }
- }
-
- static inline bool isValidChannelMask(audio_channel_mask_t channelMask) {
- return audio_channel_mask_is_valid(channelMask); // the RemixBufferProvider is flexible.
- }
-
-private:
-
- /* For multi-format functions (calls template functions
- * in AudioMixerOps.h). The template parameters are as follows:
- *
- * MIXTYPE (see AudioMixerOps.h MIXTYPE_* enumeration)
- * USEFLOATVOL (set to true if float volume is used)
- * ADJUSTVOL (set to true if volume ramp parameters needs adjustment afterwards)
- * TO: int32_t (Q4.27) or float
- * TI: int32_t (Q4.27) or int16_t (Q0.15) or float
- * TA: int32_t (Q4.27)
- */
-
- enum {
- // FIXME this representation permits up to 8 channels
- NEEDS_CHANNEL_COUNT__MASK = 0x00000007,
- };
-
- enum {
- NEEDS_CHANNEL_1 = 0x00000000, // mono
- NEEDS_CHANNEL_2 = 0x00000001, // stereo
-
- // sample format is not explicitly specified, and is assumed to be AUDIO_FORMAT_PCM_16_BIT
-
- NEEDS_MUTE = 0x00000100,
- NEEDS_RESAMPLE = 0x00001000,
- NEEDS_AUX = 0x00010000,
- };
-
- // hook types
- enum {
- PROCESSTYPE_NORESAMPLEONETRACK, // others set elsewhere
- };
-
- enum {
- TRACKTYPE_NOP,
- TRACKTYPE_RESAMPLE,
- TRACKTYPE_NORESAMPLE,
- TRACKTYPE_NORESAMPLEMONO,
- };
-
- // process hook functionality
- using process_hook_t = void(AudioMixer::*)();
-
- struct Track;
- using hook_t = void(Track::*)(int32_t* output, size_t numOutFrames, int32_t* temp, int32_t* aux);
-
- struct Track {
- Track()
- : bufferProvider(nullptr)
- {
- // TODO: move additional initialization here.
- }
-
- ~Track()
- {
- // bufferProvider, mInputBufferProvider need not be deleted.
- mResampler.reset(nullptr);
- // Ensure the order of destruction of buffer providers as they
- // release the upstream provider in the destructor.
- mTimestretchBufferProvider.reset(nullptr);
- mPostDownmixReformatBufferProvider.reset(nullptr);
- mDownmixerBufferProvider.reset(nullptr);
- mReformatBufferProvider.reset(nullptr);
- mContractChannelsNonDestructiveBufferProvider.reset(nullptr);
- mAdjustChannelsBufferProvider.reset(nullptr);
- }
-
- bool needsRamp() { return (volumeInc[0] | volumeInc[1] | auxInc) != 0; }
- bool setResampler(uint32_t trackSampleRate, uint32_t devSampleRate);
- bool doesResample() const { return mResampler.get() != nullptr; }
- void resetResampler() { if (mResampler.get() != nullptr) mResampler->reset(); }
- void adjustVolumeRamp(bool aux, bool useFloat = false);
- size_t getUnreleasedFrames() const { return mResampler.get() != nullptr ?
- mResampler->getUnreleasedFrames() : 0; };
-
- status_t prepareForDownmix();
- void unprepareForDownmix();
- status_t prepareForReformat();
- void unprepareForReformat();
- status_t prepareForAdjustChannels();
- void unprepareForAdjustChannels();
- status_t prepareForAdjustChannelsNonDestructive(size_t frames);
- void unprepareForAdjustChannelsNonDestructive();
- void clearContractedBuffer();
- bool setPlaybackRate(const AudioPlaybackRate &playbackRate);
- void reconfigureBufferProviders();
-
- static hook_t getTrackHook(int trackType, uint32_t channelCount,
- audio_format_t mixerInFormat, audio_format_t mixerOutFormat);
-
- void track__nop(int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
-
- template <int MIXTYPE, bool USEFLOATVOL, bool ADJUSTVOL,
- typename TO, typename TI, typename TA>
- void volumeMix(TO *out, size_t outFrames, const TI *in, TA *aux, bool ramp);
-
- uint32_t needs;
-
- // TODO: Eventually remove legacy integer volume settings
- union {
- int16_t volume[MAX_NUM_VOLUMES]; // U4.12 fixed point (top bit should be zero)
- int32_t volumeRL;
- };
-
- int32_t prevVolume[MAX_NUM_VOLUMES];
- int32_t volumeInc[MAX_NUM_VOLUMES];
- int32_t auxInc;
- int32_t prevAuxLevel;
- int16_t auxLevel; // 0 <= auxLevel <= MAX_GAIN_INT, but signed for mul performance
-
- uint16_t frameCount;
-
- uint8_t channelCount; // 1 or 2, redundant with (needs & NEEDS_CHANNEL_COUNT__MASK)
- uint8_t unused_padding; // formerly format, was always 16
- uint16_t enabled; // actually bool
- audio_channel_mask_t channelMask;
-
- // actual buffer provider used by the track hooks, see DownmixerBufferProvider below
- // for how the Track buffer provider is wrapped by another one when dowmixing is required
- AudioBufferProvider* bufferProvider;
-
- mutable AudioBufferProvider::Buffer buffer; // 8 bytes
-
- hook_t hook;
- const void *mIn; // current location in buffer
-
- std::unique_ptr<AudioResampler> mResampler;
- uint32_t sampleRate;
- int32_t* mainBuffer;
- int32_t* auxBuffer;
-
- /* Buffer providers are constructed to translate the track input data as needed.
- *
- * TODO: perhaps make a single PlaybackConverterProvider class to move
- * all pre-mixer track buffer conversions outside the AudioMixer class.
- *
- * 1) mInputBufferProvider: The AudioTrack buffer provider.
- * 2) mAdjustChannelsBufferProvider: Expands or contracts sample data from one interleaved
- * channel format to another. Expanded channels are filled with zeros and put at the end
- * of each audio frame. Contracted channels are copied to the end of the buffer.
- * 3) mContractChannelsNonDestructiveBufferProvider: Non-destructively contract sample data.
- * This is currently using at audio-haptic coupled playback to separate audio and haptic
- * data. Contracted channels could be written to given buffer.
- * 4) mReformatBufferProvider: If not NULL, performs the audio reformat to
- * match either mMixerInFormat or mDownmixRequiresFormat, if the downmixer
- * requires reformat. For example, it may convert floating point input to
- * PCM_16_bit if that's required by the downmixer.
- * 5) mDownmixerBufferProvider: If not NULL, performs the channel remixing to match
- * the number of channels required by the mixer sink.
- * 6) mPostDownmixReformatBufferProvider: If not NULL, performs reformatting from
- * the downmixer requirements to the mixer engine input requirements.
- * 7) mTimestretchBufferProvider: Adds timestretching for playback rate
- */
- AudioBufferProvider* mInputBufferProvider; // externally provided buffer provider.
- // TODO: combine mAdjustChannelsBufferProvider and
- // mContractChannelsNonDestructiveBufferProvider
- std::unique_ptr<PassthruBufferProvider> mAdjustChannelsBufferProvider;
- std::unique_ptr<PassthruBufferProvider> mContractChannelsNonDestructiveBufferProvider;
- std::unique_ptr<PassthruBufferProvider> mReformatBufferProvider;
- std::unique_ptr<PassthruBufferProvider> mDownmixerBufferProvider;
- std::unique_ptr<PassthruBufferProvider> mPostDownmixReformatBufferProvider;
- std::unique_ptr<PassthruBufferProvider> mTimestretchBufferProvider;
-
- int32_t sessionId;
-
- audio_format_t mMixerFormat; // output mix format: AUDIO_FORMAT_PCM_(FLOAT|16_BIT)
- audio_format_t mFormat; // input track format
- audio_format_t mMixerInFormat; // mix internal format AUDIO_FORMAT_PCM_(FLOAT|16_BIT)
- // each track must be converted to this format.
- audio_format_t mDownmixRequiresFormat; // required downmixer format
- // AUDIO_FORMAT_PCM_16_BIT if 16 bit necessary
- // AUDIO_FORMAT_INVALID if no required format
-
- float mVolume[MAX_NUM_VOLUMES]; // floating point set volume
- float mPrevVolume[MAX_NUM_VOLUMES]; // floating point previous volume
- float mVolumeInc[MAX_NUM_VOLUMES]; // floating point volume increment
-
- float mAuxLevel; // floating point set aux level
- float mPrevAuxLevel; // floating point prev aux level
- float mAuxInc; // floating point aux increment
-
- audio_channel_mask_t mMixerChannelMask;
- uint32_t mMixerChannelCount;
-
- AudioPlaybackRate mPlaybackRate;
-
- // Haptic
- bool mHapticPlaybackEnabled;
- haptic_intensity_t mHapticIntensity;
- audio_channel_mask_t mHapticChannelMask;
- uint32_t mHapticChannelCount;
- audio_channel_mask_t mMixerHapticChannelMask;
- uint32_t mMixerHapticChannelCount;
- uint32_t mAdjustInChannelCount;
- uint32_t mAdjustOutChannelCount;
- uint32_t mAdjustNonDestructiveInChannelCount;
- uint32_t mAdjustNonDestructiveOutChannelCount;
- bool mKeepContractedChannels;
-
- float getHapticScaleGamma() const {
- // Need to keep consistent with the value in VibratorService.
- switch (mHapticIntensity) {
- case HAPTIC_SCALE_VERY_LOW:
- return 2.0f;
- case HAPTIC_SCALE_LOW:
- return 1.5f;
- case HAPTIC_SCALE_HIGH:
- return 0.5f;
- case HAPTIC_SCALE_VERY_HIGH:
- return 0.25f;
- default:
- return 1.0f;
- }
- }
-
- float getHapticMaxAmplitudeRatio() const {
- // Need to keep consistent with the value in VibratorService.
- switch (mHapticIntensity) {
- case HAPTIC_SCALE_VERY_LOW:
- return HAPTIC_SCALE_VERY_LOW_RATIO;
- case HAPTIC_SCALE_LOW:
- return HAPTIC_SCALE_LOW_RATIO;
- case HAPTIC_SCALE_NONE:
- case HAPTIC_SCALE_HIGH:
- case HAPTIC_SCALE_VERY_HIGH:
- return 1.0f;
- default:
- return 0.0f;
- }
- }
-
- private:
- // hooks
- void track__genericResample(int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
- void track__16BitsStereo(int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
- void track__16BitsMono(int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
-
- void volumeRampStereo(int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux);
- void volumeStereo(int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux);
-
- // multi-format track hooks
- template <int MIXTYPE, typename TO, typename TI, typename TA>
- void track__Resample(TO* out, size_t frameCount, TO* temp __unused, TA* aux);
- template <int MIXTYPE, typename TO, typename TI, typename TA>
- void track__NoResample(TO* out, size_t frameCount, TO* temp __unused, TA* aux);
- };
-
- // TODO: remove BLOCKSIZE unit of processing - it isn't needed anymore.
- static constexpr int BLOCKSIZE = 16;
-
- bool setChannelMasks(int name,
- audio_channel_mask_t trackChannelMask, audio_channel_mask_t mixerChannelMask);
-
- // Called when track info changes and a new process hook should be determined.
- void invalidate() {
- mHook = &AudioMixer::process__validate;
- }
-
- void process__validate();
- void process__nop();
- void process__genericNoResampling();
- void process__genericResampling();
- void process__oneTrack16BitsStereoNoResampling();
-
- template <int MIXTYPE, typename TO, typename TI, typename TA>
- void process__noResampleOneTrack();
-
- void processHapticData();
-
- static process_hook_t getProcessHook(int processType, uint32_t channelCount,
- audio_format_t mixerInFormat, audio_format_t mixerOutFormat);
-
- static void convertMixerFormat(void *out, audio_format_t mixerOutFormat,
- void *in, audio_format_t mixerInFormat, size_t sampleCount);
-
- static void sInitRoutine();
-
- // initialization constants
- const uint32_t mSampleRate;
- const size_t mFrameCount;
-
- NBLog::Writer *mNBLogWriter = nullptr; // associated NBLog::Writer
-
- process_hook_t mHook = &AudioMixer::process__nop; // one of process__*, never nullptr
-
- // the size of the type (int32_t) should be the largest of all types supported
- // by the mixer.
- std::unique_ptr<int32_t[]> mOutputTemp;
- std::unique_ptr<int32_t[]> mResampleTemp;
-
- // track names grouped by main buffer, in no particular order of main buffer.
- // however names for a particular main buffer are in order (by construction).
- std::unordered_map<void * /* mainBuffer */, std::vector<int /* name */>> mGroups;
-
- // track names that are enabled, in increasing order (by construction).
- std::vector<int /* name */> mEnabled;
-
- // track smart pointers, by name, in increasing order of name.
- std::map<int /* name */, std::shared_ptr<Track>> mTracks;
-
- static pthread_once_t sOnceControl; // initialized in constructor by first new
-};
-
-// ----------------------------------------------------------------------------
-} // namespace android
-
-#endif // ANDROID_AUDIO_MIXER_H
diff --git a/media/libaudioclient/include/media/AudioParameter.h b/media/libaudioclient/include/media/AudioParameter.h
deleted file mode 100644
index 24837e3..0000000
--- a/media/libaudioclient/include/media/AudioParameter.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2008-2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_AUDIOPARAMETER_H_
-#define ANDROID_AUDIOPARAMETER_H_
-
-#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
-#include <utils/String8.h>
-
-namespace android {
-
-class AudioParameter {
-
-public:
- AudioParameter() {}
- AudioParameter(const String8& keyValuePairs);
- virtual ~AudioParameter();
-
- // reserved parameter keys for changing standard parameters with setParameters() function.
- // Using these keys is mandatory for AudioFlinger to properly monitor audio output/input
- // configuration changes and act accordingly.
- // keyRouting: to change audio routing, value is an int in audio_devices_t
- // keySamplingRate: to change sampling rate routing, value is an int
- // keyFormat: to change audio format, value is an int in audio_format_t
- // keyChannels: to change audio channel configuration, value is an int in audio_channels_t
- // keyFrameCount: to change audio output frame count, value is an int
- // keyInputSource: to change audio input source, value is an int in audio_source_t
- // (defined in media/mediarecorder.h)
- // keyScreenState: either "on" or "off"
- static const char * const keyRouting;
- static const char * const keySamplingRate;
- static const char * const keyFormat;
- static const char * const keyChannels;
- static const char * const keyFrameCount;
- static const char * const keyInputSource;
- static const char * const keyScreenState;
-
- // keyBtNrec: BT SCO Noise Reduction + Echo Cancellation parameters
- // keyHwAvSync: get HW synchronization source identifier from a device
- // keyMonoOutput: Enable mono audio playback
- // keyStreamHwAvSync: set HW synchronization source identifier on a stream
- static const char * const keyBtNrec;
- static const char * const keyHwAvSync;
- static const char * const keyMonoOutput;
- static const char * const keyStreamHwAvSync;
-
- // keys for presentation selection
- // keyPresentationId: Audio presentation identifier
- // keyProgramId: Audio presentation program identifier
- static const char * const keyPresentationId;
- static const char * const keyProgramId;
-
- // keyAudioLanguagePreferred: Preferred audio language
- static const char * const keyAudioLanguagePreferred;
-
- // keyStreamConnect / Disconnect: value is an int in audio_devices_t
- static const char * const keyStreamConnect;
- static const char * const keyStreamDisconnect;
-
- // For querying stream capabilities. All the returned values are lists.
- // keyStreamSupportedFormats: audio_format_t
- // keyStreamSupportedChannels: audio_channel_mask_t
- // keyStreamSupportedSamplingRates: sampling rate values
- static const char * const keyStreamSupportedFormats;
- static const char * const keyStreamSupportedChannels;
- static const char * const keyStreamSupportedSamplingRates;
-
- static const char * const valueOn;
- static const char * const valueOff;
-
- static const char * const valueListSeparator;
-
- // keyReconfigA2dp: Ask HwModule to reconfigure A2DP offloaded codec
- // keyReconfigA2dpSupported: Query if HwModule supports A2DP offload codec config
- static const char * const keyReconfigA2dp;
- static const char * const keyReconfigA2dpSupported;
-
- String8 toString() const { return toStringImpl(true); }
- String8 keysToString() const { return toStringImpl(false); }
-
- status_t add(const String8& key, const String8& value);
- status_t addInt(const String8& key, const int value);
- status_t addKey(const String8& key);
- status_t addFloat(const String8& key, const float value);
-
- status_t remove(const String8& key);
-
- status_t get(const String8& key, String8& value) const;
- status_t getInt(const String8& key, int& value) const;
- status_t getFloat(const String8& key, float& value) const;
- status_t getAt(size_t index, String8& key) const;
- status_t getAt(size_t index, String8& key, String8& value) const;
-
- size_t size() const { return mParameters.size(); }
-
-private:
- String8 mKeyValuePairs;
- KeyedVector <String8, String8> mParameters;
-
- String8 toStringImpl(bool useValues) const;
-};
-
-}; // namespace android
-
-#endif /*ANDROID_AUDIOPARAMETER_H_*/
diff --git a/media/libaudioclient/include/media/AudioPolicy.h b/media/libaudioclient/include/media/AudioPolicy.h
index ef39fd1..00fe278 100644
--- a/media/libaudioclient/include/media/AudioPolicy.h
+++ b/media/libaudioclient/include/media/AudioPolicy.h
@@ -18,11 +18,13 @@
#ifndef ANDROID_AUDIO_POLICY_H
#define ANDROID_AUDIO_POLICY_H
+#include <binder/Parcel.h>
+#include <media/AudioDeviceTypeAddr.h>
#include <system/audio.h>
#include <system/audio_policy.h>
-#include <binder/Parcel.h>
#include <utils/String8.h>
#include <utils/Vector.h>
+#include <cutils/multiuser.h>
namespace android {
@@ -31,10 +33,12 @@
#define RULE_MATCH_ATTRIBUTE_USAGE 0x1
#define RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET (0x1 << 1)
#define RULE_MATCH_UID (0x1 << 2)
+#define RULE_MATCH_USERID (0x1 << 3)
#define RULE_EXCLUDE_ATTRIBUTE_USAGE (RULE_EXCLUSION_MASK|RULE_MATCH_ATTRIBUTE_USAGE)
#define RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET \
(RULE_EXCLUSION_MASK|RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET)
#define RULE_EXCLUDE_UID (RULE_EXCLUSION_MASK|RULE_MATCH_UID)
+#define RULE_EXCLUDE_USERID (RULE_EXCLUSION_MASK|RULE_MATCH_USERID)
#define MIX_TYPE_INVALID (-1)
#define MIX_TYPE_PLAYERS 0
@@ -60,19 +64,6 @@
#define MAX_MIXES_PER_POLICY 10
#define MAX_CRITERIA_PER_MIX 20
-class AudioDeviceTypeAddr {
-public:
- AudioDeviceTypeAddr() {}
- AudioDeviceTypeAddr(audio_devices_t type, String8 address) :
- mType(type), mAddress(address) {}
-
- status_t readFromParcel(Parcel *parcel);
- status_t writeToParcel(Parcel *parcel) const;
-
- audio_devices_t mType;
- String8 mAddress;
-};
-
class AudioMixMatchCriterion {
public:
AudioMixMatchCriterion() {}
@@ -85,6 +76,7 @@
audio_usage_t mUsage;
audio_source_t mSource;
uid_t mUid;
+ int mUserId;
} mValue;
uint32_t mRule;
};
@@ -110,6 +102,13 @@
bool hasUidRule(bool match, uid_t uid) const;
/** returns true if this mix has a rule for uid match (any uid) */
bool hasMatchUidRule() const;
+
+ void setExcludeUserId(int userId) const;
+ void setMatchUserId(int userId) const;
+ /** returns true if this mix has a rule to match or exclude the given userId */
+ bool hasUserIdRule(bool match, int userId) const;
+ /** returns true if this mix has a rule for userId match (any userId) */
+ bool hasMatchUserIdRule() const;
/** returns true if this mix can be used for uid-device affinity routing */
bool isDeviceAffinityCompatible() const;
@@ -122,6 +121,8 @@
uint32_t mCbFlags; // flags indicating which callbacks to use, see kCbFlag*
/** Ignore the AUDIO_FLAG_NO_MEDIA_PROJECTION */
bool mAllowPrivilegedPlaybackCapture = false;
+ /** Indicates if the caller can capture voice communication output */
+ bool mVoiceCommunicationCaptureAllowed = false;
};
diff --git a/media/libaudioclient/include/media/AudioRecord.h b/media/libaudioclient/include/media/AudioRecord.h
index a3c0fe4..5c300ed 100644
--- a/media/libaudioclient/include/media/AudioRecord.h
+++ b/media/libaudioclient/include/media/AudioRecord.h
@@ -24,7 +24,7 @@
#include <cutils/sched_policy.h>
#include <media/AudioSystem.h>
#include <media/AudioTimestamp.h>
-#include <media/MediaAnalyticsItem.h>
+#include <media/MediaMetricsItem.h>
#include <media/Modulo.h>
#include <media/MicrophoneInfo.h>
#include <media/RecordingActivityTracker.h>
@@ -92,6 +92,11 @@
int8_t* i8; // unsigned 8-bit, offset by 0x80
// input to obtainBuffer(): unused, output: pointer to buffer
};
+
+ uint32_t sequence; // IAudioRecord instance sequence number, as of obtainBuffer().
+ // It is set by obtainBuffer() and confirmed by releaseBuffer().
+ // Not "user-serviceable".
+ // TODO Consider sp<IMemory> instead, or in addition to this.
};
/* As a convenience, if a callback is supplied, a handler thread
@@ -270,7 +275,7 @@
/*
* return metrics information for the current instance.
*/
- status_t getMetrics(MediaAnalyticsItem * &item);
+ status_t getMetrics(mediametrics::Item * &item);
/* After it's created the track is not active. Call start() to
* make it active. If set, the callback will start being called.
@@ -420,14 +425,17 @@
* frameCount number of frames requested
* size ignored
* raw ignored
+ * sequence ignored
* After error return:
* frameCount 0
* size 0
* raw undefined
+ * sequence undefined
* After successful return:
* frameCount actual number of frames available, <= number requested
* size actual number of bytes available
* raw pointer to the buffer
+ * sequence IAudioRecord instance sequence number, as of obtainBuffer()
*/
status_t obtainBuffer(Buffer* audioBuffer, int32_t waitCount,
@@ -733,27 +741,27 @@
private:
class MediaMetrics {
public:
- MediaMetrics() : mAnalyticsItem(MediaAnalyticsItem::create("audiorecord")),
+ MediaMetrics() : mMetricsItem(mediametrics::Item::create("audiorecord")),
mCreatedNs(systemTime(SYSTEM_TIME_REALTIME)),
mStartedNs(0), mDurationNs(0), mCount(0),
mLastError(NO_ERROR) {
}
~MediaMetrics() {
- // mAnalyticsItem alloc failure will be flagged in the constructor
+ // mMetricsItem alloc failure will be flagged in the constructor
// don't log empty records
- if (mAnalyticsItem->count() > 0) {
- mAnalyticsItem->selfrecord();
+ if (mMetricsItem->count() > 0) {
+ mMetricsItem->selfrecord();
}
}
void gather(const AudioRecord *record);
- MediaAnalyticsItem *dup() { return mAnalyticsItem->dup(); }
+ mediametrics::Item *dup() { return mMetricsItem->dup(); }
void logStart(nsecs_t when) { mStartedNs = when; mCount++; }
void logStop(nsecs_t when) { mDurationNs += (when-mStartedNs); mStartedNs = 0;}
void markError(status_t errcode, const char *func)
{ mLastError = errcode; mLastErrorFunc = func;}
private:
- std::unique_ptr<MediaAnalyticsItem> mAnalyticsItem;
+ std::unique_ptr<mediametrics::Item> mMetricsItem;
nsecs_t mCreatedNs; // XXX: perhaps not worth it in production
nsecs_t mStartedNs;
nsecs_t mDurationNs;
@@ -763,6 +771,7 @@
std::string mLastErrorFunc;
};
MediaMetrics mMediaMetrics;
+ std::string mMetricsId; // GUARDED_BY(mLock), could change in createRecord_l().
};
}; // namespace android
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 09e80b2..aebc875 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -19,6 +19,7 @@
#include <sys/types.h>
+#include <media/AudioDeviceTypeAddr.h>
#include <media/AudioPolicy.h>
#include <media/AudioProductStrategy.h>
#include <media/AudioVolumeGroup.h>
@@ -26,6 +27,7 @@
#include <media/IAudioFlingerClient.h>
#include <media/IAudioPolicyServiceClient.h>
#include <media/MicrophoneInfo.h>
+#include <set>
#include <system/audio.h>
#include <system/audio_effect.h>
#include <system/audio_policy.h>
@@ -106,7 +108,16 @@
static status_t setParameters(const String8& keyValuePairs);
static String8 getParameters(const String8& keys);
- static void setErrorCallback(audio_error_callback cb);
+ // Registers an error callback. When this callback is invoked, it means all
+ // state implied by this interface has been reset.
+ // Returns a token that can be used for un-registering.
+ // Might block while callbacks are being invoked.
+ static uintptr_t addErrorCallback(audio_error_callback cb);
+
+ // Un-registers a callback previously added with addErrorCallback.
+ // Might block while callbacks are being invoked.
+ static void removeErrorCallback(uintptr_t cb);
+
static void setDynPolicyCallback(dynamic_policy_callback cb);
static void setRecordConfigCallback(record_config_callback);
@@ -171,7 +182,7 @@
// or an unspecified existing unique ID.
static audio_unique_id_t newAudioUniqueId(audio_unique_id_use_t use);
- static void acquireAudioSessionId(audio_session_t audioSession, pid_t pid);
+ static void acquireAudioSessionId(audio_session_t audioSession, pid_t pid, uid_t uid);
static void releaseAudioSessionId(audio_session_t audioSession, pid_t pid);
// Get the HW synchronization source used for an audio session.
@@ -210,6 +221,7 @@
//
// IAudioPolicyService interface (see AudioPolicyInterface for method descriptions)
//
+ static void onNewAudioModulesAvailable();
static status_t setDeviceConnectionState(audio_devices_t device, audio_policy_dev_state_t state,
const char *device_address, const char *device_name,
audio_format_t encodedFormat);
@@ -219,7 +231,7 @@
const char *device_address,
const char *device_name,
audio_format_t encodedFormat);
- static status_t setPhoneState(audio_mode_t state);
+ static status_t setPhoneState(audio_mode_t state, uid_t uid);
static status_t setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config);
static audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage);
@@ -229,6 +241,7 @@
audio_stream_type_t *stream,
pid_t pid,
uid_t uid,
+ const String16& opPackageName,
const audio_config_t *config,
audio_output_flags_t flags,
audio_port_handle_t *selectedDeviceId,
@@ -278,6 +291,8 @@
static uint32_t getStrategyForStream(audio_stream_type_t stream);
static audio_devices_t getDevicesForStream(audio_stream_type_t stream);
+ static status_t getDevicesForAttributes(const AudioAttributes &aa,
+ AudioDeviceTypeAddrVector *devices);
static audio_io_handle_t getOutputForEffect(const effect_descriptor_t *desc);
static status_t registerEffect(const effect_descriptor_t *desc,
@@ -301,6 +316,8 @@
static status_t setLowRamDevice(bool isLowRamDevice, int64_t totalMemory);
+ static status_t setSupportedSystemUsages(const std::vector<audio_usage_t>& systemUsages);
+
static status_t setAllowedCapturePolicy(uid_t uid, audio_flags_mask_t flags);
// Check if hw offload is possible for given format, stream type, sample rate,
@@ -349,6 +366,10 @@
static status_t removeUidDeviceAffinities(uid_t uid);
+ static status_t setUserIdDeviceAffinities(int userId, const Vector<AudioDeviceTypeAddr>& devices);
+
+ static status_t removeUserIdDeviceAffinities(int userId);
+
static status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
audio_port_handle_t *portId);
@@ -396,6 +417,25 @@
static status_t setRttEnabled(bool enabled);
+ static bool isCallScreenModeSupported();
+
+ /**
+ * Send audio HAL server process pids to native audioserver process for use
+ * when generating audio HAL servers tombstones
+ */
+ static status_t setAudioHalPids(const std::vector<pid_t>& pids);
+
+ static status_t setPreferredDeviceForStrategy(product_strategy_t strategy,
+ const AudioDeviceTypeAddr &device);
+
+ static status_t removePreferredDeviceForStrategy(product_strategy_t strategy);
+
+ static status_t getPreferredDeviceForStrategy(product_strategy_t strategy,
+ AudioDeviceTypeAddr &device);
+
+ static status_t getDeviceForStrategy(product_strategy_t strategy,
+ AudioDeviceTypeAddr &device);
+
// ----------------------------------------------------------------------------
class AudioVolumeGroupCallback : public RefBase
@@ -540,15 +580,19 @@
static const sp<AudioFlingerClient> getAudioFlingerClient();
static sp<AudioIoDescriptor> getIoDescriptor(audio_io_handle_t ioHandle);
+ // Invokes all registered error callbacks with the given error code.
+ static void reportError(status_t err);
+
static sp<AudioFlingerClient> gAudioFlingerClient;
static sp<AudioPolicyServiceClient> gAudioPolicyServiceClient;
friend class AudioFlingerClient;
friend class AudioPolicyServiceClient;
- static Mutex gLock; // protects gAudioFlinger and gAudioErrorCallback,
+ static Mutex gLock; // protects gAudioFlinger
+ static Mutex gLockErrorCallbacks; // protects gAudioErrorCallbacks
static Mutex gLockAPS; // protects gAudioPolicyService and gAudioPolicyServiceClient
static sp<IAudioFlinger> gAudioFlinger;
- static audio_error_callback gAudioErrorCallback;
+ static std::set<audio_error_callback> gAudioErrorCallbacks;
static dynamic_policy_callback gDynPolicyCallback;
static record_config_callback gRecordConfigCallback;
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index df5eabc..4adaaea 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -22,10 +22,13 @@
#include <media/AudioTimestamp.h>
#include <media/IAudioTrack.h>
#include <media/AudioResamplerPublic.h>
-#include <media/MediaAnalyticsItem.h>
+#include <media/MediaMetricsItem.h>
#include <media/Modulo.h>
#include <utils/threads.h>
+#include "android/media/BnAudioTrackCallback.h"
+#include "android/media/IAudioTrackCallback.h"
+
namespace android {
// ----------------------------------------------------------------------------
@@ -107,6 +110,11 @@
int16_t* i16; // signed 16-bit
int8_t* i8; // unsigned 8-bit, offset by 0x80
}; // input to obtainBuffer(): unused, output: pointer to buffer
+
+ uint32_t sequence; // IAudioTrack instance sequence number, as of obtainBuffer().
+ // It is set by obtainBuffer() and confirmed by releaseBuffer().
+ // Not "user-serviceable".
+ // TODO Consider sp<IMemory> instead, or in addition to this.
};
/* As a convenience, if a callback is supplied, a handler thread
@@ -400,7 +408,7 @@
/*
* return metrics information for the current track.
*/
- status_t getMetrics(MediaAnalyticsItem * &item);
+ status_t getMetrics(mediametrics::Item * &item);
/* After it's created the track is not active. Call start() to
* make it active. If set, the callback will start being called.
@@ -692,14 +700,17 @@
* frameCount number of [empty slots for] frames requested
* size ignored
* raw ignored
+ * sequence ignored
* After error return:
* frameCount 0
* size 0
* raw undefined
+ * sequence undefined
* After successful return:
* frameCount actual number of [empty slots for] frames available, <= number requested
* size actual number of bytes available
* raw pointer to the buffer
+ * sequence IAudioTrack instance sequence number, as of obtainBuffer()
*/
status_t obtainBuffer(Buffer* audioBuffer, int32_t waitCount,
size_t *nonContig = NULL);
@@ -877,8 +888,6 @@
virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
audio_port_handle_t deviceId);
-
-
/* Obtain the pending duration in milliseconds for playback of pure PCM
* (mixable without embedded timing) data remaining in AudioTrack.
*
@@ -925,6 +934,10 @@
*/
audio_port_handle_t getPortId() const { return mPortId; };
+ void setAudioTrackCallback(const sp<media::IAudioTrackCallback>& callback) {
+ mAudioTrackCallback->setAudioTrackCallback(callback);
+ }
+
protected:
/* copying audio tracks is not allowed */
AudioTrack(const AudioTrack& other);
@@ -1230,21 +1243,34 @@
private:
class MediaMetrics {
public:
- MediaMetrics() : mAnalyticsItem(MediaAnalyticsItem::create("audiotrack")) {
+ MediaMetrics() : mMetricsItem(mediametrics::Item::create("audiotrack")) {
}
~MediaMetrics() {
- // mAnalyticsItem alloc failure will be flagged in the constructor
+ // mMetricsItem alloc failure will be flagged in the constructor
// don't log empty records
- if (mAnalyticsItem->count() > 0) {
- mAnalyticsItem->selfrecord();
+ if (mMetricsItem->count() > 0) {
+ mMetricsItem->selfrecord();
}
}
void gather(const AudioTrack *track);
- MediaAnalyticsItem *dup() { return mAnalyticsItem->dup(); }
+ mediametrics::Item *dup() { return mMetricsItem->dup(); }
private:
- std::unique_ptr<MediaAnalyticsItem> mAnalyticsItem;
+ std::unique_ptr<mediametrics::Item> mMetricsItem;
};
MediaMetrics mMediaMetrics;
+ std::string mMetricsId; // GUARDED_BY(mLock), could change in createTrack_l().
+
+private:
+ class AudioTrackCallback : public media::BnAudioTrackCallback {
+ public:
+ binder::Status onCodecFormatChanged(const std::vector<uint8_t>& audioMetadata) override;
+
+ void setAudioTrackCallback(const sp<media::IAudioTrackCallback>& callback);
+ private:
+ Mutex mAudioTrackCbLock;
+ wp<media::IAudioTrackCallback> mCallback;
+ };
+ sp<AudioTrackCallback> mAudioTrackCallback;
};
}; // namespace android
diff --git a/media/libmedia/include/media/ExtendedAudioBufferProvider.h b/media/libaudioclient/include/media/ExtendedAudioBufferProvider.h
similarity index 100%
rename from media/libmedia/include/media/ExtendedAudioBufferProvider.h
rename to media/libaudioclient/include/media/ExtendedAudioBufferProvider.h
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index 8ec8931..c9d9716 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -27,6 +27,7 @@
#include <binder/Parcel.h>
#include <binder/Parcelable.h>
#include <media/AudioClient.h>
+#include <media/DeviceDescriptorBase.h>
#include <media/IAudioTrack.h>
#include <media/IAudioFlingerClient.h>
#include <system/audio.h>
@@ -39,6 +40,7 @@
#include <vector>
#include "android/media/IAudioRecord.h"
+#include "android/media/IAudioTrackCallback.h"
namespace android {
@@ -69,14 +71,21 @@
if (clientInfo.readFromParcel(parcel) != NO_ERROR) {
return DEAD_OBJECT;
}
+ opPackageName = parcel->readString16();
if (parcel->readInt32() != 0) {
+ // TODO: Using unsecurePointer() has some associated security
+ // pitfalls (see declaration for details).
+ // Either document why it is safe in this case or address
+ // the issue (e.g. by copying).
sharedBuffer = interface_cast<IMemory>(parcel->readStrongBinder());
- if (sharedBuffer == 0 || sharedBuffer->pointer() == NULL) {
+ if (sharedBuffer == 0 || sharedBuffer->unsecurePointer() == NULL) {
return BAD_VALUE;
}
}
notificationsPerBuffer = parcel->readInt32();
speed = parcel->readFloat();
+ audioTrackCallback = interface_cast<media::IAudioTrackCallback>(
+ parcel->readStrongBinder());
/* input/output arguments*/
(void)parcel->read(&flags, sizeof(audio_output_flags_t));
@@ -92,6 +101,7 @@
(void)parcel->write(&attr, sizeof(audio_attributes_t));
(void)parcel->write(&config, sizeof(audio_config_t));
(void)clientInfo.writeToParcel(parcel);
+ (void)parcel->writeString16(opPackageName);
if (sharedBuffer != 0) {
(void)parcel->writeInt32(1);
(void)parcel->writeStrongBinder(IInterface::asBinder(sharedBuffer));
@@ -100,6 +110,7 @@
}
(void)parcel->writeInt32(notificationsPerBuffer);
(void)parcel->writeFloat(speed);
+ (void)parcel->writeStrongBinder(IInterface::asBinder(audioTrackCallback));
/* input/output arguments*/
(void)parcel->write(&flags, sizeof(audio_output_flags_t));
@@ -114,9 +125,11 @@
audio_attributes_t attr;
audio_config_t config;
AudioClient clientInfo;
+ String16 opPackageName;
sp<IMemory> sharedBuffer;
uint32_t notificationsPerBuffer;
float speed;
+ sp<media::IAudioTrackCallback> audioTrackCallback;
/* input/output */
audio_output_flags_t flags;
@@ -269,13 +282,21 @@
(void)parcel->read(&inputId, sizeof(audio_io_handle_t));
if (parcel->readInt32() != 0) {
cblk = interface_cast<IMemory>(parcel->readStrongBinder());
- if (cblk == 0 || cblk->pointer() == NULL) {
+ // TODO: Using unsecurePointer() has some associated security
+ // pitfalls (see declaration for details).
+ // Either document why it is safe in this case or address
+ // the issue (e.g. by copying).
+ if (cblk == 0 || cblk->unsecurePointer() == NULL) {
return BAD_VALUE;
}
}
if (parcel->readInt32() != 0) {
buffers = interface_cast<IMemory>(parcel->readStrongBinder());
- if (buffers == 0 || buffers->pointer() == NULL) {
+ // TODO: Using unsecurePointer() has some associated security
+ // pitfalls (see declaration for details).
+ // Either document why it is safe in this case or address
+ // the issue (e.g. by copying).
+ if (buffers == 0 || buffers->unsecurePointer() == NULL) {
return BAD_VALUE;
}
}
@@ -384,7 +405,7 @@
// mic mute/state
virtual status_t setMicMute(bool state) = 0;
virtual bool getMicMute() const = 0;
- virtual void setRecordSilenced(uid_t uid, bool silenced) = 0;
+ virtual void setRecordSilenced(audio_port_handle_t portId, bool silenced) = 0;
virtual status_t setParameters(audio_io_handle_t ioHandle,
const String8& keyValuePairs) = 0;
@@ -396,7 +417,7 @@
// Thus the IAudioFlingerClient must be a singleton per process.
virtual void registerClient(const sp<IAudioFlingerClient>& client) = 0;
- // retrieve the audio recording buffer size
+ // retrieve the audio recording buffer size in bytes
// FIXME This API assumes a route, and so should be deprecated.
virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format,
audio_channel_mask_t channelMask) const = 0;
@@ -404,8 +425,7 @@
virtual status_t openOutput(audio_module_handle_t module,
audio_io_handle_t *output,
audio_config_t *config,
- audio_devices_t *devices,
- const String8& address,
+ const sp<DeviceDescriptorBase>& device,
uint32_t *latencyMs,
audio_output_flags_t flags) = 0;
virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1,
@@ -434,7 +454,7 @@
virtual audio_unique_id_t newAudioUniqueId(audio_unique_id_use_t use) = 0;
- virtual void acquireAudioSessionId(audio_session_t audioSession, pid_t pid) = 0;
+ virtual void acquireAudioSessionId(audio_session_t audioSession, pid_t pid, uid_t uid) = 0;
virtual void releaseAudioSessionId(audio_session_t audioSession, pid_t pid) = 0;
virtual status_t queryNumberEffects(uint32_t *numEffects) const = 0;
@@ -453,8 +473,10 @@
// AudioFlinger doesn't take over handle reference from client
audio_io_handle_t output,
audio_session_t sessionId,
+ const AudioDeviceTypeAddr& device,
const String16& callingPackage,
pid_t pid,
+ bool probe,
status_t *status,
int *id,
int *enabled) = 0;
@@ -511,6 +533,8 @@
/* List available microphones and their characteristics */
virtual status_t getMicrophones(std::vector<media::MicrophoneInfo> *microphones) = 0;
+
+ virtual status_t setAudioHalPids(const std::vector<pid_t>& pids) = 0;
};
diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h
index 32275cf..ec3461e 100644
--- a/media/libaudioclient/include/media/IAudioPolicyService.h
+++ b/media/libaudioclient/include/media/IAudioPolicyService.h
@@ -23,6 +23,7 @@
#include <utils/RefBase.h>
#include <utils/Errors.h>
#include <binder/IInterface.h>
+#include <media/AudioDeviceTypeAddr.h>
#include <media/AudioSystem.h>
#include <media/AudioPolicy.h>
#include <media/IAudioPolicyServiceClient.h>
@@ -41,6 +42,7 @@
//
// IAudioPolicyService interface (see AudioPolicyInterface for method descriptions)
//
+ virtual void onNewAudioModulesAvailable() = 0;
virtual status_t setDeviceConnectionState(audio_devices_t device,
audio_policy_dev_state_t state,
const char *device_address,
@@ -52,7 +54,7 @@
const char *device_address,
const char *device_name,
audio_format_t encodedFormat) = 0;
- virtual status_t setPhoneState(audio_mode_t state) = 0;
+ virtual status_t setPhoneState(audio_mode_t state, uid_t uid) = 0;
virtual status_t setForceUse(audio_policy_force_use_t usage,
audio_policy_forced_cfg_t config) = 0;
virtual audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage) = 0;
@@ -63,6 +65,7 @@
audio_stream_type_t *stream,
pid_t pid,
uid_t uid,
+ const String16& opPackageName,
const audio_config_t *config,
audio_output_flags_t flags,
audio_port_handle_t *selectedDeviceId,
@@ -107,6 +110,8 @@
virtual uint32_t getStrategyForStream(audio_stream_type_t stream) = 0;
virtual audio_devices_t getDevicesForStream(audio_stream_type_t stream) = 0;
+ virtual status_t getDevicesForAttributes(const AudioAttributes &aa,
+ AudioDeviceTypeAddrVector *devices) const = 0;
virtual audio_io_handle_t getOutputForEffect(const effect_descriptor_t *desc) = 0;
virtual status_t registerEffect(const effect_descriptor_t *desc,
audio_io_handle_t io,
@@ -137,6 +142,7 @@
audio_unique_id_t* id) = 0;
virtual status_t removeSourceDefaultEffect(audio_unique_id_t id) = 0;
virtual status_t removeStreamDefaultEffect(audio_unique_id_t id) = 0;
+ virtual status_t setSupportedSystemUsages(const std::vector<audio_usage_t>& systemUsages) = 0;
virtual status_t setAllowedCapturePolicy(uid_t uid, audio_flags_mask_t flags) = 0;
// Check if offload is possible for given format, stream type, sample rate,
// bit rate, duration, video and streaming or offload property is enabled
@@ -191,6 +197,11 @@
virtual status_t removeUidDeviceAffinities(uid_t uid) = 0;
+ virtual status_t setUserIdDeviceAffinities(int userId,
+ const Vector<AudioDeviceTypeAddr>& devices) = 0;
+
+ virtual status_t removeUserIdDeviceAffinities(int userId) = 0;
+
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
audio_port_handle_t *portId) = 0;
@@ -222,6 +233,16 @@
volume_group_t &volumeGroup) = 0;
virtual status_t setRttEnabled(bool enabled) = 0;
+
+ virtual bool isCallScreenModeSupported() = 0;
+
+ virtual status_t setPreferredDeviceForStrategy(product_strategy_t strategy,
+ const AudioDeviceTypeAddr &device) = 0;
+
+ virtual status_t removePreferredDeviceForStrategy(product_strategy_t strategy) = 0;
+
+ virtual status_t getPreferredDeviceForStrategy(product_strategy_t strategy,
+ AudioDeviceTypeAddr &device) = 0;
};
diff --git a/media/libaudioclient/tests/Android.bp b/media/libaudioclient/tests/Android.bp
index 52bb2fb..350a780 100644
--- a/media/libaudioclient/tests/Android.bp
+++ b/media/libaudioclient/tests/Android.bp
@@ -11,6 +11,10 @@
defaults: ["libaudioclient_tests_defaults"],
srcs: ["test_create_audiotrack.cpp",
"test_create_utils.cpp"],
+ header_libs: [
+ "libmedia_headers",
+ "libmediametrics_headers",
+ ],
shared_libs: [
"libaudioclient",
"libbinder",
@@ -25,6 +29,10 @@
defaults: ["libaudioclient_tests_defaults"],
srcs: ["test_create_audiorecord.cpp",
"test_create_utils.cpp"],
+ header_libs: [
+ "libmedia_headers",
+ "libmediametrics_headers",
+ ],
shared_libs: [
"libaudioclient",
"libbinder",
diff --git a/media/libaudiofoundation/Android.bp b/media/libaudiofoundation/Android.bp
new file mode 100644
index 0000000..93bc4d9
--- /dev/null
+++ b/media/libaudiofoundation/Android.bp
@@ -0,0 +1,50 @@
+cc_library_headers {
+ name: "libaudiofoundation_headers",
+ vendor_available: true,
+ export_include_dirs: ["include"],
+ header_libs: [
+ "libaudio_system_headers",
+ "libmedia_helper_headers",
+ ],
+ export_header_lib_headers: [
+ "libaudio_system_headers",
+ "libmedia_helper_headers",
+ ],
+}
+
+cc_library {
+ name: "libaudiofoundation",
+ vendor_available: true,
+ double_loadable: true,
+
+ srcs: [
+ "AudioContainers.cpp",
+ "AudioDeviceTypeAddr.cpp",
+ "AudioGain.cpp",
+ "AudioPort.cpp",
+ "AudioProfile.cpp",
+ "DeviceDescriptorBase.cpp",
+ ],
+
+ shared_libs: [
+ "libaudioutils",
+ "libbase",
+ "libbinder",
+ "liblog",
+ "libmedia_helper",
+ "libutils",
+ ],
+
+ header_libs: [
+ "libaudiofoundation_headers",
+ ],
+
+ export_header_lib_headers: [
+ "libaudiofoundation_headers",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+}
diff --git a/media/libaudiofoundation/AudioContainers.cpp b/media/libaudiofoundation/AudioContainers.cpp
new file mode 100644
index 0000000..31257d5
--- /dev/null
+++ b/media/libaudiofoundation/AudioContainers.cpp
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+#include <sstream>
+#include <string>
+
+#include <media/AudioContainers.h>
+
+namespace android {
+
+const DeviceTypeSet& getAudioDeviceOutAllSet() {
+ static const DeviceTypeSet audioDeviceOutAllSet = DeviceTypeSet(
+ std::begin(AUDIO_DEVICE_OUT_ALL_ARRAY),
+ std::end(AUDIO_DEVICE_OUT_ALL_ARRAY));
+ return audioDeviceOutAllSet;
+}
+
+const DeviceTypeSet& getAudioDeviceOutAllA2dpSet() {
+ static const DeviceTypeSet audioDeviceOutAllA2dpSet = DeviceTypeSet(
+ std::begin(AUDIO_DEVICE_OUT_ALL_A2DP_ARRAY),
+ std::end(AUDIO_DEVICE_OUT_ALL_A2DP_ARRAY));
+ return audioDeviceOutAllA2dpSet;
+}
+
+const DeviceTypeSet& getAudioDeviceOutAllScoSet() {
+ static const DeviceTypeSet audioDeviceOutAllScoSet = DeviceTypeSet(
+ std::begin(AUDIO_DEVICE_OUT_ALL_SCO_ARRAY),
+ std::end(AUDIO_DEVICE_OUT_ALL_SCO_ARRAY));
+ return audioDeviceOutAllScoSet;
+}
+
+const DeviceTypeSet& getAudioDeviceOutAllUsbSet() {
+ static const DeviceTypeSet audioDeviceOutAllUsbSet = DeviceTypeSet(
+ std::begin(AUDIO_DEVICE_OUT_ALL_USB_ARRAY),
+ std::end(AUDIO_DEVICE_OUT_ALL_USB_ARRAY));
+ return audioDeviceOutAllUsbSet;
+}
+
+const DeviceTypeSet& getAudioDeviceInAllSet() {
+ static const DeviceTypeSet audioDeviceInAllSet = DeviceTypeSet(
+ std::begin(AUDIO_DEVICE_IN_ALL_ARRAY),
+ std::end(AUDIO_DEVICE_IN_ALL_ARRAY));
+ return audioDeviceInAllSet;
+}
+
+const DeviceTypeSet& getAudioDeviceInAllUsbSet() {
+ static const DeviceTypeSet audioDeviceInAllUsbSet = DeviceTypeSet(
+ std::begin(AUDIO_DEVICE_IN_ALL_USB_ARRAY),
+ std::end(AUDIO_DEVICE_IN_ALL_USB_ARRAY));
+ return audioDeviceInAllUsbSet;
+}
+
+bool deviceTypesToString(const DeviceTypeSet &deviceTypes, std::string &str) {
+ if (deviceTypes.empty()) {
+ str = "Empty device types";
+ return true;
+ }
+ bool ret = true;
+ for (auto it = deviceTypes.begin(); it != deviceTypes.end();) {
+ std::string deviceTypeStr;
+ ret = audio_is_output_device(*it) ?
+ OutputDeviceConverter::toString(*it, deviceTypeStr) :
+ InputDeviceConverter::toString(*it, deviceTypeStr);
+ if (!ret) {
+ break;
+ }
+ str.append(deviceTypeStr);
+ if (++it != deviceTypes.end()) {
+ str.append(" , ");
+ }
+ }
+ if (!ret) {
+ str = "Unknown values";
+ }
+ return ret;
+}
+
+std::string dumpDeviceTypes(const DeviceTypeSet &deviceTypes) {
+ std::string ret;
+ for (auto it = deviceTypes.begin(); it != deviceTypes.end();) {
+ std::stringstream ss;
+ ss << "0x" << std::hex << (*it);
+ ret.append(ss.str());
+ if (++it != deviceTypes.end()) {
+ ret.append(" , ");
+ }
+ }
+ return ret;
+}
+
+std::string toString(const DeviceTypeSet& deviceTypes) {
+ std::string ret;
+ deviceTypesToString(deviceTypes, ret);
+ return ret;
+}
+
+} // namespace android
diff --git a/media/libaudiofoundation/AudioDeviceTypeAddr.cpp b/media/libaudiofoundation/AudioDeviceTypeAddr.cpp
new file mode 100644
index 0000000..b44043a
--- /dev/null
+++ b/media/libaudiofoundation/AudioDeviceTypeAddr.cpp
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+#include <media/AudioDeviceTypeAddr.h>
+
+namespace android {
+
+const char* AudioDeviceTypeAddr::getAddress() const {
+ return mAddress.c_str();
+}
+
+bool AudioDeviceTypeAddr::equals(const AudioDeviceTypeAddr& other) const {
+ return mType == other.mType && mAddress == other.mAddress;
+}
+
+bool AudioDeviceTypeAddr::operator<(const AudioDeviceTypeAddr& other) const {
+ if (mType < other.mType) return true;
+ if (mType > other.mType) return false;
+
+ if (mAddress < other.mAddress) return true;
+ // if (mAddress > other.mAddress) return false;
+
+ return false;
+}
+
+void AudioDeviceTypeAddr::reset() {
+ mType = AUDIO_DEVICE_NONE;
+ mAddress = "";
+}
+
+status_t AudioDeviceTypeAddr::readFromParcel(const Parcel *parcel) {
+ status_t status;
+ if ((status = parcel->readUint32(&mType)) != NO_ERROR) return status;
+ status = parcel->readUtf8FromUtf16(&mAddress);
+ return status;
+}
+
+status_t AudioDeviceTypeAddr::writeToParcel(Parcel *parcel) const {
+ status_t status;
+ if ((status = parcel->writeUint32(mType)) != NO_ERROR) return status;
+ status = parcel->writeUtf8AsUtf16(mAddress);
+ return status;
+}
+
+
+DeviceTypeSet getAudioDeviceTypes(const AudioDeviceTypeAddrVector& deviceTypeAddrs) {
+ DeviceTypeSet deviceTypes;
+ for (const auto& deviceTypeAddr : deviceTypeAddrs) {
+ deviceTypes.insert(deviceTypeAddr.mType);
+ }
+ return deviceTypes;
+}
+
+}
\ No newline at end of file
diff --git a/media/libaudiofoundation/AudioGain.cpp b/media/libaudiofoundation/AudioGain.cpp
new file mode 100644
index 0000000..0d28335
--- /dev/null
+++ b/media/libaudiofoundation/AudioGain.cpp
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AudioGain"
+//#define LOG_NDEBUG 0
+
+//#define VERY_VERBOSE_LOGGING
+#ifdef VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
+
+#include <algorithm>
+
+#include <android-base/stringprintf.h>
+#include <media/AudioGain.h>
+#include <utils/Log.h>
+
+#include <math.h>
+
+namespace android {
+
+AudioGain::AudioGain(int index, bool useInChannelMask)
+{
+ mIndex = index;
+ mUseInChannelMask = useInChannelMask;
+ memset(&mGain, 0, sizeof(struct audio_gain));
+}
+
+void AudioGain::getDefaultConfig(struct audio_gain_config *config)
+{
+ config->index = mIndex;
+ config->mode = mGain.mode;
+ config->channel_mask = mGain.channel_mask;
+ if ((mGain.mode & AUDIO_GAIN_MODE_JOINT) == AUDIO_GAIN_MODE_JOINT) {
+ config->values[0] = mGain.default_value;
+ } else {
+ uint32_t numValues;
+ if (mUseInChannelMask) {
+ numValues = audio_channel_count_from_in_mask(mGain.channel_mask);
+ } else {
+ numValues = audio_channel_count_from_out_mask(mGain.channel_mask);
+ }
+ for (size_t i = 0; i < numValues; i++) {
+ config->values[i] = mGain.default_value;
+ }
+ }
+ if ((mGain.mode & AUDIO_GAIN_MODE_RAMP) == AUDIO_GAIN_MODE_RAMP) {
+ config->ramp_duration_ms = mGain.min_ramp_ms;
+ }
+}
+
+status_t AudioGain::checkConfig(const struct audio_gain_config *config)
+{
+ if ((config->mode & ~mGain.mode) != 0) {
+ return BAD_VALUE;
+ }
+ if ((config->mode & AUDIO_GAIN_MODE_JOINT) == AUDIO_GAIN_MODE_JOINT) {
+ if ((config->values[0] < mGain.min_value) ||
+ (config->values[0] > mGain.max_value)) {
+ return BAD_VALUE;
+ }
+ } else {
+ if ((config->channel_mask & ~mGain.channel_mask) != 0) {
+ return BAD_VALUE;
+ }
+ uint32_t numValues;
+ if (mUseInChannelMask) {
+ numValues = audio_channel_count_from_in_mask(config->channel_mask);
+ } else {
+ numValues = audio_channel_count_from_out_mask(config->channel_mask);
+ }
+ for (size_t i = 0; i < numValues; i++) {
+ if ((config->values[i] < mGain.min_value) ||
+ (config->values[i] > mGain.max_value)) {
+ return BAD_VALUE;
+ }
+ }
+ }
+ if ((config->mode & AUDIO_GAIN_MODE_RAMP) == AUDIO_GAIN_MODE_RAMP) {
+ if ((config->ramp_duration_ms < mGain.min_ramp_ms) ||
+ (config->ramp_duration_ms > mGain.max_ramp_ms)) {
+ return BAD_VALUE;
+ }
+ }
+ return NO_ERROR;
+}
+
+void AudioGain::dump(std::string *dst, int spaces, int index) const
+{
+ dst->append(base::StringPrintf("%*sGain %d:\n", spaces, "", index+1));
+ dst->append(base::StringPrintf("%*s- mode: %08x\n", spaces, "", mGain.mode));
+ dst->append(base::StringPrintf("%*s- channel_mask: %08x\n", spaces, "", mGain.channel_mask));
+ dst->append(base::StringPrintf("%*s- min_value: %d mB\n", spaces, "", mGain.min_value));
+ dst->append(base::StringPrintf("%*s- max_value: %d mB\n", spaces, "", mGain.max_value));
+ dst->append(base::StringPrintf("%*s- default_value: %d mB\n", spaces, "", mGain.default_value));
+ dst->append(base::StringPrintf("%*s- step_value: %d mB\n", spaces, "", mGain.step_value));
+ dst->append(base::StringPrintf("%*s- min_ramp_ms: %d ms\n", spaces, "", mGain.min_ramp_ms));
+ dst->append(base::StringPrintf("%*s- max_ramp_ms: %d ms\n", spaces, "", mGain.max_ramp_ms));
+}
+
+bool AudioGain::equals(const sp<AudioGain>& other) const
+{
+ return other != nullptr &&
+ mUseInChannelMask == other->mUseInChannelMask &&
+ mUseForVolume == other->mUseForVolume &&
+ // Compare audio gain
+ mGain.mode == other->mGain.mode &&
+ mGain.channel_mask == other->mGain.channel_mask &&
+ mGain.min_value == other->mGain.min_value &&
+ mGain.max_value == other->mGain.max_value &&
+ mGain.default_value == other->mGain.default_value &&
+ mGain.step_value == other->mGain.step_value &&
+ mGain.min_ramp_ms == other->mGain.min_ramp_ms &&
+ mGain.max_ramp_ms == other->mGain.max_ramp_ms;
+}
+
+status_t AudioGain::writeToParcel(android::Parcel *parcel) const
+{
+ status_t status = NO_ERROR;
+ if ((status = parcel->writeInt32(mIndex)) != NO_ERROR) return status;
+ if ((status = parcel->writeBool(mUseInChannelMask)) != NO_ERROR) return status;
+ if ((status = parcel->writeBool(mUseForVolume)) != NO_ERROR) return status;
+ if ((status = parcel->writeUint32(mGain.mode)) != NO_ERROR) return status;
+ if ((status = parcel->writeUint32(mGain.channel_mask)) != NO_ERROR) return status;
+ if ((status = parcel->writeInt32(mGain.min_value)) != NO_ERROR) return status;
+ if ((status = parcel->writeInt32(mGain.max_value)) != NO_ERROR) return status;
+ if ((status = parcel->writeInt32(mGain.default_value)) != NO_ERROR) return status;
+ if ((status = parcel->writeUint32(mGain.step_value)) != NO_ERROR) return status;
+ if ((status = parcel->writeUint32(mGain.min_ramp_ms)) != NO_ERROR) return status;
+ status = parcel->writeUint32(mGain.max_ramp_ms);
+ return status;
+}
+
+status_t AudioGain::readFromParcel(const android::Parcel *parcel)
+{
+ status_t status = NO_ERROR;
+ if ((status = parcel->readInt32(&mIndex)) != NO_ERROR) return status;
+ if ((status = parcel->readBool(&mUseInChannelMask)) != NO_ERROR) return status;
+ if ((status = parcel->readBool(&mUseForVolume)) != NO_ERROR) return status;
+ if ((status = parcel->readUint32(&mGain.mode)) != NO_ERROR) return status;
+ if ((status = parcel->readUint32(&mGain.channel_mask)) != NO_ERROR) return status;
+ if ((status = parcel->readInt32(&mGain.min_value)) != NO_ERROR) return status;
+ if ((status = parcel->readInt32(&mGain.max_value)) != NO_ERROR) return status;
+ if ((status = parcel->readInt32(&mGain.default_value)) != NO_ERROR) return status;
+ if ((status = parcel->readUint32(&mGain.step_value)) != NO_ERROR) return status;
+ if ((status = parcel->readUint32(&mGain.min_ramp_ms)) != NO_ERROR) return status;
+ status = parcel->readUint32(&mGain.max_ramp_ms);
+ return status;
+}
+
+bool AudioGains::equals(const AudioGains &other) const
+{
+ return std::equal(begin(), end(), other.begin(), other.end(),
+ [](const sp<AudioGain>& left, const sp<AudioGain>& right) {
+ return left->equals(right);
+ });
+}
+
+status_t AudioGains::writeToParcel(android::Parcel *parcel) const {
+ status_t status = NO_ERROR;
+ if ((status = parcel->writeVectorSize(*this)) != NO_ERROR) return status;
+ for (const auto &audioGain : *this) {
+ if ((status = parcel->writeParcelable(*audioGain)) != NO_ERROR) {
+ break;
+ }
+ }
+ return status;
+}
+
+status_t AudioGains::readFromParcel(const android::Parcel *parcel) {
+ status_t status = NO_ERROR;
+ this->clear();
+ if ((status = parcel->resizeOutVector(this)) != NO_ERROR) return status;
+ for (size_t i = 0; i < this->size(); i++) {
+ this->at(i) = new AudioGain(0, false);
+ if ((status = parcel->readParcelable(this->at(i).get())) != NO_ERROR) {
+ this->clear();
+ break;
+ }
+ }
+ return status;
+}
+
+} // namespace android
diff --git a/media/libaudiofoundation/AudioPort.cpp b/media/libaudiofoundation/AudioPort.cpp
new file mode 100644
index 0000000..f988690
--- /dev/null
+++ b/media/libaudiofoundation/AudioPort.cpp
@@ -0,0 +1,287 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "AudioPort"
+
+#include <algorithm>
+
+#include <android-base/stringprintf.h>
+#include <media/AudioPort.h>
+#include <utils/Log.h>
+
+namespace android {
+
+void AudioPort::importAudioPort(const sp<AudioPort>& port, bool force __unused)
+{
+ for (const auto& profileToImport : port->mProfiles) {
+ // Import only valid port, i.e. valid format, non empty rates and channels masks
+ if (!profileToImport->isValid()) {
+ continue;
+ }
+ if (std::find_if(mProfiles.begin(), mProfiles.end(),
+ [profileToImport](const auto &profile) {
+ return *profile == *profileToImport; }) == mProfiles.end()) {
+ addAudioProfile(profileToImport);
+ }
+ }
+}
+
+void AudioPort::toAudioPort(struct audio_port *port) const {
+ // TODO: update this function once audio_port structure reflects the new profile definition.
+ // For compatibility reason: flatening the AudioProfile into audio_port structure.
+ FormatSet flatenedFormats;
+ SampleRateSet flatenedRates;
+ ChannelMaskSet flatenedChannels;
+ for (const auto& profile : mProfiles) {
+ if (profile->isValid()) {
+ audio_format_t formatToExport = profile->getFormat();
+ const SampleRateSet &ratesToExport = profile->getSampleRates();
+ const ChannelMaskSet &channelsToExport = profile->getChannels();
+
+ flatenedFormats.insert(formatToExport);
+ flatenedRates.insert(ratesToExport.begin(), ratesToExport.end());
+ flatenedChannels.insert(channelsToExport.begin(), channelsToExport.end());
+
+ if (flatenedRates.size() > AUDIO_PORT_MAX_SAMPLING_RATES ||
+ flatenedChannels.size() > AUDIO_PORT_MAX_CHANNEL_MASKS ||
+ flatenedFormats.size() > AUDIO_PORT_MAX_FORMATS) {
+ ALOGE("%s: bailing out: cannot export profiles to port config", __func__);
+ return;
+ }
+ }
+ }
+ port->role = mRole;
+ port->type = mType;
+ strlcpy(port->name, mName.c_str(), AUDIO_PORT_MAX_NAME_LEN);
+ port->num_sample_rates = flatenedRates.size();
+ port->num_channel_masks = flatenedChannels.size();
+ port->num_formats = flatenedFormats.size();
+ std::copy(flatenedRates.begin(), flatenedRates.end(), port->sample_rates);
+ std::copy(flatenedChannels.begin(), flatenedChannels.end(), port->channel_masks);
+ std::copy(flatenedFormats.begin(), flatenedFormats.end(), port->formats);
+
+ ALOGV("AudioPort::toAudioPort() num gains %zu", mGains.size());
+
+ port->num_gains = std::min(mGains.size(), (size_t) AUDIO_PORT_MAX_GAINS);
+ for (size_t i = 0; i < port->num_gains; i++) {
+ port->gains[i] = mGains[i]->getGain();
+ }
+}
+
+void AudioPort::dump(std::string *dst, int spaces, bool verbose) const {
+ if (!mName.empty()) {
+ dst->append(base::StringPrintf("%*s- name: %s\n", spaces, "", mName.c_str()));
+ }
+ if (verbose) {
+ std::string profilesStr;
+ mProfiles.dump(&profilesStr, spaces);
+ dst->append(profilesStr);
+
+ if (mGains.size() != 0) {
+ dst->append(base::StringPrintf("%*s- gains:\n", spaces, ""));
+ for (size_t i = 0; i < mGains.size(); i++) {
+ std::string gainStr;
+ mGains[i]->dump(&gainStr, spaces + 2, i);
+ dst->append(gainStr);
+ }
+ }
+ }
+}
+
+void AudioPort::log(const char* indent) const
+{
+ ALOGI("%s Port[nm:%s, type:%d, role:%d]", indent, mName.c_str(), mType, mRole);
+}
+
+bool AudioPort::equals(const sp<AudioPort> &other) const
+{
+ return other != nullptr &&
+ mGains.equals(other->getGains()) &&
+ mName.compare(other->getName()) == 0 &&
+ mType == other->getType() &&
+ mRole == other->getRole() &&
+ mProfiles.equals(other->getAudioProfiles());
+}
+
+status_t AudioPort::writeToParcel(Parcel *parcel) const
+{
+ status_t status = NO_ERROR;
+ if ((status = parcel->writeUtf8AsUtf16(mName)) != NO_ERROR) return status;
+ if ((status = parcel->writeUint32(mType)) != NO_ERROR) return status;
+ if ((status = parcel->writeUint32(mRole)) != NO_ERROR) return status;
+ if ((status = parcel->writeParcelable(mProfiles)) != NO_ERROR) return status;
+ if ((status = parcel->writeParcelable(mGains)) != NO_ERROR) return status;
+ return status;
+}
+
+status_t AudioPort::readFromParcel(const Parcel *parcel)
+{
+ status_t status = NO_ERROR;
+ if ((status = parcel->readUtf8FromUtf16(&mName)) != NO_ERROR) return status;
+ static_assert(sizeof(mType) == sizeof(uint32_t));
+ if ((status = parcel->readUint32(reinterpret_cast<uint32_t*>(&mType))) != NO_ERROR) {
+ return status;
+ }
+ static_assert(sizeof(mRole) == sizeof(uint32_t));
+ if ((status = parcel->readUint32(reinterpret_cast<uint32_t*>(&mRole))) != NO_ERROR) {
+ return status;
+ }
+ mProfiles.clear();
+ if ((status = parcel->readParcelable(&mProfiles)) != NO_ERROR) return status;
+ mGains.clear();
+ if ((status = parcel->readParcelable(&mGains)) != NO_ERROR) return status;
+ return status;
+}
+
+// --- AudioPortConfig class implementation
+
+status_t AudioPortConfig::applyAudioPortConfig(
+ const struct audio_port_config *config,
+ struct audio_port_config *backupConfig __unused)
+{
+ if (config->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
+ mSamplingRate = config->sample_rate;
+ }
+ if (config->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
+ mChannelMask = config->channel_mask;
+ }
+ if (config->config_mask & AUDIO_PORT_CONFIG_FORMAT) {
+ mFormat = config->format;
+ }
+ if (config->config_mask & AUDIO_PORT_CONFIG_GAIN) {
+ mGain = config->gain;
+ }
+
+ return NO_ERROR;
+}
+
+namespace {
+
+template<typename T>
+void updateField(
+ const T& portConfigField, T audio_port_config::*port_config_field,
+ struct audio_port_config *dstConfig, const struct audio_port_config *srcConfig,
+ unsigned int configMask, T defaultValue)
+{
+ if (dstConfig->config_mask & configMask) {
+ if ((srcConfig != nullptr) && (srcConfig->config_mask & configMask)) {
+ dstConfig->*port_config_field = srcConfig->*port_config_field;
+ } else {
+ dstConfig->*port_config_field = portConfigField;
+ }
+ } else {
+ dstConfig->*port_config_field = defaultValue;
+ }
+}
+
+} // namespace
+
+void AudioPortConfig::toAudioPortConfig(
+ struct audio_port_config *dstConfig,
+ const struct audio_port_config *srcConfig) const
+{
+ updateField(mSamplingRate, &audio_port_config::sample_rate,
+ dstConfig, srcConfig, AUDIO_PORT_CONFIG_SAMPLE_RATE, 0u);
+ updateField(mChannelMask, &audio_port_config::channel_mask,
+ dstConfig, srcConfig, AUDIO_PORT_CONFIG_CHANNEL_MASK,
+ (audio_channel_mask_t)AUDIO_CHANNEL_NONE);
+ updateField(mFormat, &audio_port_config::format,
+ dstConfig, srcConfig, AUDIO_PORT_CONFIG_FORMAT, AUDIO_FORMAT_INVALID);
+ dstConfig->id = mId;
+
+ sp<AudioPort> audioport = getAudioPort();
+ if ((dstConfig->config_mask & AUDIO_PORT_CONFIG_GAIN) && audioport != NULL) {
+ dstConfig->gain = mGain;
+ if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_GAIN)
+ && audioport->checkGain(&srcConfig->gain, srcConfig->gain.index) == OK) {
+ dstConfig->gain = srcConfig->gain;
+ }
+ } else {
+ dstConfig->gain.index = -1;
+ }
+ if (dstConfig->gain.index != -1) {
+ dstConfig->config_mask |= AUDIO_PORT_CONFIG_GAIN;
+ } else {
+ dstConfig->config_mask &= ~AUDIO_PORT_CONFIG_GAIN;
+ }
+}
+
+bool AudioPortConfig::hasGainController(bool canUseForVolume) const
+{
+ sp<AudioPort> audioport = getAudioPort();
+ if (!audioport) {
+ return false;
+ }
+ return canUseForVolume ? audioport->getGains().canUseForVolume()
+ : audioport->getGains().size() > 0;
+}
+
+bool AudioPortConfig::equals(const sp<AudioPortConfig> &other) const
+{
+ return other != nullptr &&
+ mSamplingRate == other->getSamplingRate() &&
+ mFormat == other->getFormat() &&
+ mChannelMask == other->getChannelMask() &&
+ // Compare audio gain config
+ mGain.index == other->mGain.index &&
+ mGain.mode == other->mGain.mode &&
+ mGain.channel_mask == other->mGain.channel_mask &&
+ std::equal(std::begin(mGain.values), std::end(mGain.values),
+ std::begin(other->mGain.values)) &&
+ mGain.ramp_duration_ms == other->mGain.ramp_duration_ms;
+}
+
+status_t AudioPortConfig::writeToParcel(Parcel *parcel) const
+{
+ status_t status = NO_ERROR;
+ if ((status = parcel->writeUint32(mSamplingRate)) != NO_ERROR) return status;
+ if ((status = parcel->writeUint32(mFormat)) != NO_ERROR) return status;
+ if ((status = parcel->writeUint32(mChannelMask)) != NO_ERROR) return status;
+ if ((status = parcel->writeInt32(mId)) != NO_ERROR) return status;
+ // Write mGain to parcel.
+ if ((status = parcel->writeInt32(mGain.index)) != NO_ERROR) return status;
+ if ((status = parcel->writeUint32(mGain.mode)) != NO_ERROR) return status;
+ if ((status = parcel->writeUint32(mGain.channel_mask)) != NO_ERROR) return status;
+ if ((status = parcel->writeUint32(mGain.ramp_duration_ms)) != NO_ERROR) return status;
+ std::vector<int> values(std::begin(mGain.values), std::end(mGain.values));
+ if ((status = parcel->writeInt32Vector(values)) != NO_ERROR) return status;
+ return status;
+}
+
+status_t AudioPortConfig::readFromParcel(const Parcel *parcel)
+{
+ status_t status = NO_ERROR;
+ if ((status = parcel->readUint32(&mSamplingRate)) != NO_ERROR) return status;
+ static_assert(sizeof(mFormat) == sizeof(uint32_t));
+ if ((status = parcel->readUint32(reinterpret_cast<uint32_t*>(&mFormat))) != NO_ERROR) {
+ return status;
+ }
+ if ((status = parcel->readUint32(&mChannelMask)) != NO_ERROR) return status;
+ if ((status = parcel->readInt32(&mId)) != NO_ERROR) return status;
+ // Read mGain from parcel.
+ if ((status = parcel->readInt32(&mGain.index)) != NO_ERROR) return status;
+ if ((status = parcel->readUint32(&mGain.mode)) != NO_ERROR) return status;
+ if ((status = parcel->readUint32(&mGain.channel_mask)) != NO_ERROR) return status;
+ if ((status = parcel->readUint32(&mGain.ramp_duration_ms)) != NO_ERROR) return status;
+ std::vector<int> values;
+ if ((status = parcel->readInt32Vector(&values)) != NO_ERROR) return status;
+ if (values.size() != std::size(mGain.values)) {
+ return BAD_VALUE;
+ }
+ std::copy(values.begin(), values.end(), mGain.values);
+ return status;
+}
+
+} // namespace android
diff --git a/media/libaudiofoundation/AudioProfile.cpp b/media/libaudiofoundation/AudioProfile.cpp
new file mode 100644
index 0000000..91be346
--- /dev/null
+++ b/media/libaudiofoundation/AudioProfile.cpp
@@ -0,0 +1,307 @@
+/*
+ * 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.
+ */
+
+#include <set>
+
+#define LOG_TAG "AudioProfile"
+//#define LOG_NDEBUG 0
+
+#include <android-base/stringprintf.h>
+#include <media/AudioContainers.h>
+#include <media/AudioProfile.h>
+#include <media/TypeConverter.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+bool operator == (const AudioProfile &left, const AudioProfile &right)
+{
+ return (left.getFormat() == right.getFormat()) &&
+ (left.getChannels() == right.getChannels()) &&
+ (left.getSampleRates() == right.getSampleRates());
+}
+
+// static
+sp<AudioProfile> AudioProfile::createFullDynamic(audio_format_t dynamicFormat)
+{
+ AudioProfile* dynamicProfile = new AudioProfile(dynamicFormat,
+ ChannelMaskSet(), SampleRateSet());
+ dynamicProfile->setDynamicFormat(true);
+ dynamicProfile->setDynamicChannels(true);
+ dynamicProfile->setDynamicRate(true);
+ return dynamicProfile;
+}
+
+AudioProfile::AudioProfile(audio_format_t format,
+ audio_channel_mask_t channelMasks,
+ uint32_t samplingRate) :
+ mName(""),
+ mFormat(format)
+{
+ mChannelMasks.insert(channelMasks);
+ mSamplingRates.insert(samplingRate);
+}
+
+AudioProfile::AudioProfile(audio_format_t format,
+ const ChannelMaskSet &channelMasks,
+ const SampleRateSet &samplingRateCollection) :
+ mName(""),
+ mFormat(format),
+ mChannelMasks(channelMasks),
+ mSamplingRates(samplingRateCollection) {}
+
+void AudioProfile::setChannels(const ChannelMaskSet &channelMasks)
+{
+ if (mIsDynamicChannels) {
+ mChannelMasks = channelMasks;
+ }
+}
+
+void AudioProfile::setSampleRates(const SampleRateSet &sampleRates)
+{
+ if (mIsDynamicRate) {
+ mSamplingRates = sampleRates;
+ }
+}
+
+void AudioProfile::clear()
+{
+ if (mIsDynamicChannels) {
+ mChannelMasks.clear();
+ }
+ if (mIsDynamicRate) {
+ mSamplingRates.clear();
+ }
+}
+
+void AudioProfile::dump(std::string *dst, int spaces) const
+{
+ dst->append(base::StringPrintf("%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "",
+ mIsDynamicChannels ? "[dynamic channels]" : "",
+ mIsDynamicRate ? "[dynamic rates]" : ""));
+ if (mName.length() != 0) {
+ dst->append(base::StringPrintf("%*s- name: %s\n", spaces, "", mName.c_str()));
+ }
+ std::string formatLiteral;
+ if (FormatConverter::toString(mFormat, formatLiteral)) {
+ dst->append(base::StringPrintf("%*s- format: %s\n", spaces, "", formatLiteral.c_str()));
+ }
+ if (!mSamplingRates.empty()) {
+ dst->append(base::StringPrintf("%*s- sampling rates:", spaces, ""));
+ for (auto it = mSamplingRates.begin(); it != mSamplingRates.end();) {
+ dst->append(base::StringPrintf("%d", *it));
+ dst->append(++it == mSamplingRates.end() ? "" : ", ");
+ }
+ dst->append("\n");
+ }
+
+ if (!mChannelMasks.empty()) {
+ dst->append(base::StringPrintf("%*s- channel masks:", spaces, ""));
+ for (auto it = mChannelMasks.begin(); it != mChannelMasks.end();) {
+ dst->append(base::StringPrintf("0x%04x", *it));
+ dst->append(++it == mChannelMasks.end() ? "" : ", ");
+ }
+ dst->append("\n");
+ }
+}
+
+bool AudioProfile::equals(const sp<AudioProfile>& other) const
+{
+ return other != nullptr &&
+ mName.compare(other->mName) == 0 &&
+ mFormat == other->getFormat() &&
+ mChannelMasks == other->getChannels() &&
+ mSamplingRates == other->getSampleRates() &&
+ mIsDynamicFormat == other->isDynamicFormat() &&
+ mIsDynamicChannels == other->isDynamicChannels() &&
+ mIsDynamicRate == other->isDynamicRate();
+}
+
+status_t AudioProfile::writeToParcel(Parcel *parcel) const
+{
+ status_t status = NO_ERROR;
+ if ((status = parcel->writeUtf8AsUtf16(mName)) != NO_ERROR) return status;
+ if ((status = parcel->writeUint32(mFormat)) != NO_ERROR) return status;
+ std::vector<int> values(mChannelMasks.begin(), mChannelMasks.end());
+ if ((status = parcel->writeInt32Vector(values)) != NO_ERROR) return status;
+ values.clear();
+ values.assign(mSamplingRates.begin(), mSamplingRates.end());
+ if ((status = parcel->writeInt32Vector(values)) != NO_ERROR) return status;
+ if ((status = parcel->writeBool(mIsDynamicFormat)) != NO_ERROR) return status;
+ if ((status = parcel->writeBool(mIsDynamicChannels)) != NO_ERROR) return status;
+ if ((status = parcel->writeBool(mIsDynamicRate)) != NO_ERROR) return status;
+ return status;
+}
+
+status_t AudioProfile::readFromParcel(const Parcel *parcel)
+{
+ status_t status = NO_ERROR;
+ if ((status = parcel->readUtf8FromUtf16(&mName)) != NO_ERROR) return status;
+ static_assert(sizeof(mFormat) == sizeof(uint32_t));
+ if ((status = parcel->readUint32(reinterpret_cast<uint32_t*>(&mFormat))) != NO_ERROR) {
+ return status;
+ }
+ std::vector<int> values;
+ if ((status = parcel->readInt32Vector(&values)) != NO_ERROR) return status;
+ mChannelMasks.clear();
+ mChannelMasks.insert(values.begin(), values.end());
+ values.clear();
+ if ((status = parcel->readInt32Vector(&values)) != NO_ERROR) return status;
+ mSamplingRates.clear();
+ mSamplingRates.insert(values.begin(), values.end());
+ if ((status = parcel->readBool(&mIsDynamicFormat)) != NO_ERROR) return status;
+ if ((status = parcel->readBool(&mIsDynamicChannels)) != NO_ERROR) return status;
+ if ((status = parcel->readBool(&mIsDynamicRate)) != NO_ERROR) return status;
+ return status;
+}
+
+ssize_t AudioProfileVector::add(const sp<AudioProfile> &profile)
+{
+ ssize_t index = size();
+ push_back(profile);
+ return index;
+}
+
+void AudioProfileVector::clearProfiles()
+{
+ for (auto it = begin(); it != end();) {
+ if ((*it)->isDynamicFormat() && (*it)->hasValidFormat()) {
+ it = erase(it);
+ } else {
+ (*it)->clear();
+ ++it;
+ }
+ }
+}
+
+sp<AudioProfile> AudioProfileVector::getFirstValidProfile() const
+{
+ for (const auto &profile : *this) {
+ if (profile->isValid()) {
+ return profile;
+ }
+ }
+ return nullptr;
+}
+
+sp<AudioProfile> AudioProfileVector::getFirstValidProfileFor(audio_format_t format) const
+{
+ for (const auto &profile : *this) {
+ if (profile->isValid() && profile->getFormat() == format) {
+ return profile;
+ }
+ }
+ return nullptr;
+}
+
+FormatVector AudioProfileVector::getSupportedFormats() const
+{
+ FormatVector supportedFormats;
+ for (const auto &profile : *this) {
+ if (profile->hasValidFormat()) {
+ supportedFormats.push_back(profile->getFormat());
+ }
+ }
+ return supportedFormats;
+}
+
+bool AudioProfileVector::hasDynamicChannelsFor(audio_format_t format) const
+{
+ for (const auto &profile : *this) {
+ if (profile->getFormat() == format && profile->isDynamicChannels()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AudioProfileVector::hasDynamicFormat() const
+{
+ for (const auto &profile : *this) {
+ if (profile->isDynamicFormat()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AudioProfileVector::hasDynamicProfile() const
+{
+ for (const auto &profile : *this) {
+ if (profile->isDynamic()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AudioProfileVector::hasDynamicRateFor(audio_format_t format) const
+{
+ for (const auto &profile : *this) {
+ if (profile->getFormat() == format && profile->isDynamicRate()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void AudioProfileVector::dump(std::string *dst, int spaces) const
+{
+ dst->append(base::StringPrintf("%*s- Profiles:\n", spaces, ""));
+ for (size_t i = 0; i < size(); i++) {
+ dst->append(base::StringPrintf("%*sProfile %zu:", spaces + 4, "", i));
+ std::string profileStr;
+ at(i)->dump(&profileStr, spaces + 8);
+ dst->append(profileStr);
+ }
+}
+
+status_t AudioProfileVector::writeToParcel(Parcel *parcel) const
+{
+ status_t status = NO_ERROR;
+ if ((status = parcel->writeVectorSize(*this)) != NO_ERROR) return status;
+ for (const auto &audioProfile : *this) {
+ if ((status = parcel->writeParcelable(*audioProfile)) != NO_ERROR) {
+ break;
+ }
+ }
+ return status;
+}
+
+status_t AudioProfileVector::readFromParcel(const Parcel *parcel)
+{
+ status_t status = NO_ERROR;
+ this->clear();
+ if ((status = parcel->resizeOutVector(this)) != NO_ERROR) return status;
+ for (size_t i = 0; i < this->size(); ++i) {
+ this->at(i) = new AudioProfile(AUDIO_FORMAT_DEFAULT, AUDIO_CHANNEL_NONE, 0 /*sampleRate*/);
+ if ((status = parcel->readParcelable(this->at(i).get())) != NO_ERROR) {
+ this->clear();
+ break;
+ }
+ }
+ return status;
+}
+
+bool AudioProfileVector::equals(const AudioProfileVector& other) const
+{
+ return std::equal(begin(), end(), other.begin(), other.end(),
+ [](const sp<AudioProfile>& left, const sp<AudioProfile>& right) {
+ return left->equals(right);
+ });
+}
+
+} // namespace android
diff --git a/media/libaudiofoundation/DeviceDescriptorBase.cpp b/media/libaudiofoundation/DeviceDescriptorBase.cpp
new file mode 100644
index 0000000..ef7576e
--- /dev/null
+++ b/media/libaudiofoundation/DeviceDescriptorBase.cpp
@@ -0,0 +1,171 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "DeviceDescriptorBase"
+//#define LOG_NDEBUG 0
+
+#include <android-base/stringprintf.h>
+#include <audio_utils/string.h>
+#include <media/DeviceDescriptorBase.h>
+#include <media/TypeConverter.h>
+
+namespace android {
+
+DeviceDescriptorBase::DeviceDescriptorBase(audio_devices_t type) :
+ DeviceDescriptorBase(type, "")
+{
+}
+
+DeviceDescriptorBase::DeviceDescriptorBase(audio_devices_t type, const std::string& address) :
+ DeviceDescriptorBase(AudioDeviceTypeAddr(type, address))
+{
+}
+
+DeviceDescriptorBase::DeviceDescriptorBase(const AudioDeviceTypeAddr &deviceTypeAddr) :
+ AudioPort("", AUDIO_PORT_TYPE_DEVICE,
+ audio_is_output_device(deviceTypeAddr.mType) ? AUDIO_PORT_ROLE_SINK :
+ AUDIO_PORT_ROLE_SOURCE),
+ mDeviceTypeAddr(deviceTypeAddr)
+{
+ if (mDeviceTypeAddr.mAddress.empty() && audio_is_remote_submix_device(mDeviceTypeAddr.mType)) {
+ mDeviceTypeAddr.mAddress = "0";
+ }
+}
+
+void DeviceDescriptorBase::toAudioPortConfig(struct audio_port_config *dstConfig,
+ const struct audio_port_config *srcConfig) const
+{
+ dstConfig->config_mask = AUDIO_PORT_CONFIG_GAIN;
+ if (mSamplingRate != 0) {
+ dstConfig->config_mask |= AUDIO_PORT_CONFIG_SAMPLE_RATE;
+ }
+ if (mChannelMask != AUDIO_CHANNEL_NONE) {
+ dstConfig->config_mask |= AUDIO_PORT_CONFIG_CHANNEL_MASK;
+ }
+ if (mFormat != AUDIO_FORMAT_INVALID) {
+ dstConfig->config_mask |= AUDIO_PORT_CONFIG_FORMAT;
+ }
+
+ if (srcConfig != NULL) {
+ dstConfig->config_mask |= srcConfig->config_mask;
+ }
+
+ AudioPortConfig::toAudioPortConfig(dstConfig, srcConfig);
+
+ dstConfig->role = audio_is_output_device(mDeviceTypeAddr.mType) ?
+ AUDIO_PORT_ROLE_SINK : AUDIO_PORT_ROLE_SOURCE;
+ dstConfig->type = AUDIO_PORT_TYPE_DEVICE;
+ dstConfig->ext.device.type = mDeviceTypeAddr.mType;
+
+ (void)audio_utils_strlcpy_zerofill(dstConfig->ext.device.address, mDeviceTypeAddr.getAddress());
+}
+
+void DeviceDescriptorBase::toAudioPort(struct audio_port *port) const
+{
+ ALOGV("DeviceDescriptorBase::toAudioPort() handle %d type %08x", mId, mDeviceTypeAddr.mType);
+ AudioPort::toAudioPort(port);
+ toAudioPortConfig(&port->active_config);
+ port->id = mId;
+ port->ext.device.type = mDeviceTypeAddr.mType;
+ (void)audio_utils_strlcpy_zerofill(port->ext.device.address, mDeviceTypeAddr.getAddress());
+}
+
+void DeviceDescriptorBase::dump(std::string *dst, int spaces, int index,
+ const char* extraInfo, bool verbose) const
+{
+ dst->append(base::StringPrintf("%*sDevice %d:\n", spaces, "", index + 1));
+ if (mId != 0) {
+ dst->append(base::StringPrintf("%*s- id: %2d\n", spaces, "", mId));
+ }
+
+ if (extraInfo != nullptr) {
+ dst->append(extraInfo);
+ }
+
+ dst->append(base::StringPrintf("%*s- type: %-48s\n",
+ spaces, "", ::android::toString(mDeviceTypeAddr.mType).c_str()));
+
+ if (mDeviceTypeAddr.mAddress.size() != 0) {
+ dst->append(base::StringPrintf(
+ "%*s- address: %-32s\n", spaces, "", mDeviceTypeAddr.getAddress()));
+ }
+ AudioPort::dump(dst, spaces, verbose);
+}
+
+std::string DeviceDescriptorBase::toString() const
+{
+ std::stringstream sstream;
+ sstream << "type:0x" << std::hex << type() << ",@:" << mDeviceTypeAddr.mAddress;
+ return sstream.str();
+}
+
+void DeviceDescriptorBase::log() const
+{
+ ALOGI("Device id:%d type:0x%08X:%s, addr:%s", mId, mDeviceTypeAddr.mType,
+ ::android::toString(mDeviceTypeAddr.mType).c_str(),
+ mDeviceTypeAddr.getAddress());
+
+ AudioPort::log(" ");
+}
+
+bool DeviceDescriptorBase::equals(const sp<DeviceDescriptorBase> &other) const
+{
+ return other != nullptr &&
+ static_cast<const AudioPort*>(this)->equals(other) &&
+ static_cast<const AudioPortConfig*>(this)->equals(other) &&
+ mDeviceTypeAddr.equals(other->mDeviceTypeAddr);
+}
+
+status_t DeviceDescriptorBase::writeToParcel(Parcel *parcel) const
+{
+ status_t status = NO_ERROR;
+ if ((status = AudioPort::writeToParcel(parcel)) != NO_ERROR) return status;
+ if ((status = AudioPortConfig::writeToParcel(parcel)) != NO_ERROR) return status;
+ if ((status = parcel->writeParcelable(mDeviceTypeAddr)) != NO_ERROR) return status;
+ return status;
+}
+
+status_t DeviceDescriptorBase::readFromParcel(const Parcel *parcel)
+{
+ status_t status = NO_ERROR;
+ if ((status = AudioPort::readFromParcel(parcel)) != NO_ERROR) return status;
+ if ((status = AudioPortConfig::readFromParcel(parcel)) != NO_ERROR) return status;
+ if ((status = parcel->readParcelable(&mDeviceTypeAddr)) != NO_ERROR) return status;
+ return status;
+}
+
+std::string toString(const DeviceDescriptorBaseVector& devices)
+{
+ std::string ret;
+ for (const auto& device : devices) {
+ if (device != *devices.begin()) {
+ ret += ";";
+ }
+ ret += device->toString();
+ }
+ return ret;
+}
+
+AudioDeviceTypeAddrVector deviceTypeAddrsFromDescriptors(const DeviceDescriptorBaseVector& devices)
+{
+ AudioDeviceTypeAddrVector deviceTypeAddrs;
+ for (const auto& device : devices) {
+ deviceTypeAddrs.push_back(device->getDeviceTypeAddr());
+ }
+ return deviceTypeAddrs;
+}
+
+} // namespace android
diff --git a/media/libaudiofoundation/TEST_MAPPING b/media/libaudiofoundation/TEST_MAPPING
new file mode 100644
index 0000000..f6d249a
--- /dev/null
+++ b/media/libaudiofoundation/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "audiofoundation_parcelable_test"
+ }
+ ]
+}
diff --git a/media/libaudiofoundation/include/media/AudioContainers.h b/media/libaudiofoundation/include/media/AudioContainers.h
new file mode 100644
index 0000000..72fda49
--- /dev/null
+++ b/media/libaudiofoundation/include/media/AudioContainers.h
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <functional>
+#include <iterator>
+#include <set>
+#include <vector>
+
+#include <media/TypeConverter.h>
+#include <system/audio.h>
+
+namespace android {
+
+using ChannelMaskSet = std::set<audio_channel_mask_t>;
+using DeviceTypeSet = std::set<audio_devices_t>;
+using FormatSet = std::set<audio_format_t>;
+using SampleRateSet = std::set<uint32_t>;
+
+using FormatVector = std::vector<audio_format_t>;
+
+const DeviceTypeSet& getAudioDeviceOutAllSet();
+const DeviceTypeSet& getAudioDeviceOutAllA2dpSet();
+const DeviceTypeSet& getAudioDeviceOutAllScoSet();
+const DeviceTypeSet& getAudioDeviceOutAllUsbSet();
+const DeviceTypeSet& getAudioDeviceInAllSet();
+const DeviceTypeSet& getAudioDeviceInAllUsbSet();
+
+template<typename T>
+static std::vector<T> Intersection(const std::set<T>& a, const std::set<T>& b) {
+ std::vector<T> intersection;
+ std::set_intersection(a.begin(), a.end(),
+ b.begin(), b.end(),
+ std::back_inserter(intersection));
+ return intersection;
+}
+
+static inline ChannelMaskSet asInMask(const ChannelMaskSet& channelMasks) {
+ ChannelMaskSet inMaskSet;
+ for (const auto &channel : channelMasks) {
+ if (audio_channel_mask_out_to_in(channel) != AUDIO_CHANNEL_INVALID) {
+ inMaskSet.insert(audio_channel_mask_out_to_in(channel));
+ }
+ }
+ return inMaskSet;
+}
+
+static inline ChannelMaskSet asOutMask(const ChannelMaskSet& channelMasks) {
+ ChannelMaskSet outMaskSet;
+ for (const auto &channel : channelMasks) {
+ if (audio_channel_mask_in_to_out(channel) != AUDIO_CHANNEL_INVALID) {
+ outMaskSet.insert(audio_channel_mask_in_to_out(channel));
+ }
+ }
+ return outMaskSet;
+}
+
+static inline bool isSingleDeviceType(const DeviceTypeSet& deviceTypes,
+ audio_devices_t deviceType) {
+ return deviceTypes.size() == 1 && *(deviceTypes.begin()) == deviceType;
+}
+
+typedef bool (*DeviceTypeUnaryPredicate)(audio_devices_t);
+static inline bool isSingleDeviceType(const DeviceTypeSet& deviceTypes,
+ DeviceTypeUnaryPredicate p) {
+ return deviceTypes.size() == 1 && p(*(deviceTypes.begin()));
+}
+
+static inline bool areAllOfSameDeviceType(const DeviceTypeSet& deviceTypes,
+ std::function<bool(audio_devices_t)> p) {
+ return std::all_of(deviceTypes.begin(), deviceTypes.end(), p);
+}
+
+static inline void resetDeviceTypes(DeviceTypeSet& deviceTypes, audio_devices_t typeToAdd) {
+ deviceTypes.clear();
+ deviceTypes.insert(typeToAdd);
+}
+
+// FIXME: This is temporary helper function. Remove this when getting rid of all
+// bit mask usages of audio device types.
+static inline audio_devices_t deviceTypesToBitMask(const DeviceTypeSet& deviceTypes) {
+ audio_devices_t types = AUDIO_DEVICE_NONE;
+ for (auto deviceType : deviceTypes) {
+ types |= deviceType;
+ }
+ return types;
+}
+
+// FIXME: This is temporary helper function. Remove this when getting rid of all
+// bit mask usages of audio device types.
+static inline DeviceTypeSet deviceTypesFromBitMask(audio_devices_t types) {
+ DeviceTypeSet deviceTypes;
+ if ((types & AUDIO_DEVICE_BIT_IN) == 0) {
+ for (auto deviceType : AUDIO_DEVICE_OUT_ALL_ARRAY) {
+ if ((types & deviceType) == deviceType) {
+ deviceTypes.insert(deviceType);
+ }
+ }
+ } else {
+ for (auto deviceType : AUDIO_DEVICE_IN_ALL_ARRAY) {
+ if ((types & deviceType) == deviceType) {
+ deviceTypes.insert(deviceType);
+ }
+ }
+ }
+ return deviceTypes;
+}
+
+bool deviceTypesToString(const DeviceTypeSet& deviceTypes, std::string &str);
+
+std::string dumpDeviceTypes(const DeviceTypeSet& deviceTypes);
+
+/**
+ * Return human readable string for device types.
+ */
+std::string toString(const DeviceTypeSet& deviceTypes);
+
+
+} // namespace android
\ No newline at end of file
diff --git a/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h b/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h
new file mode 100644
index 0000000..60ea78e
--- /dev/null
+++ b/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include <binder/Parcelable.h>
+#include <binder/Parcel.h>
+#include <media/AudioContainers.h>
+#include <system/audio.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+struct AudioDeviceTypeAddr : public Parcelable {
+ AudioDeviceTypeAddr() = default;
+
+ AudioDeviceTypeAddr(audio_devices_t type, const std::string& address) :
+ mType(type), mAddress(address) {}
+
+ const char* getAddress() const;
+
+ bool equals(const AudioDeviceTypeAddr& other) const;
+
+ AudioDeviceTypeAddr& operator= (const AudioDeviceTypeAddr&) = default;
+
+ bool operator<(const AudioDeviceTypeAddr& other) const;
+
+ void reset();
+
+ status_t readFromParcel(const Parcel *parcel) override;
+
+ status_t writeToParcel(Parcel *parcel) const override;
+
+ audio_devices_t mType = AUDIO_DEVICE_NONE;
+ std::string mAddress;
+};
+
+using AudioDeviceTypeAddrVector = std::vector<AudioDeviceTypeAddr>;
+
+/**
+ * Return a collection of audio device types from a collection of AudioDeviceTypeAddr
+ */
+DeviceTypeSet getAudioDeviceTypes(const AudioDeviceTypeAddrVector& deviceTypeAddrs);
+
+}
diff --git a/media/libaudiofoundation/include/media/AudioGain.h b/media/libaudiofoundation/include/media/AudioGain.h
new file mode 100644
index 0000000..859f1e7
--- /dev/null
+++ b/media/libaudiofoundation/include/media/AudioGain.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <system/audio.h>
+#include <string>
+#include <vector>
+
+namespace android {
+
+class AudioGain: public RefBase, public Parcelable
+{
+public:
+ AudioGain(int index, bool useInChannelMask);
+ virtual ~AudioGain() {}
+
+ void setMode(audio_gain_mode_t mode) { mGain.mode = mode; }
+ const audio_gain_mode_t &getMode() const { return mGain.mode; }
+
+ void setChannelMask(audio_channel_mask_t mask) { mGain.channel_mask = mask; }
+ const audio_channel_mask_t &getChannelMask() const { return mGain.channel_mask; }
+
+ void setMinValueInMb(int minValue) { mGain.min_value = minValue; }
+ int getMinValueInMb() const { return mGain.min_value; }
+
+ void setMaxValueInMb(int maxValue) { mGain.max_value = maxValue; }
+ int getMaxValueInMb() const { return mGain.max_value; }
+
+ void setDefaultValueInMb(int defaultValue) { mGain.default_value = defaultValue; }
+ int getDefaultValueInMb() const { return mGain.default_value; }
+
+ void setStepValueInMb(uint32_t stepValue) { mGain.step_value = stepValue; }
+ int getStepValueInMb() const { return mGain.step_value; }
+
+ void setMinRampInMs(uint32_t minRamp) { mGain.min_ramp_ms = minRamp; }
+ int getMinRampInMs() const { return mGain.min_ramp_ms; }
+
+ void setMaxRampInMs(uint32_t maxRamp) { mGain.max_ramp_ms = maxRamp; }
+ int getMaxRampInMs() const { return mGain.max_ramp_ms; }
+
+ // TODO: remove dump from here (split serialization)
+ void dump(std::string *dst, int spaces, int index) const;
+
+ void getDefaultConfig(struct audio_gain_config *config);
+ status_t checkConfig(const struct audio_gain_config *config);
+
+ void setUseForVolume(bool canUseForVolume) { mUseForVolume = canUseForVolume; }
+ bool canUseForVolume() const { return mUseForVolume; }
+
+ const struct audio_gain &getGain() const { return mGain; }
+
+ bool equals(const sp<AudioGain>& other) const;
+
+ status_t writeToParcel(Parcel* parcel) const override;
+ status_t readFromParcel(const Parcel* parcel) override;
+
+private:
+ int mIndex;
+ struct audio_gain mGain;
+ bool mUseInChannelMask;
+ bool mUseForVolume = false;
+};
+
+class AudioGains : public std::vector<sp<AudioGain> >, public Parcelable
+{
+public:
+ bool canUseForVolume() const
+ {
+ for (const auto &gain: *this) {
+ if (gain->canUseForVolume()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ int32_t add(const sp<AudioGain> gain)
+ {
+ push_back(gain);
+ return 0;
+ }
+
+ bool equals(const AudioGains& other) const;
+
+ status_t writeToParcel(Parcel* parcel) const override;
+ status_t readFromParcel(const Parcel* parcel) override;
+};
+
+} // namespace android
diff --git a/media/libaudiofoundation/include/media/AudioPort.h b/media/libaudiofoundation/include/media/AudioPort.h
new file mode 100644
index 0000000..3c013cb
--- /dev/null
+++ b/media/libaudiofoundation/include/media/AudioPort.h
@@ -0,0 +1,131 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <media/AudioGain.h>
+#include <media/AudioProfile.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <system/audio.h>
+#include <cutils/config_utils.h>
+
+namespace android {
+
+class AudioPort : public virtual RefBase, public virtual Parcelable
+{
+public:
+ AudioPort(const std::string& name, audio_port_type_t type, audio_port_role_t role) :
+ mName(name), mType(type), mRole(role) {}
+
+ virtual ~AudioPort() = default;
+
+ void setName(const std::string &name) { mName = name; }
+ const std::string &getName() const { return mName; }
+
+ audio_port_type_t getType() const { return mType; }
+ audio_port_role_t getRole() const { return mRole; }
+
+ void setGains(const AudioGains &gains) { mGains = gains; }
+ const AudioGains &getGains() const { return mGains; }
+
+ virtual void toAudioPort(struct audio_port *port) const;
+
+ virtual void addAudioProfile(const sp<AudioProfile> &profile) {
+ mProfiles.add(profile);
+ }
+ virtual void clearAudioProfiles() {
+ mProfiles.clearProfiles();
+ }
+
+ bool hasValidAudioProfile() const { return mProfiles.hasValidProfile(); }
+
+ bool hasDynamicAudioProfile() const { return mProfiles.hasDynamicProfile(); }
+
+ void setAudioProfiles(const AudioProfileVector &profiles) { mProfiles = profiles; }
+ AudioProfileVector &getAudioProfiles() { return mProfiles; }
+
+ virtual void importAudioPort(const sp<AudioPort>& port, bool force = false);
+
+ status_t checkGain(const struct audio_gain_config *gainConfig, int index) const {
+ if (index < 0 || (size_t)index >= mGains.size()) {
+ return BAD_VALUE;
+ }
+ return mGains[index]->checkConfig(gainConfig);
+ }
+
+ bool useInputChannelMask() const
+ {
+ return ((mType == AUDIO_PORT_TYPE_DEVICE) && (mRole == AUDIO_PORT_ROLE_SOURCE)) ||
+ ((mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SINK));
+ }
+
+ void dump(std::string *dst, int spaces, bool verbose = true) const;
+
+ void log(const char* indent) const;
+
+ bool equals(const sp<AudioPort>& other) const;
+
+ status_t writeToParcel(Parcel* parcel) const override;
+ status_t readFromParcel(const Parcel* parcel) override;
+
+ AudioGains mGains; // gain controllers
+protected:
+ std::string mName;
+ audio_port_type_t mType;
+ audio_port_role_t mRole;
+ AudioProfileVector mProfiles; // AudioProfiles supported by this port (format, Rates, Channels)
+};
+
+
+class AudioPortConfig : public virtual RefBase, public virtual Parcelable
+{
+public:
+ virtual ~AudioPortConfig() = default;
+
+ virtual sp<AudioPort> getAudioPort() const = 0;
+
+ virtual status_t applyAudioPortConfig(const struct audio_port_config *config,
+ struct audio_port_config *backupConfig = NULL);
+
+ virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
+ const struct audio_port_config *srcConfig = NULL) const;
+
+ unsigned int getSamplingRate() const { return mSamplingRate; }
+ audio_format_t getFormat() const { return mFormat; }
+ audio_channel_mask_t getChannelMask() const { return mChannelMask; }
+ audio_port_handle_t getId() const { return mId; }
+
+ bool hasGainController(bool canUseForVolume = false) const;
+
+ bool equals(const sp<AudioPortConfig>& other) const;
+
+ status_t writeToParcel(Parcel* parcel) const override;
+ status_t readFromParcel(const Parcel* parcel) override;
+
+protected:
+ unsigned int mSamplingRate = 0u;
+ audio_format_t mFormat = AUDIO_FORMAT_INVALID;
+ audio_channel_mask_t mChannelMask = AUDIO_CHANNEL_NONE;
+ audio_port_handle_t mId = AUDIO_PORT_HANDLE_NONE;
+ struct audio_gain_config mGain = { .index = -1 };
+};
+
+} // namespace android
diff --git a/media/libaudiofoundation/include/media/AudioProfile.h b/media/libaudiofoundation/include/media/AudioProfile.h
new file mode 100644
index 0000000..730138a
--- /dev/null
+++ b/media/libaudiofoundation/include/media/AudioProfile.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <media/AudioContainers.h>
+#include <system/audio.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+class AudioProfile final : public RefBase, public Parcelable
+{
+public:
+ static sp<AudioProfile> createFullDynamic(audio_format_t dynamicFormat = AUDIO_FORMAT_DEFAULT);
+
+ AudioProfile(audio_format_t format, audio_channel_mask_t channelMasks, uint32_t samplingRate);
+ AudioProfile(audio_format_t format,
+ const ChannelMaskSet &channelMasks,
+ const SampleRateSet &samplingRateCollection);
+
+ audio_format_t getFormat() const { return mFormat; }
+ const ChannelMaskSet &getChannels() const { return mChannelMasks; }
+ const SampleRateSet &getSampleRates() const { return mSamplingRates; }
+ void setChannels(const ChannelMaskSet &channelMasks);
+ void setSampleRates(const SampleRateSet &sampleRates);
+
+ void clear();
+ bool isValid() const { return hasValidFormat() && hasValidRates() && hasValidChannels(); }
+ bool supportsChannels(audio_channel_mask_t channels) const
+ {
+ return mChannelMasks.count(channels) != 0;
+ }
+ bool supportsRate(uint32_t rate) const { return mSamplingRates.count(rate) != 0; }
+
+ bool hasValidFormat() const { return mFormat != AUDIO_FORMAT_DEFAULT; }
+ bool hasValidRates() const { return !mSamplingRates.empty(); }
+ bool hasValidChannels() const { return !mChannelMasks.empty(); }
+
+ void setDynamicChannels(bool dynamic) { mIsDynamicChannels = dynamic; }
+ bool isDynamicChannels() const { return mIsDynamicChannels; }
+
+ void setDynamicRate(bool dynamic) { mIsDynamicRate = dynamic; }
+ bool isDynamicRate() const { return mIsDynamicRate; }
+
+ void setDynamicFormat(bool dynamic) { mIsDynamicFormat = dynamic; }
+ bool isDynamicFormat() const { return mIsDynamicFormat; }
+
+ bool isDynamic() { return mIsDynamicFormat || mIsDynamicChannels || mIsDynamicRate; }
+
+ void dump(std::string *dst, int spaces) const;
+
+ bool equals(const sp<AudioProfile>& other) const;
+
+ status_t writeToParcel(Parcel* parcel) const override;
+ status_t readFromParcel(const Parcel* parcel) override;
+
+private:
+ std::string mName;
+ audio_format_t mFormat; // The format for an audio profile should only be set when initialized.
+ ChannelMaskSet mChannelMasks;
+ SampleRateSet mSamplingRates;
+
+ bool mIsDynamicFormat = false;
+ bool mIsDynamicChannels = false;
+ bool mIsDynamicRate = false;
+};
+
+class AudioProfileVector : public std::vector<sp<AudioProfile>>, public Parcelable
+{
+public:
+ virtual ~AudioProfileVector() = default;
+
+ virtual ssize_t add(const sp<AudioProfile> &profile);
+
+ // If the profile is dynamic format and has valid format, it will be removed when doing
+ // clearProfiles(). Otherwise, AudioProfile::clear() will be called.
+ virtual void clearProfiles();
+
+ sp<AudioProfile> getFirstValidProfile() const;
+ sp<AudioProfile> getFirstValidProfileFor(audio_format_t format) const;
+ bool hasValidProfile() const { return getFirstValidProfile() != 0; }
+
+ FormatVector getSupportedFormats() const;
+ bool hasDynamicChannelsFor(audio_format_t format) const;
+ bool hasDynamicFormat() const;
+ bool hasDynamicProfile() const;
+ bool hasDynamicRateFor(audio_format_t format) const;
+
+ virtual void dump(std::string *dst, int spaces) const;
+
+ bool equals(const AudioProfileVector& other) const;
+
+ status_t writeToParcel(Parcel* parcel) const override;
+ status_t readFromParcel(const Parcel* parcel) override;
+};
+
+bool operator == (const AudioProfile &left, const AudioProfile &right);
+
+} // namespace android
diff --git a/media/libaudiofoundation/include/media/DeviceDescriptorBase.h b/media/libaudiofoundation/include/media/DeviceDescriptorBase.h
new file mode 100644
index 0000000..4c03667
--- /dev/null
+++ b/media/libaudiofoundation/include/media/DeviceDescriptorBase.h
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <vector>
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <media/AudioContainers.h>
+#include <media/AudioPort.h>
+#include <media/AudioDeviceTypeAddr.h>
+#include <utils/Errors.h>
+#include <cutils/config_utils.h>
+#include <system/audio.h>
+#include <system/audio_policy.h>
+
+namespace android {
+
+class DeviceDescriptorBase : public AudioPort, public AudioPortConfig
+{
+public:
+ // Note that empty name refers by convention to a generic device.
+ explicit DeviceDescriptorBase(audio_devices_t type);
+ DeviceDescriptorBase(audio_devices_t type, const std::string& address);
+ explicit DeviceDescriptorBase(const AudioDeviceTypeAddr& deviceTypeAddr);
+
+ virtual ~DeviceDescriptorBase() {}
+
+ audio_devices_t type() const { return mDeviceTypeAddr.mType; }
+ std::string address() const { return mDeviceTypeAddr.mAddress; }
+ void setAddress(const std::string &address) { mDeviceTypeAddr.mAddress = address; }
+ const AudioDeviceTypeAddr& getDeviceTypeAddr() const { return mDeviceTypeAddr; }
+
+ // AudioPortConfig
+ virtual sp<AudioPort> getAudioPort() const {
+ return static_cast<AudioPort*>(const_cast<DeviceDescriptorBase*>(this));
+ }
+ virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
+ const struct audio_port_config *srcConfig = NULL) const;
+
+ // AudioPort
+ virtual void toAudioPort(struct audio_port *port) const;
+
+ void dump(std::string *dst, int spaces, int index,
+ const char* extraInfo = nullptr, bool verbose = true) const;
+ void log() const;
+ std::string toString() const;
+
+ bool equals(const sp<DeviceDescriptorBase>& other) const;
+
+ status_t writeToParcel(Parcel* parcel) const override;
+ status_t readFromParcel(const Parcel* parcel) override;
+
+protected:
+ AudioDeviceTypeAddr mDeviceTypeAddr;
+};
+
+using DeviceDescriptorBaseVector = std::vector<sp<DeviceDescriptorBase>>;
+
+/**
+ * Return human readable string for collection of DeviceDescriptorBase.
+ * For a DeviceDescriptorBase, it contains port id, audio device type and address.
+ */
+std::string toString(const DeviceDescriptorBaseVector& devices);
+
+/**
+ * Return a set of device types and addresses from collection of DeviceDescriptorBase.
+ */
+AudioDeviceTypeAddrVector deviceTypeAddrsFromDescriptors(const DeviceDescriptorBaseVector& devices);
+
+} // namespace android
diff --git a/media/libaudiofoundation/tests/Android.bp b/media/libaudiofoundation/tests/Android.bp
new file mode 100644
index 0000000..f258b14
--- /dev/null
+++ b/media/libaudiofoundation/tests/Android.bp
@@ -0,0 +1,25 @@
+cc_test {
+ name: "audiofoundation_parcelable_test",
+
+ shared_libs: [
+ "libaudiofoundation",
+ "libbinder",
+ "liblog",
+ "libutils",
+ ],
+
+ header_libs: [
+ "libaudio_system_headers",
+ ],
+
+ srcs: [
+ "audiofoundation_parcelable_test.cpp",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ test_suites: ["device-tests"],
+}
diff --git a/media/libaudiofoundation/tests/audiofoundation_parcelable_test.cpp b/media/libaudiofoundation/tests/audiofoundation_parcelable_test.cpp
new file mode 100644
index 0000000..5baa072
--- /dev/null
+++ b/media/libaudiofoundation/tests/audiofoundation_parcelable_test.cpp
@@ -0,0 +1,142 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "audiofoundation_parcelable_test"
+
+#include <gtest/gtest.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/Parcelable.h>
+#include <binder/ProcessState.h>
+#include <media/AudioGain.h>
+#include <media/AudioPort.h>
+#include <media/AudioProfile.h>
+#include <media/DeviceDescriptorBase.h>
+#include <utils/Log.h>
+#include <utils/String16.h>
+
+namespace android {
+
+static const audio_port_config TEST_AUDIO_PORT_CONFIG = {
+ .id = 0,
+ .role = AUDIO_PORT_ROLE_SINK,
+ .type = AUDIO_PORT_TYPE_DEVICE,
+ .config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE | AUDIO_PORT_CONFIG_CHANNEL_MASK |
+ AUDIO_PORT_CONFIG_FORMAT | AUDIO_PORT_CONFIG_GAIN,
+ .sample_rate = 48000,
+ .channel_mask = AUDIO_CHANNEL_OUT_STEREO,
+ .format = AUDIO_FORMAT_PCM_16_BIT,
+ .gain = {
+ .index = 0,
+ .mode = AUDIO_GAIN_MODE_JOINT,
+ .channel_mask = AUDIO_CHANNEL_OUT_STEREO,
+ }
+};
+
+class AudioPortConfigTestStub : public AudioPortConfig {
+public:
+ sp<AudioPort> getAudioPort() const override { return nullptr; }
+};
+
+AudioGains getAudioGainsForTest() {
+ AudioGains audioGains;
+ sp<AudioGain> audioGain = new AudioGain(0 /*index*/, false /*useInChannelMask*/);
+ audioGain->setMode(AUDIO_GAIN_MODE_JOINT);
+ audioGain->setChannelMask(AUDIO_CHANNEL_OUT_STEREO);
+ audioGain->setMinValueInMb(-3200);
+ audioGain->setMaxValueInMb(600);
+ audioGain->setDefaultValueInMb(0);
+ audioGain->setStepValueInMb(100);
+ audioGain->setMinRampInMs(100);
+ audioGain->setMaxRampInMs(500);
+ audioGains.push_back(audioGain);
+ return audioGains;
+}
+
+AudioProfileVector getAudioProfileVectorForTest() {
+ AudioProfileVector audioProfiles;
+ sp<AudioProfile> audioProfile = AudioProfile::createFullDynamic();
+ audioProfile->setChannels({AUDIO_CHANNEL_OUT_MONO, AUDIO_CHANNEL_OUT_STEREO});
+ audioProfile->setSampleRates({48000});
+ audioProfiles.add(audioProfile);
+ return audioProfiles;
+}
+
+TEST(AudioFoundationParcelableTest, ParcelingAudioGain) {
+ Parcel data;
+ AudioGains audioGains = getAudioGainsForTest();
+
+ ASSERT_EQ(data.writeParcelable(audioGains), NO_ERROR);
+ data.setDataPosition(0);
+ AudioGains audioGainsFromParcel;
+ ASSERT_EQ(data.readParcelable(&audioGainsFromParcel), NO_ERROR);
+ ASSERT_TRUE(audioGainsFromParcel.equals(audioGains));
+}
+
+TEST(AudioFoundationParcelableTest, ParcelingAudioProfileVector) {
+ Parcel data;
+ AudioProfileVector audioProfiles = getAudioProfileVectorForTest();
+
+ ASSERT_EQ(data.writeParcelable(audioProfiles), NO_ERROR);
+ data.setDataPosition(0);
+ AudioProfileVector audioProfilesFromParcel;
+ ASSERT_EQ(data.readParcelable(&audioProfilesFromParcel), NO_ERROR);
+ ASSERT_TRUE(audioProfilesFromParcel.equals(audioProfiles));
+}
+
+TEST(AudioFoundationParcelableTest, ParcelingAudioPort) {
+ Parcel data;
+ sp<AudioPort> audioPort = new AudioPort(
+ "AudioPortName", AUDIO_PORT_TYPE_DEVICE, AUDIO_PORT_ROLE_SINK);
+ audioPort->setGains(getAudioGainsForTest());
+ audioPort->setAudioProfiles(getAudioProfileVectorForTest());
+
+ ASSERT_EQ(data.writeParcelable(*audioPort), NO_ERROR);
+ data.setDataPosition(0);
+ sp<AudioPort> audioPortFromParcel = new AudioPort(
+ "", AUDIO_PORT_TYPE_NONE, AUDIO_PORT_ROLE_NONE);
+ ASSERT_EQ(data.readParcelable(audioPortFromParcel.get()), NO_ERROR);
+ ASSERT_TRUE(audioPortFromParcel->equals(audioPort));
+}
+
+TEST(AudioFoundationParcelableTest, ParcelingAudioPortConfig) {
+ Parcel data;
+ sp<AudioPortConfig> audioPortConfig = new AudioPortConfigTestStub();
+ audioPortConfig->applyAudioPortConfig(&TEST_AUDIO_PORT_CONFIG);
+
+ ASSERT_EQ(data.writeParcelable(*audioPortConfig), NO_ERROR);
+ data.setDataPosition(0);
+ sp<AudioPortConfig> audioPortConfigFromParcel = new AudioPortConfigTestStub();
+ ASSERT_EQ(data.readParcelable(audioPortConfigFromParcel.get()), NO_ERROR);
+ ASSERT_TRUE(audioPortConfigFromParcel->equals(audioPortConfig));
+}
+
+TEST(AudioFoundationParcelableTest, ParcelingDeviceDescriptorBase) {
+ Parcel data;
+ sp<DeviceDescriptorBase> desc = new DeviceDescriptorBase(AUDIO_DEVICE_OUT_SPEAKER);
+ desc->setGains(getAudioGainsForTest());
+ desc->setAudioProfiles(getAudioProfileVectorForTest());
+ desc->applyAudioPortConfig(&TEST_AUDIO_PORT_CONFIG);
+ desc->setAddress("DeviceDescriptorBaseTestAddress");
+
+ ASSERT_EQ(data.writeParcelable(*desc), NO_ERROR);
+ data.setDataPosition(0);
+ sp<DeviceDescriptorBase> descFromParcel = new DeviceDescriptorBase(AUDIO_DEVICE_NONE);
+ ASSERT_EQ(data.readParcelable(descFromParcel.get()), NO_ERROR);
+ ASSERT_TRUE(descFromParcel->equals(desc));
+}
+
+} // namespace android
diff --git a/media/libaudiohal/Android.bp b/media/libaudiohal/Android.bp
index 584c2c0..1709d1e 100644
--- a/media/libaudiohal/Android.bp
+++ b/media/libaudiohal/Android.bp
@@ -4,6 +4,7 @@
srcs: [
"DevicesFactoryHalInterface.cpp",
"EffectsFactoryHalInterface.cpp",
+ "FactoryHalHidl.cpp",
],
cflags: [
@@ -12,21 +13,23 @@
"-Werror",
],
- shared_libs: [
- "android.hardware.audio.effect@2.0",
- "android.hardware.audio.effect@4.0",
- "android.hardware.audio.effect@5.0",
- "android.hardware.audio@2.0",
- "android.hardware.audio@4.0",
- "android.hardware.audio@5.0",
+ required: [
"libaudiohal@2.0",
"libaudiohal@4.0",
"libaudiohal@5.0",
+ "libaudiohal@6.0",
+ ],
+
+ shared_libs: [
+ "libdl",
+ "libhidlbase",
+ "liblog",
"libutils",
],
header_libs: [
- "libaudiohal_headers"
+ "libaudiohal_headers",
+ "libbase_headers",
]
}
@@ -57,4 +60,10 @@
name: "libaudiohal_headers",
export_include_dirs: ["include"],
+
+ // This is needed because the stream interface includes media/MicrophoneInfo.h
+ // which is not in any library but has a dependency on headers from libbinder.
+ header_libs: ["libbinder_headers"],
+
+ export_header_lib_headers: ["libbinder_headers"],
}
diff --git a/media/libaudiohal/DevicesFactoryHalInterface.cpp b/media/libaudiohal/DevicesFactoryHalInterface.cpp
index f86009c..325a547 100644
--- a/media/libaudiohal/DevicesFactoryHalInterface.cpp
+++ b/media/libaudiohal/DevicesFactoryHalInterface.cpp
@@ -14,26 +14,15 @@
* limitations under the License.
*/
-#include <android/hardware/audio/2.0/IDevicesFactory.h>
-#include <android/hardware/audio/4.0/IDevicesFactory.h>
-#include <android/hardware/audio/5.0/IDevicesFactory.h>
-
-#include <libaudiohal/FactoryHalHidl.h>
+#include <media/audiohal/DevicesFactoryHalInterface.h>
+#include <media/audiohal/FactoryHalHidl.h>
namespace android {
// static
sp<DevicesFactoryHalInterface> DevicesFactoryHalInterface::create() {
- if (hardware::audio::V5_0::IDevicesFactory::getService() != nullptr) {
- return V5_0::createDevicesFactoryHal();
- }
- if (hardware::audio::V4_0::IDevicesFactory::getService() != nullptr) {
- return V4_0::createDevicesFactoryHal();
- }
- if (hardware::audio::V2_0::IDevicesFactory::getService() != nullptr) {
- return V2_0::createDevicesFactoryHal();
- }
- return nullptr;
+ return createPreferredImpl<DevicesFactoryHalInterface>(
+ "android.hardware.audio", "IDevicesFactory");
}
} // namespace android
diff --git a/media/libaudiohal/EffectsFactoryHalInterface.cpp b/media/libaudiohal/EffectsFactoryHalInterface.cpp
index bd3ef61..bc3b4c1 100644
--- a/media/libaudiohal/EffectsFactoryHalInterface.cpp
+++ b/media/libaudiohal/EffectsFactoryHalInterface.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 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.
@@ -14,26 +14,15 @@
* limitations under the License.
*/
-#include <android/hardware/audio/effect/2.0/IEffectsFactory.h>
-#include <android/hardware/audio/effect/4.0/IEffectsFactory.h>
-#include <android/hardware/audio/effect/5.0/IEffectsFactory.h>
-
-#include <libaudiohal/FactoryHalHidl.h>
+#include <media/audiohal/EffectsFactoryHalInterface.h>
+#include <media/audiohal/FactoryHalHidl.h>
namespace android {
// static
sp<EffectsFactoryHalInterface> EffectsFactoryHalInterface::create() {
- if (hardware::audio::effect::V5_0::IEffectsFactory::getService() != nullptr) {
- return effect::V5_0::createEffectsFactoryHal();
- }
- if (hardware::audio::effect::V4_0::IEffectsFactory::getService() != nullptr) {
- return effect::V4_0::createEffectsFactoryHal();
- }
- if (hardware::audio::effect::V2_0::IEffectsFactory::getService() != nullptr) {
- return effect::V2_0::createEffectsFactoryHal();
- }
- return nullptr;
+ return createPreferredImpl<EffectsFactoryHalInterface>(
+ "android.hardware.audio.effect", "IEffectsFactory");
}
// static
diff --git a/media/libaudiohal/FactoryHalHidl.cpp b/media/libaudiohal/FactoryHalHidl.cpp
new file mode 100644
index 0000000..5985ef0
--- /dev/null
+++ b/media/libaudiohal/FactoryHalHidl.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "FactoryHalHidl"
+
+#include <media/audiohal/FactoryHalHidl.h>
+
+#include <dlfcn.h>
+
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <hidl/ServiceManagement.h>
+#include <hidl/Status.h>
+#include <utils/Log.h>
+
+namespace android::detail {
+
+namespace {
+/** Supported HAL versions, in order of preference.
+ */
+const char* sAudioHALVersions[] = {
+ "6.0",
+ "5.0",
+ "4.0",
+ "2.0",
+ nullptr
+};
+
+bool createHalService(const std::string& version, const std::string& interface,
+ void** rawInterface) {
+ const std::string libName = "libaudiohal@" + version + ".so";
+ const std::string factoryFunctionName = "create" + interface;
+ constexpr int dlMode = RTLD_LAZY;
+ void* handle = nullptr;
+ dlerror(); // clear
+ handle = dlopen(libName.c_str(), dlMode);
+ if (handle == nullptr) {
+ const char* error = dlerror();
+ ALOGE("Failed to dlopen %s: %s", libName.c_str(),
+ error != nullptr ? error : "unknown error");
+ return false;
+ }
+ void* (*factoryFunction)();
+ *(void **)(&factoryFunction) = dlsym(handle, factoryFunctionName.c_str());
+ if (!factoryFunction) {
+ const char* error = dlerror();
+ ALOGE("Factory function %s not found in library %s: %s",
+ factoryFunctionName.c_str(), libName.c_str(),
+ error != nullptr ? error : "unknown error");
+ dlclose(handle);
+ return false;
+ }
+ *rawInterface = (*factoryFunction)();
+ ALOGW_IF(!*rawInterface, "Factory function %s from %s returned nullptr",
+ factoryFunctionName.c_str(), libName.c_str());
+ return true;
+}
+
+bool hasHalService(const std::string& package, const std::string& version,
+ const std::string& interface) {
+ using ::android::hidl::manager::V1_0::IServiceManager;
+ sp<IServiceManager> sm = ::android::hardware::defaultServiceManager();
+ if (!sm) {
+ ALOGE("Failed to obtain HIDL ServiceManager");
+ return false;
+ }
+ // Since audio HAL doesn't support multiple clients, avoid instantiating
+ // the interface right away. Instead, query the transport type for it.
+ using ::android::hardware::Return;
+ using Transport = IServiceManager::Transport;
+ const std::string fqName = package + "@" + version + "::" + interface;
+ const std::string instance = "default";
+ Return<Transport> transport = sm->getTransport(fqName, instance);
+ if (!transport.isOk()) {
+ ALOGE("Failed to obtain transport type for %s/%s: %s",
+ fqName.c_str(), instance.c_str(), transport.description().c_str());
+ return false;
+ }
+ return transport != Transport::EMPTY;
+}
+
+} // namespace
+
+void* createPreferredImpl(const std::string& package, const std::string& interface) {
+ for (auto version = detail::sAudioHALVersions; version != nullptr; ++version) {
+ void* rawInterface = nullptr;
+ if (hasHalService(package, *version, interface)
+ && createHalService(*version, interface, &rawInterface)) {
+ return rawInterface;
+ }
+ }
+ return nullptr;
+}
+
+} // namespace android::detail
diff --git a/media/libaudiohal/impl/Android.bp b/media/libaudiohal/impl/Android.bp
index 88533da..967fba1 100644
--- a/media/libaudiohal/impl/Android.bp
+++ b/media/libaudiohal/impl/Android.bp
@@ -16,17 +16,17 @@
"StreamHalHidl.cpp",
],
- export_include_dirs: ["include"],
-
cflags: [
"-Wall",
"-Wextra",
"-Werror",
+ "-fvisibility=hidden",
],
shared_libs: [
"android.hardware.audio.common-util",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
+ "libaudiofoundation",
"libaudiohal_deathhandler",
"libaudioutils",
"libbase",
@@ -36,8 +36,6 @@
"libhardware",
"libhidlbase",
"libhidlmemory",
- "libhidltransport",
- "libhwbinder",
"liblog",
"libmedia_helper",
"libmediautils",
@@ -45,6 +43,7 @@
],
header_libs: [
"android.hardware.audio.common.util@all-versions",
+ "libaudioclient_headers",
"libaudiohal_headers"
],
@@ -100,3 +99,20 @@
"-include common/all-versions/VersionMacro.h",
]
}
+
+cc_library_shared {
+ name: "libaudiohal@6.0",
+ defaults: ["libaudiohal_default"],
+ shared_libs: [
+ "android.hardware.audio.common@6.0",
+ "android.hardware.audio.common@6.0-util",
+ "android.hardware.audio.effect@6.0",
+ "android.hardware.audio@6.0",
+ ],
+ cflags: [
+ "-DMAJOR_VERSION=6",
+ "-DMINOR_VERSION=0",
+ "-include common/all-versions/VersionMacro.h",
+ ]
+}
+
diff --git a/media/libaudiohal/impl/ConversionHelperHidl.cpp b/media/libaudiohal/impl/ConversionHelperHidl.cpp
index 9f8a520..f29b0f3 100644
--- a/media/libaudiohal/impl/ConversionHelperHidl.cpp
+++ b/media/libaudiohal/impl/ConversionHelperHidl.cpp
@@ -17,6 +17,7 @@
#include <string.h>
#define LOG_TAG "HalHidl"
+#include <media/AudioContainers.h>
#include <media/AudioParameter.h>
#include <utils/Log.h>
@@ -109,26 +110,22 @@
char halAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN];
memset(halAddress, 0, sizeof(halAddress));
audio_devices_t halDevice = static_cast<audio_devices_t>(address.device);
- const bool isInput = (halDevice & AUDIO_DEVICE_BIT_IN) != 0;
- if (isInput) halDevice &= ~AUDIO_DEVICE_BIT_IN;
- if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != 0) ||
- (isInput && (halDevice & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) != 0)) {
+ if (getAudioDeviceOutAllA2dpSet().count(halDevice) > 0 ||
+ halDevice == AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {
snprintf(halAddress, sizeof(halAddress), "%02X:%02X:%02X:%02X:%02X:%02X",
address.address.mac[0], address.address.mac[1], address.address.mac[2],
address.address.mac[3], address.address.mac[4], address.address.mac[5]);
- } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_IP) != 0) ||
- (isInput && (halDevice & AUDIO_DEVICE_IN_IP) != 0)) {
+ } else if (halDevice == AUDIO_DEVICE_OUT_IP || halDevice == AUDIO_DEVICE_IN_IP) {
snprintf(halAddress, sizeof(halAddress), "%d.%d.%d.%d", address.address.ipv4[0],
address.address.ipv4[1], address.address.ipv4[2], address.address.ipv4[3]);
- } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_ALL_USB) != 0) ||
- (isInput && (halDevice & AUDIO_DEVICE_IN_ALL_USB) != 0)) {
+ } else if (getAudioDeviceOutAllUsbSet().count(halDevice) > 0 ||
+ getAudioDeviceInAllUsbSet().count(halDevice) > 0) {
snprintf(halAddress, sizeof(halAddress), "card=%d;device=%d", address.address.alsa.card,
address.address.alsa.device);
- } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_BUS) != 0) ||
- (isInput && (halDevice & AUDIO_DEVICE_IN_BUS) != 0)) {
+ } else if (halDevice == AUDIO_DEVICE_OUT_BUS || halDevice == AUDIO_DEVICE_IN_BUS) {
snprintf(halAddress, sizeof(halAddress), "%s", address.busAddress.c_str());
- } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) != 0 ||
- (isInput && (halDevice & AUDIO_DEVICE_IN_REMOTE_SUBMIX) != 0)) {
+ } else if (halDevice == AUDIO_DEVICE_OUT_REMOTE_SUBMIX ||
+ halDevice == AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
snprintf(halAddress, sizeof(halAddress), "%s", address.rSubmixAddress.c_str());
} else {
snprintf(halAddress, sizeof(halAddress), "%s", address.busAddress.c_str());
diff --git a/media/libaudiohal/impl/DeviceHalHidl.cpp b/media/libaudiohal/impl/DeviceHalHidl.cpp
index b25f82e..7d0d83d 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalHidl.cpp
@@ -22,11 +22,13 @@
#include PATH(android/hardware/audio/FILE_VERSION/IPrimaryDevice.h)
#include <cutils/native_handle.h>
#include <hwbinder/IPCThreadState.h>
+#include <media/AudioContainers.h>
#include <utils/Log.h>
#include <common/all-versions/VersionUtils.h>
#include "DeviceHalHidl.h"
+#include "EffectHalHidl.h"
#include "HidlUtils.h"
#include "StreamHalHidl.h"
#include "VersionUtils.h"
@@ -42,6 +44,8 @@
using namespace ::android::hardware::audio::common::CPP_VERSION;
using namespace ::android::hardware::audio::CPP_VERSION;
+using EffectHalHidl = ::android::effect::CPP_VERSION::EffectHalHidl;
+
namespace {
status_t deviceAddressFromHal(
@@ -51,42 +55,32 @@
if (halAddress == nullptr || strnlen(halAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0) {
return OK;
}
- const bool isInput = (device & AUDIO_DEVICE_BIT_IN) != 0;
- if (isInput) device &= ~AUDIO_DEVICE_BIT_IN;
- if ((!isInput && (device & AUDIO_DEVICE_OUT_ALL_A2DP) != 0)
- || (isInput && (device & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) != 0)) {
+ if (getAudioDeviceOutAllA2dpSet().count(device) > 0
+ || device == AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {
int status = sscanf(halAddress,
"%hhX:%hhX:%hhX:%hhX:%hhX:%hhX",
&address->address.mac[0], &address->address.mac[1], &address->address.mac[2],
&address->address.mac[3], &address->address.mac[4], &address->address.mac[5]);
return status == 6 ? OK : BAD_VALUE;
- } else if ((!isInput && (device & AUDIO_DEVICE_OUT_IP) != 0)
- || (isInput && (device & AUDIO_DEVICE_IN_IP) != 0)) {
+ } else if (device == AUDIO_DEVICE_OUT_IP || device == AUDIO_DEVICE_IN_IP) {
int status = sscanf(halAddress,
"%hhu.%hhu.%hhu.%hhu",
&address->address.ipv4[0], &address->address.ipv4[1],
&address->address.ipv4[2], &address->address.ipv4[3]);
return status == 4 ? OK : BAD_VALUE;
- } else if ((!isInput && (device & AUDIO_DEVICE_OUT_ALL_USB)) != 0
- || (isInput && (device & AUDIO_DEVICE_IN_ALL_USB)) != 0) {
+ } else if (getAudioDeviceOutAllUsbSet().count(device) > 0
+ || getAudioDeviceInAllUsbSet().count(device) > 0) {
int status = sscanf(halAddress,
"card=%d;device=%d",
&address->address.alsa.card, &address->address.alsa.device);
return status == 2 ? OK : BAD_VALUE;
- } else if ((!isInput && (device & AUDIO_DEVICE_OUT_BUS) != 0)
- || (isInput && (device & AUDIO_DEVICE_IN_BUS) != 0)) {
- if (halAddress != NULL) {
- address->busAddress = halAddress;
- return OK;
- }
- return BAD_VALUE;
- } else if ((!isInput && (device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) != 0
- || (isInput && (device & AUDIO_DEVICE_IN_REMOTE_SUBMIX) != 0)) {
- if (halAddress != NULL) {
- address->rSubmixAddress = halAddress;
- return OK;
- }
- return BAD_VALUE;
+ } else if (device == AUDIO_DEVICE_OUT_BUS || device == AUDIO_DEVICE_IN_BUS) {
+ address->busAddress = halAddress;
+ return OK;
+ } else if (device == AUDIO_DEVICE_OUT_REMOTE_SUBMIX
+ || device == AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
+ address->rSubmixAddress = halAddress;
+ return OK;
}
return OK;
}
@@ -100,8 +94,12 @@
DeviceHalHidl::~DeviceHalHidl() {
if (mDevice != 0) {
+#if MAJOR_VERSION <= 5
mDevice.clear();
hardware::IPCThreadState::self()->flushCommands();
+#elif MAJOR_VERSION >= 6
+ mDevice->close();
+#endif
}
}
@@ -229,14 +227,14 @@
status_t DeviceHalHidl::openOutputStream(
audio_io_handle_t handle,
- audio_devices_t devices,
+ audio_devices_t deviceType,
audio_output_flags_t flags,
struct audio_config *config,
const char *address,
sp<StreamOutHalInterface> *outStream) {
if (mDevice == 0) return NO_INIT;
DeviceAddress hidlDevice;
- status_t status = deviceAddressFromHal(devices, address, &hidlDevice);
+ status_t status = deviceAddressFromHal(deviceType, address, &hidlDevice);
if (status != OK) return status;
AudioConfig hidlConfig;
HidlUtils::audioConfigFromHal(*config, &hidlConfig);
@@ -294,6 +292,10 @@
sinkMetadata.tracks[0].destination.device(std::move(hidlOutputDevice));
}
#endif
+#if MAJOR_VERSION <= 5
+ // Some flags were specific to framework and must not leak to the HAL.
+ flags = static_cast<audio_input_flags_t>(flags & ~AUDIO_INPUT_FLAG_DIRECT);
+#endif
Return<void> ret = mDevice->openInputStream(
handle,
hidlDevice,
@@ -322,19 +324,47 @@
const struct audio_port_config *sinks,
audio_patch_handle_t *patch) {
if (mDevice == 0) return NO_INIT;
+ if (patch == nullptr) return BAD_VALUE;
+
+#if MAJOR_VERSION < 6
+ if (*patch != AUDIO_PATCH_HANDLE_NONE) {
+ status_t status = releaseAudioPatch(*patch);
+ ALOGW_IF(status != NO_ERROR, "%s error %d releasing patch handle %d",
+ __func__, status, *patch);
+ *patch = AUDIO_PATCH_HANDLE_NONE;
+ }
+#endif
+
hidl_vec<AudioPortConfig> hidlSources, hidlSinks;
HidlUtils::audioPortConfigsFromHal(num_sources, sources, &hidlSources);
HidlUtils::audioPortConfigsFromHal(num_sinks, sinks, &hidlSinks);
- Result retval;
- Return<void> ret = mDevice->createAudioPatch(
- hidlSources, hidlSinks,
- [&](Result r, AudioPatchHandle hidlPatch) {
- retval = r;
- if (retval == Result::OK) {
- *patch = static_cast<audio_patch_handle_t>(hidlPatch);
- }
- });
- return processReturn("createAudioPatch", ret, retval);
+ Result retval = Result::OK;
+ Return<void> ret;
+ std::string methodName = "createAudioPatch";
+ if (*patch == AUDIO_PATCH_HANDLE_NONE) { // always true for MAJOR_VERSION < 6
+ ret = mDevice->createAudioPatch(
+ hidlSources, hidlSinks,
+ [&](Result r, AudioPatchHandle hidlPatch) {
+ retval = r;
+ if (retval == Result::OK) {
+ *patch = static_cast<audio_patch_handle_t>(hidlPatch);
+ }
+ });
+ } else {
+#if MAJOR_VERSION >= 6
+ ret = mDevice->updateAudioPatch(
+ *patch,
+ hidlSources, hidlSinks,
+ [&](Result r, AudioPatchHandle hidlPatch) {
+ retval = r;
+ if (retval == Result::OK) {
+ *patch = static_cast<audio_patch_handle_t>(hidlPatch);
+ }
+ });
+ methodName = "updateAudioPatch";
+#endif
+ }
+ return processReturn(methodName.c_str(), ret, retval);
}
status_t DeviceHalHidl::releaseAudioPatch(audio_patch_handle_t patch) {
@@ -390,6 +420,36 @@
}
#endif
+#if MAJOR_VERSION >= 6
+status_t DeviceHalHidl::addDeviceEffect(
+ audio_port_handle_t device, sp<EffectHalInterface> effect) {
+ if (mDevice == 0) return NO_INIT;
+ return processReturn("addDeviceEffect", mDevice->addDeviceEffect(
+ static_cast<AudioPortHandle>(device),
+ static_cast<EffectHalHidl*>(effect.get())->effectId()));
+}
+#else
+status_t DeviceHalHidl::addDeviceEffect(
+ audio_port_handle_t device __unused, sp<EffectHalInterface> effect __unused) {
+ return INVALID_OPERATION;
+}
+#endif
+
+#if MAJOR_VERSION >= 6
+status_t DeviceHalHidl::removeDeviceEffect(
+ audio_port_handle_t device, sp<EffectHalInterface> effect) {
+ if (mDevice == 0) return NO_INIT;
+ return processReturn("removeDeviceEffect", mDevice->removeDeviceEffect(
+ static_cast<AudioPortHandle>(device),
+ static_cast<EffectHalHidl*>(effect.get())->effectId()));
+}
+#else
+status_t DeviceHalHidl::removeDeviceEffect(
+ audio_port_handle_t device __unused, sp<EffectHalInterface> effect __unused) {
+ return INVALID_OPERATION;
+}
+#endif
+
status_t DeviceHalHidl::dump(int fd) {
if (mDevice == 0) return NO_INIT;
native_handle_t* hidlHandle = native_handle_create(1, 0);
diff --git a/media/libaudiohal/impl/DeviceHalHidl.h b/media/libaudiohal/impl/DeviceHalHidl.h
index f7d465f..d342d4a 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.h
+++ b/media/libaudiohal/impl/DeviceHalHidl.h
@@ -113,6 +113,9 @@
// List microphones
virtual status_t getMicrophones(std::vector<media::MicrophoneInfo> *microphones);
+ status_t addDeviceEffect(audio_port_handle_t device, sp<EffectHalInterface> effect) override;
+ status_t removeDeviceEffect(audio_port_handle_t device, sp<EffectHalInterface> effect) override;
+
virtual status_t dump(int fd);
private:
diff --git a/media/libaudiohal/impl/DeviceHalLocal.cpp b/media/libaudiohal/impl/DeviceHalLocal.cpp
index ee68252..8021d92 100644
--- a/media/libaudiohal/impl/DeviceHalLocal.cpp
+++ b/media/libaudiohal/impl/DeviceHalLocal.cpp
@@ -104,7 +104,7 @@
status_t DeviceHalLocal::openOutputStream(
audio_io_handle_t handle,
- audio_devices_t devices,
+ audio_devices_t deviceType,
audio_output_flags_t flags,
struct audio_config *config,
const char *address,
@@ -112,11 +112,11 @@
audio_stream_out_t *halStream;
ALOGV("open_output_stream handle: %d devices: %x flags: %#x"
"srate: %d format %#x channels %x address %s",
- handle, devices, flags,
+ handle, deviceType, flags,
config->sample_rate, config->format, config->channel_mask,
address);
int openResut = mDev->open_output_stream(
- mDev, handle, devices, flags, config, &halStream, address);
+ mDev, handle, deviceType, flags, config, &halStream, address);
if (openResut == OK) {
*outStream = new StreamOutHalLocal(halStream, this);
}
@@ -206,6 +206,17 @@
}
#endif
+// Local HAL implementation does not support effects
+status_t DeviceHalLocal::addDeviceEffect(
+ audio_port_handle_t device __unused, sp<EffectHalInterface> effect __unused) {
+ return INVALID_OPERATION;
+}
+
+status_t DeviceHalLocal::removeDeviceEffect(
+ audio_port_handle_t device __unused, sp<EffectHalInterface> effect __unused) {
+ return INVALID_OPERATION;
+}
+
status_t DeviceHalLocal::dump(int fd) {
return mDev->dump(mDev, fd);
}
diff --git a/media/libaudiohal/impl/DeviceHalLocal.h b/media/libaudiohal/impl/DeviceHalLocal.h
index 36db72e..d85e2a7 100644
--- a/media/libaudiohal/impl/DeviceHalLocal.h
+++ b/media/libaudiohal/impl/DeviceHalLocal.h
@@ -106,6 +106,9 @@
// List microphones
virtual status_t getMicrophones(std::vector<media::MicrophoneInfo> *microphones);
+ status_t addDeviceEffect(audio_port_handle_t device, sp<EffectHalInterface> effect) override;
+ status_t removeDeviceEffect(audio_port_handle_t device, sp<EffectHalInterface> effect) override;
+
virtual status_t dump(int fd);
void closeOutputStream(struct audio_stream_out *stream_out);
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp b/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp
index 5e01e42..1c0eacb 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp
+++ b/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp
@@ -15,11 +15,13 @@
*/
#include <string.h>
-#include <vector>
+#include <set>
#define LOG_TAG "DevicesFactoryHalHidl"
//#define LOG_NDEBUG 0
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <android/hidl/manager/1.0/IServiceNotification.h>
#include PATH(android/hardware/audio/FILE_VERSION/IDevice.h)
#include <media/audiohal/hidl/HalDeathHandler.h>
#include <utils/Log.h>
@@ -31,31 +33,54 @@
using ::android::hardware::audio::CPP_VERSION::IDevice;
using ::android::hardware::audio::CPP_VERSION::Result;
using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hidl::manager::V1_0::IServiceManager;
+using ::android::hidl::manager::V1_0::IServiceNotification;
namespace android {
namespace CPP_VERSION {
-DevicesFactoryHalHidl::DevicesFactoryHalHidl() {
- sp<IDevicesFactory> defaultFactory{IDevicesFactory::getService()};
- if (!defaultFactory) {
- ALOGE("Failed to obtain IDevicesFactory/default service, terminating process.");
- exit(1);
- }
- mDeviceFactories.push_back(defaultFactory);
- if (MAJOR_VERSION >= 4) {
- // The MSD factory is optional and only available starting at HAL 4.0
- sp<IDevicesFactory> msdFactory{IDevicesFactory::getService(AUDIO_HAL_SERVICE_NAME_MSD)};
- if (msdFactory) {
- mDeviceFactories.push_back(msdFactory);
+class ServiceNotificationListener : public IServiceNotification {
+ public:
+ explicit ServiceNotificationListener(sp<DevicesFactoryHalHidl> factory)
+ : mFactory(factory) {}
+
+ Return<void> onRegistration(const hidl_string& /*fully_qualified_name*/,
+ const hidl_string& instance_name,
+ bool /*pre_existing*/) override {
+ if (static_cast<std::string>(instance_name) == "default") return Void();
+ sp<DevicesFactoryHalHidl> factory = mFactory.promote();
+ if (!factory) return Void();
+ sp<IDevicesFactory> halFactory = IDevicesFactory::getService(instance_name);
+ if (halFactory) {
+ factory->addDeviceFactory(halFactory, true /*needToNotify*/);
}
+ return Void();
}
- for (const auto& factory : mDeviceFactories) {
- // It is assumed that the DevicesFactoryHalInterface instance is owned
- // by AudioFlinger and thus have the same lifespan.
- factory->linkToDeath(HalDeathHandler::getInstance(), 0 /*cookie*/);
- }
+
+ private:
+ wp<DevicesFactoryHalHidl> mFactory;
+};
+
+DevicesFactoryHalHidl::DevicesFactoryHalHidl(sp<IDevicesFactory> devicesFactory) {
+ ALOG_ASSERT(devicesFactory != nullptr, "Provided default IDevicesFactory service is NULL");
+ addDeviceFactory(devicesFactory, false /*needToNotify*/);
}
+void DevicesFactoryHalHidl::onFirstRef() {
+ sp<IServiceManager> sm = IServiceManager::getService();
+ ALOG_ASSERT(sm != nullptr, "Hardware service manager is not running");
+ sp<ServiceNotificationListener> listener = new ServiceNotificationListener(this);
+ Return<bool> result = sm->registerForNotifications(
+ IDevicesFactory::descriptor, "", listener);
+ if (result.isOk()) {
+ ALOGE_IF(!static_cast<bool>(result),
+ "Hardware service manager refused to register listener");
+ } else {
+ ALOGE("Failed to register for hardware service manager notifications: %s",
+ result.description().c_str());
+ }
+}
#if MAJOR_VERSION == 2
static IDevicesFactory::Device idFromHal(const char *name, status_t* status) {
@@ -83,12 +108,13 @@
#endif
status_t DevicesFactoryHalHidl::openDevice(const char *name, sp<DeviceHalInterface> *device) {
- if (mDeviceFactories.empty()) return NO_INIT;
+ auto factories = copyDeviceFactories();
+ if (factories.empty()) return NO_INIT;
status_t status;
auto hidlId = idFromHal(name, &status);
if (status != OK) return status;
Result retval = Result::NOT_INITIALIZED;
- for (const auto& factory : mDeviceFactories) {
+ for (const auto& factory : factories) {
Return<void> ret = factory->openDevice(
hidlId,
[&](Result r, const sp<IDevice>& result) {
@@ -111,5 +137,71 @@
return BAD_VALUE;
}
+status_t DevicesFactoryHalHidl::getHalPids(std::vector<pid_t> *pids) {
+ std::set<pid_t> pidsSet;
+ auto factories = copyDeviceFactories();
+ for (const auto& factory : factories) {
+ using ::android::hidl::base::V1_0::DebugInfo;
+
+ DebugInfo debugInfo;
+ auto ret = factory->getDebugInfo([&] (const auto &info) {
+ debugInfo = info;
+ });
+ if (!ret.isOk()) {
+ return INVALID_OPERATION;
+ }
+ if (debugInfo.pid == (int)IServiceManager::PidConstant::NO_PID) {
+ continue;
+ }
+ pidsSet.insert(debugInfo.pid);
+ }
+
+ *pids = {pidsSet.begin(), pidsSet.end()};
+ return NO_ERROR;
+}
+
+status_t DevicesFactoryHalHidl::setCallbackOnce(sp<DevicesFactoryHalCallback> callback) {
+ ALOG_ASSERT(callback != nullptr);
+ bool needToCallCallback = false;
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mCallback.unsafe_get()) return INVALID_OPERATION;
+ mCallback = callback;
+ if (mHaveUndeliveredNotifications) {
+ needToCallCallback = true;
+ mHaveUndeliveredNotifications = false;
+ }
+ }
+ if (needToCallCallback) {
+ callback->onNewDevicesAvailable();
+ }
+ return NO_ERROR;
+}
+
+void DevicesFactoryHalHidl::addDeviceFactory(sp<IDevicesFactory> factory, bool needToNotify) {
+ // It is assumed that the DevicesFactoryHalInterface instance is owned
+ // by AudioFlinger and thus have the same lifespan.
+ factory->linkToDeath(HalDeathHandler::getInstance(), 0 /*cookie*/);
+ sp<DevicesFactoryHalCallback> callback;
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ mDeviceFactories.push_back(factory);
+ if (needToNotify) {
+ callback = mCallback.promote();
+ if (!callback) {
+ mHaveUndeliveredNotifications = true;
+ }
+ }
+ }
+ if (callback) {
+ callback->onNewDevicesAvailable();
+ }
+}
+
+std::vector<sp<IDevicesFactory>> DevicesFactoryHalHidl::copyDeviceFactories() {
+ std::lock_guard<std::mutex> lock(mLock);
+ return mDeviceFactories;
+}
+
} // namespace CPP_VERSION
} // namespace android
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHidl.h b/media/libaudiohal/impl/DevicesFactoryHalHidl.h
index 27e0649..6f84efe 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHidl.h
+++ b/media/libaudiohal/impl/DevicesFactoryHalHidl.h
@@ -17,6 +17,9 @@
#ifndef ANDROID_HARDWARE_DEVICES_FACTORY_HAL_HIDL_H
#define ANDROID_HARDWARE_DEVICES_FACTORY_HAL_HIDL_H
+#include <mutex>
+#include <vector>
+
#include PATH(android/hardware/audio/FILE_VERSION/IDevicesFactory.h)
#include <media/audiohal/DevicesFactoryHalInterface.h>
#include <utils/Errors.h>
@@ -32,17 +35,26 @@
class DevicesFactoryHalHidl : public DevicesFactoryHalInterface
{
public:
+ explicit DevicesFactoryHalHidl(sp<IDevicesFactory> devicesFactory);
+ void onFirstRef() override;
+
// Opens a device with the specified name. To close the device, it is
// necessary to release references to the returned object.
- virtual status_t openDevice(const char *name, sp<DeviceHalInterface> *device);
+ status_t openDevice(const char *name, sp<DeviceHalInterface> *device) override;
+
+ status_t getHalPids(std::vector<pid_t> *pids) override;
+
+ status_t setCallbackOnce(sp<DevicesFactoryHalCallback> callback) override;
private:
- friend class DevicesFactoryHalHybrid;
+ friend class ServiceNotificationListener;
+ void addDeviceFactory(sp<IDevicesFactory> factory, bool needToNotify);
+ std::vector<sp<IDevicesFactory>> copyDeviceFactories();
- std::vector<sp<IDevicesFactory>> mDeviceFactories;
-
- // Can not be constructed directly by clients.
- DevicesFactoryHalHidl();
+ std::mutex mLock;
+ std::vector<sp<IDevicesFactory>> mDeviceFactories; // GUARDED_BY(mLock)
+ wp<DevicesFactoryHalCallback> mCallback; // GUARDED_BY(mLock)
+ bool mHaveUndeliveredNotifications = false; // GUARDED_BY(mLock)
virtual ~DevicesFactoryHalHidl() = default;
};
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp b/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp
index f337a8b..cde8d85 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp
+++ b/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp
@@ -17,16 +17,16 @@
#define LOG_TAG "DevicesFactoryHalHybrid"
//#define LOG_NDEBUG 0
+#include "DevicesFactoryHalHidl.h"
#include "DevicesFactoryHalHybrid.h"
#include "DevicesFactoryHalLocal.h"
-#include "DevicesFactoryHalHidl.h"
namespace android {
namespace CPP_VERSION {
-DevicesFactoryHalHybrid::DevicesFactoryHalHybrid()
+DevicesFactoryHalHybrid::DevicesFactoryHalHybrid(sp<IDevicesFactory> hidlFactory)
: mLocalFactory(new DevicesFactoryHalLocal()),
- mHidlFactory(new DevicesFactoryHalHidl()) {
+ mHidlFactory(new DevicesFactoryHalHidl(hidlFactory)) {
}
status_t DevicesFactoryHalHybrid::openDevice(const char *name, sp<DeviceHalInterface> *device) {
@@ -37,5 +37,25 @@
return mLocalFactory->openDevice(name, device);
}
+status_t DevicesFactoryHalHybrid::getHalPids(std::vector<pid_t> *pids) {
+ if (mHidlFactory != 0) {
+ return mHidlFactory->getHalPids(pids);
+ }
+ return INVALID_OPERATION;
+}
+
+status_t DevicesFactoryHalHybrid::setCallbackOnce(sp<DevicesFactoryHalCallback> callback) {
+ if (mHidlFactory) {
+ return mHidlFactory->setCallbackOnce(callback);
+ }
+ return INVALID_OPERATION;
+}
+
} // namespace CPP_VERSION
+
+extern "C" __attribute__((visibility("default"))) void* createIDevicesFactory() {
+ auto service = hardware::audio::CPP_VERSION::IDevicesFactory::getService();
+ return service ? new CPP_VERSION::DevicesFactoryHalHybrid(service) : nullptr;
+}
+
} // namespace android
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHybrid.h b/media/libaudiohal/impl/DevicesFactoryHalHybrid.h
index 5ac0d0d..568a1fb 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHybrid.h
+++ b/media/libaudiohal/impl/DevicesFactoryHalHybrid.h
@@ -17,31 +17,34 @@
#ifndef ANDROID_HARDWARE_DEVICES_FACTORY_HAL_HYBRID_H
#define ANDROID_HARDWARE_DEVICES_FACTORY_HAL_HYBRID_H
+#include PATH(android/hardware/audio/FILE_VERSION/IDevicesFactory.h)
#include <media/audiohal/DevicesFactoryHalInterface.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
+using ::android::hardware::audio::CPP_VERSION::IDevicesFactory;
+
namespace android {
namespace CPP_VERSION {
class DevicesFactoryHalHybrid : public DevicesFactoryHalInterface
{
public:
- DevicesFactoryHalHybrid();
+ DevicesFactoryHalHybrid(sp<IDevicesFactory> hidlFactory);
// Opens a device with the specified name. To close the device, it is
// necessary to release references to the returned object.
virtual status_t openDevice(const char *name, sp<DeviceHalInterface> *device);
+ status_t getHalPids(std::vector<pid_t> *pids) override;
+
+ status_t setCallbackOnce(sp<DevicesFactoryHalCallback> callback) override;
+
private:
sp<DevicesFactoryHalInterface> mLocalFactory;
sp<DevicesFactoryHalInterface> mHidlFactory;
};
-sp<DevicesFactoryHalInterface> createDevicesFactoryHal() {
- return new DevicesFactoryHalHybrid();
-}
-
} // namespace CPP_VERSION
} // namespace android
diff --git a/media/libaudiohal/impl/DevicesFactoryHalLocal.h b/media/libaudiohal/impl/DevicesFactoryHalLocal.h
index 5d108dd..32bf362 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalLocal.h
+++ b/media/libaudiohal/impl/DevicesFactoryHalLocal.h
@@ -33,6 +33,14 @@
// necessary to release references to the returned object.
virtual status_t openDevice(const char *name, sp<DeviceHalInterface> *device);
+ status_t getHalPids(std::vector<pid_t> *pids __unused) override {
+ return INVALID_OPERATION;
+ }
+
+ status_t setCallbackOnce(sp<DevicesFactoryHalCallback> callback __unused) override {
+ return INVALID_OPERATION;
+ }
+
private:
friend class DevicesFactoryHalHybrid;
diff --git a/media/libaudiohal/impl/EffectsFactoryHalHidl.cpp b/media/libaudiohal/impl/EffectsFactoryHalHidl.cpp
index 7fd6bde..9192a31 100644
--- a/media/libaudiohal/impl/EffectsFactoryHalHidl.cpp
+++ b/media/libaudiohal/impl/EffectsFactoryHalHidl.cpp
@@ -19,10 +19,10 @@
#include <cutils/native_handle.h>
-#include "EffectsFactoryHalHidl.h"
#include "ConversionHelperHidl.h"
#include "EffectBufferHalHidl.h"
#include "EffectHalHidl.h"
+#include "EffectsFactoryHalHidl.h"
#include "HidlUtils.h"
using ::android::hardware::audio::common::CPP_VERSION::implementation::HidlUtils;
@@ -35,12 +35,10 @@
using namespace ::android::hardware::audio::common::CPP_VERSION;
using namespace ::android::hardware::audio::effect::CPP_VERSION;
-EffectsFactoryHalHidl::EffectsFactoryHalHidl() : ConversionHelperHidl("EffectsFactory") {
- mEffectsFactory = IEffectsFactory::getService();
- if (mEffectsFactory == 0) {
- ALOGE("Failed to obtain IEffectsFactory service, terminating process.");
- exit(1);
- }
+EffectsFactoryHalHidl::EffectsFactoryHalHidl(sp<IEffectsFactory> effectsFactory)
+ : ConversionHelperHidl("EffectsFactory") {
+ ALOG_ASSERT(effectsFactory != nullptr, "Provided IDevicesFactory service is NULL");
+ mEffectsFactory = effectsFactory;
}
status_t EffectsFactoryHalHidl::queryAllDescriptors() {
@@ -106,12 +104,26 @@
status_t EffectsFactoryHalHidl::createEffect(
const effect_uuid_t *pEffectUuid, int32_t sessionId, int32_t ioId,
- sp<EffectHalInterface> *effect) {
+ int32_t deviceId __unused, sp<EffectHalInterface> *effect) {
if (mEffectsFactory == 0) return NO_INIT;
Uuid hidlUuid;
HidlUtils::uuidFromHal(*pEffectUuid, &hidlUuid);
Result retval = Result::NOT_INITIALIZED;
- Return<void> ret = mEffectsFactory->createEffect(
+ Return<void> ret;
+#if MAJOR_VERSION >= 6
+ ret = mEffectsFactory->createEffect(
+ hidlUuid, sessionId, ioId, deviceId,
+ [&](Result r, const sp<IEffect>& result, uint64_t effectId) {
+ retval = r;
+ if (retval == Result::OK) {
+ *effect = new EffectHalHidl(result, effectId);
+ }
+ });
+#else
+ if (sessionId == AUDIO_SESSION_DEVICE && ioId == AUDIO_IO_HANDLE_NONE) {
+ return INVALID_OPERATION;
+ }
+ ret = mEffectsFactory->createEffect(
hidlUuid, sessionId, ioId,
[&](Result r, const sp<IEffect>& result, uint64_t effectId) {
retval = r;
@@ -119,6 +131,7 @@
*effect = new EffectHalHidl(result, effectId);
}
});
+#endif
if (ret.isOk()) {
if (retval == Result::OK) return OK;
else if (retval == Result::INVALID_ARGUMENTS) return NAME_NOT_FOUND;
@@ -147,4 +160,10 @@
} // namespace CPP_VERSION
} // namespace effect
+
+extern "C" __attribute__((visibility("default"))) void* createIEffectsFactory() {
+ auto service = hardware::audio::effect::CPP_VERSION::IEffectsFactory::getService();
+ return service ? new effect::CPP_VERSION::EffectsFactoryHalHidl(service) : nullptr;
+}
+
} // namespace android
diff --git a/media/libaudiohal/impl/EffectsFactoryHalHidl.h b/media/libaudiohal/impl/EffectsFactoryHalHidl.h
index 01178ff..dece1bb 100644
--- a/media/libaudiohal/impl/EffectsFactoryHalHidl.h
+++ b/media/libaudiohal/impl/EffectsFactoryHalHidl.h
@@ -18,7 +18,6 @@
#define ANDROID_HARDWARE_EFFECTS_FACTORY_HAL_HIDL_H
#include PATH(android/hardware/audio/effect/FILE_VERSION/IEffectsFactory.h)
-#include PATH(android/hardware/audio/effect/FILE_VERSION/types.h)
#include <media/audiohal/EffectsFactoryHalInterface.h>
#include "ConversionHelperHidl.h"
@@ -34,7 +33,7 @@
class EffectsFactoryHalHidl : public EffectsFactoryHalInterface, public ConversionHelperHidl
{
public:
- EffectsFactoryHalHidl();
+ EffectsFactoryHalHidl(sp<IEffectsFactory> effectsFactory);
// Returns the number of different effects in all loaded libraries.
virtual status_t queryNumberEffects(uint32_t *pNumEffects);
@@ -50,7 +49,7 @@
// To release the effect engine, it is necessary to release references
// to the returned effect object.
virtual status_t createEffect(const effect_uuid_t *pEffectUuid,
- int32_t sessionId, int32_t ioId,
+ int32_t sessionId, int32_t ioId, int32_t deviceId,
sp<EffectHalInterface> *effect);
virtual status_t dumpEffects(int fd);
@@ -66,10 +65,6 @@
status_t queryAllDescriptors();
};
-sp<EffectsFactoryHalInterface> createEffectsFactoryHal() {
- return new EffectsFactoryHalHidl();
-}
-
} // namespace CPP_VERSION
} // namespace effect
} // namespace android
diff --git a/media/libaudiohal/impl/StreamHalHidl.cpp b/media/libaudiohal/impl/StreamHalHidl.cpp
index c08dddb..2726e36 100644
--- a/media/libaudiohal/impl/StreamHalHidl.cpp
+++ b/media/libaudiohal/impl/StreamHalHidl.cpp
@@ -299,10 +299,17 @@
if (mCallback.unsafe_get()) {
processReturn("clearCallback", mStream->clearCallback());
}
+#if MAJOR_VERSION >= 6
+ if (mEventCallback.unsafe_get() != nullptr) {
+ processReturn("setEventCallback",
+ mStream->setEventCallback(nullptr));
+ }
+#endif
processReturn("close", mStream->close());
mStream.clear();
}
mCallback.clear();
+ mEventCallback.clear();
hardware::IPCThreadState::self()->flushCommands();
if (mEfGroup) {
EventFlag::deleteEventFlag(&mEfGroup);
@@ -614,6 +621,50 @@
}
#endif
+#if MAJOR_VERSION < 6
+status_t StreamOutHalHidl::setEventCallback(
+ const sp<StreamOutHalInterfaceEventCallback>& callback __unused) {
+ // Codec format callback is supported starting from audio HAL V6.0
+ return INVALID_OPERATION;
+}
+#else
+
+#include PATH(android/hardware/audio/FILE_VERSION/IStreamOutEventCallback.h)
+
+namespace {
+
+struct StreamOutEventCallback : public IStreamOutEventCallback {
+ StreamOutEventCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
+
+ // IStreamOutEventCallback implementation
+ Return<void> onCodecFormatChanged(
+ const android::hardware::hidl_vec<uint8_t>& audioMetadata) override {
+ sp<StreamOutHalHidl> stream = mStream.promote();
+ if (stream != nullptr) {
+ std::basic_string<uint8_t> metadataBs(audioMetadata.begin(), audioMetadata.end());
+ stream->onCodecFormatChanged(metadataBs);
+ }
+ return Void();
+ }
+
+ private:
+ wp<StreamOutHalHidl> mStream;
+};
+
+} // namespace
+
+status_t StreamOutHalHidl::setEventCallback(
+ const sp<StreamOutHalInterfaceEventCallback>& callback) {
+ if (mStream == nullptr) return NO_INIT;
+ mEventCallback = callback;
+ status_t status = processReturn(
+ "setEventCallback",
+ mStream->setEventCallback(
+ callback.get() == nullptr ? nullptr : new StreamOutEventCallback(this)));
+ return status;
+}
+#endif
+
void StreamOutHalHidl::onWriteReady() {
sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
if (callback == 0) return;
@@ -635,6 +686,13 @@
callback->onError();
}
+void StreamOutHalHidl::onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs) {
+ sp<StreamOutHalInterfaceEventCallback> callback = mEventCallback.promote();
+ if (callback == nullptr) return;
+ ALOGV("asyncCodecFormatCallback %s", __func__);
+ callback->onCodecFormatChanged(metadataBs);
+}
+
StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
: StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
diff --git a/media/libaudiohal/impl/StreamHalHidl.h b/media/libaudiohal/impl/StreamHalHidl.h
index f587889..88f8587 100644
--- a/media/libaudiohal/impl/StreamHalHidl.h
+++ b/media/libaudiohal/impl/StreamHalHidl.h
@@ -173,6 +173,11 @@
void onDrainReady();
void onError();
+ status_t setEventCallback(const sp<StreamOutHalInterfaceEventCallback>& callback) override;
+
+ // Methods used by StreamCodecFormatCallback (HIDL).
+ void onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs);
+
private:
friend class DeviceHalHidl;
typedef MessageQueue<WriteCommand, hardware::kSynchronizedReadWrite> CommandMQ;
@@ -180,6 +185,7 @@
typedef MessageQueue<WriteStatus, hardware::kSynchronizedReadWrite> StatusMQ;
wp<StreamOutHalInterfaceCallback> mCallback;
+ wp<StreamOutHalInterfaceEventCallback> mEventCallback;
sp<IStreamOut> mStream;
std::unique_ptr<CommandMQ> mCommandMQ;
std::unique_ptr<DataMQ> mDataMQ;
diff --git a/media/libaudiohal/impl/StreamHalLocal.cpp b/media/libaudiohal/impl/StreamHalLocal.cpp
index 4818fd8..69be303 100644
--- a/media/libaudiohal/impl/StreamHalLocal.cpp
+++ b/media/libaudiohal/impl/StreamHalLocal.cpp
@@ -275,6 +275,43 @@
return mStream->get_mmap_position(mStream, position);
}
+status_t StreamOutHalLocal::setEventCallback(
+ const sp<StreamOutHalInterfaceEventCallback>& callback) {
+ if (mStream->set_event_callback == nullptr) {
+ return INVALID_OPERATION;
+ }
+ stream_event_callback_t asyncCallback =
+ callback == nullptr ? nullptr : StreamOutHalLocal::asyncEventCallback;
+ status_t result = mStream->set_event_callback(mStream, asyncCallback, this);
+ if (result == OK) {
+ mEventCallback = callback;
+ }
+ return result;
+}
+
+// static
+int StreamOutHalLocal::asyncEventCallback(
+ stream_event_callback_type_t event, void *param, void *cookie) {
+ // We act as if we gave a wp<StreamOutHalLocal> to HAL. This way we should handle
+ // correctly the case when the callback is invoked while StreamOutHalLocal's destructor is
+ // already running, because the destructor is invoked after the refcount has been atomically
+ // decremented.
+ wp<StreamOutHalLocal> weakSelf(static_cast<StreamOutHalLocal*>(cookie));
+ sp<StreamOutHalLocal> self = weakSelf.promote();
+ if (self == nullptr) return 0;
+ sp<StreamOutHalInterfaceEventCallback> callback = self->mEventCallback.promote();
+ if (callback.get() == nullptr) return 0;
+ switch (event) {
+ case STREAM_EVENT_CBK_TYPE_CODEC_FORMAT_CHANGED:
+ callback->onCodecFormatChanged(std::basic_string<uint8_t>((uint8_t*)param));
+ break;
+ default:
+ ALOGW("%s unknown event %d", __func__, event);
+ break;
+ }
+ return 0;
+}
+
StreamInHalLocal::StreamInHalLocal(audio_stream_in_t *stream, sp<DeviceHalLocal> device)
: StreamHalLocal(&stream->common, device), mStream(stream) {
}
diff --git a/media/libaudiohal/impl/StreamHalLocal.h b/media/libaudiohal/impl/StreamHalLocal.h
index 34f2bd8..d17f9f3 100644
--- a/media/libaudiohal/impl/StreamHalLocal.h
+++ b/media/libaudiohal/impl/StreamHalLocal.h
@@ -156,9 +156,12 @@
// Called when the metadata of the stream's source has been changed.
status_t updateSourceMetadata(const SourceMetadata& sourceMetadata) override;
+ status_t setEventCallback(const sp<StreamOutHalInterfaceEventCallback>& callback) override;
+
private:
audio_stream_out_t *mStream;
wp<StreamOutHalInterfaceCallback> mCallback;
+ wp<StreamOutHalInterfaceEventCallback> mEventCallback;
friend class DeviceHalLocal;
@@ -168,6 +171,8 @@
virtual ~StreamOutHalLocal();
static int asyncCallback(stream_callback_event_t event, void *param, void *cookie);
+
+ static int asyncEventCallback(stream_event_callback_type_t event, void *param, void *cookie);
};
class StreamInHalLocal : public StreamInHalInterface, public StreamHalLocal {
diff --git a/media/libaudiohal/impl/include/libaudiohal/FactoryHalHidl.h b/media/libaudiohal/impl/include/libaudiohal/FactoryHalHidl.h
deleted file mode 100644
index c7319d0..0000000
--- a/media/libaudiohal/impl/include/libaudiohal/FactoryHalHidl.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_FACTORY_HAL_HIDL_H
-#define ANDROID_HARDWARE_FACTORY_HAL_HIDL_H
-
-/** @file Library entry points to create the HAL factories. */
-
-#include <media/audiohal/DevicesFactoryHalInterface.h>
-#include <media/audiohal/EffectsFactoryHalInterface.h>
-#include <utils/StrongPointer.h>
-
-namespace android {
-
-namespace effect {
-namespace V2_0 {
-sp<EffectsFactoryHalInterface> createEffectsFactoryHal();
-} // namespace V2_0
-
-namespace V4_0 {
-sp<EffectsFactoryHalInterface> createEffectsFactoryHal();
-} // namespace V4_0
-
-namespace V5_0 {
-sp<EffectsFactoryHalInterface> createEffectsFactoryHal();
-} // namespace V5_0
-} // namespace effect
-
-namespace V2_0 {
-sp<DevicesFactoryHalInterface> createDevicesFactoryHal();
-} // namespace V2_0
-
-namespace V4_0 {
-sp<DevicesFactoryHalInterface> createDevicesFactoryHal();
-} // namespace V4_0
-
-namespace V5_0 {
-sp<DevicesFactoryHalInterface> createDevicesFactoryHal();
-} // namespace V5_0
-
-} // namespace android
-
-#endif // ANDROID_HARDWARE_FACTORY_HAL_HIDL_H
diff --git a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
index e565237..1e04b21 100644
--- a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_HARDWARE_DEVICE_HAL_INTERFACE_H
#define ANDROID_HARDWARE_DEVICE_HAL_INTERFACE_H
+#include <media/audiohal/EffectHalInterface.h>
#include <media/MicrophoneInfo.h>
#include <system/audio.h>
#include <utils/Errors.h>
@@ -69,7 +70,7 @@
// by releasing all references to the returned object.
virtual status_t openOutputStream(
audio_io_handle_t handle,
- audio_devices_t devices,
+ audio_devices_t deviceType,
audio_output_flags_t flags,
struct audio_config *config,
const char *address,
@@ -111,6 +112,11 @@
// List microphones
virtual status_t getMicrophones(std::vector<media::MicrophoneInfo> *microphones) = 0;
+ virtual status_t addDeviceEffect(
+ audio_port_handle_t device, sp<EffectHalInterface> effect) = 0;
+ virtual status_t removeDeviceEffect(
+ audio_port_handle_t device, sp<EffectHalInterface> effect) = 0;
+
virtual status_t dump(int fd) = 0;
protected:
diff --git a/media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h b/media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h
index 14af384..5091558 100644
--- a/media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h
@@ -20,9 +20,16 @@
#include <media/audiohal/DeviceHalInterface.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
+#include <vector>
namespace android {
+class DevicesFactoryHalCallback : public RefBase
+{
+ public:
+ virtual void onNewDevicesAvailable() = 0;
+};
+
class DevicesFactoryHalInterface : public RefBase
{
public:
@@ -30,6 +37,12 @@
// necessary to release references to the returned object.
virtual status_t openDevice(const char *name, sp<DeviceHalInterface> *device) = 0;
+ virtual status_t getHalPids(std::vector<pid_t> *pids) = 0;
+
+ // Sets a DevicesFactoryHalCallback to notify the client.
+ // The callback can be only set once.
+ virtual status_t setCallbackOnce(sp<DevicesFactoryHalCallback> callback) = 0;
+
static sp<DevicesFactoryHalInterface> create();
protected:
diff --git a/media/libaudiohal/include/media/audiohal/EffectsFactoryHalInterface.h b/media/libaudiohal/include/media/audiohal/EffectsFactoryHalInterface.h
index 316a46c..3a76f9f 100644
--- a/media/libaudiohal/include/media/audiohal/EffectsFactoryHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/EffectsFactoryHalInterface.h
@@ -41,7 +41,7 @@
// To release the effect engine, it is necessary to release references
// to the returned effect object.
virtual status_t createEffect(const effect_uuid_t *pEffectUuid,
- int32_t sessionId, int32_t ioId,
+ int32_t sessionId, int32_t ioId, int32_t deviceId,
sp<EffectHalInterface> *effect) = 0;
virtual status_t dumpEffects(int fd) = 0;
diff --git a/media/libaudiohal/include/media/audiohal/FactoryHalHidl.h b/media/libaudiohal/include/media/audiohal/FactoryHalHidl.h
new file mode 100644
index 0000000..d353ed0
--- /dev/null
+++ b/media/libaudiohal/include/media/audiohal/FactoryHalHidl.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_FACTORY_HAL_HIDL_H
+#define ANDROID_HARDWARE_FACTORY_HAL_HIDL_H
+
+#include <string>
+
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+namespace detail {
+
+void* createPreferredImpl(const std::string& package, const std::string& interface);
+
+} // namespace detail
+
+/** @Return the preferred available implementation or nullptr if none are available. */
+template <class Interface>
+static sp<Interface> createPreferredImpl(const std::string& package, const std::string& interface) {
+ return sp<Interface>{static_cast<Interface*>(detail::createPreferredImpl(package, interface))};
+}
+
+} // namespace android
+
+#endif // ANDROID_HARDWARE_FACTORY_HAL_HIDL_H
diff --git a/media/libaudiohal/include/media/audiohal/StreamHalInterface.h b/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
index 6c3b21c..e30cb72 100644
--- a/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
@@ -101,6 +101,15 @@
virtual ~StreamOutHalInterfaceCallback() {}
};
+class StreamOutHalInterfaceEventCallback : public virtual RefBase {
+public:
+ virtual void onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs) = 0;
+
+protected:
+ StreamOutHalInterfaceEventCallback() {}
+ virtual ~StreamOutHalInterfaceEventCallback() {}
+};
+
class StreamOutHalInterface : public virtual StreamHalInterface {
public:
// Return the audio hardware driver estimated latency in milliseconds.
@@ -157,6 +166,8 @@
*/
virtual status_t updateSourceMetadata(const SourceMetadata& sourceMetadata) = 0;
+ virtual status_t setEventCallback(const sp<StreamOutHalInterfaceEventCallback>& callback) = 0;
+
protected:
virtual ~StreamOutHalInterface() {}
};
diff --git a/media/libaudioprocessing/Android.bp b/media/libaudioprocessing/Android.bp
index cb78063..39b0ceb 100644
--- a/media/libaudioprocessing/Android.bp
+++ b/media/libaudioprocessing/Android.bp
@@ -3,20 +3,13 @@
export_include_dirs: ["include"],
+ header_libs: ["libaudioclient_headers"],
+
shared_libs: [
- "libaudiohal",
"libaudioutils",
"libcutils",
"liblog",
- "libnbaio",
- "libnblog",
- "libsonic",
"libutils",
- "libvibrator",
- ],
-
- header_libs: [
- "libbase_headers",
],
cflags: [
@@ -26,6 +19,25 @@
// uncomment to disable NEON on architectures that actually do support NEON, for benchmarking
// "-DUSE_NEON=false",
],
+
+ arch: {
+ x86: {
+ avx2: {
+ cflags: [
+ "-mavx2",
+ "-mfma",
+ ],
+ },
+ },
+ x86_64: {
+ avx2: {
+ cflags: [
+ "-mavx2",
+ "-mfma",
+ ],
+ },
+ },
+ },
}
cc_library_shared {
@@ -33,18 +45,33 @@
defaults: ["libaudioprocessing_defaults"],
srcs: [
+ "AudioMixer.cpp",
"BufferProviders.cpp",
"RecordBufferConverter.cpp",
],
- whole_static_libs: ["libaudioprocessing_arm"],
+
+ header_libs: [
+ "libaudiohal_headers",
+ "libbase_headers",
+ "libmedia_headers"
+ ],
+
+ shared_libs: [
+ "libaudiohal",
+ "libsonic",
+ "libvibrator",
+ ],
+
+ whole_static_libs: ["libaudioprocessing_base"],
}
cc_library_static {
- name: "libaudioprocessing_arm",
+ name: "libaudioprocessing_base",
defaults: ["libaudioprocessing_defaults"],
+ vendor_available: true,
srcs: [
- "AudioMixer.cpp",
+ "AudioMixerBase.cpp",
"AudioResampler.cpp",
"AudioResamplerCubic.cpp",
"AudioResamplerSinc.cpp",
diff --git a/media/libaudioprocessing/AudioMixer.cpp b/media/libaudioprocessing/AudioMixer.cpp
index f7cc096..1a31420 100644
--- a/media/libaudioprocessing/AudioMixer.cpp
+++ b/media/libaudioprocessing/AudioMixer.cpp
@@ -18,6 +18,7 @@
#define LOG_TAG "AudioMixer"
//#define LOG_NDEBUG 0
+#include <sstream>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
@@ -27,9 +28,6 @@
#include <utils/Errors.h>
#include <utils/Log.h>
-#include <cutils/compiler.h>
-#include <utils/Debug.h>
-
#include <system/audio.h>
#include <audio_utils/primitives.h>
@@ -58,138 +56,15 @@
#define ALOGVV(a...) do { } while (0)
#endif
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
-#endif
-
-// Set kUseNewMixer to true to use the new mixer engine always. Otherwise the
-// original code will be used for stereo sinks, the new mixer for multichannel.
-static constexpr bool kUseNewMixer = true;
-
-// Set kUseFloat to true to allow floating input into the mixer engine.
-// If kUseNewMixer is false, this is ignored or may be overridden internally
-// because of downmix/upmix support.
-static constexpr bool kUseFloat = true;
-
-#ifdef FLOAT_AUX
-using TYPE_AUX = float;
-static_assert(kUseNewMixer && kUseFloat,
- "kUseNewMixer and kUseFloat must be true for FLOAT_AUX option");
-#else
-using TYPE_AUX = int32_t; // q4.27
-#endif
-
// Set to default copy buffer size in frames for input processing.
-static const size_t kCopyBufferFrameCount = 256;
+static constexpr size_t kCopyBufferFrameCount = 256;
namespace android {
// ----------------------------------------------------------------------------
-static inline audio_format_t selectMixerInFormat(audio_format_t inputFormat __unused) {
- return kUseFloat && kUseNewMixer ? AUDIO_FORMAT_PCM_FLOAT : AUDIO_FORMAT_PCM_16_BIT;
-}
-
-status_t AudioMixer::create(
- int name, audio_channel_mask_t channelMask, audio_format_t format, int sessionId)
-{
- LOG_ALWAYS_FATAL_IF(exists(name), "name %d already exists", name);
-
- if (!isValidChannelMask(channelMask)) {
- ALOGE("%s invalid channelMask: %#x", __func__, channelMask);
- return BAD_VALUE;
- }
- if (!isValidFormat(format)) {
- ALOGE("%s invalid format: %#x", __func__, format);
- return BAD_VALUE;
- }
-
- auto t = std::make_shared<Track>();
- {
- // TODO: move initialization to the Track constructor.
- // assume default parameters for the track, except where noted below
- t->needs = 0;
-
- // Integer volume.
- // Currently integer volume is kept for the legacy integer mixer.
- // Will be removed when the legacy mixer path is removed.
- t->volume[0] = 0;
- t->volume[1] = 0;
- t->prevVolume[0] = 0 << 16;
- t->prevVolume[1] = 0 << 16;
- t->volumeInc[0] = 0;
- t->volumeInc[1] = 0;
- t->auxLevel = 0;
- t->auxInc = 0;
- t->prevAuxLevel = 0;
-
- // Floating point volume.
- t->mVolume[0] = 0.f;
- t->mVolume[1] = 0.f;
- t->mPrevVolume[0] = 0.f;
- t->mPrevVolume[1] = 0.f;
- t->mVolumeInc[0] = 0.;
- t->mVolumeInc[1] = 0.;
- t->mAuxLevel = 0.;
- t->mAuxInc = 0.;
- t->mPrevAuxLevel = 0.;
-
- // no initialization needed
- // t->frameCount
- t->mHapticChannelMask = channelMask & AUDIO_CHANNEL_HAPTIC_ALL;
- t->mHapticChannelCount = audio_channel_count_from_out_mask(t->mHapticChannelMask);
- channelMask &= ~AUDIO_CHANNEL_HAPTIC_ALL;
- t->channelCount = audio_channel_count_from_out_mask(channelMask);
- t->enabled = false;
- ALOGV_IF(audio_channel_mask_get_bits(channelMask) != AUDIO_CHANNEL_OUT_STEREO,
- "Non-stereo channel mask: %d\n", channelMask);
- t->channelMask = channelMask;
- t->sessionId = sessionId;
- // setBufferProvider(name, AudioBufferProvider *) is required before enable(name)
- t->bufferProvider = NULL;
- t->buffer.raw = NULL;
- // no initialization needed
- // t->buffer.frameCount
- t->hook = NULL;
- t->mIn = NULL;
- t->sampleRate = mSampleRate;
- // setParameter(name, TRACK, MAIN_BUFFER, mixBuffer) is required before enable(name)
- t->mainBuffer = NULL;
- t->auxBuffer = NULL;
- t->mInputBufferProvider = NULL;
- t->mMixerFormat = AUDIO_FORMAT_PCM_16_BIT;
- t->mFormat = format;
- t->mMixerInFormat = selectMixerInFormat(format);
- t->mDownmixRequiresFormat = AUDIO_FORMAT_INVALID; // no format required
- t->mMixerChannelMask = audio_channel_mask_from_representation_and_bits(
- AUDIO_CHANNEL_REPRESENTATION_POSITION, AUDIO_CHANNEL_OUT_STEREO);
- t->mMixerChannelCount = audio_channel_count_from_out_mask(t->mMixerChannelMask);
- t->mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT;
- // haptic
- t->mHapticPlaybackEnabled = false;
- t->mHapticIntensity = HAPTIC_SCALE_NONE;
- t->mMixerHapticChannelMask = AUDIO_CHANNEL_NONE;
- t->mMixerHapticChannelCount = 0;
- t->mAdjustInChannelCount = t->channelCount + t->mHapticChannelCount;
- t->mAdjustOutChannelCount = t->channelCount + t->mMixerHapticChannelCount;
- t->mAdjustNonDestructiveInChannelCount = t->mAdjustOutChannelCount;
- t->mAdjustNonDestructiveOutChannelCount = t->channelCount;
- t->mKeepContractedChannels = false;
- // Check the downmixing (or upmixing) requirements.
- status_t status = t->prepareForDownmix();
- if (status != OK) {
- ALOGE("AudioMixer::getTrackName invalid channelMask (%#x)", channelMask);
- return BAD_VALUE;
- }
- // prepareForDownmix() may change mDownmixRequiresFormat
- ALOGVV("mMixerFormat:%#x mMixerInFormat:%#x\n", t->mMixerFormat, t->mMixerInFormat);
- t->prepareForReformat();
- t->prepareForAdjustChannelsNonDestructive(mFrameCount);
- t->prepareForAdjustChannels();
-
- mTracks[name] = t;
- return OK;
- }
+bool AudioMixer::isValidChannelMask(audio_channel_mask_t channelMask) const {
+ return audio_channel_mask_is_valid(channelMask); // the RemixBufferProvider is flexible.
}
// Called when channel masks have changed for a track name
@@ -198,7 +73,7 @@
bool AudioMixer::setChannelMasks(int name,
audio_channel_mask_t trackChannelMask, audio_channel_mask_t mixerChannelMask) {
LOG_ALWAYS_FATAL_IF(!exists(name), "invalid name: %d", name);
- const std::shared_ptr<Track> &track = mTracks[name];
+ const std::shared_ptr<Track> &track = getTrack(name);
if (trackChannelMask == (track->channelMask | track->mHapticChannelMask)
&& mixerChannelMask == (track->mMixerChannelMask | track->mMixerHapticChannelMask)) {
@@ -255,14 +130,8 @@
track->prepareForAdjustChannelsNonDestructive(mFrameCount);
track->prepareForAdjustChannels();
- if (track->mResampler.get() != nullptr) {
- // resampler channels may have changed.
- const uint32_t resetToSampleRate = track->sampleRate;
- track->mResampler.reset(nullptr);
- track->sampleRate = mSampleRate; // without resampler, track rate is device sample rate.
- // recreate the resampler with updated format, channels, saved sampleRate.
- track->setResampler(resetToSampleRate /*trackSampleRate*/, mSampleRate /*devSampleRate*/);
- }
+ // Resampler channels may have changed.
+ track->recreateResampler(mSampleRate);
return true;
}
@@ -293,10 +162,10 @@
// discard the previous downmixer if there was one
unprepareForDownmix();
// MONO_HACK Only remix (upmix or downmix) if the track and mixer/device channel masks
- // are not the same and not handled internally, as mono -> stereo currently is.
+ // are not the same and not handled internally, as mono for channel position masks is.
if (channelMask == mMixerChannelMask
|| (channelMask == AUDIO_CHANNEL_OUT_MONO
- && mMixerChannelMask == AUDIO_CHANNEL_OUT_STEREO)) {
+ && isAudioChannelPositionMask(mMixerChannelMask))) {
return NO_ERROR;
}
// DownmixerBufferProvider is only used for position masks.
@@ -477,171 +346,10 @@
}
}
-void AudioMixer::destroy(int name)
-{
- LOG_ALWAYS_FATAL_IF(!exists(name), "invalid name: %d", name);
- ALOGV("deleteTrackName(%d)", name);
-
- if (mTracks[name]->enabled) {
- invalidate();
- }
- mTracks.erase(name); // deallocate track
-}
-
-void AudioMixer::enable(int name)
-{
- LOG_ALWAYS_FATAL_IF(!exists(name), "invalid name: %d", name);
- const std::shared_ptr<Track> &track = mTracks[name];
-
- if (!track->enabled) {
- track->enabled = true;
- ALOGV("enable(%d)", name);
- invalidate();
- }
-}
-
-void AudioMixer::disable(int name)
-{
- LOG_ALWAYS_FATAL_IF(!exists(name), "invalid name: %d", name);
- const std::shared_ptr<Track> &track = mTracks[name];
-
- if (track->enabled) {
- track->enabled = false;
- ALOGV("disable(%d)", name);
- invalidate();
- }
-}
-
-/* Sets the volume ramp variables for the AudioMixer.
- *
- * The volume ramp variables are used to transition from the previous
- * volume to the set volume. ramp controls the duration of the transition.
- * Its value is typically one state framecount period, but may also be 0,
- * meaning "immediate."
- *
- * FIXME: 1) Volume ramp is enabled only if there is a nonzero integer increment
- * even if there is a nonzero floating point increment (in that case, the volume
- * change is immediate). This restriction should be changed when the legacy mixer
- * is removed (see #2).
- * FIXME: 2) Integer volume variables are used for Legacy mixing and should be removed
- * when no longer needed.
- *
- * @param newVolume set volume target in floating point [0.0, 1.0].
- * @param ramp number of frames to increment over. if ramp is 0, the volume
- * should be set immediately. Currently ramp should not exceed 65535 (frames).
- * @param pIntSetVolume pointer to the U4.12 integer target volume, set on return.
- * @param pIntPrevVolume pointer to the U4.28 integer previous volume, set on return.
- * @param pIntVolumeInc pointer to the U4.28 increment per output audio frame, set on return.
- * @param pSetVolume pointer to the float target volume, set on return.
- * @param pPrevVolume pointer to the float previous volume, set on return.
- * @param pVolumeInc pointer to the float increment per output audio frame, set on return.
- * @return true if the volume has changed, false if volume is same.
- */
-static inline bool setVolumeRampVariables(float newVolume, int32_t ramp,
- int16_t *pIntSetVolume, int32_t *pIntPrevVolume, int32_t *pIntVolumeInc,
- float *pSetVolume, float *pPrevVolume, float *pVolumeInc) {
- // check floating point volume to see if it is identical to the previously
- // set volume.
- // We do not use a tolerance here (and reject changes too small)
- // as it may be confusing to use a different value than the one set.
- // If the resulting volume is too small to ramp, it is a direct set of the volume.
- if (newVolume == *pSetVolume) {
- return false;
- }
- if (newVolume < 0) {
- newVolume = 0; // should not have negative volumes
- } else {
- switch (fpclassify(newVolume)) {
- case FP_SUBNORMAL:
- case FP_NAN:
- newVolume = 0;
- break;
- case FP_ZERO:
- break; // zero volume is fine
- case FP_INFINITE:
- // Infinite volume could be handled consistently since
- // floating point math saturates at infinities,
- // but we limit volume to unity gain float.
- // ramp = 0; break;
- //
- newVolume = AudioMixer::UNITY_GAIN_FLOAT;
- break;
- case FP_NORMAL:
- default:
- // Floating point does not have problems with overflow wrap
- // that integer has. However, we limit the volume to
- // unity gain here.
- // TODO: Revisit the volume limitation and perhaps parameterize.
- if (newVolume > AudioMixer::UNITY_GAIN_FLOAT) {
- newVolume = AudioMixer::UNITY_GAIN_FLOAT;
- }
- break;
- }
- }
-
- // set floating point volume ramp
- if (ramp != 0) {
- // when the ramp completes, *pPrevVolume is set to *pSetVolume, so there
- // is no computational mismatch; hence equality is checked here.
- ALOGD_IF(*pPrevVolume != *pSetVolume, "previous float ramp hasn't finished,"
- " prev:%f set_to:%f", *pPrevVolume, *pSetVolume);
- const float inc = (newVolume - *pPrevVolume) / ramp; // could be inf, nan, subnormal
- // could be inf, cannot be nan, subnormal
- const float maxv = std::max(newVolume, *pPrevVolume);
-
- if (isnormal(inc) // inc must be a normal number (no subnormals, infinite, nan)
- && maxv + inc != maxv) { // inc must make forward progress
- *pVolumeInc = inc;
- // ramp is set now.
- // Note: if newVolume is 0, then near the end of the ramp,
- // it may be possible that the ramped volume may be subnormal or
- // temporarily negative by a small amount or subnormal due to floating
- // point inaccuracies.
- } else {
- ramp = 0; // ramp not allowed
- }
- }
-
- // compute and check integer volume, no need to check negative values
- // The integer volume is limited to "unity_gain" to avoid wrapping and other
- // audio artifacts, so it never reaches the range limit of U4.28.
- // We safely use signed 16 and 32 bit integers here.
- const float scaledVolume = newVolume * AudioMixer::UNITY_GAIN_INT; // not neg, subnormal, nan
- const int32_t intVolume = (scaledVolume >= (float)AudioMixer::UNITY_GAIN_INT) ?
- AudioMixer::UNITY_GAIN_INT : (int32_t)scaledVolume;
-
- // set integer volume ramp
- if (ramp != 0) {
- // integer volume is U4.12 (to use 16 bit multiplies), but ramping uses U4.28.
- // when the ramp completes, *pIntPrevVolume is set to *pIntSetVolume << 16, so there
- // is no computational mismatch; hence equality is checked here.
- ALOGD_IF(*pIntPrevVolume != *pIntSetVolume << 16, "previous int ramp hasn't finished,"
- " prev:%d set_to:%d", *pIntPrevVolume, *pIntSetVolume << 16);
- const int32_t inc = ((intVolume << 16) - *pIntPrevVolume) / ramp;
-
- if (inc != 0) { // inc must make forward progress
- *pIntVolumeInc = inc;
- } else {
- ramp = 0; // ramp not allowed
- }
- }
-
- // if no ramp, or ramp not allowed, then clear float and integer increments
- if (ramp == 0) {
- *pVolumeInc = 0;
- *pPrevVolume = newVolume;
- *pIntVolumeInc = 0;
- *pIntPrevVolume = intVolume << 16;
- }
- *pSetVolume = newVolume;
- *pIntSetVolume = intVolume;
- return true;
-}
-
void AudioMixer::setParameter(int name, int target, int param, void *value)
{
LOG_ALWAYS_FATAL_IF(!exists(name), "invalid name: %d", name);
- const std::shared_ptr<Track> &track = mTracks[name];
+ const std::shared_ptr<Track> &track = getTrack(name);
int valueInt = static_cast<int>(reinterpret_cast<uintptr_t>(value));
int32_t *valueBuf = reinterpret_cast<int32_t*>(value);
@@ -670,11 +378,7 @@
}
break;
case AUX_BUFFER:
- if (track->auxBuffer != valueBuf) {
- track->auxBuffer = valueBuf;
- ALOGV("setParameter(TRACK, AUX_BUFFER, %p)", valueBuf);
- invalidate();
- }
+ AudioMixerBase::setParameter(name, target, param, value);
break;
case FORMAT: {
audio_format_t format = static_cast<audio_format_t>(valueInt);
@@ -730,127 +434,38 @@
break;
case RESAMPLE:
- switch (param) {
- case SAMPLE_RATE:
- ALOG_ASSERT(valueInt > 0, "bad sample rate %d", valueInt);
- if (track->setResampler(uint32_t(valueInt), mSampleRate)) {
- ALOGV("setParameter(RESAMPLE, SAMPLE_RATE, %u)",
- uint32_t(valueInt));
- invalidate();
- }
- break;
- case RESET:
- track->resetResampler();
- invalidate();
- break;
- case REMOVE:
- track->mResampler.reset(nullptr);
- track->sampleRate = mSampleRate;
- invalidate();
- break;
- default:
- LOG_ALWAYS_FATAL("setParameter resample: bad param %d", param);
- }
- break;
-
case RAMP_VOLUME:
case VOLUME:
+ AudioMixerBase::setParameter(name, target, param, value);
+ break;
+ case TIMESTRETCH:
switch (param) {
- case AUXLEVEL:
- if (setVolumeRampVariables(*reinterpret_cast<float*>(value),
- target == RAMP_VOLUME ? mFrameCount : 0,
- &track->auxLevel, &track->prevAuxLevel, &track->auxInc,
- &track->mAuxLevel, &track->mPrevAuxLevel, &track->mAuxInc)) {
- ALOGV("setParameter(%s, AUXLEVEL: %04x)",
- target == VOLUME ? "VOLUME" : "RAMP_VOLUME", track->auxLevel);
- invalidate();
+ case PLAYBACK_RATE: {
+ const AudioPlaybackRate *playbackRate =
+ reinterpret_cast<AudioPlaybackRate*>(value);
+ ALOGW_IF(!isAudioPlaybackRateValid(*playbackRate),
+ "bad parameters speed %f, pitch %f",
+ playbackRate->mSpeed, playbackRate->mPitch);
+ if (track->setPlaybackRate(*playbackRate)) {
+ ALOGV("setParameter(TIMESTRETCH, PLAYBACK_RATE, STRETCH_MODE, FALLBACK_MODE "
+ "%f %f %d %d",
+ playbackRate->mSpeed,
+ playbackRate->mPitch,
+ playbackRate->mStretchMode,
+ playbackRate->mFallbackMode);
+ // invalidate(); (should not require reconfigure)
}
- break;
+ } break;
default:
- if ((unsigned)param >= VOLUME0 && (unsigned)param < VOLUME0 + MAX_NUM_VOLUMES) {
- if (setVolumeRampVariables(*reinterpret_cast<float*>(value),
- target == RAMP_VOLUME ? mFrameCount : 0,
- &track->volume[param - VOLUME0],
- &track->prevVolume[param - VOLUME0],
- &track->volumeInc[param - VOLUME0],
- &track->mVolume[param - VOLUME0],
- &track->mPrevVolume[param - VOLUME0],
- &track->mVolumeInc[param - VOLUME0])) {
- ALOGV("setParameter(%s, VOLUME%d: %04x)",
- target == VOLUME ? "VOLUME" : "RAMP_VOLUME", param - VOLUME0,
- track->volume[param - VOLUME0]);
- invalidate();
- }
- } else {
- LOG_ALWAYS_FATAL("setParameter volume: bad param %d", param);
- }
+ LOG_ALWAYS_FATAL("setParameter timestretch: bad param %d", param);
}
break;
- case TIMESTRETCH:
- switch (param) {
- case PLAYBACK_RATE: {
- const AudioPlaybackRate *playbackRate =
- reinterpret_cast<AudioPlaybackRate*>(value);
- ALOGW_IF(!isAudioPlaybackRateValid(*playbackRate),
- "bad parameters speed %f, pitch %f",
- playbackRate->mSpeed, playbackRate->mPitch);
- if (track->setPlaybackRate(*playbackRate)) {
- ALOGV("setParameter(TIMESTRETCH, PLAYBACK_RATE, STRETCH_MODE, FALLBACK_MODE "
- "%f %f %d %d",
- playbackRate->mSpeed,
- playbackRate->mPitch,
- playbackRate->mStretchMode,
- playbackRate->mFallbackMode);
- // invalidate(); (should not require reconfigure)
- }
- } break;
- default:
- LOG_ALWAYS_FATAL("setParameter timestretch: bad param %d", param);
- }
- break;
default:
LOG_ALWAYS_FATAL("setParameter: bad target %d", target);
}
}
-bool AudioMixer::Track::setResampler(uint32_t trackSampleRate, uint32_t devSampleRate)
-{
- if (trackSampleRate != devSampleRate || mResampler.get() != nullptr) {
- if (sampleRate != trackSampleRate) {
- sampleRate = trackSampleRate;
- if (mResampler.get() == nullptr) {
- ALOGV("Creating resampler from track %d Hz to device %d Hz",
- trackSampleRate, devSampleRate);
- AudioResampler::src_quality quality;
- // force lowest quality level resampler if use case isn't music or video
- // FIXME this is flawed for dynamic sample rates, as we choose the resampler
- // quality level based on the initial ratio, but that could change later.
- // Should have a way to distinguish tracks with static ratios vs. dynamic ratios.
- if (isMusicRate(trackSampleRate)) {
- quality = AudioResampler::DEFAULT_QUALITY;
- } else {
- quality = AudioResampler::DYN_LOW_QUALITY;
- }
-
- // TODO: Remove MONO_HACK. Resampler sees #channels after the downmixer
- // but if none exists, it is the channel count (1 for mono).
- const int resamplerChannelCount = mDownmixerBufferProvider.get() != nullptr
- ? mMixerChannelCount : channelCount;
- ALOGVV("Creating resampler:"
- " format(%#x) channels(%d) devSampleRate(%u) quality(%d)\n",
- mMixerInFormat, resamplerChannelCount, devSampleRate, quality);
- mResampler.reset(AudioResampler::create(
- mMixerInFormat,
- resamplerChannelCount,
- devSampleRate, quality));
- }
- return true;
- }
- }
- return false;
-}
-
bool AudioMixer::Track::setPlaybackRate(const AudioPlaybackRate &playbackRate)
{
if ((mTimestretchBufferProvider.get() == nullptr &&
@@ -863,8 +478,7 @@
if (mTimestretchBufferProvider.get() == nullptr) {
// TODO: Remove MONO_HACK. Resampler sees #channels after the downmixer
// but if none exists, it is the channel count (1 for mono).
- const int timestretchChannelCount = mDownmixerBufferProvider.get() != nullptr
- ? mMixerChannelCount : channelCount;
+ const int timestretchChannelCount = getOutputChannelCount();
mTimestretchBufferProvider.reset(new TimestretchBufferProvider(timestretchChannelCount,
mMixerInFormat, sampleRate, playbackRate));
reconfigureBufferProviders();
@@ -875,84 +489,10 @@
return true;
}
-/* Checks to see if the volume ramp has completed and clears the increment
- * variables appropriately.
- *
- * FIXME: There is code to handle int/float ramp variable switchover should it not
- * complete within a mixer buffer processing call, but it is preferred to avoid switchover
- * due to precision issues. The switchover code is included for legacy code purposes
- * and can be removed once the integer volume is removed.
- *
- * It is not sufficient to clear only the volumeInc integer variable because
- * if one channel requires ramping, all channels are ramped.
- *
- * There is a bit of duplicated code here, but it keeps backward compatibility.
- */
-inline void AudioMixer::Track::adjustVolumeRamp(bool aux, bool useFloat)
-{
- if (useFloat) {
- for (uint32_t i = 0; i < MAX_NUM_VOLUMES; i++) {
- if ((mVolumeInc[i] > 0 && mPrevVolume[i] + mVolumeInc[i] >= mVolume[i]) ||
- (mVolumeInc[i] < 0 && mPrevVolume[i] + mVolumeInc[i] <= mVolume[i])) {
- volumeInc[i] = 0;
- prevVolume[i] = volume[i] << 16;
- mVolumeInc[i] = 0.;
- mPrevVolume[i] = mVolume[i];
- } else {
- //ALOGV("ramp: %f %f %f", mVolume[i], mPrevVolume[i], mVolumeInc[i]);
- prevVolume[i] = u4_28_from_float(mPrevVolume[i]);
- }
- }
- } else {
- for (uint32_t i = 0; i < MAX_NUM_VOLUMES; i++) {
- if (((volumeInc[i]>0) && (((prevVolume[i]+volumeInc[i])>>16) >= volume[i])) ||
- ((volumeInc[i]<0) && (((prevVolume[i]+volumeInc[i])>>16) <= volume[i]))) {
- volumeInc[i] = 0;
- prevVolume[i] = volume[i] << 16;
- mVolumeInc[i] = 0.;
- mPrevVolume[i] = mVolume[i];
- } else {
- //ALOGV("ramp: %d %d %d", volume[i] << 16, prevVolume[i], volumeInc[i]);
- mPrevVolume[i] = float_from_u4_28(prevVolume[i]);
- }
- }
- }
-
- if (aux) {
-#ifdef FLOAT_AUX
- if (useFloat) {
- if ((mAuxInc > 0.f && mPrevAuxLevel + mAuxInc >= mAuxLevel) ||
- (mAuxInc < 0.f && mPrevAuxLevel + mAuxInc <= mAuxLevel)) {
- auxInc = 0;
- prevAuxLevel = auxLevel << 16;
- mAuxInc = 0.f;
- mPrevAuxLevel = mAuxLevel;
- }
- } else
-#endif
- if ((auxInc > 0 && ((prevAuxLevel + auxInc) >> 16) >= auxLevel) ||
- (auxInc < 0 && ((prevAuxLevel + auxInc) >> 16) <= auxLevel)) {
- auxInc = 0;
- prevAuxLevel = auxLevel << 16;
- mAuxInc = 0.f;
- mPrevAuxLevel = mAuxLevel;
- }
- }
-}
-
-size_t AudioMixer::getUnreleasedFrames(int name) const
-{
- const auto it = mTracks.find(name);
- if (it != mTracks.end()) {
- return it->second->getUnreleasedFrames();
- }
- return 0;
-}
-
void AudioMixer::setBufferProvider(int name, AudioBufferProvider* bufferProvider)
{
LOG_ALWAYS_FATAL_IF(!exists(name), "invalid name: %d", name);
- const std::shared_ptr<Track> &track = mTracks[name];
+ const std::shared_ptr<Track> &track = getTrack(name);
if (track->mInputBufferProvider == bufferProvider) {
return; // don't reset any buffer providers if identical.
@@ -976,679 +516,6 @@
track->reconfigureBufferProviders();
}
-void AudioMixer::process__validate()
-{
- // TODO: fix all16BitsStereNoResample logic to
- // either properly handle muted tracks (it should ignore them)
- // or remove altogether as an obsolete optimization.
- bool all16BitsStereoNoResample = true;
- bool resampling = false;
- bool volumeRamp = false;
-
- mEnabled.clear();
- mGroups.clear();
- for (const auto &pair : mTracks) {
- const int name = pair.first;
- const std::shared_ptr<Track> &t = pair.second;
- if (!t->enabled) continue;
-
- mEnabled.emplace_back(name); // we add to mEnabled in order of name.
- mGroups[t->mainBuffer].emplace_back(name); // mGroups also in order of name.
-
- uint32_t n = 0;
- // FIXME can overflow (mask is only 3 bits)
- n |= NEEDS_CHANNEL_1 + t->channelCount - 1;
- if (t->doesResample()) {
- n |= NEEDS_RESAMPLE;
- }
- if (t->auxLevel != 0 && t->auxBuffer != NULL) {
- n |= NEEDS_AUX;
- }
-
- if (t->volumeInc[0]|t->volumeInc[1]) {
- volumeRamp = true;
- } else if (!t->doesResample() && t->volumeRL == 0) {
- n |= NEEDS_MUTE;
- }
- t->needs = n;
-
- if (n & NEEDS_MUTE) {
- t->hook = &Track::track__nop;
- } else {
- if (n & NEEDS_AUX) {
- all16BitsStereoNoResample = false;
- }
- if (n & NEEDS_RESAMPLE) {
- all16BitsStereoNoResample = false;
- resampling = true;
- t->hook = Track::getTrackHook(TRACKTYPE_RESAMPLE, t->mMixerChannelCount,
- t->mMixerInFormat, t->mMixerFormat);
- ALOGV_IF((n & NEEDS_CHANNEL_COUNT__MASK) > NEEDS_CHANNEL_2,
- "Track %d needs downmix + resample", name);
- } else {
- if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_1){
- t->hook = Track::getTrackHook(
- (t->mMixerChannelMask == AUDIO_CHANNEL_OUT_STEREO // TODO: MONO_HACK
- && t->channelMask == AUDIO_CHANNEL_OUT_MONO)
- ? TRACKTYPE_NORESAMPLEMONO : TRACKTYPE_NORESAMPLE,
- t->mMixerChannelCount,
- t->mMixerInFormat, t->mMixerFormat);
- all16BitsStereoNoResample = false;
- }
- if ((n & NEEDS_CHANNEL_COUNT__MASK) >= NEEDS_CHANNEL_2){
- t->hook = Track::getTrackHook(TRACKTYPE_NORESAMPLE, t->mMixerChannelCount,
- t->mMixerInFormat, t->mMixerFormat);
- ALOGV_IF((n & NEEDS_CHANNEL_COUNT__MASK) > NEEDS_CHANNEL_2,
- "Track %d needs downmix", name);
- }
- }
- }
- }
-
- // select the processing hooks
- mHook = &AudioMixer::process__nop;
- if (mEnabled.size() > 0) {
- if (resampling) {
- if (mOutputTemp.get() == nullptr) {
- mOutputTemp.reset(new int32_t[MAX_NUM_CHANNELS * mFrameCount]);
- }
- if (mResampleTemp.get() == nullptr) {
- mResampleTemp.reset(new int32_t[MAX_NUM_CHANNELS * mFrameCount]);
- }
- mHook = &AudioMixer::process__genericResampling;
- } else {
- // we keep temp arrays around.
- mHook = &AudioMixer::process__genericNoResampling;
- if (all16BitsStereoNoResample && !volumeRamp) {
- if (mEnabled.size() == 1) {
- const std::shared_ptr<Track> &t = mTracks[mEnabled[0]];
- if ((t->needs & NEEDS_MUTE) == 0) {
- // The check prevents a muted track from acquiring a process hook.
- //
- // This is dangerous if the track is MONO as that requires
- // special case handling due to implicit channel duplication.
- // Stereo or Multichannel should actually be fine here.
- mHook = getProcessHook(PROCESSTYPE_NORESAMPLEONETRACK,
- t->mMixerChannelCount, t->mMixerInFormat, t->mMixerFormat);
- }
- }
- }
- }
- }
-
- ALOGV("mixer configuration change: %zu "
- "all16BitsStereoNoResample=%d, resampling=%d, volumeRamp=%d",
- mEnabled.size(), all16BitsStereoNoResample, resampling, volumeRamp);
-
- process();
-
- // Now that the volume ramp has been done, set optimal state and
- // track hooks for subsequent mixer process
- if (mEnabled.size() > 0) {
- bool allMuted = true;
-
- for (const int name : mEnabled) {
- const std::shared_ptr<Track> &t = mTracks[name];
- if (!t->doesResample() && t->volumeRL == 0) {
- t->needs |= NEEDS_MUTE;
- t->hook = &Track::track__nop;
- } else {
- allMuted = false;
- }
- }
- if (allMuted) {
- mHook = &AudioMixer::process__nop;
- } else if (all16BitsStereoNoResample) {
- if (mEnabled.size() == 1) {
- //const int i = 31 - __builtin_clz(enabledTracks);
- const std::shared_ptr<Track> &t = mTracks[mEnabled[0]];
- // Muted single tracks handled by allMuted above.
- mHook = getProcessHook(PROCESSTYPE_NORESAMPLEONETRACK,
- t->mMixerChannelCount, t->mMixerInFormat, t->mMixerFormat);
- }
- }
- }
-}
-
-void AudioMixer::Track::track__genericResample(
- int32_t* out, size_t outFrameCount, int32_t* temp, int32_t* aux)
-{
- ALOGVV("track__genericResample\n");
- mResampler->setSampleRate(sampleRate);
-
- // ramp gain - resample to temp buffer and scale/mix in 2nd step
- if (aux != NULL) {
- // always resample with unity gain when sending to auxiliary buffer to be able
- // to apply send level after resampling
- mResampler->setVolume(UNITY_GAIN_FLOAT, UNITY_GAIN_FLOAT);
- memset(temp, 0, outFrameCount * mMixerChannelCount * sizeof(int32_t));
- mResampler->resample(temp, outFrameCount, bufferProvider);
- if (CC_UNLIKELY(volumeInc[0]|volumeInc[1]|auxInc)) {
- volumeRampStereo(out, outFrameCount, temp, aux);
- } else {
- volumeStereo(out, outFrameCount, temp, aux);
- }
- } else {
- if (CC_UNLIKELY(volumeInc[0]|volumeInc[1])) {
- mResampler->setVolume(UNITY_GAIN_FLOAT, UNITY_GAIN_FLOAT);
- memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t));
- mResampler->resample(temp, outFrameCount, bufferProvider);
- volumeRampStereo(out, outFrameCount, temp, aux);
- }
-
- // constant gain
- else {
- mResampler->setVolume(mVolume[0], mVolume[1]);
- mResampler->resample(out, outFrameCount, bufferProvider);
- }
- }
-}
-
-void AudioMixer::Track::track__nop(int32_t* out __unused,
- size_t outFrameCount __unused, int32_t* temp __unused, int32_t* aux __unused)
-{
-}
-
-void AudioMixer::Track::volumeRampStereo(
- int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux)
-{
- int32_t vl = prevVolume[0];
- int32_t vr = prevVolume[1];
- const int32_t vlInc = volumeInc[0];
- const int32_t vrInc = volumeInc[1];
-
- //ALOGD("[0] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
- // t, vlInc/65536.0f, vl/65536.0f, volume[0],
- // (vl + vlInc*frameCount)/65536.0f, frameCount);
-
- // ramp volume
- if (CC_UNLIKELY(aux != NULL)) {
- int32_t va = prevAuxLevel;
- const int32_t vaInc = auxInc;
- int32_t l;
- int32_t r;
-
- do {
- l = (*temp++ >> 12);
- r = (*temp++ >> 12);
- *out++ += (vl >> 16) * l;
- *out++ += (vr >> 16) * r;
- *aux++ += (va >> 17) * (l + r);
- vl += vlInc;
- vr += vrInc;
- va += vaInc;
- } while (--frameCount);
- prevAuxLevel = va;
- } else {
- do {
- *out++ += (vl >> 16) * (*temp++ >> 12);
- *out++ += (vr >> 16) * (*temp++ >> 12);
- vl += vlInc;
- vr += vrInc;
- } while (--frameCount);
- }
- prevVolume[0] = vl;
- prevVolume[1] = vr;
- adjustVolumeRamp(aux != NULL);
-}
-
-void AudioMixer::Track::volumeStereo(
- int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux)
-{
- const int16_t vl = volume[0];
- const int16_t vr = volume[1];
-
- if (CC_UNLIKELY(aux != NULL)) {
- const int16_t va = auxLevel;
- do {
- int16_t l = (int16_t)(*temp++ >> 12);
- int16_t r = (int16_t)(*temp++ >> 12);
- out[0] = mulAdd(l, vl, out[0]);
- int16_t a = (int16_t)(((int32_t)l + r) >> 1);
- out[1] = mulAdd(r, vr, out[1]);
- out += 2;
- aux[0] = mulAdd(a, va, aux[0]);
- aux++;
- } while (--frameCount);
- } else {
- do {
- int16_t l = (int16_t)(*temp++ >> 12);
- int16_t r = (int16_t)(*temp++ >> 12);
- out[0] = mulAdd(l, vl, out[0]);
- out[1] = mulAdd(r, vr, out[1]);
- out += 2;
- } while (--frameCount);
- }
-}
-
-void AudioMixer::Track::track__16BitsStereo(
- int32_t* out, size_t frameCount, int32_t* temp __unused, int32_t* aux)
-{
- ALOGVV("track__16BitsStereo\n");
- const int16_t *in = static_cast<const int16_t *>(mIn);
-
- if (CC_UNLIKELY(aux != NULL)) {
- int32_t l;
- int32_t r;
- // ramp gain
- if (CC_UNLIKELY(volumeInc[0]|volumeInc[1]|auxInc)) {
- int32_t vl = prevVolume[0];
- int32_t vr = prevVolume[1];
- int32_t va = prevAuxLevel;
- const int32_t vlInc = volumeInc[0];
- const int32_t vrInc = volumeInc[1];
- const int32_t vaInc = auxInc;
- // ALOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
- // t, vlInc/65536.0f, vl/65536.0f, volume[0],
- // (vl + vlInc*frameCount)/65536.0f, frameCount);
-
- do {
- l = (int32_t)*in++;
- r = (int32_t)*in++;
- *out++ += (vl >> 16) * l;
- *out++ += (vr >> 16) * r;
- *aux++ += (va >> 17) * (l + r);
- vl += vlInc;
- vr += vrInc;
- va += vaInc;
- } while (--frameCount);
-
- prevVolume[0] = vl;
- prevVolume[1] = vr;
- prevAuxLevel = va;
- adjustVolumeRamp(true);
- }
-
- // constant gain
- else {
- const uint32_t vrl = volumeRL;
- const int16_t va = (int16_t)auxLevel;
- do {
- uint32_t rl = *reinterpret_cast<const uint32_t *>(in);
- int16_t a = (int16_t)(((int32_t)in[0] + in[1]) >> 1);
- in += 2;
- out[0] = mulAddRL(1, rl, vrl, out[0]);
- out[1] = mulAddRL(0, rl, vrl, out[1]);
- out += 2;
- aux[0] = mulAdd(a, va, aux[0]);
- aux++;
- } while (--frameCount);
- }
- } else {
- // ramp gain
- if (CC_UNLIKELY(volumeInc[0]|volumeInc[1])) {
- int32_t vl = prevVolume[0];
- int32_t vr = prevVolume[1];
- const int32_t vlInc = volumeInc[0];
- const int32_t vrInc = volumeInc[1];
-
- // ALOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
- // t, vlInc/65536.0f, vl/65536.0f, volume[0],
- // (vl + vlInc*frameCount)/65536.0f, frameCount);
-
- do {
- *out++ += (vl >> 16) * (int32_t) *in++;
- *out++ += (vr >> 16) * (int32_t) *in++;
- vl += vlInc;
- vr += vrInc;
- } while (--frameCount);
-
- prevVolume[0] = vl;
- prevVolume[1] = vr;
- adjustVolumeRamp(false);
- }
-
- // constant gain
- else {
- const uint32_t vrl = volumeRL;
- do {
- uint32_t rl = *reinterpret_cast<const uint32_t *>(in);
- in += 2;
- out[0] = mulAddRL(1, rl, vrl, out[0]);
- out[1] = mulAddRL(0, rl, vrl, out[1]);
- out += 2;
- } while (--frameCount);
- }
- }
- mIn = in;
-}
-
-void AudioMixer::Track::track__16BitsMono(
- int32_t* out, size_t frameCount, int32_t* temp __unused, int32_t* aux)
-{
- ALOGVV("track__16BitsMono\n");
- const int16_t *in = static_cast<int16_t const *>(mIn);
-
- if (CC_UNLIKELY(aux != NULL)) {
- // ramp gain
- if (CC_UNLIKELY(volumeInc[0]|volumeInc[1]|auxInc)) {
- int32_t vl = prevVolume[0];
- int32_t vr = prevVolume[1];
- int32_t va = prevAuxLevel;
- const int32_t vlInc = volumeInc[0];
- const int32_t vrInc = volumeInc[1];
- const int32_t vaInc = auxInc;
-
- // ALOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
- // t, vlInc/65536.0f, vl/65536.0f, volume[0],
- // (vl + vlInc*frameCount)/65536.0f, frameCount);
-
- do {
- int32_t l = *in++;
- *out++ += (vl >> 16) * l;
- *out++ += (vr >> 16) * l;
- *aux++ += (va >> 16) * l;
- vl += vlInc;
- vr += vrInc;
- va += vaInc;
- } while (--frameCount);
-
- prevVolume[0] = vl;
- prevVolume[1] = vr;
- prevAuxLevel = va;
- adjustVolumeRamp(true);
- }
- // constant gain
- else {
- const int16_t vl = volume[0];
- const int16_t vr = volume[1];
- const int16_t va = (int16_t)auxLevel;
- do {
- int16_t l = *in++;
- out[0] = mulAdd(l, vl, out[0]);
- out[1] = mulAdd(l, vr, out[1]);
- out += 2;
- aux[0] = mulAdd(l, va, aux[0]);
- aux++;
- } while (--frameCount);
- }
- } else {
- // ramp gain
- if (CC_UNLIKELY(volumeInc[0]|volumeInc[1])) {
- int32_t vl = prevVolume[0];
- int32_t vr = prevVolume[1];
- const int32_t vlInc = volumeInc[0];
- const int32_t vrInc = volumeInc[1];
-
- // ALOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
- // t, vlInc/65536.0f, vl/65536.0f, volume[0],
- // (vl + vlInc*frameCount)/65536.0f, frameCount);
-
- do {
- int32_t l = *in++;
- *out++ += (vl >> 16) * l;
- *out++ += (vr >> 16) * l;
- vl += vlInc;
- vr += vrInc;
- } while (--frameCount);
-
- prevVolume[0] = vl;
- prevVolume[1] = vr;
- adjustVolumeRamp(false);
- }
- // constant gain
- else {
- const int16_t vl = volume[0];
- const int16_t vr = volume[1];
- do {
- int16_t l = *in++;
- out[0] = mulAdd(l, vl, out[0]);
- out[1] = mulAdd(l, vr, out[1]);
- out += 2;
- } while (--frameCount);
- }
- }
- mIn = in;
-}
-
-// no-op case
-void AudioMixer::process__nop()
-{
- ALOGVV("process__nop\n");
-
- for (const auto &pair : mGroups) {
- // process by group of tracks with same output buffer to
- // avoid multiple memset() on same buffer
- const auto &group = pair.second;
-
- const std::shared_ptr<Track> &t = mTracks[group[0]];
- memset(t->mainBuffer, 0,
- mFrameCount * audio_bytes_per_frame(
- t->mMixerChannelCount + t->mMixerHapticChannelCount, t->mMixerFormat));
-
- // now consume data
- for (const int name : group) {
- const std::shared_ptr<Track> &t = mTracks[name];
- size_t outFrames = mFrameCount;
- while (outFrames) {
- t->buffer.frameCount = outFrames;
- t->bufferProvider->getNextBuffer(&t->buffer);
- if (t->buffer.raw == NULL) break;
- outFrames -= t->buffer.frameCount;
- t->bufferProvider->releaseBuffer(&t->buffer);
- }
- }
- }
-}
-
-// generic code without resampling
-void AudioMixer::process__genericNoResampling()
-{
- ALOGVV("process__genericNoResampling\n");
- int32_t outTemp[BLOCKSIZE * MAX_NUM_CHANNELS] __attribute__((aligned(32)));
-
- for (const auto &pair : mGroups) {
- // process by group of tracks with same output main buffer to
- // avoid multiple memset() on same buffer
- const auto &group = pair.second;
-
- // acquire buffer
- for (const int name : group) {
- const std::shared_ptr<Track> &t = mTracks[name];
- t->buffer.frameCount = mFrameCount;
- t->bufferProvider->getNextBuffer(&t->buffer);
- t->frameCount = t->buffer.frameCount;
- t->mIn = t->buffer.raw;
- }
-
- int32_t *out = (int *)pair.first;
- size_t numFrames = 0;
- do {
- const size_t frameCount = std::min((size_t)BLOCKSIZE, mFrameCount - numFrames);
- memset(outTemp, 0, sizeof(outTemp));
- for (const int name : group) {
- const std::shared_ptr<Track> &t = mTracks[name];
- int32_t *aux = NULL;
- if (CC_UNLIKELY(t->needs & NEEDS_AUX)) {
- aux = t->auxBuffer + numFrames;
- }
- for (int outFrames = frameCount; outFrames > 0; ) {
- // t->in == nullptr can happen if the track was flushed just after having
- // been enabled for mixing.
- if (t->mIn == nullptr) {
- break;
- }
- size_t inFrames = (t->frameCount > outFrames)?outFrames:t->frameCount;
- if (inFrames > 0) {
- (t.get()->*t->hook)(
- outTemp + (frameCount - outFrames) * t->mMixerChannelCount,
- inFrames, mResampleTemp.get() /* naked ptr */, aux);
- t->frameCount -= inFrames;
- outFrames -= inFrames;
- if (CC_UNLIKELY(aux != NULL)) {
- aux += inFrames;
- }
- }
- if (t->frameCount == 0 && outFrames) {
- t->bufferProvider->releaseBuffer(&t->buffer);
- t->buffer.frameCount = (mFrameCount - numFrames) -
- (frameCount - outFrames);
- t->bufferProvider->getNextBuffer(&t->buffer);
- t->mIn = t->buffer.raw;
- if (t->mIn == nullptr) {
- break;
- }
- t->frameCount = t->buffer.frameCount;
- }
- }
- }
-
- const std::shared_ptr<Track> &t1 = mTracks[group[0]];
- convertMixerFormat(out, t1->mMixerFormat, outTemp, t1->mMixerInFormat,
- frameCount * t1->mMixerChannelCount);
- // TODO: fix ugly casting due to choice of out pointer type
- out = reinterpret_cast<int32_t*>((uint8_t*)out
- + frameCount * t1->mMixerChannelCount
- * audio_bytes_per_sample(t1->mMixerFormat));
- numFrames += frameCount;
- } while (numFrames < mFrameCount);
-
- // release each track's buffer
- for (const int name : group) {
- const std::shared_ptr<Track> &t = mTracks[name];
- t->bufferProvider->releaseBuffer(&t->buffer);
- }
- }
-}
-
-// generic code with resampling
-void AudioMixer::process__genericResampling()
-{
- ALOGVV("process__genericResampling\n");
- int32_t * const outTemp = mOutputTemp.get(); // naked ptr
- size_t numFrames = mFrameCount;
-
- for (const auto &pair : mGroups) {
- const auto &group = pair.second;
- const std::shared_ptr<Track> &t1 = mTracks[group[0]];
-
- // clear temp buffer
- memset(outTemp, 0, sizeof(*outTemp) * t1->mMixerChannelCount * mFrameCount);
- for (const int name : group) {
- const std::shared_ptr<Track> &t = mTracks[name];
- int32_t *aux = NULL;
- if (CC_UNLIKELY(t->needs & NEEDS_AUX)) {
- aux = t->auxBuffer;
- }
-
- // this is a little goofy, on the resampling case we don't
- // acquire/release the buffers because it's done by
- // the resampler.
- if (t->needs & NEEDS_RESAMPLE) {
- (t.get()->*t->hook)(outTemp, numFrames, mResampleTemp.get() /* naked ptr */, aux);
- } else {
-
- size_t outFrames = 0;
-
- while (outFrames < numFrames) {
- t->buffer.frameCount = numFrames - outFrames;
- t->bufferProvider->getNextBuffer(&t->buffer);
- t->mIn = t->buffer.raw;
- // t->mIn == nullptr can happen if the track was flushed just after having
- // been enabled for mixing.
- if (t->mIn == nullptr) break;
-
- (t.get()->*t->hook)(
- outTemp + outFrames * t->mMixerChannelCount, t->buffer.frameCount,
- mResampleTemp.get() /* naked ptr */,
- aux != nullptr ? aux + outFrames : nullptr);
- outFrames += t->buffer.frameCount;
-
- t->bufferProvider->releaseBuffer(&t->buffer);
- }
- }
- }
- convertMixerFormat(t1->mainBuffer, t1->mMixerFormat,
- outTemp, t1->mMixerInFormat, numFrames * t1->mMixerChannelCount);
- }
-}
-
-// one track, 16 bits stereo without resampling is the most common case
-void AudioMixer::process__oneTrack16BitsStereoNoResampling()
-{
- ALOGVV("process__oneTrack16BitsStereoNoResampling\n");
- LOG_ALWAYS_FATAL_IF(mEnabled.size() != 0,
- "%zu != 1 tracks enabled", mEnabled.size());
- const int name = mEnabled[0];
- const std::shared_ptr<Track> &t = mTracks[name];
-
- AudioBufferProvider::Buffer& b(t->buffer);
-
- int32_t* out = t->mainBuffer;
- float *fout = reinterpret_cast<float*>(out);
- size_t numFrames = mFrameCount;
-
- const int16_t vl = t->volume[0];
- const int16_t vr = t->volume[1];
- const uint32_t vrl = t->volumeRL;
- while (numFrames) {
- b.frameCount = numFrames;
- t->bufferProvider->getNextBuffer(&b);
- const int16_t *in = b.i16;
-
- // in == NULL can happen if the track was flushed just after having
- // been enabled for mixing.
- if (in == NULL || (((uintptr_t)in) & 3)) {
- if ( AUDIO_FORMAT_PCM_FLOAT == t->mMixerFormat ) {
- memset((char*)fout, 0, numFrames
- * t->mMixerChannelCount * audio_bytes_per_sample(t->mMixerFormat));
- } else {
- memset((char*)out, 0, numFrames
- * t->mMixerChannelCount * audio_bytes_per_sample(t->mMixerFormat));
- }
- ALOGE_IF((((uintptr_t)in) & 3),
- "process__oneTrack16BitsStereoNoResampling: misaligned buffer"
- " %p track %d, channels %d, needs %08x, volume %08x vfl %f vfr %f",
- in, name, t->channelCount, t->needs, vrl, t->mVolume[0], t->mVolume[1]);
- return;
- }
- size_t outFrames = b.frameCount;
-
- switch (t->mMixerFormat) {
- case AUDIO_FORMAT_PCM_FLOAT:
- do {
- uint32_t rl = *reinterpret_cast<const uint32_t *>(in);
- in += 2;
- int32_t l = mulRL(1, rl, vrl);
- int32_t r = mulRL(0, rl, vrl);
- *fout++ = float_from_q4_27(l);
- *fout++ = float_from_q4_27(r);
- // Note: In case of later int16_t sink output,
- // conversion and clamping is done by memcpy_to_i16_from_float().
- } while (--outFrames);
- break;
- case AUDIO_FORMAT_PCM_16_BIT:
- if (CC_UNLIKELY(uint32_t(vl) > UNITY_GAIN_INT || uint32_t(vr) > UNITY_GAIN_INT)) {
- // volume is boosted, so we might need to clamp even though
- // we process only one track.
- do {
- uint32_t rl = *reinterpret_cast<const uint32_t *>(in);
- in += 2;
- int32_t l = mulRL(1, rl, vrl) >> 12;
- int32_t r = mulRL(0, rl, vrl) >> 12;
- // clamping...
- l = clamp16(l);
- r = clamp16(r);
- *out++ = (r<<16) | (l & 0xFFFF);
- } while (--outFrames);
- } else {
- do {
- uint32_t rl = *reinterpret_cast<const uint32_t *>(in);
- in += 2;
- int32_t l = mulRL(1, rl, vrl) >> 12;
- int32_t r = mulRL(0, rl, vrl) >> 12;
- *out++ = (r<<16) | (l & 0xFFFF);
- } while (--outFrames);
- }
- break;
- default:
- LOG_ALWAYS_FATAL("bad mixer format: %d", t->mMixerFormat);
- }
- numFrames -= b.frameCount;
- t->bufferProvider->releaseBuffer(&b);
- }
-}
-
/*static*/ pthread_once_t AudioMixer::sOnceControl = PTHREAD_ONCE_INIT;
/*static*/ void AudioMixer::sInitRoutine()
@@ -1656,211 +523,71 @@
DownmixerBufferProvider::init(); // for the downmixer
}
-/* TODO: consider whether this level of optimization is necessary.
- * Perhaps just stick with a single for loop.
- */
-
-// Needs to derive a compile time constant (constexpr). Could be targeted to go
-// to a MONOVOL mixtype based on MAX_NUM_VOLUMES, but that's an unnecessary complication.
-#define MIXTYPE_MONOVOL(mixtype) ((mixtype) == MIXTYPE_MULTI ? MIXTYPE_MULTI_MONOVOL : \
- (mixtype) == MIXTYPE_MULTI_SAVEONLY ? MIXTYPE_MULTI_SAVEONLY_MONOVOL : (mixtype))
-
-/* MIXTYPE (see AudioMixerOps.h MIXTYPE_* enumeration)
- * TO: int32_t (Q4.27) or float
- * TI: int32_t (Q4.27) or int16_t (Q0.15) or float
- * TA: int32_t (Q4.27) or float
- */
-template <int MIXTYPE,
- typename TO, typename TI, typename TV, typename TA, typename TAV>
-static void volumeRampMulti(uint32_t channels, TO* out, size_t frameCount,
- const TI* in, TA* aux, TV *vol, const TV *volinc, TAV *vola, TAV volainc)
+std::shared_ptr<AudioMixerBase::TrackBase> AudioMixer::preCreateTrack()
{
- switch (channels) {
- case 1:
- volumeRampMulti<MIXTYPE, 1>(out, frameCount, in, aux, vol, volinc, vola, volainc);
- break;
- case 2:
- volumeRampMulti<MIXTYPE, 2>(out, frameCount, in, aux, vol, volinc, vola, volainc);
- break;
- case 3:
- volumeRampMulti<MIXTYPE_MONOVOL(MIXTYPE), 3>(out,
- frameCount, in, aux, vol, volinc, vola, volainc);
- break;
- case 4:
- volumeRampMulti<MIXTYPE_MONOVOL(MIXTYPE), 4>(out,
- frameCount, in, aux, vol, volinc, vola, volainc);
- break;
- case 5:
- volumeRampMulti<MIXTYPE_MONOVOL(MIXTYPE), 5>(out,
- frameCount, in, aux, vol, volinc, vola, volainc);
- break;
- case 6:
- volumeRampMulti<MIXTYPE_MONOVOL(MIXTYPE), 6>(out,
- frameCount, in, aux, vol, volinc, vola, volainc);
- break;
- case 7:
- volumeRampMulti<MIXTYPE_MONOVOL(MIXTYPE), 7>(out,
- frameCount, in, aux, vol, volinc, vola, volainc);
- break;
- case 8:
- volumeRampMulti<MIXTYPE_MONOVOL(MIXTYPE), 8>(out,
- frameCount, in, aux, vol, volinc, vola, volainc);
- break;
- }
+ return std::make_shared<Track>();
}
-/* MIXTYPE (see AudioMixerOps.h MIXTYPE_* enumeration)
- * TO: int32_t (Q4.27) or float
- * TI: int32_t (Q4.27) or int16_t (Q0.15) or float
- * TA: int32_t (Q4.27) or float
- */
-template <int MIXTYPE,
- typename TO, typename TI, typename TV, typename TA, typename TAV>
-static void volumeMulti(uint32_t channels, TO* out, size_t frameCount,
- const TI* in, TA* aux, const TV *vol, TAV vola)
+status_t AudioMixer::postCreateTrack(TrackBase *track)
{
- switch (channels) {
- case 1:
- volumeMulti<MIXTYPE, 1>(out, frameCount, in, aux, vol, vola);
- break;
- case 2:
- volumeMulti<MIXTYPE, 2>(out, frameCount, in, aux, vol, vola);
- break;
- case 3:
- volumeMulti<MIXTYPE_MONOVOL(MIXTYPE), 3>(out, frameCount, in, aux, vol, vola);
- break;
- case 4:
- volumeMulti<MIXTYPE_MONOVOL(MIXTYPE), 4>(out, frameCount, in, aux, vol, vola);
- break;
- case 5:
- volumeMulti<MIXTYPE_MONOVOL(MIXTYPE), 5>(out, frameCount, in, aux, vol, vola);
- break;
- case 6:
- volumeMulti<MIXTYPE_MONOVOL(MIXTYPE), 6>(out, frameCount, in, aux, vol, vola);
- break;
- case 7:
- volumeMulti<MIXTYPE_MONOVOL(MIXTYPE), 7>(out, frameCount, in, aux, vol, vola);
- break;
- case 8:
- volumeMulti<MIXTYPE_MONOVOL(MIXTYPE), 8>(out, frameCount, in, aux, vol, vola);
- break;
+ Track* t = static_cast<Track*>(track);
+
+ audio_channel_mask_t channelMask = t->channelMask;
+ t->mHapticChannelMask = channelMask & AUDIO_CHANNEL_HAPTIC_ALL;
+ t->mHapticChannelCount = audio_channel_count_from_out_mask(t->mHapticChannelMask);
+ channelMask &= ~AUDIO_CHANNEL_HAPTIC_ALL;
+ t->channelCount = audio_channel_count_from_out_mask(channelMask);
+ ALOGV_IF(audio_channel_mask_get_bits(channelMask) != AUDIO_CHANNEL_OUT_STEREO,
+ "Non-stereo channel mask: %d\n", channelMask);
+ t->channelMask = channelMask;
+ t->mInputBufferProvider = NULL;
+ t->mDownmixRequiresFormat = AUDIO_FORMAT_INVALID; // no format required
+ t->mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT;
+ // haptic
+ t->mHapticPlaybackEnabled = false;
+ t->mHapticIntensity = HAPTIC_SCALE_NONE;
+ t->mMixerHapticChannelMask = AUDIO_CHANNEL_NONE;
+ t->mMixerHapticChannelCount = 0;
+ t->mAdjustInChannelCount = t->channelCount + t->mHapticChannelCount;
+ t->mAdjustOutChannelCount = t->channelCount + t->mMixerHapticChannelCount;
+ t->mAdjustNonDestructiveInChannelCount = t->mAdjustOutChannelCount;
+ t->mAdjustNonDestructiveOutChannelCount = t->channelCount;
+ t->mKeepContractedChannels = false;
+ // Check the downmixing (or upmixing) requirements.
+ status_t status = t->prepareForDownmix();
+ if (status != OK) {
+ ALOGE("AudioMixer::getTrackName invalid channelMask (%#x)", channelMask);
+ return BAD_VALUE;
}
+ // prepareForDownmix() may change mDownmixRequiresFormat
+ ALOGVV("mMixerFormat:%#x mMixerInFormat:%#x\n", t->mMixerFormat, t->mMixerInFormat);
+ t->prepareForReformat();
+ t->prepareForAdjustChannelsNonDestructive(mFrameCount);
+ t->prepareForAdjustChannels();
+ return OK;
}
-/* MIXTYPE (see AudioMixerOps.h MIXTYPE_* enumeration)
- * USEFLOATVOL (set to true if float volume is used)
- * ADJUSTVOL (set to true if volume ramp parameters needs adjustment afterwards)
- * TO: int32_t (Q4.27) or float
- * TI: int32_t (Q4.27) or int16_t (Q0.15) or float
- * TA: int32_t (Q4.27) or float
- */
-template <int MIXTYPE, bool USEFLOATVOL, bool ADJUSTVOL,
- typename TO, typename TI, typename TA>
-void AudioMixer::Track::volumeMix(TO *out, size_t outFrames,
- const TI *in, TA *aux, bool ramp)
+void AudioMixer::preProcess()
{
- if (USEFLOATVOL) {
- if (ramp) {
- volumeRampMulti<MIXTYPE>(mMixerChannelCount, out, outFrames, in, aux,
- mPrevVolume, mVolumeInc,
-#ifdef FLOAT_AUX
- &mPrevAuxLevel, mAuxInc
-#else
- &prevAuxLevel, auxInc
-#endif
- );
- if (ADJUSTVOL) {
- adjustVolumeRamp(aux != NULL, true);
- }
- } else {
- volumeMulti<MIXTYPE>(mMixerChannelCount, out, outFrames, in, aux,
- mVolume,
-#ifdef FLOAT_AUX
- mAuxLevel
-#else
- auxLevel
-#endif
- );
- }
- } else {
- if (ramp) {
- volumeRampMulti<MIXTYPE>(mMixerChannelCount, out, outFrames, in, aux,
- prevVolume, volumeInc, &prevAuxLevel, auxInc);
- if (ADJUSTVOL) {
- adjustVolumeRamp(aux != NULL);
- }
- } else {
- volumeMulti<MIXTYPE>(mMixerChannelCount, out, outFrames, in, aux,
- volume, auxLevel);
+ for (const auto &pair : mTracks) {
+ // Clear contracted buffer before processing if contracted channels are saved
+ const std::shared_ptr<TrackBase> &tb = pair.second;
+ Track *t = static_cast<Track*>(tb.get());
+ if (t->mKeepContractedChannels) {
+ t->clearContractedBuffer();
}
}
}
-/* This process hook is called when there is a single track without
- * aux buffer, volume ramp, or resampling.
- * TODO: Update the hook selection: this can properly handle aux and ramp.
- *
- * MIXTYPE (see AudioMixerOps.h MIXTYPE_* enumeration)
- * TO: int32_t (Q4.27) or float
- * TI: int32_t (Q4.27) or int16_t (Q0.15) or float
- * TA: int32_t (Q4.27)
- */
-template <int MIXTYPE, typename TO, typename TI, typename TA>
-void AudioMixer::process__noResampleOneTrack()
+void AudioMixer::postProcess()
{
- ALOGVV("process__noResampleOneTrack\n");
- LOG_ALWAYS_FATAL_IF(mEnabled.size() != 1,
- "%zu != 1 tracks enabled", mEnabled.size());
- const std::shared_ptr<Track> &t = mTracks[mEnabled[0]];
- const uint32_t channels = t->mMixerChannelCount;
- TO* out = reinterpret_cast<TO*>(t->mainBuffer);
- TA* aux = reinterpret_cast<TA*>(t->auxBuffer);
- const bool ramp = t->needsRamp();
-
- for (size_t numFrames = mFrameCount; numFrames > 0; ) {
- AudioBufferProvider::Buffer& b(t->buffer);
- // get input buffer
- b.frameCount = numFrames;
- t->bufferProvider->getNextBuffer(&b);
- const TI *in = reinterpret_cast<TI*>(b.raw);
-
- // in == NULL can happen if the track was flushed just after having
- // been enabled for mixing.
- if (in == NULL || (((uintptr_t)in) & 3)) {
- memset(out, 0, numFrames
- * channels * audio_bytes_per_sample(t->mMixerFormat));
- ALOGE_IF((((uintptr_t)in) & 3), "process__noResampleOneTrack: bus error: "
- "buffer %p track %p, channels %d, needs %#x",
- in, &t, t->channelCount, t->needs);
- return;
- }
-
- const size_t outFrames = b.frameCount;
- t->volumeMix<MIXTYPE, is_same<TI, float>::value /* USEFLOATVOL */, false /* ADJUSTVOL */> (
- out, outFrames, in, aux, ramp);
-
- out += outFrames * channels;
- if (aux != NULL) {
- aux += outFrames;
- }
- numFrames -= b.frameCount;
-
- // release buffer
- t->bufferProvider->releaseBuffer(&b);
- }
- if (ramp) {
- t->adjustVolumeRamp(aux != NULL, is_same<TI, float>::value);
- }
-}
-
-void AudioMixer::processHapticData()
-{
+ // Process haptic data.
// Need to keep consistent with VibrationEffect.scale(int, float, int)
for (const auto &pair : mGroups) {
// process by group of tracks with same output main buffer.
const auto &group = pair.second;
for (const int name : group) {
- const std::shared_ptr<Track> &t = mTracks[name];
+ const std::shared_ptr<Track> &t = getTrack(name);
if (t->mHapticPlaybackEnabled) {
size_t sampleCount = mFrameCount * t->mMixerHapticChannelCount;
float gamma = t->getHapticScaleGamma();
@@ -1887,225 +614,5 @@
}
}
-/* This track hook is called to do resampling then mixing,
- * pulling from the track's upstream AudioBufferProvider.
- *
- * MIXTYPE (see AudioMixerOps.h MIXTYPE_* enumeration)
- * TO: int32_t (Q4.27) or float
- * TI: int32_t (Q4.27) or int16_t (Q0.15) or float
- * TA: int32_t (Q4.27) or float
- */
-template <int MIXTYPE, typename TO, typename TI, typename TA>
-void AudioMixer::Track::track__Resample(TO* out, size_t outFrameCount, TO* temp, TA* aux)
-{
- ALOGVV("track__Resample\n");
- mResampler->setSampleRate(sampleRate);
- const bool ramp = needsRamp();
- if (ramp || aux != NULL) {
- // if ramp: resample with unity gain to temp buffer and scale/mix in 2nd step.
- // if aux != NULL: resample with unity gain to temp buffer then apply send level.
-
- mResampler->setVolume(UNITY_GAIN_FLOAT, UNITY_GAIN_FLOAT);
- memset(temp, 0, outFrameCount * mMixerChannelCount * sizeof(TO));
- mResampler->resample((int32_t*)temp, outFrameCount, bufferProvider);
-
- volumeMix<MIXTYPE, is_same<TI, float>::value /* USEFLOATVOL */, true /* ADJUSTVOL */>(
- out, outFrameCount, temp, aux, ramp);
-
- } else { // constant volume gain
- mResampler->setVolume(mVolume[0], mVolume[1]);
- mResampler->resample((int32_t*)out, outFrameCount, bufferProvider);
- }
-}
-
-/* This track hook is called to mix a track, when no resampling is required.
- * The input buffer should be present in in.
- *
- * MIXTYPE (see AudioMixerOps.h MIXTYPE_* enumeration)
- * TO: int32_t (Q4.27) or float
- * TI: int32_t (Q4.27) or int16_t (Q0.15) or float
- * TA: int32_t (Q4.27) or float
- */
-template <int MIXTYPE, typename TO, typename TI, typename TA>
-void AudioMixer::Track::track__NoResample(TO* out, size_t frameCount, TO* temp __unused, TA* aux)
-{
- ALOGVV("track__NoResample\n");
- const TI *in = static_cast<const TI *>(mIn);
-
- volumeMix<MIXTYPE, is_same<TI, float>::value /* USEFLOATVOL */, true /* ADJUSTVOL */>(
- out, frameCount, in, aux, needsRamp());
-
- // MIXTYPE_MONOEXPAND reads a single input channel and expands to NCHAN output channels.
- // MIXTYPE_MULTI reads NCHAN input channels and places to NCHAN output channels.
- in += (MIXTYPE == MIXTYPE_MONOEXPAND) ? frameCount : frameCount * mMixerChannelCount;
- mIn = in;
-}
-
-/* The Mixer engine generates either int32_t (Q4_27) or float data.
- * We use this function to convert the engine buffers
- * to the desired mixer output format, either int16_t (Q.15) or float.
- */
-/* static */
-void AudioMixer::convertMixerFormat(void *out, audio_format_t mixerOutFormat,
- void *in, audio_format_t mixerInFormat, size_t sampleCount)
-{
- switch (mixerInFormat) {
- case AUDIO_FORMAT_PCM_FLOAT:
- switch (mixerOutFormat) {
- case AUDIO_FORMAT_PCM_FLOAT:
- memcpy(out, in, sampleCount * sizeof(float)); // MEMCPY. TODO optimize out
- break;
- case AUDIO_FORMAT_PCM_16_BIT:
- memcpy_to_i16_from_float((int16_t*)out, (float*)in, sampleCount);
- break;
- default:
- LOG_ALWAYS_FATAL("bad mixerOutFormat: %#x", mixerOutFormat);
- break;
- }
- break;
- case AUDIO_FORMAT_PCM_16_BIT:
- switch (mixerOutFormat) {
- case AUDIO_FORMAT_PCM_FLOAT:
- memcpy_to_float_from_q4_27((float*)out, (const int32_t*)in, sampleCount);
- break;
- case AUDIO_FORMAT_PCM_16_BIT:
- memcpy_to_i16_from_q4_27((int16_t*)out, (const int32_t*)in, sampleCount);
- break;
- default:
- LOG_ALWAYS_FATAL("bad mixerOutFormat: %#x", mixerOutFormat);
- break;
- }
- break;
- default:
- LOG_ALWAYS_FATAL("bad mixerInFormat: %#x", mixerInFormat);
- break;
- }
-}
-
-/* Returns the proper track hook to use for mixing the track into the output buffer.
- */
-/* static */
-AudioMixer::hook_t AudioMixer::Track::getTrackHook(int trackType, uint32_t channelCount,
- audio_format_t mixerInFormat, audio_format_t mixerOutFormat __unused)
-{
- if (!kUseNewMixer && channelCount == FCC_2 && mixerInFormat == AUDIO_FORMAT_PCM_16_BIT) {
- switch (trackType) {
- case TRACKTYPE_NOP:
- return &Track::track__nop;
- case TRACKTYPE_RESAMPLE:
- return &Track::track__genericResample;
- case TRACKTYPE_NORESAMPLEMONO:
- return &Track::track__16BitsMono;
- case TRACKTYPE_NORESAMPLE:
- return &Track::track__16BitsStereo;
- default:
- LOG_ALWAYS_FATAL("bad trackType: %d", trackType);
- break;
- }
- }
- LOG_ALWAYS_FATAL_IF(channelCount > MAX_NUM_CHANNELS);
- switch (trackType) {
- case TRACKTYPE_NOP:
- return &Track::track__nop;
- case TRACKTYPE_RESAMPLE:
- switch (mixerInFormat) {
- case AUDIO_FORMAT_PCM_FLOAT:
- return (AudioMixer::hook_t) &Track::track__Resample<
- MIXTYPE_MULTI, float /*TO*/, float /*TI*/, TYPE_AUX>;
- case AUDIO_FORMAT_PCM_16_BIT:
- return (AudioMixer::hook_t) &Track::track__Resample<
- MIXTYPE_MULTI, int32_t /*TO*/, int16_t /*TI*/, TYPE_AUX>;
- default:
- LOG_ALWAYS_FATAL("bad mixerInFormat: %#x", mixerInFormat);
- break;
- }
- break;
- case TRACKTYPE_NORESAMPLEMONO:
- switch (mixerInFormat) {
- case AUDIO_FORMAT_PCM_FLOAT:
- return (AudioMixer::hook_t) &Track::track__NoResample<
- MIXTYPE_MONOEXPAND, float /*TO*/, float /*TI*/, TYPE_AUX>;
- case AUDIO_FORMAT_PCM_16_BIT:
- return (AudioMixer::hook_t) &Track::track__NoResample<
- MIXTYPE_MONOEXPAND, int32_t /*TO*/, int16_t /*TI*/, TYPE_AUX>;
- default:
- LOG_ALWAYS_FATAL("bad mixerInFormat: %#x", mixerInFormat);
- break;
- }
- break;
- case TRACKTYPE_NORESAMPLE:
- switch (mixerInFormat) {
- case AUDIO_FORMAT_PCM_FLOAT:
- return (AudioMixer::hook_t) &Track::track__NoResample<
- MIXTYPE_MULTI, float /*TO*/, float /*TI*/, TYPE_AUX>;
- case AUDIO_FORMAT_PCM_16_BIT:
- return (AudioMixer::hook_t) &Track::track__NoResample<
- MIXTYPE_MULTI, int32_t /*TO*/, int16_t /*TI*/, TYPE_AUX>;
- default:
- LOG_ALWAYS_FATAL("bad mixerInFormat: %#x", mixerInFormat);
- break;
- }
- break;
- default:
- LOG_ALWAYS_FATAL("bad trackType: %d", trackType);
- break;
- }
- return NULL;
-}
-
-/* Returns the proper process hook for mixing tracks. Currently works only for
- * PROCESSTYPE_NORESAMPLEONETRACK, a mix involving one track, no resampling.
- *
- * TODO: Due to the special mixing considerations of duplicating to
- * a stereo output track, the input track cannot be MONO. This should be
- * prevented by the caller.
- */
-/* static */
-AudioMixer::process_hook_t AudioMixer::getProcessHook(
- int processType, uint32_t channelCount,
- audio_format_t mixerInFormat, audio_format_t mixerOutFormat)
-{
- if (processType != PROCESSTYPE_NORESAMPLEONETRACK) { // Only NORESAMPLEONETRACK
- LOG_ALWAYS_FATAL("bad processType: %d", processType);
- return NULL;
- }
- if (!kUseNewMixer && channelCount == FCC_2 && mixerInFormat == AUDIO_FORMAT_PCM_16_BIT) {
- return &AudioMixer::process__oneTrack16BitsStereoNoResampling;
- }
- LOG_ALWAYS_FATAL_IF(channelCount > MAX_NUM_CHANNELS);
- switch (mixerInFormat) {
- case AUDIO_FORMAT_PCM_FLOAT:
- switch (mixerOutFormat) {
- case AUDIO_FORMAT_PCM_FLOAT:
- return &AudioMixer::process__noResampleOneTrack<
- MIXTYPE_MULTI_SAVEONLY, float /*TO*/, float /*TI*/, TYPE_AUX>;
- case AUDIO_FORMAT_PCM_16_BIT:
- return &AudioMixer::process__noResampleOneTrack<
- MIXTYPE_MULTI_SAVEONLY, int16_t /*TO*/, float /*TI*/, TYPE_AUX>;
- default:
- LOG_ALWAYS_FATAL("bad mixerOutFormat: %#x", mixerOutFormat);
- break;
- }
- break;
- case AUDIO_FORMAT_PCM_16_BIT:
- switch (mixerOutFormat) {
- case AUDIO_FORMAT_PCM_FLOAT:
- return &AudioMixer::process__noResampleOneTrack<
- MIXTYPE_MULTI_SAVEONLY, float /*TO*/, int16_t /*TI*/, TYPE_AUX>;
- case AUDIO_FORMAT_PCM_16_BIT:
- return &AudioMixer::process__noResampleOneTrack<
- MIXTYPE_MULTI_SAVEONLY, int16_t /*TO*/, int16_t /*TI*/, TYPE_AUX>;
- default:
- LOG_ALWAYS_FATAL("bad mixerOutFormat: %#x", mixerOutFormat);
- break;
- }
- break;
- default:
- LOG_ALWAYS_FATAL("bad mixerInFormat: %#x", mixerInFormat);
- break;
- }
- return NULL;
-}
-
// ----------------------------------------------------------------------------
} // namespace android
diff --git a/media/libaudioprocessing/AudioMixerBase.cpp b/media/libaudioprocessing/AudioMixerBase.cpp
new file mode 100644
index 0000000..64f91fe
--- /dev/null
+++ b/media/libaudioprocessing/AudioMixerBase.cpp
@@ -0,0 +1,1803 @@
+/*
+**
+** Copyright 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.
+*/
+
+#define LOG_TAG "AudioMixer"
+//#define LOG_NDEBUG 0
+
+#include <sstream>
+#include <string.h>
+
+#include <audio_utils/primitives.h>
+#include <cutils/compiler.h>
+#include <media/AudioMixerBase.h>
+#include <utils/Log.h>
+
+#include "AudioMixerOps.h"
+
+// The FCC_2 macro refers to the Fixed Channel Count of 2 for the legacy integer mixer.
+#ifndef FCC_2
+#define FCC_2 2
+#endif
+
+// Look for MONO_HACK for any Mono hack involving legacy mono channel to
+// stereo channel conversion.
+
+/* VERY_VERY_VERBOSE_LOGGING will show exactly which process hook and track hook is
+ * being used. This is a considerable amount of log spam, so don't enable unless you
+ * are verifying the hook based code.
+ */
+//#define VERY_VERY_VERBOSE_LOGGING
+#ifdef VERY_VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+//define ALOGVV printf // for test-mixer.cpp
+#else
+#define ALOGVV(a...) do { } while (0)
+#endif
+
+// TODO: remove BLOCKSIZE unit of processing - it isn't needed anymore.
+static constexpr int BLOCKSIZE = 16;
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+bool AudioMixerBase::isValidFormat(audio_format_t format) const
+{
+ switch (format) {
+ case AUDIO_FORMAT_PCM_8_BIT:
+ case AUDIO_FORMAT_PCM_16_BIT:
+ case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+ case AUDIO_FORMAT_PCM_32_BIT:
+ case AUDIO_FORMAT_PCM_FLOAT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool AudioMixerBase::isValidChannelMask(audio_channel_mask_t channelMask) const
+{
+ return audio_channel_count_from_out_mask(channelMask) <= MAX_NUM_CHANNELS;
+}
+
+std::shared_ptr<AudioMixerBase::TrackBase> AudioMixerBase::preCreateTrack()
+{
+ return std::make_shared<TrackBase>();
+}
+
+status_t AudioMixerBase::create(
+ int name, audio_channel_mask_t channelMask, audio_format_t format, int sessionId)
+{
+ LOG_ALWAYS_FATAL_IF(exists(name), "name %d already exists", name);
+
+ if (!isValidChannelMask(channelMask)) {
+ ALOGE("%s invalid channelMask: %#x", __func__, channelMask);
+ return BAD_VALUE;
+ }
+ if (!isValidFormat(format)) {
+ ALOGE("%s invalid format: %#x", __func__, format);
+ return BAD_VALUE;
+ }
+
+ auto t = preCreateTrack();
+ {
+ // TODO: move initialization to the Track constructor.
+ // assume default parameters for the track, except where noted below
+ t->needs = 0;
+
+ // Integer volume.
+ // Currently integer volume is kept for the legacy integer mixer.
+ // Will be removed when the legacy mixer path is removed.
+ t->volume[0] = 0;
+ t->volume[1] = 0;
+ t->prevVolume[0] = 0 << 16;
+ t->prevVolume[1] = 0 << 16;
+ t->volumeInc[0] = 0;
+ t->volumeInc[1] = 0;
+ t->auxLevel = 0;
+ t->auxInc = 0;
+ t->prevAuxLevel = 0;
+
+ // Floating point volume.
+ t->mVolume[0] = 0.f;
+ t->mVolume[1] = 0.f;
+ t->mPrevVolume[0] = 0.f;
+ t->mPrevVolume[1] = 0.f;
+ t->mVolumeInc[0] = 0.;
+ t->mVolumeInc[1] = 0.;
+ t->mAuxLevel = 0.;
+ t->mAuxInc = 0.;
+ t->mPrevAuxLevel = 0.;
+
+ // no initialization needed
+ // t->frameCount
+ t->channelCount = audio_channel_count_from_out_mask(channelMask);
+ t->enabled = false;
+ ALOGV_IF(audio_channel_mask_get_bits(channelMask) != AUDIO_CHANNEL_OUT_STEREO,
+ "Non-stereo channel mask: %d\n", channelMask);
+ t->channelMask = channelMask;
+ t->sessionId = sessionId;
+ // setBufferProvider(name, AudioBufferProvider *) is required before enable(name)
+ t->bufferProvider = NULL;
+ t->buffer.raw = NULL;
+ // no initialization needed
+ // t->buffer.frameCount
+ t->hook = NULL;
+ t->mIn = NULL;
+ t->sampleRate = mSampleRate;
+ // setParameter(name, TRACK, MAIN_BUFFER, mixBuffer) is required before enable(name)
+ t->mainBuffer = NULL;
+ t->auxBuffer = NULL;
+ t->mMixerFormat = AUDIO_FORMAT_PCM_16_BIT;
+ t->mFormat = format;
+ t->mMixerInFormat = kUseFloat && kUseNewMixer ?
+ AUDIO_FORMAT_PCM_FLOAT : AUDIO_FORMAT_PCM_16_BIT;
+ t->mMixerChannelMask = audio_channel_mask_from_representation_and_bits(
+ AUDIO_CHANNEL_REPRESENTATION_POSITION, AUDIO_CHANNEL_OUT_STEREO);
+ t->mMixerChannelCount = audio_channel_count_from_out_mask(t->mMixerChannelMask);
+ status_t status = postCreateTrack(t.get());
+ if (status != OK) return status;
+ mTracks[name] = t;
+ return OK;
+ }
+}
+
+// Called when channel masks have changed for a track name
+bool AudioMixerBase::setChannelMasks(int name,
+ audio_channel_mask_t trackChannelMask, audio_channel_mask_t mixerChannelMask)
+{
+ LOG_ALWAYS_FATAL_IF(!exists(name), "invalid name: %d", name);
+ const std::shared_ptr<TrackBase> &track = mTracks[name];
+
+ if (trackChannelMask == track->channelMask && mixerChannelMask == track->mMixerChannelMask) {
+ return false; // no need to change
+ }
+ // always recompute for both channel masks even if only one has changed.
+ const uint32_t trackChannelCount = audio_channel_count_from_out_mask(trackChannelMask);
+ const uint32_t mixerChannelCount = audio_channel_count_from_out_mask(mixerChannelMask);
+
+ ALOG_ASSERT(trackChannelCount && mixerChannelCount);
+ track->channelMask = trackChannelMask;
+ track->channelCount = trackChannelCount;
+ track->mMixerChannelMask = mixerChannelMask;
+ track->mMixerChannelCount = mixerChannelCount;
+
+ // Resampler channels may have changed.
+ track->recreateResampler(mSampleRate);
+ return true;
+}
+
+void AudioMixerBase::destroy(int name)
+{
+ LOG_ALWAYS_FATAL_IF(!exists(name), "invalid name: %d", name);
+ ALOGV("deleteTrackName(%d)", name);
+
+ if (mTracks[name]->enabled) {
+ invalidate();
+ }
+ mTracks.erase(name); // deallocate track
+}
+
+void AudioMixerBase::enable(int name)
+{
+ LOG_ALWAYS_FATAL_IF(!exists(name), "invalid name: %d", name);
+ const std::shared_ptr<TrackBase> &track = mTracks[name];
+
+ if (!track->enabled) {
+ track->enabled = true;
+ ALOGV("enable(%d)", name);
+ invalidate();
+ }
+}
+
+void AudioMixerBase::disable(int name)
+{
+ LOG_ALWAYS_FATAL_IF(!exists(name), "invalid name: %d", name);
+ const std::shared_ptr<TrackBase> &track = mTracks[name];
+
+ if (track->enabled) {
+ track->enabled = false;
+ ALOGV("disable(%d)", name);
+ invalidate();
+ }
+}
+
+/* Sets the volume ramp variables for the AudioMixer.
+ *
+ * The volume ramp variables are used to transition from the previous
+ * volume to the set volume. ramp controls the duration of the transition.
+ * Its value is typically one state framecount period, but may also be 0,
+ * meaning "immediate."
+ *
+ * FIXME: 1) Volume ramp is enabled only if there is a nonzero integer increment
+ * even if there is a nonzero floating point increment (in that case, the volume
+ * change is immediate). This restriction should be changed when the legacy mixer
+ * is removed (see #2).
+ * FIXME: 2) Integer volume variables are used for Legacy mixing and should be removed
+ * when no longer needed.
+ *
+ * @param newVolume set volume target in floating point [0.0, 1.0].
+ * @param ramp number of frames to increment over. if ramp is 0, the volume
+ * should be set immediately. Currently ramp should not exceed 65535 (frames).
+ * @param pIntSetVolume pointer to the U4.12 integer target volume, set on return.
+ * @param pIntPrevVolume pointer to the U4.28 integer previous volume, set on return.
+ * @param pIntVolumeInc pointer to the U4.28 increment per output audio frame, set on return.
+ * @param pSetVolume pointer to the float target volume, set on return.
+ * @param pPrevVolume pointer to the float previous volume, set on return.
+ * @param pVolumeInc pointer to the float increment per output audio frame, set on return.
+ * @return true if the volume has changed, false if volume is same.
+ */
+static inline bool setVolumeRampVariables(float newVolume, int32_t ramp,
+ int16_t *pIntSetVolume, int32_t *pIntPrevVolume, int32_t *pIntVolumeInc,
+ float *pSetVolume, float *pPrevVolume, float *pVolumeInc) {
+ // check floating point volume to see if it is identical to the previously
+ // set volume.
+ // We do not use a tolerance here (and reject changes too small)
+ // as it may be confusing to use a different value than the one set.
+ // If the resulting volume is too small to ramp, it is a direct set of the volume.
+ if (newVolume == *pSetVolume) {
+ return false;
+ }
+ if (newVolume < 0) {
+ newVolume = 0; // should not have negative volumes
+ } else {
+ switch (fpclassify(newVolume)) {
+ case FP_SUBNORMAL:
+ case FP_NAN:
+ newVolume = 0;
+ break;
+ case FP_ZERO:
+ break; // zero volume is fine
+ case FP_INFINITE:
+ // Infinite volume could be handled consistently since
+ // floating point math saturates at infinities,
+ // but we limit volume to unity gain float.
+ // ramp = 0; break;
+ //
+ newVolume = AudioMixerBase::UNITY_GAIN_FLOAT;
+ break;
+ case FP_NORMAL:
+ default:
+ // Floating point does not have problems with overflow wrap
+ // that integer has. However, we limit the volume to
+ // unity gain here.
+ // TODO: Revisit the volume limitation and perhaps parameterize.
+ if (newVolume > AudioMixerBase::UNITY_GAIN_FLOAT) {
+ newVolume = AudioMixerBase::UNITY_GAIN_FLOAT;
+ }
+ break;
+ }
+ }
+
+ // set floating point volume ramp
+ if (ramp != 0) {
+ // when the ramp completes, *pPrevVolume is set to *pSetVolume, so there
+ // is no computational mismatch; hence equality is checked here.
+ ALOGD_IF(*pPrevVolume != *pSetVolume, "previous float ramp hasn't finished,"
+ " prev:%f set_to:%f", *pPrevVolume, *pSetVolume);
+ const float inc = (newVolume - *pPrevVolume) / ramp; // could be inf, nan, subnormal
+ // could be inf, cannot be nan, subnormal
+ const float maxv = std::max(newVolume, *pPrevVolume);
+
+ if (isnormal(inc) // inc must be a normal number (no subnormals, infinite, nan)
+ && maxv + inc != maxv) { // inc must make forward progress
+ *pVolumeInc = inc;
+ // ramp is set now.
+ // Note: if newVolume is 0, then near the end of the ramp,
+ // it may be possible that the ramped volume may be subnormal or
+ // temporarily negative by a small amount or subnormal due to floating
+ // point inaccuracies.
+ } else {
+ ramp = 0; // ramp not allowed
+ }
+ }
+
+ // compute and check integer volume, no need to check negative values
+ // The integer volume is limited to "unity_gain" to avoid wrapping and other
+ // audio artifacts, so it never reaches the range limit of U4.28.
+ // We safely use signed 16 and 32 bit integers here.
+ const float scaledVolume = newVolume * AudioMixerBase::UNITY_GAIN_INT; // not neg, subnormal, nan
+ const int32_t intVolume = (scaledVolume >= (float)AudioMixerBase::UNITY_GAIN_INT) ?
+ AudioMixerBase::UNITY_GAIN_INT : (int32_t)scaledVolume;
+
+ // set integer volume ramp
+ if (ramp != 0) {
+ // integer volume is U4.12 (to use 16 bit multiplies), but ramping uses U4.28.
+ // when the ramp completes, *pIntPrevVolume is set to *pIntSetVolume << 16, so there
+ // is no computational mismatch; hence equality is checked here.
+ ALOGD_IF(*pIntPrevVolume != *pIntSetVolume << 16, "previous int ramp hasn't finished,"
+ " prev:%d set_to:%d", *pIntPrevVolume, *pIntSetVolume << 16);
+ const int32_t inc = ((intVolume << 16) - *pIntPrevVolume) / ramp;
+
+ if (inc != 0) { // inc must make forward progress
+ *pIntVolumeInc = inc;
+ } else {
+ ramp = 0; // ramp not allowed
+ }
+ }
+
+ // if no ramp, or ramp not allowed, then clear float and integer increments
+ if (ramp == 0) {
+ *pVolumeInc = 0;
+ *pPrevVolume = newVolume;
+ *pIntVolumeInc = 0;
+ *pIntPrevVolume = intVolume << 16;
+ }
+ *pSetVolume = newVolume;
+ *pIntSetVolume = intVolume;
+ return true;
+}
+
+void AudioMixerBase::setParameter(int name, int target, int param, void *value)
+{
+ LOG_ALWAYS_FATAL_IF(!exists(name), "invalid name: %d", name);
+ const std::shared_ptr<TrackBase> &track = mTracks[name];
+
+ int valueInt = static_cast<int>(reinterpret_cast<uintptr_t>(value));
+ int32_t *valueBuf = reinterpret_cast<int32_t*>(value);
+
+ switch (target) {
+
+ case TRACK:
+ switch (param) {
+ case CHANNEL_MASK: {
+ const audio_channel_mask_t trackChannelMask =
+ static_cast<audio_channel_mask_t>(valueInt);
+ if (setChannelMasks(name, trackChannelMask, track->mMixerChannelMask)) {
+ ALOGV("setParameter(TRACK, CHANNEL_MASK, %x)", trackChannelMask);
+ invalidate();
+ }
+ } break;
+ case MAIN_BUFFER:
+ if (track->mainBuffer != valueBuf) {
+ track->mainBuffer = valueBuf;
+ ALOGV("setParameter(TRACK, MAIN_BUFFER, %p)", valueBuf);
+ invalidate();
+ }
+ break;
+ case AUX_BUFFER:
+ if (track->auxBuffer != valueBuf) {
+ track->auxBuffer = valueBuf;
+ ALOGV("setParameter(TRACK, AUX_BUFFER, %p)", valueBuf);
+ invalidate();
+ }
+ break;
+ case FORMAT: {
+ audio_format_t format = static_cast<audio_format_t>(valueInt);
+ if (track->mFormat != format) {
+ ALOG_ASSERT(audio_is_linear_pcm(format), "Invalid format %#x", format);
+ track->mFormat = format;
+ ALOGV("setParameter(TRACK, FORMAT, %#x)", format);
+ invalidate();
+ }
+ } break;
+ case MIXER_FORMAT: {
+ audio_format_t format = static_cast<audio_format_t>(valueInt);
+ if (track->mMixerFormat != format) {
+ track->mMixerFormat = format;
+ ALOGV("setParameter(TRACK, MIXER_FORMAT, %#x)", format);
+ }
+ } break;
+ case MIXER_CHANNEL_MASK: {
+ const audio_channel_mask_t mixerChannelMask =
+ static_cast<audio_channel_mask_t>(valueInt);
+ if (setChannelMasks(name, track->channelMask, mixerChannelMask)) {
+ ALOGV("setParameter(TRACK, MIXER_CHANNEL_MASK, %#x)", mixerChannelMask);
+ invalidate();
+ }
+ } break;
+ default:
+ LOG_ALWAYS_FATAL("setParameter track: bad param %d", param);
+ }
+ break;
+
+ case RESAMPLE:
+ switch (param) {
+ case SAMPLE_RATE:
+ ALOG_ASSERT(valueInt > 0, "bad sample rate %d", valueInt);
+ if (track->setResampler(uint32_t(valueInt), mSampleRate)) {
+ ALOGV("setParameter(RESAMPLE, SAMPLE_RATE, %u)",
+ uint32_t(valueInt));
+ invalidate();
+ }
+ break;
+ case RESET:
+ track->resetResampler();
+ invalidate();
+ break;
+ case REMOVE:
+ track->mResampler.reset(nullptr);
+ track->sampleRate = mSampleRate;
+ invalidate();
+ break;
+ default:
+ LOG_ALWAYS_FATAL("setParameter resample: bad param %d", param);
+ }
+ break;
+
+ case RAMP_VOLUME:
+ case VOLUME:
+ switch (param) {
+ case AUXLEVEL:
+ if (setVolumeRampVariables(*reinterpret_cast<float*>(value),
+ target == RAMP_VOLUME ? mFrameCount : 0,
+ &track->auxLevel, &track->prevAuxLevel, &track->auxInc,
+ &track->mAuxLevel, &track->mPrevAuxLevel, &track->mAuxInc)) {
+ ALOGV("setParameter(%s, AUXLEVEL: %04x)",
+ target == VOLUME ? "VOLUME" : "RAMP_VOLUME", track->auxLevel);
+ invalidate();
+ }
+ break;
+ default:
+ if ((unsigned)param >= VOLUME0 && (unsigned)param < VOLUME0 + MAX_NUM_VOLUMES) {
+ if (setVolumeRampVariables(*reinterpret_cast<float*>(value),
+ target == RAMP_VOLUME ? mFrameCount : 0,
+ &track->volume[param - VOLUME0],
+ &track->prevVolume[param - VOLUME0],
+ &track->volumeInc[param - VOLUME0],
+ &track->mVolume[param - VOLUME0],
+ &track->mPrevVolume[param - VOLUME0],
+ &track->mVolumeInc[param - VOLUME0])) {
+ ALOGV("setParameter(%s, VOLUME%d: %04x)",
+ target == VOLUME ? "VOLUME" : "RAMP_VOLUME", param - VOLUME0,
+ track->volume[param - VOLUME0]);
+ invalidate();
+ }
+ } else {
+ LOG_ALWAYS_FATAL("setParameter volume: bad param %d", param);
+ }
+ }
+ break;
+
+ default:
+ LOG_ALWAYS_FATAL("setParameter: bad target %d", target);
+ }
+}
+
+bool AudioMixerBase::TrackBase::setResampler(uint32_t trackSampleRate, uint32_t devSampleRate)
+{
+ if (trackSampleRate != devSampleRate || mResampler.get() != nullptr) {
+ if (sampleRate != trackSampleRate) {
+ sampleRate = trackSampleRate;
+ if (mResampler.get() == nullptr) {
+ ALOGV("Creating resampler from track %d Hz to device %d Hz",
+ trackSampleRate, devSampleRate);
+ AudioResampler::src_quality quality;
+ // force lowest quality level resampler if use case isn't music or video
+ // FIXME this is flawed for dynamic sample rates, as we choose the resampler
+ // quality level based on the initial ratio, but that could change later.
+ // Should have a way to distinguish tracks with static ratios vs. dynamic ratios.
+ if (isMusicRate(trackSampleRate)) {
+ quality = AudioResampler::DEFAULT_QUALITY;
+ } else {
+ quality = AudioResampler::DYN_LOW_QUALITY;
+ }
+
+ // TODO: Remove MONO_HACK. Resampler sees #channels after the downmixer
+ // but if none exists, it is the channel count (1 for mono).
+ const int resamplerChannelCount = getOutputChannelCount();
+ ALOGVV("Creating resampler:"
+ " format(%#x) channels(%d) devSampleRate(%u) quality(%d)\n",
+ mMixerInFormat, resamplerChannelCount, devSampleRate, quality);
+ mResampler.reset(AudioResampler::create(
+ mMixerInFormat,
+ resamplerChannelCount,
+ devSampleRate, quality));
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Checks to see if the volume ramp has completed and clears the increment
+ * variables appropriately.
+ *
+ * FIXME: There is code to handle int/float ramp variable switchover should it not
+ * complete within a mixer buffer processing call, but it is preferred to avoid switchover
+ * due to precision issues. The switchover code is included for legacy code purposes
+ * and can be removed once the integer volume is removed.
+ *
+ * It is not sufficient to clear only the volumeInc integer variable because
+ * if one channel requires ramping, all channels are ramped.
+ *
+ * There is a bit of duplicated code here, but it keeps backward compatibility.
+ */
+void AudioMixerBase::TrackBase::adjustVolumeRamp(bool aux, bool useFloat)
+{
+ if (useFloat) {
+ for (uint32_t i = 0; i < MAX_NUM_VOLUMES; i++) {
+ if ((mVolumeInc[i] > 0 && mPrevVolume[i] + mVolumeInc[i] >= mVolume[i]) ||
+ (mVolumeInc[i] < 0 && mPrevVolume[i] + mVolumeInc[i] <= mVolume[i])) {
+ volumeInc[i] = 0;
+ prevVolume[i] = volume[i] << 16;
+ mVolumeInc[i] = 0.;
+ mPrevVolume[i] = mVolume[i];
+ } else {
+ //ALOGV("ramp: %f %f %f", mVolume[i], mPrevVolume[i], mVolumeInc[i]);
+ prevVolume[i] = u4_28_from_float(mPrevVolume[i]);
+ }
+ }
+ } else {
+ for (uint32_t i = 0; i < MAX_NUM_VOLUMES; i++) {
+ if (((volumeInc[i]>0) && (((prevVolume[i]+volumeInc[i])>>16) >= volume[i])) ||
+ ((volumeInc[i]<0) && (((prevVolume[i]+volumeInc[i])>>16) <= volume[i]))) {
+ volumeInc[i] = 0;
+ prevVolume[i] = volume[i] << 16;
+ mVolumeInc[i] = 0.;
+ mPrevVolume[i] = mVolume[i];
+ } else {
+ //ALOGV("ramp: %d %d %d", volume[i] << 16, prevVolume[i], volumeInc[i]);
+ mPrevVolume[i] = float_from_u4_28(prevVolume[i]);
+ }
+ }
+ }
+
+ if (aux) {
+#ifdef FLOAT_AUX
+ if (useFloat) {
+ if ((mAuxInc > 0.f && mPrevAuxLevel + mAuxInc >= mAuxLevel) ||
+ (mAuxInc < 0.f && mPrevAuxLevel + mAuxInc <= mAuxLevel)) {
+ auxInc = 0;
+ prevAuxLevel = auxLevel << 16;
+ mAuxInc = 0.f;
+ mPrevAuxLevel = mAuxLevel;
+ }
+ } else
+#endif
+ if ((auxInc > 0 && ((prevAuxLevel + auxInc) >> 16) >= auxLevel) ||
+ (auxInc < 0 && ((prevAuxLevel + auxInc) >> 16) <= auxLevel)) {
+ auxInc = 0;
+ prevAuxLevel = auxLevel << 16;
+ mAuxInc = 0.f;
+ mPrevAuxLevel = mAuxLevel;
+ }
+ }
+}
+
+void AudioMixerBase::TrackBase::recreateResampler(uint32_t devSampleRate)
+{
+ if (mResampler.get() != nullptr) {
+ const uint32_t resetToSampleRate = sampleRate;
+ mResampler.reset(nullptr);
+ sampleRate = devSampleRate; // without resampler, track rate is device sample rate.
+ // recreate the resampler with updated format, channels, saved sampleRate.
+ setResampler(resetToSampleRate /*trackSampleRate*/, devSampleRate);
+ }
+}
+
+size_t AudioMixerBase::getUnreleasedFrames(int name) const
+{
+ const auto it = mTracks.find(name);
+ if (it != mTracks.end()) {
+ return it->second->getUnreleasedFrames();
+ }
+ return 0;
+}
+
+std::string AudioMixerBase::trackNames() const
+{
+ std::stringstream ss;
+ for (const auto &pair : mTracks) {
+ ss << pair.first << " ";
+ }
+ return ss.str();
+}
+
+void AudioMixerBase::process__validate()
+{
+ // TODO: fix all16BitsStereNoResample logic to
+ // either properly handle muted tracks (it should ignore them)
+ // or remove altogether as an obsolete optimization.
+ bool all16BitsStereoNoResample = true;
+ bool resampling = false;
+ bool volumeRamp = false;
+
+ mEnabled.clear();
+ mGroups.clear();
+ for (const auto &pair : mTracks) {
+ const int name = pair.first;
+ const std::shared_ptr<TrackBase> &t = pair.second;
+ if (!t->enabled) continue;
+
+ mEnabled.emplace_back(name); // we add to mEnabled in order of name.
+ mGroups[t->mainBuffer].emplace_back(name); // mGroups also in order of name.
+
+ uint32_t n = 0;
+ // FIXME can overflow (mask is only 3 bits)
+ n |= NEEDS_CHANNEL_1 + t->channelCount - 1;
+ if (t->doesResample()) {
+ n |= NEEDS_RESAMPLE;
+ }
+ if (t->auxLevel != 0 && t->auxBuffer != NULL) {
+ n |= NEEDS_AUX;
+ }
+
+ if (t->volumeInc[0]|t->volumeInc[1]) {
+ volumeRamp = true;
+ } else if (!t->doesResample() && t->volumeRL == 0) {
+ n |= NEEDS_MUTE;
+ }
+ t->needs = n;
+
+ if (n & NEEDS_MUTE) {
+ t->hook = &TrackBase::track__nop;
+ } else {
+ if (n & NEEDS_AUX) {
+ all16BitsStereoNoResample = false;
+ }
+ if (n & NEEDS_RESAMPLE) {
+ all16BitsStereoNoResample = false;
+ resampling = true;
+ if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_1
+ && t->channelMask == AUDIO_CHANNEL_OUT_MONO // MONO_HACK
+ && isAudioChannelPositionMask(t->mMixerChannelMask)) {
+ t->hook = TrackBase::getTrackHook(
+ TRACKTYPE_RESAMPLEMONO, t->mMixerChannelCount,
+ t->mMixerInFormat, t->mMixerFormat);
+ } else if ((n & NEEDS_CHANNEL_COUNT__MASK) >= NEEDS_CHANNEL_2
+ && t->useStereoVolume()) {
+ t->hook = TrackBase::getTrackHook(
+ TRACKTYPE_RESAMPLESTEREO, t->mMixerChannelCount,
+ t->mMixerInFormat, t->mMixerFormat);
+ } else {
+ t->hook = TrackBase::getTrackHook(
+ TRACKTYPE_RESAMPLE, t->mMixerChannelCount,
+ t->mMixerInFormat, t->mMixerFormat);
+ }
+ ALOGV_IF((n & NEEDS_CHANNEL_COUNT__MASK) > NEEDS_CHANNEL_2,
+ "Track %d needs downmix + resample", name);
+ } else {
+ if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_1){
+ t->hook = TrackBase::getTrackHook(
+ (isAudioChannelPositionMask(t->mMixerChannelMask) // TODO: MONO_HACK
+ && t->channelMask == AUDIO_CHANNEL_OUT_MONO)
+ ? TRACKTYPE_NORESAMPLEMONO : TRACKTYPE_NORESAMPLE,
+ t->mMixerChannelCount,
+ t->mMixerInFormat, t->mMixerFormat);
+ all16BitsStereoNoResample = false;
+ }
+ if ((n & NEEDS_CHANNEL_COUNT__MASK) >= NEEDS_CHANNEL_2){
+ t->hook = TrackBase::getTrackHook(
+ t->useStereoVolume() ? TRACKTYPE_NORESAMPLESTEREO
+ : TRACKTYPE_NORESAMPLE,
+ t->mMixerChannelCount, t->mMixerInFormat,
+ t->mMixerFormat);
+ ALOGV_IF((n & NEEDS_CHANNEL_COUNT__MASK) > NEEDS_CHANNEL_2,
+ "Track %d needs downmix", name);
+ }
+ }
+ }
+ }
+
+ // select the processing hooks
+ mHook = &AudioMixerBase::process__nop;
+ if (mEnabled.size() > 0) {
+ if (resampling) {
+ if (mOutputTemp.get() == nullptr) {
+ mOutputTemp.reset(new int32_t[MAX_NUM_CHANNELS * mFrameCount]);
+ }
+ if (mResampleTemp.get() == nullptr) {
+ mResampleTemp.reset(new int32_t[MAX_NUM_CHANNELS * mFrameCount]);
+ }
+ mHook = &AudioMixerBase::process__genericResampling;
+ } else {
+ // we keep temp arrays around.
+ mHook = &AudioMixerBase::process__genericNoResampling;
+ if (all16BitsStereoNoResample && !volumeRamp) {
+ if (mEnabled.size() == 1) {
+ const std::shared_ptr<TrackBase> &t = mTracks[mEnabled[0]];
+ if ((t->needs & NEEDS_MUTE) == 0) {
+ // The check prevents a muted track from acquiring a process hook.
+ //
+ // This is dangerous if the track is MONO as that requires
+ // special case handling due to implicit channel duplication.
+ // Stereo or Multichannel should actually be fine here.
+ mHook = getProcessHook(PROCESSTYPE_NORESAMPLEONETRACK,
+ t->mMixerChannelCount, t->mMixerInFormat, t->mMixerFormat,
+ t->useStereoVolume());
+ }
+ }
+ }
+ }
+ }
+
+ ALOGV("mixer configuration change: %zu "
+ "all16BitsStereoNoResample=%d, resampling=%d, volumeRamp=%d",
+ mEnabled.size(), all16BitsStereoNoResample, resampling, volumeRamp);
+
+ process();
+
+ // Now that the volume ramp has been done, set optimal state and
+ // track hooks for subsequent mixer process
+ if (mEnabled.size() > 0) {
+ bool allMuted = true;
+
+ for (const int name : mEnabled) {
+ const std::shared_ptr<TrackBase> &t = mTracks[name];
+ if (!t->doesResample() && t->volumeRL == 0) {
+ t->needs |= NEEDS_MUTE;
+ t->hook = &TrackBase::track__nop;
+ } else {
+ allMuted = false;
+ }
+ }
+ if (allMuted) {
+ mHook = &AudioMixerBase::process__nop;
+ } else if (all16BitsStereoNoResample) {
+ if (mEnabled.size() == 1) {
+ //const int i = 31 - __builtin_clz(enabledTracks);
+ const std::shared_ptr<TrackBase> &t = mTracks[mEnabled[0]];
+ // Muted single tracks handled by allMuted above.
+ mHook = getProcessHook(PROCESSTYPE_NORESAMPLEONETRACK,
+ t->mMixerChannelCount, t->mMixerInFormat, t->mMixerFormat,
+ t->useStereoVolume());
+ }
+ }
+ }
+}
+
+void AudioMixerBase::TrackBase::track__genericResample(
+ int32_t* out, size_t outFrameCount, int32_t* temp, int32_t* aux)
+{
+ ALOGVV("track__genericResample\n");
+ mResampler->setSampleRate(sampleRate);
+
+ // ramp gain - resample to temp buffer and scale/mix in 2nd step
+ if (aux != NULL) {
+ // always resample with unity gain when sending to auxiliary buffer to be able
+ // to apply send level after resampling
+ mResampler->setVolume(UNITY_GAIN_FLOAT, UNITY_GAIN_FLOAT);
+ memset(temp, 0, outFrameCount * mMixerChannelCount * sizeof(int32_t));
+ mResampler->resample(temp, outFrameCount, bufferProvider);
+ if (CC_UNLIKELY(volumeInc[0]|volumeInc[1]|auxInc)) {
+ volumeRampStereo(out, outFrameCount, temp, aux);
+ } else {
+ volumeStereo(out, outFrameCount, temp, aux);
+ }
+ } else {
+ if (CC_UNLIKELY(volumeInc[0]|volumeInc[1])) {
+ mResampler->setVolume(UNITY_GAIN_FLOAT, UNITY_GAIN_FLOAT);
+ memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t));
+ mResampler->resample(temp, outFrameCount, bufferProvider);
+ volumeRampStereo(out, outFrameCount, temp, aux);
+ }
+
+ // constant gain
+ else {
+ mResampler->setVolume(mVolume[0], mVolume[1]);
+ mResampler->resample(out, outFrameCount, bufferProvider);
+ }
+ }
+}
+
+void AudioMixerBase::TrackBase::track__nop(int32_t* out __unused,
+ size_t outFrameCount __unused, int32_t* temp __unused, int32_t* aux __unused)
+{
+}
+
+void AudioMixerBase::TrackBase::volumeRampStereo(
+ int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux)
+{
+ int32_t vl = prevVolume[0];
+ int32_t vr = prevVolume[1];
+ const int32_t vlInc = volumeInc[0];
+ const int32_t vrInc = volumeInc[1];
+
+ //ALOGD("[0] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
+ // t, vlInc/65536.0f, vl/65536.0f, volume[0],
+ // (vl + vlInc*frameCount)/65536.0f, frameCount);
+
+ // ramp volume
+ if (CC_UNLIKELY(aux != NULL)) {
+ int32_t va = prevAuxLevel;
+ const int32_t vaInc = auxInc;
+ int32_t l;
+ int32_t r;
+
+ do {
+ l = (*temp++ >> 12);
+ r = (*temp++ >> 12);
+ *out++ += (vl >> 16) * l;
+ *out++ += (vr >> 16) * r;
+ *aux++ += (va >> 17) * (l + r);
+ vl += vlInc;
+ vr += vrInc;
+ va += vaInc;
+ } while (--frameCount);
+ prevAuxLevel = va;
+ } else {
+ do {
+ *out++ += (vl >> 16) * (*temp++ >> 12);
+ *out++ += (vr >> 16) * (*temp++ >> 12);
+ vl += vlInc;
+ vr += vrInc;
+ } while (--frameCount);
+ }
+ prevVolume[0] = vl;
+ prevVolume[1] = vr;
+ adjustVolumeRamp(aux != NULL);
+}
+
+void AudioMixerBase::TrackBase::volumeStereo(
+ int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux)
+{
+ const int16_t vl = volume[0];
+ const int16_t vr = volume[1];
+
+ if (CC_UNLIKELY(aux != NULL)) {
+ const int16_t va = auxLevel;
+ do {
+ int16_t l = (int16_t)(*temp++ >> 12);
+ int16_t r = (int16_t)(*temp++ >> 12);
+ out[0] = mulAdd(l, vl, out[0]);
+ int16_t a = (int16_t)(((int32_t)l + r) >> 1);
+ out[1] = mulAdd(r, vr, out[1]);
+ out += 2;
+ aux[0] = mulAdd(a, va, aux[0]);
+ aux++;
+ } while (--frameCount);
+ } else {
+ do {
+ int16_t l = (int16_t)(*temp++ >> 12);
+ int16_t r = (int16_t)(*temp++ >> 12);
+ out[0] = mulAdd(l, vl, out[0]);
+ out[1] = mulAdd(r, vr, out[1]);
+ out += 2;
+ } while (--frameCount);
+ }
+}
+
+void AudioMixerBase::TrackBase::track__16BitsStereo(
+ int32_t* out, size_t frameCount, int32_t* temp __unused, int32_t* aux)
+{
+ ALOGVV("track__16BitsStereo\n");
+ const int16_t *in = static_cast<const int16_t *>(mIn);
+
+ if (CC_UNLIKELY(aux != NULL)) {
+ int32_t l;
+ int32_t r;
+ // ramp gain
+ if (CC_UNLIKELY(volumeInc[0]|volumeInc[1]|auxInc)) {
+ int32_t vl = prevVolume[0];
+ int32_t vr = prevVolume[1];
+ int32_t va = prevAuxLevel;
+ const int32_t vlInc = volumeInc[0];
+ const int32_t vrInc = volumeInc[1];
+ const int32_t vaInc = auxInc;
+ // ALOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
+ // t, vlInc/65536.0f, vl/65536.0f, volume[0],
+ // (vl + vlInc*frameCount)/65536.0f, frameCount);
+
+ do {
+ l = (int32_t)*in++;
+ r = (int32_t)*in++;
+ *out++ += (vl >> 16) * l;
+ *out++ += (vr >> 16) * r;
+ *aux++ += (va >> 17) * (l + r);
+ vl += vlInc;
+ vr += vrInc;
+ va += vaInc;
+ } while (--frameCount);
+
+ prevVolume[0] = vl;
+ prevVolume[1] = vr;
+ prevAuxLevel = va;
+ adjustVolumeRamp(true);
+ }
+
+ // constant gain
+ else {
+ const uint32_t vrl = volumeRL;
+ const int16_t va = (int16_t)auxLevel;
+ do {
+ uint32_t rl = *reinterpret_cast<const uint32_t *>(in);
+ int16_t a = (int16_t)(((int32_t)in[0] + in[1]) >> 1);
+ in += 2;
+ out[0] = mulAddRL(1, rl, vrl, out[0]);
+ out[1] = mulAddRL(0, rl, vrl, out[1]);
+ out += 2;
+ aux[0] = mulAdd(a, va, aux[0]);
+ aux++;
+ } while (--frameCount);
+ }
+ } else {
+ // ramp gain
+ if (CC_UNLIKELY(volumeInc[0]|volumeInc[1])) {
+ int32_t vl = prevVolume[0];
+ int32_t vr = prevVolume[1];
+ const int32_t vlInc = volumeInc[0];
+ const int32_t vrInc = volumeInc[1];
+
+ // ALOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
+ // t, vlInc/65536.0f, vl/65536.0f, volume[0],
+ // (vl + vlInc*frameCount)/65536.0f, frameCount);
+
+ do {
+ *out++ += (vl >> 16) * (int32_t) *in++;
+ *out++ += (vr >> 16) * (int32_t) *in++;
+ vl += vlInc;
+ vr += vrInc;
+ } while (--frameCount);
+
+ prevVolume[0] = vl;
+ prevVolume[1] = vr;
+ adjustVolumeRamp(false);
+ }
+
+ // constant gain
+ else {
+ const uint32_t vrl = volumeRL;
+ do {
+ uint32_t rl = *reinterpret_cast<const uint32_t *>(in);
+ in += 2;
+ out[0] = mulAddRL(1, rl, vrl, out[0]);
+ out[1] = mulAddRL(0, rl, vrl, out[1]);
+ out += 2;
+ } while (--frameCount);
+ }
+ }
+ mIn = in;
+}
+
+void AudioMixerBase::TrackBase::track__16BitsMono(
+ int32_t* out, size_t frameCount, int32_t* temp __unused, int32_t* aux)
+{
+ ALOGVV("track__16BitsMono\n");
+ const int16_t *in = static_cast<int16_t const *>(mIn);
+
+ if (CC_UNLIKELY(aux != NULL)) {
+ // ramp gain
+ if (CC_UNLIKELY(volumeInc[0]|volumeInc[1]|auxInc)) {
+ int32_t vl = prevVolume[0];
+ int32_t vr = prevVolume[1];
+ int32_t va = prevAuxLevel;
+ const int32_t vlInc = volumeInc[0];
+ const int32_t vrInc = volumeInc[1];
+ const int32_t vaInc = auxInc;
+
+ // ALOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
+ // t, vlInc/65536.0f, vl/65536.0f, volume[0],
+ // (vl + vlInc*frameCount)/65536.0f, frameCount);
+
+ do {
+ int32_t l = *in++;
+ *out++ += (vl >> 16) * l;
+ *out++ += (vr >> 16) * l;
+ *aux++ += (va >> 16) * l;
+ vl += vlInc;
+ vr += vrInc;
+ va += vaInc;
+ } while (--frameCount);
+
+ prevVolume[0] = vl;
+ prevVolume[1] = vr;
+ prevAuxLevel = va;
+ adjustVolumeRamp(true);
+ }
+ // constant gain
+ else {
+ const int16_t vl = volume[0];
+ const int16_t vr = volume[1];
+ const int16_t va = (int16_t)auxLevel;
+ do {
+ int16_t l = *in++;
+ out[0] = mulAdd(l, vl, out[0]);
+ out[1] = mulAdd(l, vr, out[1]);
+ out += 2;
+ aux[0] = mulAdd(l, va, aux[0]);
+ aux++;
+ } while (--frameCount);
+ }
+ } else {
+ // ramp gain
+ if (CC_UNLIKELY(volumeInc[0]|volumeInc[1])) {
+ int32_t vl = prevVolume[0];
+ int32_t vr = prevVolume[1];
+ const int32_t vlInc = volumeInc[0];
+ const int32_t vrInc = volumeInc[1];
+
+ // ALOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
+ // t, vlInc/65536.0f, vl/65536.0f, volume[0],
+ // (vl + vlInc*frameCount)/65536.0f, frameCount);
+
+ do {
+ int32_t l = *in++;
+ *out++ += (vl >> 16) * l;
+ *out++ += (vr >> 16) * l;
+ vl += vlInc;
+ vr += vrInc;
+ } while (--frameCount);
+
+ prevVolume[0] = vl;
+ prevVolume[1] = vr;
+ adjustVolumeRamp(false);
+ }
+ // constant gain
+ else {
+ const int16_t vl = volume[0];
+ const int16_t vr = volume[1];
+ do {
+ int16_t l = *in++;
+ out[0] = mulAdd(l, vl, out[0]);
+ out[1] = mulAdd(l, vr, out[1]);
+ out += 2;
+ } while (--frameCount);
+ }
+ }
+ mIn = in;
+}
+
+// no-op case
+void AudioMixerBase::process__nop()
+{
+ ALOGVV("process__nop\n");
+
+ for (const auto &pair : mGroups) {
+ // process by group of tracks with same output buffer to
+ // avoid multiple memset() on same buffer
+ const auto &group = pair.second;
+
+ const std::shared_ptr<TrackBase> &t = mTracks[group[0]];
+ memset(t->mainBuffer, 0,
+ mFrameCount * audio_bytes_per_frame(t->getMixerChannelCount(), t->mMixerFormat));
+
+ // now consume data
+ for (const int name : group) {
+ const std::shared_ptr<TrackBase> &t = mTracks[name];
+ size_t outFrames = mFrameCount;
+ while (outFrames) {
+ t->buffer.frameCount = outFrames;
+ t->bufferProvider->getNextBuffer(&t->buffer);
+ if (t->buffer.raw == NULL) break;
+ outFrames -= t->buffer.frameCount;
+ t->bufferProvider->releaseBuffer(&t->buffer);
+ }
+ }
+ }
+}
+
+// generic code without resampling
+void AudioMixerBase::process__genericNoResampling()
+{
+ ALOGVV("process__genericNoResampling\n");
+ int32_t outTemp[BLOCKSIZE * MAX_NUM_CHANNELS] __attribute__((aligned(32)));
+
+ for (const auto &pair : mGroups) {
+ // process by group of tracks with same output main buffer to
+ // avoid multiple memset() on same buffer
+ const auto &group = pair.second;
+
+ // acquire buffer
+ for (const int name : group) {
+ const std::shared_ptr<TrackBase> &t = mTracks[name];
+ t->buffer.frameCount = mFrameCount;
+ t->bufferProvider->getNextBuffer(&t->buffer);
+ t->frameCount = t->buffer.frameCount;
+ t->mIn = t->buffer.raw;
+ }
+
+ int32_t *out = (int *)pair.first;
+ size_t numFrames = 0;
+ do {
+ const size_t frameCount = std::min((size_t)BLOCKSIZE, mFrameCount - numFrames);
+ memset(outTemp, 0, sizeof(outTemp));
+ for (const int name : group) {
+ const std::shared_ptr<TrackBase> &t = mTracks[name];
+ int32_t *aux = NULL;
+ if (CC_UNLIKELY(t->needs & NEEDS_AUX)) {
+ aux = t->auxBuffer + numFrames;
+ }
+ for (int outFrames = frameCount; outFrames > 0; ) {
+ // t->in == nullptr can happen if the track was flushed just after having
+ // been enabled for mixing.
+ if (t->mIn == nullptr) {
+ break;
+ }
+ size_t inFrames = (t->frameCount > outFrames)?outFrames:t->frameCount;
+ if (inFrames > 0) {
+ (t.get()->*t->hook)(
+ outTemp + (frameCount - outFrames) * t->mMixerChannelCount,
+ inFrames, mResampleTemp.get() /* naked ptr */, aux);
+ t->frameCount -= inFrames;
+ outFrames -= inFrames;
+ if (CC_UNLIKELY(aux != NULL)) {
+ aux += inFrames;
+ }
+ }
+ if (t->frameCount == 0 && outFrames) {
+ t->bufferProvider->releaseBuffer(&t->buffer);
+ t->buffer.frameCount = (mFrameCount - numFrames) -
+ (frameCount - outFrames);
+ t->bufferProvider->getNextBuffer(&t->buffer);
+ t->mIn = t->buffer.raw;
+ if (t->mIn == nullptr) {
+ break;
+ }
+ t->frameCount = t->buffer.frameCount;
+ }
+ }
+ }
+
+ const std::shared_ptr<TrackBase> &t1 = mTracks[group[0]];
+ convertMixerFormat(out, t1->mMixerFormat, outTemp, t1->mMixerInFormat,
+ frameCount * t1->mMixerChannelCount);
+ // TODO: fix ugly casting due to choice of out pointer type
+ out = reinterpret_cast<int32_t*>((uint8_t*)out
+ + frameCount * t1->mMixerChannelCount
+ * audio_bytes_per_sample(t1->mMixerFormat));
+ numFrames += frameCount;
+ } while (numFrames < mFrameCount);
+
+ // release each track's buffer
+ for (const int name : group) {
+ const std::shared_ptr<TrackBase> &t = mTracks[name];
+ t->bufferProvider->releaseBuffer(&t->buffer);
+ }
+ }
+}
+
+// generic code with resampling
+void AudioMixerBase::process__genericResampling()
+{
+ ALOGVV("process__genericResampling\n");
+ int32_t * const outTemp = mOutputTemp.get(); // naked ptr
+ size_t numFrames = mFrameCount;
+
+ for (const auto &pair : mGroups) {
+ const auto &group = pair.second;
+ const std::shared_ptr<TrackBase> &t1 = mTracks[group[0]];
+
+ // clear temp buffer
+ memset(outTemp, 0, sizeof(*outTemp) * t1->mMixerChannelCount * mFrameCount);
+ for (const int name : group) {
+ const std::shared_ptr<TrackBase> &t = mTracks[name];
+ int32_t *aux = NULL;
+ if (CC_UNLIKELY(t->needs & NEEDS_AUX)) {
+ aux = t->auxBuffer;
+ }
+
+ // this is a little goofy, on the resampling case we don't
+ // acquire/release the buffers because it's done by
+ // the resampler.
+ if (t->needs & NEEDS_RESAMPLE) {
+ (t.get()->*t->hook)(outTemp, numFrames, mResampleTemp.get() /* naked ptr */, aux);
+ } else {
+
+ size_t outFrames = 0;
+
+ while (outFrames < numFrames) {
+ t->buffer.frameCount = numFrames - outFrames;
+ t->bufferProvider->getNextBuffer(&t->buffer);
+ t->mIn = t->buffer.raw;
+ // t->mIn == nullptr can happen if the track was flushed just after having
+ // been enabled for mixing.
+ if (t->mIn == nullptr) break;
+
+ (t.get()->*t->hook)(
+ outTemp + outFrames * t->mMixerChannelCount, t->buffer.frameCount,
+ mResampleTemp.get() /* naked ptr */,
+ aux != nullptr ? aux + outFrames : nullptr);
+ outFrames += t->buffer.frameCount;
+
+ t->bufferProvider->releaseBuffer(&t->buffer);
+ }
+ }
+ }
+ convertMixerFormat(t1->mainBuffer, t1->mMixerFormat,
+ outTemp, t1->mMixerInFormat, numFrames * t1->mMixerChannelCount);
+ }
+}
+
+// one track, 16 bits stereo without resampling is the most common case
+void AudioMixerBase::process__oneTrack16BitsStereoNoResampling()
+{
+ ALOGVV("process__oneTrack16BitsStereoNoResampling\n");
+ LOG_ALWAYS_FATAL_IF(mEnabled.size() != 0,
+ "%zu != 1 tracks enabled", mEnabled.size());
+ const int name = mEnabled[0];
+ const std::shared_ptr<TrackBase> &t = mTracks[name];
+
+ AudioBufferProvider::Buffer& b(t->buffer);
+
+ int32_t* out = t->mainBuffer;
+ float *fout = reinterpret_cast<float*>(out);
+ size_t numFrames = mFrameCount;
+
+ const int16_t vl = t->volume[0];
+ const int16_t vr = t->volume[1];
+ const uint32_t vrl = t->volumeRL;
+ while (numFrames) {
+ b.frameCount = numFrames;
+ t->bufferProvider->getNextBuffer(&b);
+ const int16_t *in = b.i16;
+
+ // in == NULL can happen if the track was flushed just after having
+ // been enabled for mixing.
+ if (in == NULL || (((uintptr_t)in) & 3)) {
+ if ( AUDIO_FORMAT_PCM_FLOAT == t->mMixerFormat ) {
+ memset((char*)fout, 0, numFrames
+ * t->mMixerChannelCount * audio_bytes_per_sample(t->mMixerFormat));
+ } else {
+ memset((char*)out, 0, numFrames
+ * t->mMixerChannelCount * audio_bytes_per_sample(t->mMixerFormat));
+ }
+ ALOGE_IF((((uintptr_t)in) & 3),
+ "process__oneTrack16BitsStereoNoResampling: misaligned buffer"
+ " %p track %d, channels %d, needs %08x, volume %08x vfl %f vfr %f",
+ in, name, t->channelCount, t->needs, vrl, t->mVolume[0], t->mVolume[1]);
+ return;
+ }
+ size_t outFrames = b.frameCount;
+
+ switch (t->mMixerFormat) {
+ case AUDIO_FORMAT_PCM_FLOAT:
+ do {
+ uint32_t rl = *reinterpret_cast<const uint32_t *>(in);
+ in += 2;
+ int32_t l = mulRL(1, rl, vrl);
+ int32_t r = mulRL(0, rl, vrl);
+ *fout++ = float_from_q4_27(l);
+ *fout++ = float_from_q4_27(r);
+ // Note: In case of later int16_t sink output,
+ // conversion and clamping is done by memcpy_to_i16_from_float().
+ } while (--outFrames);
+ break;
+ case AUDIO_FORMAT_PCM_16_BIT:
+ if (CC_UNLIKELY(uint32_t(vl) > UNITY_GAIN_INT || uint32_t(vr) > UNITY_GAIN_INT)) {
+ // volume is boosted, so we might need to clamp even though
+ // we process only one track.
+ do {
+ uint32_t rl = *reinterpret_cast<const uint32_t *>(in);
+ in += 2;
+ int32_t l = mulRL(1, rl, vrl) >> 12;
+ int32_t r = mulRL(0, rl, vrl) >> 12;
+ // clamping...
+ l = clamp16(l);
+ r = clamp16(r);
+ *out++ = (r<<16) | (l & 0xFFFF);
+ } while (--outFrames);
+ } else {
+ do {
+ uint32_t rl = *reinterpret_cast<const uint32_t *>(in);
+ in += 2;
+ int32_t l = mulRL(1, rl, vrl) >> 12;
+ int32_t r = mulRL(0, rl, vrl) >> 12;
+ *out++ = (r<<16) | (l & 0xFFFF);
+ } while (--outFrames);
+ }
+ break;
+ default:
+ LOG_ALWAYS_FATAL("bad mixer format: %d", t->mMixerFormat);
+ }
+ numFrames -= b.frameCount;
+ t->bufferProvider->releaseBuffer(&b);
+ }
+}
+
+/* TODO: consider whether this level of optimization is necessary.
+ * Perhaps just stick with a single for loop.
+ */
+
+// Needs to derive a compile time constant (constexpr). Could be targeted to go
+// to a MONOVOL mixtype based on MAX_NUM_VOLUMES, but that's an unnecessary complication.
+#define MIXTYPE_MONOVOL(mixtype) ((mixtype) == MIXTYPE_MULTI ? MIXTYPE_MULTI_MONOVOL : \
+ (mixtype) == MIXTYPE_MULTI_SAVEONLY ? MIXTYPE_MULTI_SAVEONLY_MONOVOL : (mixtype))
+
+/* MIXTYPE (see AudioMixerOps.h MIXTYPE_* enumeration)
+ * TO: int32_t (Q4.27) or float
+ * TI: int32_t (Q4.27) or int16_t (Q0.15) or float
+ * TA: int32_t (Q4.27) or float
+ */
+template <int MIXTYPE,
+ typename TO, typename TI, typename TV, typename TA, typename TAV>
+static void volumeRampMulti(uint32_t channels, TO* out, size_t frameCount,
+ const TI* in, TA* aux, TV *vol, const TV *volinc, TAV *vola, TAV volainc)
+{
+ switch (channels) {
+ case 1:
+ volumeRampMulti<MIXTYPE, 1>(out, frameCount, in, aux, vol, volinc, vola, volainc);
+ break;
+ case 2:
+ volumeRampMulti<MIXTYPE, 2>(out, frameCount, in, aux, vol, volinc, vola, volainc);
+ break;
+ case 3:
+ volumeRampMulti<MIXTYPE_MONOVOL(MIXTYPE), 3>(out,
+ frameCount, in, aux, vol, volinc, vola, volainc);
+ break;
+ case 4:
+ volumeRampMulti<MIXTYPE_MONOVOL(MIXTYPE), 4>(out,
+ frameCount, in, aux, vol, volinc, vola, volainc);
+ break;
+ case 5:
+ volumeRampMulti<MIXTYPE_MONOVOL(MIXTYPE), 5>(out,
+ frameCount, in, aux, vol, volinc, vola, volainc);
+ break;
+ case 6:
+ volumeRampMulti<MIXTYPE_MONOVOL(MIXTYPE), 6>(out,
+ frameCount, in, aux, vol, volinc, vola, volainc);
+ break;
+ case 7:
+ volumeRampMulti<MIXTYPE_MONOVOL(MIXTYPE), 7>(out,
+ frameCount, in, aux, vol, volinc, vola, volainc);
+ break;
+ case 8:
+ volumeRampMulti<MIXTYPE_MONOVOL(MIXTYPE), 8>(out,
+ frameCount, in, aux, vol, volinc, vola, volainc);
+ break;
+ }
+}
+
+/* MIXTYPE (see AudioMixerOps.h MIXTYPE_* enumeration)
+ * TO: int32_t (Q4.27) or float
+ * TI: int32_t (Q4.27) or int16_t (Q0.15) or float
+ * TA: int32_t (Q4.27) or float
+ */
+template <int MIXTYPE,
+ typename TO, typename TI, typename TV, typename TA, typename TAV>
+static void volumeMulti(uint32_t channels, TO* out, size_t frameCount,
+ const TI* in, TA* aux, const TV *vol, TAV vola)
+{
+ switch (channels) {
+ case 1:
+ volumeMulti<MIXTYPE, 1>(out, frameCount, in, aux, vol, vola);
+ break;
+ case 2:
+ volumeMulti<MIXTYPE, 2>(out, frameCount, in, aux, vol, vola);
+ break;
+ case 3:
+ volumeMulti<MIXTYPE_MONOVOL(MIXTYPE), 3>(out, frameCount, in, aux, vol, vola);
+ break;
+ case 4:
+ volumeMulti<MIXTYPE_MONOVOL(MIXTYPE), 4>(out, frameCount, in, aux, vol, vola);
+ break;
+ case 5:
+ volumeMulti<MIXTYPE_MONOVOL(MIXTYPE), 5>(out, frameCount, in, aux, vol, vola);
+ break;
+ case 6:
+ volumeMulti<MIXTYPE_MONOVOL(MIXTYPE), 6>(out, frameCount, in, aux, vol, vola);
+ break;
+ case 7:
+ volumeMulti<MIXTYPE_MONOVOL(MIXTYPE), 7>(out, frameCount, in, aux, vol, vola);
+ break;
+ case 8:
+ volumeMulti<MIXTYPE_MONOVOL(MIXTYPE), 8>(out, frameCount, in, aux, vol, vola);
+ break;
+ }
+}
+
+/* MIXTYPE (see AudioMixerOps.h MIXTYPE_* enumeration)
+ * USEFLOATVOL (set to true if float volume is used)
+ * ADJUSTVOL (set to true if volume ramp parameters needs adjustment afterwards)
+ * TO: int32_t (Q4.27) or float
+ * TI: int32_t (Q4.27) or int16_t (Q0.15) or float
+ * TA: int32_t (Q4.27) or float
+ */
+template <int MIXTYPE, bool USEFLOATVOL, bool ADJUSTVOL,
+ typename TO, typename TI, typename TA>
+void AudioMixerBase::TrackBase::volumeMix(TO *out, size_t outFrames,
+ const TI *in, TA *aux, bool ramp)
+{
+ if (USEFLOATVOL) {
+ if (ramp) {
+ volumeRampMulti<MIXTYPE>(mMixerChannelCount, out, outFrames, in, aux,
+ mPrevVolume, mVolumeInc,
+#ifdef FLOAT_AUX
+ &mPrevAuxLevel, mAuxInc
+#else
+ &prevAuxLevel, auxInc
+#endif
+ );
+ if (ADJUSTVOL) {
+ adjustVolumeRamp(aux != NULL, true);
+ }
+ } else {
+ volumeMulti<MIXTYPE>(mMixerChannelCount, out, outFrames, in, aux,
+ mVolume,
+#ifdef FLOAT_AUX
+ mAuxLevel
+#else
+ auxLevel
+#endif
+ );
+ }
+ } else {
+ if (ramp) {
+ volumeRampMulti<MIXTYPE>(mMixerChannelCount, out, outFrames, in, aux,
+ prevVolume, volumeInc, &prevAuxLevel, auxInc);
+ if (ADJUSTVOL) {
+ adjustVolumeRamp(aux != NULL);
+ }
+ } else {
+ volumeMulti<MIXTYPE>(mMixerChannelCount, out, outFrames, in, aux,
+ volume, auxLevel);
+ }
+ }
+}
+
+/* This process hook is called when there is a single track without
+ * aux buffer, volume ramp, or resampling.
+ * TODO: Update the hook selection: this can properly handle aux and ramp.
+ *
+ * MIXTYPE (see AudioMixerOps.h MIXTYPE_* enumeration)
+ * TO: int32_t (Q4.27) or float
+ * TI: int32_t (Q4.27) or int16_t (Q0.15) or float
+ * TA: int32_t (Q4.27)
+ */
+template <int MIXTYPE, typename TO, typename TI, typename TA>
+void AudioMixerBase::process__noResampleOneTrack()
+{
+ ALOGVV("process__noResampleOneTrack\n");
+ LOG_ALWAYS_FATAL_IF(mEnabled.size() != 1,
+ "%zu != 1 tracks enabled", mEnabled.size());
+ const std::shared_ptr<TrackBase> &t = mTracks[mEnabled[0]];
+ const uint32_t channels = t->mMixerChannelCount;
+ TO* out = reinterpret_cast<TO*>(t->mainBuffer);
+ TA* aux = reinterpret_cast<TA*>(t->auxBuffer);
+ const bool ramp = t->needsRamp();
+
+ for (size_t numFrames = mFrameCount; numFrames > 0; ) {
+ AudioBufferProvider::Buffer& b(t->buffer);
+ // get input buffer
+ b.frameCount = numFrames;
+ t->bufferProvider->getNextBuffer(&b);
+ const TI *in = reinterpret_cast<TI*>(b.raw);
+
+ // in == NULL can happen if the track was flushed just after having
+ // been enabled for mixing.
+ if (in == NULL || (((uintptr_t)in) & 3)) {
+ memset(out, 0, numFrames
+ * channels * audio_bytes_per_sample(t->mMixerFormat));
+ ALOGE_IF((((uintptr_t)in) & 3), "process__noResampleOneTrack: bus error: "
+ "buffer %p track %p, channels %d, needs %#x",
+ in, &t, t->channelCount, t->needs);
+ return;
+ }
+
+ const size_t outFrames = b.frameCount;
+ t->volumeMix<MIXTYPE, std::is_same_v<TI, float> /* USEFLOATVOL */, false /* ADJUSTVOL */> (
+ out, outFrames, in, aux, ramp);
+
+ out += outFrames * channels;
+ if (aux != NULL) {
+ aux += outFrames;
+ }
+ numFrames -= b.frameCount;
+
+ // release buffer
+ t->bufferProvider->releaseBuffer(&b);
+ }
+ if (ramp) {
+ t->adjustVolumeRamp(aux != NULL, std::is_same_v<TI, float>);
+ }
+}
+
+/* This track hook is called to do resampling then mixing,
+ * pulling from the track's upstream AudioBufferProvider.
+ *
+ * MIXTYPE (see AudioMixerOps.h MIXTYPE_* enumeration)
+ * TO: int32_t (Q4.27) or float
+ * TI: int32_t (Q4.27) or int16_t (Q0.15) or float
+ * TA: int32_t (Q4.27) or float
+ */
+template <int MIXTYPE, typename TO, typename TI, typename TA>
+void AudioMixerBase::TrackBase::track__Resample(TO* out, size_t outFrameCount, TO* temp, TA* aux)
+{
+ ALOGVV("track__Resample\n");
+ mResampler->setSampleRate(sampleRate);
+ const bool ramp = needsRamp();
+ if (MIXTYPE == MIXTYPE_MONOEXPAND || MIXTYPE == MIXTYPE_STEREOEXPAND
+ || ramp || aux != NULL) {
+ // if ramp: resample with unity gain to temp buffer and scale/mix in 2nd step.
+ // if aux != NULL: resample with unity gain to temp buffer then apply send level.
+
+ mResampler->setVolume(UNITY_GAIN_FLOAT, UNITY_GAIN_FLOAT);
+ memset(temp, 0, outFrameCount * mMixerChannelCount * sizeof(TO));
+ mResampler->resample((int32_t*)temp, outFrameCount, bufferProvider);
+
+ volumeMix<MIXTYPE, std::is_same_v<TI, float> /* USEFLOATVOL */, true /* ADJUSTVOL */>(
+ out, outFrameCount, temp, aux, ramp);
+
+ } else { // constant volume gain
+ mResampler->setVolume(mVolume[0], mVolume[1]);
+ mResampler->resample((int32_t*)out, outFrameCount, bufferProvider);
+ }
+}
+
+/* This track hook is called to mix a track, when no resampling is required.
+ * The input buffer should be present in in.
+ *
+ * MIXTYPE (see AudioMixerOps.h MIXTYPE_* enumeration)
+ * TO: int32_t (Q4.27) or float
+ * TI: int32_t (Q4.27) or int16_t (Q0.15) or float
+ * TA: int32_t (Q4.27) or float
+ */
+template <int MIXTYPE, typename TO, typename TI, typename TA>
+void AudioMixerBase::TrackBase::track__NoResample(
+ TO* out, size_t frameCount, TO* temp __unused, TA* aux)
+{
+ ALOGVV("track__NoResample\n");
+ const TI *in = static_cast<const TI *>(mIn);
+
+ volumeMix<MIXTYPE, std::is_same_v<TI, float> /* USEFLOATVOL */, true /* ADJUSTVOL */>(
+ out, frameCount, in, aux, needsRamp());
+
+ // MIXTYPE_MONOEXPAND reads a single input channel and expands to NCHAN output channels.
+ // MIXTYPE_MULTI reads NCHAN input channels and places to NCHAN output channels.
+ in += (MIXTYPE == MIXTYPE_MONOEXPAND) ? frameCount : frameCount * mMixerChannelCount;
+ mIn = in;
+}
+
+/* The Mixer engine generates either int32_t (Q4_27) or float data.
+ * We use this function to convert the engine buffers
+ * to the desired mixer output format, either int16_t (Q.15) or float.
+ */
+/* static */
+void AudioMixerBase::convertMixerFormat(void *out, audio_format_t mixerOutFormat,
+ void *in, audio_format_t mixerInFormat, size_t sampleCount)
+{
+ switch (mixerInFormat) {
+ case AUDIO_FORMAT_PCM_FLOAT:
+ switch (mixerOutFormat) {
+ case AUDIO_FORMAT_PCM_FLOAT:
+ memcpy(out, in, sampleCount * sizeof(float)); // MEMCPY. TODO optimize out
+ break;
+ case AUDIO_FORMAT_PCM_16_BIT:
+ memcpy_to_i16_from_float((int16_t*)out, (float*)in, sampleCount);
+ break;
+ default:
+ LOG_ALWAYS_FATAL("bad mixerOutFormat: %#x", mixerOutFormat);
+ break;
+ }
+ break;
+ case AUDIO_FORMAT_PCM_16_BIT:
+ switch (mixerOutFormat) {
+ case AUDIO_FORMAT_PCM_FLOAT:
+ memcpy_to_float_from_q4_27((float*)out, (const int32_t*)in, sampleCount);
+ break;
+ case AUDIO_FORMAT_PCM_16_BIT:
+ memcpy_to_i16_from_q4_27((int16_t*)out, (const int32_t*)in, sampleCount);
+ break;
+ default:
+ LOG_ALWAYS_FATAL("bad mixerOutFormat: %#x", mixerOutFormat);
+ break;
+ }
+ break;
+ default:
+ LOG_ALWAYS_FATAL("bad mixerInFormat: %#x", mixerInFormat);
+ break;
+ }
+}
+
+/* Returns the proper track hook to use for mixing the track into the output buffer.
+ */
+/* static */
+AudioMixerBase::hook_t AudioMixerBase::TrackBase::getTrackHook(int trackType, uint32_t channelCount,
+ audio_format_t mixerInFormat, audio_format_t mixerOutFormat __unused)
+{
+ if (!kUseNewMixer && channelCount == FCC_2 && mixerInFormat == AUDIO_FORMAT_PCM_16_BIT) {
+ switch (trackType) {
+ case TRACKTYPE_NOP:
+ return &TrackBase::track__nop;
+ case TRACKTYPE_RESAMPLE:
+ return &TrackBase::track__genericResample;
+ case TRACKTYPE_NORESAMPLEMONO:
+ return &TrackBase::track__16BitsMono;
+ case TRACKTYPE_NORESAMPLE:
+ return &TrackBase::track__16BitsStereo;
+ default:
+ LOG_ALWAYS_FATAL("bad trackType: %d", trackType);
+ break;
+ }
+ }
+ LOG_ALWAYS_FATAL_IF(channelCount > MAX_NUM_CHANNELS);
+ switch (trackType) {
+ case TRACKTYPE_NOP:
+ return &TrackBase::track__nop;
+ case TRACKTYPE_RESAMPLE:
+ switch (mixerInFormat) {
+ case AUDIO_FORMAT_PCM_FLOAT:
+ return (AudioMixerBase::hook_t) &TrackBase::track__Resample<
+ MIXTYPE_MULTI, float /*TO*/, float /*TI*/, TYPE_AUX>;
+ case AUDIO_FORMAT_PCM_16_BIT:
+ return (AudioMixerBase::hook_t) &TrackBase::track__Resample<
+ MIXTYPE_MULTI, int32_t /*TO*/, int16_t /*TI*/, TYPE_AUX>;
+ default:
+ LOG_ALWAYS_FATAL("bad mixerInFormat: %#x", mixerInFormat);
+ break;
+ }
+ break;
+ case TRACKTYPE_RESAMPLESTEREO:
+ switch (mixerInFormat) {
+ case AUDIO_FORMAT_PCM_FLOAT:
+ return (AudioMixerBase::hook_t) &TrackBase::track__Resample<
+ MIXTYPE_MULTI_STEREOVOL, float /*TO*/, float /*TI*/,
+ TYPE_AUX>;
+ case AUDIO_FORMAT_PCM_16_BIT:
+ return (AudioMixerBase::hook_t) &TrackBase::track__Resample<
+ MIXTYPE_MULTI_STEREOVOL, int32_t /*TO*/, int16_t /*TI*/,
+ TYPE_AUX>;
+ default:
+ LOG_ALWAYS_FATAL("bad mixerInFormat: %#x", mixerInFormat);
+ break;
+ }
+ break;
+ // RESAMPLEMONO needs MIXTYPE_STEREOEXPAND since resampler will upmix mono
+ // track to stereo track
+ case TRACKTYPE_RESAMPLEMONO:
+ switch (mixerInFormat) {
+ case AUDIO_FORMAT_PCM_FLOAT:
+ return (AudioMixerBase::hook_t) &TrackBase::track__Resample<
+ MIXTYPE_STEREOEXPAND, float /*TO*/, float /*TI*/,
+ TYPE_AUX>;
+ case AUDIO_FORMAT_PCM_16_BIT:
+ return (AudioMixerBase::hook_t) &TrackBase::track__Resample<
+ MIXTYPE_STEREOEXPAND, int32_t /*TO*/, int16_t /*TI*/,
+ TYPE_AUX>;
+ default:
+ LOG_ALWAYS_FATAL("bad mixerInFormat: %#x", mixerInFormat);
+ break;
+ }
+ break;
+ case TRACKTYPE_NORESAMPLEMONO:
+ switch (mixerInFormat) {
+ case AUDIO_FORMAT_PCM_FLOAT:
+ return (AudioMixerBase::hook_t) &TrackBase::track__NoResample<
+ MIXTYPE_MONOEXPAND, float /*TO*/, float /*TI*/, TYPE_AUX>;
+ case AUDIO_FORMAT_PCM_16_BIT:
+ return (AudioMixerBase::hook_t) &TrackBase::track__NoResample<
+ MIXTYPE_MONOEXPAND, int32_t /*TO*/, int16_t /*TI*/, TYPE_AUX>;
+ default:
+ LOG_ALWAYS_FATAL("bad mixerInFormat: %#x", mixerInFormat);
+ break;
+ }
+ break;
+ case TRACKTYPE_NORESAMPLE:
+ switch (mixerInFormat) {
+ case AUDIO_FORMAT_PCM_FLOAT:
+ return (AudioMixerBase::hook_t) &TrackBase::track__NoResample<
+ MIXTYPE_MULTI, float /*TO*/, float /*TI*/, TYPE_AUX>;
+ case AUDIO_FORMAT_PCM_16_BIT:
+ return (AudioMixerBase::hook_t) &TrackBase::track__NoResample<
+ MIXTYPE_MULTI, int32_t /*TO*/, int16_t /*TI*/, TYPE_AUX>;
+ default:
+ LOG_ALWAYS_FATAL("bad mixerInFormat: %#x", mixerInFormat);
+ break;
+ }
+ break;
+ case TRACKTYPE_NORESAMPLESTEREO:
+ switch (mixerInFormat) {
+ case AUDIO_FORMAT_PCM_FLOAT:
+ return (AudioMixerBase::hook_t) &TrackBase::track__NoResample<
+ MIXTYPE_MULTI_STEREOVOL, float /*TO*/, float /*TI*/,
+ TYPE_AUX>;
+ case AUDIO_FORMAT_PCM_16_BIT:
+ return (AudioMixerBase::hook_t) &TrackBase::track__NoResample<
+ MIXTYPE_MULTI_STEREOVOL, int32_t /*TO*/, int16_t /*TI*/,
+ TYPE_AUX>;
+ default:
+ LOG_ALWAYS_FATAL("bad mixerInFormat: %#x", mixerInFormat);
+ break;
+ }
+ break;
+ default:
+ LOG_ALWAYS_FATAL("bad trackType: %d", trackType);
+ break;
+ }
+ return NULL;
+}
+
+/* Returns the proper process hook for mixing tracks. Currently works only for
+ * PROCESSTYPE_NORESAMPLEONETRACK, a mix involving one track, no resampling.
+ *
+ * TODO: Due to the special mixing considerations of duplicating to
+ * a stereo output track, the input track cannot be MONO. This should be
+ * prevented by the caller.
+ */
+/* static */
+AudioMixerBase::process_hook_t AudioMixerBase::getProcessHook(
+ int processType, uint32_t channelCount,
+ audio_format_t mixerInFormat, audio_format_t mixerOutFormat,
+ bool stereoVolume)
+{
+ if (processType != PROCESSTYPE_NORESAMPLEONETRACK) { // Only NORESAMPLEONETRACK
+ LOG_ALWAYS_FATAL("bad processType: %d", processType);
+ return NULL;
+ }
+ if (!kUseNewMixer && channelCount == FCC_2 && mixerInFormat == AUDIO_FORMAT_PCM_16_BIT) {
+ return &AudioMixerBase::process__oneTrack16BitsStereoNoResampling;
+ }
+ LOG_ALWAYS_FATAL_IF(channelCount > MAX_NUM_CHANNELS);
+
+ if (stereoVolume) { // templated arguments require explicit values.
+ switch (mixerInFormat) {
+ case AUDIO_FORMAT_PCM_FLOAT:
+ switch (mixerOutFormat) {
+ case AUDIO_FORMAT_PCM_FLOAT:
+ return &AudioMixerBase::process__noResampleOneTrack<
+ MIXTYPE_MULTI_SAVEONLY_STEREOVOL, float /*TO*/,
+ float /*TI*/, TYPE_AUX>;
+ case AUDIO_FORMAT_PCM_16_BIT:
+ return &AudioMixerBase::process__noResampleOneTrack<
+ MIXTYPE_MULTI_SAVEONLY_STEREOVOL, int16_t /*TO*/,
+ float /*TI*/, TYPE_AUX>;
+ default:
+ LOG_ALWAYS_FATAL("bad mixerOutFormat: %#x", mixerOutFormat);
+ break;
+ }
+ break;
+ case AUDIO_FORMAT_PCM_16_BIT:
+ switch (mixerOutFormat) {
+ case AUDIO_FORMAT_PCM_FLOAT:
+ return &AudioMixerBase::process__noResampleOneTrack<
+ MIXTYPE_MULTI_SAVEONLY_STEREOVOL, float /*TO*/,
+ int16_t /*TI*/, TYPE_AUX>;
+ case AUDIO_FORMAT_PCM_16_BIT:
+ return &AudioMixerBase::process__noResampleOneTrack<
+ MIXTYPE_MULTI_SAVEONLY_STEREOVOL, int16_t /*TO*/,
+ int16_t /*TI*/, TYPE_AUX>;
+ default:
+ LOG_ALWAYS_FATAL("bad mixerOutFormat: %#x", mixerOutFormat);
+ break;
+ }
+ break;
+ default:
+ LOG_ALWAYS_FATAL("bad mixerInFormat: %#x", mixerInFormat);
+ break;
+ }
+ } else {
+ switch (mixerInFormat) {
+ case AUDIO_FORMAT_PCM_FLOAT:
+ switch (mixerOutFormat) {
+ case AUDIO_FORMAT_PCM_FLOAT:
+ return &AudioMixerBase::process__noResampleOneTrack<
+ MIXTYPE_MULTI_SAVEONLY, float /*TO*/,
+ float /*TI*/, TYPE_AUX>;
+ case AUDIO_FORMAT_PCM_16_BIT:
+ return &AudioMixerBase::process__noResampleOneTrack<
+ MIXTYPE_MULTI_SAVEONLY, int16_t /*TO*/,
+ float /*TI*/, TYPE_AUX>;
+ default:
+ LOG_ALWAYS_FATAL("bad mixerOutFormat: %#x", mixerOutFormat);
+ break;
+ }
+ break;
+ case AUDIO_FORMAT_PCM_16_BIT:
+ switch (mixerOutFormat) {
+ case AUDIO_FORMAT_PCM_FLOAT:
+ return &AudioMixerBase::process__noResampleOneTrack<
+ MIXTYPE_MULTI_SAVEONLY, float /*TO*/,
+ int16_t /*TI*/, TYPE_AUX>;
+ case AUDIO_FORMAT_PCM_16_BIT:
+ return &AudioMixerBase::process__noResampleOneTrack<
+ MIXTYPE_MULTI_SAVEONLY, int16_t /*TO*/,
+ int16_t /*TI*/, TYPE_AUX>;
+ default:
+ LOG_ALWAYS_FATAL("bad mixerOutFormat: %#x", mixerOutFormat);
+ break;
+ }
+ break;
+ default:
+ LOG_ALWAYS_FATAL("bad mixerInFormat: %#x", mixerInFormat);
+ break;
+ }
+ }
+ return NULL;
+}
+
+// ----------------------------------------------------------------------------
+} // namespace android
diff --git a/media/libaudioprocessing/AudioMixerOps.h b/media/libaudioprocessing/AudioMixerOps.h
index f33e361..2748182 100644
--- a/media/libaudioprocessing/AudioMixerOps.h
+++ b/media/libaudioprocessing/AudioMixerOps.h
@@ -19,21 +19,10 @@
namespace android {
-/* Behavior of is_same<>::value is true if the types are identical,
- * false otherwise. Identical to the STL std::is_same.
- */
-template<typename T, typename U>
-struct is_same
-{
- static const bool value = false;
-};
-
-template<typename T>
-struct is_same<T, T> // partial specialization
-{
- static const bool value = true;
-};
-
+// Hack to make static_assert work in a constexpr
+// https://en.cppreference.com/w/cpp/language/if
+template <int N>
+inline constexpr bool dependent_false = false;
/* MixMul is a multiplication operator to scale an audio input signal
* by a volume gain, with the formula:
@@ -179,7 +168,7 @@
template <typename TO, typename TI>
inline void MixAccum(TO *auxaccum, TI value) {
- if (!is_same<TO, TI>::value) {
+ if (!std::is_same_v<TO, TI>) {
LOG_ALWAYS_FATAL("MixAccum type not properly specialized: %zu %zu\n",
sizeof(TO), sizeof(TI));
}
@@ -228,9 +217,79 @@
MIXTYPE_MULTI_SAVEONLY,
MIXTYPE_MULTI_MONOVOL,
MIXTYPE_MULTI_SAVEONLY_MONOVOL,
+ MIXTYPE_MULTI_STEREOVOL,
+ MIXTYPE_MULTI_SAVEONLY_STEREOVOL,
+ MIXTYPE_STEREOEXPAND,
};
/*
+ * TODO: We should work on non-interleaved streams - the
+ * complexity of working on interleaved streams is now getting
+ * too high, and likely limits compiler optimization.
+ */
+template <int MIXTYPE, int NCHAN,
+ typename TO, typename TI, typename TV,
+ typename F>
+void stereoVolumeHelper(TO*& out, const TI*& in, const TV *vol, F f) {
+ static_assert(NCHAN > 0 && NCHAN <= 8);
+ static_assert(MIXTYPE == MIXTYPE_MULTI_STEREOVOL
+ || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL
+ || MIXTYPE == MIXTYPE_STEREOEXPAND);
+ auto proc = [](auto& a, const auto& b) {
+ if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL) {
+ a += b;
+ } else {
+ a = b;
+ }
+ };
+ auto inp = [&in]() -> const TI& {
+ if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND) {
+ return *in;
+ } else {
+ return *in++;
+ }
+ };
+
+ // HALs should only expose the canonical channel masks.
+ proc(*out++, f(inp(), vol[0])); // front left
+ if constexpr (NCHAN == 1) return;
+ proc(*out++, f(inp(), vol[1])); // front right
+ if constexpr (NCHAN == 2) return;
+ if constexpr (NCHAN == 4) {
+ proc(*out++, f(inp(), vol[0])); // back left
+ proc(*out++, f(inp(), vol[1])); // back right
+ return;
+ }
+
+ // TODO: Precompute center volume if not ramping.
+ std::decay_t<TV> center;
+ if constexpr (std::is_floating_point_v<TV>) {
+ center = (vol[0] + vol[1]) * 0.5; // do not use divide
+ } else {
+ center = (vol[0] >> 1) + (vol[1] >> 1); // rounds to 0.
+ }
+ proc(*out++, f(inp(), center)); // center (or 2.1 LFE)
+ if constexpr (NCHAN == 3) return;
+ if constexpr (NCHAN == 5) {
+ proc(*out++, f(inp(), vol[0])); // back left
+ proc(*out++, f(inp(), vol[1])); // back right
+ return;
+ }
+
+ proc(*out++, f(inp(), center)); // lfe
+ proc(*out++, f(inp(), vol[0])); // back left
+ proc(*out++, f(inp(), vol[1])); // back right
+ if constexpr (NCHAN == 6) return;
+ if constexpr (NCHAN == 7) {
+ proc(*out++, f(inp(), center)); // back center
+ return;
+ }
+ // NCHAN == 8
+ proc(*out++, f(inp(), vol[0])); // side left
+ proc(*out++, f(inp(), vol[1])); // side right
+}
+
+/*
* The volumeRampMulti and volumeRamp functions take a MIXTYPE
* which indicates the per-frame mixing and accumulation strategy.
*
@@ -271,6 +330,17 @@
* MIXTYPE_MULTI_SAVEONLY_MONOVOL:
* Same as MIXTYPE_MULTI_SAVEONLY, but uses only volume[0].
*
+ * MIXTYPE_MULTI_STEREOVOL:
+ * Same as MIXTYPE_MULTI, but uses only volume[0] and volume[1].
+ *
+ * MIXTYPE_MULTI_SAVEONLY_STEREOVOL:
+ * Same as MIXTYPE_MULTI_SAVEONLY, but uses only volume[0] and volume[1].
+ *
+ * MIXTYPE_STEREOEXPAND:
+ * Stereo input channel. NCHAN represents number of output channels.
+ * Expand size 2 array "in" and "vol" to multi-channel output. Note
+ * that the 2 array is assumed to have replicated L+R.
+ *
*/
template <int MIXTYPE, int NCHAN,
@@ -284,41 +354,44 @@
if (aux != NULL) {
do {
TA auxaccum = 0;
- switch (MIXTYPE) {
- case MIXTYPE_MULTI:
+ if constexpr (MIXTYPE == MIXTYPE_MULTI) {
for (int i = 0; i < NCHAN; ++i) {
*out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
vol[i] += volinc[i];
}
- break;
- case MIXTYPE_MONOEXPAND:
+ } else if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) {
for (int i = 0; i < NCHAN; ++i) {
*out++ += MixMulAux<TO, TI, TV, TA>(*in, vol[i], &auxaccum);
vol[i] += volinc[i];
}
in++;
- break;
- case MIXTYPE_MULTI_SAVEONLY:
+ } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY) {
for (int i = 0; i < NCHAN; ++i) {
*out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
vol[i] += volinc[i];
}
- break;
- case MIXTYPE_MULTI_MONOVOL:
+ } else if constexpr (MIXTYPE == MIXTYPE_MULTI_MONOVOL) {
for (int i = 0; i < NCHAN; ++i) {
*out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
}
vol[0] += volinc[0];
- break;
- case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
+ } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY_MONOVOL) {
for (int i = 0; i < NCHAN; ++i) {
*out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
}
vol[0] += volinc[0];
- break;
- default:
- LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
- break;
+ } else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL
+ || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL
+ || MIXTYPE == MIXTYPE_STEREOEXPAND) {
+ stereoVolumeHelper<MIXTYPE, NCHAN>(
+ out, in, vol, [&auxaccum] (auto &a, const auto &b) {
+ return MixMulAux<TO, TI, TV, TA>(a, b, &auxaccum);
+ });
+ if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND) in += 2;
+ vol[0] += volinc[0];
+ vol[1] += volinc[1];
+ } else /* constexpr */ {
+ static_assert(dependent_false<MIXTYPE>, "invalid mixtype");
}
auxaccum /= NCHAN;
*aux++ += MixMul<TA, TA, TAV>(auxaccum, *vola);
@@ -326,41 +399,43 @@
} while (--frameCount);
} else {
do {
- switch (MIXTYPE) {
- case MIXTYPE_MULTI:
+ if constexpr (MIXTYPE == MIXTYPE_MULTI) {
for (int i = 0; i < NCHAN; ++i) {
*out++ += MixMul<TO, TI, TV>(*in++, vol[i]);
vol[i] += volinc[i];
}
- break;
- case MIXTYPE_MONOEXPAND:
+ } else if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) {
for (int i = 0; i < NCHAN; ++i) {
*out++ += MixMul<TO, TI, TV>(*in, vol[i]);
vol[i] += volinc[i];
}
in++;
- break;
- case MIXTYPE_MULTI_SAVEONLY:
+ } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY) {
for (int i = 0; i < NCHAN; ++i) {
*out++ = MixMul<TO, TI, TV>(*in++, vol[i]);
vol[i] += volinc[i];
}
- break;
- case MIXTYPE_MULTI_MONOVOL:
+ } else if constexpr (MIXTYPE == MIXTYPE_MULTI_MONOVOL) {
for (int i = 0; i < NCHAN; ++i) {
*out++ += MixMul<TO, TI, TV>(*in++, vol[0]);
}
vol[0] += volinc[0];
- break;
- case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
+ } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY_MONOVOL) {
for (int i = 0; i < NCHAN; ++i) {
*out++ = MixMul<TO, TI, TV>(*in++, vol[0]);
}
vol[0] += volinc[0];
- break;
- default:
- LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
- break;
+ } else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL
+ || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL
+ || MIXTYPE == MIXTYPE_STEREOEXPAND) {
+ stereoVolumeHelper<MIXTYPE, NCHAN>(out, in, vol, [] (auto &a, const auto &b) {
+ return MixMul<TO, TI, TV>(a, b);
+ });
+ if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND) in += 2;
+ vol[0] += volinc[0];
+ vol[1] += volinc[1];
+ } else /* constexpr */ {
+ static_assert(dependent_false<MIXTYPE>, "invalid mixtype");
}
} while (--frameCount);
}
@@ -377,72 +452,73 @@
if (aux != NULL) {
do {
TA auxaccum = 0;
- switch (MIXTYPE) {
- case MIXTYPE_MULTI:
+ if constexpr (MIXTYPE == MIXTYPE_MULTI) {
for (int i = 0; i < NCHAN; ++i) {
*out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
}
- break;
- case MIXTYPE_MONOEXPAND:
+ } else if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) {
for (int i = 0; i < NCHAN; ++i) {
*out++ += MixMulAux<TO, TI, TV, TA>(*in, vol[i], &auxaccum);
}
in++;
- break;
- case MIXTYPE_MULTI_SAVEONLY:
+ } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY) {
for (int i = 0; i < NCHAN; ++i) {
*out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
}
- break;
- case MIXTYPE_MULTI_MONOVOL:
+ } else if constexpr (MIXTYPE == MIXTYPE_MULTI_MONOVOL) {
for (int i = 0; i < NCHAN; ++i) {
*out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
}
- break;
- case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
+ } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY_MONOVOL) {
for (int i = 0; i < NCHAN; ++i) {
*out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
}
- break;
- default:
- LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
- break;
+ } else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL
+ || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL
+ || MIXTYPE == MIXTYPE_STEREOEXPAND) {
+ stereoVolumeHelper<MIXTYPE, NCHAN>(
+ out, in, vol, [&auxaccum] (auto &a, const auto &b) {
+ return MixMulAux<TO, TI, TV, TA>(a, b, &auxaccum);
+ });
+ if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND) in += 2;
+ } else /* constexpr */ {
+ static_assert(dependent_false<MIXTYPE>, "invalid mixtype");
}
auxaccum /= NCHAN;
*aux++ += MixMul<TA, TA, TAV>(auxaccum, vola);
} while (--frameCount);
} else {
do {
- switch (MIXTYPE) {
- case MIXTYPE_MULTI:
+ if constexpr (MIXTYPE == MIXTYPE_MULTI) {
for (int i = 0; i < NCHAN; ++i) {
*out++ += MixMul<TO, TI, TV>(*in++, vol[i]);
}
- break;
- case MIXTYPE_MONOEXPAND:
+ } else if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) {
for (int i = 0; i < NCHAN; ++i) {
*out++ += MixMul<TO, TI, TV>(*in, vol[i]);
}
in++;
- break;
- case MIXTYPE_MULTI_SAVEONLY:
+ } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY) {
for (int i = 0; i < NCHAN; ++i) {
*out++ = MixMul<TO, TI, TV>(*in++, vol[i]);
}
- break;
- case MIXTYPE_MULTI_MONOVOL:
+ } else if constexpr (MIXTYPE == MIXTYPE_MULTI_MONOVOL) {
for (int i = 0; i < NCHAN; ++i) {
*out++ += MixMul<TO, TI, TV>(*in++, vol[0]);
}
- break;
- case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
+ } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY_MONOVOL) {
for (int i = 0; i < NCHAN; ++i) {
*out++ = MixMul<TO, TI, TV>(*in++, vol[0]);
}
- break;
- default:
- LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
- break;
+ } else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL
+ || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL
+ || MIXTYPE == MIXTYPE_STEREOEXPAND) {
+ stereoVolumeHelper<MIXTYPE, NCHAN>(out, in, vol, [] (auto &a, const auto &b) {
+ return MixMul<TO, TI, TV>(a, b);
+ });
+ if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND) in += 2;
+ } else /* constexpr */ {
+ static_assert(dependent_false<MIXTYPE>, "invalid mixtype");
}
} while (--frameCount);
}
diff --git a/media/libaudioprocessing/AudioResamplerFirOps.h b/media/libaudioprocessing/AudioResamplerFirOps.h
index 2e4cee3..a3f5ff5 100644
--- a/media/libaudioprocessing/AudioResamplerFirOps.h
+++ b/media/libaudioprocessing/AudioResamplerFirOps.h
@@ -36,13 +36,20 @@
#include <arm_neon.h>
#endif
-#if defined(__SSSE3__) // Should be supported in x86 ABI for both 32 & 64-bit.
+#if defined(__AVX2__) // Should be supported in x86 ABI for both 32 & 64-bit.
+#define USE_AVX2 (true) // Inference AVX2/FMA Intrinsics
#define USE_SSE (true)
+#include <immintrin.h>
+#elif defined(__SSSE3__) // Should be supported in x86 ABI for both 32 & 64-bit.
+#define USE_SSE (true) // Inference SSE Intrinsics
+#define USE_AVX2 (false)
#include <tmmintrin.h>
#else
#define USE_SSE (false)
+#define USE_AVX2(false)
#endif
+
template<typename T, typename U>
struct is_same
{
diff --git a/media/libaudioprocessing/AudioResamplerFirProcessSSE.h b/media/libaudioprocessing/AudioResamplerFirProcessSSE.h
index 30233b5..1c16bc4 100644
--- a/media/libaudioprocessing/AudioResamplerFirProcessSSE.h
+++ b/media/libaudioprocessing/AudioResamplerFirProcessSSE.h
@@ -80,11 +80,16 @@
posCoef1 = _mm_sub_ps(posCoef1, posCoef);
negCoef = _mm_sub_ps(negCoef, negCoef1);
+
+ #if USE_AVX2
+ posCoef = _mm_fmadd_ps(posCoef1, interp, posCoef);
+ negCoef = _mm_fmadd_ps(negCoef, interp, negCoef1);
+ #else
posCoef1 = _mm_mul_ps(posCoef1, interp);
negCoef = _mm_mul_ps(negCoef, interp);
-
posCoef = _mm_add_ps(posCoef1, posCoef);
negCoef = _mm_add_ps(negCoef, negCoef1);
+ #endif //USE_AVX2
}
switch (CHANNELS) {
case 1: {
@@ -94,11 +99,17 @@
sN += 4;
posSamp = _mm_shuffle_ps(posSamp, posSamp, 0x1B);
+
+ #if USE_AVX2
+ accL = _mm_fmadd_ps(posSamp, posCoef, accL);
+ accL = _mm_fmadd_ps(negSamp, negCoef, accL);
+ #else
posSamp = _mm_mul_ps(posSamp, posCoef);
negSamp = _mm_mul_ps(negSamp, negCoef);
-
accL = _mm_add_ps(accL, posSamp);
accL = _mm_add_ps(accL, negSamp);
+ #endif
+
} break;
case 2: {
__m128 posSamp0 = _mm_loadu_ps(sP);
@@ -114,15 +125,23 @@
__m128 negSampL = _mm_shuffle_ps(negSamp0, negSamp1, 0x88);
__m128 negSampR = _mm_shuffle_ps(negSamp0, negSamp1, 0xDD);
- posSampL = _mm_mul_ps(posSampL, posCoef);
- posSampR = _mm_mul_ps(posSampR, posCoef);
- negSampL = _mm_mul_ps(negSampL, negCoef);
- negSampR = _mm_mul_ps(negSampR, negCoef);
+ #if USE_AVX2
+ accL = _mm_fmadd_ps(posSampL, posCoef, accL);
+ accR = _mm_fmadd_ps(posSampR, posCoef, accR);
+ accL = _mm_fmadd_ps(negSampL, negCoef, accL);
+ accR = _mm_fmadd_ps(negSampR, negCoef, accR);
+ #else
+ posSampL = _mm_mul_ps(posSampL, posCoef);
+ posSampR = _mm_mul_ps(posSampR, posCoef);
+ negSampL = _mm_mul_ps(negSampL, negCoef);
+ negSampR = _mm_mul_ps(negSampR, negCoef);
- accL = _mm_add_ps(accL, posSampL);
- accR = _mm_add_ps(accR, posSampR);
- accL = _mm_add_ps(accL, negSampL);
- accR = _mm_add_ps(accR, negSampR);
+ accL = _mm_add_ps(accL, posSampL);
+ accR = _mm_add_ps(accR, posSampR);
+ accL = _mm_add_ps(accL, negSampL);
+ accR = _mm_add_ps(accR, negSampR);
+ #endif
+
} break;
}
} while (count -= 4);
@@ -144,9 +163,13 @@
outAccum = _mm_hadd_ps(accL, accR);
outAccum = _mm_hadd_ps(outAccum, outAccum);
}
-
+ #if USE_AVX2
+ outSamp = _mm_fmadd_ps(outAccum, vLR,outSamp);
+ #else
outAccum = _mm_mul_ps(outAccum, vLR);
outSamp = _mm_add_ps(outSamp, outAccum);
+ #endif
+
_mm_storel_pi(reinterpret_cast<__m64*>(out), outSamp);
}
diff --git a/media/libaudioprocessing/BufferProviders.cpp b/media/libaudioprocessing/BufferProviders.cpp
index 21d25e1..6d31c12 100644
--- a/media/libaudioprocessing/BufferProviders.cpp
+++ b/media/libaudioprocessing/BufferProviders.cpp
@@ -164,6 +164,7 @@
if (mEffectsFactory->createEffect(&sDwnmFxDesc.uuid,
sessionId,
SESSION_ID_INVALID_AND_IGNORED,
+ AUDIO_PORT_HANDLE_NONE,
&mDownmixInterface) != 0) {
ALOGE("DownmixerBufferProvider() error creating downmixer effect");
mDownmixInterface.clear();
diff --git a/media/libaudioprocessing/include/media/AudioMixer.h b/media/libaudioprocessing/include/media/AudioMixer.h
new file mode 100644
index 0000000..3f7cd48
--- /dev/null
+++ b/media/libaudioprocessing/include/media/AudioMixer.h
@@ -0,0 +1,238 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ANDROID_AUDIO_MIXER_H
+#define ANDROID_AUDIO_MIXER_H
+
+#include <pthread.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <android/os/IExternalVibratorService.h>
+#include <media/AudioMixerBase.h>
+#include <media/BufferProviders.h>
+#include <utils/threads.h>
+
+// FIXME This is actually unity gain, which might not be max in future, expressed in U.12
+#define MAX_GAIN_INT AudioMixerBase::UNITY_GAIN_INT
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+// AudioMixer extends AudioMixerBase by adding support for down- and up-mixing
+// and time stretch that are implemented via Effects HAL, and adding support
+// for haptic channels which depends on Vibrator service. This is the version
+// that is used by Audioflinger.
+
+class AudioMixer : public AudioMixerBase
+{
+public:
+ // maximum number of channels supported for the content
+ static const uint32_t MAX_NUM_CHANNELS_TO_DOWNMIX = AUDIO_CHANNEL_COUNT_MAX;
+
+ enum { // extension of AudioMixerBase parameters
+ DOWNMIX_TYPE = 0x4004,
+ // for haptic
+ HAPTIC_ENABLED = 0x4007, // Set haptic data from this track should be played or not.
+ HAPTIC_INTENSITY = 0x4008, // Set the intensity to play haptic data.
+ // for target TIMESTRETCH
+ PLAYBACK_RATE = 0x4300, // Configure timestretch on this track name;
+ // parameter 'value' is a pointer to the new playback rate.
+ };
+
+ typedef enum { // Haptic intensity, should keep consistent with VibratorService
+ HAPTIC_SCALE_MUTE = os::IExternalVibratorService::SCALE_MUTE,
+ HAPTIC_SCALE_VERY_LOW = os::IExternalVibratorService::SCALE_VERY_LOW,
+ HAPTIC_SCALE_LOW = os::IExternalVibratorService::SCALE_LOW,
+ HAPTIC_SCALE_NONE = os::IExternalVibratorService::SCALE_NONE,
+ HAPTIC_SCALE_HIGH = os::IExternalVibratorService::SCALE_HIGH,
+ HAPTIC_SCALE_VERY_HIGH = os::IExternalVibratorService::SCALE_VERY_HIGH,
+ } haptic_intensity_t;
+ static constexpr float HAPTIC_SCALE_VERY_LOW_RATIO = 2.0f / 3.0f;
+ static constexpr float HAPTIC_SCALE_LOW_RATIO = 3.0f / 4.0f;
+ static const constexpr float HAPTIC_MAX_AMPLITUDE_FLOAT = 1.0f;
+
+ static inline bool isValidHapticIntensity(haptic_intensity_t hapticIntensity) {
+ switch (hapticIntensity) {
+ case HAPTIC_SCALE_MUTE:
+ case HAPTIC_SCALE_VERY_LOW:
+ case HAPTIC_SCALE_LOW:
+ case HAPTIC_SCALE_NONE:
+ case HAPTIC_SCALE_HIGH:
+ case HAPTIC_SCALE_VERY_HIGH:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ AudioMixer(size_t frameCount, uint32_t sampleRate)
+ : AudioMixerBase(frameCount, sampleRate) {
+ pthread_once(&sOnceControl, &sInitRoutine);
+ }
+
+ bool isValidChannelMask(audio_channel_mask_t channelMask) const override;
+
+ void setParameter(int name, int target, int param, void *value) override;
+ void setBufferProvider(int name, AudioBufferProvider* bufferProvider);
+
+private:
+
+ struct Track : public TrackBase {
+ Track() : TrackBase() {}
+
+ ~Track()
+ {
+ // mInputBufferProvider need not be deleted.
+ // Ensure the order of destruction of buffer providers as they
+ // release the upstream provider in the destructor.
+ mTimestretchBufferProvider.reset(nullptr);
+ mPostDownmixReformatBufferProvider.reset(nullptr);
+ mDownmixerBufferProvider.reset(nullptr);
+ mReformatBufferProvider.reset(nullptr);
+ mContractChannelsNonDestructiveBufferProvider.reset(nullptr);
+ mAdjustChannelsBufferProvider.reset(nullptr);
+ }
+
+ uint32_t getOutputChannelCount() override {
+ return mDownmixerBufferProvider.get() != nullptr ? mMixerChannelCount : channelCount;
+ }
+ uint32_t getMixerChannelCount() override {
+ return mMixerChannelCount + mMixerHapticChannelCount;
+ }
+
+ status_t prepareForDownmix();
+ void unprepareForDownmix();
+ status_t prepareForReformat();
+ void unprepareForReformat();
+ status_t prepareForAdjustChannels();
+ void unprepareForAdjustChannels();
+ status_t prepareForAdjustChannelsNonDestructive(size_t frames);
+ void unprepareForAdjustChannelsNonDestructive();
+ void clearContractedBuffer();
+ bool setPlaybackRate(const AudioPlaybackRate &playbackRate);
+ void reconfigureBufferProviders();
+
+ /* Buffer providers are constructed to translate the track input data as needed.
+ * See DownmixerBufferProvider below for how the Track buffer provider
+ * is wrapped by another one when dowmixing is required.
+ *
+ * TODO: perhaps make a single PlaybackConverterProvider class to move
+ * all pre-mixer track buffer conversions outside the AudioMixer class.
+ *
+ * 1) mInputBufferProvider: The AudioTrack buffer provider.
+ * 2) mAdjustChannelsBufferProvider: Expands or contracts sample data from one interleaved
+ * channel format to another. Expanded channels are filled with zeros and put at the end
+ * of each audio frame. Contracted channels are copied to the end of the buffer.
+ * 3) mContractChannelsNonDestructiveBufferProvider: Non-destructively contract sample data.
+ * This is currently using at audio-haptic coupled playback to separate audio and haptic
+ * data. Contracted channels could be written to given buffer.
+ * 4) mReformatBufferProvider: If not NULL, performs the audio reformat to
+ * match either mMixerInFormat or mDownmixRequiresFormat, if the downmixer
+ * requires reformat. For example, it may convert floating point input to
+ * PCM_16_bit if that's required by the downmixer.
+ * 5) mDownmixerBufferProvider: If not NULL, performs the channel remixing to match
+ * the number of channels required by the mixer sink.
+ * 6) mPostDownmixReformatBufferProvider: If not NULL, performs reformatting from
+ * the downmixer requirements to the mixer engine input requirements.
+ * 7) mTimestretchBufferProvider: Adds timestretching for playback rate
+ */
+ AudioBufferProvider* mInputBufferProvider; // externally provided buffer provider.
+ // TODO: combine mAdjustChannelsBufferProvider and
+ // mContractChannelsNonDestructiveBufferProvider
+ std::unique_ptr<PassthruBufferProvider> mAdjustChannelsBufferProvider;
+ std::unique_ptr<PassthruBufferProvider> mContractChannelsNonDestructiveBufferProvider;
+ std::unique_ptr<PassthruBufferProvider> mReformatBufferProvider;
+ std::unique_ptr<PassthruBufferProvider> mDownmixerBufferProvider;
+ std::unique_ptr<PassthruBufferProvider> mPostDownmixReformatBufferProvider;
+ std::unique_ptr<PassthruBufferProvider> mTimestretchBufferProvider;
+
+ audio_format_t mDownmixRequiresFormat; // required downmixer format
+ // AUDIO_FORMAT_PCM_16_BIT if 16 bit necessary
+ // AUDIO_FORMAT_INVALID if no required format
+
+ AudioPlaybackRate mPlaybackRate;
+
+ // Haptic
+ bool mHapticPlaybackEnabled;
+ haptic_intensity_t mHapticIntensity;
+ audio_channel_mask_t mHapticChannelMask;
+ uint32_t mHapticChannelCount;
+ audio_channel_mask_t mMixerHapticChannelMask;
+ uint32_t mMixerHapticChannelCount;
+ uint32_t mAdjustInChannelCount;
+ uint32_t mAdjustOutChannelCount;
+ uint32_t mAdjustNonDestructiveInChannelCount;
+ uint32_t mAdjustNonDestructiveOutChannelCount;
+ bool mKeepContractedChannels;
+
+ float getHapticScaleGamma() const {
+ // Need to keep consistent with the value in VibratorService.
+ switch (mHapticIntensity) {
+ case HAPTIC_SCALE_VERY_LOW:
+ return 2.0f;
+ case HAPTIC_SCALE_LOW:
+ return 1.5f;
+ case HAPTIC_SCALE_HIGH:
+ return 0.5f;
+ case HAPTIC_SCALE_VERY_HIGH:
+ return 0.25f;
+ default:
+ return 1.0f;
+ }
+ }
+
+ float getHapticMaxAmplitudeRatio() const {
+ // Need to keep consistent with the value in VibratorService.
+ switch (mHapticIntensity) {
+ case HAPTIC_SCALE_VERY_LOW:
+ return HAPTIC_SCALE_VERY_LOW_RATIO;
+ case HAPTIC_SCALE_LOW:
+ return HAPTIC_SCALE_LOW_RATIO;
+ case HAPTIC_SCALE_NONE:
+ case HAPTIC_SCALE_HIGH:
+ case HAPTIC_SCALE_VERY_HIGH:
+ return 1.0f;
+ default:
+ return 0.0f;
+ }
+ }
+ };
+
+ inline std::shared_ptr<Track> getTrack(int name) {
+ return std::static_pointer_cast<Track>(mTracks[name]);
+ }
+
+ std::shared_ptr<TrackBase> preCreateTrack() override;
+ status_t postCreateTrack(TrackBase *track) override;
+
+ void preProcess() override;
+ void postProcess() override;
+
+ bool setChannelMasks(int name,
+ audio_channel_mask_t trackChannelMask, audio_channel_mask_t mixerChannelMask) override;
+
+ static void sInitRoutine();
+
+ static pthread_once_t sOnceControl; // initialized in constructor by first new
+};
+
+// ----------------------------------------------------------------------------
+} // namespace android
+
+#endif // ANDROID_AUDIO_MIXER_H
diff --git a/media/libaudioprocessing/include/media/AudioMixerBase.h b/media/libaudioprocessing/include/media/AudioMixerBase.h
new file mode 100644
index 0000000..cf84b83
--- /dev/null
+++ b/media/libaudioprocessing/include/media/AudioMixerBase.h
@@ -0,0 +1,371 @@
+/*
+**
+** Copyright 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.
+*/
+
+#ifndef ANDROID_AUDIO_MIXER_BASE_H
+#define ANDROID_AUDIO_MIXER_BASE_H
+
+#include <map>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <media/AudioBufferProvider.h>
+#include <media/AudioResampler.h>
+#include <media/AudioResamplerPublic.h>
+#include <system/audio.h>
+#include <utils/Compat.h>
+
+// This must match frameworks/av/services/audioflinger/Configuration.h
+// when used with the Audio Framework.
+#define FLOAT_AUX
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+// AudioMixerBase is functional on its own if only mixing and resampling
+// is needed.
+
+class AudioMixerBase
+{
+public:
+ // Do not change these unless underlying code changes.
+ // This mixer has a hard-coded upper limit of 8 channels for output.
+ static constexpr uint32_t MAX_NUM_CHANNELS = FCC_8;
+ static constexpr uint32_t MAX_NUM_VOLUMES = FCC_2; // stereo volume only
+
+ static const uint16_t UNITY_GAIN_INT = 0x1000;
+ static const CONSTEXPR float UNITY_GAIN_FLOAT = 1.0f;
+
+ enum { // names
+ // setParameter targets
+ TRACK = 0x3000,
+ RESAMPLE = 0x3001,
+ RAMP_VOLUME = 0x3002, // ramp to new volume
+ VOLUME = 0x3003, // don't ramp
+ TIMESTRETCH = 0x3004,
+
+ // set Parameter names
+ // for target TRACK
+ CHANNEL_MASK = 0x4000,
+ FORMAT = 0x4001,
+ MAIN_BUFFER = 0x4002,
+ AUX_BUFFER = 0x4003,
+ // 0x4004 reserved
+ MIXER_FORMAT = 0x4005, // AUDIO_FORMAT_PCM_(FLOAT|16_BIT)
+ MIXER_CHANNEL_MASK = 0x4006, // Channel mask for mixer output
+ // for target RESAMPLE
+ SAMPLE_RATE = 0x4100, // Configure sample rate conversion on this track name;
+ // parameter 'value' is the new sample rate in Hz.
+ // Only creates a sample rate converter the first time that
+ // the track sample rate is different from the mix sample rate.
+ // If the new sample rate is the same as the mix sample rate,
+ // and a sample rate converter already exists,
+ // then the sample rate converter remains present but is a no-op.
+ RESET = 0x4101, // Reset sample rate converter without changing sample rate.
+ // This clears out the resampler's input buffer.
+ REMOVE = 0x4102, // Remove the sample rate converter on this track name;
+ // the track is restored to the mix sample rate.
+ // for target RAMP_VOLUME and VOLUME (8 channels max)
+ // FIXME use float for these 3 to improve the dynamic range
+ VOLUME0 = 0x4200,
+ VOLUME1 = 0x4201,
+ AUXLEVEL = 0x4210,
+ };
+
+ AudioMixerBase(size_t frameCount, uint32_t sampleRate)
+ : mSampleRate(sampleRate)
+ , mFrameCount(frameCount) {
+ }
+
+ virtual ~AudioMixerBase() {}
+
+ virtual bool isValidFormat(audio_format_t format) const;
+ virtual bool isValidChannelMask(audio_channel_mask_t channelMask) const;
+
+ // Create a new track in the mixer.
+ //
+ // \param name a unique user-provided integer associated with the track.
+ // If name already exists, the function will abort.
+ // \param channelMask output channel mask.
+ // \param format PCM format
+ // \param sessionId Session id for the track. Tracks with the same
+ // session id will be submixed together.
+ //
+ // \return OK on success.
+ // BAD_VALUE if the format does not satisfy isValidFormat()
+ // or the channelMask does not satisfy isValidChannelMask().
+ status_t create(
+ int name, audio_channel_mask_t channelMask, audio_format_t format, int sessionId);
+
+ bool exists(int name) const {
+ return mTracks.count(name) > 0;
+ }
+
+ // Free an allocated track by name.
+ void destroy(int name);
+
+ // Enable or disable an allocated track by name
+ void enable(int name);
+ void disable(int name);
+
+ virtual void setParameter(int name, int target, int param, void *value);
+
+ void process() {
+ preProcess();
+ (this->*mHook)();
+ postProcess();
+ }
+
+ size_t getUnreleasedFrames(int name) const;
+
+ std::string trackNames() const;
+
+ protected:
+ // Set kUseNewMixer to true to use the new mixer engine always. Otherwise the
+ // original code will be used for stereo sinks, the new mixer for everything else.
+ static constexpr bool kUseNewMixer = true;
+
+ // Set kUseFloat to true to allow floating input into the mixer engine.
+ // If kUseNewMixer is false, this is ignored or may be overridden internally
+ static constexpr bool kUseFloat = true;
+
+#ifdef FLOAT_AUX
+ using TYPE_AUX = float;
+ static_assert(kUseNewMixer && kUseFloat,
+ "kUseNewMixer and kUseFloat must be true for FLOAT_AUX option");
+#else
+ using TYPE_AUX = int32_t; // q4.27
+#endif
+
+ /* For multi-format functions (calls template functions
+ * in AudioMixerOps.h). The template parameters are as follows:
+ *
+ * MIXTYPE (see AudioMixerOps.h MIXTYPE_* enumeration)
+ * USEFLOATVOL (set to true if float volume is used)
+ * ADJUSTVOL (set to true if volume ramp parameters needs adjustment afterwards)
+ * TO: int32_t (Q4.27) or float
+ * TI: int32_t (Q4.27) or int16_t (Q0.15) or float
+ * TA: int32_t (Q4.27)
+ */
+
+ enum {
+ // FIXME this representation permits up to 8 channels
+ NEEDS_CHANNEL_COUNT__MASK = 0x00000007,
+ };
+
+ enum {
+ NEEDS_CHANNEL_1 = 0x00000000, // mono
+ NEEDS_CHANNEL_2 = 0x00000001, // stereo
+
+ // sample format is not explicitly specified, and is assumed to be AUDIO_FORMAT_PCM_16_BIT
+
+ NEEDS_MUTE = 0x00000100,
+ NEEDS_RESAMPLE = 0x00001000,
+ NEEDS_AUX = 0x00010000,
+ };
+
+ // hook types
+ enum {
+ PROCESSTYPE_NORESAMPLEONETRACK, // others set elsewhere
+ };
+
+ enum {
+ TRACKTYPE_NOP,
+ TRACKTYPE_RESAMPLE,
+ TRACKTYPE_RESAMPLEMONO,
+ TRACKTYPE_RESAMPLESTEREO,
+ TRACKTYPE_NORESAMPLE,
+ TRACKTYPE_NORESAMPLEMONO,
+ TRACKTYPE_NORESAMPLESTEREO,
+ };
+
+ // process hook functionality
+ using process_hook_t = void(AudioMixerBase::*)();
+
+ static bool isAudioChannelPositionMask(audio_channel_mask_t channelMask) {
+ return audio_channel_mask_get_representation(channelMask)
+ == AUDIO_CHANNEL_REPRESENTATION_POSITION;
+ }
+
+ struct TrackBase;
+ using hook_t = void(TrackBase::*)(
+ int32_t* output, size_t numOutFrames, int32_t* temp, int32_t* aux);
+
+ struct TrackBase {
+ TrackBase()
+ : bufferProvider(nullptr)
+ {
+ // TODO: move additional initialization here.
+ }
+ virtual ~TrackBase() {}
+
+ virtual uint32_t getOutputChannelCount() { return channelCount; }
+ virtual uint32_t getMixerChannelCount() { return mMixerChannelCount; }
+
+ bool needsRamp() { return (volumeInc[0] | volumeInc[1] | auxInc) != 0; }
+ bool setResampler(uint32_t trackSampleRate, uint32_t devSampleRate);
+ bool doesResample() const { return mResampler.get() != nullptr; }
+ void recreateResampler(uint32_t devSampleRate);
+ void resetResampler() { if (mResampler.get() != nullptr) mResampler->reset(); }
+ void adjustVolumeRamp(bool aux, bool useFloat = false);
+ size_t getUnreleasedFrames() const { return mResampler.get() != nullptr ?
+ mResampler->getUnreleasedFrames() : 0; };
+
+ bool useStereoVolume() const { return channelMask == AUDIO_CHANNEL_OUT_STEREO
+ && isAudioChannelPositionMask(mMixerChannelMask); }
+
+ static hook_t getTrackHook(int trackType, uint32_t channelCount,
+ audio_format_t mixerInFormat, audio_format_t mixerOutFormat);
+
+ void track__nop(int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
+
+ template <int MIXTYPE, bool USEFLOATVOL, bool ADJUSTVOL,
+ typename TO, typename TI, typename TA>
+ void volumeMix(TO *out, size_t outFrames, const TI *in, TA *aux, bool ramp);
+
+ uint32_t needs;
+
+ // TODO: Eventually remove legacy integer volume settings
+ union {
+ int16_t volume[MAX_NUM_VOLUMES]; // U4.12 fixed point (top bit should be zero)
+ int32_t volumeRL;
+ };
+
+ int32_t prevVolume[MAX_NUM_VOLUMES];
+ int32_t volumeInc[MAX_NUM_VOLUMES];
+ int32_t auxInc;
+ int32_t prevAuxLevel;
+ int16_t auxLevel; // 0 <= auxLevel <= MAX_GAIN_INT, but signed for mul performance
+
+ uint16_t frameCount;
+
+ uint8_t channelCount; // 1 or 2, redundant with (needs & NEEDS_CHANNEL_COUNT__MASK)
+ uint8_t unused_padding; // formerly format, was always 16
+ uint16_t enabled; // actually bool
+ audio_channel_mask_t channelMask;
+
+ // actual buffer provider used by the track hooks
+ AudioBufferProvider* bufferProvider;
+
+ mutable AudioBufferProvider::Buffer buffer; // 8 bytes
+
+ hook_t hook;
+ const void *mIn; // current location in buffer
+
+ std::unique_ptr<AudioResampler> mResampler;
+ uint32_t sampleRate;
+ int32_t* mainBuffer;
+ int32_t* auxBuffer;
+
+ int32_t sessionId;
+
+ audio_format_t mMixerFormat; // output mix format: AUDIO_FORMAT_PCM_(FLOAT|16_BIT)
+ audio_format_t mFormat; // input track format
+ audio_format_t mMixerInFormat; // mix internal format AUDIO_FORMAT_PCM_(FLOAT|16_BIT)
+ // each track must be converted to this format.
+
+ float mVolume[MAX_NUM_VOLUMES]; // floating point set volume
+ float mPrevVolume[MAX_NUM_VOLUMES]; // floating point previous volume
+ float mVolumeInc[MAX_NUM_VOLUMES]; // floating point volume increment
+
+ float mAuxLevel; // floating point set aux level
+ float mPrevAuxLevel; // floating point prev aux level
+ float mAuxInc; // floating point aux increment
+
+ audio_channel_mask_t mMixerChannelMask;
+ uint32_t mMixerChannelCount;
+
+ protected:
+
+ // hooks
+ void track__genericResample(int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
+ void track__16BitsStereo(int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
+ void track__16BitsMono(int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
+
+ void volumeRampStereo(int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux);
+ void volumeStereo(int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux);
+
+ // multi-format track hooks
+ template <int MIXTYPE, typename TO, typename TI, typename TA>
+ void track__Resample(TO* out, size_t frameCount, TO* temp __unused, TA* aux);
+ template <int MIXTYPE, typename TO, typename TI, typename TA>
+ void track__NoResample(TO* out, size_t frameCount, TO* temp __unused, TA* aux);
+ };
+
+ // preCreateTrack must create an instance of a proper TrackBase descendant.
+ // postCreateTrack is called after filling out fields of TrackBase. It can
+ // abort track creation by returning non-OK status. See the implementation
+ // of create() for details.
+ virtual std::shared_ptr<TrackBase> preCreateTrack();
+ virtual status_t postCreateTrack(TrackBase *track __unused) { return OK; }
+
+ // preProcess is called before the process hook, postProcess after,
+ // see the implementation of process() method.
+ virtual void preProcess() {}
+ virtual void postProcess() {}
+
+ virtual bool setChannelMasks(int name,
+ audio_channel_mask_t trackChannelMask, audio_channel_mask_t mixerChannelMask);
+
+ // Called when track info changes and a new process hook should be determined.
+ void invalidate() {
+ mHook = &AudioMixerBase::process__validate;
+ }
+
+ void process__validate();
+ void process__nop();
+ void process__genericNoResampling();
+ void process__genericResampling();
+ void process__oneTrack16BitsStereoNoResampling();
+
+ template <int MIXTYPE, typename TO, typename TI, typename TA>
+ void process__noResampleOneTrack();
+
+ static process_hook_t getProcessHook(int processType, uint32_t channelCount,
+ audio_format_t mixerInFormat, audio_format_t mixerOutFormat,
+ bool useStereoVolume);
+
+ static void convertMixerFormat(void *out, audio_format_t mixerOutFormat,
+ void *in, audio_format_t mixerInFormat, size_t sampleCount);
+
+ // initialization constants
+ const uint32_t mSampleRate;
+ const size_t mFrameCount;
+
+ process_hook_t mHook = &AudioMixerBase::process__nop; // one of process__*, never nullptr
+
+ // the size of the type (int32_t) should be the largest of all types supported
+ // by the mixer.
+ std::unique_ptr<int32_t[]> mOutputTemp;
+ std::unique_ptr<int32_t[]> mResampleTemp;
+
+ // track names grouped by main buffer, in no particular order of main buffer.
+ // however names for a particular main buffer are in order (by construction).
+ std::unordered_map<void * /* mainBuffer */, std::vector<int /* name */>> mGroups;
+
+ // track names that are enabled, in increasing order (by construction).
+ std::vector<int /* name */> mEnabled;
+
+ // track smart pointers, by name, in increasing order of name.
+ std::map<int /* name */, std::shared_ptr<TrackBase>> mTracks;
+};
+
+} // namespace android
+
+#endif // ANDROID_AUDIO_MIXER_BASE_H
diff --git a/media/libaudioprocessing/include/media/AudioResamplerPublic.h b/media/libaudioprocessing/include/media/AudioResamplerPublic.h
index 50ca33d..1b39067 100644
--- a/media/libaudioprocessing/include/media/AudioResamplerPublic.h
+++ b/media/libaudioprocessing/include/media/AudioResamplerPublic.h
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <math.h>
+#include <system/audio.h>
namespace android {
@@ -37,68 +38,16 @@
// an int32_t of the phase increments, making the resulting sample rate inexact.
#define AUDIO_RESAMPLER_UP_RATIO_MAX 65536
-// AUDIO_TIMESTRETCH_SPEED_MIN and AUDIO_TIMESTRETCH_SPEED_MAX define the min and max time stretch
-// speeds supported by the system. These are enforced by the system and values outside this range
-// will result in a runtime error.
-// Depending on the AudioPlaybackRate::mStretchMode, the effective limits might be narrower than
-// the ones specified here
-// AUDIO_TIMESTRETCH_SPEED_MIN_DELTA is the minimum absolute speed difference that might trigger a
-// parameter update
-#define AUDIO_TIMESTRETCH_SPEED_MIN 0.01f
-#define AUDIO_TIMESTRETCH_SPEED_MAX 20.0f
-#define AUDIO_TIMESTRETCH_SPEED_NORMAL 1.0f
-#define AUDIO_TIMESTRETCH_SPEED_MIN_DELTA 0.0001f
-
-// AUDIO_TIMESTRETCH_PITCH_MIN and AUDIO_TIMESTRETCH_PITCH_MAX define the min and max time stretch
-// pitch shifting supported by the system. These are not enforced by the system and values
-// outside this range might result in a pitch different than the one requested.
-// Depending on the AudioPlaybackRate::mStretchMode, the effective limits might be narrower than
-// the ones specified here.
-// AUDIO_TIMESTRETCH_PITCH_MIN_DELTA is the minimum absolute pitch difference that might trigger a
-// parameter update
-#define AUDIO_TIMESTRETCH_PITCH_MIN 0.25f
-#define AUDIO_TIMESTRETCH_PITCH_MAX 4.0f
-#define AUDIO_TIMESTRETCH_PITCH_NORMAL 1.0f
-#define AUDIO_TIMESTRETCH_PITCH_MIN_DELTA 0.0001f
-
-
//Determines the current algorithm used for stretching
-enum AudioTimestretchStretchMode : int32_t {
- AUDIO_TIMESTRETCH_STRETCH_DEFAULT = 0,
- AUDIO_TIMESTRETCH_STRETCH_SPEECH = 1,
- //TODO: add more stretch modes/algorithms
-};
-
-//Limits for AUDIO_TIMESTRETCH_STRETCH_SPEECH mode
-#define TIMESTRETCH_SONIC_SPEED_MIN 0.1f
-#define TIMESTRETCH_SONIC_SPEED_MAX 6.0f
+using AudioTimestretchStretchMode = ::audio_timestretch_stretch_mode_t;
//Determines behavior of Timestretch if current algorithm can't perform
//with current parameters.
-// FALLBACK_CUT_REPEAT: (internal only) for speed <1.0 will truncate frames
-// for speed > 1.0 will repeat frames
-// FALLBACK_MUTE: will set all processed frames to zero
-// FALLBACK_FAIL: will stop program execution and log a fatal error
-enum AudioTimestretchFallbackMode : int32_t {
- AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT = -1,
- AUDIO_TIMESTRETCH_FALLBACK_DEFAULT = 0,
- AUDIO_TIMESTRETCH_FALLBACK_MUTE = 1,
- AUDIO_TIMESTRETCH_FALLBACK_FAIL = 2,
-};
+using AudioTimestretchFallbackMode = ::audio_timestretch_fallback_mode_t;
-struct AudioPlaybackRate {
- float mSpeed;
- float mPitch;
- enum AudioTimestretchStretchMode mStretchMode;
- enum AudioTimestretchFallbackMode mFallbackMode;
-};
+using AudioPlaybackRate = ::audio_playback_rate_t;
-static const AudioPlaybackRate AUDIO_PLAYBACK_RATE_DEFAULT = {
- AUDIO_TIMESTRETCH_SPEED_NORMAL,
- AUDIO_TIMESTRETCH_PITCH_NORMAL,
- AUDIO_TIMESTRETCH_STRETCH_DEFAULT,
- AUDIO_TIMESTRETCH_FALLBACK_DEFAULT
-};
+static const AudioPlaybackRate AUDIO_PLAYBACK_RATE_DEFAULT = ::AUDIO_PLAYBACK_RATE_INITIALIZER;
static inline bool isAudioPlaybackRateEqual(const AudioPlaybackRate &pr1,
const AudioPlaybackRate &pr2) {
diff --git a/media/libmedia/include/media/BufferProviders.h b/media/libaudioprocessing/include/media/BufferProviders.h
similarity index 100%
rename from media/libmedia/include/media/BufferProviders.h
rename to media/libaudioprocessing/include/media/BufferProviders.h
diff --git a/media/libmedia/include/media/RecordBufferConverter.h b/media/libaudioprocessing/include/media/RecordBufferConverter.h
similarity index 100%
rename from media/libmedia/include/media/RecordBufferConverter.h
rename to media/libaudioprocessing/include/media/RecordBufferConverter.h
diff --git a/media/libaudioprocessing/tests/Android.bp b/media/libaudioprocessing/tests/Android.bp
index d990111..18acef7 100644
--- a/media/libaudioprocessing/tests/Android.bp
+++ b/media/libaudioprocessing/tests/Android.bp
@@ -3,8 +3,13 @@
cc_defaults {
name: "libaudioprocessing_test_defaults",
- header_libs: ["libbase_headers"],
+ header_libs: [
+ "libbase_headers",
+ "libmedia_headers",
+ ],
+
shared_libs: [
+ "libaudioclient",
"libaudioprocessing",
"libaudioutils",
"libcutils",
@@ -50,3 +55,26 @@
srcs: ["test-resampler.cpp"],
static_libs: ["libsndfile"],
}
+
+//
+// build mixerops objdump
+//
+// This is used to verify proper optimization of the code.
+//
+// For example, use:
+// ./prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin/aarch64-linux-android-objdump
+// -d --source ./out/target/product/crosshatch/symbols/system/bin/mixerops_objdump
+//
+cc_binary {
+ name: "mixerops_objdump",
+ srcs: ["mixerops_objdump.cpp"],
+}
+
+//
+// build mixerops benchmark
+//
+cc_benchmark {
+ name: "mixerops_benchmark",
+ srcs: ["mixerops_benchmark.cpp"],
+ static_libs: ["libgoogle-benchmark"],
+}
diff --git a/media/libaudioprocessing/tests/fuzzer/Android.bp b/media/libaudioprocessing/tests/fuzzer/Android.bp
new file mode 100644
index 0000000..1df47b7
--- /dev/null
+++ b/media/libaudioprocessing/tests/fuzzer/Android.bp
@@ -0,0 +1,10 @@
+cc_fuzz {
+ name: "libaudioprocessing_resampler_fuzzer",
+ srcs: [
+ "libaudioprocessing_resampler_fuzzer.cpp",
+ ],
+ defaults: ["libaudioprocessing_test_defaults"],
+ static_libs: [
+ "libsndfile",
+ ],
+}
diff --git a/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_resampler_fuzzer.cpp b/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_resampler_fuzzer.cpp
new file mode 100644
index 0000000..938c610
--- /dev/null
+++ b/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_resampler_fuzzer.cpp
@@ -0,0 +1,188 @@
+/*
+ * 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.
+ */
+
+#include <android-base/macros.h>
+#include <audio_utils/primitives.h>
+#include <audio_utils/sndfile.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <math.h>
+#include <media/AudioBufferProvider.h>
+#include <media/AudioResampler.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+#include <utils/Vector.h>
+
+#include <memory>
+
+using namespace android;
+
+const int MAX_FRAMES = 10;
+const int MIN_FREQ = 1e3;
+const int MAX_FREQ = 100e3;
+
+const AudioResampler::src_quality qualities[] = {
+ AudioResampler::DEFAULT_QUALITY,
+ AudioResampler::LOW_QUALITY,
+ AudioResampler::MED_QUALITY,
+ AudioResampler::HIGH_QUALITY,
+ AudioResampler::VERY_HIGH_QUALITY,
+ AudioResampler::DYN_LOW_QUALITY,
+ AudioResampler::DYN_MED_QUALITY,
+ AudioResampler::DYN_HIGH_QUALITY,
+};
+
+class Provider : public AudioBufferProvider {
+ const void* mAddr; // base address
+ const size_t mNumFrames; // total frames
+ const size_t mFrameSize; // size of each frame in bytes
+ size_t mNextFrame; // index of next frame to provide
+ size_t mUnrel; // number of frames not yet released
+ public:
+ Provider(const void* addr, size_t frames, size_t frameSize)
+ : mAddr(addr),
+ mNumFrames(frames),
+ mFrameSize(frameSize),
+ mNextFrame(0),
+ mUnrel(0) {}
+ status_t getNextBuffer(Buffer* buffer) override {
+ if (buffer->frameCount > mNumFrames - mNextFrame) {
+ buffer->frameCount = mNumFrames - mNextFrame;
+ }
+ mUnrel = buffer->frameCount;
+ if (buffer->frameCount > 0) {
+ buffer->raw = (char*)mAddr + mFrameSize * mNextFrame;
+ return NO_ERROR;
+ } else {
+ buffer->raw = nullptr;
+ return NOT_ENOUGH_DATA;
+ }
+ }
+ virtual void releaseBuffer(Buffer* buffer) {
+ if (buffer->frameCount > mUnrel) {
+ mNextFrame += mUnrel;
+ mUnrel = 0;
+ } else {
+ mNextFrame += buffer->frameCount;
+ mUnrel -= buffer->frameCount;
+ }
+ buffer->frameCount = 0;
+ buffer->raw = nullptr;
+ }
+ void reset() { mNextFrame = 0; }
+};
+
+audio_format_t chooseFormat(AudioResampler::src_quality quality,
+ uint8_t input_byte) {
+ switch (quality) {
+ case AudioResampler::DYN_LOW_QUALITY:
+ case AudioResampler::DYN_MED_QUALITY:
+ case AudioResampler::DYN_HIGH_QUALITY:
+ if (input_byte % 2) {
+ return AUDIO_FORMAT_PCM_FLOAT;
+ }
+ FALLTHROUGH_INTENDED;
+ default:
+ return AUDIO_FORMAT_PCM_16_BIT;
+ }
+}
+
+int parseValue(const uint8_t* src, int index, void* dst, size_t size) {
+ memcpy(dst, &src[index], size);
+ return size;
+}
+
+bool validFreq(int freq) { return freq > MIN_FREQ && freq < MAX_FREQ; }
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ int input_freq = 0;
+ int output_freq = 0;
+ int input_channels = 0;
+
+ float left_volume = 0;
+ float right_volume = 0;
+
+ size_t metadata_size = 2 + 3 * sizeof(int) + 2 * sizeof(float);
+ if (size < metadata_size) {
+ // not enough data to set options
+ return 0;
+ }
+
+ AudioResampler::src_quality quality = qualities[data[0] % 8];
+ audio_format_t format = chooseFormat(quality, data[1]);
+
+ int index = 2;
+
+ index += parseValue(data, index, &input_freq, sizeof(int));
+ index += parseValue(data, index, &output_freq, sizeof(int));
+ index += parseValue(data, index, &input_channels, sizeof(int));
+
+ index += parseValue(data, index, &left_volume, sizeof(float));
+ index += parseValue(data, index, &right_volume, sizeof(float));
+
+ if (!validFreq(input_freq) || !validFreq(output_freq)) {
+ // sampling frequencies must be reasonable
+ return 0;
+ }
+
+ if (input_channels < 1 ||
+ input_channels > (quality < AudioResampler::DYN_LOW_QUALITY ? 2 : 8)) {
+ // invalid number of input channels
+ return 0;
+ }
+
+ size_t single_channel_size =
+ format == AUDIO_FORMAT_PCM_FLOAT ? sizeof(float) : sizeof(int16_t);
+ size_t input_frame_size = single_channel_size * input_channels;
+ size_t input_size = size - metadata_size;
+ uint8_t input_data[input_size];
+ memcpy(input_data, &data[metadata_size], input_size);
+
+ size_t input_frames = input_size / input_frame_size;
+ if (input_frames > MAX_FRAMES) {
+ return 0;
+ }
+
+ Provider provider(input_data, input_frames, input_frame_size);
+
+ std::unique_ptr<AudioResampler> resampler(
+ AudioResampler::create(format, input_channels, output_freq, quality));
+
+ resampler->setSampleRate(input_freq);
+ resampler->setVolume(left_volume, right_volume);
+
+ // output is at least stereo samples
+ int output_channels = input_channels > 2 ? input_channels : 2;
+ size_t output_frame_size = output_channels * sizeof(int32_t);
+ size_t output_frames = (input_frames * output_freq) / input_freq;
+ size_t output_size = output_frames * output_frame_size;
+
+ uint8_t output_data[output_size];
+ for (size_t i = 0; i < output_frames; i++) {
+ memset(output_data, 0, output_size);
+ resampler->resample((int*)output_data, i, &provider);
+ }
+
+ return 0;
+}
diff --git a/media/libaudioprocessing/tests/mixerops_benchmark.cpp b/media/libaudioprocessing/tests/mixerops_benchmark.cpp
new file mode 100644
index 0000000..86f5429
--- /dev/null
+++ b/media/libaudioprocessing/tests/mixerops_benchmark.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <inttypes.h>
+#include <type_traits>
+#include "../../../../system/media/audio_utils/include/audio_utils/primitives.h"
+#define LOG_ALWAYS_FATAL(...)
+
+#include <../AudioMixerOps.h>
+
+#include <benchmark/benchmark.h>
+
+using namespace android;
+
+template <int MIXTYPE, int NCHAN>
+static void BM_VolumeRampMulti(benchmark::State& state) {
+ constexpr size_t FRAME_COUNT = 1000;
+ constexpr size_t SAMPLE_COUNT = FRAME_COUNT * NCHAN;
+
+ // data inialized to 0.
+ float out[SAMPLE_COUNT]{};
+ float in[SAMPLE_COUNT]{};
+ float aux[FRAME_COUNT]{};
+
+ // volume initialized to 0
+ float vola = 0.f;
+ float vol[2] = {0.f, 0.f};
+
+ // some volume increment
+ float volainc = 0.01f;
+ float volinc[2] = {0.01f, 0.01f};
+
+ while (state.KeepRunning()) {
+ benchmark::DoNotOptimize(out);
+ benchmark::DoNotOptimize(in);
+ volumeRampMulti<MIXTYPE, NCHAN>(out, FRAME_COUNT, in, aux, vol, volinc, &vola, volainc);
+ benchmark::ClobberMemory();
+ }
+}
+
+template <int MIXTYPE, int NCHAN>
+static void BM_VolumeMulti(benchmark::State& state) {
+ constexpr size_t FRAME_COUNT = 1000;
+ constexpr size_t SAMPLE_COUNT = FRAME_COUNT * NCHAN;
+
+ // data inialized to 0.
+ float out[SAMPLE_COUNT]{};
+ float in[SAMPLE_COUNT]{};
+ float aux[FRAME_COUNT]{};
+
+ // volume initialized to 0
+ float vola = 0.f;
+ float vol[2] = {0.f, 0.f};
+
+
+ while (state.KeepRunning()) {
+ benchmark::DoNotOptimize(out);
+ benchmark::DoNotOptimize(in);
+ volumeMulti<MIXTYPE, NCHAN>(out, FRAME_COUNT, in, aux, vol, vola);
+ benchmark::ClobberMemory();
+ }
+}
+
+BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI, 2);
+BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY, 2);
+BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_STEREOVOL, 2);
+BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY_STEREOVOL, 2);
+
+BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI, 4);
+BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY, 4);
+BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_STEREOVOL, 4);
+BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY_STEREOVOL, 4);
+
+BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI, 5);
+BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY, 5);
+BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_STEREOVOL, 5);
+BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY_STEREOVOL, 5);
+
+BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI, 8);
+BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY, 8);
+BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_STEREOVOL, 8);
+BENCHMARK_TEMPLATE(BM_VolumeRampMulti, MIXTYPE_MULTI_SAVEONLY_STEREOVOL, 8);
+
+BENCHMARK_TEMPLATE(BM_VolumeMulti, MIXTYPE_MULTI, 8);
+BENCHMARK_TEMPLATE(BM_VolumeMulti, MIXTYPE_MULTI_SAVEONLY, 8);
+BENCHMARK_TEMPLATE(BM_VolumeMulti, MIXTYPE_MULTI_STEREOVOL, 8);
+BENCHMARK_TEMPLATE(BM_VolumeMulti, MIXTYPE_MULTI_SAVEONLY_STEREOVOL, 8);
+
+BENCHMARK_MAIN();
diff --git a/media/libaudioprocessing/tests/mixerops_objdump.cpp b/media/libaudioprocessing/tests/mixerops_objdump.cpp
new file mode 100644
index 0000000..ee7e837
--- /dev/null
+++ b/media/libaudioprocessing/tests/mixerops_objdump.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <inttypes.h>
+#include <type_traits>
+#include "../../../../system/media/audio_utils/include/audio_utils/primitives.h"
+#define LOG_ALWAYS_FATAL(...)
+
+#include <../AudioMixerOps.h>
+
+using namespace android;
+
+template <int MIXTYPE, int NCHAN>
+static void checkVolumeRampMulti() {
+ constexpr size_t FRAME_COUNT = 1000;
+ constexpr size_t SAMPLE_COUNT = FRAME_COUNT * NCHAN;
+
+ // data inialized to 0.
+ float out[SAMPLE_COUNT]{};
+ float in[SAMPLE_COUNT]{};
+ float aux[FRAME_COUNT]{};
+
+ // volume initialized to 0
+ float vola = 0.f;
+ float vol[2] = {0.f, 0.f};
+
+ // some volume increment
+ float volainc = 0.01f;
+ float volinc[2] = {0.01f, 0.01f};
+
+ // try the multi ramp code.
+ volumeRampMulti<MIXTYPE, NCHAN>(out, FRAME_COUNT, in, aux, vol, volinc, &vola, volainc);
+}
+
+// Use this to check the objdump to ensure reasonable code.
+int main() {
+ checkVolumeRampMulti<MIXTYPE_MULTI_STEREOVOL, 5>();
+ return EXIT_SUCCESS;
+}
diff --git a/media/libcpustats/Android.bp b/media/libcpustats/Android.bp
index 8fcd8a4..6e8ca1d 100644
--- a/media/libcpustats/Android.bp
+++ b/media/libcpustats/Android.bp
@@ -6,6 +6,14 @@
"ThreadCpuUsage.cpp",
],
+ local_include_dirs: [
+ "include",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+
cflags: [
"-Werror",
"-Wall",
diff --git a/media/libdatasource/Android.bp b/media/libdatasource/Android.bp
new file mode 100644
index 0000000..f191c21
--- /dev/null
+++ b/media/libdatasource/Android.bp
@@ -0,0 +1,63 @@
+cc_library {
+ name: "libdatasource",
+
+ srcs: [
+ "DataSourceFactory.cpp",
+ "DataURISource.cpp",
+ "FileSource.cpp",
+ "HTTPBase.cpp",
+ "MediaHTTP.cpp",
+ "NuCachedSource2.cpp",
+ ],
+
+ aidl: {
+ local_include_dirs: ["aidl"],
+ export_aidl_headers: true,
+ },
+
+ header_libs: [
+ "libstagefright_headers",
+ "media_ndk_headers",
+ "libmedia_headers",
+ ],
+
+ export_header_lib_headers: [
+ "libstagefright_headers",
+ "media_ndk_headers",
+ ],
+
+ shared_libs: [
+ "liblog",
+ "libcutils",
+ "libutils",
+ "libstagefright_foundation",
+ "libdl",
+ ],
+
+ static_libs: [
+ "libc_malloc_debug_backtrace", // for memory heap analysis
+ "libmedia_midiiowrapper",
+ ],
+
+ local_include_dirs: [
+ "include",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wno-error=deprecated-declarations",
+ "-Wall",
+ ],
+
+ sanitize: {
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ cfi: true,
+ },
+}
diff --git a/media/libdatasource/DataSourceFactory.cpp b/media/libdatasource/DataSourceFactory.cpp
new file mode 100644
index 0000000..bb6a08c
--- /dev/null
+++ b/media/libdatasource/DataSourceFactory.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+//#define LOG_NDEBUG 0
+#define LOG_TAG "DataSource"
+
+
+#include <datasource/DataSourceFactory.h>
+#include <datasource/DataURISource.h>
+#include <datasource/HTTPBase.h>
+#include <datasource/FileSource.h>
+#include <datasource/MediaHTTP.h>
+#include <datasource/NuCachedSource2.h>
+#include <media/MediaHTTPConnection.h>
+#include <media/MediaHTTPService.h>
+#include <utils/String8.h>
+
+namespace android {
+
+// static
+sp<DataSourceFactory> DataSourceFactory::sInstance;
+// static
+Mutex DataSourceFactory::sInstanceLock;
+
+// static
+sp<DataSourceFactory> DataSourceFactory::getInstance() {
+ Mutex::Autolock l(sInstanceLock);
+ if (!sInstance) {
+ sInstance = new DataSourceFactory();
+ }
+ return sInstance;
+}
+
+sp<DataSource> DataSourceFactory::CreateFromURI(
+ const sp<MediaHTTPService> &httpService,
+ const char *uri,
+ const KeyedVector<String8, String8> *headers,
+ String8 *contentType,
+ HTTPBase *httpSource) {
+ if (contentType != NULL) {
+ *contentType = "";
+ }
+
+ sp<DataSource> source;
+ if (!strncasecmp("file://", uri, 7)) {
+ source = CreateFileSource(uri + 7);
+ } else if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
+ if (httpService == NULL) {
+ ALOGE("Invalid http service!");
+ return NULL;
+ }
+
+ sp<HTTPBase> mediaHTTP = httpSource;
+ if (mediaHTTP == NULL) {
+ mediaHTTP = static_cast<HTTPBase *>(CreateMediaHTTP(httpService).get());
+ }
+
+ String8 cacheConfig;
+ bool disconnectAtHighwatermark = false;
+ KeyedVector<String8, String8> nonCacheSpecificHeaders;
+ if (headers != NULL) {
+ nonCacheSpecificHeaders = *headers;
+ NuCachedSource2::RemoveCacheSpecificHeaders(
+ &nonCacheSpecificHeaders,
+ &cacheConfig,
+ &disconnectAtHighwatermark);
+ }
+
+ if (mediaHTTP->connect(uri, &nonCacheSpecificHeaders) != OK) {
+ ALOGE("Failed to connect http source!");
+ return NULL;
+ }
+
+ if (contentType != NULL) {
+ *contentType = mediaHTTP->getMIMEType();
+ }
+
+ source = NuCachedSource2::Create(
+ mediaHTTP,
+ cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
+ disconnectAtHighwatermark);
+ } else if (!strncasecmp("data:", uri, 5)) {
+ source = DataURISource::Create(uri);
+ } else {
+ // Assume it's a filename.
+ source = CreateFileSource(uri);
+ }
+
+ if (source == NULL || source->initCheck() != OK) {
+ return NULL;
+ }
+
+ return source;
+}
+
+sp<DataSource> DataSourceFactory::CreateFromFd(int fd, int64_t offset, int64_t length) {
+ sp<FileSource> source = new FileSource(fd, offset, length);
+ return source->initCheck() != OK ? nullptr : source;
+}
+
+sp<DataSource> DataSourceFactory::CreateMediaHTTP(const sp<MediaHTTPService> &httpService) {
+ if (httpService == NULL) {
+ return NULL;
+ }
+
+ sp<MediaHTTPConnection> conn = httpService->makeHTTPConnection();
+ if (conn == NULL) {
+ ALOGE("Failed to make http connection from http service!");
+ return NULL;
+ } else {
+ return new MediaHTTP(conn);
+ }
+}
+
+sp<DataSource> DataSourceFactory::CreateFileSource(const char *uri) {
+ return new FileSource(uri);
+}
+
+} // namespace android
diff --git a/media/libdatasource/DataURISource.cpp b/media/libdatasource/DataURISource.cpp
new file mode 100644
index 0000000..216f3d0
--- /dev/null
+++ b/media/libdatasource/DataURISource.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <datasource/DataURISource.h>
+
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/base64.h>
+
+namespace android {
+
+// static
+sp<DataURISource> DataURISource::Create(const char *uri) {
+ if (strncasecmp("data:", uri, 5)) {
+ return NULL;
+ }
+
+ const char *commaPos = strrchr(uri, ',');
+
+ if (commaPos == NULL) {
+ return NULL;
+ }
+
+ sp<ABuffer> buffer;
+
+ AString tmp(&uri[5], commaPos - &uri[5]);
+
+ if (tmp.endsWith(";base64")) {
+
+ // strip all CR and LF characters.
+ const char *src = commaPos+1;
+ int len = strlen(src) + 1;
+ char *cleansed = (char *) malloc(len);
+ if (cleansed == NULL) return NULL;
+ char *keeping = cleansed;
+ int left = len;
+ for (int i = 0; i < len ; i++)
+ {
+ const char c = *src++;
+ if (c == '\r' || c == '\n') {
+ continue;
+ }
+ *keeping++ = c;
+ left--;
+ }
+ memset(keeping, 0, left);
+
+ AString encoded(cleansed);
+ free(cleansed);
+
+ buffer = decodeBase64(encoded);
+
+ if (buffer == NULL) {
+ ALOGE("Malformed base64 encoded content found.");
+ return NULL;
+ }
+ } else {
+#if 0
+ size_t dataLen = strlen(uri) - tmp.size() - 6;
+ buffer = new ABuffer(dataLen);
+ memcpy(buffer->data(), commaPos + 1, dataLen);
+
+ // unescape
+#else
+ // MediaPlayer doesn't care for this right now as we don't
+ // play any text-based media.
+ return NULL;
+#endif
+ }
+
+ // We don't really care about charset or mime type.
+
+ return new DataURISource(buffer);
+}
+
+DataURISource::DataURISource(const sp<ABuffer> &buffer)
+ : mBuffer(buffer) {
+}
+
+DataURISource::~DataURISource() {
+}
+
+status_t DataURISource::initCheck() const {
+ return OK;
+}
+
+ssize_t DataURISource::readAt(off64_t offset, void *data, size_t size) {
+ if ((offset < 0) || (offset >= (off64_t)mBuffer->size())) {
+ return 0;
+ }
+
+ size_t copy = mBuffer->size() - offset;
+ if (copy > size) {
+ copy = size;
+ }
+
+ memcpy(data, mBuffer->data() + offset, copy);
+
+ return copy;
+}
+
+status_t DataURISource::getSize(off64_t *size) {
+ *size = mBuffer->size();
+
+ return OK;
+}
+
+} // namespace android
+
diff --git a/media/libdatasource/FileSource.cpp b/media/libdatasource/FileSource.cpp
new file mode 100644
index 0000000..3d34d0c
--- /dev/null
+++ b/media/libdatasource/FileSource.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "FileSource"
+#include <utils/Log.h>
+
+#include <datasource/FileSource.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/FoundationUtils.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+namespace android {
+
+FileSource::FileSource(const char *filename)
+ : mFd(-1),
+ mOffset(0),
+ mLength(-1),
+ mName("<null>") {
+
+ if (filename) {
+ mName = String8::format("FileSource(%s)", filename);
+ }
+ ALOGV("%s", filename);
+ mFd = open(filename, O_LARGEFILE | O_RDONLY);
+
+ if (mFd >= 0) {
+ mLength = lseek64(mFd, 0, SEEK_END);
+ } else {
+ ALOGE("Failed to open file '%s'. (%s)", filename, strerror(errno));
+ }
+}
+
+FileSource::FileSource(int fd, int64_t offset, int64_t length)
+ : mFd(fd),
+ mOffset(offset),
+ mLength(length),
+ mName("<null>") {
+ ALOGV("fd=%d (%s), offset=%lld, length=%lld",
+ fd, nameForFd(fd).c_str(), (long long) offset, (long long) length);
+
+ if (mOffset < 0) {
+ mOffset = 0;
+ }
+ if (mLength < 0) {
+ mLength = 0;
+ }
+ if (mLength > INT64_MAX - mOffset) {
+ mLength = INT64_MAX - mOffset;
+ }
+ struct stat s;
+ if (fstat(fd, &s) == 0) {
+ if (mOffset > s.st_size) {
+ mOffset = s.st_size;
+ mLength = 0;
+ }
+ if (mOffset + mLength > s.st_size) {
+ mLength = s.st_size - mOffset;
+ }
+ }
+ if (mOffset != offset || mLength != length) {
+ ALOGW("offset/length adjusted from %lld/%lld to %lld/%lld",
+ (long long) offset, (long long) length,
+ (long long) mOffset, (long long) mLength);
+ }
+
+ mName = String8::format(
+ "FileSource(fd(%s), %lld, %lld)",
+ nameForFd(fd).c_str(),
+ (long long) mOffset,
+ (long long) mLength);
+
+}
+
+FileSource::~FileSource() {
+ if (mFd >= 0) {
+ ::close(mFd);
+ mFd = -1;
+ }
+}
+
+status_t FileSource::initCheck() const {
+ return mFd >= 0 ? OK : NO_INIT;
+}
+
+ssize_t FileSource::readAt(off64_t offset, void *data, size_t size) {
+ if (mFd < 0) {
+ return NO_INIT;
+ }
+
+ Mutex::Autolock autoLock(mLock);
+ if (mLength >= 0) {
+ if (offset < 0) {
+ return UNKNOWN_ERROR;
+ }
+ if (offset >= mLength) {
+ return 0; // read beyond EOF.
+ }
+ uint64_t numAvailable = mLength - offset;
+ if ((uint64_t)size > numAvailable) {
+ size = numAvailable;
+ }
+ }
+ return readAt_l(offset, data, size);
+}
+
+ssize_t FileSource::readAt_l(off64_t offset, void *data, size_t size) {
+ off64_t result = lseek64(mFd, offset + mOffset, SEEK_SET);
+ if (result == -1) {
+ ALOGE("seek to %lld failed", (long long)(offset + mOffset));
+ return UNKNOWN_ERROR;
+ }
+
+ return ::read(mFd, data, size);
+}
+
+status_t FileSource::getSize(off64_t *size) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mFd < 0) {
+ return NO_INIT;
+ }
+
+ *size = mLength;
+
+ return OK;
+}
+
+} // namespace android
diff --git a/media/libdatasource/HTTPBase.cpp b/media/libdatasource/HTTPBase.cpp
new file mode 100644
index 0000000..ef29c48
--- /dev/null
+++ b/media/libdatasource/HTTPBase.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "HTTPBase"
+#include <utils/Log.h>
+
+#include <datasource/HTTPBase.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
+
+#include <cutils/properties.h>
+#include <cutils/qtaguid.h>
+
+namespace android {
+
+HTTPBase::HTTPBase()
+ : mNumBandwidthHistoryItems(0),
+ mTotalTransferTimeUs(0),
+ mTotalTransferBytes(0),
+ mMaxBandwidthHistoryItems(100),
+ mPrevBandwidthMeasureTimeUs(0),
+ mPrevEstimatedBandWidthKbps(0),
+ mBandWidthCollectFreqMs(5000) {
+ mName = String8("HTTPBase(<disconnected>)");
+}
+
+void HTTPBase::addBandwidthMeasurement(
+ size_t numBytes, int64_t delayUs) {
+ Mutex::Autolock autoLock(mLock);
+
+ BandwidthEntry entry;
+ entry.mDelayUs = delayUs;
+ entry.mNumBytes = numBytes;
+ mTotalTransferTimeUs += delayUs;
+ mTotalTransferBytes += numBytes;
+
+ mBandwidthHistory.push_back(entry);
+ if (++mNumBandwidthHistoryItems > mMaxBandwidthHistoryItems) {
+ BandwidthEntry *entry = &*mBandwidthHistory.begin();
+ mTotalTransferTimeUs -= entry->mDelayUs;
+ mTotalTransferBytes -= entry->mNumBytes;
+ mBandwidthHistory.erase(mBandwidthHistory.begin());
+ --mNumBandwidthHistoryItems;
+
+ int64_t timeNowUs = ALooper::GetNowUs();
+ if (timeNowUs - mPrevBandwidthMeasureTimeUs >=
+ mBandWidthCollectFreqMs * 1000LL) {
+
+ if (mPrevBandwidthMeasureTimeUs != 0) {
+ mPrevEstimatedBandWidthKbps =
+ (mTotalTransferBytes * 8E3 / mTotalTransferTimeUs);
+ }
+ mPrevBandwidthMeasureTimeUs = timeNowUs;
+ }
+ }
+
+}
+
+bool HTTPBase::estimateBandwidth(int32_t *bandwidth_bps) {
+ Mutex::Autolock autoLock(mLock);
+
+ // Do not do bandwidth estimation if we don't have enough samples, or
+ // total bytes download are too small (<64K).
+ // Bandwidth estimation from these samples can often shoot up and cause
+ // unwanted bw adaption behaviors.
+ if (mNumBandwidthHistoryItems < 2 || mTotalTransferBytes < 65536) {
+ return false;
+ }
+
+ *bandwidth_bps = ((double)mTotalTransferBytes * 8E6 / mTotalTransferTimeUs);
+
+ return true;
+}
+
+status_t HTTPBase::getEstimatedBandwidthKbps(int32_t *kbps) {
+ Mutex::Autolock autoLock(mLock);
+ *kbps = mPrevEstimatedBandWidthKbps;
+ return OK;
+}
+
+status_t HTTPBase::setBandwidthStatCollectFreq(int32_t freqMs) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (freqMs < kMinBandwidthCollectFreqMs
+ || freqMs > kMaxBandwidthCollectFreqMs) {
+
+ ALOGE("frequency (%d ms) is out of range [1000, 60000]", freqMs);
+ return BAD_VALUE;
+ }
+
+ ALOGI("frequency set to %d ms", freqMs);
+ mBandWidthCollectFreqMs = freqMs;
+ return OK;
+}
+
+void HTTPBase::setBandwidthHistorySize(size_t numHistoryItems) {
+ mMaxBandwidthHistoryItems = numHistoryItems;
+}
+
+} // namespace android
diff --git a/media/libdatasource/MediaHTTP.cpp b/media/libdatasource/MediaHTTP.cpp
new file mode 100644
index 0000000..58c1ce8
--- /dev/null
+++ b/media/libdatasource/MediaHTTP.cpp
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaHTTP"
+#include <utils/Log.h>
+
+#include <datasource/MediaHTTP.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/FoundationUtils.h>
+
+#include <media/MediaHTTPConnection.h>
+
+namespace android {
+
+MediaHTTP::MediaHTTP(const sp<MediaHTTPConnection> &conn)
+ : mInitCheck((conn != NULL) ? OK : NO_INIT),
+ mHTTPConnection(conn),
+ mCachedSizeValid(false),
+ mCachedSize(0ll) {
+}
+
+MediaHTTP::~MediaHTTP() {
+}
+
+status_t MediaHTTP::connect(
+ const char *uri,
+ const KeyedVector<String8, String8> *headers,
+ off64_t /* offset */) {
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ KeyedVector<String8, String8> extHeaders;
+ if (headers != NULL) {
+ extHeaders = *headers;
+ }
+
+ if (extHeaders.indexOfKey(String8("User-Agent")) < 0) {
+ extHeaders.add(String8("User-Agent"), String8(MakeUserAgent().c_str()));
+ }
+
+ mLastURI = uri;
+ // reconnect() calls with uri == old mLastURI.c_str(), which gets zapped
+ // as part of the above assignment. Ensure no accidental later use.
+ uri = NULL;
+
+ bool success = mHTTPConnection->connect(mLastURI.c_str(), &extHeaders);
+
+ mLastHeaders = extHeaders;
+
+ mCachedSizeValid = false;
+
+ if (success) {
+ AString sanitized = uriDebugString(mLastURI);
+ mName = String8::format("MediaHTTP(%s)", sanitized.c_str());
+ }
+
+ return success ? OK : UNKNOWN_ERROR;
+}
+
+void MediaHTTP::close() {
+ disconnect();
+}
+
+void MediaHTTP::disconnect() {
+ mName = String8("MediaHTTP(<disconnected>)");
+ if (mInitCheck != OK) {
+ return;
+ }
+
+ mHTTPConnection->disconnect();
+}
+
+status_t MediaHTTP::initCheck() const {
+ return mInitCheck;
+}
+
+ssize_t MediaHTTP::readAt(off64_t offset, void *data, size_t size) {
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ int64_t startTimeUs = ALooper::GetNowUs();
+
+ size_t numBytesRead = 0;
+ while (numBytesRead < size) {
+ size_t copy = size - numBytesRead;
+
+ if (copy > 64 * 1024) {
+ // limit the buffer sizes transferred across binder boundaries
+ // to avoid spurious transaction failures.
+ copy = 64 * 1024;
+ }
+
+ ssize_t n = mHTTPConnection->readAt(
+ offset + numBytesRead, (uint8_t *)data + numBytesRead, copy);
+
+ if (n < 0) {
+ return n;
+ } else if (n == 0) {
+ break;
+ }
+
+ numBytesRead += n;
+ }
+
+ int64_t delayUs = ALooper::GetNowUs() - startTimeUs;
+
+ addBandwidthMeasurement(numBytesRead, delayUs);
+
+ return numBytesRead;
+}
+
+status_t MediaHTTP::getSize(off64_t *size) {
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ // Caching the returned size so that it stays valid even after a
+ // disconnect. NuCachedSource2 relies on this.
+
+ if (!mCachedSizeValid) {
+ mCachedSize = mHTTPConnection->getSize();
+ mCachedSizeValid = true;
+ }
+
+ *size = mCachedSize;
+
+ return *size < 0 ? *size : static_cast<status_t>(OK);
+}
+
+uint32_t MediaHTTP::flags() {
+ return kWantsPrefetching | kIsHTTPBasedSource;
+}
+
+status_t MediaHTTP::reconnectAtOffset(off64_t offset) {
+ return connect(mLastURI.c_str(), &mLastHeaders, offset);
+}
+
+
+String8 MediaHTTP::getUri() {
+ if (mInitCheck != OK) {
+ return String8::empty();
+ }
+
+ String8 uri;
+ if (OK == mHTTPConnection->getUri(&uri)) {
+ return uri;
+ }
+ return String8(mLastURI.c_str());
+}
+
+String8 MediaHTTP::getMIMEType() const {
+ if (mInitCheck != OK) {
+ return String8("application/octet-stream");
+ }
+
+ String8 mimeType;
+ status_t err = mHTTPConnection->getMIMEType(&mimeType);
+
+ if (err != OK) {
+ return String8("application/octet-stream");
+ }
+
+ return mimeType;
+}
+
+} // namespace android
diff --git a/media/libdatasource/NuCachedSource2.cpp b/media/libdatasource/NuCachedSource2.cpp
new file mode 100644
index 0000000..6d63ffb
--- /dev/null
+++ b/media/libdatasource/NuCachedSource2.cpp
@@ -0,0 +1,780 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <inttypes.h>
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "NuCachedSource2"
+#include <utils/Log.h>
+
+#include <datasource/NuCachedSource2.h>
+#include <datasource/HTTPBase.h>
+
+#include <cutils/properties.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaErrors.h>
+
+namespace android {
+
+struct PageCache {
+ explicit PageCache(size_t pageSize);
+ ~PageCache();
+
+ struct Page {
+ void *mData;
+ size_t mSize;
+ };
+
+ Page *acquirePage();
+ void releasePage(Page *page);
+
+ void appendPage(Page *page);
+ size_t releaseFromStart(size_t maxBytes);
+
+ size_t totalSize() const {
+ return mTotalSize;
+ }
+
+ void copy(size_t from, void *data, size_t size);
+
+private:
+ size_t mPageSize;
+ size_t mTotalSize;
+
+ List<Page *> mActivePages;
+ List<Page *> mFreePages;
+
+ void freePages(List<Page *> *list);
+
+ DISALLOW_EVIL_CONSTRUCTORS(PageCache);
+};
+
+PageCache::PageCache(size_t pageSize)
+ : mPageSize(pageSize),
+ mTotalSize(0) {
+}
+
+PageCache::~PageCache() {
+ freePages(&mActivePages);
+ freePages(&mFreePages);
+}
+
+void PageCache::freePages(List<Page *> *list) {
+ List<Page *>::iterator it = list->begin();
+ while (it != list->end()) {
+ Page *page = *it;
+
+ free(page->mData);
+ delete page;
+ page = NULL;
+
+ ++it;
+ }
+}
+
+PageCache::Page *PageCache::acquirePage() {
+ if (!mFreePages.empty()) {
+ List<Page *>::iterator it = mFreePages.begin();
+ Page *page = *it;
+ mFreePages.erase(it);
+
+ return page;
+ }
+
+ Page *page = new Page;
+ page->mData = malloc(mPageSize);
+ page->mSize = 0;
+
+ return page;
+}
+
+void PageCache::releasePage(Page *page) {
+ page->mSize = 0;
+ mFreePages.push_back(page);
+}
+
+void PageCache::appendPage(Page *page) {
+ mTotalSize += page->mSize;
+ mActivePages.push_back(page);
+}
+
+size_t PageCache::releaseFromStart(size_t maxBytes) {
+ size_t bytesReleased = 0;
+
+ while (maxBytes > 0 && !mActivePages.empty()) {
+ List<Page *>::iterator it = mActivePages.begin();
+
+ Page *page = *it;
+
+ if (maxBytes < page->mSize) {
+ break;
+ }
+
+ mActivePages.erase(it);
+
+ maxBytes -= page->mSize;
+ bytesReleased += page->mSize;
+
+ releasePage(page);
+ }
+
+ mTotalSize -= bytesReleased;
+ return bytesReleased;
+}
+
+void PageCache::copy(size_t from, void *data, size_t size) {
+ ALOGV("copy from %zu size %zu", from, size);
+
+ if (size == 0) {
+ return;
+ }
+
+ CHECK_LE(from + size, mTotalSize);
+
+ size_t offset = 0;
+ List<Page *>::iterator it = mActivePages.begin();
+ while (from >= offset + (*it)->mSize) {
+ offset += (*it)->mSize;
+ ++it;
+ }
+
+ size_t delta = from - offset;
+ size_t avail = (*it)->mSize - delta;
+
+ if (avail >= size) {
+ memcpy(data, (const uint8_t *)(*it)->mData + delta, size);
+ return;
+ }
+
+ memcpy(data, (const uint8_t *)(*it)->mData + delta, avail);
+ ++it;
+ data = (uint8_t *)data + avail;
+ size -= avail;
+
+ while (size > 0) {
+ size_t copy = (*it)->mSize;
+ if (copy > size) {
+ copy = size;
+ }
+ memcpy(data, (*it)->mData, copy);
+ data = (uint8_t *)data + copy;
+ size -= copy;
+ ++it;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+NuCachedSource2::NuCachedSource2(
+ const sp<DataSource> &source,
+ const char *cacheConfig,
+ bool disconnectAtHighwatermark)
+ : mSource(source),
+ mReflector(new AHandlerReflector<NuCachedSource2>(this)),
+ mLooper(new ALooper),
+ mCache(new PageCache(kPageSize)),
+ mCacheOffset(0),
+ mFinalStatus(OK),
+ mLastAccessPos(0),
+ mFetching(true),
+ mDisconnecting(false),
+ mLastFetchTimeUs(-1),
+ mNumRetriesLeft(kMaxNumRetries),
+ mHighwaterThresholdBytes(kDefaultHighWaterThreshold),
+ mLowwaterThresholdBytes(kDefaultLowWaterThreshold),
+ mKeepAliveIntervalUs(kDefaultKeepAliveIntervalUs),
+ mDisconnectAtHighwatermark(disconnectAtHighwatermark) {
+ // We are NOT going to support disconnect-at-highwatermark indefinitely
+ // and we are not guaranteeing support for client-specified cache
+ // parameters. Both of these are temporary measures to solve a specific
+ // problem that will be solved in a better way going forward.
+
+ updateCacheParamsFromSystemProperty();
+
+ if (cacheConfig != NULL) {
+ updateCacheParamsFromString(cacheConfig);
+ }
+
+ if (mDisconnectAtHighwatermark) {
+ // Makes no sense to disconnect and do keep-alives...
+ mKeepAliveIntervalUs = 0;
+ }
+
+ mLooper->setName("NuCachedSource2");
+ mLooper->registerHandler(mReflector);
+
+ // Since it may not be obvious why our looper thread needs to be
+ // able to call into java since it doesn't appear to do so at all...
+ // IMediaHTTPConnection may be (and most likely is) implemented in JAVA
+ // and a local JAVA IBinder will call directly into JNI methods.
+ // So whenever we call DataSource::readAt it may end up in a call to
+ // IMediaHTTPConnection::readAt and therefore call back into JAVA.
+ mLooper->start(false /* runOnCallingThread */, true /* canCallJava */);
+
+ mName = String8::format("NuCachedSource2(%s)", mSource->toString().string());
+}
+
+NuCachedSource2::~NuCachedSource2() {
+ mLooper->stop();
+ mLooper->unregisterHandler(mReflector->id());
+
+ delete mCache;
+ mCache = NULL;
+}
+
+// static
+sp<NuCachedSource2> NuCachedSource2::Create(
+ const sp<DataSource> &source,
+ const char *cacheConfig,
+ bool disconnectAtHighwatermark) {
+ sp<NuCachedSource2> instance = new NuCachedSource2(
+ source, cacheConfig, disconnectAtHighwatermark);
+ Mutex::Autolock autoLock(instance->mLock);
+ (new AMessage(kWhatFetchMore, instance->mReflector))->post();
+ return instance;
+}
+
+status_t NuCachedSource2::getEstimatedBandwidthKbps(int32_t *kbps) {
+ if (mSource->flags() & kIsHTTPBasedSource) {
+ HTTPBase* source = static_cast<HTTPBase *>(mSource.get());
+ return source->getEstimatedBandwidthKbps(kbps);
+ }
+ return ERROR_UNSUPPORTED;
+}
+
+void NuCachedSource2::close() {
+ disconnect();
+}
+
+void NuCachedSource2::disconnect() {
+ if (mSource->flags() & kIsHTTPBasedSource) {
+ ALOGV("disconnecting HTTPBasedSource");
+
+ {
+ Mutex::Autolock autoLock(mLock);
+ // set mDisconnecting to true, if a fetch returns after
+ // this, the source will be marked as EOS.
+ mDisconnecting = true;
+
+ // explicitly signal mCondition so that the pending readAt()
+ // will immediately return
+ mCondition.signal();
+ }
+
+ // explicitly disconnect from the source, to allow any
+ // pending reads to return more promptly
+ static_cast<HTTPBase *>(mSource.get())->disconnect();
+ }
+}
+
+status_t NuCachedSource2::setCacheStatCollectFreq(int32_t freqMs) {
+ if (mSource->flags() & kIsHTTPBasedSource) {
+ HTTPBase *source = static_cast<HTTPBase *>(mSource.get());
+ return source->setBandwidthStatCollectFreq(freqMs);
+ }
+ return ERROR_UNSUPPORTED;
+}
+
+status_t NuCachedSource2::initCheck() const {
+ return mSource->initCheck();
+}
+
+status_t NuCachedSource2::getSize(off64_t *size) {
+ return mSource->getSize(size);
+}
+
+uint32_t NuCachedSource2::flags() {
+ // Remove HTTP related flags since NuCachedSource2 is not HTTP-based.
+ uint32_t flags = mSource->flags() & ~(kWantsPrefetching | kIsHTTPBasedSource);
+ return (flags | kIsCachingDataSource);
+}
+
+void NuCachedSource2::onMessageReceived(const sp<AMessage> &msg) {
+ switch (msg->what()) {
+ case kWhatFetchMore:
+ {
+ onFetch();
+ break;
+ }
+
+ case kWhatRead:
+ {
+ onRead(msg);
+ break;
+ }
+
+ default:
+ TRESPASS();
+ }
+}
+
+void NuCachedSource2::fetchInternal() {
+ ALOGV("fetchInternal");
+
+ bool reconnect = false;
+
+ {
+ Mutex::Autolock autoLock(mLock);
+ CHECK(mFinalStatus == OK || mNumRetriesLeft > 0);
+
+ if (mFinalStatus != OK) {
+ --mNumRetriesLeft;
+
+ reconnect = true;
+ }
+ }
+
+ if (reconnect) {
+ status_t err =
+ mSource->reconnectAtOffset(mCacheOffset + mCache->totalSize());
+
+ Mutex::Autolock autoLock(mLock);
+
+ if (mDisconnecting) {
+ mNumRetriesLeft = 0;
+ mFinalStatus = ERROR_END_OF_STREAM;
+ return;
+ } else if (err == ERROR_UNSUPPORTED || err == -EPIPE) {
+ // These are errors that are not likely to go away even if we
+ // retry, i.e. the server doesn't support range requests or similar.
+ mNumRetriesLeft = 0;
+ return;
+ } else if (err != OK) {
+ ALOGI("The attempt to reconnect failed, %d retries remaining",
+ mNumRetriesLeft);
+
+ return;
+ }
+ }
+
+ PageCache::Page *page = mCache->acquirePage();
+
+ ssize_t n = mSource->readAt(
+ mCacheOffset + mCache->totalSize(), page->mData, kPageSize);
+
+ Mutex::Autolock autoLock(mLock);
+
+ if (n == 0 || mDisconnecting) {
+ ALOGI("caching reached eos.");
+
+ mNumRetriesLeft = 0;
+ mFinalStatus = ERROR_END_OF_STREAM;
+
+ mCache->releasePage(page);
+ } else if (n < 0) {
+ mFinalStatus = n;
+ if (n == ERROR_UNSUPPORTED || n == -EPIPE) {
+ // These are errors that are not likely to go away even if we
+ // retry, i.e. the server doesn't support range requests or similar.
+ mNumRetriesLeft = 0;
+ }
+
+ ALOGE("source returned error %zd, %d retries left", n, mNumRetriesLeft);
+ mCache->releasePage(page);
+ } else {
+ if (mFinalStatus != OK) {
+ ALOGI("retrying a previously failed read succeeded.");
+ }
+ mNumRetriesLeft = kMaxNumRetries;
+ mFinalStatus = OK;
+
+ page->mSize = n;
+ mCache->appendPage(page);
+ }
+}
+
+void NuCachedSource2::onFetch() {
+ ALOGV("onFetch");
+
+ if (mFinalStatus != OK && mNumRetriesLeft == 0) {
+ ALOGV("EOS reached, done prefetching for now");
+ mFetching = false;
+ }
+
+ bool keepAlive =
+ !mFetching
+ && mFinalStatus == OK
+ && mKeepAliveIntervalUs > 0
+ && ALooper::GetNowUs() >= mLastFetchTimeUs + mKeepAliveIntervalUs;
+
+ if (mFetching || keepAlive) {
+ if (keepAlive) {
+ ALOGI("Keep alive");
+ }
+
+ fetchInternal();
+
+ mLastFetchTimeUs = ALooper::GetNowUs();
+
+ if (mFetching && mCache->totalSize() >= mHighwaterThresholdBytes) {
+ ALOGI("Cache full, done prefetching for now");
+ mFetching = false;
+
+ if (mDisconnectAtHighwatermark
+ && (mSource->flags() & DataSource::kIsHTTPBasedSource)) {
+ ALOGV("Disconnecting at high watermark");
+ static_cast<HTTPBase *>(mSource.get())->disconnect();
+ mFinalStatus = -EAGAIN;
+ }
+ }
+ } else {
+ Mutex::Autolock autoLock(mLock);
+ restartPrefetcherIfNecessary_l();
+ }
+
+ int64_t delayUs;
+ if (mFetching) {
+ if (mFinalStatus != OK && mNumRetriesLeft > 0) {
+ // We failed this time and will try again in 3 seconds.
+ delayUs = 3000000LL;
+ } else {
+ delayUs = 0;
+ }
+ } else {
+ delayUs = 100000LL;
+ }
+
+ (new AMessage(kWhatFetchMore, mReflector))->post(delayUs);
+}
+
+void NuCachedSource2::onRead(const sp<AMessage> &msg) {
+ ALOGV("onRead");
+
+ int64_t offset;
+ CHECK(msg->findInt64("offset", &offset));
+
+ void *data;
+ CHECK(msg->findPointer("data", &data));
+
+ size_t size;
+ CHECK(msg->findSize("size", &size));
+
+ ssize_t result = readInternal(offset, data, size);
+
+ if (result == -EAGAIN) {
+ msg->post(50000);
+ return;
+ }
+
+ Mutex::Autolock autoLock(mLock);
+ if (mDisconnecting) {
+ mCondition.signal();
+ return;
+ }
+
+ CHECK(mAsyncResult == NULL);
+
+ mAsyncResult = new AMessage;
+ mAsyncResult->setInt32("result", result);
+
+ mCondition.signal();
+}
+
+void NuCachedSource2::restartPrefetcherIfNecessary_l(
+ bool ignoreLowWaterThreshold, bool force) {
+ static const size_t kGrayArea = 1024 * 1024;
+
+ if (mFetching || (mFinalStatus != OK && mNumRetriesLeft == 0)) {
+ return;
+ }
+
+ if (!ignoreLowWaterThreshold && !force
+ && mCacheOffset + mCache->totalSize() - mLastAccessPos
+ >= mLowwaterThresholdBytes) {
+ return;
+ }
+
+ size_t maxBytes = mLastAccessPos - mCacheOffset;
+
+ if (!force) {
+ if (maxBytes < kGrayArea) {
+ return;
+ }
+
+ maxBytes -= kGrayArea;
+ }
+
+ size_t actualBytes = mCache->releaseFromStart(maxBytes);
+ mCacheOffset += actualBytes;
+
+ ALOGI("restarting prefetcher, totalSize = %zu", mCache->totalSize());
+ mFetching = true;
+}
+
+ssize_t NuCachedSource2::readAt(off64_t offset, void *data, size_t size) {
+ Mutex::Autolock autoSerializer(mSerializer);
+
+ ALOGV("readAt offset %lld, size %zu", (long long)offset, size);
+
+ Mutex::Autolock autoLock(mLock);
+ if (mDisconnecting) {
+ return ERROR_END_OF_STREAM;
+ }
+
+ // If the request can be completely satisfied from the cache, do so.
+
+ if (offset >= mCacheOffset
+ && offset + size <= mCacheOffset + mCache->totalSize()) {
+ size_t delta = offset - mCacheOffset;
+ mCache->copy(delta, data, size);
+
+ mLastAccessPos = offset + size;
+
+ return size;
+ }
+
+ sp<AMessage> msg = new AMessage(kWhatRead, mReflector);
+ msg->setInt64("offset", offset);
+ msg->setPointer("data", data);
+ msg->setSize("size", size);
+
+ CHECK(mAsyncResult == NULL);
+ msg->post();
+
+ while (mAsyncResult == NULL && !mDisconnecting) {
+ mCondition.wait(mLock);
+ }
+
+ if (mDisconnecting) {
+ mAsyncResult.clear();
+ return ERROR_END_OF_STREAM;
+ }
+
+ int32_t result;
+ CHECK(mAsyncResult->findInt32("result", &result));
+
+ mAsyncResult.clear();
+
+ if (result > 0) {
+ mLastAccessPos = offset + result;
+ }
+
+ return (ssize_t)result;
+}
+
+size_t NuCachedSource2::cachedSize() {
+ Mutex::Autolock autoLock(mLock);
+ return mCacheOffset + mCache->totalSize();
+}
+
+status_t NuCachedSource2::getAvailableSize(off64_t offset, off64_t *size) {
+ Mutex::Autolock autoLock(mLock);
+ status_t finalStatus = UNKNOWN_ERROR;
+ *size = approxDataRemaining_l(offset, &finalStatus);
+ return finalStatus;
+}
+
+size_t NuCachedSource2::approxDataRemaining(status_t *finalStatus) const {
+ Mutex::Autolock autoLock(mLock);
+ return approxDataRemaining_l(mLastAccessPos, finalStatus);
+}
+
+size_t NuCachedSource2::approxDataRemaining_l(off64_t offset, status_t *finalStatus) const {
+ *finalStatus = mFinalStatus;
+
+ if (mFinalStatus != OK && mNumRetriesLeft > 0) {
+ // Pretend that everything is fine until we're out of retries.
+ *finalStatus = OK;
+ }
+
+ offset = offset >= 0 ? offset : mLastAccessPos;
+ off64_t lastBytePosCached = mCacheOffset + mCache->totalSize();
+ if (offset < lastBytePosCached) {
+ return lastBytePosCached - offset;
+ }
+ return 0;
+}
+
+ssize_t NuCachedSource2::readInternal(off64_t offset, void *data, size_t size) {
+ CHECK_LE(size, (size_t)mHighwaterThresholdBytes);
+
+ ALOGV("readInternal offset %lld size %zu", (long long)offset, size);
+
+ Mutex::Autolock autoLock(mLock);
+
+ // If we're disconnecting, return EOS and don't access *data pointer.
+ // data could be on the stack of the caller to NuCachedSource2::readAt(),
+ // which may have exited already.
+ if (mDisconnecting) {
+ return ERROR_END_OF_STREAM;
+ }
+
+ if (!mFetching) {
+ mLastAccessPos = offset;
+ restartPrefetcherIfNecessary_l(
+ false, // ignoreLowWaterThreshold
+ true); // force
+ }
+
+ if (offset < mCacheOffset
+ || offset >= (off64_t)(mCacheOffset + mCache->totalSize())) {
+ static const off64_t kPadding = 256 * 1024;
+
+ // In the presence of multiple decoded streams, once of them will
+ // trigger this seek request, the other one will request data "nearby"
+ // soon, adjust the seek position so that that subsequent request
+ // does not trigger another seek.
+ off64_t seekOffset = (offset > kPadding) ? offset - kPadding : 0;
+
+ seekInternal_l(seekOffset);
+ }
+
+ size_t delta = offset - mCacheOffset;
+
+ if (mFinalStatus != OK && mNumRetriesLeft == 0) {
+ if (delta >= mCache->totalSize()) {
+ return mFinalStatus;
+ }
+
+ size_t avail = mCache->totalSize() - delta;
+
+ if (avail > size) {
+ avail = size;
+ }
+
+ mCache->copy(delta, data, avail);
+
+ return avail;
+ }
+
+ if (offset + size <= mCacheOffset + mCache->totalSize()) {
+ mCache->copy(delta, data, size);
+
+ return size;
+ }
+
+ ALOGV("deferring read");
+
+ return -EAGAIN;
+}
+
+status_t NuCachedSource2::seekInternal_l(off64_t offset) {
+ mLastAccessPos = offset;
+
+ if (offset >= mCacheOffset
+ && offset <= (off64_t)(mCacheOffset + mCache->totalSize())) {
+ return OK;
+ }
+
+ ALOGI("new range: offset= %lld", (long long)offset);
+
+ mCacheOffset = offset;
+
+ size_t totalSize = mCache->totalSize();
+ CHECK_EQ(mCache->releaseFromStart(totalSize), totalSize);
+
+ mNumRetriesLeft = kMaxNumRetries;
+ mFetching = true;
+
+ return OK;
+}
+
+void NuCachedSource2::resumeFetchingIfNecessary() {
+ Mutex::Autolock autoLock(mLock);
+
+ restartPrefetcherIfNecessary_l(true /* ignore low water threshold */);
+}
+
+String8 NuCachedSource2::getUri() {
+ return mSource->getUri();
+}
+
+String8 NuCachedSource2::getMIMEType() const {
+ return mSource->getMIMEType();
+}
+
+void NuCachedSource2::updateCacheParamsFromSystemProperty() {
+ char value[PROPERTY_VALUE_MAX];
+ if (!property_get("media.stagefright.cache-params", value, NULL)) {
+ return;
+ }
+
+ updateCacheParamsFromString(value);
+}
+
+void NuCachedSource2::updateCacheParamsFromString(const char *s) {
+ ssize_t lowwaterMarkKb, highwaterMarkKb;
+ int keepAliveSecs;
+
+ if (sscanf(s, "%zd/%zd/%d",
+ &lowwaterMarkKb, &highwaterMarkKb, &keepAliveSecs) != 3) {
+ ALOGE("Failed to parse cache parameters from '%s'.", s);
+ return;
+ }
+
+ if (lowwaterMarkKb >= 0) {
+ mLowwaterThresholdBytes = lowwaterMarkKb * 1024;
+ } else {
+ mLowwaterThresholdBytes = kDefaultLowWaterThreshold;
+ }
+
+ if (highwaterMarkKb >= 0) {
+ mHighwaterThresholdBytes = highwaterMarkKb * 1024;
+ } else {
+ mHighwaterThresholdBytes = kDefaultHighWaterThreshold;
+ }
+
+ if (mLowwaterThresholdBytes >= mHighwaterThresholdBytes) {
+ ALOGE("Illegal low/highwater marks specified, reverting to defaults.");
+
+ mLowwaterThresholdBytes = kDefaultLowWaterThreshold;
+ mHighwaterThresholdBytes = kDefaultHighWaterThreshold;
+ }
+
+ if (keepAliveSecs >= 0) {
+ mKeepAliveIntervalUs = keepAliveSecs * 1000000LL;
+ } else {
+ mKeepAliveIntervalUs = kDefaultKeepAliveIntervalUs;
+ }
+
+ ALOGV("lowwater = %zu bytes, highwater = %zu bytes, keepalive = %lld us",
+ mLowwaterThresholdBytes,
+ mHighwaterThresholdBytes,
+ (long long)mKeepAliveIntervalUs);
+}
+
+// static
+void NuCachedSource2::RemoveCacheSpecificHeaders(
+ KeyedVector<String8, String8> *headers,
+ String8 *cacheConfig,
+ bool *disconnectAtHighwatermark) {
+ *cacheConfig = String8();
+ *disconnectAtHighwatermark = false;
+
+ if (headers == NULL) {
+ return;
+ }
+
+ ssize_t index;
+ if ((index = headers->indexOfKey(String8("x-cache-config"))) >= 0) {
+ *cacheConfig = headers->valueAt(index);
+
+ headers->removeItemsAt(index);
+
+ ALOGV("Using special cache config '%s'", cacheConfig->string());
+ }
+
+ if ((index = headers->indexOfKey(
+ String8("x-disconnect-at-highwatermark"))) >= 0) {
+ *disconnectAtHighwatermark = true;
+ headers->removeItemsAt(index);
+
+ ALOGV("Client requested disconnection at highwater mark");
+ }
+}
+
+} // namespace android
diff --git a/media/libdatasource/include/datasource/DataSourceFactory.h b/media/libdatasource/include/datasource/DataSourceFactory.h
new file mode 100644
index 0000000..194abe2
--- /dev/null
+++ b/media/libdatasource/include/datasource/DataSourceFactory.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DATA_SOURCE_FACTORY_H_
+
+#define DATA_SOURCE_FACTORY_H_
+
+#include <media/DataSource.h>
+#include <sys/types.h>
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+struct MediaHTTPService;
+class String8;
+struct HTTPBase;
+
+class DataSourceFactory : public RefBase {
+public:
+ static sp<DataSourceFactory> getInstance();
+ sp<DataSource> CreateFromURI(
+ const sp<MediaHTTPService> &httpService,
+ const char *uri,
+ const KeyedVector<String8, String8> *headers = NULL,
+ String8 *contentType = NULL,
+ HTTPBase *httpSource = NULL);
+
+ virtual sp<DataSource> CreateMediaHTTP(const sp<MediaHTTPService> &httpService);
+ sp<DataSource> CreateFromFd(int fd, int64_t offset, int64_t length);
+
+protected:
+ virtual sp<DataSource> CreateFileSource(const char *uri);
+ DataSourceFactory() {};
+ virtual ~DataSourceFactory() {};
+
+private:
+ static sp<DataSourceFactory> sInstance;
+ static Mutex sInstanceLock;
+};
+
+} // namespace android
+
+#endif // DATA_SOURCE_FACTORY_H_
diff --git a/media/libstagefright/include/media/stagefright/DataURISource.h b/media/libdatasource/include/datasource/DataURISource.h
similarity index 100%
rename from media/libstagefright/include/media/stagefright/DataURISource.h
rename to media/libdatasource/include/datasource/DataURISource.h
diff --git a/media/libdatasource/include/datasource/FileSource.h b/media/libdatasource/include/datasource/FileSource.h
new file mode 100644
index 0000000..dee0c33
--- /dev/null
+++ b/media/libdatasource/include/datasource/FileSource.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FILE_SOURCE_H_
+
+#define FILE_SOURCE_H_
+
+#include <stdio.h>
+
+#include <media/DataSource.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class FileSource : public DataSource {
+public:
+ FileSource(const char *filename);
+ // FileSource takes ownership and will close the fd
+ FileSource(int fd, int64_t offset, int64_t length);
+
+ virtual status_t initCheck() const;
+
+ virtual ssize_t readAt(off64_t offset, void *data, size_t size);
+
+ virtual status_t getSize(off64_t *size);
+
+ virtual uint32_t flags() {
+ return kIsLocalFileSource;
+ }
+
+ virtual String8 toString() {
+ return mName;
+ }
+
+protected:
+ virtual ~FileSource();
+ virtual ssize_t readAt_l(off64_t offset, void *data, size_t size);
+
+ int mFd;
+ int64_t mOffset;
+ int64_t mLength;
+ Mutex mLock;
+
+private:
+ String8 mName;
+
+ FileSource(const FileSource &);
+ FileSource &operator=(const FileSource &);
+};
+
+} // namespace android
+
+#endif // FILE_SOURCE_H_
+
diff --git a/media/libdatasource/include/datasource/HTTPBase.h b/media/libdatasource/include/datasource/HTTPBase.h
new file mode 100644
index 0000000..656e85e
--- /dev/null
+++ b/media/libdatasource/include/datasource/HTTPBase.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HTTP_BASE_H_
+
+#define HTTP_BASE_H_
+
+#include <media/DataSource.h>
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/KeyedVector.h>
+#include <utils/List.h>
+#include <utils/threads.h>
+
+namespace android {
+
+struct HTTPBase : public DataSource {
+ enum Flags {
+ // Don't log any URLs.
+ kFlagIncognito = 1
+ };
+
+ HTTPBase();
+
+ virtual status_t connect(
+ const char *uri,
+ const KeyedVector<String8, String8> *headers = NULL,
+ off64_t offset = 0) = 0;
+
+ virtual void disconnect() = 0;
+
+ // Returns true if bandwidth could successfully be estimated,
+ // false otherwise.
+ virtual bool estimateBandwidth(int32_t *bandwidth_bps);
+
+ virtual status_t getEstimatedBandwidthKbps(int32_t *kbps);
+
+ virtual status_t setBandwidthStatCollectFreq(int32_t freqMs);
+
+ virtual void setBandwidthHistorySize(size_t numHistoryItems);
+
+ virtual String8 toString() {
+ return mName;
+ }
+
+protected:
+ virtual void addBandwidthMeasurement(size_t numBytes, int64_t delayUs);
+ String8 mName;
+
+private:
+ struct BandwidthEntry {
+ int64_t mDelayUs;
+ size_t mNumBytes;
+ };
+
+ Mutex mLock;
+
+ List<BandwidthEntry> mBandwidthHistory;
+ size_t mNumBandwidthHistoryItems;
+ int64_t mTotalTransferTimeUs;
+ size_t mTotalTransferBytes;
+ size_t mMaxBandwidthHistoryItems;
+
+ enum {
+ kMinBandwidthCollectFreqMs = 1000, // 1 second
+ kMaxBandwidthCollectFreqMs = 60000, // one minute
+ };
+
+ int64_t mPrevBandwidthMeasureTimeUs;
+ int32_t mPrevEstimatedBandWidthKbps;
+ int32_t mBandWidthCollectFreqMs;
+
+ DISALLOW_EVIL_CONSTRUCTORS(HTTPBase);
+};
+
+} // namespace android
+
+#endif // HTTP_BASE_H_
diff --git a/media/libdatasource/include/datasource/MediaHTTP.h b/media/libdatasource/include/datasource/MediaHTTP.h
new file mode 100644
index 0000000..a8d203b
--- /dev/null
+++ b/media/libdatasource/include/datasource/MediaHTTP.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MEDIA_HTTP_H_
+
+#define MEDIA_HTTP_H_
+
+#include <media/stagefright/foundation/AString.h>
+
+#include "HTTPBase.h"
+
+namespace android {
+
+struct MediaHTTPConnection;
+
+struct MediaHTTP : public HTTPBase {
+ MediaHTTP(const sp<MediaHTTPConnection> &conn);
+
+ virtual status_t connect(
+ const char *uri,
+ const KeyedVector<String8, String8> *headers,
+ off64_t offset);
+
+ virtual void close();
+
+ virtual void disconnect();
+
+ virtual status_t initCheck() const;
+
+ virtual ssize_t readAt(off64_t offset, void *data, size_t size);
+
+ virtual status_t getSize(off64_t *size);
+
+ virtual uint32_t flags();
+
+ virtual status_t reconnectAtOffset(off64_t offset);
+
+protected:
+ virtual ~MediaHTTP();
+
+ virtual String8 getUri();
+ virtual String8 getMIMEType() const;
+
+ AString mLastURI;
+
+private:
+ status_t mInitCheck;
+ sp<MediaHTTPConnection> mHTTPConnection;
+
+ KeyedVector<String8, String8> mLastHeaders;
+
+ bool mCachedSizeValid;
+ off64_t mCachedSize;
+
+ DISALLOW_EVIL_CONSTRUCTORS(MediaHTTP);
+};
+
+} // namespace android
+
+#endif // MEDIA_HTTP_H_
diff --git a/media/libdatasource/include/datasource/NuCachedSource2.h b/media/libdatasource/include/datasource/NuCachedSource2.h
new file mode 100644
index 0000000..4c253ad
--- /dev/null
+++ b/media/libdatasource/include/datasource/NuCachedSource2.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef NU_CACHED_SOURCE_2_H_
+
+#define NU_CACHED_SOURCE_2_H_
+
+#include <media/DataSource.h>
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/AHandlerReflector.h>
+
+namespace android {
+
+struct ALooper;
+struct PageCache;
+
+struct NuCachedSource2 : public DataSource {
+ static sp<NuCachedSource2> Create(
+ const sp<DataSource> &source,
+ const char *cacheConfig = NULL,
+ bool disconnectAtHighwatermark = false);
+
+ virtual status_t initCheck() const;
+
+ virtual ssize_t readAt(off64_t offset, void *data, size_t size);
+
+ virtual void close();
+
+ virtual void disconnect();
+
+ virtual status_t getSize(off64_t *size);
+ virtual uint32_t flags();
+
+ virtual String8 getUri();
+
+ virtual String8 getMIMEType() const;
+
+ virtual String8 toString() {
+ return mName;
+ }
+
+ status_t getAvailableSize(off64_t offset, off64_t *size);
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ size_t cachedSize();
+ size_t approxDataRemaining(status_t *finalStatus) const;
+
+ void resumeFetchingIfNecessary();
+
+ // The following methods are supported only if the
+ // data source is HTTP-based; otherwise, ERROR_UNSUPPORTED
+ // is returned.
+ status_t getEstimatedBandwidthKbps(int32_t *kbps);
+ status_t setCacheStatCollectFreq(int32_t freqMs);
+
+ static void RemoveCacheSpecificHeaders(
+ KeyedVector<String8, String8> *headers,
+ String8 *cacheConfig,
+ bool *disconnectAtHighwatermark);
+
+protected:
+ virtual ~NuCachedSource2();
+
+private:
+ friend struct AHandlerReflector<NuCachedSource2>;
+
+ NuCachedSource2(
+ const sp<DataSource> &source,
+ const char *cacheConfig,
+ bool disconnectAtHighwatermark);
+
+ enum {
+ kPageSize = 65536,
+ kDefaultHighWaterThreshold = 20 * 1024 * 1024,
+ kDefaultLowWaterThreshold = 4 * 1024 * 1024,
+
+ // Read data after a 15 sec timeout whether we're actively
+ // fetching or not.
+ kDefaultKeepAliveIntervalUs = 15000000,
+ };
+
+ enum {
+ kWhatFetchMore = 'fetc',
+ kWhatRead = 'read',
+ };
+
+ enum {
+ kMaxNumRetries = 10,
+ };
+
+ sp<DataSource> mSource;
+ sp<AHandlerReflector<NuCachedSource2> > mReflector;
+ sp<ALooper> mLooper;
+ String8 mName;
+
+ Mutex mSerializer;
+ mutable Mutex mLock;
+ Condition mCondition;
+
+ PageCache *mCache;
+ off64_t mCacheOffset;
+ status_t mFinalStatus;
+ off64_t mLastAccessPos;
+ sp<AMessage> mAsyncResult;
+ bool mFetching;
+ bool mDisconnecting;
+ int64_t mLastFetchTimeUs;
+
+ int32_t mNumRetriesLeft;
+
+ size_t mHighwaterThresholdBytes;
+ size_t mLowwaterThresholdBytes;
+
+ // If the keep-alive interval is 0, keep-alives are disabled.
+ int64_t mKeepAliveIntervalUs;
+
+ bool mDisconnectAtHighwatermark;
+
+ void onMessageReceived(const sp<AMessage> &msg);
+ void onFetch();
+ void onRead(const sp<AMessage> &msg);
+
+ void fetchInternal();
+ ssize_t readInternal(off64_t offset, void *data, size_t size);
+ status_t seekInternal_l(off64_t offset);
+
+ size_t approxDataRemaining_l(off64_t offset, status_t *finalStatus) const;
+
+ void restartPrefetcherIfNecessary_l(
+ bool ignoreLowWaterThreshold = false, bool force = false);
+
+ void updateCacheParamsFromSystemProperty();
+ void updateCacheParamsFromString(const char *s);
+
+ DISALLOW_EVIL_CONSTRUCTORS(NuCachedSource2);
+};
+
+} // namespace android
+
+#endif // NU_CACHED_SOURCE_2_H_
diff --git a/media/libeffects/config/Android.bp b/media/libeffects/config/Android.bp
index 5fa9da9..8476f82 100644
--- a/media/libeffects/config/Android.bp
+++ b/media/libeffects/config/Android.bp
@@ -13,6 +13,8 @@
shared_libs: [
"liblog",
"libtinyxml2",
+ "libutils",
+ "libmedia_helper",
],
header_libs: ["libaudio_system_headers"],
diff --git a/media/libeffects/config/include/media/EffectsConfig.h b/media/libeffects/config/include/media/EffectsConfig.h
index fa0415b..ef10e0d 100644
--- a/media/libeffects/config/include/media/EffectsConfig.h
+++ b/media/libeffects/config/include/media/EffectsConfig.h
@@ -76,6 +76,10 @@
using OutputStream = Stream<audio_stream_type_t>;
using InputStream = Stream<audio_source_t>;
+struct DeviceEffects : Stream<audio_devices_t> {
+ std::string address;
+};
+
/** Parsed configuration.
* Intended to be a transient structure only used for deserialization.
* Note: Everything is copied in the configuration from the xml dom.
@@ -89,6 +93,7 @@
Effects effects;
std::vector<OutputStream> postprocess;
std::vector<InputStream> preprocess;
+ std::vector<DeviceEffects> deviceprocess;
};
/** Result of `parse(const char*)` */
diff --git a/media/libeffects/config/src/EffectsConfig.cpp b/media/libeffects/config/src/EffectsConfig.cpp
index f39eb0c..85fbf11 100644
--- a/media/libeffects/config/src/EffectsConfig.cpp
+++ b/media/libeffects/config/src/EffectsConfig.cpp
@@ -26,6 +26,7 @@
#include <log/log.h>
#include <media/EffectsConfig.h>
+#include <media/TypeConverter.h>
using namespace tinyxml2;
@@ -100,6 +101,7 @@
{AUDIO_STREAM_ENFORCED_AUDIBLE, "enforced_audible"},
{AUDIO_STREAM_DTMF, "dtmf"},
{AUDIO_STREAM_TTS, "tts"},
+ {AUDIO_STREAM_ASSISTANT, "assistant"},
};
/** All input stream types which support effects.
@@ -116,6 +118,8 @@
{AUDIO_SOURCE_VOICE_COMMUNICATION, "voice_communication"},
{AUDIO_SOURCE_UNPROCESSED, "unprocessed"},
{AUDIO_SOURCE_VOICE_PERFORMANCE, "voice_performance"},
+ {AUDIO_SOURCE_ECHO_REFERENCE, "echo_reference"},
+ {AUDIO_SOURCE_FM_TUNER, "fm_tuner"},
};
/** Find the stream type enum corresponding to the stream type name or return false */
@@ -131,6 +135,11 @@
return false;
}
+template <>
+bool stringToStreamType(const char *streamName, audio_devices_t* type) {
+ return deviceFromString(streamName, *type);
+}
+
/** Parse a library xml note and push the result in libraries or return false on failure. */
bool parseLibrary(const XMLElement& xmlLibrary, Libraries* libraries) {
const char* name = xmlLibrary.Attribute("name");
@@ -218,7 +227,7 @@
return true;
}
-/** Parse an stream from an xml element describing it.
+/** Parse an <Output|Input>stream or a device from an xml element describing it.
* @return true and pushes the stream in streams on success,
* false on failure. */
template <class Stream>
@@ -230,14 +239,14 @@
}
Stream stream;
if (!stringToStreamType(streamType, &stream.type)) {
- ALOGE("Invalid stream type %s: %s", streamType, dump(xmlStream));
+ ALOGE("Invalid <stream|device> type %s: %s", streamType, dump(xmlStream));
return false;
}
for (auto& xmlApply : getChildren(xmlStream, "apply")) {
const char* effectName = xmlApply.get().Attribute("effect");
if (effectName == nullptr) {
- ALOGE("stream/apply must have reference an effect: %s", dump(xmlApply));
+ ALOGE("<stream|device>/apply must have reference an effect: %s", dump(xmlApply));
return false;
}
auto* effect = findByName(effectName, effects);
@@ -251,6 +260,21 @@
return true;
}
+bool parseDeviceEffects(
+ const XMLElement& xmlDevice, Effects& effects, std::vector<DeviceEffects>* deviceEffects) {
+
+ const char* address = xmlDevice.Attribute("address");
+ if (address == nullptr) {
+ ALOGE("device must have an address: %s", dump(xmlDevice));
+ return false;
+ }
+ if (!parseStream(xmlDevice, effects, deviceEffects)) {
+ return false;
+ }
+ deviceEffects->back().address = address;
+ return true;
+}
+
/** Internal version of the public parse(const char* path) where path always exist. */
ParsingResult parseWithPath(std::string&& path) {
XMLDocument doc;
@@ -295,6 +319,14 @@
registerFailure(parseStream(xmlStream, config->effects, &config->postprocess));
}
}
+
+ // Parse device effect chains
+ for (auto& xmlDeviceEffects : getChildren(xmlConfig, "deviceEffects")) {
+ for (auto& xmlDevice : getChildren(xmlDeviceEffects, "devicePort")) {
+ registerFailure(
+ parseDeviceEffects(xmlDevice, config->effects, &config->deviceprocess));
+ }
+ }
}
return {std::move(config), nbSkippedElements, std::move(path)};
}
diff --git a/media/libeffects/data/audio_effects.xml b/media/libeffects/data/audio_effects.xml
index 3f85052..2e5f529 100644
--- a/media/libeffects/data/audio_effects.xml
+++ b/media/libeffects/data/audio_effects.xml
@@ -99,4 +99,31 @@
</postprocess>
-->
+ <!-- Device pre/post processor configurations.
+ The device pre/post processor configuration is described in a deviceEffects element and
+ consists in a list of elements each describing pre/post proecessor settings for a given
+ device or "devicePort".
+ Each devicePort element has a "type" attribute corresponding to the device type (e.g.
+ speaker, bus), an "address" attribute corresponding to the device address and contains a
+ list of "apply" elements indicating one effect to apply.
+ If the device is a source, only pre processing effects are expected, if the
+ device is a sink, only post processing effects are expected.
+ The effect to apply is designated by its name in the "effects" elements.
+ The effect will be enabled by default and the audio framework will automatically add
+ and activate the effect if the given port is involved in an audio patch.
+ If the patch is "HW", the effect must be HW accelerated.
+
+ <deviceEffects>
+ <devicePort type="AUDIO_DEVICE_OUT_BUS" address="BUS00_USAGE_MAIN">
+ <apply effect="equalizer"/>
+ </devicePort>
+ <devicePort type="AUDIO_DEVICE_OUT_BUS" address="BUS04_USAGE_VOICE">
+ <apply effect="volume"/>
+ </devicePort>
+ <devicePort type="AUDIO_DEVICE_IN_BUILTIN_MIC" address="bottom">
+ <apply effect="agc"/>
+ </devicePort>
+ </deviceEffects>
+ -->
+
</audio_effects_conf>
diff --git a/media/libeffects/downmix/Android.bp b/media/libeffects/downmix/Android.bp
index 9c82b1d..2a2f36e 100644
--- a/media/libeffects/downmix/Android.bp
+++ b/media/libeffects/downmix/Android.bp
@@ -6,6 +6,7 @@
srcs: ["EffectDownmix.c"],
shared_libs: [
+ "libaudioutils",
"libcutils",
"liblog",
],
@@ -23,5 +24,4 @@
"libaudioeffects",
"libhardware_headers",
],
- static_libs: ["libaudioutils" ],
}
diff --git a/media/libeffects/factory/EffectsFactory.c b/media/libeffects/factory/EffectsFactory.c
index c1ce513..dcdf634 100644
--- a/media/libeffects/factory/EffectsFactory.c
+++ b/media/libeffects/factory/EffectsFactory.c
@@ -254,7 +254,8 @@
return ret;
}
-int EffectCreate(const effect_uuid_t *uuid, int32_t sessionId, int32_t ioId, effect_handle_t *pHandle)
+int doEffectCreate(const effect_uuid_t *uuid, int32_t sessionId, int32_t ioId, int32_t deviceId,
+ effect_handle_t *pHandle)
{
list_elem_t *e = gLibraryList;
lib_entry_t *l = NULL;
@@ -268,9 +269,9 @@
}
ALOGV("EffectCreate() UUID: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X\n",
- uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion,
- uuid->clockSeq, uuid->node[0], uuid->node[1],uuid->node[2],
- uuid->node[3],uuid->node[4],uuid->node[5]);
+ uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion,
+ uuid->clockSeq, uuid->node[0], uuid->node[1], uuid->node[2],
+ uuid->node[3], uuid->node[4], uuid->node[5]);
ret = init();
@@ -282,17 +283,29 @@
pthread_mutex_lock(&gLibLock);
ret = findEffect(NULL, uuid, &l, &d);
- if (ret < 0){
+ if (ret < 0) {
// Sub effects are not associated with the library->effects,
// so, findEffect will fail. Search for the effect in gSubEffectList.
ret = findSubEffect(uuid, &l, &d);
- if (ret < 0 ) {
+ if (ret < 0) {
goto exit;
}
}
// create effect in library
- ret = l->desc->create_effect(uuid, sessionId, ioId, &itfe);
+ if (sessionId == AUDIO_SESSION_DEVICE) {
+ if (l->desc->version >= EFFECT_LIBRARY_API_VERSION_3_1) {
+ ALOGI("EffectCreate() create_effect_3_1");
+ ret = l->desc->create_effect_3_1(uuid, sessionId, ioId, deviceId, &itfe);
+ } else {
+ ALOGE("EffectCreate() cannot create device effect on library with API version < 3.1");
+ ret = -ENOSYS;
+ }
+ } else {
+ ALOGI("EffectCreate() create_effect");
+ ret = l->desc->create_effect(uuid, sessionId, ioId, &itfe);
+ }
+
if (ret != 0) {
ALOGW("EffectCreate() library %s: could not create fx %s, error %d", l->name, d->name, ret);
goto exit;
@@ -324,6 +337,16 @@
return ret;
}
+int EffectCreate(const effect_uuid_t *uuid, int32_t sessionId, int32_t ioId,
+ effect_handle_t *pHandle) {
+ return doEffectCreate(uuid, sessionId, ioId, AUDIO_PORT_HANDLE_NONE, pHandle);
+}
+
+int EffectCreateOnDevice(const effect_uuid_t *uuid, int32_t deviceId, int32_t ioId,
+ effect_handle_t *pHandle) {
+ return doEffectCreate(uuid, AUDIO_SESSION_DEVICE, ioId, deviceId, pHandle);
+}
+
int EffectRelease(effect_handle_t handle)
{
effect_entry_t *fx;
diff --git a/media/libeffects/factory/EffectsFactory.h b/media/libeffects/factory/EffectsFactory.h
index 29dbc9c..1936343 100644
--- a/media/libeffects/factory/EffectsFactory.h
+++ b/media/libeffects/factory/EffectsFactory.h
@@ -27,6 +27,8 @@
extern "C" {
#endif
+#define EFFECT_LIBRARY_API_VERSION_CURRENT EFFECT_LIBRARY_API_VERSION_3_1
+
#define PROPERTY_IGNORE_EFFECTS "ro.audio.ignore_effects"
typedef struct list_elem_s {
diff --git a/media/libeffects/factory/EffectsXmlConfigLoader.cpp b/media/libeffects/factory/EffectsXmlConfigLoader.cpp
index 052a88b..505be7c 100644
--- a/media/libeffects/factory/EffectsXmlConfigLoader.cpp
+++ b/media/libeffects/factory/EffectsXmlConfigLoader.cpp
@@ -94,7 +94,7 @@
}
uint32_t majorVersion = EFFECT_API_VERSION_MAJOR(description->version);
- uint32_t expectedMajorVersion = EFFECT_API_VERSION_MAJOR(EFFECT_LIBRARY_API_VERSION);
+ uint32_t expectedMajorVersion = EFFECT_API_VERSION_MAJOR(EFFECT_LIBRARY_API_VERSION_CURRENT);
if (majorVersion != expectedMajorVersion) {
ALOGE("Unsupported major version %#08x, expected %#08x for library %s",
majorVersion, expectedMajorVersion, path);
diff --git a/media/libeffects/factory/include/media/EffectsFactoryApi.h b/media/libeffects/factory/include/media/EffectsFactoryApi.h
index a5a12eb..8f7239e 100644
--- a/media/libeffects/factory/include/media/EffectsFactoryApi.h
+++ b/media/libeffects/factory/include/media/EffectsFactoryApi.h
@@ -119,6 +119,36 @@
////////////////////////////////////////////////////////////////////////////////
//
+// Function: EffectCreateOnDevice
+//
+// Description: Same as EffectCreate but uesed when creating an effect attached to a
+// particular audio device instance
+//
+// Input:
+// pEffectUuid: pointer to the effect uuid.
+// deviceId: identifies the sink or source device this effect is directed to in
+// audio HAL. Must be specified if sessionId is AUDIO_SESSION_DEVICE.
+// deviceId is the audio_port_handle_t used for the device when the audio
+// patch is created at the audio HAL.//
+// ioId: identifies the output or input stream this effect is directed to at audio HAL.
+// For future use especially with tunneled HW accelerated effects
+// Input/Output:
+// pHandle: address where to return the effect handle.
+//
+// Output:
+// returned value: 0 successful operation.
+// -ENODEV factory failed to initialize
+// -EINVAL invalid pEffectUuid or pHandle
+// -ENOENT no effect with this uuid found
+// *pHandle: updated with the effect handle.
+//
+////////////////////////////////////////////////////////////////////////////////
+ANDROID_API
+int EffectCreateOnDevice(const effect_uuid_t *pEffectUuid, int32_t deviceId, int32_t ioId,
+ effect_handle_t *pHandle);
+
+////////////////////////////////////////////////////////////////////////////////
+//
// Function: EffectRelease
//
// Description: Releases the effect engine whose handle is given as argument.
diff --git a/media/libeffects/lvm/lib/Android.bp b/media/libeffects/lvm/lib/Android.bp
index d150f18..1f2a5e1 100644
--- a/media/libeffects/lvm/lib/Android.bp
+++ b/media/libeffects/lvm/lib/Android.bp
@@ -10,107 +10,107 @@
vendor: true,
srcs: [
- "StereoWidening/src/LVCS_BypassMix.c",
- "StereoWidening/src/LVCS_Control.c",
- "StereoWidening/src/LVCS_Equaliser.c",
- "StereoWidening/src/LVCS_Init.c",
- "StereoWidening/src/LVCS_Process.c",
- "StereoWidening/src/LVCS_ReverbGenerator.c",
- "StereoWidening/src/LVCS_StereoEnhancer.c",
- "StereoWidening/src/LVCS_Tables.c",
- "Bass/src/LVDBE_Control.c",
- "Bass/src/LVDBE_Init.c",
- "Bass/src/LVDBE_Process.c",
- "Bass/src/LVDBE_Tables.c",
- "Bundle/src/LVM_API_Specials.c",
- "Bundle/src/LVM_Buffers.c",
- "Bundle/src/LVM_Init.c",
- "Bundle/src/LVM_Process.c",
- "Bundle/src/LVM_Tables.c",
- "Bundle/src/LVM_Control.c",
- "SpectrumAnalyzer/src/LVPSA_Control.c",
- "SpectrumAnalyzer/src/LVPSA_Init.c",
- "SpectrumAnalyzer/src/LVPSA_Memory.c",
- "SpectrumAnalyzer/src/LVPSA_Process.c",
- "SpectrumAnalyzer/src/LVPSA_QPD_Init.c",
- "SpectrumAnalyzer/src/LVPSA_QPD_Process.c",
- "SpectrumAnalyzer/src/LVPSA_Tables.c",
- "Eq/src/LVEQNB_CalcCoef.c",
- "Eq/src/LVEQNB_Control.c",
- "Eq/src/LVEQNB_Init.c",
- "Eq/src/LVEQNB_Process.c",
- "Eq/src/LVEQNB_Tables.c",
- "Common/src/InstAlloc.c",
- "Common/src/DC_2I_D16_TRC_WRA_01.c",
- "Common/src/DC_2I_D16_TRC_WRA_01_Init.c",
- "Common/src/FO_2I_D16F32C15_LShx_TRC_WRA_01.c",
- "Common/src/FO_2I_D16F32Css_LShx_TRC_WRA_01_Init.c",
- "Common/src/FO_1I_D16F16C15_TRC_WRA_01.c",
- "Common/src/FO_1I_D16F16Css_TRC_WRA_01_Init.c",
- "Common/src/BP_1I_D16F32C30_TRC_WRA_01.c",
- "Common/src/BP_1I_D16F16C14_TRC_WRA_01.c",
- "Common/src/BP_1I_D32F32C30_TRC_WRA_02.c",
- "Common/src/BP_1I_D16F16Css_TRC_WRA_01_Init.c",
- "Common/src/BP_1I_D16F32Cll_TRC_WRA_01_Init.c",
- "Common/src/BP_1I_D32F32Cll_TRC_WRA_02_Init.c",
- "Common/src/BQ_2I_D32F32Cll_TRC_WRA_01_Init.c",
- "Common/src/BQ_2I_D32F32C30_TRC_WRA_01.c",
- "Common/src/BQ_2I_D16F32C15_TRC_WRA_01.c",
- "Common/src/BQ_2I_D16F32C14_TRC_WRA_01.c",
- "Common/src/BQ_2I_D16F32C13_TRC_WRA_01.c",
- "Common/src/BQ_2I_D16F32Css_TRC_WRA_01_init.c",
- "Common/src/BQ_2I_D16F16C15_TRC_WRA_01.c",
- "Common/src/BQ_2I_D16F16C14_TRC_WRA_01.c",
- "Common/src/BQ_2I_D16F16Css_TRC_WRA_01_Init.c",
- "Common/src/BQ_1I_D16F16C15_TRC_WRA_01.c",
- "Common/src/BQ_1I_D16F16Css_TRC_WRA_01_Init.c",
- "Common/src/BQ_1I_D16F32C14_TRC_WRA_01.c",
- "Common/src/BQ_1I_D16F32Css_TRC_WRA_01_init.c",
- "Common/src/PK_2I_D32F32C30G11_TRC_WRA_01.c",
- "Common/src/PK_2I_D32F32C14G11_TRC_WRA_01.c",
- "Common/src/PK_2I_D32F32CssGss_TRC_WRA_01_Init.c",
- "Common/src/PK_2I_D32F32CllGss_TRC_WRA_01_Init.c",
- "Common/src/Int16LShiftToInt32_16x32.c",
- "Common/src/From2iToMono_16.c",
- "Common/src/Copy_16.c",
- "Common/src/MonoTo2I_16.c",
- "Common/src/MonoTo2I_32.c",
- "Common/src/LoadConst_16.c",
- "Common/src/LoadConst_32.c",
- "Common/src/dB_to_Lin32.c",
- "Common/src/Shift_Sat_v16xv16.c",
- "Common/src/Shift_Sat_v32xv32.c",
- "Common/src/Abs_32.c",
- "Common/src/Int32RShiftToInt16_Sat_32x16.c",
- "Common/src/From2iToMono_32.c",
- "Common/src/mult3s_16x16.c",
- "Common/src/Mult3s_32x16.c",
- "Common/src/NonLinComp_D16.c",
- "Common/src/DelayMix_16x16.c",
- "Common/src/MSTo2i_Sat_16x16.c",
- "Common/src/From2iToMS_16x16.c",
- "Common/src/Mac3s_Sat_16x16.c",
- "Common/src/Mac3s_Sat_32x16.c",
- "Common/src/Add2_Sat_16x16.c",
- "Common/src/Add2_Sat_32x32.c",
- "Common/src/LVC_MixSoft_1St_2i_D16C31_SAT.c",
- "Common/src/LVC_MixSoft_1St_D16C31_SAT.c",
- "Common/src/LVC_Mixer_VarSlope_SetTimeConstant.c",
- "Common/src/LVC_Mixer_SetTimeConstant.c",
- "Common/src/LVC_Mixer_SetTarget.c",
- "Common/src/LVC_Mixer_GetTarget.c",
- "Common/src/LVC_Mixer_Init.c",
- "Common/src/LVC_Core_MixHard_1St_2i_D16C31_SAT.c",
- "Common/src/LVC_Core_MixSoft_1St_2i_D16C31_WRA.c",
- "Common/src/LVC_Core_MixInSoft_D16C31_SAT.c",
- "Common/src/LVC_Mixer_GetCurrent.c",
- "Common/src/LVC_MixSoft_2St_D16C31_SAT.c",
- "Common/src/LVC_Core_MixSoft_1St_D16C31_WRA.c",
- "Common/src/LVC_Core_MixHard_2St_D16C31_SAT.c",
- "Common/src/LVC_MixInSoft_D16C31_SAT.c",
- "Common/src/AGC_MIX_VOL_2St1Mon_D32_WRA.c",
- "Common/src/LVM_Timer.c",
- "Common/src/LVM_Timer_Init.c",
+ "StereoWidening/src/LVCS_BypassMix.cpp",
+ "StereoWidening/src/LVCS_Control.cpp",
+ "StereoWidening/src/LVCS_Equaliser.cpp",
+ "StereoWidening/src/LVCS_Init.cpp",
+ "StereoWidening/src/LVCS_Process.cpp",
+ "StereoWidening/src/LVCS_ReverbGenerator.cpp",
+ "StereoWidening/src/LVCS_StereoEnhancer.cpp",
+ "StereoWidening/src/LVCS_Tables.cpp",
+ "Bass/src/LVDBE_Control.cpp",
+ "Bass/src/LVDBE_Init.cpp",
+ "Bass/src/LVDBE_Process.cpp",
+ "Bass/src/LVDBE_Tables.cpp",
+ "Bundle/src/LVM_API_Specials.cpp",
+ "Bundle/src/LVM_Buffers.cpp",
+ "Bundle/src/LVM_Init.cpp",
+ "Bundle/src/LVM_Process.cpp",
+ "Bundle/src/LVM_Tables.cpp",
+ "Bundle/src/LVM_Control.cpp",
+ "SpectrumAnalyzer/src/LVPSA_Control.cpp",
+ "SpectrumAnalyzer/src/LVPSA_Init.cpp",
+ "SpectrumAnalyzer/src/LVPSA_Memory.cpp",
+ "SpectrumAnalyzer/src/LVPSA_Process.cpp",
+ "SpectrumAnalyzer/src/LVPSA_QPD_Init.cpp",
+ "SpectrumAnalyzer/src/LVPSA_QPD_Process.cpp",
+ "SpectrumAnalyzer/src/LVPSA_Tables.cpp",
+ "Eq/src/LVEQNB_CalcCoef.cpp",
+ "Eq/src/LVEQNB_Control.cpp",
+ "Eq/src/LVEQNB_Init.cpp",
+ "Eq/src/LVEQNB_Process.cpp",
+ "Eq/src/LVEQNB_Tables.cpp",
+ "Common/src/InstAlloc.cpp",
+ "Common/src/DC_2I_D16_TRC_WRA_01.cpp",
+ "Common/src/DC_2I_D16_TRC_WRA_01_Init.cpp",
+ "Common/src/FO_2I_D16F32C15_LShx_TRC_WRA_01.cpp",
+ "Common/src/FO_2I_D16F32Css_LShx_TRC_WRA_01_Init.cpp",
+ "Common/src/FO_1I_D16F16C15_TRC_WRA_01.cpp",
+ "Common/src/FO_1I_D16F16Css_TRC_WRA_01_Init.cpp",
+ "Common/src/BP_1I_D16F32C30_TRC_WRA_01.cpp",
+ "Common/src/BP_1I_D16F16C14_TRC_WRA_01.cpp",
+ "Common/src/BP_1I_D32F32C30_TRC_WRA_02.cpp",
+ "Common/src/BP_1I_D16F16Css_TRC_WRA_01_Init.cpp",
+ "Common/src/BP_1I_D16F32Cll_TRC_WRA_01_Init.cpp",
+ "Common/src/BP_1I_D32F32Cll_TRC_WRA_02_Init.cpp",
+ "Common/src/BQ_2I_D32F32Cll_TRC_WRA_01_Init.cpp",
+ "Common/src/BQ_2I_D32F32C30_TRC_WRA_01.cpp",
+ "Common/src/BQ_2I_D16F32C15_TRC_WRA_01.cpp",
+ "Common/src/BQ_2I_D16F32C14_TRC_WRA_01.cpp",
+ "Common/src/BQ_2I_D16F32C13_TRC_WRA_01.cpp",
+ "Common/src/BQ_2I_D16F32Css_TRC_WRA_01_init.cpp",
+ "Common/src/BQ_2I_D16F16C15_TRC_WRA_01.cpp",
+ "Common/src/BQ_2I_D16F16C14_TRC_WRA_01.cpp",
+ "Common/src/BQ_2I_D16F16Css_TRC_WRA_01_Init.cpp",
+ "Common/src/BQ_1I_D16F16C15_TRC_WRA_01.cpp",
+ "Common/src/BQ_1I_D16F16Css_TRC_WRA_01_Init.cpp",
+ "Common/src/BQ_1I_D16F32C14_TRC_WRA_01.cpp",
+ "Common/src/BQ_1I_D16F32Css_TRC_WRA_01_init.cpp",
+ "Common/src/PK_2I_D32F32C30G11_TRC_WRA_01.cpp",
+ "Common/src/PK_2I_D32F32C14G11_TRC_WRA_01.cpp",
+ "Common/src/PK_2I_D32F32CssGss_TRC_WRA_01_Init.cpp",
+ "Common/src/PK_2I_D32F32CllGss_TRC_WRA_01_Init.cpp",
+ "Common/src/Int16LShiftToInt32_16x32.cpp",
+ "Common/src/From2iToMono_16.cpp",
+ "Common/src/Copy_16.cpp",
+ "Common/src/MonoTo2I_16.cpp",
+ "Common/src/MonoTo2I_32.cpp",
+ "Common/src/LoadConst_16.cpp",
+ "Common/src/LoadConst_32.cpp",
+ "Common/src/dB_to_Lin32.cpp",
+ "Common/src/Shift_Sat_v16xv16.cpp",
+ "Common/src/Shift_Sat_v32xv32.cpp",
+ "Common/src/Abs_32.cpp",
+ "Common/src/Int32RShiftToInt16_Sat_32x16.cpp",
+ "Common/src/From2iToMono_32.cpp",
+ "Common/src/mult3s_16x16.cpp",
+ "Common/src/Mult3s_32x16.cpp",
+ "Common/src/NonLinComp_D16.cpp",
+ "Common/src/DelayMix_16x16.cpp",
+ "Common/src/MSTo2i_Sat_16x16.cpp",
+ "Common/src/From2iToMS_16x16.cpp",
+ "Common/src/Mac3s_Sat_16x16.cpp",
+ "Common/src/Mac3s_Sat_32x16.cpp",
+ "Common/src/Add2_Sat_16x16.cpp",
+ "Common/src/Add2_Sat_32x32.cpp",
+ "Common/src/LVC_MixSoft_1St_2i_D16C31_SAT.cpp",
+ "Common/src/LVC_MixSoft_1St_D16C31_SAT.cpp",
+ "Common/src/LVC_Mixer_VarSlope_SetTimeConstant.cpp",
+ "Common/src/LVC_Mixer_SetTimeConstant.cpp",
+ "Common/src/LVC_Mixer_SetTarget.cpp",
+ "Common/src/LVC_Mixer_GetTarget.cpp",
+ "Common/src/LVC_Mixer_Init.cpp",
+ "Common/src/LVC_Core_MixHard_1St_2i_D16C31_SAT.cpp",
+ "Common/src/LVC_Core_MixSoft_1St_2i_D16C31_WRA.cpp",
+ "Common/src/LVC_Core_MixInSoft_D16C31_SAT.cpp",
+ "Common/src/LVC_Mixer_GetCurrent.cpp",
+ "Common/src/LVC_MixSoft_2St_D16C31_SAT.cpp",
+ "Common/src/LVC_Core_MixSoft_1St_D16C31_WRA.cpp",
+ "Common/src/LVC_Core_MixHard_2St_D16C31_SAT.cpp",
+ "Common/src/LVC_MixInSoft_D16C31_SAT.cpp",
+ "Common/src/AGC_MIX_VOL_2St1Mon_D32_WRA.cpp",
+ "Common/src/LVM_Timer.cpp",
+ "Common/src/LVM_Timer_Init.cpp",
],
local_include_dirs: [
@@ -135,10 +135,8 @@
header_libs: [
"libhardware_headers"
],
- cflags: [
+ cppflags: [
"-fvisibility=hidden",
- "-DBUILD_FLOAT",
- "-DHIGHER_FS",
"-DSUPPORT_MC",
"-Wall",
@@ -159,42 +157,42 @@
vendor: true,
srcs: [
- "Reverb/src/LVREV_ApplyNewSettings.c",
- "Reverb/src/LVREV_ClearAudioBuffers.c",
- "Reverb/src/LVREV_GetControlParameters.c",
- "Reverb/src/LVREV_GetInstanceHandle.c",
- "Reverb/src/LVREV_GetMemoryTable.c",
- "Reverb/src/LVREV_Process.c",
- "Reverb/src/LVREV_SetControlParameters.c",
- "Reverb/src/LVREV_Tables.c",
- "Common/src/Abs_32.c",
- "Common/src/InstAlloc.c",
- "Common/src/LoadConst_16.c",
- "Common/src/LoadConst_32.c",
- "Common/src/From2iToMono_32.c",
- "Common/src/Mult3s_32x16.c",
- "Common/src/FO_1I_D32F32C31_TRC_WRA_01.c",
- "Common/src/FO_1I_D32F32Cll_TRC_WRA_01_Init.c",
- "Common/src/DelayAllPass_Sat_32x16To32.c",
- "Common/src/Copy_16.c",
- "Common/src/Mac3s_Sat_32x16.c",
- "Common/src/DelayWrite_32.c",
- "Common/src/Shift_Sat_v32xv32.c",
- "Common/src/Add2_Sat_32x32.c",
- "Common/src/JoinTo2i_32x32.c",
- "Common/src/MonoTo2I_32.c",
- "Common/src/LVM_FO_HPF.c",
- "Common/src/LVM_FO_LPF.c",
- "Common/src/LVM_Polynomial.c",
- "Common/src/LVM_Power10.c",
- "Common/src/LVM_GetOmega.c",
- "Common/src/MixSoft_2St_D32C31_SAT.c",
- "Common/src/MixSoft_1St_D32C31_WRA.c",
- "Common/src/MixInSoft_D32C31_SAT.c",
- "Common/src/LVM_Mixer_TimeConstant.c",
- "Common/src/Core_MixHard_2St_D32C31_SAT.c",
- "Common/src/Core_MixSoft_1St_D32C31_WRA.c",
- "Common/src/Core_MixInSoft_D32C31_SAT.c",
+ "Reverb/src/LVREV_ApplyNewSettings.cpp",
+ "Reverb/src/LVREV_ClearAudioBuffers.cpp",
+ "Reverb/src/LVREV_GetControlParameters.cpp",
+ "Reverb/src/LVREV_GetInstanceHandle.cpp",
+ "Reverb/src/LVREV_GetMemoryTable.cpp",
+ "Reverb/src/LVREV_Process.cpp",
+ "Reverb/src/LVREV_SetControlParameters.cpp",
+ "Reverb/src/LVREV_Tables.cpp",
+ "Common/src/Abs_32.cpp",
+ "Common/src/InstAlloc.cpp",
+ "Common/src/LoadConst_16.cpp",
+ "Common/src/LoadConst_32.cpp",
+ "Common/src/From2iToMono_32.cpp",
+ "Common/src/Mult3s_32x16.cpp",
+ "Common/src/FO_1I_D32F32C31_TRC_WRA_01.cpp",
+ "Common/src/FO_1I_D32F32Cll_TRC_WRA_01_Init.cpp",
+ "Common/src/DelayAllPass_Sat_32x16To32.cpp",
+ "Common/src/Copy_16.cpp",
+ "Common/src/Mac3s_Sat_32x16.cpp",
+ "Common/src/DelayWrite_32.cpp",
+ "Common/src/Shift_Sat_v32xv32.cpp",
+ "Common/src/Add2_Sat_32x32.cpp",
+ "Common/src/JoinTo2i_32x32.cpp",
+ "Common/src/MonoTo2I_32.cpp",
+ "Common/src/LVM_FO_HPF.cpp",
+ "Common/src/LVM_FO_LPF.cpp",
+ "Common/src/LVM_Polynomial.cpp",
+ "Common/src/LVM_Power10.cpp",
+ "Common/src/LVM_GetOmega.cpp",
+ "Common/src/MixSoft_2St_D32C31_SAT.cpp",
+ "Common/src/MixSoft_1St_D32C31_WRA.cpp",
+ "Common/src/MixInSoft_D32C31_SAT.cpp",
+ "Common/src/LVM_Mixer_TimeConstant.cpp",
+ "Common/src/Core_MixHard_2St_D32C31_SAT.cpp",
+ "Common/src/Core_MixSoft_1St_D32C31_WRA.cpp",
+ "Common/src/Core_MixInSoft_D32C31_SAT.cpp",
],
local_include_dirs: [
@@ -206,10 +204,8 @@
"Common/lib",
],
- cflags: [
+ cppflags: [
"-fvisibility=hidden",
- "-DBUILD_FLOAT",
- "-DHIGHER_FS",
"-Wall",
"-Werror",
diff --git a/media/libeffects/lvm/lib/Bass/lib/LVDBE.h b/media/libeffects/lvm/lib/Bass/lib/LVDBE.h
index cc066b0..948d79c 100644
--- a/media/libeffects/lvm/lib/Bass/lib/LVDBE.h
+++ b/media/libeffects/lvm/lib/Bass/lib/LVDBE.h
@@ -55,11 +55,6 @@
#ifndef __LVDBE_H__
#define __LVDBE_H__
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-
/****************************************************************************************/
/* */
/* Includes */
@@ -68,7 +63,6 @@
#include "LVM_Types.h"
-
/****************************************************************************************/
/* */
/* Definitions */
@@ -85,7 +79,6 @@
#define LVDBE_EFFECT_12DB 12
#define LVDBE_EFFECT_15DB 15
-
/****************************************************************************************/
/* */
/* Types */
@@ -95,7 +88,6 @@
/* Instance handle */
typedef void *LVDBE_Handle_t;
-
/* Operating modes */
typedef enum
{
@@ -104,7 +96,6 @@
LVDBE_MODE_MAX = LVM_MAXINT_32
} LVDBE_Mode_en;
-
/* High pass filter */
typedef enum
{
@@ -113,7 +104,6 @@
LVDBE_HPF_MAX = LVM_MAXINT_32
} LVDBE_FilterSelect_en;
-
/* Volume control */
typedef enum
{
@@ -122,7 +112,6 @@
LVDBE_VOLUME_MAX = LVM_MAXINT_32
} LVDBE_Volume_en;
-
/* Memory Types */
typedef enum
{
@@ -134,7 +123,6 @@
} LVDBE_MemoryTypes_en;
-
/* Function return status */
typedef enum
{
@@ -146,7 +134,6 @@
LVDBE_STATUS_MAX = LVM_MAXINT_32
} LVDBE_ReturnStatus_en;
-
/****************************************************************************************/
/* */
/* Linked enumerated type and capability definitions */
@@ -185,7 +172,6 @@
LVDBE_CENTRE_MAX = LVM_MAXINT_32
} LVDBE_CentreFreq_en;
-
/*
* Supported sample rates in samples per second
*/
@@ -198,12 +184,10 @@
#define LVDBE_CAP_FS_32000 64
#define LVDBE_CAP_FS_44100 128
#define LVDBE_CAP_FS_48000 256
-#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
#define LVDBE_CAP_FS_88200 512
#define LVDBE_CAP_FS_96000 1024
#define LVDBE_CAP_FS_176400 2048
#define LVDBE_CAP_FS_192000 4096
-#endif
typedef enum
{
@@ -216,16 +200,13 @@
LVDBE_FS_32000 = 6,
LVDBE_FS_44100 = 7,
LVDBE_FS_48000 = 8,
-#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
LVDBE_FS_88200 = 9,
LVDBE_FS_96000 = 10,
LVDBE_FS_176400 = 11,
LVDBE_FS_192000 = 12,
-#endif
LVDBE_FS_MAX = LVM_MAXINT_32
} LVDBE_Fs_en;
-
/****************************************************************************************/
/* */
/* Structures */
@@ -241,14 +222,12 @@
void *pBaseAddress; /* Pointer to the region base address */
} LVDBE_MemoryRegion_t;
-
/* Memory table containing the region definitions */
typedef struct
{
LVDBE_MemoryRegion_t Region[LVDBE_NR_MEMORY_REGIONS]; /* One definition for each region */
} LVDBE_MemTab_t;
-
/* Parameter structure */
typedef struct
{
@@ -266,7 +245,6 @@
} LVDBE_Params_t;
-
/* Capability structure */
typedef struct
{
@@ -275,7 +253,6 @@
LVM_UINT16 MaxBlockSize; /* Maximum block size in sample pairs */
} LVDBE_Capabilities_t;
-
/****************************************************************************************/
/* */
/* Function Prototypes */
@@ -317,7 +294,6 @@
LVDBE_MemTab_t *pMemoryTable,
LVDBE_Capabilities_t *pCapabilities);
-
/****************************************************************************************/
/* */
/* FUNCTION: LVDBE_Init */
@@ -355,7 +331,6 @@
LVDBE_MemTab_t *pMemoryTable,
LVDBE_Capabilities_t *pCapabilities);
-
/****************************************************************************************/
/* */
/* FUNCTION: LVDBE_GetParameters */
@@ -379,7 +354,6 @@
LVDBE_ReturnStatus_en LVDBE_GetParameters(LVDBE_Handle_t hInstance,
LVDBE_Params_t *pParams);
-
/****************************************************************************************/
/* */
/* FUNCTION: LVDBE_GetCapabilities */
@@ -403,7 +377,6 @@
LVDBE_ReturnStatus_en LVDBE_GetCapabilities(LVDBE_Handle_t hInstance,
LVDBE_Capabilities_t *pCapabilities);
-
/****************************************************************************************/
/* */
/* FUNCTION: LVDBE_Control */
@@ -444,7 +417,6 @@
LVDBE_ReturnStatus_en LVDBE_Control(LVDBE_Handle_t hInstance,
LVDBE_Params_t *pParams);
-
/****************************************************************************************/
/* */
/* FUNCTION: LVDBE_Process */
@@ -465,20 +437,9 @@
/* NOTES: */
/* */
/****************************************************************************************/
-#ifdef BUILD_FLOAT
LVDBE_ReturnStatus_en LVDBE_Process(LVDBE_Handle_t hInstance,
const LVM_FLOAT *pInData,
LVM_FLOAT *pOutData,
LVM_UINT16 NumSamples);
-#else
-LVDBE_ReturnStatus_en LVDBE_Process(LVDBE_Handle_t hInstance,
- const LVM_INT16 *pInData,
- LVM_INT16 *pOutData,
- LVM_UINT16 NumSamples);
-#endif
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
#endif /* __LVDBE_H__ */
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Coeffs.h b/media/libeffects/lvm/lib/Bass/src/LVDBE_Coeffs.h
index 8f058e8..b364dae 100644
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Coeffs.h
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Coeffs.h
@@ -18,8 +18,6 @@
#ifndef __LVDBE_COEFFS_H__
#define __LVDBE_COEFFS_H__
-
-#ifndef BUILD_FLOAT
/************************************************************************************/
/* */
/* General */
@@ -28,504 +26,6 @@
#define LVDBE_SCALESHIFT 10 /* As a power of 2 */
-
-/************************************************************************************/
-/* */
-/* High Pass Filter coefficients */
-/* */
-/************************************************************************************/
-
- /* Coefficients for centre frequency 55Hz */
-#define HPF_Fs8000_Fc55_A0 1029556328 /* Floating point value 0.958849 */
-#define HPF_Fs8000_Fc55_A1 (-2059112655) /* Floating point value -1.917698 */
-#define HPF_Fs8000_Fc55_A2 1029556328 /* Floating point value 0.958849 */
-#define HPF_Fs8000_Fc55_B1 (-2081986375) /* Floating point value -1.939001 */
-#define HPF_Fs8000_Fc55_B2 1010183914 /* Floating point value 0.940807 */
-#define HPF_Fs11025_Fc55_A0 1038210831 /* Floating point value 0.966909 */
-#define HPF_Fs11025_Fc55_A1 (-2076421662) /* Floating point value -1.933818 */
-#define HPF_Fs11025_Fc55_A2 1038210831 /* Floating point value 0.966909 */
-#define HPF_Fs11025_Fc55_B1 (-2099950710) /* Floating point value -1.955732 */
-#define HPF_Fs11025_Fc55_B2 1027238450 /* Floating point value 0.956690 */
-#define HPF_Fs12000_Fc55_A0 1040079943 /* Floating point value 0.968650 */
-#define HPF_Fs12000_Fc55_A1 (-2080159885) /* Floating point value -1.937300 */
-#define HPF_Fs12000_Fc55_A2 1040079943 /* Floating point value 0.968650 */
-#define HPF_Fs12000_Fc55_B1 (-2103811702) /* Floating point value -1.959327 */
-#define HPF_Fs12000_Fc55_B2 1030940477 /* Floating point value 0.960138 */
-#define HPF_Fs16000_Fc55_A0 1045381988 /* Floating point value 0.973588 */
-#define HPF_Fs16000_Fc55_A1 (-2090763976) /* Floating point value -1.947176 */
-#define HPF_Fs16000_Fc55_A2 1045381988 /* Floating point value 0.973588 */
-#define HPF_Fs16000_Fc55_B1 (-2114727793) /* Floating point value -1.969494 */
-#define HPF_Fs16000_Fc55_B2 1041478147 /* Floating point value 0.969952 */
-#define HPF_Fs22050_Fc55_A0 1049766523 /* Floating point value 0.977671 */
-#define HPF_Fs22050_Fc55_A1 (-2099533046) /* Floating point value -1.955343 */
-#define HPF_Fs22050_Fc55_A2 1049766523 /* Floating point value 0.977671 */
-#define HPF_Fs22050_Fc55_B1 (-2123714381) /* Floating point value -1.977863 */
-#define HPF_Fs22050_Fc55_B2 1050232780 /* Floating point value 0.978105 */
-#define HPF_Fs24000_Fc55_A0 1050711051 /* Floating point value 0.978551 */
-#define HPF_Fs24000_Fc55_A1 (-2101422103) /* Floating point value -1.957102 */
-#define HPF_Fs24000_Fc55_A2 1050711051 /* Floating point value 0.978551 */
-#define HPF_Fs24000_Fc55_B1 (-2125645498) /* Floating point value -1.979662 */
-#define HPF_Fs24000_Fc55_B2 1052123526 /* Floating point value 0.979866 */
-#define HPF_Fs32000_Fc55_A0 1053385759 /* Floating point value 0.981042 */
-#define HPF_Fs32000_Fc55_A1 (-2106771519) /* Floating point value -1.962084 */
-#define HPF_Fs32000_Fc55_A2 1053385759 /* Floating point value 0.981042 */
-#define HPF_Fs32000_Fc55_B1 (-2131104794) /* Floating point value -1.984746 */
-#define HPF_Fs32000_Fc55_B2 1057486949 /* Floating point value 0.984861 */
-#define HPF_Fs44100_Fc55_A0 1055592498 /* Floating point value 0.983097 */
-#define HPF_Fs44100_Fc55_A1 (-2111184995) /* Floating point value -1.966194 */
-#define HPF_Fs44100_Fc55_A2 1055592498 /* Floating point value 0.983097 */
-#define HPF_Fs44100_Fc55_B1 (-2135598658) /* Floating point value -1.988931 */
-#define HPF_Fs44100_Fc55_B2 1061922249 /* Floating point value 0.988992 */
-#define HPF_Fs48000_Fc55_A0 1056067276 /* Floating point value 0.983539 */
-#define HPF_Fs48000_Fc55_A1 (-2112134551) /* Floating point value -1.967079 */
-#define HPF_Fs48000_Fc55_A2 1056067276 /* Floating point value 0.983539 */
-#define HPF_Fs48000_Fc55_B1 (-2136564296) /* Floating point value -1.989831 */
-#define HPF_Fs48000_Fc55_B2 1062877714 /* Floating point value 0.989882 */
-
- /* Coefficients for centre frequency 66Hz */
-#define HPF_Fs8000_Fc66_A0 1023293271 /* Floating point value 0.953016 */
-#define HPF_Fs8000_Fc66_A1 (-2046586542) /* Floating point value -1.906032 */
-#define HPF_Fs8000_Fc66_A2 1023293271 /* Floating point value 0.953016 */
-#define HPF_Fs8000_Fc66_B1 (-2068896860) /* Floating point value -1.926810 */
-#define HPF_Fs8000_Fc66_B2 997931110 /* Floating point value 0.929396 */
-#define HPF_Fs11025_Fc66_A0 1033624228 /* Floating point value 0.962638 */
-#define HPF_Fs11025_Fc66_A1 (-2067248455) /* Floating point value -1.925275 */
-#define HPF_Fs11025_Fc66_A2 1033624228 /* Floating point value 0.962638 */
-#define HPF_Fs11025_Fc66_B1 (-2090448000) /* Floating point value -1.946881 */
-#define HPF_Fs11025_Fc66_B2 1018182305 /* Floating point value 0.948256 */
-#define HPF_Fs12000_Fc66_A0 1035857662 /* Floating point value 0.964718 */
-#define HPF_Fs12000_Fc66_A1 (-2071715325) /* Floating point value -1.929435 */
-#define HPF_Fs12000_Fc66_A2 1035857662 /* Floating point value 0.964718 */
-#define HPF_Fs12000_Fc66_B1 (-2095080333) /* Floating point value -1.951196 */
-#define HPF_Fs12000_Fc66_B2 1022587158 /* Floating point value 0.952359 */
-#define HPF_Fs16000_Fc66_A0 1042197528 /* Floating point value 0.970622 */
-#define HPF_Fs16000_Fc66_A1 (-2084395056) /* Floating point value -1.941244 */
-#define HPF_Fs16000_Fc66_A2 1042197528 /* Floating point value 0.970622 */
-#define HPF_Fs16000_Fc66_B1 (-2108177912) /* Floating point value -1.963394 */
-#define HPF_Fs16000_Fc66_B2 1035142690 /* Floating point value 0.964052 */
-#define HPF_Fs22050_Fc66_A0 1047445145 /* Floating point value 0.975509 */
-#define HPF_Fs22050_Fc66_A1 (-2094890289) /* Floating point value -1.951019 */
-#define HPF_Fs22050_Fc66_A2 1047445145 /* Floating point value 0.975509 */
-#define HPF_Fs22050_Fc66_B1 (-2118961025) /* Floating point value -1.973436 */
-#define HPF_Fs22050_Fc66_B2 1045593102 /* Floating point value 0.973784 */
-#define HPF_Fs24000_Fc66_A0 1048576175 /* Floating point value 0.976563 */
-#define HPF_Fs24000_Fc66_A1 (-2097152349) /* Floating point value -1.953125 */
-#define HPF_Fs24000_Fc66_A2 1048576175 /* Floating point value 0.976563 */
-#define HPF_Fs24000_Fc66_B1 (-2121278255) /* Floating point value -1.975594 */
-#define HPF_Fs24000_Fc66_B2 1047852379 /* Floating point value 0.975889 */
-#define HPF_Fs32000_Fc66_A0 1051780119 /* Floating point value 0.979547 */
-#define HPF_Fs32000_Fc66_A1 (-2103560237) /* Floating point value -1.959093 */
-#define HPF_Fs32000_Fc66_A2 1051780119 /* Floating point value 0.979547 */
-#define HPF_Fs32000_Fc66_B1 (-2127829187) /* Floating point value -1.981695 */
-#define HPF_Fs32000_Fc66_B2 1054265623 /* Floating point value 0.981861 */
-#define HPF_Fs44100_Fc66_A0 1054424722 /* Floating point value 0.982010 */
-#define HPF_Fs44100_Fc66_A1 (-2108849444) /* Floating point value -1.964019 */
-#define HPF_Fs44100_Fc66_A2 1054424722 /* Floating point value 0.982010 */
-#define HPF_Fs44100_Fc66_B1 (-2133221723) /* Floating point value -1.986718 */
-#define HPF_Fs44100_Fc66_B2 1059573993 /* Floating point value 0.986805 */
-#define HPF_Fs48000_Fc66_A0 1054993851 /* Floating point value 0.982540 */
-#define HPF_Fs48000_Fc66_A1 (-2109987702) /* Floating point value -1.965079 */
-#define HPF_Fs48000_Fc66_A2 1054993851 /* Floating point value 0.982540 */
-#define HPF_Fs48000_Fc66_B1 (-2134380475) /* Floating point value -1.987797 */
-#define HPF_Fs48000_Fc66_B2 1060718118 /* Floating point value 0.987871 */
-
- /* Coefficients for centre frequency 78Hz */
-#define HPF_Fs8000_Fc78_A0 1016504203 /* Floating point value 0.946693 */
-#define HPF_Fs8000_Fc78_A1 (-2033008405) /* Floating point value -1.893387 */
-#define HPF_Fs8000_Fc78_A2 1016504203 /* Floating point value 0.946693 */
-#define HPF_Fs8000_Fc78_B1 (-2054623390) /* Floating point value -1.913517 */
-#define HPF_Fs8000_Fc78_B2 984733853 /* Floating point value 0.917105 */
-#define HPF_Fs11025_Fc78_A0 1028643741 /* Floating point value 0.957999 */
-#define HPF_Fs11025_Fc78_A1 (-2057287482) /* Floating point value -1.915998 */
-#define HPF_Fs11025_Fc78_A2 1028643741 /* Floating point value 0.957999 */
-#define HPF_Fs11025_Fc78_B1 (-2080083769) /* Floating point value -1.937229 */
-#define HPF_Fs11025_Fc78_B2 1008393904 /* Floating point value 0.939140 */
-#define HPF_Fs12000_Fc78_A0 1031271067 /* Floating point value 0.960446 */
-#define HPF_Fs12000_Fc78_A1 (-2062542133) /* Floating point value -1.920892 */
-#define HPF_Fs12000_Fc78_A2 1031271067 /* Floating point value 0.960446 */
-#define HPF_Fs12000_Fc78_B1 (-2085557048) /* Floating point value -1.942326 */
-#define HPF_Fs12000_Fc78_B2 1013551620 /* Floating point value 0.943944 */
-#define HPF_Fs16000_Fc78_A0 1038734628 /* Floating point value 0.967397 */
-#define HPF_Fs16000_Fc78_A1 (-2077469256) /* Floating point value -1.934794 */
-#define HPF_Fs16000_Fc78_A2 1038734628 /* Floating point value 0.967397 */
-#define HPF_Fs16000_Fc78_B1 (-2101033380) /* Floating point value -1.956740 */
-#define HPF_Fs16000_Fc78_B2 1028275228 /* Floating point value 0.957656 */
-#define HPF_Fs22050_Fc78_A0 1044918584 /* Floating point value 0.973156 */
-#define HPF_Fs22050_Fc78_A1 (-2089837169) /* Floating point value -1.946313 */
-#define HPF_Fs22050_Fc78_A2 1044918584 /* Floating point value 0.973156 */
-#define HPF_Fs22050_Fc78_B1 (-2113775854) /* Floating point value -1.968607 */
-#define HPF_Fs22050_Fc78_B2 1040555007 /* Floating point value 0.969092 */
-#define HPF_Fs24000_Fc78_A0 1046252164 /* Floating point value 0.974398 */
-#define HPF_Fs24000_Fc78_A1 (-2092504328) /* Floating point value -1.948797 */
-#define HPF_Fs24000_Fc78_A2 1046252164 /* Floating point value 0.974398 */
-#define HPF_Fs24000_Fc78_B1 (-2116514229) /* Floating point value -1.971157 */
-#define HPF_Fs24000_Fc78_B2 1043212719 /* Floating point value 0.971568 */
-#define HPF_Fs32000_Fc78_A0 1050031301 /* Floating point value 0.977918 */
-#define HPF_Fs32000_Fc78_A1 (-2100062603) /* Floating point value -1.955836 */
-#define HPF_Fs32000_Fc78_A2 1050031301 /* Floating point value 0.977918 */
-#define HPF_Fs32000_Fc78_B1 (-2124255900) /* Floating point value -1.978367 */
-#define HPF_Fs32000_Fc78_B2 1050762639 /* Floating point value 0.978599 */
-#define HPF_Fs44100_Fc78_A0 1053152258 /* Floating point value 0.980824 */
-#define HPF_Fs44100_Fc78_A1 (-2106304516) /* Floating point value -1.961649 */
-#define HPF_Fs44100_Fc78_A2 1053152258 /* Floating point value 0.980824 */
-#define HPF_Fs44100_Fc78_B1 (-2130628742) /* Floating point value -1.984303 */
-#define HPF_Fs44100_Fc78_B2 1057018180 /* Floating point value 0.984425 */
-#define HPF_Fs48000_Fc78_A0 1053824087 /* Floating point value 0.981450 */
-#define HPF_Fs48000_Fc78_A1 (-2107648173) /* Floating point value -1.962900 */
-#define HPF_Fs48000_Fc78_A2 1053824087 /* Floating point value 0.981450 */
-#define HPF_Fs48000_Fc78_B1 (-2131998154) /* Floating point value -1.985578 */
-#define HPF_Fs48000_Fc78_B2 1058367200 /* Floating point value 0.985681 */
-
- /* Coefficients for centre frequency 90Hz */
-#define HPF_Fs8000_Fc90_A0 1009760053 /* Floating point value 0.940412 */
-#define HPF_Fs8000_Fc90_A1 (-2019520105) /* Floating point value -1.880825 */
-#define HPF_Fs8000_Fc90_A2 1009760053 /* Floating point value 0.940412 */
-#define HPF_Fs8000_Fc90_B1 (-2040357139) /* Floating point value -1.900231 */
-#define HPF_Fs8000_Fc90_B2 971711129 /* Floating point value 0.904977 */
-#define HPF_Fs11025_Fc90_A0 1023687217 /* Floating point value 0.953383 */
-#define HPF_Fs11025_Fc90_A1 (-2047374434) /* Floating point value -1.906766 */
-#define HPF_Fs11025_Fc90_A2 1023687217 /* Floating point value 0.953383 */
-#define HPF_Fs11025_Fc90_B1 (-2069722397) /* Floating point value -1.927579 */
-#define HPF_Fs11025_Fc90_B2 998699604 /* Floating point value 0.930111 */
-#define HPF_Fs12000_Fc90_A0 1026704754 /* Floating point value 0.956193 */
-#define HPF_Fs12000_Fc90_A1 (-2053409508) /* Floating point value -1.912387 */
-#define HPF_Fs12000_Fc90_A2 1026704754 /* Floating point value 0.956193 */
-#define HPF_Fs12000_Fc90_B1 (-2076035996) /* Floating point value -1.933459 */
-#define HPF_Fs12000_Fc90_B2 1004595918 /* Floating point value 0.935603 */
-#define HPF_Fs16000_Fc90_A0 1035283225 /* Floating point value 0.964183 */
-#define HPF_Fs16000_Fc90_A1 (-2070566451) /* Floating point value -1.928365 */
-#define HPF_Fs16000_Fc90_A2 1035283225 /* Floating point value 0.964183 */
-#define HPF_Fs16000_Fc90_B1 (-2093889811) /* Floating point value -1.950087 */
-#define HPF_Fs16000_Fc90_B2 1021453326 /* Floating point value 0.951303 */
-#define HPF_Fs22050_Fc90_A0 1042398116 /* Floating point value 0.970809 */
-#define HPF_Fs22050_Fc90_A1 (-2084796232) /* Floating point value -1.941618 */
-#define HPF_Fs22050_Fc90_A2 1042398116 /* Floating point value 0.970809 */
-#define HPF_Fs22050_Fc90_B1 (-2108591057) /* Floating point value -1.963778 */
-#define HPF_Fs22050_Fc90_B2 1035541188 /* Floating point value 0.964423 */
-#define HPF_Fs24000_Fc90_A0 1043933302 /* Floating point value 0.972239 */
-#define HPF_Fs24000_Fc90_A1 (-2087866604) /* Floating point value -1.944477 */
-#define HPF_Fs24000_Fc90_A2 1043933302 /* Floating point value 0.972239 */
-#define HPF_Fs24000_Fc90_B1 (-2111750495) /* Floating point value -1.966721 */
-#define HPF_Fs24000_Fc90_B2 1038593601 /* Floating point value 0.967266 */
-#define HPF_Fs32000_Fc90_A0 1048285391 /* Floating point value 0.976292 */
-#define HPF_Fs32000_Fc90_A1 (-2096570783) /* Floating point value -1.952584 */
-#define HPF_Fs32000_Fc90_A2 1048285391 /* Floating point value 0.976292 */
-#define HPF_Fs32000_Fc90_B1 (-2120682737) /* Floating point value -1.975040 */
-#define HPF_Fs32000_Fc90_B2 1047271295 /* Floating point value 0.975347 */
-#define HPF_Fs44100_Fc90_A0 1051881330 /* Floating point value 0.979641 */
-#define HPF_Fs44100_Fc90_A1 (-2103762660) /* Floating point value -1.959282 */
-#define HPF_Fs44100_Fc90_A2 1051881330 /* Floating point value 0.979641 */
-#define HPF_Fs44100_Fc90_B1 (-2128035809) /* Floating point value -1.981888 */
-#define HPF_Fs44100_Fc90_B2 1054468533 /* Floating point value 0.982050 */
-#define HPF_Fs48000_Fc90_A0 1052655619 /* Floating point value 0.980362 */
-#define HPF_Fs48000_Fc90_A1 (-2105311238) /* Floating point value -1.960724 */
-#define HPF_Fs48000_Fc90_A2 1052655619 /* Floating point value 0.980362 */
-#define HPF_Fs48000_Fc90_B1 (-2129615871) /* Floating point value -1.983359 */
-#define HPF_Fs48000_Fc90_B2 1056021492 /* Floating point value 0.983497 */
-
-
-/************************************************************************************/
-/* */
-/* Band Pass Filter coefficients */
-/* */
-/************************************************************************************/
-
- /* Coefficients for centre frequency 55Hz */
-#define BPF_Fs8000_Fc55_A0 9875247 /* Floating point value 0.009197 */
-#define BPF_Fs8000_Fc55_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs8000_Fc55_A2 (-9875247) /* Floating point value -0.009197 */
-#define BPF_Fs8000_Fc55_B1 (-2125519830) /* Floating point value -1.979545 */
-#define BPF_Fs8000_Fc55_B2 1053762629 /* Floating point value 0.981393 */
-#define BPF_Fs11025_Fc55_A0 7183952 /* Floating point value 0.006691 */
-#define BPF_Fs11025_Fc55_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs11025_Fc55_A2 (-7183952) /* Floating point value -0.006691 */
-#define BPF_Fs11025_Fc55_B1 (-2131901658) /* Floating point value -1.985488 */
-#define BPF_Fs11025_Fc55_B2 1059207548 /* Floating point value 0.986464 */
-#define BPF_Fs12000_Fc55_A0 6603871 /* Floating point value 0.006150 */
-#define BPF_Fs12000_Fc55_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs12000_Fc55_A2 (-6603871) /* Floating point value -0.006150 */
-#define BPF_Fs12000_Fc55_B1 (-2133238092) /* Floating point value -1.986733 */
-#define BPF_Fs12000_Fc55_B2 1060381143 /* Floating point value 0.987557 */
-#define BPF_Fs16000_Fc55_A0 4960591 /* Floating point value 0.004620 */
-#define BPF_Fs16000_Fc55_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs16000_Fc55_A2 (-4960591) /* Floating point value -0.004620 */
-#define BPF_Fs16000_Fc55_B1 (-2136949052) /* Floating point value -1.990189 */
-#define BPF_Fs16000_Fc55_B2 1063705760 /* Floating point value 0.990653 */
-#define BPF_Fs22050_Fc55_A0 3604131 /* Floating point value 0.003357 */
-#define BPF_Fs22050_Fc55_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs22050_Fc55_A2 (-3604131) /* Floating point value -0.003357 */
-#define BPF_Fs22050_Fc55_B1 (-2139929085) /* Floating point value -1.992964 */
-#define BPF_Fs22050_Fc55_B2 1066450095 /* Floating point value 0.993209 */
-#define BPF_Fs24000_Fc55_A0 3312207 /* Floating point value 0.003085 */
-#define BPF_Fs24000_Fc55_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs24000_Fc55_A2 (-3312207) /* Floating point value -0.003085 */
-#define BPF_Fs24000_Fc55_B1 (-2140560606) /* Floating point value -1.993552 */
-#define BPF_Fs24000_Fc55_B2 1067040703 /* Floating point value 0.993759 */
-#define BPF_Fs32000_Fc55_A0 2486091 /* Floating point value 0.002315 */
-#define BPF_Fs32000_Fc55_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs32000_Fc55_A2 (-2486091) /* Floating point value -0.002315 */
-#define BPF_Fs32000_Fc55_B1 (-2142328962) /* Floating point value -1.995199 */
-#define BPF_Fs32000_Fc55_B2 1068712067 /* Floating point value 0.995316 */
-#define BPF_Fs44100_Fc55_A0 1805125 /* Floating point value 0.001681 */
-#define BPF_Fs44100_Fc55_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs44100_Fc55_A2 (-1805125) /* Floating point value -0.001681 */
-#define BPF_Fs44100_Fc55_B1 (-2143765772) /* Floating point value -1.996537 */
-#define BPF_Fs44100_Fc55_B2 1070089770 /* Floating point value 0.996599 */
-#define BPF_Fs48000_Fc55_A0 1658687 /* Floating point value 0.001545 */
-#define BPF_Fs48000_Fc55_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs48000_Fc55_A2 (-1658687) /* Floating point value -0.001545 */
-#define BPF_Fs48000_Fc55_B1 (-2144072292) /* Floating point value -1.996823 */
-#define BPF_Fs48000_Fc55_B2 1070386036 /* Floating point value 0.996875 */
-
- /* Coefficients for centre frequency 66Hz */
-#define BPF_Fs8000_Fc66_A0 13580189 /* Floating point value 0.012648 */
-#define BPF_Fs8000_Fc66_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs8000_Fc66_A2 (-13580189) /* Floating point value -0.012648 */
-#define BPF_Fs8000_Fc66_B1 (-2117161175) /* Floating point value -1.971760 */
-#define BPF_Fs8000_Fc66_B2 1046266945 /* Floating point value 0.974412 */
-#define BPF_Fs11025_Fc66_A0 9888559 /* Floating point value 0.009209 */
-#define BPF_Fs11025_Fc66_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs11025_Fc66_A2 (-9888559) /* Floating point value -0.009209 */
-#define BPF_Fs11025_Fc66_B1 (-2125972738) /* Floating point value -1.979966 */
-#define BPF_Fs11025_Fc66_B2 1053735698 /* Floating point value 0.981368 */
-#define BPF_Fs12000_Fc66_A0 9091954 /* Floating point value 0.008468 */
-#define BPF_Fs12000_Fc66_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs12000_Fc66_A2 (-9091954) /* Floating point value -0.008468 */
-#define BPF_Fs12000_Fc66_B1 (-2127818004) /* Floating point value -1.981685 */
-#define BPF_Fs12000_Fc66_B2 1055347356 /* Floating point value 0.982869 */
-#define BPF_Fs16000_Fc66_A0 6833525 /* Floating point value 0.006364 */
-#define BPF_Fs16000_Fc66_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs16000_Fc66_A2 (-6833525) /* Floating point value -0.006364 */
-#define BPF_Fs16000_Fc66_B1 (-2132941739) /* Floating point value -1.986457 */
-#define BPF_Fs16000_Fc66_B2 1059916517 /* Floating point value 0.987124 */
-#define BPF_Fs22050_Fc66_A0 4967309 /* Floating point value 0.004626 */
-#define BPF_Fs22050_Fc66_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs22050_Fc66_A2 (-4967309) /* Floating point value -0.004626 */
-#define BPF_Fs22050_Fc66_B1 (-2137056003) /* Floating point value -1.990288 */
-#define BPF_Fs22050_Fc66_B2 1063692170 /* Floating point value 0.990641 */
-#define BPF_Fs24000_Fc66_A0 4565445 /* Floating point value 0.004252 */
-#define BPF_Fs24000_Fc66_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs24000_Fc66_A2 (-4565445) /* Floating point value -0.004252 */
-#define BPF_Fs24000_Fc66_B1 (-2137927842) /* Floating point value -1.991100 */
-#define BPF_Fs24000_Fc66_B2 1064505202 /* Floating point value 0.991398 */
-#define BPF_Fs32000_Fc66_A0 3427761 /* Floating point value 0.003192 */
-#define BPF_Fs32000_Fc66_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs32000_Fc66_A2 (-3427761) /* Floating point value -0.003192 */
-#define BPF_Fs32000_Fc66_B1 (-2140369007) /* Floating point value -1.993374 */
-#define BPF_Fs32000_Fc66_B2 1066806920 /* Floating point value 0.993541 */
-#define BPF_Fs44100_Fc66_A0 2489466 /* Floating point value 0.002318 */
-#define BPF_Fs44100_Fc66_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs44100_Fc66_A2 (-2489466) /* Floating point value -0.002318 */
-#define BPF_Fs44100_Fc66_B1 (-2142352342) /* Floating point value -1.995221 */
-#define BPF_Fs44100_Fc66_B2 1068705240 /* Floating point value 0.995309 */
-#define BPF_Fs48000_Fc66_A0 2287632 /* Floating point value 0.002131 */
-#define BPF_Fs48000_Fc66_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs48000_Fc66_A2 (-2287632) /* Floating point value -0.002131 */
-#define BPF_Fs48000_Fc66_B1 (-2142775436) /* Floating point value -1.995615 */
-#define BPF_Fs48000_Fc66_B2 1069113581 /* Floating point value 0.995690 */
-
- /* Coefficients for centre frequency 78Hz */
-#define BPF_Fs8000_Fc78_A0 19941180 /* Floating point value 0.018572 */
-#define BPF_Fs8000_Fc78_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs8000_Fc78_A2 (-19941180) /* Floating point value -0.018572 */
-#define BPF_Fs8000_Fc78_B1 (-2103186749) /* Floating point value -1.958745 */
-#define BPF_Fs8000_Fc78_B2 1033397648 /* Floating point value 0.962427 */
-#define BPF_Fs11025_Fc78_A0 14543934 /* Floating point value 0.013545 */
-#define BPF_Fs11025_Fc78_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs11025_Fc78_A2 (-14543934) /* Floating point value -0.013545 */
-#define BPF_Fs11025_Fc78_B1 (-2115966638) /* Floating point value -1.970647 */
-#define BPF_Fs11025_Fc78_B2 1044317135 /* Floating point value 0.972596 */
-#define BPF_Fs12000_Fc78_A0 13376999 /* Floating point value 0.012458 */
-#define BPF_Fs12000_Fc78_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs12000_Fc78_A2 (-13376999) /* Floating point value -0.012458 */
-#define BPF_Fs12000_Fc78_B1 (-2118651708) /* Floating point value -1.973148 */
-#define BPF_Fs12000_Fc78_B2 1046678029 /* Floating point value 0.974795 */
-#define BPF_Fs16000_Fc78_A0 10064222 /* Floating point value 0.009373 */
-#define BPF_Fs16000_Fc78_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs16000_Fc78_A2 (-10064222) /* Floating point value -0.009373 */
-#define BPF_Fs16000_Fc78_B1 (-2126124342) /* Floating point value -1.980108 */
-#define BPF_Fs16000_Fc78_B2 1053380304 /* Floating point value 0.981037 */
-#define BPF_Fs22050_Fc78_A0 7321780 /* Floating point value 0.006819 */
-#define BPF_Fs22050_Fc78_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs22050_Fc78_A2 (-7321780) /* Floating point value -0.006819 */
-#define BPF_Fs22050_Fc78_B1 (-2132143771) /* Floating point value -1.985714 */
-#define BPF_Fs22050_Fc78_B2 1058928700 /* Floating point value 0.986204 */
-#define BPF_Fs24000_Fc78_A0 6730640 /* Floating point value 0.006268 */
-#define BPF_Fs24000_Fc78_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs24000_Fc78_A2 (-6730640) /* Floating point value -0.006268 */
-#define BPF_Fs24000_Fc78_B1 (-2133421607) /* Floating point value -1.986904 */
-#define BPF_Fs24000_Fc78_B2 1060124669 /* Floating point value 0.987318 */
-#define BPF_Fs32000_Fc78_A0 5055965 /* Floating point value 0.004709 */
-#define BPF_Fs32000_Fc78_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs32000_Fc78_A2 (-5055965) /* Floating point value -0.004709 */
-#define BPF_Fs32000_Fc78_B1 (-2137003977) /* Floating point value -1.990240 */
-#define BPF_Fs32000_Fc78_B2 1063512802 /* Floating point value 0.990473 */
-#define BPF_Fs44100_Fc78_A0 3673516 /* Floating point value 0.003421 */
-#define BPF_Fs44100_Fc78_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs44100_Fc78_A2 (-3673516) /* Floating point value -0.003421 */
-#define BPF_Fs44100_Fc78_B1 (-2139919394) /* Floating point value -1.992955 */
-#define BPF_Fs44100_Fc78_B2 1066309718 /* Floating point value 0.993078 */
-#define BPF_Fs48000_Fc78_A0 3375990 /* Floating point value 0.003144 */
-#define BPF_Fs48000_Fc78_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs48000_Fc78_A2 (-3375990) /* Floating point value -0.003144 */
-#define BPF_Fs48000_Fc78_B1 (-2140541906) /* Floating point value -1.993535 */
-#define BPF_Fs48000_Fc78_B2 1066911660 /* Floating point value 0.993639 */
-
- /* Coefficients for centre frequency 90Hz */
-#define BPF_Fs8000_Fc90_A0 24438548 /* Floating point value 0.022760 */
-#define BPF_Fs8000_Fc90_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs8000_Fc90_A2 (-24438548) /* Floating point value -0.022760 */
-#define BPF_Fs8000_Fc90_B1 (-2092801347) /* Floating point value -1.949073 */
-#define BPF_Fs8000_Fc90_B2 1024298757 /* Floating point value 0.953953 */
-#define BPF_Fs11025_Fc90_A0 17844385 /* Floating point value 0.016619 */
-#define BPF_Fs11025_Fc90_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs11025_Fc90_A2 (-17844385) /* Floating point value -0.016619 */
-#define BPF_Fs11025_Fc90_B1 (-2108604921) /* Floating point value -1.963791 */
-#define BPF_Fs11025_Fc90_B2 1037639797 /* Floating point value 0.966377 */
-#define BPF_Fs12000_Fc90_A0 16416707 /* Floating point value 0.015289 */
-#define BPF_Fs12000_Fc90_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs12000_Fc90_A2 (-16416707) /* Floating point value -0.015289 */
-#define BPF_Fs12000_Fc90_B1 (-2111922936) /* Floating point value -1.966882 */
-#define BPF_Fs12000_Fc90_B2 1040528216 /* Floating point value 0.969067 */
-#define BPF_Fs16000_Fc90_A0 12359883 /* Floating point value 0.011511 */
-#define BPF_Fs16000_Fc90_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs16000_Fc90_A2 (-12359883) /* Floating point value -0.011511 */
-#define BPF_Fs16000_Fc90_B1 (-2121152162) /* Floating point value -1.975477 */
-#define BPF_Fs16000_Fc90_B2 1048735817 /* Floating point value 0.976711 */
-#define BPF_Fs22050_Fc90_A0 8997173 /* Floating point value 0.008379 */
-#define BPF_Fs22050_Fc90_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs22050_Fc90_A2 (-8997173) /* Floating point value -0.008379 */
-#define BPF_Fs22050_Fc90_B1 (-2128580762) /* Floating point value -1.982395 */
-#define BPF_Fs22050_Fc90_B2 1055539113 /* Floating point value 0.983047 */
-#define BPF_Fs24000_Fc90_A0 8271818 /* Floating point value 0.007704 */
-#define BPF_Fs24000_Fc90_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs24000_Fc90_A2 (-8271818) /* Floating point value -0.007704 */
-#define BPF_Fs24000_Fc90_B1 (-2130157013) /* Floating point value -1.983863 */
-#define BPF_Fs24000_Fc90_B2 1057006621 /* Floating point value 0.984414 */
-#define BPF_Fs32000_Fc90_A0 6215918 /* Floating point value 0.005789 */
-#define BPF_Fs32000_Fc90_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs32000_Fc90_A2 (-6215918) /* Floating point value -0.005789 */
-#define BPF_Fs32000_Fc90_B1 (-2134574521) /* Floating point value -1.987977 */
-#define BPF_Fs32000_Fc90_B2 1061166033 /* Floating point value 0.988288 */
-#define BPF_Fs44100_Fc90_A0 4517651 /* Floating point value 0.004207 */
-#define BPF_Fs44100_Fc90_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs44100_Fc90_A2 (-4517651) /* Floating point value -0.004207 */
-#define BPF_Fs44100_Fc90_B1 (-2138167926) /* Floating point value -1.991324 */
-#define BPF_Fs44100_Fc90_B2 1064601898 /* Floating point value 0.991488 */
-#define BPF_Fs48000_Fc90_A0 4152024 /* Floating point value 0.003867 */
-#define BPF_Fs48000_Fc90_A1 0 /* Floating point value 0.000000 */
-#define BPF_Fs48000_Fc90_A2 (-4152024) /* Floating point value -0.003867 */
-#define BPF_Fs48000_Fc90_B1 (-2138935002) /* Floating point value -1.992038 */
-#define BPF_Fs48000_Fc90_B2 1065341620 /* Floating point value 0.992177 */
-
-
-/************************************************************************************/
-/* */
-/* Automatic Gain Control time constants and gain settings */
-/* */
-/************************************************************************************/
-
-/* AGC Time constants */
-#define AGC_ATTACK_Fs8000 27571 /* Floating point value 0.841395 */
-#define AGC_ATTACK_Fs11025 28909 /* Floating point value 0.882223 */
-#define AGC_ATTACK_Fs12000 29205 /* Floating point value 0.891251 */
-#define AGC_ATTACK_Fs16000 30057 /* Floating point value 0.917276 */
-#define AGC_ATTACK_Fs22050 30778 /* Floating point value 0.939267 */
-#define AGC_ATTACK_Fs24000 30935 /* Floating point value 0.944061 */
-#define AGC_ATTACK_Fs32000 31383 /* Floating point value 0.957745 */
-#define AGC_ATTACK_Fs44100 31757 /* Floating point value 0.969158 */
-#define AGC_ATTACK_Fs48000 31838 /* Floating point value 0.971628 */
-#define DECAY_SHIFT 10 /* As a power of 2 */
-#define AGC_DECAY_Fs8000 44 /* Floating point value 0.000042 */
-#define AGC_DECAY_Fs11025 32 /* Floating point value 0.000030 */
-#define AGC_DECAY_Fs12000 29 /* Floating point value 0.000028 */
-#define AGC_DECAY_Fs16000 22 /* Floating point value 0.000021 */
-#define AGC_DECAY_Fs22050 16 /* Floating point value 0.000015 */
-#define AGC_DECAY_Fs24000 15 /* Floating point value 0.000014 */
-#define AGC_DECAY_Fs32000 11 /* Floating point value 0.000010 */
-#define AGC_DECAY_Fs44100 8 /* Floating point value 0.000008 */
-#define AGC_DECAY_Fs48000 7 /* Floating point value 0.000007 */
-
-/* AGC Gain settings */
-#define AGC_GAIN_SCALE 31 /* As a power of 2 */
-#define AGC_GAIN_SHIFT 4 /* As a power of 2 */
-#define AGC_TARGETLEVEL 33170337 /* Floating point value -0.100000dB */
-#define AGC_HPFGAIN_0dB 110739704 /* Floating point value 0.412538 */
-#define AGC_GAIN_0dB 0 /* Floating point value 0.000000 */
-#define AGC_HPFGAIN_1dB 157006071 /* Floating point value 0.584893 */
-#define AGC_GAIN_1dB 32754079 /* Floating point value 0.122018 */
-#define AGC_HPFGAIN_2dB 208917788 /* Floating point value 0.778279 */
-#define AGC_GAIN_2dB 69504761 /* Floating point value 0.258925 */
-#define AGC_HPFGAIN_3dB 267163693 /* Floating point value 0.995262 */
-#define AGC_GAIN_3dB 110739704 /* Floating point value 0.412538 */
-#define AGC_HPFGAIN_4dB 332516674 /* Floating point value 1.238721 */
-#define AGC_GAIN_4dB 157006071 /* Floating point value 0.584893 */
-#define AGC_HPFGAIN_5dB 405843924 /* Floating point value 1.511886 */
-#define AGC_GAIN_5dB 208917788 /* Floating point value 0.778279 */
-#define AGC_HPFGAIN_6dB 488118451 /* Floating point value 1.818383 */
-#define AGC_GAIN_6dB 267163693 /* Floating point value 0.995262 */
-#define AGC_HPFGAIN_7dB 580431990 /* Floating point value 2.162278 */
-#define AGC_GAIN_7dB 332516674 /* Floating point value 1.238721 */
-#define AGC_HPFGAIN_8dB 684009483 /* Floating point value 2.548134 */
-#define AGC_GAIN_8dB 405843924 /* Floating point value 1.511886 */
-#define AGC_HPFGAIN_9dB 800225343 /* Floating point value 2.981072 */
-#define AGC_GAIN_9dB 488118451 /* Floating point value 1.818383 */
-#define AGC_HPFGAIN_10dB 930621681 /* Floating point value 3.466836 */
-#define AGC_GAIN_10dB 580431990 /* Floating point value 2.162278 */
-#define AGC_HPFGAIN_11dB 1076928780 /* Floating point value 4.011872 */
-#define AGC_GAIN_11dB 684009483 /* Floating point value 2.548134 */
-#define AGC_HPFGAIN_12dB 1241088045 /* Floating point value 4.623413 */
-#define AGC_GAIN_12dB 800225343 /* Floating point value 2.981072 */
-#define AGC_HPFGAIN_13dB 1425277769 /* Floating point value 5.309573 */
-#define AGC_GAIN_13dB 930621681 /* Floating point value 3.466836 */
-#define AGC_HPFGAIN_14dB 1631942039 /* Floating point value 6.079458 */
-#define AGC_GAIN_14dB 1076928780 /* Floating point value 4.011872 */
-#define AGC_HPFGAIN_15dB 1863823163 /* Floating point value 6.943282 */
-#define AGC_GAIN_15dB 1241088045 /* Floating point value 4.623413 */
-
-
-/************************************************************************************/
-/* */
-/* Volume control */
-/* */
-/************************************************************************************/
-
-/* Volume control gain */
-#define VOLUME_MAX 0 /* In dBs */
-#define VOLUME_SHIFT 0 /* In dBs */
-
-/* Volume control time constants */
-#define VOL_TC_SHIFT 21 /* As a power of 2 */
-#define VOL_TC_Fs8000 25889 /* Floating point value 0.024690 */
-#define VOL_TC_Fs11025 18850 /* Floating point value 0.017977 */
-#define VOL_TC_Fs12000 17331 /* Floating point value 0.016529 */
-#define VOL_TC_Fs16000 13026 /* Floating point value 0.012422 */
-#define VOL_TC_Fs22050 9468 /* Floating point value 0.009029 */
-#define VOL_TC_Fs24000 8702 /* Floating point value 0.008299 */
-#define VOL_TC_Fs32000 6533 /* Floating point value 0.006231 */
-#define VOL_TC_Fs44100 4745 /* Floating point value 0.004525 */
-#define VOL_TC_Fs48000 4360 /* Floating point value 0.004158 */
-#define MIX_TC_Fs8000 29365 /* Floating point value 0.896151 */
-#define MIX_TC_Fs11025 30230 /* Floating point value 0.922548 */
-#define MIX_TC_Fs12000 30422 /* Floating point value 0.928415 */
-#define MIX_TC_Fs16000 30978 /* Floating point value 0.945387 */
-#define MIX_TC_Fs22050 31451 /* Floating point value 0.959804 */
-#define MIX_TC_Fs24000 31554 /* Floating point value 0.962956 */
-#define MIX_TC_Fs32000 31850 /* Floating point value 0.971973 */
-#define MIX_TC_Fs44100 32097 /* Floating point value 0.979515 */
-#define MIX_TC_Fs48000 32150 /* Floating point value 0.981150 */
-
-#else /*BUILD_FLOAT*/
-
-/************************************************************************************/
-/* */
-/* General */
-/* */
-/************************************************************************************/
-
-#define LVDBE_SCALESHIFT 10 /* As a power of 2 */
-
-
/************************************************************************************/
/* */
/* High Pass Filter coefficients */
@@ -579,7 +79,6 @@
#define HPF_Fs48000_Fc55_B1 (-1.989831f)
#define HPF_Fs48000_Fc55_B2 0.989882f
-#ifdef HIGHER_FS
#define HPF_Fs88200_Fc55_A0 0.985818f
#define HPF_Fs88200_Fc55_A1 (-1.971636f)
#define HPF_Fs88200_Fc55_A2 0.985818f
@@ -603,8 +102,6 @@
#define HPF_Fs192000_Fc55_A2 0.987294f
#define HPF_Fs192000_Fc55_B1 (-1.997458f)
#define HPF_Fs192000_Fc55_B2 0.997461f
-#endif
-
/* Coefficients for centre frequency 66Hz */
#define HPF_Fs8000_Fc66_A0 0.953016f
@@ -653,7 +150,6 @@
#define HPF_Fs48000_Fc66_B1 (-1.987797f)
#define HPF_Fs48000_Fc66_B2 0.987871f
-#ifdef HIGHER_FS
#define HPF_Fs88200_Fc66_A0 0.985273f
#define HPF_Fs88200_Fc66_A1 (-1.970546f)
#define HPF_Fs88200_Fc66_A2 0.985273f
@@ -677,7 +173,6 @@
#define HPF_Fs192000_Fc66_A2 0.987043f
#define HPF_Fs192000_Fc66_B1 (-1.996949f)
#define HPF_Fs192000_Fc66_B2 0.996954f
-#endif
/* Coefficients for centre frequency 78Hz */
#define HPF_Fs8000_Fc78_A0 0.946693f
@@ -726,7 +221,6 @@
#define HPF_Fs48000_Fc78_B1 (-1.985578f)
#define HPF_Fs48000_Fc78_B2 0.985681f
-#ifdef HIGHER_FS
#define HPF_Fs88200_Fc78_A0 0.984678f
#define HPF_Fs88200_Fc78_A1 (-1.969356f)
#define HPF_Fs88200_Fc78_A2 0.984678f
@@ -750,7 +244,6 @@
#define HPF_Fs192000_Fc78_A2 0.986769f
#define HPF_Fs192000_Fc78_B1 (-1.996394f)
#define HPF_Fs192000_Fc78_B2 0.996401f
-#endif
/* Coefficients for centre frequency 90Hz */
#define HPF_Fs8000_Fc90_A0 0.940412f
@@ -799,7 +292,6 @@
#define HPF_Fs48000_Fc90_B1 (-1.983359f)
#define HPF_Fs48000_Fc90_B2 0.983497f
-#ifdef HIGHER_FS
#define HPF_Fs88200_Fc90_A0 0.984084f
#define HPF_Fs88200_Fc90_A1 (-1.968168f)
#define HPF_Fs88200_Fc90_A2 0.984084f
@@ -823,7 +315,6 @@
#define HPF_Fs192000_Fc90_A2 0.986496f
#define HPF_Fs192000_Fc90_B1 (-1.995840f)
#define HPF_Fs192000_Fc90_B2 0.995848f
-#endif
/************************************************************************************/
/* */
@@ -878,7 +369,6 @@
#define BPF_Fs48000_Fc55_B1 (-1.996823f)
#define BPF_Fs48000_Fc55_B2 0.996875f
-#ifdef HIGHER_FS
#define BPF_Fs88200_Fc55_A0 0.000831f
#define BPF_Fs88200_Fc55_A1 0.000000f
#define BPF_Fs88200_Fc55_A2 (-0.000831f)
@@ -902,7 +392,6 @@
#define BPF_Fs192000_Fc55_A2 (-0.000381f)
#define BPF_Fs192000_Fc55_B1 (-1.999234f)
#define BPF_Fs192000_Fc55_B2 0.999238f
-#endif
/* Coefficients for centre frequency 66Hz */
#define BPF_Fs8000_Fc66_A0 0.012648f
@@ -951,7 +440,6 @@
#define BPF_Fs48000_Fc66_B1 (-1.995615f)
#define BPF_Fs48000_Fc66_B2 0.995690f
-#ifdef HIGHER_FS
#define BPF_Fs88200_Fc66_A0 0.001146f
#define BPF_Fs88200_Fc66_A1 0.000000f
#define BPF_Fs88200_Fc66_A2 (-0.001146f)
@@ -975,7 +463,6 @@
#define BPF_Fs192000_Fc66_A2 (-0.000528f)
#define BPF_Fs192000_Fc66_B1 (-1.998939f)
#define BPF_Fs192000_Fc66_B2 0.998945f
-#endif
/* Coefficients for centre frequency 78Hz */
#define BPF_Fs8000_Fc78_A0 0.018572f
@@ -1024,7 +511,6 @@
#define BPF_Fs48000_Fc78_B1 (-1.993535f)
#define BPF_Fs48000_Fc78_B2 0.993639f
-#ifdef HIGHER_FS
#define BPF_Fs88200_Fc78_A0 0.001693f
#define BPF_Fs88200_Fc78_A1 0.000000f
#define BPF_Fs88200_Fc78_A2 (-0.001693f)
@@ -1048,7 +534,6 @@
#define BPF_Fs192000_Fc78_A2 (-0.000778f)
#define BPF_Fs192000_Fc78_B1 (-1.998437f)
#define BPF_Fs192000_Fc78_B2 0.998444f
-#endif
/* Coefficients for centre frequency 90Hz */
#define BPF_Fs8000_Fc90_A0 0.022760f
@@ -1097,7 +582,6 @@
#define BPF_Fs48000_Fc90_B1 (-1.992038f)
#define BPF_Fs48000_Fc90_B2 0.992177f
-#ifdef HIGHER_FS
#define BPF_Fs88200_Fc90_A0 0.002083f
#define BPF_Fs88200_Fc90_A1 0.000000f
#define BPF_Fs88200_Fc90_A2 (-0.002083f)
@@ -1121,7 +605,6 @@
#define BPF_Fs192000_Fc90_A2 (-0.000958f)
#define BPF_Fs192000_Fc90_B1 (-1.998075f)
#define BPF_Fs192000_Fc90_B2 0.998085f
-#endif
/************************************************************************************/
/* */
@@ -1140,12 +623,10 @@
#define AGC_ATTACK_Fs44100 0.969158f
#define AGC_ATTACK_Fs48000 0.971628f
-#ifdef HIGHER_FS
#define AGC_ATTACK_Fs88200 0.984458f
#define AGC_ATTACK_Fs96000 0.985712f
#define AGC_ATTACK_Fs176400 0.992199f
#define AGC_ATTACK_Fs192000 0.992830f
-#endif
#define DECAY_SHIFT 10
@@ -1159,12 +640,10 @@
#define AGC_DECAY_Fs44100 0.000008f
#define AGC_DECAY_Fs48000 0.000007f
-#ifdef HIGHER_FS
#define AGC_DECAY_Fs88200 0.0000038f
#define AGC_DECAY_FS96000 0.0000035f
#define AGC_DECAY_Fs176400 0.00000188f
#define AGC_DECAY_FS192000 0.00000175f
-#endif
/* AGC Gain settings */
#define AGC_GAIN_SCALE 31 /* As a power of 2 */
@@ -1224,12 +703,10 @@
#define VOL_TC_Fs32000 0.006231f
#define VOL_TC_Fs44100 0.004525f
#define VOL_TC_Fs48000 0.004158f
-#ifdef HIGHER_FS
#define VOL_TC_Fs88200 0.002263f
#define VOL_TC_Fs96000 0.002079f
#define VOL_TC_Fs176400 0.001131f
#define VOL_TC_Fs192000 0.001039f
-#endif
#define MIX_TC_Fs8000 29365 /* Floating point value 0.896151 */
#define MIX_TC_Fs11025 30230 /* Floating point value 0.922548 */
#define MIX_TC_Fs12000 30422 /* Floating point value 0.928415 */
@@ -1239,14 +716,11 @@
#define MIX_TC_Fs32000 31850 /* Floating point value 0.971973 */
#define MIX_TC_Fs44100 32097 /* Floating point value 0.979515 */
#define MIX_TC_Fs48000 32150 /* Floating point value 0.981150 */
-#ifdef HIGHER_FS
/* Floating point value 0.989704 */
#define MIX_TC_Fs88200 32430
#define MIX_TC_Fs96000 32456 /* Floating point value 0.990530 */
/* Floating point value 0.994838 */
#define MIX_TC_Fs176400 32598
#define MIX_TC_Fs192000 32611 /* Floating point value 0.992524 */
-#endif
-#endif /*BUILD_FLOAT*/
#endif
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Control.c b/media/libeffects/lvm/lib/Bass/src/LVDBE_Control.c
deleted file mode 100644
index 0ba2c86..0000000
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Control.c
+++ /dev/null
@@ -1,460 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/****************************************************************************************/
-/* */
-/* Includes */
-/* */
-/****************************************************************************************/
-
-#include "LVDBE.h"
-#include "LVDBE_Private.h"
-#include "VectorArithmetic.h"
-#include "LVDBE_Coeffs.h"
-#include "LVDBE_Tables.h"
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVDBE_GetParameters */
-/* */
-/* DESCRIPTION: */
-/* Request the Dynamic Bass Enhancement parameters. The current parameter set is */
-/* returned via the parameter pointer. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance handle */
-/* pParams Pointer to an empty parameter structure */
-/* */
-/* RETURNS: */
-/* LVDBE_SUCCESS Always succeeds */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVDBE_Process function */
-/* */
-/****************************************************************************************/
-
-LVDBE_ReturnStatus_en LVDBE_GetParameters(LVDBE_Handle_t hInstance,
- LVDBE_Params_t *pParams)
-{
-
- LVDBE_Instance_t *pInstance =(LVDBE_Instance_t *)hInstance;
-
- *pParams = pInstance->Params;
-
- return(LVDBE_SUCCESS);
-}
-
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVDBE_GetCapabilities */
-/* */
-/* DESCRIPTION: Dynamic Bass Enhnacement capabilities. The current capabilities are */
-/* returned via the pointer. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance handle */
-/* pCapabilities Pointer to an empty capability structure */
-/* */
-/* RETURNS: */
-/* LVDBE_Success Always succeeds */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVDBE_Process function */
-/* */
-/************************************************************************************/
-
-LVDBE_ReturnStatus_en LVDBE_GetCapabilities(LVDBE_Handle_t hInstance,
- LVDBE_Capabilities_t *pCapabilities)
-{
-
- LVDBE_Instance_t *pInstance =(LVDBE_Instance_t *)hInstance;
-
- *pCapabilities = pInstance->Capabilities;
-
- return(LVDBE_SUCCESS);
-}
-
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVDBE_SetFilters */
-/* */
-/* DESCRIPTION: */
-/* Sets the filter coefficients and clears the data history */
-/* */
-/* PARAMETERS: */
-/* pInstance Pointer to the instance */
-/* pParams Initialisation parameters */
-/* */
-/************************************************************************************/
-
-void LVDBE_SetFilters(LVDBE_Instance_t *pInstance,
- LVDBE_Params_t *pParams)
-{
-
-#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
- /*
- * Calculate the table offsets
- */
- LVM_UINT16 Offset = (LVM_UINT16)((LVM_UINT16)pParams->SampleRate + \
- (LVM_UINT16)(pParams->CentreFrequency * (1+LVDBE_FS_192000)));
-#else
- /*
- * Calculate the table offsets
- */
- LVM_UINT16 Offset = (LVM_UINT16)((LVM_UINT16)pParams->SampleRate + \
- (LVM_UINT16)(pParams->CentreFrequency * (1+LVDBE_FS_48000)));
-#endif
-
- /*
- * Setup the high pass filter
- */
-#ifndef BUILD_FLOAT
- LoadConst_16(0, /* Clear the history, value 0 */
- (void *)&pInstance->pData->HPFTaps, /* Destination Cast to void: \
- no dereferencing in function*/
- sizeof(pInstance->pData->HPFTaps)/sizeof(LVM_INT16)); /* Number of words */
-#else
- LoadConst_Float(0, /* Clear the history, value 0 */
- (void *)&pInstance->pData->HPFTaps, /* Destination Cast to void: \
- no dereferencing in function*/
- sizeof(pInstance->pData->HPFTaps) / sizeof(LVM_FLOAT)); /* Number of words */
-#endif
-#ifndef BUILD_FLOAT
- BQ_2I_D32F32Cll_TRC_WRA_01_Init(&pInstance->pCoef->HPFInstance, /* Initialise the filter */
- &pInstance->pData->HPFTaps,
- (BQ_C32_Coefs_t *)&LVDBE_HPF_Table[Offset]);
-#else
- BQ_2I_D32F32Cll_TRC_WRA_01_Init(&pInstance->pCoef->HPFInstance, /* Initialise the filter */
- &pInstance->pData->HPFTaps,
- (BQ_FLOAT_Coefs_t *)&LVDBE_HPF_Table[Offset]);
-#endif
-
-
- /*
- * Setup the band pass filter
- */
-#ifndef BUILD_FLOAT
- LoadConst_16(0, /* Clear the history, value 0 */
- (void *)&pInstance->pData->BPFTaps, /* Destination Cast to void: \
- no dereferencing in function*/
- sizeof(pInstance->pData->BPFTaps)/sizeof(LVM_INT16)); /* Number of words */
-#else
- LoadConst_Float(0, /* Clear the history, value 0 */
- (void *)&pInstance->pData->BPFTaps, /* Destination Cast to void: \
- no dereferencing in function*/
- sizeof(pInstance->pData->BPFTaps) / sizeof(LVM_FLOAT)); /* Number of words */
-#endif
-#ifndef BUILD_FLOAT
- BP_1I_D32F32Cll_TRC_WRA_02_Init(&pInstance->pCoef->BPFInstance, /* Initialise the filter */
- &pInstance->pData->BPFTaps,
- (BP_C32_Coefs_t *)&LVDBE_BPF_Table[Offset]);
-#else
- BP_1I_D32F32Cll_TRC_WRA_02_Init(&pInstance->pCoef->BPFInstance, /* Initialise the filter */
- &pInstance->pData->BPFTaps,
- (BP_FLOAT_Coefs_t *)&LVDBE_BPF_Table[Offset]);
-#endif
-}
-
-
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVDBE_SetAGC */
-/* */
-/* DESCRIPTION: */
-/* Sets the AGC gain level and attack and decay times constants. */
-/* */
-/* PARAMETERS: */
-/* pInstance Pointer to the instance */
-/* pParams Initialisation parameters */
-/* */
-/************************************************************************************/
-
-void LVDBE_SetAGC(LVDBE_Instance_t *pInstance,
- LVDBE_Params_t *pParams)
-{
-
- /*
- * Get the attack and decay time constants
- */
- pInstance->pData->AGCInstance.AGC_Attack = LVDBE_AGC_ATTACK_Table[(LVM_UINT16)pParams->SampleRate]; /* Attack multiplier */
- pInstance->pData->AGCInstance.AGC_Decay = LVDBE_AGC_DECAY_Table[(LVM_UINT16)pParams->SampleRate]; /* Decay multipler */
-
-
- /*
- * Get the boost gain
- */
- if (pParams->HPFSelect == LVDBE_HPF_ON)
- {
- pInstance->pData->AGCInstance.AGC_MaxGain = LVDBE_AGC_HPFGAIN_Table[(LVM_UINT16)pParams->EffectLevel]; /* High pass filter on */
- }
- else
- {
- pInstance->pData->AGCInstance.AGC_MaxGain = LVDBE_AGC_GAIN_Table[(LVM_UINT16)pParams->EffectLevel]; /* High pass filter off */
- }
-#ifndef BUILD_FLOAT
- pInstance->pData->AGCInstance.AGC_GainShift = AGC_GAIN_SHIFT;
-#endif
- pInstance->pData->AGCInstance.AGC_Target = AGC_TARGETLEVEL;
-
-}
-
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVDBE_SetVolume */
-/* */
-/* DESCRIPTION: */
-/* Converts the input volume demand from dBs to linear. */
-/* */
-/* PARAMETERS: */
-/* pInstance Pointer to the instance */
-/* pParams Initialisation parameters */
-/* */
-/* NOTES: */
-/* 1. The volume should have the following settings: */
-/* */
-/* DBE Vol Control Volume setting */
-/* === =========== =================== */
-/* Off Off HeadroomdB */
-/* Off On VolumedB+HeadroomdB */
-/* On Off HeadroomdB */
-/* On On VolumedB+HeadroomdB */
-/* */
-/************************************************************************************/
-
-void LVDBE_SetVolume(LVDBE_Instance_t *pInstance,
- LVDBE_Params_t *pParams)
-{
-
- LVM_UINT16 dBShifts; /* 6dB shifts */
- LVM_UINT16 dBOffset; /* Table offset */
- LVM_INT16 Volume = 0; /* Required volume in dBs */
-
-#ifdef BUILD_FLOAT
- LVM_FLOAT dBShifts_fac;
-#endif
- /*
- * Apply the volume if enabled
- */
- if (pParams->VolumeControl == LVDBE_VOLUME_ON)
- {
- /*
- * Limit the gain to the maximum allowed
- */
- if (pParams->VolumedB > VOLUME_MAX)
- {
- Volume = VOLUME_MAX;
- }
- else
- {
- Volume = pParams->VolumedB;
- }
- }
-
-
- /*
- * Calculate the required gain and shifts
- */
- dBOffset = (LVM_UINT16)(6 + Volume % 6); /* Get the dBs 0-5 */
- dBShifts = (LVM_UINT16)(Volume / -6); /* Get the 6dB shifts */
-
-#ifdef BUILD_FLOAT
- dBShifts_fac = (LVM_FLOAT)(1 << dBShifts);
-#endif
- /*
- * When DBE is enabled use AGC volume
- */
-#ifndef BUILD_FLOAT
- pInstance->pData->AGCInstance.Target = ((LVM_INT32)LVDBE_VolumeTable[dBOffset] << 16);
- pInstance->pData->AGCInstance.Target = pInstance->pData->AGCInstance.Target >> dBShifts;
-#else
- pInstance->pData->AGCInstance.Target = (LVDBE_VolumeTable[dBOffset]);
- pInstance->pData->AGCInstance.Target = pInstance->pData->AGCInstance.Target / dBShifts_fac;
-#endif
- pInstance->pData->AGCInstance.VolumeTC = LVDBE_VolumeTCTable[(LVM_UINT16)pParams->SampleRate]; /* Volume update time constant */
-#ifndef BUILD_FLOAT
- pInstance->pData->AGCInstance.VolumeShift = VOLUME_SHIFT+1;
-#endif
-
- /*
- * When DBE is disabled use the bypass volume control
- */
- if(dBShifts > 0)
- {
-#ifndef BUILD_FLOAT
- LVC_Mixer_SetTarget(&pInstance->pData->BypassVolume.MixerStream[0],(((LVM_INT32)LVDBE_VolumeTable[dBOffset]) >> dBShifts));
-#else
- LVC_Mixer_SetTarget(&pInstance->pData->BypassVolume.MixerStream[0],
- LVDBE_VolumeTable[dBOffset] / dBShifts_fac);
-#endif
- }
- else
- {
-#ifndef BUILD_FLOAT
- LVC_Mixer_SetTarget(&pInstance->pData->BypassVolume.MixerStream[0],(LVM_INT32)LVDBE_VolumeTable[dBOffset]);
-#else
- LVC_Mixer_SetTarget(&pInstance->pData->BypassVolume.MixerStream[0],
- LVDBE_VolumeTable[dBOffset]);
-#endif
- }
-
- pInstance->pData->BypassVolume.MixerStream[0].CallbackSet = 1;
-#ifndef BUILD_FLOAT
- LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->pData->BypassVolume.MixerStream[0],
- LVDBE_MIXER_TC,
- (LVM_Fs_en)pInstance->Params.SampleRate,
- 2);
-#else
- LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->pData->BypassVolume.MixerStream[0],
- LVDBE_MIXER_TC,
- (LVM_Fs_en)pInstance->Params.SampleRate,
- 2);
-#endif
-}
-
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVDBE_Control */
-/* */
-/* DESCRIPTION: */
-/* Sets or changes the Bass Enhancement parameters. Changing the parameters while the */
-/* module is processing signals may have the following side effects: */
-/* */
-/* General parameters: */
-/* =================== */
-/* OperatingMode: Changing the mode of operation may cause a change in volume */
-/* level or cause pops and clicks. */
-/* */
-/* SampleRate: Changing the sample rate may cause pops and clicks. */
-/* */
-/* EffectLevel: Changing the effect level may cause pops and clicks */
-/* */
-/* CentreFrequency: Changing the centre frequency may cause pops and clicks */
-/* */
-/* HPFSelect: Selecting/de-selecting the high pass filter may cause pops and */
-/* clicks */
-/* */
-/* VolumedB Changing the volume setting will have no side effects */
-/* */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance handle */
-/* pParams Pointer to a parameter structure */
-/* */
-/* RETURNS: */
-/* LVDBE_SUCCESS Always succeeds */
-/* */
-/* NOTES: */
-/* 1. This function must not be interrupted by the LVDBE_Process function */
-/* */
-/****************************************************************************************/
-
-LVDBE_ReturnStatus_en LVDBE_Control(LVDBE_Handle_t hInstance,
- LVDBE_Params_t *pParams)
-{
-
- LVDBE_Instance_t *pInstance =(LVDBE_Instance_t *)hInstance;
-#ifndef BUILD_FLOAT
- LVMixer3_2St_st *pBypassMixer_Instance = &pInstance->pData->BypassMixer;
-#else
- LVMixer3_2St_FLOAT_st *pBypassMixer_Instance = &pInstance->pData->BypassMixer;
-#endif
-
-
- /*
- * Update the filters
- */
- if ((pInstance->Params.SampleRate != pParams->SampleRate) ||
- (pInstance->Params.CentreFrequency != pParams->CentreFrequency))
- {
- LVDBE_SetFilters(pInstance, /* Instance pointer */
- pParams); /* New parameters */
- }
-
-
- /*
- * Update the AGC is the effect level has changed
- */
- if ((pInstance->Params.SampleRate != pParams->SampleRate) ||
- (pInstance->Params.EffectLevel != pParams->EffectLevel) ||
- (pInstance->Params.HPFSelect != pParams->HPFSelect))
- {
- LVDBE_SetAGC(pInstance, /* Instance pointer */
- pParams); /* New parameters */
-#ifndef BUILD_FLOAT
- LVC_Mixer_SetTimeConstant(&pBypassMixer_Instance->MixerStream[0],
- LVDBE_BYPASS_MIXER_TC,(LVM_Fs_en)pParams->SampleRate,2);
-
- LVC_Mixer_SetTimeConstant(&pBypassMixer_Instance->MixerStream[1],
- LVDBE_BYPASS_MIXER_TC,(LVM_Fs_en)pParams->SampleRate,2);
-#else
- LVC_Mixer_SetTimeConstant(&pBypassMixer_Instance->MixerStream[0],
- LVDBE_BYPASS_MIXER_TC,(LVM_Fs_en)pParams->SampleRate, 2);
-
- LVC_Mixer_SetTimeConstant(&pBypassMixer_Instance->MixerStream[1],
- LVDBE_BYPASS_MIXER_TC,(LVM_Fs_en)pParams->SampleRate, 2);
-#endif
-
-
- }
-
-
- /*
- * Update the Volume if the volume demand has changed
- */
- if ((pInstance->Params.VolumedB != pParams->VolumedB) ||
- (pInstance->Params.SampleRate != pParams->SampleRate) ||
- (pInstance->Params.HeadroomdB != pParams->HeadroomdB) ||
- (pInstance->Params.VolumeControl != pParams->VolumeControl))
- {
- LVDBE_SetVolume(pInstance, /* Instance pointer */
- pParams); /* New parameters */
- }
-
- if (pInstance->Params.OperatingMode==LVDBE_ON && pParams->OperatingMode==LVDBE_OFF)
- {
-#ifndef BUILD_FLOAT
- LVC_Mixer_SetTarget(&pInstance->pData->BypassMixer.MixerStream[0],0);
- LVC_Mixer_SetTarget(&pInstance->pData->BypassMixer.MixerStream[1],0x00007FFF);
-#else
- LVC_Mixer_SetTarget(&pInstance->pData->BypassMixer.MixerStream[0], 0);
- LVC_Mixer_SetTarget(&pInstance->pData->BypassMixer.MixerStream[1], 1.0f);
-#endif
- }
- if (pInstance->Params.OperatingMode==LVDBE_OFF && pParams->OperatingMode==LVDBE_ON)
- {
-#ifndef BUILD_FLOAT
- LVC_Mixer_SetTarget(&pInstance->pData->BypassMixer.MixerStream[0],0x00007FFF);
- LVC_Mixer_SetTarget(&pInstance->pData->BypassMixer.MixerStream[1],0);
-#else
- LVC_Mixer_SetTarget(&pInstance->pData->BypassMixer.MixerStream[0], 1.0f);
- LVC_Mixer_SetTarget(&pInstance->pData->BypassMixer.MixerStream[1], 0);
-#endif
- }
-
- /*
- * Update the instance parameters
- */
- pInstance->Params = *pParams;
-
-
- return(LVDBE_SUCCESS);
-}
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Control.cpp b/media/libeffects/lvm/lib/Bass/src/LVDBE_Control.cpp
new file mode 100644
index 0000000..53feae8
--- /dev/null
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Control.cpp
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/****************************************************************************************/
+/* */
+/* Includes */
+/* */
+/****************************************************************************************/
+
+#include "LVDBE.h"
+#include "LVDBE_Private.h"
+#include "VectorArithmetic.h"
+#include "LVDBE_Coeffs.h"
+#include "LVDBE_Tables.h"
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVDBE_GetParameters */
+/* */
+/* DESCRIPTION: */
+/* Request the Dynamic Bass Enhancement parameters. The current parameter set is */
+/* returned via the parameter pointer. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance handle */
+/* pParams Pointer to an empty parameter structure */
+/* */
+/* RETURNS: */
+/* LVDBE_SUCCESS Always succeeds */
+/* */
+/* NOTES: */
+/* 1. This function may be interrupted by the LVDBE_Process function */
+/* */
+/****************************************************************************************/
+
+LVDBE_ReturnStatus_en LVDBE_GetParameters(LVDBE_Handle_t hInstance,
+ LVDBE_Params_t *pParams)
+{
+
+ LVDBE_Instance_t *pInstance =(LVDBE_Instance_t *)hInstance;
+
+ *pParams = pInstance->Params;
+
+ return(LVDBE_SUCCESS);
+}
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVDBE_GetCapabilities */
+/* */
+/* DESCRIPTION: Dynamic Bass Enhnacement capabilities. The current capabilities are */
+/* returned via the pointer. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance handle */
+/* pCapabilities Pointer to an empty capability structure */
+/* */
+/* RETURNS: */
+/* LVDBE_Success Always succeeds */
+/* */
+/* NOTES: */
+/* 1. This function may be interrupted by the LVDBE_Process function */
+/* */
+/************************************************************************************/
+
+LVDBE_ReturnStatus_en LVDBE_GetCapabilities(LVDBE_Handle_t hInstance,
+ LVDBE_Capabilities_t *pCapabilities)
+{
+
+ LVDBE_Instance_t *pInstance =(LVDBE_Instance_t *)hInstance;
+
+ *pCapabilities = pInstance->Capabilities;
+
+ return(LVDBE_SUCCESS);
+}
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVDBE_SetFilters */
+/* */
+/* DESCRIPTION: */
+/* Sets the filter coefficients and clears the data history */
+/* */
+/* PARAMETERS: */
+/* pInstance Pointer to the instance */
+/* pParams Initialisation parameters */
+/* */
+/************************************************************************************/
+
+void LVDBE_SetFilters(LVDBE_Instance_t *pInstance,
+ LVDBE_Params_t *pParams)
+{
+
+ /*
+ * Calculate the table offsets
+ */
+ LVM_UINT16 Offset = (LVM_UINT16)((LVM_UINT16)pParams->SampleRate + \
+ (LVM_UINT16)(pParams->CentreFrequency * (1+LVDBE_FS_192000)));
+
+ /*
+ * Setup the high pass filter
+ */
+ LoadConst_Float(0, /* Clear the history, value 0 */
+ (LVM_FLOAT *)&pInstance->pData->HPFTaps, /* Destination */
+ sizeof(pInstance->pData->HPFTaps) / sizeof(LVM_FLOAT)); /* Number of words */
+ BQ_2I_D32F32Cll_TRC_WRA_01_Init(&pInstance->pCoef->HPFInstance, /* Initialise the filter */
+ &pInstance->pData->HPFTaps,
+ (BQ_FLOAT_Coefs_t *)&LVDBE_HPF_Table[Offset]);
+
+ /*
+ * Setup the band pass filter
+ */
+ LoadConst_Float(0, /* Clear the history, value 0 */
+ (LVM_FLOAT *)&pInstance->pData->BPFTaps, /* Destination */
+ sizeof(pInstance->pData->BPFTaps) / sizeof(LVM_FLOAT)); /* Number of words */
+ BP_1I_D32F32Cll_TRC_WRA_02_Init(&pInstance->pCoef->BPFInstance, /* Initialise the filter */
+ &pInstance->pData->BPFTaps,
+ (BP_FLOAT_Coefs_t *)&LVDBE_BPF_Table[Offset]);
+}
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVDBE_SetAGC */
+/* */
+/* DESCRIPTION: */
+/* Sets the AGC gain level and attack and decay times constants. */
+/* */
+/* PARAMETERS: */
+/* pInstance Pointer to the instance */
+/* pParams Initialisation parameters */
+/* */
+/************************************************************************************/
+
+void LVDBE_SetAGC(LVDBE_Instance_t *pInstance,
+ LVDBE_Params_t *pParams)
+{
+
+ /*
+ * Get the attack and decay time constants
+ */
+ pInstance->pData->AGCInstance.AGC_Attack = LVDBE_AGC_ATTACK_Table[(LVM_UINT16)pParams->SampleRate]; /* Attack multiplier */
+ pInstance->pData->AGCInstance.AGC_Decay = LVDBE_AGC_DECAY_Table[(LVM_UINT16)pParams->SampleRate]; /* Decay multipler */
+
+ /*
+ * Get the boost gain
+ */
+ if (pParams->HPFSelect == LVDBE_HPF_ON)
+ {
+ pInstance->pData->AGCInstance.AGC_MaxGain = LVDBE_AGC_HPFGAIN_Table[(LVM_UINT16)pParams->EffectLevel]; /* High pass filter on */
+ }
+ else
+ {
+ pInstance->pData->AGCInstance.AGC_MaxGain = LVDBE_AGC_GAIN_Table[(LVM_UINT16)pParams->EffectLevel]; /* High pass filter off */
+ }
+ pInstance->pData->AGCInstance.AGC_Target = AGC_TARGETLEVEL;
+
+}
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVDBE_SetVolume */
+/* */
+/* DESCRIPTION: */
+/* Converts the input volume demand from dBs to linear. */
+/* */
+/* PARAMETERS: */
+/* pInstance Pointer to the instance */
+/* pParams Initialisation parameters */
+/* */
+/* NOTES: */
+/* 1. The volume should have the following settings: */
+/* */
+/* DBE Vol Control Volume setting */
+/* === =========== =================== */
+/* Off Off HeadroomdB */
+/* Off On VolumedB+HeadroomdB */
+/* On Off HeadroomdB */
+/* On On VolumedB+HeadroomdB */
+/* */
+/************************************************************************************/
+
+void LVDBE_SetVolume(LVDBE_Instance_t *pInstance,
+ LVDBE_Params_t *pParams)
+{
+
+ LVM_UINT16 dBShifts; /* 6dB shifts */
+ LVM_UINT16 dBOffset; /* Table offset */
+ LVM_INT16 Volume = 0; /* Required volume in dBs */
+
+ LVM_FLOAT dBShifts_fac;
+ /*
+ * Apply the volume if enabled
+ */
+ if (pParams->VolumeControl == LVDBE_VOLUME_ON)
+ {
+ /*
+ * Limit the gain to the maximum allowed
+ */
+ if (pParams->VolumedB > VOLUME_MAX)
+ {
+ Volume = VOLUME_MAX;
+ }
+ else
+ {
+ Volume = pParams->VolumedB;
+ }
+ }
+
+ /*
+ * Calculate the required gain and shifts
+ */
+ dBOffset = (LVM_UINT16)(6 + Volume % 6); /* Get the dBs 0-5 */
+ dBShifts = (LVM_UINT16)(Volume / -6); /* Get the 6dB shifts */
+
+ dBShifts_fac = (LVM_FLOAT)(1 << dBShifts);
+ /*
+ * When DBE is enabled use AGC volume
+ */
+ pInstance->pData->AGCInstance.Target = (LVDBE_VolumeTable[dBOffset]);
+ pInstance->pData->AGCInstance.Target = pInstance->pData->AGCInstance.Target / dBShifts_fac;
+ pInstance->pData->AGCInstance.VolumeTC = LVDBE_VolumeTCTable[(LVM_UINT16)pParams->SampleRate]; /* Volume update time constant */
+
+ /*
+ * When DBE is disabled use the bypass volume control
+ */
+ if(dBShifts > 0)
+ {
+ LVC_Mixer_SetTarget(&pInstance->pData->BypassVolume.MixerStream[0],
+ LVDBE_VolumeTable[dBOffset] / dBShifts_fac);
+ }
+ else
+ {
+ LVC_Mixer_SetTarget(&pInstance->pData->BypassVolume.MixerStream[0],
+ LVDBE_VolumeTable[dBOffset]);
+ }
+
+ pInstance->pData->BypassVolume.MixerStream[0].CallbackSet = 1;
+ LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->pData->BypassVolume.MixerStream[0],
+ LVDBE_MIXER_TC,
+ (LVM_Fs_en)pInstance->Params.SampleRate,
+ 2);
+}
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVDBE_Control */
+/* */
+/* DESCRIPTION: */
+/* Sets or changes the Bass Enhancement parameters. Changing the parameters while the */
+/* module is processing signals may have the following side effects: */
+/* */
+/* General parameters: */
+/* =================== */
+/* OperatingMode: Changing the mode of operation may cause a change in volume */
+/* level or cause pops and clicks. */
+/* */
+/* SampleRate: Changing the sample rate may cause pops and clicks. */
+/* */
+/* EffectLevel: Changing the effect level may cause pops and clicks */
+/* */
+/* CentreFrequency: Changing the centre frequency may cause pops and clicks */
+/* */
+/* HPFSelect: Selecting/de-selecting the high pass filter may cause pops and */
+/* clicks */
+/* */
+/* VolumedB Changing the volume setting will have no side effects */
+/* */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance handle */
+/* pParams Pointer to a parameter structure */
+/* */
+/* RETURNS: */
+/* LVDBE_SUCCESS Always succeeds */
+/* */
+/* NOTES: */
+/* 1. This function must not be interrupted by the LVDBE_Process function */
+/* */
+/****************************************************************************************/
+
+LVDBE_ReturnStatus_en LVDBE_Control(LVDBE_Handle_t hInstance,
+ LVDBE_Params_t *pParams)
+{
+
+ LVDBE_Instance_t *pInstance =(LVDBE_Instance_t *)hInstance;
+ LVMixer3_2St_FLOAT_st *pBypassMixer_Instance = &pInstance->pData->BypassMixer;
+
+ /*
+ * Update the filters
+ */
+ if ((pInstance->Params.SampleRate != pParams->SampleRate) ||
+ (pInstance->Params.CentreFrequency != pParams->CentreFrequency))
+ {
+ LVDBE_SetFilters(pInstance, /* Instance pointer */
+ pParams); /* New parameters */
+ }
+
+ /*
+ * Update the AGC is the effect level has changed
+ */
+ if ((pInstance->Params.SampleRate != pParams->SampleRate) ||
+ (pInstance->Params.EffectLevel != pParams->EffectLevel) ||
+ (pInstance->Params.HPFSelect != pParams->HPFSelect))
+ {
+ LVDBE_SetAGC(pInstance, /* Instance pointer */
+ pParams); /* New parameters */
+ LVC_Mixer_SetTimeConstant(&pBypassMixer_Instance->MixerStream[0],
+ LVDBE_BYPASS_MIXER_TC,(LVM_Fs_en)pParams->SampleRate, 2);
+
+ LVC_Mixer_SetTimeConstant(&pBypassMixer_Instance->MixerStream[1],
+ LVDBE_BYPASS_MIXER_TC,(LVM_Fs_en)pParams->SampleRate, 2);
+
+ }
+
+ /*
+ * Update the Volume if the volume demand has changed
+ */
+ if ((pInstance->Params.VolumedB != pParams->VolumedB) ||
+ (pInstance->Params.SampleRate != pParams->SampleRate) ||
+ (pInstance->Params.HeadroomdB != pParams->HeadroomdB) ||
+ (pInstance->Params.VolumeControl != pParams->VolumeControl))
+ {
+ LVDBE_SetVolume(pInstance, /* Instance pointer */
+ pParams); /* New parameters */
+ }
+
+ if (pInstance->Params.OperatingMode==LVDBE_ON && pParams->OperatingMode==LVDBE_OFF)
+ {
+ LVC_Mixer_SetTarget(&pInstance->pData->BypassMixer.MixerStream[0], 0);
+ LVC_Mixer_SetTarget(&pInstance->pData->BypassMixer.MixerStream[1], 1.0f);
+ }
+ if (pInstance->Params.OperatingMode==LVDBE_OFF && pParams->OperatingMode==LVDBE_ON)
+ {
+ LVC_Mixer_SetTarget(&pInstance->pData->BypassMixer.MixerStream[0], 1.0f);
+ LVC_Mixer_SetTarget(&pInstance->pData->BypassMixer.MixerStream[1], 0);
+ }
+
+ /*
+ * Update the instance parameters
+ */
+ pInstance->Params = *pParams;
+
+ return(LVDBE_SUCCESS);
+}
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Init.c b/media/libeffects/lvm/lib/Bass/src/LVDBE_Init.c
deleted file mode 100644
index 2946734..0000000
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Init.c
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/****************************************************************************************/
-/* */
-/* Includes */
-/* */
-/****************************************************************************************/
-
-#include "LVDBE.h"
-#include "LVDBE_Private.h"
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVDBE_Memory */
-/* */
-/* DESCRIPTION: */
-/* This function is used for memory allocation and free. It can be called in */
-/* two ways: */
-/* */
-/* hInstance = NULL Returns the memory requirements */
-/* hInstance = Instance handle Returns the memory requirements and */
-/* allocated base addresses for the instance */
-/* */
-/* When this function is called for memory allocation (hInstance=NULL) the memory */
-/* base address pointers are NULL on return. */
-/* */
-/* When the function is called for free (hInstance = Instance Handle) the memory */
-/* table returns the allocated memory and base addresses used during initialisation. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance Handle */
-/* pMemoryTable Pointer to an empty memory definition table */
-/* pCapabilities Pointer to the instance capabilities */
-/* */
-/* RETURNS: */
-/* LVDBE_SUCCESS Succeeded */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVDBE_Process function */
-/* */
-/****************************************************************************************/
-
-LVDBE_ReturnStatus_en LVDBE_Memory(LVDBE_Handle_t hInstance,
- LVDBE_MemTab_t *pMemoryTable,
- LVDBE_Capabilities_t *pCapabilities)
-{
-
- LVM_UINT32 ScratchSize;
- LVDBE_Instance_t *pInstance = (LVDBE_Instance_t *)hInstance;
-
-
- /*
- * Fill in the memory table
- */
- if (hInstance == LVM_NULL)
- {
- /*
- * Instance memory
- */
- pMemoryTable->Region[LVDBE_MEMREGION_INSTANCE].Size = sizeof(LVDBE_Instance_t);
- pMemoryTable->Region[LVDBE_MEMREGION_INSTANCE].Alignment = LVDBE_INSTANCE_ALIGN;
- pMemoryTable->Region[LVDBE_MEMREGION_INSTANCE].Type = LVDBE_PERSISTENT;
- pMemoryTable->Region[LVDBE_MEMREGION_INSTANCE].pBaseAddress = LVM_NULL;
-
- /*
- * Data memory
- */
-#ifdef BUILD_FLOAT
- pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_DATA].Size = sizeof(LVDBE_Data_FLOAT_t);
-#else
- pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_DATA].Size = sizeof(LVDBE_Data_t);
-#endif
- pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_DATA].Alignment = LVDBE_PERSISTENT_DATA_ALIGN;
- pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_DATA].Type = LVDBE_PERSISTENT_DATA;
- pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_DATA].pBaseAddress = LVM_NULL;
-
- /*
- * Coef memory
- */
-#ifdef BUILD_FLOAT
- pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].Size = sizeof(LVDBE_Coef_FLOAT_t);
-#else
- pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].Size = sizeof(LVDBE_Coef_t);
-#endif
- pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].Alignment = LVDBE_PERSISTENT_COEF_ALIGN;
- pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].Type = LVDBE_PERSISTENT_COEF;
- pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].pBaseAddress = LVM_NULL;
-
- /*
- * Scratch memory
- */
-#ifdef BUILD_FLOAT
- ScratchSize = (LVM_UINT32)(LVDBE_SCRATCHBUFFERS_INPLACE*sizeof(LVM_FLOAT) * \
- pCapabilities->MaxBlockSize);
-#else /*BUILD_FLOAT*/
- ScratchSize = (LVM_UINT32)(LVDBE_SCRATCHBUFFERS_INPLACE*sizeof(LVM_INT16)*pCapabilities->MaxBlockSize);
-#endif
- pMemoryTable->Region[LVDBE_MEMREGION_SCRATCH].Size = ScratchSize;
- pMemoryTable->Region[LVDBE_MEMREGION_SCRATCH].Alignment = LVDBE_SCRATCH_ALIGN;
- pMemoryTable->Region[LVDBE_MEMREGION_SCRATCH].Type = LVDBE_SCRATCH;
- pMemoryTable->Region[LVDBE_MEMREGION_SCRATCH].pBaseAddress = LVM_NULL;
- }
- else
- {
- /* Read back memory allocation table */
- *pMemoryTable = pInstance->MemoryTable;
- }
-
- return(LVDBE_SUCCESS);
-}
-
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVDBE_Init */
-/* */
-/* DESCRIPTION: */
-/* Create and initialisation function for the Dynamic Bass Enhancement module */
-/* */
-/* This function can be used to create an algorithm instance by calling with */
-/* hInstance set to NULL. In this case the algorithm returns the new instance */
-/* handle. */
-/* */
-/* This function can be used to force a full re-initialisation of the algorithm */
-/* by calling with hInstance = Instance Handle. In this case the memory table */
-/* should be correct for the instance, this can be ensured by calling the function */
-/* DBE_Memory before calling this function. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance handle */
-/* pMemoryTable Pointer to the memory definition table */
-/* pCapabilities Pointer to the instance capabilities */
-/* */
-/* RETURNS: */
-/* LVDBE_SUCCESS Initialisation succeeded */
-/* LVDBE_ALIGNMENTERROR Instance or scratch memory on incorrect alignment */
-/* LVDBE_NULLADDRESS Instance or scratch memory has a NULL pointer */
-/* */
-/* NOTES: */
-/* 1. The instance handle is the pointer to the base address of the first memory */
-/* region. */
-/* 2. This function must not be interrupted by the LVDBE_Process function */
-/* */
-/****************************************************************************************/
-
-LVDBE_ReturnStatus_en LVDBE_Init(LVDBE_Handle_t *phInstance,
- LVDBE_MemTab_t *pMemoryTable,
- LVDBE_Capabilities_t *pCapabilities)
-{
-
- LVDBE_Instance_t *pInstance;
-#ifdef BUILD_FLOAT
- LVMixer3_1St_FLOAT_st *pMixer_Instance;
- LVMixer3_2St_FLOAT_st *pBypassMixer_Instance;
- LVM_FLOAT MixGain;
-#else
- LVMixer3_1St_st *pMixer_Instance;
- LVMixer3_2St_st *pBypassMixer_Instance;
- LVM_INT32 MixGain;
-#endif
- LVM_INT16 i;
-
-
- /*
- * Set the instance handle if not already initialised
- */
- if (*phInstance == LVM_NULL)
- {
- *phInstance = (LVDBE_Handle_t)pMemoryTable->Region[LVDBE_MEMREGION_INSTANCE].pBaseAddress;
- }
- pInstance =(LVDBE_Instance_t *)*phInstance;
-
-
- /*
- * Check the memory table for NULL pointers and incorrectly aligned data
- */
- for (i=0; i<LVDBE_NR_MEMORY_REGIONS; i++)
- {
- if (pMemoryTable->Region[i].Size!=0)
- {
- if (pMemoryTable->Region[i].pBaseAddress==LVM_NULL)
- {
- return(LVDBE_NULLADDRESS);
- }
- if (((uintptr_t)pMemoryTable->Region[i].pBaseAddress % pMemoryTable->Region[i].Alignment)!=0){
- return(LVDBE_ALIGNMENTERROR);
- }
- }
- }
-
-
- /*
- * Save the memory table in the instance structure
- */
- pInstance->Capabilities = *pCapabilities;
-
-
- /*
- * Save the memory table in the instance structure
- */
- pInstance->MemoryTable = *pMemoryTable;
-
-
- /*
- * Set the default instance parameters
- */
- pInstance->Params.CentreFrequency = LVDBE_CENTRE_55HZ;
- pInstance->Params.EffectLevel = 0;
- pInstance->Params.HeadroomdB = 0;
- pInstance->Params.HPFSelect = LVDBE_HPF_OFF;
- pInstance->Params.OperatingMode = LVDBE_OFF;
- pInstance->Params.SampleRate = LVDBE_FS_8000;
- pInstance->Params.VolumeControl = LVDBE_VOLUME_OFF;
- pInstance->Params.VolumedB = 0;
-
-
- /*
- * Set pointer to data and coef memory
- */
- pInstance->pData = pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_DATA].pBaseAddress;
- pInstance->pCoef = pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].pBaseAddress;
-
-
- /*
- * Initialise the filters
- */
- LVDBE_SetFilters(pInstance, /* Set the filter taps and coefficients */
- &pInstance->Params);
-
-
- /*
- * Initialise the AGC
- */
- LVDBE_SetAGC(pInstance, /* Set the AGC gain */
- &pInstance->Params);
- pInstance->pData->AGCInstance.AGC_Gain = pInstance->pData->AGCInstance.AGC_MaxGain;
- /* Default to the bass boost setting */
-
- // initialize the mixer with some fixes values since otherwise LVDBE_SetVolume ends up
- // reading uninitialized data
- pMixer_Instance = &pInstance->pData->BypassVolume;
-#ifndef BUILD_FLOAT
- LVC_Mixer_Init(&pMixer_Instance->MixerStream[0],0x00007FFF,0x00007FFF);
-#else
- LVC_Mixer_Init(&pMixer_Instance->MixerStream[0], 1.0, 1.0);
-#endif
-
- /*
- * Initialise the volume
- */
- LVDBE_SetVolume(pInstance, /* Set the Volume */
- &pInstance->Params);
-
- pInstance->pData->AGCInstance.Volume = pInstance->pData->AGCInstance.Target;
- /* Initialise as the target */
-#ifndef BUILD_FLOAT
- MixGain = LVC_Mixer_GetTarget(&pMixer_Instance->MixerStream[0]);
- LVC_Mixer_Init(&pMixer_Instance->MixerStream[0],MixGain,MixGain);
-#else
- MixGain = LVC_Mixer_GetTarget(&pMixer_Instance->MixerStream[0]);
- LVC_Mixer_Init(&pMixer_Instance->MixerStream[0], MixGain, MixGain);
-#endif
-
- /* Configure the mixer process path */
- pMixer_Instance->MixerStream[0].CallbackParam = 0;
- pMixer_Instance->MixerStream[0].pCallbackHandle = LVM_NULL;
- pMixer_Instance->MixerStream[0].pCallBack = LVM_NULL;
- pMixer_Instance->MixerStream[0].CallbackSet = 0;
-
- /*
- * Initialise the clicks minimisation BypassMixer
- */
-
- pBypassMixer_Instance = &pInstance->pData->BypassMixer;
-
- /*
- * Setup the mixer gain for the processed path
- */
- pBypassMixer_Instance->MixerStream[0].CallbackParam = 0;
- pBypassMixer_Instance->MixerStream[0].pCallbackHandle = LVM_NULL;
- pBypassMixer_Instance->MixerStream[0].pCallBack = LVM_NULL;
- pBypassMixer_Instance->MixerStream[0].CallbackSet=0;
-
- LVC_Mixer_Init(&pBypassMixer_Instance->MixerStream[0],0,0);
- LVC_Mixer_SetTimeConstant(&pBypassMixer_Instance->MixerStream[0],
- LVDBE_BYPASS_MIXER_TC,(LVM_Fs_en)pInstance->Params.SampleRate,2);
-
- /*
- * Setup the mixer gain for the unprocessed path
- */
- pBypassMixer_Instance->MixerStream[1].CallbackParam = 0;
- pBypassMixer_Instance->MixerStream[1].pCallbackHandle = LVM_NULL;
- pBypassMixer_Instance->MixerStream[1].pCallBack = LVM_NULL;
- pBypassMixer_Instance->MixerStream[1].CallbackSet=0;
-#ifndef BUILD_FLOAT
- LVC_Mixer_Init(&pBypassMixer_Instance->MixerStream[1],0x00007FFF,0x00007FFF);
- LVC_Mixer_SetTimeConstant(&pBypassMixer_Instance->MixerStream[1],
- LVDBE_BYPASS_MIXER_TC,(LVM_Fs_en)pInstance->Params.SampleRate,2);
-#else
- LVC_Mixer_Init(&pBypassMixer_Instance->MixerStream[1], 1.0, 1.0);
- LVC_Mixer_SetTimeConstant(&pBypassMixer_Instance->MixerStream[1],
- LVDBE_BYPASS_MIXER_TC,(LVM_Fs_en)pInstance->Params.SampleRate, 2);
-#endif
-
- return(LVDBE_SUCCESS);
-}
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Init.cpp b/media/libeffects/lvm/lib/Bass/src/LVDBE_Init.cpp
new file mode 100644
index 0000000..ad77696
--- /dev/null
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Init.cpp
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/****************************************************************************************/
+/* */
+/* Includes */
+/* */
+/****************************************************************************************/
+
+#include "LVDBE.h"
+#include "LVDBE_Private.h"
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVDBE_Memory */
+/* */
+/* DESCRIPTION: */
+/* This function is used for memory allocation and free. It can be called in */
+/* two ways: */
+/* */
+/* hInstance = NULL Returns the memory requirements */
+/* hInstance = Instance handle Returns the memory requirements and */
+/* allocated base addresses for the instance */
+/* */
+/* When this function is called for memory allocation (hInstance=NULL) the memory */
+/* base address pointers are NULL on return. */
+/* */
+/* When the function is called for free (hInstance = Instance Handle) the memory */
+/* table returns the allocated memory and base addresses used during initialisation. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance Handle */
+/* pMemoryTable Pointer to an empty memory definition table */
+/* pCapabilities Pointer to the instance capabilities */
+/* */
+/* RETURNS: */
+/* LVDBE_SUCCESS Succeeded */
+/* */
+/* NOTES: */
+/* 1. This function may be interrupted by the LVDBE_Process function */
+/* */
+/****************************************************************************************/
+
+LVDBE_ReturnStatus_en LVDBE_Memory(LVDBE_Handle_t hInstance,
+ LVDBE_MemTab_t *pMemoryTable,
+ LVDBE_Capabilities_t *pCapabilities)
+{
+
+ LVM_UINT32 ScratchSize;
+ LVDBE_Instance_t *pInstance = (LVDBE_Instance_t *)hInstance;
+
+ /*
+ * Fill in the memory table
+ */
+ if (hInstance == LVM_NULL)
+ {
+ /*
+ * Instance memory
+ */
+ pMemoryTable->Region[LVDBE_MEMREGION_INSTANCE].Size = sizeof(LVDBE_Instance_t);
+ pMemoryTable->Region[LVDBE_MEMREGION_INSTANCE].Alignment = LVDBE_INSTANCE_ALIGN;
+ pMemoryTable->Region[LVDBE_MEMREGION_INSTANCE].Type = LVDBE_PERSISTENT;
+ pMemoryTable->Region[LVDBE_MEMREGION_INSTANCE].pBaseAddress = LVM_NULL;
+
+ /*
+ * Data memory
+ */
+ pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_DATA].Size = sizeof(LVDBE_Data_FLOAT_t);
+ pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_DATA].Alignment = LVDBE_PERSISTENT_DATA_ALIGN;
+ pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_DATA].Type = LVDBE_PERSISTENT_DATA;
+ pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_DATA].pBaseAddress = LVM_NULL;
+
+ /*
+ * Coef memory
+ */
+ pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].Size = sizeof(LVDBE_Coef_FLOAT_t);
+ pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].Alignment = LVDBE_PERSISTENT_COEF_ALIGN;
+ pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].Type = LVDBE_PERSISTENT_COEF;
+ pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].pBaseAddress = LVM_NULL;
+
+ /*
+ * Scratch memory
+ */
+ ScratchSize = (LVM_UINT32)(LVDBE_SCRATCHBUFFERS_INPLACE*sizeof(LVM_FLOAT) * \
+ pCapabilities->MaxBlockSize);
+ pMemoryTable->Region[LVDBE_MEMREGION_SCRATCH].Size = ScratchSize;
+ pMemoryTable->Region[LVDBE_MEMREGION_SCRATCH].Alignment = LVDBE_SCRATCH_ALIGN;
+ pMemoryTable->Region[LVDBE_MEMREGION_SCRATCH].Type = LVDBE_SCRATCH;
+ pMemoryTable->Region[LVDBE_MEMREGION_SCRATCH].pBaseAddress = LVM_NULL;
+ }
+ else
+ {
+ /* Read back memory allocation table */
+ *pMemoryTable = pInstance->MemoryTable;
+ }
+
+ return(LVDBE_SUCCESS);
+}
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVDBE_Init */
+/* */
+/* DESCRIPTION: */
+/* Create and initialisation function for the Dynamic Bass Enhancement module */
+/* */
+/* This function can be used to create an algorithm instance by calling with */
+/* hInstance set to NULL. In this case the algorithm returns the new instance */
+/* handle. */
+/* */
+/* This function can be used to force a full re-initialisation of the algorithm */
+/* by calling with hInstance = Instance Handle. In this case the memory table */
+/* should be correct for the instance, this can be ensured by calling the function */
+/* DBE_Memory before calling this function. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance handle */
+/* pMemoryTable Pointer to the memory definition table */
+/* pCapabilities Pointer to the instance capabilities */
+/* */
+/* RETURNS: */
+/* LVDBE_SUCCESS Initialisation succeeded */
+/* LVDBE_ALIGNMENTERROR Instance or scratch memory on incorrect alignment */
+/* LVDBE_NULLADDRESS Instance or scratch memory has a NULL pointer */
+/* */
+/* NOTES: */
+/* 1. The instance handle is the pointer to the base address of the first memory */
+/* region. */
+/* 2. This function must not be interrupted by the LVDBE_Process function */
+/* */
+/****************************************************************************************/
+
+LVDBE_ReturnStatus_en LVDBE_Init(LVDBE_Handle_t *phInstance,
+ LVDBE_MemTab_t *pMemoryTable,
+ LVDBE_Capabilities_t *pCapabilities)
+{
+
+ LVDBE_Instance_t *pInstance;
+ LVMixer3_1St_FLOAT_st *pMixer_Instance;
+ LVMixer3_2St_FLOAT_st *pBypassMixer_Instance;
+ LVM_FLOAT MixGain;
+ LVM_INT16 i;
+
+ /*
+ * Set the instance handle if not already initialised
+ */
+ if (*phInstance == LVM_NULL)
+ {
+ *phInstance = (LVDBE_Handle_t)pMemoryTable->Region[LVDBE_MEMREGION_INSTANCE].pBaseAddress;
+ }
+ pInstance =(LVDBE_Instance_t *)*phInstance;
+
+ /*
+ * Check the memory table for NULL pointers and incorrectly aligned data
+ */
+ for (i=0; i<LVDBE_NR_MEMORY_REGIONS; i++)
+ {
+ if (pMemoryTable->Region[i].Size!=0)
+ {
+ if (pMemoryTable->Region[i].pBaseAddress==LVM_NULL)
+ {
+ return(LVDBE_NULLADDRESS);
+ }
+ if (((uintptr_t)pMemoryTable->Region[i].pBaseAddress % pMemoryTable->Region[i].Alignment)!=0){
+ return(LVDBE_ALIGNMENTERROR);
+ }
+ }
+ }
+
+ /*
+ * Save the memory table in the instance structure
+ */
+ pInstance->Capabilities = *pCapabilities;
+
+ /*
+ * Save the memory table in the instance structure
+ */
+ pInstance->MemoryTable = *pMemoryTable;
+
+ /*
+ * Set the default instance parameters
+ */
+ pInstance->Params.CentreFrequency = LVDBE_CENTRE_55HZ;
+ pInstance->Params.EffectLevel = 0;
+ pInstance->Params.HeadroomdB = 0;
+ pInstance->Params.HPFSelect = LVDBE_HPF_OFF;
+ pInstance->Params.OperatingMode = LVDBE_OFF;
+ pInstance->Params.SampleRate = LVDBE_FS_8000;
+ pInstance->Params.VolumeControl = LVDBE_VOLUME_OFF;
+ pInstance->Params.VolumedB = 0;
+
+ /*
+ * Set pointer to data and coef memory
+ */
+ pInstance->pData =
+ (LVDBE_Data_FLOAT_t *)pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_DATA].pBaseAddress;
+ pInstance->pCoef =
+ (LVDBE_Coef_FLOAT_t *)pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].pBaseAddress;
+
+ /*
+ * Initialise the filters
+ */
+ LVDBE_SetFilters(pInstance, /* Set the filter taps and coefficients */
+ &pInstance->Params);
+
+ /*
+ * Initialise the AGC
+ */
+ LVDBE_SetAGC(pInstance, /* Set the AGC gain */
+ &pInstance->Params);
+ pInstance->pData->AGCInstance.AGC_Gain = pInstance->pData->AGCInstance.AGC_MaxGain;
+ /* Default to the bass boost setting */
+
+ // initialize the mixer with some fixes values since otherwise LVDBE_SetVolume ends up
+ // reading uninitialized data
+ pMixer_Instance = &pInstance->pData->BypassVolume;
+ LVC_Mixer_Init(&pMixer_Instance->MixerStream[0], 1.0, 1.0);
+
+ /*
+ * Initialise the volume
+ */
+ LVDBE_SetVolume(pInstance, /* Set the Volume */
+ &pInstance->Params);
+
+ pInstance->pData->AGCInstance.Volume = pInstance->pData->AGCInstance.Target;
+ /* Initialise as the target */
+ MixGain = LVC_Mixer_GetTarget(&pMixer_Instance->MixerStream[0]);
+ LVC_Mixer_Init(&pMixer_Instance->MixerStream[0], MixGain, MixGain);
+
+ /* Configure the mixer process path */
+ pMixer_Instance->MixerStream[0].CallbackParam = 0;
+ pMixer_Instance->MixerStream[0].pCallbackHandle = LVM_NULL;
+ pMixer_Instance->MixerStream[0].pCallBack = LVM_NULL;
+ pMixer_Instance->MixerStream[0].CallbackSet = 0;
+
+ /*
+ * Initialise the clicks minimisation BypassMixer
+ */
+
+ pBypassMixer_Instance = &pInstance->pData->BypassMixer;
+
+ /*
+ * Setup the mixer gain for the processed path
+ */
+ pBypassMixer_Instance->MixerStream[0].CallbackParam = 0;
+ pBypassMixer_Instance->MixerStream[0].pCallbackHandle = LVM_NULL;
+ pBypassMixer_Instance->MixerStream[0].pCallBack = LVM_NULL;
+ pBypassMixer_Instance->MixerStream[0].CallbackSet=0;
+
+ LVC_Mixer_Init(&pBypassMixer_Instance->MixerStream[0],0,0);
+ LVC_Mixer_SetTimeConstant(&pBypassMixer_Instance->MixerStream[0],
+ LVDBE_BYPASS_MIXER_TC,(LVM_Fs_en)pInstance->Params.SampleRate,2);
+
+ /*
+ * Setup the mixer gain for the unprocessed path
+ */
+ pBypassMixer_Instance->MixerStream[1].CallbackParam = 0;
+ pBypassMixer_Instance->MixerStream[1].pCallbackHandle = LVM_NULL;
+ pBypassMixer_Instance->MixerStream[1].pCallBack = LVM_NULL;
+ pBypassMixer_Instance->MixerStream[1].CallbackSet=0;
+ LVC_Mixer_Init(&pBypassMixer_Instance->MixerStream[1], 1.0, 1.0);
+ LVC_Mixer_SetTimeConstant(&pBypassMixer_Instance->MixerStream[1],
+ LVDBE_BYPASS_MIXER_TC,(LVM_Fs_en)pInstance->Params.SampleRate, 2);
+
+ return(LVDBE_SUCCESS);
+}
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Private.h b/media/libeffects/lvm/lib/Bass/src/LVDBE_Private.h
index 4225a30..f3faaed 100644
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Private.h
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Private.h
@@ -27,11 +27,6 @@
#ifndef __LVDBE_PRIVATE_H__
#define __LVDBE_PRIVATE_H__
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-
/****************************************************************************************/
/* */
/* Includes */
@@ -43,7 +38,6 @@
#include "LVC_Mixer.h"
#include "AGC.h"
-
/****************************************************************************************/
/* */
/* Defines */
@@ -74,7 +68,6 @@
#define LVDBE_MIXER_TC 5 /* Mixer time */
#define LVDBE_BYPASS_MIXER_TC 100 /* Bypass mixer time */
-
/****************************************************************************************/
/* */
/* Structures */
@@ -82,29 +75,6 @@
/****************************************************************************************/
/* Data structure */
-#ifndef BUILD_FLOAT
-typedef struct
-{
- /* AGC parameters */
- AGC_MIX_VOL_2St1Mon_D32_t AGCInstance; /* AGC instance parameters */
-
- /* Process variables */
- Biquad_2I_Order2_Taps_t HPFTaps; /* High pass filter taps */
- Biquad_1I_Order2_Taps_t BPFTaps; /* Band pass filter taps */
- LVMixer3_1St_st BypassVolume; /* Bypass volume scaler */
- LVMixer3_2St_st BypassMixer; /* Bypass Mixer for Click Removal */
-
-} LVDBE_Data_t;
-
-/* Coefs structure */
-typedef struct
-{
- /* Process variables */
- Biquad_Instance_t HPFInstance; /* High pass filter instance */
- Biquad_Instance_t BPFInstance; /* Band pass filter instance */
-
-} LVDBE_Coef_t;
-#else
/* Data structure */
typedef struct
{
@@ -126,7 +96,6 @@
Biquad_FLOAT_Instance_t HPFInstance; /* High pass filter instance */
Biquad_FLOAT_Instance_t BPFInstance; /* Band pass filter instance */
} LVDBE_Coef_FLOAT_t;
-#endif
/* Instance structure */
typedef struct
{
@@ -136,16 +105,10 @@
LVDBE_Capabilities_t Capabilities; /* Instance capabilities */
/* Data and coefficient pointers */
-#ifndef BUILD_FLOAT
- LVDBE_Data_t *pData; /* Instance data */
- LVDBE_Coef_t *pCoef; /* Instance coefficients */
-#else
LVDBE_Data_FLOAT_t *pData; /* Instance data */
LVDBE_Coef_FLOAT_t *pCoef; /* Instance coefficients */
-#endif
} LVDBE_Instance_t;
-
/****************************************************************************************/
/* */
/* Function prototypes */
@@ -155,17 +118,10 @@
void LVDBE_SetAGC(LVDBE_Instance_t *pInstance,
LVDBE_Params_t *pParams);
-
void LVDBE_SetVolume(LVDBE_Instance_t *pInstance,
LVDBE_Params_t *pParams);
-
void LVDBE_SetFilters(LVDBE_Instance_t *pInstance,
LVDBE_Params_t *pParams);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
#endif /* __LVDBE_PRIVATE_H__ */
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Process.c b/media/libeffects/lvm/lib/Bass/src/LVDBE_Process.c
deleted file mode 100644
index c4d3403..0000000
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Process.c
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/****************************************************************************************/
-/* */
-/* Includes */
-/* */
-/****************************************************************************************/
-
-#include <string.h> // memset
-#include "LVDBE.h"
-#include "LVDBE_Private.h"
-#include "VectorArithmetic.h"
-#include "AGC.h"
-#include "LVDBE_Coeffs.h" /* Filter coefficients */
-#include <log/log.h>
-
-/********************************************************************************************/
-/* */
-/* FUNCTION: LVDBE_Process */
-/* */
-/* DESCRIPTION: */
-/* Process function for the Bass Enhancement module. */
-/* */
-/* Data can be processed in two formats, stereo or mono-in-stereo. Data in mono */
-/* format is not supported, the calling routine must convert the mono stream to */
-/* mono-in-stereo. */
-/* ___________ */
-/* ________ | | ________ */
-/* | | _____ |------------------------->| | | | */
-/* | 16-bit | | | | ________ | | | 32-bit | */
-/* -+-->| to |-->| HPF |--| | | _____ | AGC Mixer |-->| to |--| */
-/* | | 32-bit | |_____| | | Stereo | | | | | | 16-bit | | */
-/* | |________| |-->| to |-->| BPF |-->| | |________| 0 */
-/* | | Mono | |_____| |___________| \--> */
-/* | |________| */
-/* | _________ 0 */
-/* | | | | */
-/* |----------------------------------------------------| Volume |-----------------| */
-/* | Control | */
-/* |_________| */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance handle */
-/* pInData Pointer to the input data */
-/* pOutData Pointer to the output data */
-/* NumSamples Number of samples in the input buffer */
-/* */
-/* RETURNS: */
-/* LVDBE_SUCCESS Succeeded */
-/* LVDBE_TOOMANYSAMPLES NumSamples was larger than the maximum block size */
-/* */
-/* NOTES: */
-/* 1. The input and output data must be 32-bit format. The input is scaled by a shift */
-/* when converting from 16-bit format, this scaling allows for internal headroom in the */
-/* bass enhancement algorithm. */
-/* 2. For a 16-bit implementation the converstion to 32-bit is removed and replaced with */
-/* the headroom loss. This headroom loss is compensated in the volume control so the */
-/* overall end to end gain is odB. */
-/* */
-/********************************************************************************************/
-#ifndef BUILD_FLOAT
-LVDBE_ReturnStatus_en LVDBE_Process(LVDBE_Handle_t hInstance,
- const LVM_INT16 *pInData, LVM_INT16 *pOutData, LVM_UINT16 NumSamples) {
-
- LVDBE_Instance_t *pInstance = (LVDBE_Instance_t *) hInstance;
- LVM_INT32 *pScratch =
- (LVM_INT32 *) pInstance->MemoryTable.Region[LVDBE_MEMREGION_SCRATCH].pBaseAddress;
- LVM_INT32 *pMono;
- LVM_INT16 *pInput = (LVM_INT16 *) pInData;
-
- /* Scratch for Volume Control starts at offset of 2*NumSamples short values from pScratch */
- LVM_INT16 *pScratchVol = (LVM_INT16 *) (&pScratch[NumSamples]);
-
- /* Scratch for Mono path starts at offset of 2*NumSamples 32-bit values from pScratch */
- pMono = &pScratch[2 * NumSamples];
-
- /*
- * Check the number of samples is not too large
- */
- if (NumSamples > pInstance->Capabilities.MaxBlockSize) {
- return (LVDBE_TOOMANYSAMPLES);
- }
-
- /*
- * Check if the algorithm is enabled
- */
- /* DBE path is processed when DBE is ON or during On/Off transitions */
- if ((pInstance->Params.OperatingMode == LVDBE_ON)
- || (LVC_Mixer_GetCurrent(
- &pInstance->pData->BypassMixer.MixerStream[0])
- != LVC_Mixer_GetTarget(
- &pInstance->pData->BypassMixer.MixerStream[0]))) {
-
- /*
- * Convert 16-bit samples to 32-bit and scale
- * (For a 16-bit implementation apply headroom loss here)
- */
- Int16LShiftToInt32_16x32(pInput, /* Source 16-bit data */
- pScratch, /* Dest. 32-bit data */
- (LVM_INT16) (2 * NumSamples), /* Left and right */
- LVDBE_SCALESHIFT); /* Shift scale */
-
- /*
- * Apply the high pass filter if selected
- */
- if (pInstance->Params.HPFSelect == LVDBE_HPF_ON) {
- BQ_2I_D32F32C30_TRC_WRA_01(&pInstance->pCoef->HPFInstance,/* Filter instance */
- (LVM_INT32 *) pScratch, /* Source */
- (LVM_INT32 *) pScratch, /* Destination */
- (LVM_INT16) NumSamples); /* Number of samples */
- }
-
- /*
- * Create the mono stream
- */
- From2iToMono_32(pScratch, /* Stereo source */
- pMono, /* Mono destination */
- (LVM_INT16) NumSamples); /* Number of samples */
-
- /*
- * Apply the band pass filter
- */
- BP_1I_D32F32C30_TRC_WRA_02(&pInstance->pCoef->BPFInstance, /* Filter instance */
- (LVM_INT32 *) pMono, /* Source */
- (LVM_INT32 *) pMono, /* Destination */
- (LVM_INT16) NumSamples); /* Number of samples */
-
- /*
- * Apply the AGC and mix
- */
- AGC_MIX_VOL_2St1Mon_D32_WRA(&pInstance->pData->AGCInstance, /* Instance pointer */
- pScratch, /* Stereo source */
- pMono, /* Mono band pass source */
- pScratch, /* Stereo destination */
- NumSamples); /* Number of samples */
-
- /*
- * Convert 32-bit samples to 16-bit and saturate
- * (Not required for 16-bit implemenations)
- */
- Int32RShiftToInt16_Sat_32x16(pScratch, /* Source 32-bit data */
- (LVM_INT16 *) pScratch, /* Dest. 16-bit data */
- (LVM_INT16) (2 * NumSamples), /* Left and right */
- LVDBE_SCALESHIFT); /* Shift scale */
-
- }
-
- /* Bypass Volume path is processed when DBE is OFF or during On/Off transitions */
- if ((pInstance->Params.OperatingMode == LVDBE_OFF)
- || (LVC_Mixer_GetCurrent(
- &pInstance->pData->BypassMixer.MixerStream[1])
- != LVC_Mixer_GetTarget(
- &pInstance->pData->BypassMixer.MixerStream[1]))) {
-
- /*
- * The algorithm is disabled but volume management is required to compensate for
- * headroom and volume (if enabled)
- */
- LVC_MixSoft_1St_D16C31_SAT(&pInstance->pData->BypassVolume, pInData,
- pScratchVol, (LVM_INT16) (2 * NumSamples)); /* Left and right */
-
- }
-
- /*
- * Mix DBE processed path and bypass volume path
- */
- LVC_MixSoft_2St_D16C31_SAT(&pInstance->pData->BypassMixer,
- (LVM_INT16 *) pScratch, pScratchVol, pOutData,
- (LVM_INT16) (2 * NumSamples));
-
- return (LVDBE_SUCCESS);
-}
-#else /*BUILD_FLOAT*/
-LVDBE_ReturnStatus_en LVDBE_Process(LVDBE_Handle_t hInstance,
- const LVM_FLOAT *pInData,
- LVM_FLOAT *pOutData,
- const LVM_UINT16 NrFrames) // updated to use samples = frames * channels.
-{
- LVDBE_Instance_t *pInstance =(LVDBE_Instance_t *)hInstance;
-
- /*Extract number of Channels info*/
-#ifdef SUPPORT_MC
- // Mono passed in as stereo
- const LVM_INT32 NrChannels = pInstance->Params.NrChannels == 1
- ? 2 : pInstance->Params.NrChannels;
-#else
- const LVM_INT32 NrChannels = 2; // FCC_2
-#endif
- const LVM_INT32 NrSamples = NrChannels * NrFrames;
-
- /* Space to store DBE path computation */
- LVM_FLOAT * const pScratch =
- (LVM_FLOAT *)pInstance->MemoryTable.Region[LVDBE_MEMREGION_SCRATCH].pBaseAddress;
-
- /*
- * Scratch for Mono path starts at offset of
- * NrSamples float values from pScratch.
- */
- LVM_FLOAT * const pMono = pScratch + NrSamples;
-
- /*
- * TRICKY: pMono is used and discarded by the DBE path.
- * so it is available for use for the pScratchVol
- * path which is computed afterwards.
- *
- * Space to store Volume Control path computation.
- * This is identical to pMono (see TRICKY comment).
- */
- LVM_FLOAT * const pScratchVol = pMono;
-
- /*
- * Check the number of frames is not too large
- */
- if (NrFrames > pInstance->Capabilities.MaxBlockSize)
- {
- return LVDBE_TOOMANYSAMPLES;
- }
-
- /*
- * Check if the algorithm is enabled
- */
- /* DBE path is processed when DBE is ON or during On/Off transitions */
- if ((pInstance->Params.OperatingMode == LVDBE_ON)||
- (LVC_Mixer_GetCurrent(&pInstance->pData->BypassMixer.MixerStream[0])
- !=LVC_Mixer_GetTarget(&pInstance->pData->BypassMixer.MixerStream[0])))
- {
- // make copy of input data
- Copy_Float(pInData,
- pScratch,
- (LVM_INT16)NrSamples);
-
- /*
- * Apply the high pass filter if selected
- */
- if (pInstance->Params.HPFSelect == LVDBE_HPF_ON)
- {
-#ifdef SUPPORT_MC
- BQ_MC_D32F32C30_TRC_WRA_01(&pInstance->pCoef->HPFInstance, /* Filter instance */
- pScratch, /* Source */
- pScratch, /* Destination */
- (LVM_INT16)NrFrames,
- (LVM_INT16)NrChannels);
-#else
- BQ_2I_D32F32C30_TRC_WRA_01(&pInstance->pCoef->HPFInstance,/* Filter instance */
- pScratch, /* Source */
- pScratch, /* Destination */
- (LVM_INT16)NrFrames);
-#endif
- }
-
- /*
- * Create the mono stream
- */
-#ifdef SUPPORT_MC
- FromMcToMono_Float(pScratch, /* Source */
- pMono, /* Mono destination */
- (LVM_INT16)NrFrames, /* Number of frames */
- (LVM_INT16)NrChannels);
-#else
- From2iToMono_Float(pScratch, /* Stereo source */
- pMono, /* Mono destination */
- (LVM_INT16)NrFrames);
-#endif
-
- /*
- * Apply the band pass filter
- */
- BP_1I_D32F32C30_TRC_WRA_02(&pInstance->pCoef->BPFInstance, /* Filter instance */
- pMono, /* Source */
- pMono, /* Destination */
- (LVM_INT16)NrFrames);
-
- /*
- * Apply the AGC and mix
- */
-#ifdef SUPPORT_MC
- AGC_MIX_VOL_Mc1Mon_D32_WRA(&pInstance->pData->AGCInstance, /* Instance pointer */
- pScratch, /* Source */
- pMono, /* Mono band pass source */
- pScratch, /* Destination */
- NrFrames, /* Number of frames */
- NrChannels); /* Number of channels */
-#else
- AGC_MIX_VOL_2St1Mon_D32_WRA(&pInstance->pData->AGCInstance, /* Instance pointer */
- pScratch, /* Stereo source */
- pMono, /* Mono band pass source */
- pScratch, /* Stereo destination */
- NrFrames);
-#endif
-
- for (LVM_INT32 ii = 0; ii < NrSamples; ++ii) {
- //TODO: replace with existing clamping function
- if (pScratch[ii] < -1.0) {
- pScratch[ii] = -1.0;
- } else if (pScratch[ii] > 1.0) {
- pScratch[ii] = 1.0;
- }
- }
- } else {
- // clear DBE processed path
- memset(pScratch, 0, sizeof(*pScratch) * NrSamples);
- }
-
- /* Bypass Volume path is processed when DBE is OFF or during On/Off transitions */
- if ((pInstance->Params.OperatingMode == LVDBE_OFF)||
- (LVC_Mixer_GetCurrent(&pInstance->pData->BypassMixer.MixerStream[1])
- !=LVC_Mixer_GetTarget(&pInstance->pData->BypassMixer.MixerStream[1])))
- {
-
- /*
- * The algorithm is disabled but volume management is required to compensate for
- * headroom and volume (if enabled)
- */
-#ifdef SUPPORT_MC
- LVC_MixSoft_Mc_D16C31_SAT(&pInstance->pData->BypassVolume,
- pInData,
- pScratchVol,
- (LVM_INT16)NrFrames,
- (LVM_INT16)NrChannels);
-#else
- LVC_MixSoft_1St_D16C31_SAT(&pInstance->pData->BypassVolume,
- pInData,
- pScratchVol,
- (LVM_INT16)NrSamples); /* Left and right, really # samples */
-#endif
- } else {
- // clear bypass volume path
- memset(pScratchVol, 0, sizeof(*pScratchVol) * NrSamples);
- }
-
- /*
- * Mix DBE processed path and bypass volume path
- */
-#ifdef SUPPORT_MC
- LVC_MixSoft_2Mc_D16C31_SAT(&pInstance->pData->BypassMixer,
- pScratch,
- pScratchVol,
- pOutData,
- (LVM_INT16)NrFrames,
- (LVM_INT16)NrChannels);
-#else
- LVC_MixSoft_2St_D16C31_SAT(&pInstance->pData->BypassMixer,
- pScratch,
- pScratchVol,
- pOutData,
- (LVM_INT16)NrSamples);
-#endif
- return LVDBE_SUCCESS;
-}
-#endif
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Process.cpp b/media/libeffects/lvm/lib/Bass/src/LVDBE_Process.cpp
new file mode 100644
index 0000000..b4a71c7
--- /dev/null
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Process.cpp
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/****************************************************************************************/
+/* */
+/* Includes */
+/* */
+/****************************************************************************************/
+
+#include <string.h> // memset
+#include "LVDBE.h"
+#include "LVDBE_Private.h"
+#include "VectorArithmetic.h"
+#include "AGC.h"
+#include "LVDBE_Coeffs.h" /* Filter coefficients */
+#include <log/log.h>
+
+/********************************************************************************************/
+/* */
+/* FUNCTION: LVDBE_Process */
+/* */
+/* DESCRIPTION: */
+/* Process function for the Bass Enhancement module. */
+/* */
+/* Data can be processed in two formats, stereo or mono-in-stereo. Data in mono */
+/* format is not supported, the calling routine must convert the mono stream to */
+/* mono-in-stereo. */
+/* ___________ */
+/* ________ | | ________ */
+/* | | _____ |------------------------->| | | | */
+/* | 16-bit | | | | ________ | | | 32-bit | */
+/* -+-->| to |-->| HPF |--| | | _____ | AGC Mixer |-->| to |--| */
+/* | | 32-bit | |_____| | | Stereo | | | | | | 16-bit | | */
+/* | |________| |-->| to |-->| BPF |-->| | |________| 0 */
+/* | | Mono | |_____| |___________| \--> */
+/* | |________| */
+/* | _________ 0 */
+/* | | | | */
+/* |----------------------------------------------------| Volume |-----------------| */
+/* | Control | */
+/* |_________| */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance handle */
+/* pInData Pointer to the input data */
+/* pOutData Pointer to the output data */
+/* NumSamples Number of samples in the input buffer */
+/* */
+/* RETURNS: */
+/* LVDBE_SUCCESS Succeeded */
+/* LVDBE_TOOMANYSAMPLES NumSamples was larger than the maximum block size */
+/* */
+/* NOTES: */
+/* 1. The input and output data must be 32-bit format. The input is scaled by a shift */
+/* when converting from 16-bit format, this scaling allows for internal headroom in the */
+/* bass enhancement algorithm. */
+/* 2. For a 16-bit implementation the converstion to 32-bit is removed and replaced with */
+/* the headroom loss. This headroom loss is compensated in the volume control so the */
+/* overall end to end gain is odB. */
+/* */
+/********************************************************************************************/
+LVDBE_ReturnStatus_en LVDBE_Process(LVDBE_Handle_t hInstance,
+ const LVM_FLOAT *pInData,
+ LVM_FLOAT *pOutData,
+ const LVM_UINT16 NrFrames) // updated to use samples = frames * channels.
+{
+ LVDBE_Instance_t *pInstance =(LVDBE_Instance_t *)hInstance;
+
+ /*Extract number of Channels info*/
+#ifdef SUPPORT_MC
+ // Mono passed in as stereo
+ const LVM_INT32 NrChannels = pInstance->Params.NrChannels == 1
+ ? 2 : pInstance->Params.NrChannels;
+#else
+ const LVM_INT32 NrChannels = 2; // FCC_2
+#endif
+ const LVM_INT32 NrSamples = NrChannels * NrFrames;
+
+ /* Space to store DBE path computation */
+ LVM_FLOAT * const pScratch =
+ (LVM_FLOAT *)pInstance->MemoryTable.Region[LVDBE_MEMREGION_SCRATCH].pBaseAddress;
+
+ /*
+ * Scratch for Mono path starts at offset of
+ * NrSamples float values from pScratch.
+ */
+ LVM_FLOAT * const pMono = pScratch + NrSamples;
+
+ /*
+ * TRICKY: pMono is used and discarded by the DBE path.
+ * so it is available for use for the pScratchVol
+ * path which is computed afterwards.
+ *
+ * Space to store Volume Control path computation.
+ * This is identical to pMono (see TRICKY comment).
+ */
+ LVM_FLOAT * const pScratchVol = pMono;
+
+ /*
+ * Check the number of frames is not too large
+ */
+ if (NrFrames > pInstance->Capabilities.MaxBlockSize)
+ {
+ return LVDBE_TOOMANYSAMPLES;
+ }
+
+ /*
+ * Check if the algorithm is enabled
+ */
+ /* DBE path is processed when DBE is ON or during On/Off transitions */
+ if ((pInstance->Params.OperatingMode == LVDBE_ON)||
+ (LVC_Mixer_GetCurrent(&pInstance->pData->BypassMixer.MixerStream[0])
+ !=LVC_Mixer_GetTarget(&pInstance->pData->BypassMixer.MixerStream[0])))
+ {
+ // make copy of input data
+ Copy_Float(pInData,
+ pScratch,
+ (LVM_INT16)NrSamples);
+
+ /*
+ * Apply the high pass filter if selected
+ */
+ if (pInstance->Params.HPFSelect == LVDBE_HPF_ON)
+ {
+#ifdef SUPPORT_MC
+ BQ_MC_D32F32C30_TRC_WRA_01(&pInstance->pCoef->HPFInstance, /* Filter instance */
+ pScratch, /* Source */
+ pScratch, /* Destination */
+ (LVM_INT16)NrFrames,
+ (LVM_INT16)NrChannels);
+#else
+ BQ_2I_D32F32C30_TRC_WRA_01(&pInstance->pCoef->HPFInstance,/* Filter instance */
+ pScratch, /* Source */
+ pScratch, /* Destination */
+ (LVM_INT16)NrFrames);
+#endif
+ }
+
+ /*
+ * Create the mono stream
+ */
+#ifdef SUPPORT_MC
+ FromMcToMono_Float(pScratch, /* Source */
+ pMono, /* Mono destination */
+ (LVM_INT16)NrFrames, /* Number of frames */
+ (LVM_INT16)NrChannels);
+#else
+ From2iToMono_Float(pScratch, /* Stereo source */
+ pMono, /* Mono destination */
+ (LVM_INT16)NrFrames);
+#endif
+
+ /*
+ * Apply the band pass filter
+ */
+ BP_1I_D32F32C30_TRC_WRA_02(&pInstance->pCoef->BPFInstance, /* Filter instance */
+ pMono, /* Source */
+ pMono, /* Destination */
+ (LVM_INT16)NrFrames);
+
+ /*
+ * Apply the AGC and mix
+ */
+#ifdef SUPPORT_MC
+ AGC_MIX_VOL_Mc1Mon_D32_WRA(&pInstance->pData->AGCInstance, /* Instance pointer */
+ pScratch, /* Source */
+ pMono, /* Mono band pass source */
+ pScratch, /* Destination */
+ NrFrames, /* Number of frames */
+ NrChannels); /* Number of channels */
+#else
+ AGC_MIX_VOL_2St1Mon_D32_WRA(&pInstance->pData->AGCInstance, /* Instance pointer */
+ pScratch, /* Stereo source */
+ pMono, /* Mono band pass source */
+ pScratch, /* Stereo destination */
+ NrFrames);
+#endif
+
+ for (LVM_INT32 ii = 0; ii < NrSamples; ++ii) {
+ //TODO: replace with existing clamping function
+ if (pScratch[ii] < -1.0) {
+ pScratch[ii] = -1.0;
+ } else if (pScratch[ii] > 1.0) {
+ pScratch[ii] = 1.0;
+ }
+ }
+ } else {
+ // clear DBE processed path
+ memset(pScratch, 0, sizeof(*pScratch) * NrSamples);
+ }
+
+ /* Bypass Volume path is processed when DBE is OFF or during On/Off transitions */
+ if ((pInstance->Params.OperatingMode == LVDBE_OFF)||
+ (LVC_Mixer_GetCurrent(&pInstance->pData->BypassMixer.MixerStream[1])
+ !=LVC_Mixer_GetTarget(&pInstance->pData->BypassMixer.MixerStream[1])))
+ {
+
+ /*
+ * The algorithm is disabled but volume management is required to compensate for
+ * headroom and volume (if enabled)
+ */
+#ifdef SUPPORT_MC
+ LVC_MixSoft_Mc_D16C31_SAT(&pInstance->pData->BypassVolume,
+ pInData,
+ pScratchVol,
+ (LVM_INT16)NrFrames,
+ (LVM_INT16)NrChannels);
+#else
+ LVC_MixSoft_1St_D16C31_SAT(&pInstance->pData->BypassVolume,
+ pInData,
+ pScratchVol,
+ (LVM_INT16)NrSamples); /* Left and right, really # samples */
+#endif
+ } else {
+ // clear bypass volume path
+ memset(pScratchVol, 0, sizeof(*pScratchVol) * NrSamples);
+ }
+
+ /*
+ * Mix DBE processed path and bypass volume path
+ */
+#ifdef SUPPORT_MC
+ LVC_MixSoft_2Mc_D16C31_SAT(&pInstance->pData->BypassMixer,
+ pScratch,
+ pScratchVol,
+ pOutData,
+ (LVM_INT16)NrFrames,
+ (LVM_INT16)NrChannels);
+#else
+ LVC_MixSoft_2St_D16C31_SAT(&pInstance->pData->BypassMixer,
+ pScratch,
+ pScratchVol,
+ pOutData,
+ (LVM_INT16)NrSamples);
+#endif
+ return LVDBE_SUCCESS;
+}
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Tables.c b/media/libeffects/lvm/lib/Bass/src/LVDBE_Tables.c
deleted file mode 100644
index a2ce404..0000000
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Tables.c
+++ /dev/null
@@ -1,681 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-/************************************************************************************/
-/* */
-/* Includes */
-/* */
-/************************************************************************************/
-
-#include "LVDBE.h"
-#include "LVDBE_Coeffs.h" /* Filter coefficients */
-#include "BIQUAD.h"
-
-
-/************************************************************************************/
-/* */
-/* Coefficients constant table */
-/* */
-/************************************************************************************/
-
-/*
- * High Pass Filter Coefficient table
- */
-#ifndef BUILD_FLOAT
-const BQ_C32_Coefs_t LVDBE_HPF_Table[] = {
-#else /*BUILD_FLOAT*/
-const BQ_FLOAT_Coefs_t LVDBE_HPF_Table[] = {
-#endif /*BUILD_FLOAT*/
- /* Coefficients for 55Hz centre frequency */
- {HPF_Fs8000_Fc55_A2, /* 8kS/s coefficients */
- HPF_Fs8000_Fc55_A1,
- HPF_Fs8000_Fc55_A0,
- -HPF_Fs8000_Fc55_B2,
- -HPF_Fs8000_Fc55_B1},
- {HPF_Fs11025_Fc55_A2, /* 11kS/s coefficients */
- HPF_Fs11025_Fc55_A1,
- HPF_Fs11025_Fc55_A0,
- -HPF_Fs11025_Fc55_B2,
- -HPF_Fs11025_Fc55_B1},
- {HPF_Fs12000_Fc55_A2, /* 12kS/s coefficients */
- HPF_Fs12000_Fc55_A1,
- HPF_Fs12000_Fc55_A0,
- -HPF_Fs12000_Fc55_B2,
- -HPF_Fs12000_Fc55_B1},
- {HPF_Fs16000_Fc55_A2, /* 16kS/s coefficients */
- HPF_Fs16000_Fc55_A1,
- HPF_Fs16000_Fc55_A0,
- -HPF_Fs16000_Fc55_B2,
- -HPF_Fs16000_Fc55_B1},
- {HPF_Fs22050_Fc55_A2, /* 22kS/s coefficients */
- HPF_Fs22050_Fc55_A1,
- HPF_Fs22050_Fc55_A0,
- -HPF_Fs22050_Fc55_B2,
- -HPF_Fs22050_Fc55_B1},
- {HPF_Fs24000_Fc55_A2, /* 24kS/s coefficients */
- HPF_Fs24000_Fc55_A1,
- HPF_Fs24000_Fc55_A0,
- -HPF_Fs24000_Fc55_B2,
- -HPF_Fs24000_Fc55_B1},
- {HPF_Fs32000_Fc55_A2, /* 32kS/s coefficients */
- HPF_Fs32000_Fc55_A1,
- HPF_Fs32000_Fc55_A0,
- -HPF_Fs32000_Fc55_B2,
- -HPF_Fs32000_Fc55_B1},
- {HPF_Fs44100_Fc55_A2, /* 44kS/s coefficients */
- HPF_Fs44100_Fc55_A1,
- HPF_Fs44100_Fc55_A0,
- -HPF_Fs44100_Fc55_B2,
- -HPF_Fs44100_Fc55_B1},
- {HPF_Fs48000_Fc55_A2, /* 48kS/s coefficients */
- HPF_Fs48000_Fc55_A1,
- HPF_Fs48000_Fc55_A0,
- -HPF_Fs48000_Fc55_B2,
- -HPF_Fs48000_Fc55_B1},
-#ifdef HIGHER_FS
- {HPF_Fs88200_Fc55_A2, /* 88kS/s coefficients */
- HPF_Fs88200_Fc55_A1,
- HPF_Fs88200_Fc55_A0,
- -HPF_Fs88200_Fc55_B2,
- -HPF_Fs88200_Fc55_B1},
- {HPF_Fs96000_Fc55_A2, /* 96kS/s coefficients */
- HPF_Fs96000_Fc55_A1,
- HPF_Fs96000_Fc55_A0,
- -HPF_Fs96000_Fc55_B2,
- -HPF_Fs96000_Fc55_B1},
- {HPF_Fs176400_Fc55_A2, /* 176kS/s coefficients */
- HPF_Fs176400_Fc55_A1,
- HPF_Fs176400_Fc55_A0,
- -HPF_Fs176400_Fc55_B2,
- -HPF_Fs176400_Fc55_B1},
- {HPF_Fs192000_Fc55_A2, /* 192kS/s coefficients */
- HPF_Fs192000_Fc55_A1,
- HPF_Fs192000_Fc55_A0,
- -HPF_Fs192000_Fc55_B2,
- -HPF_Fs192000_Fc55_B1},
-#endif
-
- /* Coefficients for 66Hz centre frequency */
- {HPF_Fs8000_Fc66_A2, /* 8kS/s coefficients */
- HPF_Fs8000_Fc66_A1,
- HPF_Fs8000_Fc66_A0,
- -HPF_Fs8000_Fc66_B2,
- -HPF_Fs8000_Fc66_B1},
- {HPF_Fs11025_Fc66_A2, /* 11kS/s coefficients */
- HPF_Fs11025_Fc66_A1,
- HPF_Fs11025_Fc66_A0,
- -HPF_Fs11025_Fc66_B2,
- -HPF_Fs11025_Fc66_B1},
- {HPF_Fs12000_Fc66_A2, /* 12kS/s coefficients */
- HPF_Fs12000_Fc66_A1,
- HPF_Fs12000_Fc66_A0,
- -HPF_Fs12000_Fc66_B2,
- -HPF_Fs12000_Fc66_B1},
- {HPF_Fs16000_Fc66_A2, /* 16kS/s coefficients */
- HPF_Fs16000_Fc66_A1,
- HPF_Fs16000_Fc66_A0,
- -HPF_Fs16000_Fc66_B2,
- -HPF_Fs16000_Fc66_B1},
- {HPF_Fs22050_Fc66_A2, /* 22kS/s coefficients */
- HPF_Fs22050_Fc66_A1,
- HPF_Fs22050_Fc66_A0,
- -HPF_Fs22050_Fc66_B2,
- -HPF_Fs22050_Fc66_B1},
- {HPF_Fs24000_Fc66_A2, /* 24kS/s coefficients */
- HPF_Fs24000_Fc66_A1,
- HPF_Fs24000_Fc66_A0,
- -HPF_Fs24000_Fc66_B2,
- -HPF_Fs24000_Fc66_B1},
- {HPF_Fs32000_Fc66_A2, /* 32kS/s coefficients */
- HPF_Fs32000_Fc66_A1,
- HPF_Fs32000_Fc66_A0,
- -HPF_Fs32000_Fc66_B2,
- -HPF_Fs32000_Fc66_B1},
- {HPF_Fs44100_Fc66_A2, /* 44kS/s coefficients */
- HPF_Fs44100_Fc66_A1,
- HPF_Fs44100_Fc66_A0,
- -HPF_Fs44100_Fc66_B2,
- -HPF_Fs44100_Fc66_B1},
- {HPF_Fs48000_Fc66_A2, /* 48kS/s coefficients */
- HPF_Fs48000_Fc66_A1,
- HPF_Fs48000_Fc66_A0,
- -HPF_Fs48000_Fc66_B2,
- -HPF_Fs48000_Fc66_B1},
-#ifdef HIGHER_FS
- {HPF_Fs88200_Fc66_A2, /* 88kS/s coefficients */
- HPF_Fs88200_Fc66_A1,
- HPF_Fs88200_Fc66_A0,
- -HPF_Fs88200_Fc66_B2,
- -HPF_Fs88200_Fc66_B1},
- {HPF_Fs96000_Fc66_A2, /* 96kS/s coefficients */
- HPF_Fs96000_Fc66_A1,
- HPF_Fs96000_Fc66_A0,
- -HPF_Fs96000_Fc66_B2,
- -HPF_Fs96000_Fc66_B1},
- {HPF_Fs176400_Fc66_A2, /* 176kS/s coefficients */
- HPF_Fs176400_Fc66_A1,
- HPF_Fs176400_Fc66_A0,
- -HPF_Fs176400_Fc66_B2,
- -HPF_Fs176400_Fc66_B1},
- {HPF_Fs192000_Fc66_A2, /* 192kS/s coefficients */
- HPF_Fs192000_Fc66_A1,
- HPF_Fs192000_Fc66_A0,
- -HPF_Fs192000_Fc66_B2,
- -HPF_Fs192000_Fc66_B1},
-#endif
-
-
- /* Coefficients for 78Hz centre frequency */
- {HPF_Fs8000_Fc78_A2, /* 8kS/s coefficients */
- HPF_Fs8000_Fc78_A1,
- HPF_Fs8000_Fc78_A0,
- -HPF_Fs8000_Fc78_B2,
- -HPF_Fs8000_Fc78_B1},
- {HPF_Fs11025_Fc78_A2, /* 11kS/s coefficients */
- HPF_Fs11025_Fc78_A1,
- HPF_Fs11025_Fc78_A0,
- -HPF_Fs11025_Fc78_B2,
- -HPF_Fs11025_Fc78_B1},
- {HPF_Fs12000_Fc78_A2, /* 12kS/s coefficients */
- HPF_Fs12000_Fc78_A1,
- HPF_Fs12000_Fc78_A0,
- -HPF_Fs12000_Fc78_B2,
- -HPF_Fs12000_Fc78_B1},
- {HPF_Fs16000_Fc78_A2, /* 16kS/s coefficients */
- HPF_Fs16000_Fc78_A1,
- HPF_Fs16000_Fc78_A0,
- -HPF_Fs16000_Fc78_B2,
- -HPF_Fs16000_Fc78_B1},
- {HPF_Fs22050_Fc78_A2, /* 22kS/s coefficients */
- HPF_Fs22050_Fc78_A1,
- HPF_Fs22050_Fc78_A0,
- -HPF_Fs22050_Fc78_B2,
- -HPF_Fs22050_Fc78_B1},
- {HPF_Fs24000_Fc78_A2, /* 24kS/s coefficients */
- HPF_Fs24000_Fc78_A1,
- HPF_Fs24000_Fc78_A0,
- -HPF_Fs24000_Fc78_B2,
- -HPF_Fs24000_Fc78_B1},
- {HPF_Fs32000_Fc78_A2, /* 32kS/s coefficients */
- HPF_Fs32000_Fc78_A1,
- HPF_Fs32000_Fc78_A0,
- -HPF_Fs32000_Fc78_B2,
- -HPF_Fs32000_Fc78_B1},
- {HPF_Fs44100_Fc78_A2, /* 44kS/s coefficients */
- HPF_Fs44100_Fc78_A1,
- HPF_Fs44100_Fc78_A0,
- -HPF_Fs44100_Fc78_B2,
- -HPF_Fs44100_Fc78_B1},
- {HPF_Fs48000_Fc78_A2, /* 48kS/s coefficients */
- HPF_Fs48000_Fc78_A1,
- HPF_Fs48000_Fc78_A0,
- -HPF_Fs48000_Fc78_B2,
- -HPF_Fs48000_Fc78_B1},
-#ifdef HIGHER_FS
- {HPF_Fs88200_Fc78_A2, /* 88kS/s coefficients */
- HPF_Fs88200_Fc78_A1,
- HPF_Fs88200_Fc78_A0,
- -HPF_Fs88200_Fc78_B2,
- -HPF_Fs88200_Fc78_B1},
- {HPF_Fs96000_Fc78_A2, /* 96kS/s coefficients */
- HPF_Fs96000_Fc78_A1,
- HPF_Fs96000_Fc78_A0,
- -HPF_Fs96000_Fc78_B2,
- -HPF_Fs96000_Fc78_B1},
- {HPF_Fs176400_Fc78_A2, /* 176kS/s coefficients */
- HPF_Fs176400_Fc78_A1,
- HPF_Fs176400_Fc78_A0,
- -HPF_Fs176400_Fc78_B2,
- -HPF_Fs176400_Fc78_B1},
- {HPF_Fs192000_Fc78_A2, /* 192kS/s coefficients */
- HPF_Fs192000_Fc78_A1,
- HPF_Fs192000_Fc78_A0,
- -HPF_Fs192000_Fc78_B2,
- -HPF_Fs192000_Fc78_B1},
-#endif
-
-
- /* Coefficients for 90Hz centre frequency */
- {HPF_Fs8000_Fc90_A2, /* 8kS/s coefficients */
- HPF_Fs8000_Fc90_A1,
- HPF_Fs8000_Fc90_A0,
- -HPF_Fs8000_Fc90_B2,
- -HPF_Fs8000_Fc90_B1},
- {HPF_Fs11025_Fc90_A2, /* 11kS/s coefficients */
- HPF_Fs11025_Fc90_A1,
- HPF_Fs11025_Fc90_A0,
- -HPF_Fs11025_Fc90_B2,
- -HPF_Fs11025_Fc90_B1},
- {HPF_Fs12000_Fc90_A2, /* 12kS/s coefficients */
- HPF_Fs12000_Fc90_A1,
- HPF_Fs12000_Fc90_A0,
- -HPF_Fs12000_Fc90_B2,
- -HPF_Fs12000_Fc90_B1},
- {HPF_Fs16000_Fc90_A2, /* 16kS/s coefficients */
- HPF_Fs16000_Fc90_A1,
- HPF_Fs16000_Fc90_A0,
- -HPF_Fs16000_Fc90_B2,
- -HPF_Fs16000_Fc90_B1},
- {HPF_Fs22050_Fc90_A2, /* 22kS/s coefficients */
- HPF_Fs22050_Fc90_A1,
- HPF_Fs22050_Fc90_A0,
- -HPF_Fs22050_Fc90_B2,
- -HPF_Fs22050_Fc90_B1},
- {HPF_Fs24000_Fc90_A2, /* 24kS/s coefficients */
- HPF_Fs24000_Fc90_A1,
- HPF_Fs24000_Fc90_A0,
- -HPF_Fs24000_Fc90_B2,
- -HPF_Fs24000_Fc90_B1},
- {HPF_Fs32000_Fc90_A2, /* 32kS/s coefficients */
- HPF_Fs32000_Fc90_A1,
- HPF_Fs32000_Fc90_A0,
- -HPF_Fs32000_Fc90_B2,
- -HPF_Fs32000_Fc90_B1},
- {HPF_Fs44100_Fc90_A2, /* 44kS/s coefficients */
- HPF_Fs44100_Fc90_A1,
- HPF_Fs44100_Fc90_A0,
- -HPF_Fs44100_Fc90_B2,
- -HPF_Fs44100_Fc90_B1},
- {HPF_Fs48000_Fc90_A2, /* 48kS/s coefficients */
- HPF_Fs48000_Fc90_A1,
- HPF_Fs48000_Fc90_A0,
- -HPF_Fs48000_Fc90_B2,
- -HPF_Fs48000_Fc90_B1}
-
-#ifdef HIGHER_FS
- ,
- {HPF_Fs88200_Fc90_A2, /* 88kS/s coefficients */
- HPF_Fs88200_Fc90_A1,
- HPF_Fs88200_Fc90_A0,
- -HPF_Fs88200_Fc90_B2,
- -HPF_Fs88200_Fc90_B1},
- {HPF_Fs96000_Fc90_A2, /* 96kS/s coefficients */
- HPF_Fs96000_Fc90_A1,
- HPF_Fs96000_Fc90_A0,
- -HPF_Fs96000_Fc90_B2,
- -HPF_Fs96000_Fc90_B1},
- {HPF_Fs176400_Fc90_A2, /* 176kS/s coefficients */
- HPF_Fs176400_Fc90_A1,
- HPF_Fs176400_Fc90_A0,
- -HPF_Fs176400_Fc90_B2,
- -HPF_Fs176400_Fc90_B1},
- {HPF_Fs192000_Fc90_A2, /* 192kS/s coefficients */
- HPF_Fs192000_Fc90_A1,
- HPF_Fs192000_Fc90_A0,
- -HPF_Fs192000_Fc90_B2,
- -HPF_Fs192000_Fc90_B1}
-#endif
-
-};
-
-/*
- * Band Pass Filter coefficient table
- */
-#ifndef BUILD_FLOAT
-const BP_C32_Coefs_t LVDBE_BPF_Table[] = {
-#else /*BUILD_FLOAT*/
-const BP_FLOAT_Coefs_t LVDBE_BPF_Table[] = {
-#endif /*BUILD_FLOAT*/
- /* Coefficients for 55Hz centre frequency */
- {BPF_Fs8000_Fc55_A0, /* 8kS/s coefficients */
- -BPF_Fs8000_Fc55_B2,
- -BPF_Fs8000_Fc55_B1},
- {BPF_Fs11025_Fc55_A0, /* 11kS/s coefficients */
- -BPF_Fs11025_Fc55_B2,
- -BPF_Fs11025_Fc55_B1},
- {BPF_Fs12000_Fc55_A0, /* 12kS/s coefficients */
- -BPF_Fs12000_Fc55_B2,
- -BPF_Fs12000_Fc55_B1},
- {BPF_Fs16000_Fc55_A0, /* 16kS/s coefficients */
- -BPF_Fs16000_Fc55_B2,
- -BPF_Fs16000_Fc55_B1},
- {BPF_Fs22050_Fc55_A0, /* 22kS/s coefficients */
- -BPF_Fs22050_Fc55_B2,
- -BPF_Fs22050_Fc55_B1},
- {BPF_Fs24000_Fc55_A0, /* 24kS/s coefficients */
- -BPF_Fs24000_Fc55_B2,
- -BPF_Fs24000_Fc55_B1},
- {BPF_Fs32000_Fc55_A0, /* 32kS/s coefficients */
- -BPF_Fs32000_Fc55_B2,
- -BPF_Fs32000_Fc55_B1},
- {BPF_Fs44100_Fc55_A0, /* 44kS/s coefficients */
- -BPF_Fs44100_Fc55_B2,
- -BPF_Fs44100_Fc55_B1},
- {BPF_Fs48000_Fc55_A0, /* 48kS/s coefficients */
- -BPF_Fs48000_Fc55_B2,
- -BPF_Fs48000_Fc55_B1},
-#ifdef HIGHER_FS
- {BPF_Fs88200_Fc55_A0, /* 88kS/s coefficients */
- -BPF_Fs88200_Fc55_B2,
- -BPF_Fs88200_Fc55_B1},
- {BPF_Fs96000_Fc55_A0, /* 96kS/s coefficients */
- -BPF_Fs96000_Fc55_B2,
- -BPF_Fs96000_Fc55_B1},
- {BPF_Fs176400_Fc55_A0, /* 176kS/s coefficients */
- -BPF_Fs176400_Fc55_B2,
- -BPF_Fs176400_Fc55_B1},
- {BPF_Fs192000_Fc55_A0, /* 192kS/s coefficients */
- -BPF_Fs192000_Fc55_B2,
- -BPF_Fs192000_Fc55_B1},
-#endif
-
- /* Coefficients for 66Hz centre frequency */
- {BPF_Fs8000_Fc66_A0, /* 8kS/s coefficients */
- -BPF_Fs8000_Fc66_B2,
- -BPF_Fs8000_Fc66_B1},
- {BPF_Fs11025_Fc66_A0, /* 11kS/s coefficients */
- -BPF_Fs11025_Fc66_B2,
- -BPF_Fs11025_Fc66_B1},
- {BPF_Fs12000_Fc66_A0, /* 12kS/s coefficients */
- -BPF_Fs12000_Fc66_B2,
- -BPF_Fs12000_Fc66_B1},
- {BPF_Fs16000_Fc66_A0, /* 16kS/s coefficients */
- -BPF_Fs16000_Fc66_B2,
- -BPF_Fs16000_Fc66_B1},
- {BPF_Fs22050_Fc66_A0, /* 22kS/s coefficients */
- -BPF_Fs22050_Fc66_B2,
- -BPF_Fs22050_Fc66_B1},
- {BPF_Fs24000_Fc66_A0, /* 24kS/s coefficients */
- -BPF_Fs24000_Fc66_B2,
- -BPF_Fs24000_Fc66_B1},
- {BPF_Fs32000_Fc66_A0, /* 32kS/s coefficients */
- -BPF_Fs32000_Fc66_B2,
- -BPF_Fs32000_Fc66_B1},
- {BPF_Fs44100_Fc66_A0, /* 44kS/s coefficients */
- -BPF_Fs44100_Fc66_B2,
- -BPF_Fs44100_Fc66_B1},
- {BPF_Fs48000_Fc66_A0, /* 48kS/s coefficients */
- -BPF_Fs48000_Fc66_B2,
- -BPF_Fs48000_Fc66_B1},
-#ifdef HIGHER_FS
- {BPF_Fs88200_Fc66_A0, /* 88kS/s coefficients */
- -BPF_Fs88200_Fc66_B2,
- -BPF_Fs88200_Fc66_B1},
- {BPF_Fs96000_Fc66_A0, /* 96kS/s coefficients */
- -BPF_Fs96000_Fc66_B2,
- -BPF_Fs96000_Fc66_B1},
- {BPF_Fs176400_Fc66_A0, /* 176kS/s coefficients */
- -BPF_Fs176400_Fc66_B2,
- -BPF_Fs176400_Fc66_B1},
- {BPF_Fs192000_Fc66_A0, /* 192kS/s coefficients */
- -BPF_Fs192000_Fc66_B2,
- -BPF_Fs192000_Fc66_B1},
-#endif
-
- /* Coefficients for 78Hz centre frequency */
- {BPF_Fs8000_Fc78_A0, /* 8kS/s coefficients */
- -BPF_Fs8000_Fc78_B2,
- -BPF_Fs8000_Fc78_B1},
- {BPF_Fs11025_Fc78_A0, /* 11kS/s coefficients */
- -BPF_Fs11025_Fc78_B2,
- -BPF_Fs11025_Fc78_B1},
- {BPF_Fs12000_Fc78_A0, /* 12kS/s coefficients */
- -BPF_Fs12000_Fc78_B2,
- -BPF_Fs12000_Fc78_B1},
- {BPF_Fs16000_Fc78_A0, /* 16kS/s coefficients */
- -BPF_Fs16000_Fc78_B2,
- -BPF_Fs16000_Fc78_B1},
- {BPF_Fs22050_Fc78_A0, /* 22kS/s coefficients */
- -BPF_Fs22050_Fc78_B2,
- -BPF_Fs22050_Fc78_B1},
- {BPF_Fs24000_Fc78_A0, /* 24kS/s coefficients */
- -BPF_Fs24000_Fc78_B2,
- -BPF_Fs24000_Fc78_B1},
- {BPF_Fs32000_Fc78_A0, /* 32kS/s coefficients */
- -BPF_Fs32000_Fc78_B2,
- -BPF_Fs32000_Fc78_B1},
- {BPF_Fs44100_Fc78_A0, /* 44kS/s coefficients */
- -BPF_Fs44100_Fc78_B2,
- -BPF_Fs44100_Fc78_B1},
- {BPF_Fs48000_Fc78_A0, /* 48kS/s coefficients */
- -BPF_Fs48000_Fc78_B2,
- -BPF_Fs48000_Fc78_B1},
-#ifdef HIGHER_FS
- {BPF_Fs88200_Fc66_A0, /* 88kS/s coefficients */
- -BPF_Fs88200_Fc66_B2,
- -BPF_Fs88200_Fc66_B1},
- {BPF_Fs96000_Fc78_A0, /* 96kS/s coefficients */
- -BPF_Fs96000_Fc78_B2,
- -BPF_Fs96000_Fc78_B1},
- {BPF_Fs176400_Fc66_A0, /* 176kS/s coefficients */
- -BPF_Fs176400_Fc66_B2,
- -BPF_Fs176400_Fc66_B1},
- {BPF_Fs192000_Fc78_A0, /* 192kS/s coefficients */
- -BPF_Fs192000_Fc78_B2,
- -BPF_Fs192000_Fc78_B1},
-#endif
-
- /* Coefficients for 90Hz centre frequency */
- {BPF_Fs8000_Fc90_A0, /* 8kS/s coefficients */
- -BPF_Fs8000_Fc90_B2,
- -BPF_Fs8000_Fc90_B1},
- {BPF_Fs11025_Fc90_A0, /* 11kS/s coefficients */
- -BPF_Fs11025_Fc90_B2,
- -BPF_Fs11025_Fc90_B1},
- {BPF_Fs12000_Fc90_A0, /* 12kS/s coefficients */
- -BPF_Fs12000_Fc90_B2,
- -BPF_Fs12000_Fc90_B1},
- {BPF_Fs16000_Fc90_A0, /* 16kS/s coefficients */
- -BPF_Fs16000_Fc90_B2,
- -BPF_Fs16000_Fc90_B1},
- {BPF_Fs22050_Fc90_A0, /* 22kS/s coefficients */
- -BPF_Fs22050_Fc90_B2,
- -BPF_Fs22050_Fc90_B1},
- {BPF_Fs24000_Fc90_A0, /* 24kS/s coefficients */
- -BPF_Fs24000_Fc90_B2,
- -BPF_Fs24000_Fc90_B1},
- {BPF_Fs32000_Fc90_A0, /* 32kS/s coefficients */
- -BPF_Fs32000_Fc90_B2,
- -BPF_Fs32000_Fc90_B1},
- {BPF_Fs44100_Fc90_A0, /* 44kS/s coefficients */
- -BPF_Fs44100_Fc90_B2,
- -BPF_Fs44100_Fc90_B1},
- {BPF_Fs48000_Fc90_A0, /* 48kS/s coefficients */
- -BPF_Fs48000_Fc90_B2,
- -BPF_Fs48000_Fc90_B1}
-#ifdef HIGHER_FS
- ,
- {BPF_Fs88200_Fc90_A0, /* 88kS/s coefficients */
- -BPF_Fs88200_Fc90_B2,
- -BPF_Fs88200_Fc90_B1},
- {BPF_Fs96000_Fc90_A0, /* 96kS/s coefficients */
- -BPF_Fs96000_Fc90_B2,
- -BPF_Fs96000_Fc90_B1},
- {BPF_Fs176400_Fc90_A0, /* 176kS/s coefficients */
- -BPF_Fs176400_Fc90_B2,
- -BPF_Fs176400_Fc90_B1},
- {BPF_Fs192000_Fc90_A0, /* 192kS/s coefficients */
- -BPF_Fs192000_Fc90_B2,
- -BPF_Fs192000_Fc90_B1}
-#endif
-
-
-};
-
-
-/************************************************************************************/
-/* */
-/* AGC constant tables */
-/* */
-/************************************************************************************/
-
-/* Attack time (signal too large) */
-#ifndef BUILD_FLOAT
-const LVM_INT16 LVDBE_AGC_ATTACK_Table[] = {
-#else /*BUILD_FLOAT*/
-const LVM_FLOAT LVDBE_AGC_ATTACK_Table[] = {
-#endif /*BUILD_FLOAT*/
- AGC_ATTACK_Fs8000,
- AGC_ATTACK_Fs11025,
- AGC_ATTACK_Fs12000,
- AGC_ATTACK_Fs16000,
- AGC_ATTACK_Fs22050,
- AGC_ATTACK_Fs24000,
- AGC_ATTACK_Fs32000,
- AGC_ATTACK_Fs44100,
- AGC_ATTACK_Fs48000
-#ifdef HIGHER_FS
- ,AGC_ATTACK_Fs88200
- ,AGC_ATTACK_Fs96000
- ,AGC_ATTACK_Fs176400
- ,AGC_ATTACK_Fs192000
-#endif
-
-};
-
-/* Decay time (signal too small) */
-#ifndef BUILD_FLOAT
-const LVM_INT16 LVDBE_AGC_DECAY_Table[] = {
-#else /*BUILD_FLOAT*/
-const LVM_FLOAT LVDBE_AGC_DECAY_Table[] = {
-#endif /*BUILD_FLOAT*/
- AGC_DECAY_Fs8000,
- AGC_DECAY_Fs11025,
- AGC_DECAY_Fs12000,
- AGC_DECAY_Fs16000,
- AGC_DECAY_Fs22050,
- AGC_DECAY_Fs24000,
- AGC_DECAY_Fs32000,
- AGC_DECAY_Fs44100,
- AGC_DECAY_Fs48000
-#ifdef HIGHER_FS
- ,AGC_DECAY_Fs88200
- ,AGC_DECAY_FS96000
- ,AGC_DECAY_Fs176400
- ,AGC_DECAY_FS192000
-#endif
-
-};
-
-/* Gain for use without the high pass filter */
-#ifndef BUILD_FLOAT
-const LVM_INT32 LVDBE_AGC_GAIN_Table[] = {
-#else /*BUILD_FLOAT*/
-const LVM_FLOAT LVDBE_AGC_GAIN_Table[] = {
-#endif /*BUILD_FLOAT*/
- AGC_GAIN_0dB,
- AGC_GAIN_1dB,
- AGC_GAIN_2dB,
- AGC_GAIN_3dB,
- AGC_GAIN_4dB,
- AGC_GAIN_5dB,
- AGC_GAIN_6dB,
- AGC_GAIN_7dB,
- AGC_GAIN_8dB,
- AGC_GAIN_9dB,
- AGC_GAIN_10dB,
- AGC_GAIN_11dB,
- AGC_GAIN_12dB,
- AGC_GAIN_13dB,
- AGC_GAIN_14dB,
- AGC_GAIN_15dB};
-
-/* Gain for use with the high pass filter */
-#ifndef BUILD_FLOAT
-const LVM_INT32 LVDBE_AGC_HPFGAIN_Table[] = {
-#else /*BUILD_FLOAT*/
-const LVM_FLOAT LVDBE_AGC_HPFGAIN_Table[] = {
-#endif /*BUILD_FLOAT*/
- AGC_HPFGAIN_0dB,
- AGC_HPFGAIN_1dB,
- AGC_HPFGAIN_2dB,
- AGC_HPFGAIN_3dB,
- AGC_HPFGAIN_4dB,
- AGC_HPFGAIN_5dB,
- AGC_HPFGAIN_6dB,
- AGC_HPFGAIN_7dB,
- AGC_HPFGAIN_8dB,
- AGC_HPFGAIN_9dB,
- AGC_HPFGAIN_10dB,
- AGC_HPFGAIN_11dB,
- AGC_HPFGAIN_12dB,
- AGC_HPFGAIN_13dB,
- AGC_HPFGAIN_14dB,
- AGC_HPFGAIN_15dB};
-
-
-/************************************************************************************/
-/* */
-/* Volume control gain and time constant tables */
-/* */
-/************************************************************************************/
-
-/* dB to linear conversion table */
-#ifndef BUILD_FLOAT
-const LVM_INT16 LVDBE_VolumeTable[] = {
- 0x4000, /* -6dB */
- 0x47FB, /* -5dB */
- 0x50C3, /* -4dB */
- 0x5A9E, /* -3dB */
- 0x65AD, /* -2dB */
- 0x7215, /* -1dB */
- 0x7FFF}; /* 0dB */
-#else /*BUILD_FLOAT*/
-const LVM_FLOAT LVDBE_VolumeTable[] = {
- 0.500000f, /* -6dB */
- 0.562341f, /* -5dB */
- 0.630957f, /* -4dB */
- 0.707946f, /* -3dB */
- 0.794328f, /* -2dB */
- 0.891251f, /* -1dB */
- 1.000000f}; /* 0dB */
-#endif /*BUILD_FLOAT*/
-
-#ifndef BUILD_FLOAT
-const LVM_INT16 LVDBE_VolumeTCTable[] = {
-#else /*BUILD_FLOAT*/
-const LVM_FLOAT LVDBE_VolumeTCTable[] = {
-#endif /*BUILD_FLOAT*/
- VOL_TC_Fs8000,
- VOL_TC_Fs11025,
- VOL_TC_Fs12000,
- VOL_TC_Fs16000,
- VOL_TC_Fs22050,
- VOL_TC_Fs24000,
- VOL_TC_Fs32000,
- VOL_TC_Fs44100,
- VOL_TC_Fs48000
-#ifdef HIGHER_FS
- ,VOL_TC_Fs88200
- ,VOL_TC_Fs96000
- ,VOL_TC_Fs176400
- ,VOL_TC_Fs192000
-#endif
-};
-
-
-
-const LVM_INT16 LVDBE_MixerTCTable[] = {
-
- MIX_TC_Fs8000,
- MIX_TC_Fs11025,
- MIX_TC_Fs12000,
- MIX_TC_Fs16000,
- MIX_TC_Fs22050,
- MIX_TC_Fs24000,
- MIX_TC_Fs32000,
- MIX_TC_Fs44100,
- MIX_TC_Fs48000
-#ifdef HIGHER_FS
- ,MIX_TC_Fs88200
- ,MIX_TC_Fs96000
- ,MIX_TC_Fs176400
- ,MIX_TC_Fs192000
-#endif
-
-};
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Tables.cpp b/media/libeffects/lvm/lib/Bass/src/LVDBE_Tables.cpp
new file mode 100644
index 0000000..728575c
--- /dev/null
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Tables.cpp
@@ -0,0 +1,610 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/************************************************************************************/
+/* */
+/* Includes */
+/* */
+/************************************************************************************/
+
+#include "LVDBE.h"
+#include "LVDBE_Coeffs.h" /* Filter coefficients */
+#include "LVDBE_Tables.h"
+#include "BIQUAD.h"
+
+/************************************************************************************/
+/* */
+/* Coefficients constant table */
+/* */
+/************************************************************************************/
+
+/*
+ * High Pass Filter Coefficient table
+ */
+const BQ_FLOAT_Coefs_t LVDBE_HPF_Table[] = {
+ /* Coefficients for 55Hz centre frequency */
+ {HPF_Fs8000_Fc55_A2, /* 8kS/s coefficients */
+ HPF_Fs8000_Fc55_A1,
+ HPF_Fs8000_Fc55_A0,
+ -HPF_Fs8000_Fc55_B2,
+ -HPF_Fs8000_Fc55_B1},
+ {HPF_Fs11025_Fc55_A2, /* 11kS/s coefficients */
+ HPF_Fs11025_Fc55_A1,
+ HPF_Fs11025_Fc55_A0,
+ -HPF_Fs11025_Fc55_B2,
+ -HPF_Fs11025_Fc55_B1},
+ {HPF_Fs12000_Fc55_A2, /* 12kS/s coefficients */
+ HPF_Fs12000_Fc55_A1,
+ HPF_Fs12000_Fc55_A0,
+ -HPF_Fs12000_Fc55_B2,
+ -HPF_Fs12000_Fc55_B1},
+ {HPF_Fs16000_Fc55_A2, /* 16kS/s coefficients */
+ HPF_Fs16000_Fc55_A1,
+ HPF_Fs16000_Fc55_A0,
+ -HPF_Fs16000_Fc55_B2,
+ -HPF_Fs16000_Fc55_B1},
+ {HPF_Fs22050_Fc55_A2, /* 22kS/s coefficients */
+ HPF_Fs22050_Fc55_A1,
+ HPF_Fs22050_Fc55_A0,
+ -HPF_Fs22050_Fc55_B2,
+ -HPF_Fs22050_Fc55_B1},
+ {HPF_Fs24000_Fc55_A2, /* 24kS/s coefficients */
+ HPF_Fs24000_Fc55_A1,
+ HPF_Fs24000_Fc55_A0,
+ -HPF_Fs24000_Fc55_B2,
+ -HPF_Fs24000_Fc55_B1},
+ {HPF_Fs32000_Fc55_A2, /* 32kS/s coefficients */
+ HPF_Fs32000_Fc55_A1,
+ HPF_Fs32000_Fc55_A0,
+ -HPF_Fs32000_Fc55_B2,
+ -HPF_Fs32000_Fc55_B1},
+ {HPF_Fs44100_Fc55_A2, /* 44kS/s coefficients */
+ HPF_Fs44100_Fc55_A1,
+ HPF_Fs44100_Fc55_A0,
+ -HPF_Fs44100_Fc55_B2,
+ -HPF_Fs44100_Fc55_B1},
+ {HPF_Fs48000_Fc55_A2, /* 48kS/s coefficients */
+ HPF_Fs48000_Fc55_A1,
+ HPF_Fs48000_Fc55_A0,
+ -HPF_Fs48000_Fc55_B2,
+ -HPF_Fs48000_Fc55_B1},
+ {HPF_Fs88200_Fc55_A2, /* 88kS/s coefficients */
+ HPF_Fs88200_Fc55_A1,
+ HPF_Fs88200_Fc55_A0,
+ -HPF_Fs88200_Fc55_B2,
+ -HPF_Fs88200_Fc55_B1},
+ {HPF_Fs96000_Fc55_A2, /* 96kS/s coefficients */
+ HPF_Fs96000_Fc55_A1,
+ HPF_Fs96000_Fc55_A0,
+ -HPF_Fs96000_Fc55_B2,
+ -HPF_Fs96000_Fc55_B1},
+ {HPF_Fs176400_Fc55_A2, /* 176kS/s coefficients */
+ HPF_Fs176400_Fc55_A1,
+ HPF_Fs176400_Fc55_A0,
+ -HPF_Fs176400_Fc55_B2,
+ -HPF_Fs176400_Fc55_B1},
+ {HPF_Fs192000_Fc55_A2, /* 192kS/s coefficients */
+ HPF_Fs192000_Fc55_A1,
+ HPF_Fs192000_Fc55_A0,
+ -HPF_Fs192000_Fc55_B2,
+ -HPF_Fs192000_Fc55_B1},
+
+ /* Coefficients for 66Hz centre frequency */
+ {HPF_Fs8000_Fc66_A2, /* 8kS/s coefficients */
+ HPF_Fs8000_Fc66_A1,
+ HPF_Fs8000_Fc66_A0,
+ -HPF_Fs8000_Fc66_B2,
+ -HPF_Fs8000_Fc66_B1},
+ {HPF_Fs11025_Fc66_A2, /* 11kS/s coefficients */
+ HPF_Fs11025_Fc66_A1,
+ HPF_Fs11025_Fc66_A0,
+ -HPF_Fs11025_Fc66_B2,
+ -HPF_Fs11025_Fc66_B1},
+ {HPF_Fs12000_Fc66_A2, /* 12kS/s coefficients */
+ HPF_Fs12000_Fc66_A1,
+ HPF_Fs12000_Fc66_A0,
+ -HPF_Fs12000_Fc66_B2,
+ -HPF_Fs12000_Fc66_B1},
+ {HPF_Fs16000_Fc66_A2, /* 16kS/s coefficients */
+ HPF_Fs16000_Fc66_A1,
+ HPF_Fs16000_Fc66_A0,
+ -HPF_Fs16000_Fc66_B2,
+ -HPF_Fs16000_Fc66_B1},
+ {HPF_Fs22050_Fc66_A2, /* 22kS/s coefficients */
+ HPF_Fs22050_Fc66_A1,
+ HPF_Fs22050_Fc66_A0,
+ -HPF_Fs22050_Fc66_B2,
+ -HPF_Fs22050_Fc66_B1},
+ {HPF_Fs24000_Fc66_A2, /* 24kS/s coefficients */
+ HPF_Fs24000_Fc66_A1,
+ HPF_Fs24000_Fc66_A0,
+ -HPF_Fs24000_Fc66_B2,
+ -HPF_Fs24000_Fc66_B1},
+ {HPF_Fs32000_Fc66_A2, /* 32kS/s coefficients */
+ HPF_Fs32000_Fc66_A1,
+ HPF_Fs32000_Fc66_A0,
+ -HPF_Fs32000_Fc66_B2,
+ -HPF_Fs32000_Fc66_B1},
+ {HPF_Fs44100_Fc66_A2, /* 44kS/s coefficients */
+ HPF_Fs44100_Fc66_A1,
+ HPF_Fs44100_Fc66_A0,
+ -HPF_Fs44100_Fc66_B2,
+ -HPF_Fs44100_Fc66_B1},
+ {HPF_Fs48000_Fc66_A2, /* 48kS/s coefficients */
+ HPF_Fs48000_Fc66_A1,
+ HPF_Fs48000_Fc66_A0,
+ -HPF_Fs48000_Fc66_B2,
+ -HPF_Fs48000_Fc66_B1},
+ {HPF_Fs88200_Fc66_A2, /* 88kS/s coefficients */
+ HPF_Fs88200_Fc66_A1,
+ HPF_Fs88200_Fc66_A0,
+ -HPF_Fs88200_Fc66_B2,
+ -HPF_Fs88200_Fc66_B1},
+ {HPF_Fs96000_Fc66_A2, /* 96kS/s coefficients */
+ HPF_Fs96000_Fc66_A1,
+ HPF_Fs96000_Fc66_A0,
+ -HPF_Fs96000_Fc66_B2,
+ -HPF_Fs96000_Fc66_B1},
+ {HPF_Fs176400_Fc66_A2, /* 176kS/s coefficients */
+ HPF_Fs176400_Fc66_A1,
+ HPF_Fs176400_Fc66_A0,
+ -HPF_Fs176400_Fc66_B2,
+ -HPF_Fs176400_Fc66_B1},
+ {HPF_Fs192000_Fc66_A2, /* 192kS/s coefficients */
+ HPF_Fs192000_Fc66_A1,
+ HPF_Fs192000_Fc66_A0,
+ -HPF_Fs192000_Fc66_B2,
+ -HPF_Fs192000_Fc66_B1},
+
+ /* Coefficients for 78Hz centre frequency */
+ {HPF_Fs8000_Fc78_A2, /* 8kS/s coefficients */
+ HPF_Fs8000_Fc78_A1,
+ HPF_Fs8000_Fc78_A0,
+ -HPF_Fs8000_Fc78_B2,
+ -HPF_Fs8000_Fc78_B1},
+ {HPF_Fs11025_Fc78_A2, /* 11kS/s coefficients */
+ HPF_Fs11025_Fc78_A1,
+ HPF_Fs11025_Fc78_A0,
+ -HPF_Fs11025_Fc78_B2,
+ -HPF_Fs11025_Fc78_B1},
+ {HPF_Fs12000_Fc78_A2, /* 12kS/s coefficients */
+ HPF_Fs12000_Fc78_A1,
+ HPF_Fs12000_Fc78_A0,
+ -HPF_Fs12000_Fc78_B2,
+ -HPF_Fs12000_Fc78_B1},
+ {HPF_Fs16000_Fc78_A2, /* 16kS/s coefficients */
+ HPF_Fs16000_Fc78_A1,
+ HPF_Fs16000_Fc78_A0,
+ -HPF_Fs16000_Fc78_B2,
+ -HPF_Fs16000_Fc78_B1},
+ {HPF_Fs22050_Fc78_A2, /* 22kS/s coefficients */
+ HPF_Fs22050_Fc78_A1,
+ HPF_Fs22050_Fc78_A0,
+ -HPF_Fs22050_Fc78_B2,
+ -HPF_Fs22050_Fc78_B1},
+ {HPF_Fs24000_Fc78_A2, /* 24kS/s coefficients */
+ HPF_Fs24000_Fc78_A1,
+ HPF_Fs24000_Fc78_A0,
+ -HPF_Fs24000_Fc78_B2,
+ -HPF_Fs24000_Fc78_B1},
+ {HPF_Fs32000_Fc78_A2, /* 32kS/s coefficients */
+ HPF_Fs32000_Fc78_A1,
+ HPF_Fs32000_Fc78_A0,
+ -HPF_Fs32000_Fc78_B2,
+ -HPF_Fs32000_Fc78_B1},
+ {HPF_Fs44100_Fc78_A2, /* 44kS/s coefficients */
+ HPF_Fs44100_Fc78_A1,
+ HPF_Fs44100_Fc78_A0,
+ -HPF_Fs44100_Fc78_B2,
+ -HPF_Fs44100_Fc78_B1},
+ {HPF_Fs48000_Fc78_A2, /* 48kS/s coefficients */
+ HPF_Fs48000_Fc78_A1,
+ HPF_Fs48000_Fc78_A0,
+ -HPF_Fs48000_Fc78_B2,
+ -HPF_Fs48000_Fc78_B1},
+ {HPF_Fs88200_Fc78_A2, /* 88kS/s coefficients */
+ HPF_Fs88200_Fc78_A1,
+ HPF_Fs88200_Fc78_A0,
+ -HPF_Fs88200_Fc78_B2,
+ -HPF_Fs88200_Fc78_B1},
+ {HPF_Fs96000_Fc78_A2, /* 96kS/s coefficients */
+ HPF_Fs96000_Fc78_A1,
+ HPF_Fs96000_Fc78_A0,
+ -HPF_Fs96000_Fc78_B2,
+ -HPF_Fs96000_Fc78_B1},
+ {HPF_Fs176400_Fc78_A2, /* 176kS/s coefficients */
+ HPF_Fs176400_Fc78_A1,
+ HPF_Fs176400_Fc78_A0,
+ -HPF_Fs176400_Fc78_B2,
+ -HPF_Fs176400_Fc78_B1},
+ {HPF_Fs192000_Fc78_A2, /* 192kS/s coefficients */
+ HPF_Fs192000_Fc78_A1,
+ HPF_Fs192000_Fc78_A0,
+ -HPF_Fs192000_Fc78_B2,
+ -HPF_Fs192000_Fc78_B1},
+
+ /* Coefficients for 90Hz centre frequency */
+ {HPF_Fs8000_Fc90_A2, /* 8kS/s coefficients */
+ HPF_Fs8000_Fc90_A1,
+ HPF_Fs8000_Fc90_A0,
+ -HPF_Fs8000_Fc90_B2,
+ -HPF_Fs8000_Fc90_B1},
+ {HPF_Fs11025_Fc90_A2, /* 11kS/s coefficients */
+ HPF_Fs11025_Fc90_A1,
+ HPF_Fs11025_Fc90_A0,
+ -HPF_Fs11025_Fc90_B2,
+ -HPF_Fs11025_Fc90_B1},
+ {HPF_Fs12000_Fc90_A2, /* 12kS/s coefficients */
+ HPF_Fs12000_Fc90_A1,
+ HPF_Fs12000_Fc90_A0,
+ -HPF_Fs12000_Fc90_B2,
+ -HPF_Fs12000_Fc90_B1},
+ {HPF_Fs16000_Fc90_A2, /* 16kS/s coefficients */
+ HPF_Fs16000_Fc90_A1,
+ HPF_Fs16000_Fc90_A0,
+ -HPF_Fs16000_Fc90_B2,
+ -HPF_Fs16000_Fc90_B1},
+ {HPF_Fs22050_Fc90_A2, /* 22kS/s coefficients */
+ HPF_Fs22050_Fc90_A1,
+ HPF_Fs22050_Fc90_A0,
+ -HPF_Fs22050_Fc90_B2,
+ -HPF_Fs22050_Fc90_B1},
+ {HPF_Fs24000_Fc90_A2, /* 24kS/s coefficients */
+ HPF_Fs24000_Fc90_A1,
+ HPF_Fs24000_Fc90_A0,
+ -HPF_Fs24000_Fc90_B2,
+ -HPF_Fs24000_Fc90_B1},
+ {HPF_Fs32000_Fc90_A2, /* 32kS/s coefficients */
+ HPF_Fs32000_Fc90_A1,
+ HPF_Fs32000_Fc90_A0,
+ -HPF_Fs32000_Fc90_B2,
+ -HPF_Fs32000_Fc90_B1},
+ {HPF_Fs44100_Fc90_A2, /* 44kS/s coefficients */
+ HPF_Fs44100_Fc90_A1,
+ HPF_Fs44100_Fc90_A0,
+ -HPF_Fs44100_Fc90_B2,
+ -HPF_Fs44100_Fc90_B1},
+ {HPF_Fs48000_Fc90_A2, /* 48kS/s coefficients */
+ HPF_Fs48000_Fc90_A1,
+ HPF_Fs48000_Fc90_A0,
+ -HPF_Fs48000_Fc90_B2,
+ -HPF_Fs48000_Fc90_B1}
+
+ ,
+ {HPF_Fs88200_Fc90_A2, /* 88kS/s coefficients */
+ HPF_Fs88200_Fc90_A1,
+ HPF_Fs88200_Fc90_A0,
+ -HPF_Fs88200_Fc90_B2,
+ -HPF_Fs88200_Fc90_B1},
+ {HPF_Fs96000_Fc90_A2, /* 96kS/s coefficients */
+ HPF_Fs96000_Fc90_A1,
+ HPF_Fs96000_Fc90_A0,
+ -HPF_Fs96000_Fc90_B2,
+ -HPF_Fs96000_Fc90_B1},
+ {HPF_Fs176400_Fc90_A2, /* 176kS/s coefficients */
+ HPF_Fs176400_Fc90_A1,
+ HPF_Fs176400_Fc90_A0,
+ -HPF_Fs176400_Fc90_B2,
+ -HPF_Fs176400_Fc90_B1},
+ {HPF_Fs192000_Fc90_A2, /* 192kS/s coefficients */
+ HPF_Fs192000_Fc90_A1,
+ HPF_Fs192000_Fc90_A0,
+ -HPF_Fs192000_Fc90_B2,
+ -HPF_Fs192000_Fc90_B1}
+
+};
+
+/*
+ * Band Pass Filter coefficient table
+ */
+const BP_FLOAT_Coefs_t LVDBE_BPF_Table[] = {
+ /* Coefficients for 55Hz centre frequency */
+ {BPF_Fs8000_Fc55_A0, /* 8kS/s coefficients */
+ -BPF_Fs8000_Fc55_B2,
+ -BPF_Fs8000_Fc55_B1},
+ {BPF_Fs11025_Fc55_A0, /* 11kS/s coefficients */
+ -BPF_Fs11025_Fc55_B2,
+ -BPF_Fs11025_Fc55_B1},
+ {BPF_Fs12000_Fc55_A0, /* 12kS/s coefficients */
+ -BPF_Fs12000_Fc55_B2,
+ -BPF_Fs12000_Fc55_B1},
+ {BPF_Fs16000_Fc55_A0, /* 16kS/s coefficients */
+ -BPF_Fs16000_Fc55_B2,
+ -BPF_Fs16000_Fc55_B1},
+ {BPF_Fs22050_Fc55_A0, /* 22kS/s coefficients */
+ -BPF_Fs22050_Fc55_B2,
+ -BPF_Fs22050_Fc55_B1},
+ {BPF_Fs24000_Fc55_A0, /* 24kS/s coefficients */
+ -BPF_Fs24000_Fc55_B2,
+ -BPF_Fs24000_Fc55_B1},
+ {BPF_Fs32000_Fc55_A0, /* 32kS/s coefficients */
+ -BPF_Fs32000_Fc55_B2,
+ -BPF_Fs32000_Fc55_B1},
+ {BPF_Fs44100_Fc55_A0, /* 44kS/s coefficients */
+ -BPF_Fs44100_Fc55_B2,
+ -BPF_Fs44100_Fc55_B1},
+ {BPF_Fs48000_Fc55_A0, /* 48kS/s coefficients */
+ -BPF_Fs48000_Fc55_B2,
+ -BPF_Fs48000_Fc55_B1},
+ {BPF_Fs88200_Fc55_A0, /* 88kS/s coefficients */
+ -BPF_Fs88200_Fc55_B2,
+ -BPF_Fs88200_Fc55_B1},
+ {BPF_Fs96000_Fc55_A0, /* 96kS/s coefficients */
+ -BPF_Fs96000_Fc55_B2,
+ -BPF_Fs96000_Fc55_B1},
+ {BPF_Fs176400_Fc55_A0, /* 176kS/s coefficients */
+ -BPF_Fs176400_Fc55_B2,
+ -BPF_Fs176400_Fc55_B1},
+ {BPF_Fs192000_Fc55_A0, /* 192kS/s coefficients */
+ -BPF_Fs192000_Fc55_B2,
+ -BPF_Fs192000_Fc55_B1},
+
+ /* Coefficients for 66Hz centre frequency */
+ {BPF_Fs8000_Fc66_A0, /* 8kS/s coefficients */
+ -BPF_Fs8000_Fc66_B2,
+ -BPF_Fs8000_Fc66_B1},
+ {BPF_Fs11025_Fc66_A0, /* 11kS/s coefficients */
+ -BPF_Fs11025_Fc66_B2,
+ -BPF_Fs11025_Fc66_B1},
+ {BPF_Fs12000_Fc66_A0, /* 12kS/s coefficients */
+ -BPF_Fs12000_Fc66_B2,
+ -BPF_Fs12000_Fc66_B1},
+ {BPF_Fs16000_Fc66_A0, /* 16kS/s coefficients */
+ -BPF_Fs16000_Fc66_B2,
+ -BPF_Fs16000_Fc66_B1},
+ {BPF_Fs22050_Fc66_A0, /* 22kS/s coefficients */
+ -BPF_Fs22050_Fc66_B2,
+ -BPF_Fs22050_Fc66_B1},
+ {BPF_Fs24000_Fc66_A0, /* 24kS/s coefficients */
+ -BPF_Fs24000_Fc66_B2,
+ -BPF_Fs24000_Fc66_B1},
+ {BPF_Fs32000_Fc66_A0, /* 32kS/s coefficients */
+ -BPF_Fs32000_Fc66_B2,
+ -BPF_Fs32000_Fc66_B1},
+ {BPF_Fs44100_Fc66_A0, /* 44kS/s coefficients */
+ -BPF_Fs44100_Fc66_B2,
+ -BPF_Fs44100_Fc66_B1},
+ {BPF_Fs48000_Fc66_A0, /* 48kS/s coefficients */
+ -BPF_Fs48000_Fc66_B2,
+ -BPF_Fs48000_Fc66_B1},
+ {BPF_Fs88200_Fc66_A0, /* 88kS/s coefficients */
+ -BPF_Fs88200_Fc66_B2,
+ -BPF_Fs88200_Fc66_B1},
+ {BPF_Fs96000_Fc66_A0, /* 96kS/s coefficients */
+ -BPF_Fs96000_Fc66_B2,
+ -BPF_Fs96000_Fc66_B1},
+ {BPF_Fs176400_Fc66_A0, /* 176kS/s coefficients */
+ -BPF_Fs176400_Fc66_B2,
+ -BPF_Fs176400_Fc66_B1},
+ {BPF_Fs192000_Fc66_A0, /* 192kS/s coefficients */
+ -BPF_Fs192000_Fc66_B2,
+ -BPF_Fs192000_Fc66_B1},
+
+ /* Coefficients for 78Hz centre frequency */
+ {BPF_Fs8000_Fc78_A0, /* 8kS/s coefficients */
+ -BPF_Fs8000_Fc78_B2,
+ -BPF_Fs8000_Fc78_B1},
+ {BPF_Fs11025_Fc78_A0, /* 11kS/s coefficients */
+ -BPF_Fs11025_Fc78_B2,
+ -BPF_Fs11025_Fc78_B1},
+ {BPF_Fs12000_Fc78_A0, /* 12kS/s coefficients */
+ -BPF_Fs12000_Fc78_B2,
+ -BPF_Fs12000_Fc78_B1},
+ {BPF_Fs16000_Fc78_A0, /* 16kS/s coefficients */
+ -BPF_Fs16000_Fc78_B2,
+ -BPF_Fs16000_Fc78_B1},
+ {BPF_Fs22050_Fc78_A0, /* 22kS/s coefficients */
+ -BPF_Fs22050_Fc78_B2,
+ -BPF_Fs22050_Fc78_B1},
+ {BPF_Fs24000_Fc78_A0, /* 24kS/s coefficients */
+ -BPF_Fs24000_Fc78_B2,
+ -BPF_Fs24000_Fc78_B1},
+ {BPF_Fs32000_Fc78_A0, /* 32kS/s coefficients */
+ -BPF_Fs32000_Fc78_B2,
+ -BPF_Fs32000_Fc78_B1},
+ {BPF_Fs44100_Fc78_A0, /* 44kS/s coefficients */
+ -BPF_Fs44100_Fc78_B2,
+ -BPF_Fs44100_Fc78_B1},
+ {BPF_Fs48000_Fc78_A0, /* 48kS/s coefficients */
+ -BPF_Fs48000_Fc78_B2,
+ -BPF_Fs48000_Fc78_B1},
+ {BPF_Fs88200_Fc66_A0, /* 88kS/s coefficients */
+ -BPF_Fs88200_Fc66_B2,
+ -BPF_Fs88200_Fc66_B1},
+ {BPF_Fs96000_Fc78_A0, /* 96kS/s coefficients */
+ -BPF_Fs96000_Fc78_B2,
+ -BPF_Fs96000_Fc78_B1},
+ {BPF_Fs176400_Fc66_A0, /* 176kS/s coefficients */
+ -BPF_Fs176400_Fc66_B2,
+ -BPF_Fs176400_Fc66_B1},
+ {BPF_Fs192000_Fc78_A0, /* 192kS/s coefficients */
+ -BPF_Fs192000_Fc78_B2,
+ -BPF_Fs192000_Fc78_B1},
+
+ /* Coefficients for 90Hz centre frequency */
+ {BPF_Fs8000_Fc90_A0, /* 8kS/s coefficients */
+ -BPF_Fs8000_Fc90_B2,
+ -BPF_Fs8000_Fc90_B1},
+ {BPF_Fs11025_Fc90_A0, /* 11kS/s coefficients */
+ -BPF_Fs11025_Fc90_B2,
+ -BPF_Fs11025_Fc90_B1},
+ {BPF_Fs12000_Fc90_A0, /* 12kS/s coefficients */
+ -BPF_Fs12000_Fc90_B2,
+ -BPF_Fs12000_Fc90_B1},
+ {BPF_Fs16000_Fc90_A0, /* 16kS/s coefficients */
+ -BPF_Fs16000_Fc90_B2,
+ -BPF_Fs16000_Fc90_B1},
+ {BPF_Fs22050_Fc90_A0, /* 22kS/s coefficients */
+ -BPF_Fs22050_Fc90_B2,
+ -BPF_Fs22050_Fc90_B1},
+ {BPF_Fs24000_Fc90_A0, /* 24kS/s coefficients */
+ -BPF_Fs24000_Fc90_B2,
+ -BPF_Fs24000_Fc90_B1},
+ {BPF_Fs32000_Fc90_A0, /* 32kS/s coefficients */
+ -BPF_Fs32000_Fc90_B2,
+ -BPF_Fs32000_Fc90_B1},
+ {BPF_Fs44100_Fc90_A0, /* 44kS/s coefficients */
+ -BPF_Fs44100_Fc90_B2,
+ -BPF_Fs44100_Fc90_B1},
+ {BPF_Fs48000_Fc90_A0, /* 48kS/s coefficients */
+ -BPF_Fs48000_Fc90_B2,
+ -BPF_Fs48000_Fc90_B1}
+ ,
+ {BPF_Fs88200_Fc90_A0, /* 88kS/s coefficients */
+ -BPF_Fs88200_Fc90_B2,
+ -BPF_Fs88200_Fc90_B1},
+ {BPF_Fs96000_Fc90_A0, /* 96kS/s coefficients */
+ -BPF_Fs96000_Fc90_B2,
+ -BPF_Fs96000_Fc90_B1},
+ {BPF_Fs176400_Fc90_A0, /* 176kS/s coefficients */
+ -BPF_Fs176400_Fc90_B2,
+ -BPF_Fs176400_Fc90_B1},
+ {BPF_Fs192000_Fc90_A0, /* 192kS/s coefficients */
+ -BPF_Fs192000_Fc90_B2,
+ -BPF_Fs192000_Fc90_B1}
+
+};
+
+/************************************************************************************/
+/* */
+/* AGC constant tables */
+/* */
+/************************************************************************************/
+
+/* Attack time (signal too large) */
+const LVM_FLOAT LVDBE_AGC_ATTACK_Table[] = {
+ AGC_ATTACK_Fs8000,
+ AGC_ATTACK_Fs11025,
+ AGC_ATTACK_Fs12000,
+ AGC_ATTACK_Fs16000,
+ AGC_ATTACK_Fs22050,
+ AGC_ATTACK_Fs24000,
+ AGC_ATTACK_Fs32000,
+ AGC_ATTACK_Fs44100,
+ AGC_ATTACK_Fs48000
+ ,AGC_ATTACK_Fs88200
+ ,AGC_ATTACK_Fs96000
+ ,AGC_ATTACK_Fs176400
+ ,AGC_ATTACK_Fs192000
+
+};
+
+/* Decay time (signal too small) */
+const LVM_FLOAT LVDBE_AGC_DECAY_Table[] = {
+ AGC_DECAY_Fs8000,
+ AGC_DECAY_Fs11025,
+ AGC_DECAY_Fs12000,
+ AGC_DECAY_Fs16000,
+ AGC_DECAY_Fs22050,
+ AGC_DECAY_Fs24000,
+ AGC_DECAY_Fs32000,
+ AGC_DECAY_Fs44100,
+ AGC_DECAY_Fs48000
+ ,AGC_DECAY_Fs88200
+ ,AGC_DECAY_FS96000
+ ,AGC_DECAY_Fs176400
+ ,AGC_DECAY_FS192000
+
+};
+
+/* Gain for use without the high pass filter */
+const LVM_FLOAT LVDBE_AGC_GAIN_Table[] = {
+ AGC_GAIN_0dB,
+ AGC_GAIN_1dB,
+ AGC_GAIN_2dB,
+ AGC_GAIN_3dB,
+ AGC_GAIN_4dB,
+ AGC_GAIN_5dB,
+ AGC_GAIN_6dB,
+ AGC_GAIN_7dB,
+ AGC_GAIN_8dB,
+ AGC_GAIN_9dB,
+ AGC_GAIN_10dB,
+ AGC_GAIN_11dB,
+ AGC_GAIN_12dB,
+ AGC_GAIN_13dB,
+ AGC_GAIN_14dB,
+ AGC_GAIN_15dB};
+
+/* Gain for use with the high pass filter */
+const LVM_FLOAT LVDBE_AGC_HPFGAIN_Table[] = {
+ AGC_HPFGAIN_0dB,
+ AGC_HPFGAIN_1dB,
+ AGC_HPFGAIN_2dB,
+ AGC_HPFGAIN_3dB,
+ AGC_HPFGAIN_4dB,
+ AGC_HPFGAIN_5dB,
+ AGC_HPFGAIN_6dB,
+ AGC_HPFGAIN_7dB,
+ AGC_HPFGAIN_8dB,
+ AGC_HPFGAIN_9dB,
+ AGC_HPFGAIN_10dB,
+ AGC_HPFGAIN_11dB,
+ AGC_HPFGAIN_12dB,
+ AGC_HPFGAIN_13dB,
+ AGC_HPFGAIN_14dB,
+ AGC_HPFGAIN_15dB};
+
+/************************************************************************************/
+/* */
+/* Volume control gain and time constant tables */
+/* */
+/************************************************************************************/
+
+/* dB to linear conversion table */
+const LVM_FLOAT LVDBE_VolumeTable[] = {
+ 0.500000f, /* -6dB */
+ 0.562341f, /* -5dB */
+ 0.630957f, /* -4dB */
+ 0.707946f, /* -3dB */
+ 0.794328f, /* -2dB */
+ 0.891251f, /* -1dB */
+ 1.000000f}; /* 0dB */
+
+const LVM_FLOAT LVDBE_VolumeTCTable[] = {
+ VOL_TC_Fs8000,
+ VOL_TC_Fs11025,
+ VOL_TC_Fs12000,
+ VOL_TC_Fs16000,
+ VOL_TC_Fs22050,
+ VOL_TC_Fs24000,
+ VOL_TC_Fs32000,
+ VOL_TC_Fs44100,
+ VOL_TC_Fs48000
+ ,VOL_TC_Fs88200
+ ,VOL_TC_Fs96000
+ ,VOL_TC_Fs176400
+ ,VOL_TC_Fs192000
+};
+
+const LVM_INT16 LVDBE_MixerTCTable[] = {
+
+ MIX_TC_Fs8000,
+ MIX_TC_Fs11025,
+ MIX_TC_Fs12000,
+ MIX_TC_Fs16000,
+ MIX_TC_Fs22050,
+ MIX_TC_Fs24000,
+ MIX_TC_Fs32000,
+ MIX_TC_Fs44100,
+ MIX_TC_Fs48000
+ ,MIX_TC_Fs88200
+ ,MIX_TC_Fs96000
+ ,MIX_TC_Fs176400
+ ,MIX_TC_Fs192000
+
+};
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Tables.h b/media/libeffects/lvm/lib/Bass/src/LVDBE_Tables.h
index ca46e37..6eabdd2 100644
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Tables.h
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Tables.h
@@ -15,7 +15,6 @@
* limitations under the License.
*/
-
/************************************************************************************/
/* */
/* Includes */
@@ -24,61 +23,9 @@
#ifndef __LVBDE_TABLES_H__
#define __LVBDE_TABLES_H__
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
#include "BIQUAD.h"
#include "LVM_Types.h"
-#ifndef BUILD_FLOAT
-/************************************************************************************/
-/* */
-/* Coefficients constant table */
-/* */
-/************************************************************************************/
-
-/*
- * High Pass Filter Coefficient table
- */
-extern const BQ_C32_Coefs_t LVDBE_HPF_Table[];
-
-/*
- * Band Pass Filter coefficient table
- */
-extern const BP_C32_Coefs_t LVDBE_BPF_Table[];
-
-/************************************************************************************/
-/* */
-/* AGC constant tables */
-/* */
-/************************************************************************************/
-
-/* Attack time (signal too large) */
-extern const LVM_INT16 LVDBE_AGC_ATTACK_Table[];
-
-/* Decay time (signal too small) */
-extern const LVM_INT16 LVDBE_AGC_DECAY_Table[];
-
-/* Gain for use without the high pass filter */
-extern const LVM_INT32 LVDBE_AGC_GAIN_Table[];
-
-/* Gain for use with the high pass filter */
-extern const LVM_INT32 LVDBE_AGC_HPFGAIN_Table[];
-
-/************************************************************************************/
-/* */
-/* Volume control gain and time constant tables */
-/* */
-/************************************************************************************/
-
-/* dB to linear conversion table */
-extern const LVM_INT16 LVDBE_VolumeTable[];
-
-extern const LVM_INT16 LVDBE_VolumeTCTable[];
-
-#else /*BUILD_FLOAT*/
-
/************************************************************************************/
/* */
/* Coefficients constant table */
@@ -123,13 +70,6 @@
extern const LVM_FLOAT LVDBE_VolumeTable[];
extern const LVM_FLOAT LVDBE_VolumeTCTable[];
-#endif /*BUILD_FLOAT*/
-
extern const LVM_INT16 LVDBE_MixerTCTable[];
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
#endif /* __LVBDE_TABLES_H__ */
diff --git a/media/libeffects/lvm/lib/Bundle/lib/LVM.h b/media/libeffects/lvm/lib/Bundle/lib/LVM.h
index 5082a53..e4e8450 100644
--- a/media/libeffects/lvm/lib/Bundle/lib/LVM.h
+++ b/media/libeffects/lvm/lib/Bundle/lib/LVM.h
@@ -53,11 +53,6 @@
#ifndef __LVM_H__
#define __LVM_H__
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-
/****************************************************************************************/
/* */
/* Includes */
@@ -66,7 +61,6 @@
#include "LVM_Types.h"
-
/****************************************************************************************/
/* */
/* Definitions */
@@ -108,7 +102,6 @@
/* Instance handle */
typedef void *LVM_Handle_t;
-
/* Status return values */
typedef enum
{
@@ -123,7 +116,6 @@
LVM_RETURNSTATUS_DUMMY = LVM_MAXENUM
} LVM_ReturnStatus_en;
-
/* Buffer Management mode */
typedef enum
{
@@ -227,7 +219,6 @@
LVM_CHAR *pPlatform; /* Pointer to the library platform type */
} LVM_VersionInfo_st;
-
/****************************************************************************************/
/* */
/* Structures */
@@ -248,7 +239,6 @@
LVM_UINT16 QFactor; /* Band quality factor (x100) */
} LVM_EQNB_BandDef_t;
-
/* Headroom band definition */
typedef struct
{
@@ -257,7 +247,6 @@
LVM_INT16 Headroom_Offset; /* Headroom = biggest band gain - Headroom_Offset */
} LVM_HeadroomBandDef_t;
-
/* Control Parameter structure */
typedef struct
{
@@ -303,7 +292,6 @@
} LVM_ControlParams_t;
-
/* Instance Parameter structure */
typedef struct
{
@@ -333,7 +321,6 @@
/* */
/****************************************************************************************/
-
/****************************************************************************************/
/* */
/* FUNCTION: LVM_GetVersionInfo */
@@ -354,7 +341,6 @@
/****************************************************************************************/
LVM_ReturnStatus_en LVM_GetVersionInfo(LVM_VersionInfo_st *pVersion);
-
/****************************************************************************************/
/* */
/* FUNCTION: LVM_GetMemoryTable */
@@ -391,7 +377,6 @@
LVM_MemTab_t *pMemoryTable,
LVM_InstParams_t *pInstParams);
-
/****************************************************************************************/
/* */
/* FUNCTION: LVM_GetInstanceHandle */
@@ -418,7 +403,6 @@
LVM_MemTab_t *pMemoryTable,
LVM_InstParams_t *pInstParams);
-
/****************************************************************************************/
/* */
/* FUNCTION: LVM_ClearAudioBuffers */
@@ -439,7 +423,6 @@
/****************************************************************************************/
LVM_ReturnStatus_en LVM_ClearAudioBuffers(LVM_Handle_t hInstance);
-
/****************************************************************************************/
/* */
/* FUNCTION: LVM_GetControlParameters */
@@ -463,7 +446,6 @@
LVM_ReturnStatus_en LVM_GetControlParameters(LVM_Handle_t hInstance,
LVM_ControlParams_t *pParams);
-
/****************************************************************************************/
/* */
/* FUNCTION: LVM_SetControlParameters */
@@ -487,7 +469,6 @@
LVM_ReturnStatus_en LVM_SetControlParameters(LVM_Handle_t hInstance,
LVM_ControlParams_t *pParams);
-
/****************************************************************************************/
/* */
/* FUNCTION: LVM_Process */
@@ -518,20 +499,11 @@
/* STEREO the number of sample pairs in the block */
/* */
/****************************************************************************************/
-#ifdef BUILD_FLOAT
LVM_ReturnStatus_en LVM_Process(LVM_Handle_t hInstance,
const LVM_FLOAT *pInData,
LVM_FLOAT *pOutData,
LVM_UINT16 NumSamples,
LVM_UINT32 AudioTime);
-#else
-LVM_ReturnStatus_en LVM_Process(LVM_Handle_t hInstance,
- const LVM_INT16 *pInData,
- LVM_INT16 *pOutData,
- LVM_UINT16 NumSamples,
- LVM_UINT32 AudioTime);
-#endif
-
/****************************************************************************************/
/* */
@@ -555,7 +527,6 @@
LVM_ReturnStatus_en LVM_SetHeadroomParams( LVM_Handle_t hInstance,
LVM_HeadroomParams_t *pHeadroomParams);
-
/****************************************************************************************/
/* */
/* FUNCTION: LVM_GetHeadroomParams */
@@ -578,7 +549,6 @@
LVM_ReturnStatus_en LVM_GetHeadroomParams( LVM_Handle_t hInstance,
LVM_HeadroomParams_t *pHeadroomParams);
-
/****************************************************************************************/
/* */
/* FUNCTION: LVM_GetSpectrum */
@@ -632,10 +602,5 @@
LVM_ReturnStatus_en LVM_SetVolumeNoSmoothing( LVM_Handle_t hInstance,
LVM_ControlParams_t *pParams);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
#endif /* __LVM_H__ */
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_API_Specials.c b/media/libeffects/lvm/lib/Bundle/src/LVM_API_Specials.c
deleted file mode 100644
index 07b7f0e..0000000
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_API_Specials.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-/****************************************************************************************/
-/* */
-/* Includes */
-/* */
-/****************************************************************************************/
-
-#include "LVM_Private.h"
-#include "LVM_Tables.h"
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVM_GetSpectrum */
-/* */
-/* DESCRIPTION: */
-/* This function is used to retrieve Spectral information at a given Audio time */
-/* for display usage */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance Handle */
-/* pCurrentPeaks Pointer to location where currents peaks are to be saved */
-/* pPastPeaks Pointer to location where past peaks are to be saved */
-/* AudioTime Audio time at which the spectral information is needed */
-/* */
-/* RETURNS: */
-/* LVM_SUCCESS Succeeded */
-/* LVM_NULLADDRESS If any of input addresses are NULL */
-/* LVM_WRONGAUDIOTIME Failure due to audio time error */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVM_Process function */
-/* */
-/****************************************************************************************/
-LVM_ReturnStatus_en LVM_GetSpectrum(
- LVM_Handle_t hInstance,
- LVM_UINT8 *pCurrentPeaks,
- LVM_UINT8 *pPastPeaks,
- LVM_INT32 AudioTime
- )
-{
- LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
-
- pLVPSA_Handle_t *hPSAInstance;
- LVPSA_RETURN LVPSA_Status;
-
-
- if(pInstance == LVM_NULL)
- {
- return LVM_NULLADDRESS;
- }
-
- /*If PSA is not included at the time of instance creation, return without any processing*/
- if(pInstance->InstParams.PSA_Included!=LVM_PSA_ON)
- {
- return LVM_SUCCESS;
- }
-
- hPSAInstance = pInstance->hPSAInstance;
-
- if((pCurrentPeaks == LVM_NULL) ||
- (pPastPeaks == LVM_NULL))
- {
- return LVM_NULLADDRESS;
- }
-
-
- /*
- * Update new parameters if necessary
- */
- if (pInstance->ControlPending == LVM_TRUE)
- {
- LVM_ApplyNewSettings(hInstance);
- }
-
- /* If PSA module is disabled, do nothing */
- if(pInstance->Params.PSA_Enable==LVM_PSA_OFF)
- {
- return LVM_ALGORITHMDISABLED;
- }
-
- LVPSA_Status = LVPSA_GetSpectrum(hPSAInstance,
- (LVPSA_Time) (AudioTime),
- (LVM_UINT8*) pCurrentPeaks,
- (LVM_UINT8*) pPastPeaks );
-
- if(LVPSA_Status != LVPSA_OK)
- {
- if(LVPSA_Status == LVPSA_ERROR_WRONGTIME)
- {
- return (LVM_ReturnStatus_en) LVM_WRONGAUDIOTIME;
- }
- else
- {
- return (LVM_ReturnStatus_en) LVM_NULLADDRESS;
- }
- }
-
- return(LVM_SUCCESS);
-}
-
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVM_SetVolumeNoSmoothing */
-/* */
-/* DESCRIPTION: */
-/* This function is used to set output volume without any smoothing */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance Handle */
-/* pParams Control Parameters, only volume value is used here */
-/* */
-/* RETURNS: */
-/* LVM_SUCCESS Succeeded */
-/* LVM_NULLADDRESS If any of input addresses are NULL */
-/* LVM_OUTOFRANGE When any of the control parameters are out of range */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVM_Process function */
-/* */
-/****************************************************************************************/
-LVM_ReturnStatus_en LVM_SetVolumeNoSmoothing( LVM_Handle_t hInstance,
- LVM_ControlParams_t *pParams)
-{
- LVM_Instance_t *pInstance =(LVM_Instance_t *)hInstance;
- LVM_ReturnStatus_en Error;
-
- /*Apply new controls*/
- Error = LVM_SetControlParameters(hInstance,pParams);
- pInstance->NoSmoothVolume = LVM_TRUE;
- return Error;
-}
-
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_API_Specials.cpp b/media/libeffects/lvm/lib/Bundle/src/LVM_API_Specials.cpp
new file mode 100644
index 0000000..e241cdd
--- /dev/null
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_API_Specials.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/****************************************************************************************/
+/* */
+/* Includes */
+/* */
+/****************************************************************************************/
+
+#include "LVM_Private.h"
+#include "LVM_Tables.h"
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVM_GetSpectrum */
+/* */
+/* DESCRIPTION: */
+/* This function is used to retrieve Spectral information at a given Audio time */
+/* for display usage */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance Handle */
+/* pCurrentPeaks Pointer to location where currents peaks are to be saved */
+/* pPastPeaks Pointer to location where past peaks are to be saved */
+/* AudioTime Audio time at which the spectral information is needed */
+/* */
+/* RETURNS: */
+/* LVM_SUCCESS Succeeded */
+/* LVM_NULLADDRESS If any of input addresses are NULL */
+/* LVM_WRONGAUDIOTIME Failure due to audio time error */
+/* */
+/* NOTES: */
+/* 1. This function may be interrupted by the LVM_Process function */
+/* */
+/****************************************************************************************/
+LVM_ReturnStatus_en LVM_GetSpectrum(
+ LVM_Handle_t hInstance,
+ LVM_UINT8 *pCurrentPeaks,
+ LVM_UINT8 *pPastPeaks,
+ LVM_INT32 AudioTime
+ )
+{
+ LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
+
+ pLVPSA_Handle_t *hPSAInstance;
+ LVPSA_RETURN LVPSA_Status;
+
+ if(pInstance == LVM_NULL)
+ {
+ return LVM_NULLADDRESS;
+ }
+
+ /*If PSA is not included at the time of instance creation, return without any processing*/
+ if(pInstance->InstParams.PSA_Included!=LVM_PSA_ON)
+ {
+ return LVM_SUCCESS;
+ }
+
+ hPSAInstance = (pLVPSA_Handle_t *)pInstance->hPSAInstance;
+
+ if((pCurrentPeaks == LVM_NULL) ||
+ (pPastPeaks == LVM_NULL))
+ {
+ return LVM_NULLADDRESS;
+ }
+
+ /*
+ * Update new parameters if necessary
+ */
+ if (pInstance->ControlPending == LVM_TRUE)
+ {
+ LVM_ApplyNewSettings(hInstance);
+ }
+
+ /* If PSA module is disabled, do nothing */
+ if(pInstance->Params.PSA_Enable==LVM_PSA_OFF)
+ {
+ return LVM_ALGORITHMDISABLED;
+ }
+
+ LVPSA_Status = LVPSA_GetSpectrum(hPSAInstance,
+ (LVPSA_Time) (AudioTime),
+ (LVM_UINT8*) pCurrentPeaks,
+ (LVM_UINT8*) pPastPeaks );
+
+ if(LVPSA_Status != LVPSA_OK)
+ {
+ if(LVPSA_Status == LVPSA_ERROR_WRONGTIME)
+ {
+ return (LVM_ReturnStatus_en) LVM_WRONGAUDIOTIME;
+ }
+ else
+ {
+ return (LVM_ReturnStatus_en) LVM_NULLADDRESS;
+ }
+ }
+
+ return(LVM_SUCCESS);
+}
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVM_SetVolumeNoSmoothing */
+/* */
+/* DESCRIPTION: */
+/* This function is used to set output volume without any smoothing */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance Handle */
+/* pParams Control Parameters, only volume value is used here */
+/* */
+/* RETURNS: */
+/* LVM_SUCCESS Succeeded */
+/* LVM_NULLADDRESS If any of input addresses are NULL */
+/* LVM_OUTOFRANGE When any of the control parameters are out of range */
+/* */
+/* NOTES: */
+/* 1. This function may be interrupted by the LVM_Process function */
+/* */
+/****************************************************************************************/
+LVM_ReturnStatus_en LVM_SetVolumeNoSmoothing( LVM_Handle_t hInstance,
+ LVM_ControlParams_t *pParams)
+{
+ LVM_Instance_t *pInstance =(LVM_Instance_t *)hInstance;
+ LVM_ReturnStatus_en Error;
+
+ /*Apply new controls*/
+ Error = LVM_SetControlParameters(hInstance,pParams);
+ pInstance->NoSmoothVolume = LVM_TRUE;
+ return Error;
+}
+
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Buffers.c b/media/libeffects/lvm/lib/Bundle/src/LVM_Buffers.c
deleted file mode 100644
index bdca5e3..0000000
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Buffers.c
+++ /dev/null
@@ -1,1338 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-/****************************************************************************************/
-/* */
-/* Includes */
-/* */
-/****************************************************************************************/
-
-#include "LVM_Private.h"
-#include "VectorArithmetic.h"
-
-#include <log/log.h>
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVM_BufferManagedIn */
-/* */
-/* DESCRIPTION: */
-/* Full buffer management allowing the user to provide input and output buffers on */
-/* any alignment and with any number of samples. The alignment is corrected within */
-/* the buffer management and the samples are grouped in to blocks of the correct size */
-/* before processing. */
-/* */
-/* PARAMETERS: */
-/* hInstance - Instance handle */
-/* pInData - Pointer to the input data stream */
-/* *pToProcess - Pointer to pointer to the start of data processing */
-/* *pProcessed - Pointer to pointer to the destination of the processed data */
-/* pNumSamples - Pointer to the number of samples to process */
-/* */
-/* RETURNS: */
-/* None */
-/* */
-/* NOTES: */
-/* */
-/****************************************************************************************/
-#ifdef BUILD_FLOAT
-void LVM_BufferManagedIn(LVM_Handle_t hInstance,
- const LVM_FLOAT *pInData,
- LVM_FLOAT **pToProcess,
- LVM_FLOAT **pProcessed,
- LVM_UINT16 *pNumSamples)
-{
-
- LVM_INT16 SampleCount; /* Number of samples to be processed this call */
- LVM_INT16 NumSamples; /* Number of samples in scratch buffer */
- LVM_FLOAT *pStart;
- LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
- LVM_Buffer_t *pBuffer;
- LVM_FLOAT *pDest;
-#ifdef SUPPORT_MC
- LVM_INT16 NumChannels = pInstance->NrChannels;
-#else
- LVM_INT16 NumChannels = 2;
-#endif
-
- /*
- * Set the processing address pointers
- */
- pBuffer = pInstance->pBufferManagement;
- pDest = pBuffer->pScratch;
- *pToProcess = pBuffer->pScratch;
- *pProcessed = pBuffer->pScratch;
-
- /*
- * Check if it is the first call of a block
- */
- if (pInstance->SamplesToProcess == 0)
- {
- /*
- * First call for a new block of samples
- */
- pInstance->SamplesToProcess = (LVM_INT16)(*pNumSamples + pBuffer->InDelaySamples);
- pInstance->pInputSamples = (LVM_FLOAT *)pInData;
- pBuffer->BufferState = LVM_FIRSTCALL;
- }
- pStart = pInstance->pInputSamples; /* Pointer to the input samples */
- pBuffer->SamplesToOutput = 0; /* Samples to output is same as
- number read for inplace processing */
-
-
- /*
- * Calculate the number of samples to process this call and update the buffer state
- */
- if (pInstance->SamplesToProcess > pInstance->InternalBlockSize)
- {
- /*
- * Process the maximum bock size of samples.
- */
- SampleCount = pInstance->InternalBlockSize;
- NumSamples = pInstance->InternalBlockSize;
- }
- else
- {
- /*
- * Last call for the block, so calculate how many frames and samples to process
- */
- LVM_INT16 NumFrames;
-
- NumSamples = pInstance->SamplesToProcess;
- NumFrames = (LVM_INT16)(NumSamples >> MIN_INTERNAL_BLOCKSHIFT);
- SampleCount = (LVM_INT16)(NumFrames << MIN_INTERNAL_BLOCKSHIFT);
-
- /*
- * Update the buffer state
- */
- if (pBuffer->BufferState == LVM_FIRSTCALL)
- {
- pBuffer->BufferState = LVM_FIRSTLASTCALL;
- }
- else
- {
- pBuffer->BufferState = LVM_LASTCALL;
- }
- }
- *pNumSamples = (LVM_UINT16)SampleCount; /* Set the number of samples to process this call */
-
-
- /*
- * Copy samples from the delay buffer as required
- */
- if (((pBuffer->BufferState == LVM_FIRSTCALL) ||
- (pBuffer->BufferState == LVM_FIRSTLASTCALL)) &&
- (pBuffer->InDelaySamples != 0))
- {
- Copy_Float(&pBuffer->InDelayBuffer[0], /* Source */
- pDest, /* Destination */
- (LVM_INT16)(NumChannels * pBuffer->InDelaySamples)); /* Number of delay \
- samples, left and right */
- NumSamples = (LVM_INT16)(NumSamples - pBuffer->InDelaySamples); /* Update sample count */
- pDest += NumChannels * pBuffer->InDelaySamples; /* Update the destination pointer */
- }
-
-
- /*
- * Copy the rest of the samples for this call from the input buffer
- */
- if (NumSamples > 0)
- {
- Copy_Float(pStart, /* Source */
- pDest, /* Destination */
- (LVM_INT16)(NumChannels * NumSamples)); /* Number of input samples */
- pStart += NumChannels * NumSamples; /* Update the input pointer */
-
- /*
- * Update the input data pointer and samples to output
- */
- /* Update samples to output */
- pBuffer->SamplesToOutput = (LVM_INT16)(pBuffer->SamplesToOutput + NumSamples);
- }
-
-
- /*
- * Update the sample count and input pointer
- */
- /* Update the count of samples */
- pInstance->SamplesToProcess = (LVM_INT16)(pInstance->SamplesToProcess - SampleCount);
- pInstance->pInputSamples = pStart; /* Update input sample pointer */
-
-
- /*
- * Save samples to the delay buffer if any left unprocessed
- */
- if ((pBuffer->BufferState == LVM_FIRSTLASTCALL) ||
- (pBuffer->BufferState == LVM_LASTCALL))
- {
- NumSamples = pInstance->SamplesToProcess;
- pStart = pBuffer->pScratch; /* Start of the buffer */
- pStart += NumChannels * SampleCount; /* Offset by the number of processed samples */
- if (NumSamples != 0)
- {
- Copy_Float(pStart, /* Source */
- &pBuffer->InDelayBuffer[0], /* Destination */
- (LVM_INT16)(NumChannels * NumSamples)); /* Number of input samples */
- }
-
-
- /*
- * Update the delay sample count
- */
- pBuffer->InDelaySamples = NumSamples; /* Number of delay sample pairs */
- pInstance->SamplesToProcess = 0; /* All Samples used */
- }
-}
-#else
-void LVM_BufferManagedIn(LVM_Handle_t hInstance,
- const LVM_INT16 *pInData,
- LVM_INT16 **pToProcess,
- LVM_INT16 **pProcessed,
- LVM_UINT16 *pNumSamples)
-{
-
- LVM_INT16 SampleCount; /* Number of samples to be processed this call */
- LVM_INT16 NumSamples; /* Number of samples in scratch buffer */
- LVM_INT16 *pStart;
- LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
- LVM_Buffer_t *pBuffer;
- LVM_INT16 *pDest;
- LVM_INT16 NumChannels = 2;
-
- /*
- * Set the processing address pointers
- */
- pBuffer = pInstance->pBufferManagement;
- pDest = pBuffer->pScratch;
- *pToProcess = pBuffer->pScratch;
- *pProcessed = pBuffer->pScratch;
-
- /*
- * Check if it is the first call of a block
- */
- if (pInstance->SamplesToProcess == 0)
- {
- /*
- * First call for a new block of samples
- */
- pInstance->SamplesToProcess = (LVM_INT16)(*pNumSamples + pBuffer->InDelaySamples);
- pInstance->pInputSamples = (LVM_INT16 *)pInData;
- pBuffer->BufferState = LVM_FIRSTCALL;
- }
- pStart = pInstance->pInputSamples; /* Pointer to the input samples */
- pBuffer->SamplesToOutput = 0; /* Samples to output is same as number read for inplace processing */
-
-
- /*
- * Calculate the number of samples to process this call and update the buffer state
- */
- if (pInstance->SamplesToProcess > pInstance->InternalBlockSize)
- {
- /*
- * Process the maximum bock size of samples.
- */
- SampleCount = pInstance->InternalBlockSize;
- NumSamples = pInstance->InternalBlockSize;
- }
- else
- {
- /*
- * Last call for the block, so calculate how many frames and samples to process
- */
- LVM_INT16 NumFrames;
-
- NumSamples = pInstance->SamplesToProcess;
- NumFrames = (LVM_INT16)(NumSamples >> MIN_INTERNAL_BLOCKSHIFT);
- SampleCount = (LVM_INT16)(NumFrames << MIN_INTERNAL_BLOCKSHIFT);
-
- /*
- * Update the buffer state
- */
- if (pBuffer->BufferState == LVM_FIRSTCALL)
- {
- pBuffer->BufferState = LVM_FIRSTLASTCALL;
- }
- else
- {
- pBuffer->BufferState = LVM_LASTCALL;
- }
- }
- *pNumSamples = (LVM_UINT16)SampleCount; /* Set the number of samples to process this call */
-
-
- /*
- * Copy samples from the delay buffer as required
- */
- if (((pBuffer->BufferState == LVM_FIRSTCALL) ||
- (pBuffer->BufferState == LVM_FIRSTLASTCALL)) &&
- (pBuffer->InDelaySamples != 0))
- {
- Copy_16(&pBuffer->InDelayBuffer[0], /* Source */
- pDest, /* Destination */
- (LVM_INT16)(NumChannels*pBuffer->InDelaySamples)); /* Number of delay samples, left and right */
- NumSamples = (LVM_INT16)(NumSamples - pBuffer->InDelaySamples); /* Update sample count */
- pDest += NumChannels * pBuffer->InDelaySamples; /* Update the destination pointer */
- }
-
-
- /*
- * Copy the rest of the samples for this call from the input buffer
- */
- if (NumSamples > 0)
- {
- Copy_16(pStart, /* Source */
- pDest, /* Destination */
- (LVM_INT16)(NumChannels*NumSamples)); /* Number of input samples */
- pStart += NumChannels * NumSamples; /* Update the input pointer */
-
- /*
- * Update the input data pointer and samples to output
- */
- pBuffer->SamplesToOutput = (LVM_INT16)(pBuffer->SamplesToOutput + NumSamples); /* Update samples to output */
- }
-
-
- /*
- * Update the sample count and input pointer
- */
- pInstance->SamplesToProcess = (LVM_INT16)(pInstance->SamplesToProcess - SampleCount); /* Update the count of samples */
- pInstance->pInputSamples = pStart; /* Update input sample pointer */
-
-
- /*
- * Save samples to the delay buffer if any left unprocessed
- */
- if ((pBuffer->BufferState == LVM_FIRSTLASTCALL) ||
- (pBuffer->BufferState == LVM_LASTCALL))
- {
- NumSamples = pInstance->SamplesToProcess;
- pStart = pBuffer->pScratch; /* Start of the buffer */
- pStart += NumChannels*SampleCount; /* Offset by the number of processed samples */
- if (NumSamples != 0)
- {
- Copy_16(pStart, /* Source */
- &pBuffer->InDelayBuffer[0], /* Destination */
- (LVM_INT16)(NumChannels*NumSamples)); /* Number of input samples */
- }
-
-
- /*
- * Update the delay sample count
- */
- pBuffer->InDelaySamples = NumSamples; /* Number of delay sample pairs */
- pInstance->SamplesToProcess = 0; /* All Samples used */
- }
-}
-#endif
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVM_BufferUnmanagedIn */
-/* */
-/* DESCRIPTION: */
-/* This mode is selected by the user code and disables the buffer management with the */
-/* exception of the maximum block size processing. The user must ensure that the */
-/* input and output buffers are 32-bit aligned and also that the number of samples to */
-/* process is a correct multiple of samples. */
-/* */
-/* PARAMETERS: */
-/* hInstance - Instance handle */
-/* *pToProcess - Pointer to the start of data processing */
-/* *pProcessed - Pointer to the destination of the processed data */
-/* pNumSamples - Pointer to the number of samples to process */
-/* */
-/* RETURNS: */
-/* None */
-/* */
-/* NOTES: */
-/* */
-/****************************************************************************************/
-#ifdef BUILD_FLOAT
-void LVM_BufferUnmanagedIn(LVM_Handle_t hInstance,
- LVM_FLOAT **pToProcess,
- LVM_FLOAT **pProcessed,
- LVM_UINT16 *pNumSamples)
-{
-
- LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
-
-
- /*
- * Check if this is the first call of a block
- */
- if (pInstance->SamplesToProcess == 0)
- {
- pInstance->SamplesToProcess = (LVM_INT16)*pNumSamples; /* Get the number of samples
- on first call */
- pInstance->pInputSamples = *pToProcess; /* Get the I/O pointers */
- pInstance->pOutputSamples = *pProcessed;
-
-
- /*
- * Set te block size to process
- */
- if (pInstance->SamplesToProcess > pInstance->InternalBlockSize)
- {
- *pNumSamples = (LVM_UINT16)pInstance->InternalBlockSize;
- }
- else
- {
- *pNumSamples = (LVM_UINT16)pInstance->SamplesToProcess;
- }
- }
-
- /*
- * Set the process pointers
- */
- *pToProcess = pInstance->pInputSamples;
- *pProcessed = pInstance->pOutputSamples;
-}
-#else
-void LVM_BufferUnmanagedIn(LVM_Handle_t hInstance,
- LVM_INT16 **pToProcess,
- LVM_INT16 **pProcessed,
- LVM_UINT16 *pNumSamples)
-{
-
- LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
-
-
- /*
- * Check if this is the first call of a block
- */
- if (pInstance->SamplesToProcess == 0)
- {
- pInstance->SamplesToProcess = (LVM_INT16)*pNumSamples; /* Get the number of samples on first call */
- pInstance->pInputSamples = *pToProcess; /* Get the I/O pointers */
- pInstance->pOutputSamples = *pProcessed;
-
-
- /*
- * Set te block size to process
- */
- if (pInstance->SamplesToProcess > pInstance->InternalBlockSize)
- {
- *pNumSamples = (LVM_UINT16)pInstance->InternalBlockSize;
- }
- else
- {
- *pNumSamples = (LVM_UINT16)pInstance->SamplesToProcess;
- }
- }
-
- /*
- * Set the process pointers
- */
- *pToProcess = pInstance->pInputSamples;
- *pProcessed = pInstance->pOutputSamples;
-}
-#endif
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVM_BufferOptimisedIn */
-/* */
-/* DESCRIPTION: */
-/* Optimised buffer management for the case where the data is outplace processing, */
-/* the output data is 32-bit aligned and there are sufficient samples to allow some */
-/* processing directly in the output buffer. This saves one data copy per sample */
-/* compared with the unoptimsed version. */
-/* */
-/* PARAMETERS: */
-/* hInstance - Instance handle */
-/* pInData - Pointer to the input data stream */
-/* *pToProcess - Pointer to the start of data processing */
-/* *pProcessed - Pointer to the destination of the processed data */
-/* pNumSamples - Pointer to the number of samples to process */
-/* */
-/* RETURNS: */
-/* None */
-/* */
-/* NOTES: */
-/* */
-/****************************************************************************************/
-
-#ifndef BUILD_FLOAT
-void LVM_BufferOptimisedIn(LVM_Handle_t hInstance,
- const LVM_INT16 *pInData,
- LVM_INT16 **pToProcess,
- LVM_INT16 **pProcessed,
- LVM_UINT16 *pNumSamples)
-{
-
- LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
- LVM_Buffer_t *pBuffer = pInstance->pBufferManagement;
- LVM_INT16 *pDest;
- LVM_INT16 SampleCount;
- LVM_INT16 NumSamples;
- LVM_INT16 NumFrames;
-
- /*
- * Check if it is the first call for this block
- */
- if (pInstance->SamplesToProcess == 0)
- {
- /*
- * First call for a new block of samples
- */
- pBuffer->BufferState = LVM_FIRSTCALL;
- pInstance->pInputSamples = (LVM_INT16 *)pInData;
- pInstance->SamplesToProcess = (LVM_INT16)*pNumSamples;
- pBuffer->SamplesToOutput = (LVM_INT16)*pNumSamples;
- pDest = *pProcessed; /* The start of the output buffer */
-
-
- /*
- * Copy the already processed samples to the output buffer
- */
- if (pBuffer->OutDelaySamples != 0)
- {
- Copy_16(&pBuffer->OutDelayBuffer[0], /* Source */
- pDest, /* Destination */
- (LVM_INT16)(2*pBuffer->OutDelaySamples)); /* Number of delay samples */
- pDest += 2 * pBuffer->OutDelaySamples; /* Update the output pointer */
- pBuffer->SamplesToOutput = (LVM_INT16)(pBuffer->SamplesToOutput - pBuffer->OutDelaySamples); /* Update the numbr of samples to output */
- }
- *pToProcess = pDest; /* Set the address to start processing */
- *pProcessed = pDest; /* Process in the output buffer, now inplace */
-
- /*
- * Copy the input delay buffer (unprocessed) samples to the output buffer
- */
- if (pBuffer->InDelaySamples != 0)
- {
- Copy_16(&pBuffer->InDelayBuffer[0], /* Source */
- pDest, /* Destination */
- (LVM_INT16)(2*pBuffer->InDelaySamples)); /* Number of delay samples */
- pDest += 2 * pBuffer->InDelaySamples; /* Update the output pointer */
- }
-
-
- /*
- * Calculate how many input samples to process and copy
- */
- NumSamples = (LVM_INT16)(*pNumSamples - pBuffer->OutDelaySamples); /* Number that will fit in the output buffer */
- if (NumSamples >= pInstance->InternalBlockSize)
- {
- NumSamples = pInstance->InternalBlockSize;
- }
- NumFrames = (LVM_INT16)(NumSamples >> MIN_INTERNAL_BLOCKSHIFT);
- SampleCount = (LVM_INT16)(NumFrames << MIN_INTERNAL_BLOCKSHIFT);
- *pNumSamples = (LVM_UINT16)SampleCount; /* The number of samples to process */
- pBuffer->SamplesToOutput = (LVM_INT16)(pBuffer->SamplesToOutput - SampleCount); /* Update the number of samples to output */
- SampleCount = (LVM_INT16)(SampleCount - pBuffer->InDelaySamples); /* The number of samples to copy from the input */
-
-
- /*
- * Copy samples from the input buffer and update counts and pointers
- */
- Copy_16(pInstance->pInputSamples, /* Source */
- pDest, /* Destination */
- (LVM_INT16)(2*SampleCount)); /* Number of input samples */
- pInstance->pInputSamples += 2 * SampleCount; /* Update the input pointer */
- pInstance->pOutputSamples = pDest + (2 * SampleCount); /* Update the output pointer */
- pInstance->SamplesToProcess = (LVM_INT16)(pInstance->SamplesToProcess - SampleCount); /* Samples left in the input buffer */
- }
- else
- {
- /*
- * Second or subsequent call in optimised mode
- */
- if (pBuffer->SamplesToOutput >= MIN_INTERNAL_BLOCKSIZE)
- {
- /*
- * More samples can be processed directly in the output buffer
- */
- *pToProcess = pInstance->pOutputSamples; /* Set the address to start processing */
- *pProcessed = pInstance->pOutputSamples; /* Process in the output buffer, now inplace */
- NumSamples = pBuffer->SamplesToOutput; /* Number that will fit in the output buffer */
- if (NumSamples >= pInstance->InternalBlockSize)
- {
- NumSamples = pInstance->InternalBlockSize;
- }
- NumFrames = (LVM_INT16)(NumSamples >> MIN_INTERNAL_BLOCKSHIFT);
- SampleCount = (LVM_INT16)(NumFrames << MIN_INTERNAL_BLOCKSHIFT);
- *pNumSamples = (LVM_UINT16)SampleCount; /* The number of samples to process */
-
-
- /*
- * Copy samples from the input buffer and update counts and pointers
- */
- Copy_16(pInstance->pInputSamples, /* Source */
- pInstance->pOutputSamples, /* Destination */
- (LVM_INT16)(2*SampleCount)); /* Number of input samples */
- pInstance->pInputSamples += 2 * SampleCount; /* Update the input pointer */
- pInstance->pOutputSamples += 2 * SampleCount; /* Update the output pointer */
- pInstance->SamplesToProcess = (LVM_INT16)(pInstance->SamplesToProcess - SampleCount); /* Samples left in the input buffer */
- pBuffer->SamplesToOutput = (LVM_INT16)(pBuffer->SamplesToOutput - SampleCount); /* Number that will fit in the output buffer */
- }
- else
- {
- /*
- * The remaining samples can not be processed in the output buffer
- */
- pBuffer->BufferState = LVM_LASTCALL; /* Indicate this is the last bock to process */
- *pToProcess = pBuffer->pScratch; /* Set the address to start processing */
- *pProcessed = pBuffer->pScratch; /* Process in the output buffer, now inplace */
- NumSamples = pInstance->SamplesToProcess; /* Number left to be processed */
- NumFrames = (LVM_INT16)(NumSamples >> MIN_INTERNAL_BLOCKSHIFT);
- SampleCount = (LVM_INT16)(NumFrames << MIN_INTERNAL_BLOCKSHIFT);
- *pNumSamples = (LVM_UINT16)SampleCount; /* The number of samples to process */
-
-
- /*
- * Copy samples from the input buffer and update counts and pointers
- */
- Copy_16(pInstance->pInputSamples, /* Source */
- pBuffer->pScratch, /* Destination */
- (LVM_INT16)(2*SampleCount)); /* Number of input samples */
- pInstance->pInputSamples += 2 * SampleCount; /* Update the input pointer */
- pInstance->SamplesToProcess = (LVM_INT16)(pInstance->SamplesToProcess - SampleCount); /* Samples left in the input buffer */
- }
- }
-}
-#endif
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVM_BufferIn */
-/* */
-/* DESCRIPTION: */
-/* This function manages the data input, it has the following features: */
-/* - Accepts data in 16-bit aligned memory */
-/* - Copies the data to 32-bit aligned memory */
-/* - Converts Mono inputs to Mono-in-Stereo */
-/* - Accepts any number of samples as input, except 0 */
-/* - Breaks the input sample stream in to blocks of the configured frame size or */
-/* multiples of the frame size */
-/* - Limits the processing block size to the maximum block size. */
-/* - Works with inplace or outplace processing automatically */
-/* */
-/* To manage the data the function has a number of operating states: */
-/* LVM_FIRSTCALL - The first call for this block of input samples */
-/* LVM_MAXBLOCKCALL - The current block is the maximum size. Only used for the */
-/* second and subsequent blocks. */
-/* LVM_LASTCALL - The last call for this block of input samples */
-/* LVM_FIRSTLASTCALL - This is the first and last call for this block of input*/
-/* samples, this occurs when the number of samples to */
-/* process is less than the maximum block size. */
-/* */
-/* The function uses an internal delay buffer the size of the minimum frame, this is */
-/* used to temporarily hold samples when the number of samples to process is not a */
-/* multiple of the frame size. */
-/* */
-/* To ensure correct operation with inplace buffering the number of samples to output*/
-/* per call is calculated in this function and is set to the number of samples read */
-/* from the input buffer. */
-/* */
-/* The total number of samples to process is stored when the function is called for */
-/* the first time. The value is overwritten by the size of the block to be processed */
-/* in each call so the size of the processing blocks can be controlled. The number of */
-/* samples actually processed for each block of input samples is always a multiple of*/
-/* the frame size so for any particular block of input samples the actual number of */
-/* processed samples may not match the number of input samples, sometime it will be */
-/* sometimes less. The average is the same and the difference is never more than the */
-/* frame size. */
-/* */
-/* PARAMETERS: */
-/* hInstance - Instance handle */
-/* pInData - Pointer to the input data stream */
-/* *pToProcess - Pointer to the start of data processing */
-/* *pProcessed - Pointer to the destination of the processed data */
-/* pNumSamples - Pointer to the number of samples to process */
-/* */
-/* RETURNS: */
-/* None */
-/* */
-/* NOTES: */
-/* */
-/****************************************************************************************/
-#ifdef BUILD_FLOAT
-void LVM_BufferIn(LVM_Handle_t hInstance,
- const LVM_FLOAT *pInData,
- LVM_FLOAT **pToProcess,
- LVM_FLOAT **pProcessed,
- LVM_UINT16 *pNumSamples)
-{
-
- LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
-
-
- /*
- * Check which mode, managed or unmanaged
- */
- if (pInstance->InstParams.BufferMode == LVM_MANAGED_BUFFERS)
- {
- LVM_BufferManagedIn(hInstance,
- pInData,
- pToProcess,
- pProcessed,
- pNumSamples);
- }
- else
- {
- LVM_BufferUnmanagedIn(hInstance,
- pToProcess,
- pProcessed,
- pNumSamples);
- }
-}
-#else
-void LVM_BufferIn(LVM_Handle_t hInstance,
- const LVM_INT16 *pInData,
- LVM_INT16 **pToProcess,
- LVM_INT16 **pProcessed,
- LVM_UINT16 *pNumSamples)
-{
-
- LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
-
-
- /*
- * Check which mode, managed or unmanaged
- */
- if (pInstance->InstParams.BufferMode == LVM_MANAGED_BUFFERS)
- {
- LVM_BufferManagedIn(hInstance,
- pInData,
- pToProcess,
- pProcessed,
- pNumSamples);
- }
- else
- {
- LVM_BufferUnmanagedIn(hInstance,
- pToProcess,
- pProcessed,
- pNumSamples);
- }
-}
-#endif
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVM_BufferManagedOut */
-/* */
-/* DESCRIPTION: */
-/* Full buffer management output. This works in conjunction with the managed input */
-/* routine and ensures the correct number of samples are always output to the output */
-/* buffer. */
-/* */
-/* PARAMETERS: */
-/* hInstance - Instance handle */
-/* pOutData - Pointer to the output data stream */
-/* pNumSamples - Pointer to the number of samples to process */
-/* */
-/* RETURNS: */
-/* None */
-/* */
-/* NOTES: */
-/* */
-/****************************************************************************************/
-#ifdef BUILD_FLOAT
-void LVM_BufferManagedOut(LVM_Handle_t hInstance,
- LVM_FLOAT *pOutData,
- LVM_UINT16 *pNumSamples)
-{
-
- LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
- LVM_Buffer_t *pBuffer = pInstance->pBufferManagement;
- LVM_INT16 SampleCount = (LVM_INT16)*pNumSamples;
- LVM_INT16 NumSamples;
- LVM_FLOAT *pStart;
- LVM_FLOAT *pDest;
-#ifdef SUPPORT_MC
- LVM_INT32 NrChannels = pInstance->NrChannels;
-#define NrFrames NumSamples // alias for clarity
-#define FrameCount SampleCount
-#endif
-
- /*
- * Set the pointers
- */
- NumSamples = pBuffer->SamplesToOutput;
- pStart = pBuffer->pScratch;
-
- /*
- * check if it is the first call of a block
- */
- if ((pBuffer->BufferState == LVM_FIRSTCALL) ||
- (pBuffer->BufferState == LVM_FIRSTLASTCALL))
- {
- /* First call for a new block */
- pInstance->pOutputSamples = pOutData; /* Initialise the destination */
- }
- pDest = pInstance->pOutputSamples; /* Set the output address */
-
-
- /*
- * If the number of samples is non-zero then there are still samples to send to
- * the output buffer
- */
- if ((NumSamples != 0) &&
- (pBuffer->OutDelaySamples != 0))
- {
- /*
- * Copy the delayed output buffer samples to the output
- */
- if (pBuffer->OutDelaySamples <= NumSamples)
- {
- /*
- * Copy all output delay samples to the output
- */
-#ifdef SUPPORT_MC
- Copy_Float(&pBuffer->OutDelayBuffer[0], /* Source */
- pDest, /* Destination */
- /* Number of delay samples */
- (LVM_INT16)(NrChannels * pBuffer->OutDelaySamples));
-#else
- Copy_Float(&pBuffer->OutDelayBuffer[0], /* Source */
- pDest, /* Destination */
- (LVM_INT16)(2 * pBuffer->OutDelaySamples)); /* Number of delay samples */
-#endif
-
- /*
- * Update the pointer and sample counts
- */
-#ifdef SUPPORT_MC
- pDest += NrChannels * pBuffer->OutDelaySamples; /* Output sample pointer */
-#else
- pDest += 2 * pBuffer->OutDelaySamples; /* Output sample pointer */
-#endif
- NumSamples = (LVM_INT16)(NumSamples - pBuffer->OutDelaySamples); /* Samples left \
- to send */
- pBuffer->OutDelaySamples = 0; /* No samples left in the buffer */
- }
- else
- {
- /*
- * Copy only some of the ouput delay samples to the output
- */
-#ifdef SUPPORT_MC
- Copy_Float(&pBuffer->OutDelayBuffer[0], /* Source */
- pDest, /* Destination */
- (LVM_INT16)(NrChannels * NrFrames)); /* Number of delay samples */
-#else
- Copy_Float(&pBuffer->OutDelayBuffer[0], /* Source */
- pDest, /* Destination */
- (LVM_INT16)(2 * NumSamples)); /* Number of delay samples */
-#endif
-
- /*
- * Update the pointer and sample counts
- */
-#ifdef SUPPORT_MC
- pDest += NrChannels * NrFrames; /* Output sample pointer */
-#else
- pDest += 2 * NumSamples; /* Output sample pointer */
-#endif
- /* No samples left in the buffer */
- pBuffer->OutDelaySamples = (LVM_INT16)(pBuffer->OutDelaySamples - NumSamples);
-
- /*
- * Realign the delay buffer data to avoid using circular buffer management
- */
-#ifdef SUPPORT_MC
- Copy_Float(&pBuffer->OutDelayBuffer[NrChannels * NrFrames], /* Source */
- &pBuffer->OutDelayBuffer[0], /* Destination */
- /* Number of samples to move */
- (LVM_INT16)(NrChannels * pBuffer->OutDelaySamples));
-#else
- Copy_Float(&pBuffer->OutDelayBuffer[2 * NumSamples], /* Source */
- &pBuffer->OutDelayBuffer[0], /* Destination */
- (LVM_INT16)(2 * pBuffer->OutDelaySamples)); /* Number of samples to move */
-#endif
- NumSamples = 0; /* Samples left to send */
- }
- }
-
-
- /*
- * Copy the processed results to the output
- */
- if ((NumSamples != 0) &&
- (SampleCount != 0))
- {
- if (SampleCount <= NumSamples)
- {
- /*
- * Copy all processed samples to the output
- */
-#ifdef SUPPORT_MC
- Copy_Float(pStart, /* Source */
- pDest, /* Destination */
- (LVM_INT16)(NrChannels * FrameCount)); /* Number of processed samples */
-#else
- Copy_Float(pStart, /* Source */
- pDest, /* Destination */
- (LVM_INT16)(2 * SampleCount)); /* Number of processed samples */
-#endif
- /*
- * Update the pointer and sample counts
- */
-#ifdef SUPPORT_MC
- pDest += NrChannels * FrameCount; /* Output sample pointer */
-#else
- pDest += 2 * SampleCount; /* Output sample pointer */
-#endif
- NumSamples = (LVM_INT16)(NumSamples - SampleCount); /* Samples left to send */
- SampleCount = 0; /* No samples left in the buffer */
- }
- else
- {
- /*
- * Copy only some processed samples to the output
- */
-#ifdef SUPPORT_MC
- Copy_Float(pStart, /* Source */
- pDest, /* Destination */
- (LVM_INT16)(NrChannels * NrFrames)); /* Number of processed samples */
-#else
- Copy_Float(pStart, /* Source */
- pDest, /* Destination */
- (LVM_INT16)(2 * NumSamples)); /* Number of processed samples */
-#endif
- /*
- * Update the pointers and sample counts
- */
-#ifdef SUPPORT_MC
- pStart += NrChannels * NrFrames; /* Processed sample pointer */
- pDest += NrChannels * NrFrames; /* Output sample pointer */
-#else
- pStart += 2 * NumSamples; /* Processed sample pointer */
- pDest += 2 * NumSamples; /* Output sample pointer */
-#endif
- SampleCount = (LVM_INT16)(SampleCount - NumSamples); /* Processed samples left */
- NumSamples = 0; /* Clear the sample count */
- }
- }
-
-
- /*
- * Copy the remaining processed data to the output delay buffer
- */
- if (SampleCount != 0)
- {
-#ifdef SUPPORT_MC
- Copy_Float(pStart, /* Source */
- /* Destination */
- &pBuffer->OutDelayBuffer[NrChannels * pBuffer->OutDelaySamples],
- (LVM_INT16)(NrChannels * FrameCount)); /* Number of processed samples */
-#else
- Copy_Float(pStart, /* Source */
- &pBuffer->OutDelayBuffer[2 * pBuffer->OutDelaySamples], /* Destination */
- (LVM_INT16)(2 * SampleCount)); /* Number of processed samples */
-#endif
- /* Update the buffer count */
- pBuffer->OutDelaySamples = (LVM_INT16)(pBuffer->OutDelaySamples + SampleCount);
- }
-
- /*
- * pointers, counts and set default buffer processing
- */
- pBuffer->SamplesToOutput = NumSamples; /* Samples left to send */
- pInstance->pOutputSamples = pDest; /* Output sample pointer */
- pBuffer->BufferState = LVM_MAXBLOCKCALL; /* Set for the default call \
- block size */
- /* This will terminate the loop when all samples processed */
- *pNumSamples = (LVM_UINT16)pInstance->SamplesToProcess;
-}
-#else
-void LVM_BufferManagedOut(LVM_Handle_t hInstance,
- LVM_INT16 *pOutData,
- LVM_UINT16 *pNumSamples)
-{
-
- LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
- LVM_Buffer_t *pBuffer = pInstance->pBufferManagement;
- LVM_INT16 SampleCount = (LVM_INT16)*pNumSamples;
- LVM_INT16 NumSamples;
- LVM_INT16 *pStart;
- LVM_INT16 *pDest;
-
-
- /*
- * Set the pointers
- */
- NumSamples = pBuffer->SamplesToOutput;
- pStart = pBuffer->pScratch;
-
-
- /*
- * check if it is the first call of a block
- */
- if ((pBuffer->BufferState == LVM_FIRSTCALL) ||
- (pBuffer->BufferState == LVM_FIRSTLASTCALL))
- {
- /* First call for a new block */
- pInstance->pOutputSamples = pOutData; /* Initialise the destination */
- }
- pDest = pInstance->pOutputSamples; /* Set the output address */
-
-
- /*
- * If the number of samples is non-zero then there are still samples to send to
- * the output buffer
- */
- if ((NumSamples != 0) &&
- (pBuffer->OutDelaySamples != 0))
- {
- /*
- * Copy the delayed output buffer samples to the output
- */
- if (pBuffer->OutDelaySamples <= NumSamples)
- {
- /*
- * Copy all output delay samples to the output
- */
- Copy_16(&pBuffer->OutDelayBuffer[0], /* Source */
- pDest, /* Detsination */
- (LVM_INT16)(2*pBuffer->OutDelaySamples)); /* Number of delay samples */
-
- /*
- * Update the pointer and sample counts
- */
- pDest += 2*pBuffer->OutDelaySamples; /* Output sample pointer */
- NumSamples = (LVM_INT16)(NumSamples - pBuffer->OutDelaySamples); /* Samples left to send */
- pBuffer->OutDelaySamples = 0; /* No samples left in the buffer */
-
- }
- else
- {
- /*
- * Copy only some of the ouput delay samples to the output
- */
- Copy_16(&pBuffer->OutDelayBuffer[0], /* Source */
- pDest, /* Detsination */
- (LVM_INT16)(2*NumSamples)); /* Number of delay samples */
-
- /*
- * Update the pointer and sample counts
- */
- pDest += 2*NumSamples; /* Output sample pointer */
- pBuffer->OutDelaySamples = (LVM_INT16)(pBuffer->OutDelaySamples - NumSamples); /* No samples left in the buffer */
-
-
- /*
- * Realign the delay buffer data to avoid using circular buffer management
- */
- Copy_16(&pBuffer->OutDelayBuffer[2*NumSamples], /* Source */
- &pBuffer->OutDelayBuffer[0], /* Destination */
- (LVM_INT16)(2*pBuffer->OutDelaySamples)); /* Number of samples to move */
- NumSamples = 0; /* Samples left to send */
- }
- }
-
-
- /*
- * Copy the processed results to the output
- */
- if ((NumSamples != 0) &&
- (SampleCount != 0))
- {
- if (SampleCount <= NumSamples)
- {
- /*
- * Copy all processed samples to the output
- */
- Copy_16(pStart, /* Source */
- pDest, /* Detsination */
- (LVM_INT16)(2*SampleCount)); /* Number of processed samples */
-
- /*
- * Update the pointer and sample counts
- */
- pDest += 2 * SampleCount; /* Output sample pointer */
- NumSamples = (LVM_INT16)(NumSamples - SampleCount); /* Samples left to send */
- SampleCount = 0; /* No samples left in the buffer */
- }
- else
- {
- /*
- * Copy only some processed samples to the output
- */
- Copy_16(pStart, /* Source */
- pDest, /* Destination */
- (LVM_INT16)(2*NumSamples)); /* Number of processed samples */
-
-
- /*
- * Update the pointers and sample counts
- */
- pStart += 2 * NumSamples; /* Processed sample pointer */
- pDest += 2 * NumSamples; /* Output sample pointer */
- SampleCount = (LVM_INT16)(SampleCount - NumSamples); /* Processed samples left */
- NumSamples = 0; /* Clear the sample count */
- }
- }
-
-
- /*
- * Copy the remaining processed data to the output delay buffer
- */
- if (SampleCount != 0)
- {
- Copy_16(pStart, /* Source */
- &pBuffer->OutDelayBuffer[2*pBuffer->OutDelaySamples], /* Destination */
- (LVM_INT16)(2*SampleCount)); /* Number of processed samples */
- pBuffer->OutDelaySamples = (LVM_INT16)(pBuffer->OutDelaySamples + SampleCount); /* Update the buffer count */
- }
-
-
- /*
- * pointers, counts and set default buffer processing
- */
- pBuffer->SamplesToOutput = NumSamples; /* Samples left to send */
- pInstance->pOutputSamples = pDest; /* Output sample pointer */
- pBuffer->BufferState = LVM_MAXBLOCKCALL; /* Set for the default call block size */
- *pNumSamples = (LVM_UINT16)pInstance->SamplesToProcess; /* This will terminate the loop when all samples processed */
-}
-#endif
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVM_BufferUnmanagedOut */
-/* */
-/* DESCRIPTION: */
-/* This works in conjunction with the unmanaged input routine and updates the number */
-/* of samples left to be processed and adjusts the buffer pointers. */
-/* */
-/* PARAMETERS: */
-/* hInstance - Instance handle */
-/* pNumSamples - Pointer to the number of samples to process */
-/* */
-/* RETURNS: */
-/* None */
-/* */
-/* NOTES: */
-/* */
-/****************************************************************************************/
-
-void LVM_BufferUnmanagedOut(LVM_Handle_t hInstance,
- LVM_UINT16 *pNumSamples)
-{
-
- LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
-#ifdef SUPPORT_MC
- LVM_INT16 NumChannels = pInstance->NrChannels;
- if (NumChannels == 1)
- {
- /* Mono input is processed as stereo by LVM module */
- NumChannels = 2;
- }
-#undef NrFrames
-#define NrFrames (*pNumSamples) // alias for clarity
-#else
- LVM_INT16 NumChannels = 2;
-#endif
-
-
- /*
- * Update sample counts
- */
- pInstance->pInputSamples += (LVM_INT16)(*pNumSamples * NumChannels); /* Update the I/O pointers */
-#ifdef SUPPORT_MC
- pInstance->pOutputSamples += (LVM_INT16)(NrFrames * NumChannels);
-#else
- pInstance->pOutputSamples += (LVM_INT16)(*pNumSamples * 2);
-#endif
- pInstance->SamplesToProcess = (LVM_INT16)(pInstance->SamplesToProcess - *pNumSamples); /* Update the sample count */
-
- /*
- * Set te block size to process
- */
- if (pInstance->SamplesToProcess > pInstance->InternalBlockSize)
- {
- *pNumSamples = (LVM_UINT16)pInstance->InternalBlockSize;
- }
- else
- {
- *pNumSamples = (LVM_UINT16)pInstance->SamplesToProcess;
- }
-}
-
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVM_BufferOptimisedOut */
-/* */
-/* DESCRIPTION: */
-/* This works in conjunction with the optimised input routine and copies the last few */
-/* processed and unprocessed samples to their respective buffers. */
-/* */
-/* PARAMETERS: */
-/* hInstance - Instance handle */
-/* pNumSamples - Pointer to the number of samples to process */
-/* */
-/* RETURNS: */
-/* None */
-/* */
-/* NOTES: */
-/* */
-/****************************************************************************************/
-
-#ifndef BUILD_FLOAT
-void LVM_BufferOptimisedOut(LVM_Handle_t hInstance,
- LVM_UINT16 *pNumSamples)
-{
-
- LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
- LVM_Buffer_t *pBuffer = pInstance->pBufferManagement;
-
- /*
- * Check if it is the last block to process
- */
- if (pBuffer->BufferState == LVM_LASTCALL)
- {
- LVM_INT16 *pSrc = pBuffer->pScratch;
-
- /*
- * Copy the unprocessed samples to the input delay buffer
- */
- if (pInstance->SamplesToProcess != 0)
- {
- Copy_16(pInstance->pInputSamples, /* Source */
- &pBuffer->InDelayBuffer[0], /* Destination */
- (LVM_INT16)(2*pInstance->SamplesToProcess)); /* Number of input samples */
- pBuffer->InDelaySamples = pInstance->SamplesToProcess;
- pInstance->SamplesToProcess = 0;
- }
- else
- {
- pBuffer->InDelaySamples = 0;
- }
-
-
- /*
- * Fill the last empty spaces in the output buffer
- */
- if (pBuffer->SamplesToOutput != 0)
- {
- Copy_16(pSrc, /* Source */
- pInstance->pOutputSamples, /* Destination */
- (LVM_INT16)(2*pBuffer->SamplesToOutput)); /* Number of input samples */
- *pNumSamples = (LVM_UINT16)(*pNumSamples - pBuffer->SamplesToOutput);
- pSrc += 2 * pBuffer->SamplesToOutput; /* Update scratch pointer */
- pBuffer->SamplesToOutput = 0; /* No more samples in this block */
- }
-
-
- /*
- * Save any remaining processed samples in the output delay buffer
- */
- if (*pNumSamples != 0)
- {
- Copy_16(pSrc, /* Source */
- &pBuffer->OutDelayBuffer[0], /* Destination */
- (LVM_INT16)(2**pNumSamples)); /* Number of input samples */
-
- pBuffer->OutDelaySamples = (LVM_INT16)*pNumSamples;
-
- *pNumSamples = 0; /* No more samples in this block */
- }
- else
- {
- pBuffer->OutDelaySamples = 0;
- }
- }
-}
-#endif
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVM_BufferOut */
-/* */
-/* DESCRIPTION: */
-/* This function manages the data output, it has the following features: */
-/* - Output data to 16-bit aligned memory */
-/* - Reads data from 32-bit aligned memory */
-/* - Reads data only in blocks of frame size or multiples of frame size */
-/* - Writes the same number of samples as the LVM_BufferIn function reads */
-/* - Works with inplace or outplace processing automatically */
-/* */
-/* To manage the data the function has a number of operating states: */
-/* LVM_FIRSTCALL - The first call for this block of input samples */
-/* LVM_FIRSTLASTCALL - This is the first and last call for this block of input*/
-/* samples, this occurs when the number of samples to */
-/* process is less than the maximum block size. */
-/* */
-/* The function uses an internal delay buffer the size of the minimum frame, this is */
-/* used to temporarily hold samples when the number of samples to write is not a */
-/* multiple of the frame size. */
-/* */
-/* To ensure correct operation with inplace buffering the number of samples to output*/
-/* per call is always the same as the number of samples read from the input buffer. */
-/* */
-/* PARAMETERS: */
-/* hInstance - Instance handle */
-/* pOutData - Pointer to the output data stream */
-/* pNumSamples - Pointer to the number of samples to process */
-/* */
-/* RETURNS: */
-/* None */
-/* */
-/* NOTES: */
-/* */
-/****************************************************************************************/
-#ifdef BUILD_FLOAT
-void LVM_BufferOut(LVM_Handle_t hInstance,
- LVM_FLOAT *pOutData,
- LVM_UINT16 *pNumSamples)
-{
-
- LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
-
-
- /*
- * Check which mode, managed or unmanaged
- */
- if (pInstance->InstParams.BufferMode == LVM_MANAGED_BUFFERS)
- {
- LVM_BufferManagedOut(hInstance,
- pOutData,
- pNumSamples);
- }
- else
- {
- LVM_BufferUnmanagedOut(hInstance,
- pNumSamples);
- }
-}
-#else
-void LVM_BufferOut(LVM_Handle_t hInstance,
- LVM_INT16 *pOutData,
- LVM_UINT16 *pNumSamples)
-{
-
- LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
-
-
- /*
- * Check which mode, managed or unmanaged
- */
- if (pInstance->InstParams.BufferMode == LVM_MANAGED_BUFFERS)
- {
- LVM_BufferManagedOut(hInstance,
- pOutData,
- pNumSamples);
- }
- else
- {
- LVM_BufferUnmanagedOut(hInstance,
- pNumSamples);
- }
-}
-#endif
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Buffers.cpp b/media/libeffects/lvm/lib/Bundle/src/LVM_Buffers.cpp
new file mode 100644
index 0000000..3aeddbb
--- /dev/null
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Buffers.cpp
@@ -0,0 +1,722 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/****************************************************************************************/
+/* */
+/* Includes */
+/* */
+/****************************************************************************************/
+
+#include "LVM_Private.h"
+#include "VectorArithmetic.h"
+
+#include <log/log.h>
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVM_BufferManagedIn */
+/* */
+/* DESCRIPTION: */
+/* Full buffer management allowing the user to provide input and output buffers on */
+/* any alignment and with any number of samples. The alignment is corrected within */
+/* the buffer management and the samples are grouped in to blocks of the correct size */
+/* before processing. */
+/* */
+/* PARAMETERS: */
+/* hInstance - Instance handle */
+/* pInData - Pointer to the input data stream */
+/* *pToProcess - Pointer to pointer to the start of data processing */
+/* *pProcessed - Pointer to pointer to the destination of the processed data */
+/* pNumSamples - Pointer to the number of samples to process */
+/* */
+/* RETURNS: */
+/* None */
+/* */
+/* NOTES: */
+/* */
+/****************************************************************************************/
+void LVM_BufferManagedIn(LVM_Handle_t hInstance,
+ const LVM_FLOAT *pInData,
+ LVM_FLOAT **pToProcess,
+ LVM_FLOAT **pProcessed,
+ LVM_UINT16 *pNumSamples)
+{
+
+ LVM_INT16 SampleCount; /* Number of samples to be processed this call */
+ LVM_INT16 NumSamples; /* Number of samples in scratch buffer */
+ LVM_FLOAT *pStart;
+ LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
+ LVM_Buffer_t *pBuffer;
+ LVM_FLOAT *pDest;
+#ifdef SUPPORT_MC
+ LVM_INT16 NumChannels = pInstance->NrChannels;
+#else
+ LVM_INT16 NumChannels = 2;
+#endif
+
+ /*
+ * Set the processing address pointers
+ */
+ pBuffer = pInstance->pBufferManagement;
+ pDest = pBuffer->pScratch;
+ *pToProcess = pBuffer->pScratch;
+ *pProcessed = pBuffer->pScratch;
+
+ /*
+ * Check if it is the first call of a block
+ */
+ if (pInstance->SamplesToProcess == 0)
+ {
+ /*
+ * First call for a new block of samples
+ */
+ pInstance->SamplesToProcess = (LVM_INT16)(*pNumSamples + pBuffer->InDelaySamples);
+ pInstance->pInputSamples = (LVM_FLOAT *)pInData;
+ pBuffer->BufferState = LVM_FIRSTCALL;
+ }
+ pStart = pInstance->pInputSamples; /* Pointer to the input samples */
+ pBuffer->SamplesToOutput = 0; /* Samples to output is same as
+ number read for inplace processing */
+
+ /*
+ * Calculate the number of samples to process this call and update the buffer state
+ */
+ if (pInstance->SamplesToProcess > pInstance->InternalBlockSize)
+ {
+ /*
+ * Process the maximum bock size of samples.
+ */
+ SampleCount = pInstance->InternalBlockSize;
+ NumSamples = pInstance->InternalBlockSize;
+ }
+ else
+ {
+ /*
+ * Last call for the block, so calculate how many frames and samples to process
+ */
+ LVM_INT16 NumFrames;
+
+ NumSamples = pInstance->SamplesToProcess;
+ NumFrames = (LVM_INT16)(NumSamples >> MIN_INTERNAL_BLOCKSHIFT);
+ SampleCount = (LVM_INT16)(NumFrames << MIN_INTERNAL_BLOCKSHIFT);
+
+ /*
+ * Update the buffer state
+ */
+ if (pBuffer->BufferState == LVM_FIRSTCALL)
+ {
+ pBuffer->BufferState = LVM_FIRSTLASTCALL;
+ }
+ else
+ {
+ pBuffer->BufferState = LVM_LASTCALL;
+ }
+ }
+ *pNumSamples = (LVM_UINT16)SampleCount; /* Set the number of samples to process this call */
+
+ /*
+ * Copy samples from the delay buffer as required
+ */
+ if (((pBuffer->BufferState == LVM_FIRSTCALL) ||
+ (pBuffer->BufferState == LVM_FIRSTLASTCALL)) &&
+ (pBuffer->InDelaySamples != 0))
+ {
+ Copy_Float(&pBuffer->InDelayBuffer[0], /* Source */
+ pDest, /* Destination */
+ (LVM_INT16)(NumChannels * pBuffer->InDelaySamples)); /* Number of delay \
+ samples, left and right */
+ NumSamples = (LVM_INT16)(NumSamples - pBuffer->InDelaySamples); /* Update sample count */
+ pDest += NumChannels * pBuffer->InDelaySamples; /* Update the destination pointer */
+ }
+
+ /*
+ * Copy the rest of the samples for this call from the input buffer
+ */
+ if (NumSamples > 0)
+ {
+ Copy_Float(pStart, /* Source */
+ pDest, /* Destination */
+ (LVM_INT16)(NumChannels * NumSamples)); /* Number of input samples */
+ pStart += NumChannels * NumSamples; /* Update the input pointer */
+
+ /*
+ * Update the input data pointer and samples to output
+ */
+ /* Update samples to output */
+ pBuffer->SamplesToOutput = (LVM_INT16)(pBuffer->SamplesToOutput + NumSamples);
+ }
+
+ /*
+ * Update the sample count and input pointer
+ */
+ /* Update the count of samples */
+ pInstance->SamplesToProcess = (LVM_INT16)(pInstance->SamplesToProcess - SampleCount);
+ pInstance->pInputSamples = pStart; /* Update input sample pointer */
+
+ /*
+ * Save samples to the delay buffer if any left unprocessed
+ */
+ if ((pBuffer->BufferState == LVM_FIRSTLASTCALL) ||
+ (pBuffer->BufferState == LVM_LASTCALL))
+ {
+ NumSamples = pInstance->SamplesToProcess;
+ pStart = pBuffer->pScratch; /* Start of the buffer */
+ pStart += NumChannels * SampleCount; /* Offset by the number of processed samples */
+ if (NumSamples != 0)
+ {
+ Copy_Float(pStart, /* Source */
+ &pBuffer->InDelayBuffer[0], /* Destination */
+ (LVM_INT16)(NumChannels * NumSamples)); /* Number of input samples */
+ }
+
+ /*
+ * Update the delay sample count
+ */
+ pBuffer->InDelaySamples = NumSamples; /* Number of delay sample pairs */
+ pInstance->SamplesToProcess = 0; /* All Samples used */
+ }
+}
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVM_BufferUnmanagedIn */
+/* */
+/* DESCRIPTION: */
+/* This mode is selected by the user code and disables the buffer management with the */
+/* exception of the maximum block size processing. The user must ensure that the */
+/* input and output buffers are 32-bit aligned and also that the number of samples to */
+/* process is a correct multiple of samples. */
+/* */
+/* PARAMETERS: */
+/* hInstance - Instance handle */
+/* *pToProcess - Pointer to the start of data processing */
+/* *pProcessed - Pointer to the destination of the processed data */
+/* pNumSamples - Pointer to the number of samples to process */
+/* */
+/* RETURNS: */
+/* None */
+/* */
+/* NOTES: */
+/* */
+/****************************************************************************************/
+void LVM_BufferUnmanagedIn(LVM_Handle_t hInstance,
+ LVM_FLOAT **pToProcess,
+ LVM_FLOAT **pProcessed,
+ LVM_UINT16 *pNumSamples)
+{
+
+ LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
+
+ /*
+ * Check if this is the first call of a block
+ */
+ if (pInstance->SamplesToProcess == 0)
+ {
+ pInstance->SamplesToProcess = (LVM_INT16)*pNumSamples; /* Get the number of samples
+ on first call */
+ pInstance->pInputSamples = *pToProcess; /* Get the I/O pointers */
+ pInstance->pOutputSamples = *pProcessed;
+
+ /*
+ * Set te block size to process
+ */
+ if (pInstance->SamplesToProcess > pInstance->InternalBlockSize)
+ {
+ *pNumSamples = (LVM_UINT16)pInstance->InternalBlockSize;
+ }
+ else
+ {
+ *pNumSamples = (LVM_UINT16)pInstance->SamplesToProcess;
+ }
+ }
+
+ /*
+ * Set the process pointers
+ */
+ *pToProcess = pInstance->pInputSamples;
+ *pProcessed = pInstance->pOutputSamples;
+}
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVM_BufferOptimisedIn */
+/* */
+/* DESCRIPTION: */
+/* Optimised buffer management for the case where the data is outplace processing, */
+/* the output data is 32-bit aligned and there are sufficient samples to allow some */
+/* processing directly in the output buffer. This saves one data copy per sample */
+/* compared with the unoptimsed version. */
+/* */
+/* PARAMETERS: */
+/* hInstance - Instance handle */
+/* pInData - Pointer to the input data stream */
+/* *pToProcess - Pointer to the start of data processing */
+/* *pProcessed - Pointer to the destination of the processed data */
+/* pNumSamples - Pointer to the number of samples to process */
+/* */
+/* RETURNS: */
+/* None */
+/* */
+/* NOTES: */
+/* */
+/****************************************************************************************/
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVM_BufferIn */
+/* */
+/* DESCRIPTION: */
+/* This function manages the data input, it has the following features: */
+/* - Accepts data in 16-bit aligned memory */
+/* - Copies the data to 32-bit aligned memory */
+/* - Converts Mono inputs to Mono-in-Stereo */
+/* - Accepts any number of samples as input, except 0 */
+/* - Breaks the input sample stream in to blocks of the configured frame size or */
+/* multiples of the frame size */
+/* - Limits the processing block size to the maximum block size. */
+/* - Works with inplace or outplace processing automatically */
+/* */
+/* To manage the data the function has a number of operating states: */
+/* LVM_FIRSTCALL - The first call for this block of input samples */
+/* LVM_MAXBLOCKCALL - The current block is the maximum size. Only used for the */
+/* second and subsequent blocks. */
+/* LVM_LASTCALL - The last call for this block of input samples */
+/* LVM_FIRSTLASTCALL - This is the first and last call for this block of input*/
+/* samples, this occurs when the number of samples to */
+/* process is less than the maximum block size. */
+/* */
+/* The function uses an internal delay buffer the size of the minimum frame, this is */
+/* used to temporarily hold samples when the number of samples to process is not a */
+/* multiple of the frame size. */
+/* */
+/* To ensure correct operation with inplace buffering the number of samples to output*/
+/* per call is calculated in this function and is set to the number of samples read */
+/* from the input buffer. */
+/* */
+/* The total number of samples to process is stored when the function is called for */
+/* the first time. The value is overwritten by the size of the block to be processed */
+/* in each call so the size of the processing blocks can be controlled. The number of */
+/* samples actually processed for each block of input samples is always a multiple of*/
+/* the frame size so for any particular block of input samples the actual number of */
+/* processed samples may not match the number of input samples, sometime it will be */
+/* sometimes less. The average is the same and the difference is never more than the */
+/* frame size. */
+/* */
+/* PARAMETERS: */
+/* hInstance - Instance handle */
+/* pInData - Pointer to the input data stream */
+/* *pToProcess - Pointer to the start of data processing */
+/* *pProcessed - Pointer to the destination of the processed data */
+/* pNumSamples - Pointer to the number of samples to process */
+/* */
+/* RETURNS: */
+/* None */
+/* */
+/* NOTES: */
+/* */
+/****************************************************************************************/
+void LVM_BufferIn(LVM_Handle_t hInstance,
+ const LVM_FLOAT *pInData,
+ LVM_FLOAT **pToProcess,
+ LVM_FLOAT **pProcessed,
+ LVM_UINT16 *pNumSamples)
+{
+
+ LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
+
+ /*
+ * Check which mode, managed or unmanaged
+ */
+ if (pInstance->InstParams.BufferMode == LVM_MANAGED_BUFFERS)
+ {
+ LVM_BufferManagedIn(hInstance,
+ pInData,
+ pToProcess,
+ pProcessed,
+ pNumSamples);
+ }
+ else
+ {
+ LVM_BufferUnmanagedIn(hInstance,
+ pToProcess,
+ pProcessed,
+ pNumSamples);
+ }
+}
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVM_BufferManagedOut */
+/* */
+/* DESCRIPTION: */
+/* Full buffer management output. This works in conjunction with the managed input */
+/* routine and ensures the correct number of samples are always output to the output */
+/* buffer. */
+/* */
+/* PARAMETERS: */
+/* hInstance - Instance handle */
+/* pOutData - Pointer to the output data stream */
+/* pNumSamples - Pointer to the number of samples to process */
+/* */
+/* RETURNS: */
+/* None */
+/* */
+/* NOTES: */
+/* */
+/****************************************************************************************/
+void LVM_BufferManagedOut(LVM_Handle_t hInstance,
+ LVM_FLOAT *pOutData,
+ LVM_UINT16 *pNumSamples)
+{
+
+ LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
+ LVM_Buffer_t *pBuffer = pInstance->pBufferManagement;
+ LVM_INT16 SampleCount = (LVM_INT16)*pNumSamples;
+ LVM_INT16 NumSamples;
+ LVM_FLOAT *pStart;
+ LVM_FLOAT *pDest;
+#ifdef SUPPORT_MC
+ LVM_INT32 NrChannels = pInstance->NrChannels;
+#define NrFrames NumSamples // alias for clarity
+#define FrameCount SampleCount
+#endif
+
+ /*
+ * Set the pointers
+ */
+ NumSamples = pBuffer->SamplesToOutput;
+ pStart = pBuffer->pScratch;
+
+ /*
+ * check if it is the first call of a block
+ */
+ if ((pBuffer->BufferState == LVM_FIRSTCALL) ||
+ (pBuffer->BufferState == LVM_FIRSTLASTCALL))
+ {
+ /* First call for a new block */
+ pInstance->pOutputSamples = pOutData; /* Initialise the destination */
+ }
+ pDest = pInstance->pOutputSamples; /* Set the output address */
+
+ /*
+ * If the number of samples is non-zero then there are still samples to send to
+ * the output buffer
+ */
+ if ((NumSamples != 0) &&
+ (pBuffer->OutDelaySamples != 0))
+ {
+ /*
+ * Copy the delayed output buffer samples to the output
+ */
+ if (pBuffer->OutDelaySamples <= NumSamples)
+ {
+ /*
+ * Copy all output delay samples to the output
+ */
+#ifdef SUPPORT_MC
+ Copy_Float(&pBuffer->OutDelayBuffer[0], /* Source */
+ pDest, /* Destination */
+ /* Number of delay samples */
+ (LVM_INT16)(NrChannels * pBuffer->OutDelaySamples));
+#else
+ Copy_Float(&pBuffer->OutDelayBuffer[0], /* Source */
+ pDest, /* Destination */
+ (LVM_INT16)(2 * pBuffer->OutDelaySamples)); /* Number of delay samples */
+#endif
+
+ /*
+ * Update the pointer and sample counts
+ */
+#ifdef SUPPORT_MC
+ pDest += NrChannels * pBuffer->OutDelaySamples; /* Output sample pointer */
+#else
+ pDest += 2 * pBuffer->OutDelaySamples; /* Output sample pointer */
+#endif
+ NumSamples = (LVM_INT16)(NumSamples - pBuffer->OutDelaySamples); /* Samples left \
+ to send */
+ pBuffer->OutDelaySamples = 0; /* No samples left in the buffer */
+ }
+ else
+ {
+ /*
+ * Copy only some of the ouput delay samples to the output
+ */
+#ifdef SUPPORT_MC
+ Copy_Float(&pBuffer->OutDelayBuffer[0], /* Source */
+ pDest, /* Destination */
+ (LVM_INT16)(NrChannels * NrFrames)); /* Number of delay samples */
+#else
+ Copy_Float(&pBuffer->OutDelayBuffer[0], /* Source */
+ pDest, /* Destination */
+ (LVM_INT16)(2 * NumSamples)); /* Number of delay samples */
+#endif
+
+ /*
+ * Update the pointer and sample counts
+ */
+#ifdef SUPPORT_MC
+ pDest += NrChannels * NrFrames; /* Output sample pointer */
+#else
+ pDest += 2 * NumSamples; /* Output sample pointer */
+#endif
+ /* No samples left in the buffer */
+ pBuffer->OutDelaySamples = (LVM_INT16)(pBuffer->OutDelaySamples - NumSamples);
+
+ /*
+ * Realign the delay buffer data to avoid using circular buffer management
+ */
+#ifdef SUPPORT_MC
+ Copy_Float(&pBuffer->OutDelayBuffer[NrChannels * NrFrames], /* Source */
+ &pBuffer->OutDelayBuffer[0], /* Destination */
+ /* Number of samples to move */
+ (LVM_INT16)(NrChannels * pBuffer->OutDelaySamples));
+#else
+ Copy_Float(&pBuffer->OutDelayBuffer[2 * NumSamples], /* Source */
+ &pBuffer->OutDelayBuffer[0], /* Destination */
+ (LVM_INT16)(2 * pBuffer->OutDelaySamples)); /* Number of samples to move */
+#endif
+ NumSamples = 0; /* Samples left to send */
+ }
+ }
+
+ /*
+ * Copy the processed results to the output
+ */
+ if ((NumSamples != 0) &&
+ (SampleCount != 0))
+ {
+ if (SampleCount <= NumSamples)
+ {
+ /*
+ * Copy all processed samples to the output
+ */
+#ifdef SUPPORT_MC
+ Copy_Float(pStart, /* Source */
+ pDest, /* Destination */
+ (LVM_INT16)(NrChannels * FrameCount)); /* Number of processed samples */
+#else
+ Copy_Float(pStart, /* Source */
+ pDest, /* Destination */
+ (LVM_INT16)(2 * SampleCount)); /* Number of processed samples */
+#endif
+ /*
+ * Update the pointer and sample counts
+ */
+#ifdef SUPPORT_MC
+ pDest += NrChannels * FrameCount; /* Output sample pointer */
+#else
+ pDest += 2 * SampleCount; /* Output sample pointer */
+#endif
+ NumSamples = (LVM_INT16)(NumSamples - SampleCount); /* Samples left to send */
+ SampleCount = 0; /* No samples left in the buffer */
+ }
+ else
+ {
+ /*
+ * Copy only some processed samples to the output
+ */
+#ifdef SUPPORT_MC
+ Copy_Float(pStart, /* Source */
+ pDest, /* Destination */
+ (LVM_INT16)(NrChannels * NrFrames)); /* Number of processed samples */
+#else
+ Copy_Float(pStart, /* Source */
+ pDest, /* Destination */
+ (LVM_INT16)(2 * NumSamples)); /* Number of processed samples */
+#endif
+ /*
+ * Update the pointers and sample counts
+ */
+#ifdef SUPPORT_MC
+ pStart += NrChannels * NrFrames; /* Processed sample pointer */
+ pDest += NrChannels * NrFrames; /* Output sample pointer */
+#else
+ pStart += 2 * NumSamples; /* Processed sample pointer */
+ pDest += 2 * NumSamples; /* Output sample pointer */
+#endif
+ SampleCount = (LVM_INT16)(SampleCount - NumSamples); /* Processed samples left */
+ NumSamples = 0; /* Clear the sample count */
+ }
+ }
+
+ /*
+ * Copy the remaining processed data to the output delay buffer
+ */
+ if (SampleCount != 0)
+ {
+#ifdef SUPPORT_MC
+ Copy_Float(pStart, /* Source */
+ /* Destination */
+ &pBuffer->OutDelayBuffer[NrChannels * pBuffer->OutDelaySamples],
+ (LVM_INT16)(NrChannels * FrameCount)); /* Number of processed samples */
+#else
+ Copy_Float(pStart, /* Source */
+ &pBuffer->OutDelayBuffer[2 * pBuffer->OutDelaySamples], /* Destination */
+ (LVM_INT16)(2 * SampleCount)); /* Number of processed samples */
+#endif
+ /* Update the buffer count */
+ pBuffer->OutDelaySamples = (LVM_INT16)(pBuffer->OutDelaySamples + SampleCount);
+ }
+
+ /*
+ * pointers, counts and set default buffer processing
+ */
+ pBuffer->SamplesToOutput = NumSamples; /* Samples left to send */
+ pInstance->pOutputSamples = pDest; /* Output sample pointer */
+ pBuffer->BufferState = LVM_MAXBLOCKCALL; /* Set for the default call \
+ block size */
+ /* This will terminate the loop when all samples processed */
+ *pNumSamples = (LVM_UINT16)pInstance->SamplesToProcess;
+}
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVM_BufferUnmanagedOut */
+/* */
+/* DESCRIPTION: */
+/* This works in conjunction with the unmanaged input routine and updates the number */
+/* of samples left to be processed and adjusts the buffer pointers. */
+/* */
+/* PARAMETERS: */
+/* hInstance - Instance handle */
+/* pNumSamples - Pointer to the number of samples to process */
+/* */
+/* RETURNS: */
+/* None */
+/* */
+/* NOTES: */
+/* */
+/****************************************************************************************/
+
+void LVM_BufferUnmanagedOut(LVM_Handle_t hInstance,
+ LVM_UINT16 *pNumSamples)
+{
+
+ LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
+#ifdef SUPPORT_MC
+ LVM_INT16 NumChannels = pInstance->NrChannels;
+ if (NumChannels == 1)
+ {
+ /* Mono input is processed as stereo by LVM module */
+ NumChannels = 2;
+ }
+#undef NrFrames
+#define NrFrames (*pNumSamples) // alias for clarity
+#else
+ LVM_INT16 NumChannels = 2;
+#endif
+
+ /*
+ * Update sample counts
+ */
+ pInstance->pInputSamples += (LVM_INT16)(*pNumSamples * NumChannels); /* Update the I/O pointers */
+#ifdef SUPPORT_MC
+ pInstance->pOutputSamples += (LVM_INT16)(NrFrames * NumChannels);
+#else
+ pInstance->pOutputSamples += (LVM_INT16)(*pNumSamples * 2);
+#endif
+ pInstance->SamplesToProcess = (LVM_INT16)(pInstance->SamplesToProcess - *pNumSamples); /* Update the sample count */
+
+ /*
+ * Set te block size to process
+ */
+ if (pInstance->SamplesToProcess > pInstance->InternalBlockSize)
+ {
+ *pNumSamples = (LVM_UINT16)pInstance->InternalBlockSize;
+ }
+ else
+ {
+ *pNumSamples = (LVM_UINT16)pInstance->SamplesToProcess;
+ }
+}
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVM_BufferOptimisedOut */
+/* */
+/* DESCRIPTION: */
+/* This works in conjunction with the optimised input routine and copies the last few */
+/* processed and unprocessed samples to their respective buffers. */
+/* */
+/* PARAMETERS: */
+/* hInstance - Instance handle */
+/* pNumSamples - Pointer to the number of samples to process */
+/* */
+/* RETURNS: */
+/* None */
+/* */
+/* NOTES: */
+/* */
+/****************************************************************************************/
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVM_BufferOut */
+/* */
+/* DESCRIPTION: */
+/* This function manages the data output, it has the following features: */
+/* - Output data to 16-bit aligned memory */
+/* - Reads data from 32-bit aligned memory */
+/* - Reads data only in blocks of frame size or multiples of frame size */
+/* - Writes the same number of samples as the LVM_BufferIn function reads */
+/* - Works with inplace or outplace processing automatically */
+/* */
+/* To manage the data the function has a number of operating states: */
+/* LVM_FIRSTCALL - The first call for this block of input samples */
+/* LVM_FIRSTLASTCALL - This is the first and last call for this block of input*/
+/* samples, this occurs when the number of samples to */
+/* process is less than the maximum block size. */
+/* */
+/* The function uses an internal delay buffer the size of the minimum frame, this is */
+/* used to temporarily hold samples when the number of samples to write is not a */
+/* multiple of the frame size. */
+/* */
+/* To ensure correct operation with inplace buffering the number of samples to output*/
+/* per call is always the same as the number of samples read from the input buffer. */
+/* */
+/* PARAMETERS: */
+/* hInstance - Instance handle */
+/* pOutData - Pointer to the output data stream */
+/* pNumSamples - Pointer to the number of samples to process */
+/* */
+/* RETURNS: */
+/* None */
+/* */
+/* NOTES: */
+/* */
+/****************************************************************************************/
+void LVM_BufferOut(LVM_Handle_t hInstance,
+ LVM_FLOAT *pOutData,
+ LVM_UINT16 *pNumSamples)
+{
+
+ LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
+
+ /*
+ * Check which mode, managed or unmanaged
+ */
+ if (pInstance->InstParams.BufferMode == LVM_MANAGED_BUFFERS)
+ {
+ LVM_BufferManagedOut(hInstance,
+ pOutData,
+ pNumSamples);
+ }
+ else
+ {
+ LVM_BufferUnmanagedOut(hInstance,
+ pNumSamples);
+ }
+}
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Coeffs.h b/media/libeffects/lvm/lib/Bundle/src/LVM_Coeffs.h
index bab4049..812f8e5 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Coeffs.h
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Coeffs.h
@@ -18,7 +18,6 @@
#ifndef __LVM_COEFFS_H__
#define __LVM_COEFFS_H__
-
/************************************************************************************/
/* */
/* High Pass Shelving Filter coefficients */
@@ -29,7 +28,6 @@
#define TrebleBoostMinRate 4
#define TrebleBoostSteps 15
-#ifdef BUILD_FLOAT
/* Coefficients for sample rate 22050Hz */
/* Gain = 1.000000 dB */
#define HPF_Fs22050_Gain1_A0 1.038434
@@ -486,7 +484,6 @@
#define HPF_Fs48000_Gain15_B1 (-0.267949)
#define HPF_Fs48000_Gain15_B2 0.000000
-#ifdef HIGHER_FS
/* Coefficients for sample rate 88200 */
/* Gain = 1.000000 dB */
#define HPF_Fs88200_Gain1_A0 1.094374f
@@ -856,547 +853,3 @@
#define HPF_Fs192000_Gain15_B2 0.000000
#endif
-
-#else
-/* Coefficients for sample rate 22050Hz */
- /* Gain = 1.000000 dB */
-#define HPF_Fs22050_Gain1_A0 5383 /* Floating point value 0.164291 */
-#define HPF_Fs22050_Gain1_A1 16859 /* Floating point value 0.514492 */
-#define HPF_Fs22050_Gain1_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs22050_Gain1_B1 12125 /* Floating point value 0.370033 */
-#define HPF_Fs22050_Gain1_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs22050_Gain1_Shift 1 /* Shift value */
- /* Gain = 2.000000 dB */
-#define HPF_Fs22050_Gain2_A0 4683 /* Floating point value 0.142925 */
-#define HPF_Fs22050_Gain2_A1 17559 /* Floating point value 0.535858 */
-#define HPF_Fs22050_Gain2_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs22050_Gain2_B1 12125 /* Floating point value 0.370033 */
-#define HPF_Fs22050_Gain2_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs22050_Gain2_Shift 1 /* Shift value */
- /* Gain = 3.000000 dB */
-#define HPF_Fs22050_Gain3_A0 3898 /* Floating point value 0.118953 */
-#define HPF_Fs22050_Gain3_A1 18345 /* Floating point value 0.559830 */
-#define HPF_Fs22050_Gain3_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs22050_Gain3_B1 12125 /* Floating point value 0.370033 */
-#define HPF_Fs22050_Gain3_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs22050_Gain3_Shift 1 /* Shift value */
- /* Gain = 4.000000 dB */
-#define HPF_Fs22050_Gain4_A0 3016 /* Floating point value 0.092055 */
-#define HPF_Fs22050_Gain4_A1 19226 /* Floating point value 0.586728 */
-#define HPF_Fs22050_Gain4_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs22050_Gain4_B1 12125 /* Floating point value 0.370033 */
-#define HPF_Fs22050_Gain4_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs22050_Gain4_Shift 1 /* Shift value */
- /* Gain = 5.000000 dB */
-#define HPF_Fs22050_Gain5_A0 2028 /* Floating point value 0.061876 */
-#define HPF_Fs22050_Gain5_A1 20215 /* Floating point value 0.616907 */
-#define HPF_Fs22050_Gain5_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs22050_Gain5_B1 12125 /* Floating point value 0.370033 */
-#define HPF_Fs22050_Gain5_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs22050_Gain5_Shift 1 /* Shift value */
- /* Gain = 6.000000 dB */
-#define HPF_Fs22050_Gain6_A0 918 /* Floating point value 0.028013 */
-#define HPF_Fs22050_Gain6_A1 21324 /* Floating point value 0.650770 */
-#define HPF_Fs22050_Gain6_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs22050_Gain6_B1 12125 /* Floating point value 0.370033 */
-#define HPF_Fs22050_Gain6_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs22050_Gain6_Shift 1 /* Shift value */
- /* Gain = 7.000000 dB */
-#define HPF_Fs22050_Gain7_A0 (-164) /* Floating point value -0.005002 */
-#define HPF_Fs22050_Gain7_A1 11311 /* Floating point value 0.345199 */
-#define HPF_Fs22050_Gain7_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs22050_Gain7_B1 12125 /* Floating point value 0.370033 */
-#define HPF_Fs22050_Gain7_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs22050_Gain7_Shift 2 /* Shift value */
- /* Gain = 8.000000 dB */
-#define HPF_Fs22050_Gain8_A0 (-864) /* Floating point value -0.026368 */
-#define HPF_Fs22050_Gain8_A1 12012 /* Floating point value 0.366565 */
-#define HPF_Fs22050_Gain8_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs22050_Gain8_B1 12125 /* Floating point value 0.370033 */
-#define HPF_Fs22050_Gain8_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs22050_Gain8_Shift 2 /* Shift value */
- /* Gain = 9.000000 dB */
-#define HPF_Fs22050_Gain9_A0 (-1650) /* Floating point value -0.050340 */
-#define HPF_Fs22050_Gain9_A1 12797 /* Floating point value 0.390537 */
-#define HPF_Fs22050_Gain9_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs22050_Gain9_B1 12125 /* Floating point value 0.370033 */
-#define HPF_Fs22050_Gain9_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs22050_Gain9_Shift 2 /* Shift value */
- /* Gain = 10.000000 dB */
-#define HPF_Fs22050_Gain10_A0 (-2531) /* Floating point value -0.077238 */
-#define HPF_Fs22050_Gain10_A1 13679 /* Floating point value 0.417435 */
-#define HPF_Fs22050_Gain10_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs22050_Gain10_B1 12125 /* Floating point value 0.370033 */
-#define HPF_Fs22050_Gain10_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs22050_Gain10_Shift 2 /* Shift value */
- /* Gain = 11.000000 dB */
-#define HPF_Fs22050_Gain11_A0 (-3520) /* Floating point value -0.107417 */
-#define HPF_Fs22050_Gain11_A1 14667 /* Floating point value 0.447615 */
-#define HPF_Fs22050_Gain11_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs22050_Gain11_B1 12125 /* Floating point value 0.370033 */
-#define HPF_Fs22050_Gain11_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs22050_Gain11_Shift 2 /* Shift value */
- /* Gain = 12.000000 dB */
-#define HPF_Fs22050_Gain12_A0 (-4629) /* Floating point value -0.141279 */
-#define HPF_Fs22050_Gain12_A1 15777 /* Floating point value 0.481477 */
-#define HPF_Fs22050_Gain12_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs22050_Gain12_B1 12125 /* Floating point value 0.370033 */
-#define HPF_Fs22050_Gain12_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs22050_Gain12_Shift 2 /* Shift value */
- /* Gain = 13.000000 dB */
-#define HPF_Fs22050_Gain13_A0 (-2944) /* Floating point value -0.089849 */
-#define HPF_Fs22050_Gain13_A1 8531 /* Floating point value 0.260352 */
-#define HPF_Fs22050_Gain13_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs22050_Gain13_B1 12125 /* Floating point value 0.370033 */
-#define HPF_Fs22050_Gain13_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs22050_Gain13_Shift 3 /* Shift value */
- /* Gain = 14.000000 dB */
-#define HPF_Fs22050_Gain14_A0 (-3644) /* Floating point value -0.111215 */
-#define HPF_Fs22050_Gain14_A1 9231 /* Floating point value 0.281718 */
-#define HPF_Fs22050_Gain14_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs22050_Gain14_B1 12125 /* Floating point value 0.370033 */
-#define HPF_Fs22050_Gain14_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs22050_Gain14_Shift 3 /* Shift value */
- /* Gain = 15.000000 dB */
-#define HPF_Fs22050_Gain15_A0 (-4430) /* Floating point value -0.135187 */
-#define HPF_Fs22050_Gain15_A1 10017 /* Floating point value 0.305690 */
-#define HPF_Fs22050_Gain15_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs22050_Gain15_B1 12125 /* Floating point value 0.370033 */
-#define HPF_Fs22050_Gain15_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs22050_Gain15_Shift 3 /* Shift value */
-
-
-/* Coefficients for sample rate 24000Hz */
- /* Gain = 1.000000 dB */
-#define HPF_Fs24000_Gain1_A0 3625 /* Floating point value 0.110628 */
-#define HPF_Fs24000_Gain1_A1 16960 /* Floating point value 0.517578 */
-#define HPF_Fs24000_Gain1_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs24000_Gain1_B1 8780 /* Floating point value 0.267949 */
-#define HPF_Fs24000_Gain1_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs24000_Gain1_Shift 1 /* Shift value */
- /* Gain = 2.000000 dB */
-#define HPF_Fs24000_Gain2_A0 2811 /* Floating point value 0.085800 */
-#define HPF_Fs24000_Gain2_A1 17774 /* Floating point value 0.542406 */
-#define HPF_Fs24000_Gain2_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs24000_Gain2_B1 8780 /* Floating point value 0.267949 */
-#define HPF_Fs24000_Gain2_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs24000_Gain2_Shift 1 /* Shift value */
- /* Gain = 3.000000 dB */
-#define HPF_Fs24000_Gain3_A0 1899 /* Floating point value 0.057943 */
-#define HPF_Fs24000_Gain3_A1 18686 /* Floating point value 0.570263 */
-#define HPF_Fs24000_Gain3_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs24000_Gain3_B1 8780 /* Floating point value 0.267949 */
-#define HPF_Fs24000_Gain3_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs24000_Gain3_Shift 1 /* Shift value */
- /* Gain = 4.000000 dB */
-#define HPF_Fs24000_Gain4_A0 874 /* Floating point value 0.026687 */
-#define HPF_Fs24000_Gain4_A1 19711 /* Floating point value 0.601519 */
-#define HPF_Fs24000_Gain4_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs24000_Gain4_B1 8780 /* Floating point value 0.267949 */
-#define HPF_Fs24000_Gain4_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs24000_Gain4_Shift 1 /* Shift value */
- /* Gain = 5.000000 dB */
-#define HPF_Fs24000_Gain5_A0 (-275) /* Floating point value -0.008383 */
-#define HPF_Fs24000_Gain5_A1 20860 /* Floating point value 0.636589 */
-#define HPF_Fs24000_Gain5_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs24000_Gain5_B1 8780 /* Floating point value 0.267949 */
-#define HPF_Fs24000_Gain5_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs24000_Gain5_Shift 1 /* Shift value */
- /* Gain = 6.000000 dB */
-#define HPF_Fs24000_Gain6_A0 (-1564) /* Floating point value -0.047733 */
-#define HPF_Fs24000_Gain6_A1 22149 /* Floating point value 0.675938 */
-#define HPF_Fs24000_Gain6_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs24000_Gain6_B1 8780 /* Floating point value 0.267949 */
-#define HPF_Fs24000_Gain6_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs24000_Gain6_Shift 1 /* Shift value */
- /* Gain = 7.000000 dB */
-#define HPF_Fs24000_Gain7_A0 (-1509) /* Floating point value -0.046051 */
-#define HPF_Fs24000_Gain7_A1 11826 /* Floating point value 0.360899 */
-#define HPF_Fs24000_Gain7_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs24000_Gain7_B1 8780 /* Floating point value 0.267949 */
-#define HPF_Fs24000_Gain7_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs24000_Gain7_Shift 2 /* Shift value */
- /* Gain = 8.000000 dB */
-#define HPF_Fs24000_Gain8_A0 (-2323) /* Floating point value -0.070878 */
-#define HPF_Fs24000_Gain8_A1 12640 /* Floating point value 0.385727 */
-#define HPF_Fs24000_Gain8_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs24000_Gain8_B1 8780 /* Floating point value 0.267949 */
-#define HPF_Fs24000_Gain8_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs24000_Gain8_Shift 2 /* Shift value */
- /* Gain = 9.000000 dB */
-#define HPF_Fs24000_Gain9_A0 (-3235) /* Floating point value -0.098736 */
-#define HPF_Fs24000_Gain9_A1 13552 /* Floating point value 0.413584 */
-#define HPF_Fs24000_Gain9_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs24000_Gain9_B1 8780 /* Floating point value 0.267949 */
-#define HPF_Fs24000_Gain9_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs24000_Gain9_Shift 2 /* Shift value */
- /* Gain = 10.000000 dB */
-#define HPF_Fs24000_Gain10_A0 (-4260) /* Floating point value -0.129992 */
-#define HPF_Fs24000_Gain10_A1 14577 /* Floating point value 0.444841 */
-#define HPF_Fs24000_Gain10_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs24000_Gain10_B1 8780 /* Floating point value 0.267949 */
-#define HPF_Fs24000_Gain10_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs24000_Gain10_Shift 2 /* Shift value */
- /* Gain = 11.000000 dB */
-#define HPF_Fs24000_Gain11_A0 (-5409) /* Floating point value -0.165062 */
-#define HPF_Fs24000_Gain11_A1 15726 /* Floating point value 0.479911 */
-#define HPF_Fs24000_Gain11_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs24000_Gain11_B1 8780 /* Floating point value 0.267949 */
-#define HPF_Fs24000_Gain11_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs24000_Gain11_Shift 2 /* Shift value */
- /* Gain = 12.000000 dB */
-#define HPF_Fs24000_Gain12_A0 (-6698) /* Floating point value -0.204411 */
-#define HPF_Fs24000_Gain12_A1 17015 /* Floating point value 0.519260 */
-#define HPF_Fs24000_Gain12_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs24000_Gain12_B1 8780 /* Floating point value 0.267949 */
-#define HPF_Fs24000_Gain12_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs24000_Gain12_Shift 2 /* Shift value */
- /* Gain = 13.000000 dB */
-#define HPF_Fs24000_Gain13_A0 (-4082) /* Floating point value -0.124576 */
-#define HPF_Fs24000_Gain13_A1 9253 /* Floating point value 0.282374 */
-#define HPF_Fs24000_Gain13_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs24000_Gain13_B1 8780 /* Floating point value 0.267949 */
-#define HPF_Fs24000_Gain13_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs24000_Gain13_Shift 3 /* Shift value */
- /* Gain = 14.000000 dB */
-#define HPF_Fs24000_Gain14_A0 (-4896) /* Floating point value -0.149404 */
-#define HPF_Fs24000_Gain14_A1 10066 /* Floating point value 0.307202 */
-#define HPF_Fs24000_Gain14_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs24000_Gain14_B1 8780 /* Floating point value 0.267949 */
-#define HPF_Fs24000_Gain14_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs24000_Gain14_Shift 3 /* Shift value */
- /* Gain = 15.000000 dB */
-#define HPF_Fs24000_Gain15_A0 (-5808) /* Floating point value -0.177261 */
-#define HPF_Fs24000_Gain15_A1 10979 /* Floating point value 0.335059 */
-#define HPF_Fs24000_Gain15_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs24000_Gain15_B1 8780 /* Floating point value 0.267949 */
-#define HPF_Fs24000_Gain15_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs24000_Gain15_Shift 3 /* Shift value */
-
-
-/* Coefficients for sample rate 32000Hz */
- /* Gain = 1.000000 dB */
-#define HPF_Fs32000_Gain1_A0 17225 /* Floating point value 0.525677 */
-#define HPF_Fs32000_Gain1_A1 (-990) /* Floating point value -0.030227 */
-#define HPF_Fs32000_Gain1_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs32000_Gain1_B1 0 /* Floating point value -0.000000 */
-#define HPF_Fs32000_Gain1_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs32000_Gain1_Shift 1 /* Shift value */
- /* Gain = 2.000000 dB */
-#define HPF_Fs32000_Gain2_A0 18337 /* Floating point value 0.559593 */
-#define HPF_Fs32000_Gain2_A1 (-2102) /* Floating point value -0.064142 */
-#define HPF_Fs32000_Gain2_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs32000_Gain2_B1 0 /* Floating point value -0.000000 */
-#define HPF_Fs32000_Gain2_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs32000_Gain2_Shift 1 /* Shift value */
- /* Gain = 3.000000 dB */
-#define HPF_Fs32000_Gain3_A0 19584 /* Floating point value 0.597646 */
-#define HPF_Fs32000_Gain3_A1 (-3349) /* Floating point value -0.102196 */
-#define HPF_Fs32000_Gain3_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs32000_Gain3_B1 0 /* Floating point value -0.000000 */
-#define HPF_Fs32000_Gain3_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs32000_Gain3_Shift 1 /* Shift value */
- /* Gain = 4.000000 dB */
-#define HPF_Fs32000_Gain4_A0 20983 /* Floating point value 0.640343 */
-#define HPF_Fs32000_Gain4_A1 (-4748) /* Floating point value -0.144893 */
-#define HPF_Fs32000_Gain4_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs32000_Gain4_B1 0 /* Floating point value -0.000000 */
-#define HPF_Fs32000_Gain4_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs32000_Gain4_Shift 1 /* Shift value */
- /* Gain = 5.000000 dB */
-#define HPF_Fs32000_Gain5_A0 22553 /* Floating point value 0.688250 */
-#define HPF_Fs32000_Gain5_A1 (-6318) /* Floating point value -0.192799 */
-#define HPF_Fs32000_Gain5_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs32000_Gain5_B1 0 /* Floating point value -0.000000 */
-#define HPF_Fs32000_Gain5_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs32000_Gain5_Shift 1 /* Shift value */
- /* Gain = 6.000000 dB */
-#define HPF_Fs32000_Gain6_A0 24314 /* Floating point value 0.742002 */
-#define HPF_Fs32000_Gain6_A1 (-8079) /* Floating point value -0.246551 */
-#define HPF_Fs32000_Gain6_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs32000_Gain6_B1 0 /* Floating point value -0.000000 */
-#define HPF_Fs32000_Gain6_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs32000_Gain6_Shift 1 /* Shift value */
- /* Gain = 7.000000 dB */
-#define HPF_Fs32000_Gain7_A0 13176 /* Floating point value 0.402109 */
-#define HPF_Fs32000_Gain7_A1 (-5040) /* Floating point value -0.153795 */
-#define HPF_Fs32000_Gain7_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs32000_Gain7_B1 0 /* Floating point value -0.000000 */
-#define HPF_Fs32000_Gain7_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs32000_Gain7_Shift 2 /* Shift value */
- /* Gain = 8.000000 dB */
-#define HPF_Fs32000_Gain8_A0 14288 /* Floating point value 0.436024 */
-#define HPF_Fs32000_Gain8_A1 (-6151) /* Floating point value -0.187711 */
-#define HPF_Fs32000_Gain8_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs32000_Gain8_B1 0 /* Floating point value -0.000000 */
-#define HPF_Fs32000_Gain8_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs32000_Gain8_Shift 2 /* Shift value */
- /* Gain = 9.000000 dB */
-#define HPF_Fs32000_Gain9_A0 15535 /* Floating point value 0.474078 */
-#define HPF_Fs32000_Gain9_A1 (-7398) /* Floating point value -0.225764 */
-#define HPF_Fs32000_Gain9_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs32000_Gain9_B1 0 /* Floating point value -0.000000 */
-#define HPF_Fs32000_Gain9_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs32000_Gain9_Shift 2 /* Shift value */
- /* Gain = 10.000000 dB */
-#define HPF_Fs32000_Gain10_A0 16934 /* Floating point value 0.516774 */
-#define HPF_Fs32000_Gain10_A1 (-8797) /* Floating point value -0.268461 */
-#define HPF_Fs32000_Gain10_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs32000_Gain10_B1 0 /* Floating point value -0.000000 */
-#define HPF_Fs32000_Gain10_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs32000_Gain10_Shift 2 /* Shift value */
- /* Gain = 11.000000 dB */
-#define HPF_Fs32000_Gain11_A0 18503 /* Floating point value 0.564681 */
-#define HPF_Fs32000_Gain11_A1 (-10367) /* Floating point value -0.316368 */
-#define HPF_Fs32000_Gain11_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs32000_Gain11_B1 0 /* Floating point value -0.000000 */
-#define HPF_Fs32000_Gain11_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs32000_Gain11_Shift 2 /* Shift value */
- /* Gain = 12.000000 dB */
-#define HPF_Fs32000_Gain12_A0 20265 /* Floating point value 0.618433 */
-#define HPF_Fs32000_Gain12_A1 (-12128) /* Floating point value -0.370120 */
-#define HPF_Fs32000_Gain12_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs32000_Gain12_B1 0 /* Floating point value -0.000000 */
-#define HPF_Fs32000_Gain12_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs32000_Gain12_Shift 2 /* Shift value */
- /* Gain = 13.000000 dB */
-#define HPF_Fs32000_Gain13_A0 11147 /* Floating point value 0.340178 */
-#define HPF_Fs32000_Gain13_A1 (-7069) /* Floating point value -0.215726 */
-#define HPF_Fs32000_Gain13_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs32000_Gain13_B1 0 /* Floating point value -0.000000 */
-#define HPF_Fs32000_Gain13_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs32000_Gain13_Shift 3 /* Shift value */
- /* Gain = 14.000000 dB */
-#define HPF_Fs32000_Gain14_A0 12258 /* Floating point value 0.374093 */
-#define HPF_Fs32000_Gain14_A1 (-8180) /* Floating point value -0.249642 */
-#define HPF_Fs32000_Gain14_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs32000_Gain14_B1 0 /* Floating point value -0.000000 */
-#define HPF_Fs32000_Gain14_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs32000_Gain14_Shift 3 /* Shift value */
- /* Gain = 15.000000 dB */
-#define HPF_Fs32000_Gain15_A0 13505 /* Floating point value 0.412147 */
-#define HPF_Fs32000_Gain15_A1 (-9427) /* Floating point value -0.287695 */
-#define HPF_Fs32000_Gain15_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs32000_Gain15_B1 0 /* Floating point value -0.000000 */
-#define HPF_Fs32000_Gain15_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs32000_Gain15_Shift 3 /* Shift value */
-
-
-/* Coefficients for sample rate 44100Hz */
- /* Gain = 1.000000 dB */
-#define HPF_Fs44100_Gain1_A0 17442 /* Floating point value 0.532294 */
-#define HPF_Fs44100_Gain1_A1 (-4761) /* Floating point value -0.145294 */
-#define HPF_Fs44100_Gain1_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs44100_Gain1_B1 (-7173) /* Floating point value -0.218894 */
-#define HPF_Fs44100_Gain1_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs44100_Gain1_Shift 1 /* Shift value */
- /* Gain = 2.000000 dB */
-#define HPF_Fs44100_Gain2_A0 18797 /* Floating point value 0.573633 */
-#define HPF_Fs44100_Gain2_A1 (-6116) /* Floating point value -0.186634 */
-#define HPF_Fs44100_Gain2_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs44100_Gain2_B1 (-7173) /* Floating point value -0.218894 */
-#define HPF_Fs44100_Gain2_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs44100_Gain2_Shift 1 /* Shift value */
- /* Gain = 3.000000 dB */
-#define HPF_Fs44100_Gain3_A0 20317 /* Floating point value 0.620016 */
-#define HPF_Fs44100_Gain3_A1 (-7635) /* Floating point value -0.233017 */
-#define HPF_Fs44100_Gain3_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs44100_Gain3_B1 (-7173) /* Floating point value -0.218894 */
-#define HPF_Fs44100_Gain3_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs44100_Gain3_Shift 1 /* Shift value */
- /* Gain = 4.000000 dB */
-#define HPF_Fs44100_Gain4_A0 22022 /* Floating point value 0.672059 */
-#define HPF_Fs44100_Gain4_A1 (-9341) /* Floating point value -0.285060 */
-#define HPF_Fs44100_Gain4_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs44100_Gain4_B1 (-7173) /* Floating point value -0.218894 */
-#define HPF_Fs44100_Gain4_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs44100_Gain4_Shift 1 /* Shift value */
- /* Gain = 5.000000 dB */
-#define HPF_Fs44100_Gain5_A0 23935 /* Floating point value 0.730452 */
-#define HPF_Fs44100_Gain5_A1 (-11254) /* Floating point value -0.343453 */
-#define HPF_Fs44100_Gain5_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs44100_Gain5_B1 (-7173) /* Floating point value -0.218894 */
-#define HPF_Fs44100_Gain5_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs44100_Gain5_Shift 1 /* Shift value */
- /* Gain = 6.000000 dB */
-#define HPF_Fs44100_Gain6_A0 26082 /* Floating point value 0.795970 */
-#define HPF_Fs44100_Gain6_A1 (-13401) /* Floating point value -0.408971 */
-#define HPF_Fs44100_Gain6_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs44100_Gain6_B1 (-7173) /* Floating point value -0.218894 */
-#define HPF_Fs44100_Gain6_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs44100_Gain6_Shift 1 /* Shift value */
- /* Gain = 7.000000 dB */
-#define HPF_Fs44100_Gain7_A0 14279 /* Floating point value 0.435774 */
-#define HPF_Fs44100_Gain7_A1 (-7924) /* Floating point value -0.241815 */
-#define HPF_Fs44100_Gain7_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs44100_Gain7_B1 (-7173) /* Floating point value -0.218894 */
-#define HPF_Fs44100_Gain7_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs44100_Gain7_Shift 2 /* Shift value */
- /* Gain = 8.000000 dB */
-#define HPF_Fs44100_Gain8_A0 15634 /* Floating point value 0.477113 */
-#define HPF_Fs44100_Gain8_A1 (-9278) /* Floating point value -0.283154 */
-#define HPF_Fs44100_Gain8_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs44100_Gain8_B1 (-7173) /* Floating point value -0.218894 */
-#define HPF_Fs44100_Gain8_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs44100_Gain8_Shift 2 /* Shift value */
- /* Gain = 9.000000 dB */
-#define HPF_Fs44100_Gain9_A0 17154 /* Floating point value 0.523496 */
-#define HPF_Fs44100_Gain9_A1 (-10798) /* Floating point value -0.329537 */
-#define HPF_Fs44100_Gain9_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs44100_Gain9_B1 (-7173) /* Floating point value -0.218894 */
-#define HPF_Fs44100_Gain9_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs44100_Gain9_Shift 2 /* Shift value */
- /* Gain = 10.000000 dB */
-#define HPF_Fs44100_Gain10_A0 18859 /* Floating point value 0.575539 */
-#define HPF_Fs44100_Gain10_A1 (-12504) /* Floating point value -0.381580 */
-#define HPF_Fs44100_Gain10_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs44100_Gain10_B1 (-7173) /* Floating point value -0.218894 */
-#define HPF_Fs44100_Gain10_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs44100_Gain10_Shift 2 /* Shift value */
- /* Gain = 11.000000 dB */
-#define HPF_Fs44100_Gain11_A0 20773 /* Floating point value 0.633932 */
-#define HPF_Fs44100_Gain11_A1 (-14417) /* Floating point value -0.439973 */
-#define HPF_Fs44100_Gain11_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs44100_Gain11_B1 (-7173) /* Floating point value -0.218894 */
-#define HPF_Fs44100_Gain11_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs44100_Gain11_Shift 2 /* Shift value */
- /* Gain = 12.000000 dB */
-#define HPF_Fs44100_Gain12_A0 22920 /* Floating point value 0.699450 */
-#define HPF_Fs44100_Gain12_A1 (-16564) /* Floating point value -0.505491 */
-#define HPF_Fs44100_Gain12_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs44100_Gain12_B1 (-7173) /* Floating point value -0.218894 */
-#define HPF_Fs44100_Gain12_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs44100_Gain12_Shift 2 /* Shift value */
- /* Gain = 13.000000 dB */
-#define HPF_Fs44100_Gain13_A0 12694 /* Floating point value 0.387399 */
-#define HPF_Fs44100_Gain13_A1 (-9509) /* Floating point value -0.290189 */
-#define HPF_Fs44100_Gain13_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs44100_Gain13_B1 (-7173) /* Floating point value -0.218894 */
-#define HPF_Fs44100_Gain13_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs44100_Gain13_Shift 3 /* Shift value */
- /* Gain = 14.000000 dB */
-#define HPF_Fs44100_Gain14_A0 14049 /* Floating point value 0.428738 */
-#define HPF_Fs44100_Gain14_A1 (-10864) /* Floating point value -0.331528 */
-#define HPF_Fs44100_Gain14_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs44100_Gain14_B1 (-7173) /* Floating point value -0.218894 */
-#define HPF_Fs44100_Gain14_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs44100_Gain14_Shift 3 /* Shift value */
- /* Gain = 15.000000 dB */
-#define HPF_Fs44100_Gain15_A0 15569 /* Floating point value 0.475121 */
-#define HPF_Fs44100_Gain15_A1 (-12383) /* Floating point value -0.377912 */
-#define HPF_Fs44100_Gain15_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs44100_Gain15_B1 (-7173) /* Floating point value -0.218894 */
-#define HPF_Fs44100_Gain15_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs44100_Gain15_Shift 3 /* Shift value */
-
-
-/* Coefficients for sample rate 48000Hz */
- /* Gain = 1.000000 dB */
-#define HPF_Fs48000_Gain1_A0 17491 /* Floating point value 0.533777 */
-#define HPF_Fs48000_Gain1_A1 (-5606) /* Floating point value -0.171082 */
-#define HPF_Fs48000_Gain1_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs48000_Gain1_B1 (-8780) /* Floating point value -0.267949 */
-#define HPF_Fs48000_Gain1_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs48000_Gain1_Shift 1 /* Shift value */
- /* Gain = 2.000000 dB */
-#define HPF_Fs48000_Gain2_A0 18900 /* Floating point value 0.576779 */
-#define HPF_Fs48000_Gain2_A1 (-7015) /* Floating point value -0.214085 */
-#define HPF_Fs48000_Gain2_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs48000_Gain2_B1 (-8780) /* Floating point value -0.267949 */
-#define HPF_Fs48000_Gain2_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs48000_Gain2_Shift 1 /* Shift value */
- /* Gain = 3.000000 dB */
-#define HPF_Fs48000_Gain3_A0 20481 /* Floating point value 0.625029 */
-#define HPF_Fs48000_Gain3_A1 (-8596) /* Floating point value -0.262335 */
-#define HPF_Fs48000_Gain3_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs48000_Gain3_B1 (-8780) /* Floating point value -0.267949 */
-#define HPF_Fs48000_Gain3_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs48000_Gain3_Shift 1 /* Shift value */
- /* Gain = 4.000000 dB */
-#define HPF_Fs48000_Gain4_A0 22255 /* Floating point value 0.679167 */
-#define HPF_Fs48000_Gain4_A1 (-10370) /* Floating point value -0.316472 */
-#define HPF_Fs48000_Gain4_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs48000_Gain4_B1 (-8780) /* Floating point value -0.267949 */
-#define HPF_Fs48000_Gain4_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs48000_Gain4_Shift 1 /* Shift value */
- /* Gain = 5.000000 dB */
-#define HPF_Fs48000_Gain5_A0 24245 /* Floating point value 0.739910 */
-#define HPF_Fs48000_Gain5_A1 (-12361) /* Floating point value -0.377215 */
-#define HPF_Fs48000_Gain5_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs48000_Gain5_B1 (-8780) /* Floating point value -0.267949 */
-#define HPF_Fs48000_Gain5_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs48000_Gain5_Shift 1 /* Shift value */
- /* Gain = 6.000000 dB */
-#define HPF_Fs48000_Gain6_A0 26479 /* Floating point value 0.808065 */
-#define HPF_Fs48000_Gain6_A1 (-14594) /* Floating point value -0.445370 */
-#define HPF_Fs48000_Gain6_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs48000_Gain6_B1 (-8780) /* Floating point value -0.267949 */
-#define HPF_Fs48000_Gain6_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs48000_Gain6_Shift 1 /* Shift value */
- /* Gain = 7.000000 dB */
-#define HPF_Fs48000_Gain7_A0 14527 /* Floating point value 0.443318 */
-#define HPF_Fs48000_Gain7_A1 (-8570) /* Floating point value -0.261540 */
-#define HPF_Fs48000_Gain7_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs48000_Gain7_B1 (-8780) /* Floating point value -0.267949 */
-#define HPF_Fs48000_Gain7_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs48000_Gain7_Shift 2 /* Shift value */
- /* Gain = 8.000000 dB */
-#define HPF_Fs48000_Gain8_A0 15936 /* Floating point value 0.486321 */
-#define HPF_Fs48000_Gain8_A1 (-9979) /* Floating point value -0.304543 */
-#define HPF_Fs48000_Gain8_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs48000_Gain8_B1 (-8780) /* Floating point value -0.267949 */
-#define HPF_Fs48000_Gain8_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs48000_Gain8_Shift 2 /* Shift value */
- /* Gain = 9.000000 dB */
-#define HPF_Fs48000_Gain9_A0 17517 /* Floating point value 0.534571 */
-#define HPF_Fs48000_Gain9_A1 (-11560) /* Floating point value -0.352793 */
-#define HPF_Fs48000_Gain9_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs48000_Gain9_B1 (-8780) /* Floating point value -0.267949 */
-#define HPF_Fs48000_Gain9_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs48000_Gain9_Shift 2 /* Shift value */
- /* Gain = 10.000000 dB */
-#define HPF_Fs48000_Gain10_A0 19291 /* Floating point value 0.588708 */
-#define HPF_Fs48000_Gain10_A1 (-13334) /* Floating point value -0.406930 */
-#define HPF_Fs48000_Gain10_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs48000_Gain10_B1 (-8780) /* Floating point value -0.267949 */
-#define HPF_Fs48000_Gain10_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs48000_Gain10_Shift 2 /* Shift value */
- /* Gain = 11.000000 dB */
-#define HPF_Fs48000_Gain11_A0 21281 /* Floating point value 0.649452 */
-#define HPF_Fs48000_Gain11_A1 (-15325) /* Floating point value -0.467674 */
-#define HPF_Fs48000_Gain11_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs48000_Gain11_B1 (-8780) /* Floating point value -0.267949 */
-#define HPF_Fs48000_Gain11_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs48000_Gain11_Shift 2 /* Shift value */
- /* Gain = 12.000000 dB */
-#define HPF_Fs48000_Gain12_A0 23515 /* Floating point value 0.717607 */
-#define HPF_Fs48000_Gain12_A1 (-17558) /* Floating point value -0.535829 */
-#define HPF_Fs48000_Gain12_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs48000_Gain12_B1 (-8780) /* Floating point value -0.267949 */
-#define HPF_Fs48000_Gain12_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs48000_Gain12_Shift 2 /* Shift value */
- /* Gain = 13.000000 dB */
-#define HPF_Fs48000_Gain13_A0 13041 /* Floating point value 0.397982 */
-#define HPF_Fs48000_Gain13_A1 (-10056) /* Floating point value -0.306877 */
-#define HPF_Fs48000_Gain13_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs48000_Gain13_B1 (-8780) /* Floating point value -0.267949 */
-#define HPF_Fs48000_Gain13_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs48000_Gain13_Shift 3 /* Shift value */
- /* Gain = 14.000000 dB */
-#define HPF_Fs48000_Gain14_A0 14450 /* Floating point value 0.440984 */
-#define HPF_Fs48000_Gain14_A1 (-11465) /* Floating point value -0.349880 */
-#define HPF_Fs48000_Gain14_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs48000_Gain14_B1 (-8780) /* Floating point value -0.267949 */
-#define HPF_Fs48000_Gain14_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs48000_Gain14_Shift 3 /* Shift value */
- /* Gain = 15.000000 dB */
-#define HPF_Fs48000_Gain15_A0 16031 /* Floating point value 0.489234 */
-#define HPF_Fs48000_Gain15_A1 (-13046) /* Floating point value -0.398130 */
-#define HPF_Fs48000_Gain15_A2 0 /* Floating point value 0.000000 */
-#define HPF_Fs48000_Gain15_B1 (-8780) /* Floating point value -0.267949 */
-#define HPF_Fs48000_Gain15_B2 0 /* Floating point value 0.000000 */
-#define HPF_Fs48000_Gain15_Shift 3 /* Shift value */
-
-
-#endif
-#endif
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Control.c b/media/libeffects/lvm/lib/Bundle/src/LVM_Control.c
deleted file mode 100644
index 1b27cb4..0000000
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Control.c
+++ /dev/null
@@ -1,1185 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-/****************************************************************************************/
-/* */
-/* Includes */
-/* */
-/****************************************************************************************/
-
-#include "VectorArithmetic.h"
-#include "ScalarArithmetic.h"
-#include "LVM_Coeffs.h"
-#include "LVM_Tables.h"
-#include "LVM_Private.h"
-
-#include <log/log.h>
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVM_SetControlParameters */
-/* */
-/* DESCRIPTION: */
-/* Sets or changes the LifeVibes module parameters. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance handle */
-/* pParams Pointer to a parameter structure */
-/* */
-/* RETURNS: */
-/* LVM_SUCCESS Succeeded */
-/* LVM_NULLADDRESS When hInstance, pParams or any control pointers are NULL */
-/* LVM_OUTOFRANGE When any of the control parameters are out of range */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVM_Process function */
-/* */
-/****************************************************************************************/
-
-LVM_ReturnStatus_en LVM_SetControlParameters(LVM_Handle_t hInstance,
- LVM_ControlParams_t *pParams)
-{
- LVM_Instance_t *pInstance =(LVM_Instance_t *)hInstance;
-
-
- if ((pParams == LVM_NULL) || (hInstance == LVM_NULL))
- {
- return (LVM_NULLADDRESS);
- }
-
- pInstance->NewParams = *pParams;
-
- if(
- /* General parameters */
- ((pParams->OperatingMode != LVM_MODE_OFF) && (pParams->OperatingMode != LVM_MODE_ON)) ||
-#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
- ((pParams->SampleRate != LVM_FS_8000) && (pParams->SampleRate != LVM_FS_11025) && (pParams->SampleRate != LVM_FS_12000) &&
- (pParams->SampleRate != LVM_FS_16000) && (pParams->SampleRate != LVM_FS_22050) && (pParams->SampleRate != LVM_FS_24000) &&
- (pParams->SampleRate != LVM_FS_32000) && (pParams->SampleRate != LVM_FS_44100) && (pParams->SampleRate != LVM_FS_48000) &&
- (pParams->SampleRate != LVM_FS_88200) && (pParams->SampleRate != LVM_FS_96000) &&
- (pParams->SampleRate != LVM_FS_176400) && (pParams->SampleRate != LVM_FS_192000)) ||
-#else
- ((pParams->SampleRate != LVM_FS_8000) && (pParams->SampleRate != LVM_FS_11025) && (pParams->SampleRate != LVM_FS_12000) &&
- (pParams->SampleRate != LVM_FS_16000) && (pParams->SampleRate != LVM_FS_22050) && (pParams->SampleRate != LVM_FS_24000) &&
- (pParams->SampleRate != LVM_FS_32000) && (pParams->SampleRate != LVM_FS_44100) && (pParams->SampleRate != LVM_FS_48000)) ||
-#endif
-#ifdef SUPPORT_MC
- ((pParams->SourceFormat != LVM_STEREO) &&
- (pParams->SourceFormat != LVM_MONOINSTEREO) &&
- (pParams->SourceFormat != LVM_MONO) &&
- (pParams->SourceFormat != LVM_MULTICHANNEL)) ||
-#else
- ((pParams->SourceFormat != LVM_STEREO) && (pParams->SourceFormat != LVM_MONOINSTEREO) && (pParams->SourceFormat != LVM_MONO)) ||
-#endif
- (pParams->SpeakerType > LVM_EX_HEADPHONES))
- {
- return (LVM_OUTOFRANGE);
- }
-
-#ifdef SUPPORT_MC
- pInstance->Params.NrChannels = pParams->NrChannels;
- pInstance->Params.ChMask = pParams->ChMask;
-#endif
- /*
- * Cinema Sound parameters
- */
- if((pParams->VirtualizerOperatingMode != LVM_MODE_OFF) && (pParams->VirtualizerOperatingMode != LVM_MODE_ON))
- {
- return (LVM_OUTOFRANGE);
- }
-
- if(pParams->VirtualizerType != LVM_CONCERTSOUND)
- {
- return (LVM_OUTOFRANGE);
- }
-
- if(pParams->VirtualizerReverbLevel > LVM_VIRTUALIZER_MAX_REVERB_LEVEL)
- {
- return (LVM_OUTOFRANGE);
- }
-
- if(pParams->CS_EffectLevel < LVM_CS_MIN_EFFECT_LEVEL)
- {
- return (LVM_OUTOFRANGE);
- }
-
- /*
- * N-Band Equalizer
- */
- if(pParams->EQNB_NBands > pInstance->InstParams.EQNB_NumBands)
- {
- return (LVM_OUTOFRANGE);
- }
-
- /* Definition pointer */
- if ((pParams->pEQNB_BandDefinition == LVM_NULL) &&
- (pParams->EQNB_NBands != 0))
- {
- return (LVM_NULLADDRESS);
- }
-
- /*
- * Copy the filter definitions for the Equaliser
- */
- {
- LVM_INT16 i;
-
- if (pParams->EQNB_NBands != 0)
- {
- for (i=0; i<pParams->EQNB_NBands; i++)
- {
- pInstance->pEQNB_BandDefs[i] = pParams->pEQNB_BandDefinition[i];
- }
- pInstance->NewParams.pEQNB_BandDefinition = pInstance->pEQNB_BandDefs;
- }
- }
- if( /* N-Band Equaliser parameters */
- ((pParams->EQNB_OperatingMode != LVM_EQNB_OFF) && (pParams->EQNB_OperatingMode != LVM_EQNB_ON)) ||
- (pParams->EQNB_NBands > pInstance->InstParams.EQNB_NumBands))
- {
- return (LVM_OUTOFRANGE);
- }
- /* Band parameters*/
- {
- LVM_INT16 i;
- for(i = 0; i < pParams->EQNB_NBands; i++)
- {
- if(((pParams->pEQNB_BandDefinition[i].Frequency < LVM_EQNB_MIN_BAND_FREQ) ||
- (pParams->pEQNB_BandDefinition[i].Frequency > LVM_EQNB_MAX_BAND_FREQ)) ||
- ((pParams->pEQNB_BandDefinition[i].Gain < LVM_EQNB_MIN_BAND_GAIN) ||
- (pParams->pEQNB_BandDefinition[i].Gain > LVM_EQNB_MAX_BAND_GAIN)) ||
- ((pParams->pEQNB_BandDefinition[i].QFactor < LVM_EQNB_MIN_QFACTOR) ||
- (pParams->pEQNB_BandDefinition[i].QFactor > LVM_EQNB_MAX_QFACTOR)))
- {
- return (LVM_OUTOFRANGE);
- }
- }
- }
-
- /*
- * Bass Enhancement parameters
- */
- if(((pParams->BE_OperatingMode != LVM_BE_OFF) && (pParams->BE_OperatingMode != LVM_BE_ON)) ||
- ((pParams->BE_EffectLevel < LVM_BE_MIN_EFFECTLEVEL ) || (pParams->BE_EffectLevel > LVM_BE_MAX_EFFECTLEVEL ))||
- ((pParams->BE_CentreFreq != LVM_BE_CENTRE_55Hz) && (pParams->BE_CentreFreq != LVM_BE_CENTRE_66Hz) &&
- (pParams->BE_CentreFreq != LVM_BE_CENTRE_78Hz) && (pParams->BE_CentreFreq != LVM_BE_CENTRE_90Hz)) ||
- ((pParams->BE_HPF != LVM_BE_HPF_OFF) && (pParams->BE_HPF != LVM_BE_HPF_ON)))
- {
- return (LVM_OUTOFRANGE);
- }
-
- /*
- * Volume Control parameters
- */
- if((pParams->VC_EffectLevel < LVM_VC_MIN_EFFECTLEVEL ) || (pParams->VC_EffectLevel > LVM_VC_MAX_EFFECTLEVEL ))
- {
- return (LVM_OUTOFRANGE);
- }
- if((pParams->VC_Balance < LVM_VC_BALANCE_MIN ) || (pParams->VC_Balance > LVM_VC_BALANCE_MAX ))
- {
- return (LVM_OUTOFRANGE);
- }
-
- /*
- * PSA parameters
- */
- if( (pParams->PSA_PeakDecayRate > LVPSA_SPEED_HIGH) ||
- (pParams->PSA_Enable > LVM_PSA_ON))
- {
- return (LVM_OUTOFRANGE);
- }
-
-
- /*
- * Set the flag to indicate there are new parameters to use
- *
- * Protect the copy of the new parameters from interrupts to avoid possible problems
- * with loss control parameters. This problem can occur if this control function is called more
- * than once before a call to the process function. If the process function interrupts
- * the copy to NewParams then one frame may have mixed parameters, some old and some new.
- */
- pInstance->ControlPending = LVM_TRUE;
-
- return(LVM_SUCCESS);
-}
-
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVM_GetControlParameters */
-/* */
-/* DESCRIPTION: */
-/* Request the LifeVibes module parameters. The current parameter set is returned */
-/* via the parameter pointer. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance handle */
-/* pParams Pointer to an empty parameter structure */
-/* */
-/* RETURNS: */
-/* LVM_SUCCESS Succeeded */
-/* LVM_NULLADDRESS when any of hInstance or pParams is NULL */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVM_Process function */
-/* */
-/****************************************************************************************/
-
-LVM_ReturnStatus_en LVM_GetControlParameters(LVM_Handle_t hInstance,
- LVM_ControlParams_t *pParams)
-{
- LVM_Instance_t *pInstance =(LVM_Instance_t *)hInstance;
-
-
- /*
- * Check pointer
- */
- if ((pParams == LVM_NULL) || (hInstance == LVM_NULL))
- {
- return (LVM_NULLADDRESS);
- }
- *pParams = pInstance->NewParams;
-
- /*
- * Copy the filter definitions for the Equaliser
- */
- {
- LVM_INT16 i;
-
- if (pInstance->NewParams.EQNB_NBands != 0)
- for (i=0; i<pInstance->NewParams.EQNB_NBands; i++)
- {
- pInstance->pEQNB_UserDefs[i] = pInstance->pEQNB_BandDefs[i];
- }
- pParams->pEQNB_BandDefinition = pInstance->pEQNB_UserDefs;
- }
-
- return(LVM_SUCCESS);
-}
-
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVM_SetTrebleBoost */
-/* */
-/* DESCRIPTION: */
-/* Enable the treble boost when the settings are appropriate, i.e. non-zero gain */
-/* and the sample rate is high enough for the effect to be heard. */
-/* */
-/* PARAMETERS: */
-/* pInstance Pointer to the instance structure */
-/* pParams Pointer to the parameters to use */
-/* */
-/****************************************************************************************/
-void LVM_SetTrebleBoost(LVM_Instance_t *pInstance,
- LVM_ControlParams_t *pParams)
-{
-#ifdef BUILD_FLOAT
- extern FO_FLOAT_LShx_Coefs_t LVM_TrebleBoostCoefs[];
-#else
- extern FO_C16_LShx_Coefs_t LVM_TrebleBoostCoefs[];
-#endif
-
- LVM_INT16 Offset;
- LVM_INT16 EffectLevel = 0;
-
- /*
- * Load the coefficients
- */
- if ((pParams->TE_OperatingMode == LVM_TE_ON) &&
- (pParams->SampleRate >= TrebleBoostMinRate) &&
- (pParams->OperatingMode == LVM_MODE_ON) &&
- (pParams->TE_EffectLevel > 0))
- {
- if((pParams->TE_EffectLevel == LVM_TE_LOW_MIPS) &&
- ((pParams->SpeakerType == LVM_HEADPHONES)||
- (pParams->SpeakerType == LVM_EX_HEADPHONES)))
- {
- pInstance->TE_Active = LVM_FALSE;
- }
- else
- {
- EffectLevel = pParams->TE_EffectLevel;
- pInstance->TE_Active = LVM_TRUE;
- }
-
- if(pInstance->TE_Active == LVM_TRUE)
- {
- /*
- * Load the coefficients and enabled the treble boost
- */
- Offset = (LVM_INT16)(EffectLevel - 1 + TrebleBoostSteps * (pParams->SampleRate - TrebleBoostMinRate));
-#ifdef BUILD_FLOAT
- FO_2I_D16F32Css_LShx_TRC_WRA_01_Init(&pInstance->pTE_State->TrebleBoost_State,
- &pInstance->pTE_Taps->TrebleBoost_Taps,
- &LVM_TrebleBoostCoefs[Offset]);
-
- /*
- * Clear the taps
- */
- LoadConst_Float((LVM_FLOAT)0, /* Value */
- (void *)&pInstance->pTE_Taps->TrebleBoost_Taps, /* Destination.\
- Cast to void: no dereferencing in function */
- (LVM_UINT16)(sizeof(pInstance->pTE_Taps->TrebleBoost_Taps) / \
- sizeof(LVM_FLOAT))); /* Number of words */
-#else
- FO_2I_D16F32Css_LShx_TRC_WRA_01_Init(&pInstance->pTE_State->TrebleBoost_State,
- &pInstance->pTE_Taps->TrebleBoost_Taps,
- &LVM_TrebleBoostCoefs[Offset]);
-
- /*
- * Clear the taps
- */
- LoadConst_16((LVM_INT16)0, /* Value */
- (void *)&pInstance->pTE_Taps->TrebleBoost_Taps, /* Destination.\
- Cast to void: no dereferencing in function */
- (LVM_UINT16)(sizeof(pInstance->pTE_Taps->TrebleBoost_Taps)/sizeof(LVM_INT16))); /* Number of words */
-#endif
- }
- }
- else
- {
- /*
- * Disable the treble boost
- */
- pInstance->TE_Active = LVM_FALSE;
- }
-
- return;
-}
-
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVM_SetVolume */
-/* */
-/* DESCRIPTION: */
-/* Converts the input volume demand from dBs to linear. */
-/* */
-/* PARAMETERS: */
-/* pInstance Pointer to the instance */
-/* pParams Initialisation parameters */
-/* */
-/************************************************************************************/
-void LVM_SetVolume(LVM_Instance_t *pInstance,
- LVM_ControlParams_t *pParams)
-{
-
- LVM_UINT16 dBShifts; /* 6dB shifts */
- LVM_UINT16 dBOffset; /* Table offset */
- LVM_INT16 Volume = 0; /* Required volume in dBs */
-#ifdef BUILD_FLOAT
- LVM_FLOAT Temp;
-#endif
-
- /*
- * Limit the gain to the maximum allowed
- */
- if (pParams->VC_EffectLevel > 0)
- {
- Volume = 0;
- }
- else
- {
- Volume = pParams->VC_EffectLevel;
- }
-
- /* Compensate this volume in PSA plot */
- if(Volume > -60) /* Limit volume loss to PSA Limits*/
- pInstance->PSA_GainOffset=(LVM_INT16)(-Volume);/* Loss is compensated by Gain*/
- else
- pInstance->PSA_GainOffset=(LVM_INT16)60;/* Loss is compensated by Gain*/
-
- pInstance->VC_AVLFixedVolume = 0;
-
- /*
- * Set volume control and AVL volumes according to headroom and volume user setting
- */
- if(pParams->OperatingMode == LVM_MODE_ON)
- {
- /* Default Situation with no AVL and no RS */
- if(pParams->EQNB_OperatingMode == LVM_EQNB_ON)
- {
- if(Volume > -pInstance->Headroom)
- Volume = (LVM_INT16)-pInstance->Headroom;
- }
- }
-
- /*
- * Activate volume control if necessary
- */
- pInstance->VC_Active = LVM_TRUE;
- if (Volume != 0)
- {
- pInstance->VC_VolumedB = Volume;
- }
- else
- {
- pInstance->VC_VolumedB = 0;
- }
-
- /*
- * Calculate the required gain and shifts
- */
- dBOffset = (LVM_UINT16)((-Volume) % 6); /* Get the dBs 0-5 */
- dBShifts = (LVM_UINT16)(Volume / -6); /* Get the 6dB shifts */
-
-
- /*
- * Set the parameters
- */
- if(dBShifts == 0)
- {
-#ifdef BUILD_FLOAT
- LVC_Mixer_SetTarget(&pInstance->VC_Volume.MixerStream[0],
- (LVM_FLOAT)LVM_VolumeTable[dBOffset]);
-#else
- LVC_Mixer_SetTarget(&pInstance->VC_Volume.MixerStream[0],
- (LVM_INT32)LVM_VolumeTable[dBOffset]);
-#endif
- }
- else
- {
-#ifdef BUILD_FLOAT
- Temp = LVM_VolumeTable[dBOffset];
- while(dBShifts) {
- Temp = Temp / 2.0f;
- dBShifts--;
- }
- LVC_Mixer_SetTarget(&pInstance->VC_Volume.MixerStream[0], Temp);
-#else
- LVC_Mixer_SetTarget(&pInstance->VC_Volume.MixerStream[0],
- (((LVM_INT32)LVM_VolumeTable[dBOffset])>>dBShifts));
-#endif
- }
- pInstance->VC_Volume.MixerStream[0].CallbackSet = 1;
- if(pInstance->NoSmoothVolume == LVM_TRUE)
- {
-#ifdef BUILD_FLOAT
- LVC_Mixer_SetTimeConstant(&pInstance->VC_Volume.MixerStream[0], 0,
- pInstance->Params.SampleRate, 2);
-#else
- LVC_Mixer_SetTimeConstant(&pInstance->VC_Volume.MixerStream[0],0,pInstance->Params.SampleRate,2);
-#endif
- }
- else
- {
-#ifdef BUILD_FLOAT
- LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_Volume.MixerStream[0],
- LVM_VC_MIXER_TIME, pInstance->Params.SampleRate, 2);
-#else
- LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_Volume.MixerStream[0],LVM_VC_MIXER_TIME,pInstance->Params.SampleRate,2);
-#endif
- }
-}
-
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVM_SetHeadroom */
-/* */
-/* DESCRIPTION: */
-/* Find suitable headroom based on EQ settings. */
-/* */
-/* PARAMETERS: */
-/* pInstance Pointer to the instance */
-/* pParams Initialisation parameters */
-/* */
-/* RETURNS: */
-/* void Nothing */
-/* */
-/* NOTES: */
-/* */
-/************************************************************************************/
-void LVM_SetHeadroom(LVM_Instance_t *pInstance,
- LVM_ControlParams_t *pParams)
-{
- LVM_INT16 ii, jj;
- LVM_INT16 Headroom = 0;
- LVM_INT16 MaxGain = 0;
-
-
- if ((pParams->EQNB_OperatingMode == LVEQNB_ON) && (pInstance->HeadroomParams.Headroom_OperatingMode == LVM_HEADROOM_ON))
- {
- /* Find typical headroom value */
- for(jj = 0; jj < pInstance->HeadroomParams.NHeadroomBands; jj++)
- {
- MaxGain = 0;
- for( ii = 0; ii < pParams->EQNB_NBands; ii++)
- {
- if((pParams->pEQNB_BandDefinition[ii].Frequency >= pInstance->HeadroomParams.pHeadroomDefinition[jj].Limit_Low) &&
- (pParams->pEQNB_BandDefinition[ii].Frequency <= pInstance->HeadroomParams.pHeadroomDefinition[jj].Limit_High))
- {
- if(pParams->pEQNB_BandDefinition[ii].Gain > MaxGain)
- {
- MaxGain = pParams->pEQNB_BandDefinition[ii].Gain;
- }
- }
- }
-
- if((MaxGain - pInstance->HeadroomParams.pHeadroomDefinition[jj].Headroom_Offset) > Headroom){
- Headroom = (LVM_INT16)(MaxGain - pInstance->HeadroomParams.pHeadroomDefinition[jj].Headroom_Offset);
- }
- }
-
- /* Saturate */
- if(Headroom < 0)
- Headroom = 0;
- }
- pInstance->Headroom = (LVM_UINT16)Headroom ;
-
-}
-
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVM_ApplyNewSettings */
-/* */
-/* DESCRIPTION: */
-/* Applies changes to parametres. This function makes no assumptions about what */
-/* each module needs for initialisation and hence passes all parameters to all the */
-/* the modules in turn. */
-/* */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance handle */
-/* */
-/* RETURNS: */
-/* LVM_Success Succeeded */
-/* */
-/****************************************************************************************/
-
-LVM_ReturnStatus_en LVM_ApplyNewSettings(LVM_Handle_t hInstance)
-{
- LVM_Instance_t *pInstance =(LVM_Instance_t *)hInstance;
- LVM_ControlParams_t LocalParams;
- LVM_INT16 Count = 5;
-
-
- /*
- * Copy the new parameters but make sure they didn't change while copying
- */
- do
- {
- pInstance->ControlPending = LVM_FALSE;
- LocalParams = pInstance->NewParams;
- pInstance->HeadroomParams = pInstance->NewHeadroomParams;
- Count--;
- } while ((pInstance->ControlPending != LVM_FALSE) &&
- (Count > 0));
-
-#ifdef SUPPORT_MC
- pInstance->NrChannels = LocalParams.NrChannels;
- pInstance->ChMask = LocalParams.ChMask;
-#endif
-
- /* Clear all internal data if format change*/
- if(LocalParams.SourceFormat != pInstance->Params.SourceFormat)
- {
- LVM_ClearAudioBuffers(pInstance);
- pInstance->ControlPending = LVM_FALSE;
- }
-
- /*
- * Update the treble boost if required
- */
- if ((pInstance->Params.SampleRate != LocalParams.SampleRate) ||
- (pInstance->Params.TE_EffectLevel != LocalParams.TE_EffectLevel) ||
- (pInstance->Params.TE_OperatingMode != LocalParams.TE_OperatingMode) ||
- (pInstance->Params.OperatingMode != LocalParams.OperatingMode) ||
- (pInstance->Params.SpeakerType != LocalParams.SpeakerType))
- {
- LVM_SetTrebleBoost(pInstance,
- &LocalParams);
- }
-
- /*
- * Update the headroom if required
- */
- LVM_SetHeadroom(pInstance, /* Instance pointer */
- &LocalParams); /* New parameters */
-
- /*
- * Update the volume if required
- */
- {
- LVM_SetVolume(pInstance, /* Instance pointer */
- &LocalParams); /* New parameters */
- }
- /* Apply balance changes*/
- if(pInstance->Params.VC_Balance != LocalParams.VC_Balance)
- {
- /* Configure Mixer module for gradual changes to volume*/
- if(LocalParams.VC_Balance < 0)
- {
-#ifdef BUILD_FLOAT
- LVM_FLOAT Target_Float;
-#else
- LVM_INT32 Target;
-#endif
- /* Drop in right channel volume*/
-#ifdef BUILD_FLOAT
- Target_Float = LVM_MAXFLOAT;
- LVC_Mixer_SetTarget(&pInstance->VC_BalanceMix.MixerStream[0], Target_Float);
- LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[0],
- LVM_VC_MIXER_TIME, LocalParams.SampleRate, 1);
-
- Target_Float = dB_to_LinFloat((LVM_INT16)(LocalParams.VC_Balance << 4));
- LVC_Mixer_SetTarget(&pInstance->VC_BalanceMix.MixerStream[1], Target_Float);
- LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[1],
- LVM_VC_MIXER_TIME, LocalParams.SampleRate, 1);
-#else
- Target = LVM_MAXINT_16;
- LVC_Mixer_SetTarget(&pInstance->VC_BalanceMix.MixerStream[0],Target);
- LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[0],LVM_VC_MIXER_TIME,LocalParams.SampleRate,1);
-
- Target = dB_to_Lin32((LVM_INT16)(LocalParams.VC_Balance<<4));
- LVC_Mixer_SetTarget(&pInstance->VC_BalanceMix.MixerStream[1],Target);
- LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[1],LVM_VC_MIXER_TIME,LocalParams.SampleRate,1);
-#endif
- }
- else if(LocalParams.VC_Balance >0)
- {
-#ifdef BUILD_FLOAT
- LVM_FLOAT Target_Float;
-#else
- LVM_INT32 Target;
-#endif
- /* Drop in left channel volume*/
-#ifdef BUILD_FLOAT
- Target_Float = dB_to_LinFloat((LVM_INT16)((-LocalParams.VC_Balance) << 4));
- LVC_Mixer_SetTarget(&pInstance->VC_BalanceMix.MixerStream[0], Target_Float);
- LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[0],
- LVM_VC_MIXER_TIME, LocalParams.SampleRate, 1);
-
- Target_Float = LVM_MAXFLOAT;
- LVC_Mixer_SetTarget(&pInstance->VC_BalanceMix.MixerStream[1], Target_Float);
- LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[1],
- LVM_VC_MIXER_TIME, LocalParams.SampleRate, 1);
-#else
- Target = dB_to_Lin32((LVM_INT16)((-LocalParams.VC_Balance)<<4));
- LVC_Mixer_SetTarget(&pInstance->VC_BalanceMix.MixerStream[0],Target);
- LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[0],LVM_VC_MIXER_TIME,LocalParams.SampleRate,1);
-
- Target = LVM_MAXINT_16;
- LVC_Mixer_SetTarget(&pInstance->VC_BalanceMix.MixerStream[1],Target);
- LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[1],LVM_VC_MIXER_TIME,LocalParams.SampleRate,1);
-#endif
- }
- else
- {
-#ifdef BUILD_FLOAT
- LVM_FLOAT Target_Float;
-#else
- LVM_INT32 Target;
-#endif
- /* No drop*/
-#ifdef BUILD_FLOAT
- Target_Float = LVM_MAXFLOAT;
-#else
- Target = LVM_MAXINT_16;
-#endif
-#ifdef BUILD_FLOAT
- LVC_Mixer_SetTarget(&pInstance->VC_BalanceMix.MixerStream[0],Target_Float);
- LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[0],
- LVM_VC_MIXER_TIME,LocalParams.SampleRate, 1);
-
- LVC_Mixer_SetTarget(&pInstance->VC_BalanceMix.MixerStream[1],Target_Float);
- LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[1],
- LVM_VC_MIXER_TIME,LocalParams.SampleRate, 1);
-#else
- LVC_Mixer_SetTarget(&pInstance->VC_BalanceMix.MixerStream[0],Target);
- LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[0],LVM_VC_MIXER_TIME,LocalParams.SampleRate,1);
-
- LVC_Mixer_SetTarget(&pInstance->VC_BalanceMix.MixerStream[1],Target);
- LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[1],LVM_VC_MIXER_TIME,LocalParams.SampleRate,1);
-#endif
- }
- }
- /*
- * Update the bass enhancement
- */
- {
- LVDBE_ReturnStatus_en DBE_Status;
- LVDBE_Params_t DBE_Params;
- LVDBE_Handle_t *hDBEInstance = pInstance->hDBEInstance;
-
-
- /*
- * Set the new parameters
- */
- if(LocalParams.OperatingMode == LVM_MODE_OFF)
- {
- DBE_Params.OperatingMode = LVDBE_OFF;
- }
- else
- {
- DBE_Params.OperatingMode = (LVDBE_Mode_en)LocalParams.BE_OperatingMode;
- }
- DBE_Params.SampleRate = (LVDBE_Fs_en)LocalParams.SampleRate;
- DBE_Params.EffectLevel = LocalParams.BE_EffectLevel;
- DBE_Params.CentreFrequency = (LVDBE_CentreFreq_en)LocalParams.BE_CentreFreq;
- DBE_Params.HPFSelect = (LVDBE_FilterSelect_en)LocalParams.BE_HPF;
- DBE_Params.HeadroomdB = 0;
- DBE_Params.VolumeControl = LVDBE_VOLUME_OFF;
- DBE_Params.VolumedB = 0;
-#ifdef SUPPORT_MC
- DBE_Params.NrChannels = LocalParams.NrChannels;
-#endif
-
- /*
- * Make the changes
- */
- DBE_Status = LVDBE_Control(hDBEInstance,
- &DBE_Params);
-
-
- /*
- * Quit if the changes were not accepted
- */
- if (DBE_Status != LVDBE_SUCCESS)
- {
- return((LVM_ReturnStatus_en)DBE_Status);
- }
-
-
- /*
- * Set the control flag
- */
- pInstance->DBE_Active = LVM_TRUE;
- }
-
- /*
- * Update the N-Band Equaliser
- */
- {
- LVEQNB_ReturnStatus_en EQNB_Status;
- LVEQNB_Params_t EQNB_Params;
- LVEQNB_Handle_t *hEQNBInstance = pInstance->hEQNBInstance;
-
-
- /*
- * Set the new parameters
- */
-
- if(LocalParams.OperatingMode == LVM_MODE_OFF)
- {
- EQNB_Params.OperatingMode = LVEQNB_BYPASS;
- }
- else
- {
- EQNB_Params.OperatingMode = (LVEQNB_Mode_en)LocalParams.EQNB_OperatingMode;
- }
-
- EQNB_Params.SampleRate = (LVEQNB_Fs_en)LocalParams.SampleRate;
- EQNB_Params.NBands = LocalParams.EQNB_NBands;
- EQNB_Params.pBandDefinition = (LVEQNB_BandDef_t *)LocalParams.pEQNB_BandDefinition;
- if (LocalParams.SourceFormat == LVM_STEREO) /* Mono format not supported */
- {
- EQNB_Params.SourceFormat = LVEQNB_STEREO;
- }
-#ifdef SUPPORT_MC
- /* Note: Currently SourceFormat field of EQNB is not been
- * used by the module.
- */
- else if (LocalParams.SourceFormat == LVM_MULTICHANNEL)
- {
- EQNB_Params.SourceFormat = LVEQNB_MULTICHANNEL;
- }
-#endif
- else
- {
- EQNB_Params.SourceFormat = LVEQNB_MONOINSTEREO; /* Force to Mono-in-Stereo mode */
- }
-#ifdef SUPPORT_MC
- EQNB_Params.NrChannels = LocalParams.NrChannels;
-#endif
-
- /*
- * Set the control flag
- */
- if ((LocalParams.OperatingMode == LVM_MODE_ON) &&
- (LocalParams.EQNB_OperatingMode == LVM_EQNB_ON))
- {
- pInstance->EQNB_Active = LVM_TRUE;
- }
- else
- {
- EQNB_Params.OperatingMode = LVEQNB_BYPASS;
- }
-
- /*
- * Make the changes
- */
- EQNB_Status = LVEQNB_Control(hEQNBInstance,
- &EQNB_Params);
-
-
- /*
- * Quit if the changes were not accepted
- */
- if (EQNB_Status != LVEQNB_SUCCESS)
- {
- return((LVM_ReturnStatus_en)EQNB_Status);
- }
-
- }
-
-
- /*
- * Update concert sound
- */
- {
- LVCS_ReturnStatus_en CS_Status;
- LVCS_Params_t CS_Params;
- LVCS_Handle_t *hCSInstance = pInstance->hCSInstance;
- LVM_Mode_en CompressorMode=LVM_MODE_ON;
-
- /*
- * Set the new parameters
- */
- if(LocalParams.VirtualizerOperatingMode == LVM_MODE_ON)
- {
- CS_Params.OperatingMode = LVCS_ON;
- }
- else
- {
- CS_Params.OperatingMode = LVCS_OFF;
- }
-
- if((LocalParams.TE_OperatingMode == LVM_TE_ON) && (LocalParams.TE_EffectLevel == LVM_TE_LOW_MIPS))
- {
- CS_Params.SpeakerType = LVCS_EX_HEADPHONES;
- }
- else
- {
- CS_Params.SpeakerType = LVCS_HEADPHONES;
- }
-
-#ifdef SUPPORT_MC
- /* Concert sound module processes only the left and right channels
- * data. So the Source Format is set to LVCS_STEREO for multichannel
- * input also.
- */
- if (LocalParams.SourceFormat == LVM_STEREO ||
- LocalParams.SourceFormat == LVM_MULTICHANNEL)
-#else
- if (LocalParams.SourceFormat == LVM_STEREO) /* Mono format not supported */
-#endif
- {
- CS_Params.SourceFormat = LVCS_STEREO;
- }
- else
- {
- CS_Params.SourceFormat = LVCS_MONOINSTEREO; /* Force to Mono-in-Stereo mode */
- }
- CS_Params.SampleRate = LocalParams.SampleRate;
- CS_Params.ReverbLevel = LocalParams.VirtualizerReverbLevel;
- CS_Params.EffectLevel = LocalParams.CS_EffectLevel;
-#ifdef SUPPORT_MC
- CS_Params.NrChannels = LocalParams.NrChannels;
-#endif
-
- /*
- * Set the control flag
- */
- if ((LocalParams.OperatingMode == LVM_MODE_ON) &&
- (LocalParams.VirtualizerOperatingMode != LVCS_OFF))
- {
- pInstance->CS_Active = LVM_TRUE;
- }
- else
- {
- CS_Params.OperatingMode = LVCS_OFF;
- }
-
- CS_Params.CompressorMode=CompressorMode;
-
- /*
- * Make the changes
- */
- CS_Status = LVCS_Control(hCSInstance,
- &CS_Params);
-
-
- /*
- * Quit if the changes were not accepted
- */
- if (CS_Status != LVCS_SUCCESS)
- {
- return((LVM_ReturnStatus_en)CS_Status);
- }
-
- }
-
- /*
- * Update the Power Spectrum Analyser
- */
- {
- LVPSA_RETURN PSA_Status;
- LVPSA_ControlParams_t PSA_Params;
- pLVPSA_Handle_t *hPSAInstance = pInstance->hPSAInstance;
-
-
- /*
- * Set the new parameters
- */
- PSA_Params.Fs = LocalParams.SampleRate;
- PSA_Params.LevelDetectionSpeed = (LVPSA_LevelDetectSpeed_en)LocalParams.PSA_PeakDecayRate;
-
- /*
- * Make the changes
- */
- if(pInstance->InstParams.PSA_Included==LVM_PSA_ON)
- {
- PSA_Status = LVPSA_Control(hPSAInstance,
- &PSA_Params);
-
- if (PSA_Status != LVPSA_OK)
- {
- return((LVM_ReturnStatus_en)PSA_Status);
- }
-
- /*
- * Apply new settings
- */
- PSA_Status = LVPSA_ApplyNewSettings ((LVPSA_InstancePr_t*)hPSAInstance);
- if(PSA_Status != LVPSA_OK)
- {
- return((LVM_ReturnStatus_en)PSA_Status);
- }
- }
- }
-
- /*
- * Update the parameters and clear the flag
- */
- pInstance->NoSmoothVolume = LVM_FALSE;
- pInstance->Params = LocalParams;
-
-
- return(LVM_SUCCESS);
-}
-
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVM_SetHeadroomParams */
-/* */
-/* DESCRIPTION: */
-/* This function is used to set the automatiuc headroom management parameters. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance Handle */
-/* pHeadroomParams Pointer to headroom parameter structure */
-/* */
-/* RETURNS: */
-/* LVM_Success Succeeded */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVM_Process function */
-/* */
-/****************************************************************************************/
-
-LVM_ReturnStatus_en LVM_SetHeadroomParams(LVM_Handle_t hInstance,
- LVM_HeadroomParams_t *pHeadroomParams)
-{
- LVM_Instance_t *pInstance =(LVM_Instance_t *)hInstance;
- LVM_UINT16 ii, NBands;
-
- /* Check for NULL pointers */
- if ((hInstance == LVM_NULL) || (pHeadroomParams == LVM_NULL))
- {
- return (LVM_NULLADDRESS);
- }
- if ((pHeadroomParams->NHeadroomBands != 0) && (pHeadroomParams->pHeadroomDefinition == LVM_NULL))
- {
- return (LVM_NULLADDRESS);
- }
-
- /* Consider only the LVM_HEADROOM_MAX_NBANDS first bands*/
- if (pHeadroomParams->NHeadroomBands > LVM_HEADROOM_MAX_NBANDS)
- {
- NBands = LVM_HEADROOM_MAX_NBANDS;
- }
- else
- {
- NBands = pHeadroomParams->NHeadroomBands;
- }
- pInstance->NewHeadroomParams.NHeadroomBands = NBands;
-
- /* Copy settings in memory */
- for(ii = 0; ii < NBands; ii++)
- {
- pInstance->pHeadroom_BandDefs[ii] = pHeadroomParams->pHeadroomDefinition[ii];
- }
-
- pInstance->NewHeadroomParams.pHeadroomDefinition = pInstance->pHeadroom_BandDefs;
- pInstance->NewHeadroomParams.Headroom_OperatingMode = pHeadroomParams->Headroom_OperatingMode;
- pInstance->ControlPending = LVM_TRUE;
-
- return(LVM_SUCCESS);
-}
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVM_GetHeadroomParams */
-/* */
-/* DESCRIPTION: */
-/* This function is used to get the automatic headroom management parameters. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance Handle */
-/* pHeadroomParams Pointer to headroom parameter structure (output) */
-/* */
-/* RETURNS: */
-/* LVM_SUCCESS Succeeded */
-/* LVM_NULLADDRESS When hInstance or pHeadroomParams are NULL */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVM_Process function */
-/* */
-/****************************************************************************************/
-
-LVM_ReturnStatus_en LVM_GetHeadroomParams(LVM_Handle_t hInstance,
- LVM_HeadroomParams_t *pHeadroomParams)
-{
- LVM_Instance_t *pInstance =(LVM_Instance_t *)hInstance;
- LVM_UINT16 ii;
-
- /* Check for NULL pointers */
- if ((hInstance == LVM_NULL) || (pHeadroomParams == LVM_NULL))
- {
- return (LVM_NULLADDRESS);
- }
-
- pHeadroomParams->NHeadroomBands = pInstance->NewHeadroomParams.NHeadroomBands;
-
-
- /* Copy settings in memory */
- for(ii = 0; ii < pInstance->NewHeadroomParams.NHeadroomBands; ii++)
- {
- pInstance->pHeadroom_UserDefs[ii] = pInstance->pHeadroom_BandDefs[ii];
- }
-
-
- pHeadroomParams->pHeadroomDefinition = pInstance->pHeadroom_UserDefs;
- pHeadroomParams->Headroom_OperatingMode = pInstance->NewHeadroomParams.Headroom_OperatingMode;
- return(LVM_SUCCESS);
-}
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVM_AlgoCallBack */
-/* */
-/* DESCRIPTION: */
-/* This is the callback function of the algorithm. */
-/* */
-/* PARAMETERS: */
-/* pBundleHandle Pointer to the Instance Handle */
-/* pData Pointer to the data */
-/* callbackId ID of the callback */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVM_Process function */
-/* */
-/****************************************************************************************/
-LVM_INT32 LVM_AlgoCallBack( void *pBundleHandle,
- void *pData,
- LVM_INT16 callbackId)
-{
- LVM_Instance_t *pInstance =(LVM_Instance_t *)pBundleHandle;
-
- (void) pData;
-
- switch(callbackId & 0xFF00){
- case ALGORITHM_CS_ID:
- switch(callbackId & 0x00FF)
- {
- case LVCS_EVENT_ALGOFF:
- pInstance->CS_Active = LVM_FALSE;
- break;
- default:
- break;
- }
- break;
- case ALGORITHM_EQNB_ID:
- switch(callbackId & 0x00FF)
- {
- case LVEQNB_EVENT_ALGOFF:
- pInstance->EQNB_Active = LVM_FALSE;
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVM_VCCallBack */
-/* */
-/* DESCRIPTION: */
-/* This is the callback function of the Volume control. */
-/* */
-/* PARAMETERS: */
-/* pBundleHandle Pointer to the Instance Handle */
-/* pGeneralPurpose Pointer to the data */
-/* CallBackParam ID of the callback */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVM_Process function */
-/* */
-/****************************************************************************************/
-LVM_INT32 LVM_VCCallBack(void* pBundleHandle,
- void* pGeneralPurpose,
- short CallBackParam)
-{
- LVM_Instance_t *pInstance =(LVM_Instance_t *)pBundleHandle;
-#ifdef BUILD_FLOAT
- LVM_FLOAT Target;
-#else
- LVM_INT32 Target;
-#endif
-
- (void) pGeneralPurpose;
- (void) CallBackParam;
-
- /* When volume mixer has reached 0 dB target then stop it to avoid
- unnecessary processing. */
-#ifdef BUILD_FLOAT
- Target = LVC_Mixer_GetTarget(&pInstance->VC_Volume.MixerStream[0]);
- if(Target == 1.0f)
- {
- pInstance->VC_Active = LVM_FALSE;
- }
-#else
- Target = LVC_Mixer_GetTarget(&pInstance->VC_Volume.MixerStream[0]);
-
- if(Target == 0x7FFF)
- {
- pInstance->VC_Active = LVM_FALSE;
- }
-#endif
- return 1;
-}
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Control.cpp b/media/libeffects/lvm/lib/Bundle/src/LVM_Control.cpp
new file mode 100644
index 0000000..ff2c90a
--- /dev/null
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Control.cpp
@@ -0,0 +1,1061 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/****************************************************************************************/
+/* */
+/* Includes */
+/* */
+/****************************************************************************************/
+
+#include "VectorArithmetic.h"
+#include "ScalarArithmetic.h"
+#include "LVM_Coeffs.h"
+#include "LVM_Tables.h"
+#include "LVM_Private.h"
+
+#include <log/log.h>
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVM_SetControlParameters */
+/* */
+/* DESCRIPTION: */
+/* Sets or changes the LifeVibes module parameters. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance handle */
+/* pParams Pointer to a parameter structure */
+/* */
+/* RETURNS: */
+/* LVM_SUCCESS Succeeded */
+/* LVM_NULLADDRESS When hInstance, pParams or any control pointers are NULL */
+/* LVM_OUTOFRANGE When any of the control parameters are out of range */
+/* */
+/* NOTES: */
+/* 1. This function may be interrupted by the LVM_Process function */
+/* */
+/****************************************************************************************/
+
+LVM_ReturnStatus_en LVM_SetControlParameters(LVM_Handle_t hInstance,
+ LVM_ControlParams_t *pParams)
+{
+ LVM_Instance_t *pInstance =(LVM_Instance_t *)hInstance;
+
+ if ((pParams == LVM_NULL) || (hInstance == LVM_NULL))
+ {
+ return (LVM_NULLADDRESS);
+ }
+
+ pInstance->NewParams = *pParams;
+
+ if(
+ /* General parameters */
+ ((pParams->OperatingMode != LVM_MODE_OFF) && (pParams->OperatingMode != LVM_MODE_ON)) ||
+ ((pParams->SampleRate != LVM_FS_8000) && (pParams->SampleRate != LVM_FS_11025) && (pParams->SampleRate != LVM_FS_12000) &&
+ (pParams->SampleRate != LVM_FS_16000) && (pParams->SampleRate != LVM_FS_22050) && (pParams->SampleRate != LVM_FS_24000) &&
+ (pParams->SampleRate != LVM_FS_32000) && (pParams->SampleRate != LVM_FS_44100) && (pParams->SampleRate != LVM_FS_48000) &&
+ (pParams->SampleRate != LVM_FS_88200) && (pParams->SampleRate != LVM_FS_96000) &&
+ (pParams->SampleRate != LVM_FS_176400) && (pParams->SampleRate != LVM_FS_192000)) ||
+#ifdef SUPPORT_MC
+ ((pParams->SourceFormat != LVM_STEREO) &&
+ (pParams->SourceFormat != LVM_MONOINSTEREO) &&
+ (pParams->SourceFormat != LVM_MONO) &&
+ (pParams->SourceFormat != LVM_MULTICHANNEL)) ||
+#else
+ ((pParams->SourceFormat != LVM_STEREO) && (pParams->SourceFormat != LVM_MONOINSTEREO) && (pParams->SourceFormat != LVM_MONO)) ||
+#endif
+ (pParams->SpeakerType > LVM_EX_HEADPHONES))
+ {
+ return (LVM_OUTOFRANGE);
+ }
+
+#ifdef SUPPORT_MC
+ pInstance->Params.NrChannels = pParams->NrChannels;
+ pInstance->Params.ChMask = pParams->ChMask;
+#endif
+ /*
+ * Cinema Sound parameters
+ */
+ if((pParams->VirtualizerOperatingMode != LVM_MODE_OFF) && (pParams->VirtualizerOperatingMode != LVM_MODE_ON))
+ {
+ return (LVM_OUTOFRANGE);
+ }
+
+ if(pParams->VirtualizerType != LVM_CONCERTSOUND)
+ {
+ return (LVM_OUTOFRANGE);
+ }
+
+ if(pParams->VirtualizerReverbLevel > LVM_VIRTUALIZER_MAX_REVERB_LEVEL)
+ {
+ return (LVM_OUTOFRANGE);
+ }
+
+ if(pParams->CS_EffectLevel < LVM_CS_MIN_EFFECT_LEVEL)
+ {
+ return (LVM_OUTOFRANGE);
+ }
+
+ /*
+ * N-Band Equalizer
+ */
+ if(pParams->EQNB_NBands > pInstance->InstParams.EQNB_NumBands)
+ {
+ return (LVM_OUTOFRANGE);
+ }
+
+ /* Definition pointer */
+ if ((pParams->pEQNB_BandDefinition == LVM_NULL) &&
+ (pParams->EQNB_NBands != 0))
+ {
+ return (LVM_NULLADDRESS);
+ }
+
+ /*
+ * Copy the filter definitions for the Equaliser
+ */
+ {
+ LVM_INT16 i;
+
+ if (pParams->EQNB_NBands != 0)
+ {
+ for (i=0; i<pParams->EQNB_NBands; i++)
+ {
+ pInstance->pEQNB_BandDefs[i] = pParams->pEQNB_BandDefinition[i];
+ }
+ pInstance->NewParams.pEQNB_BandDefinition = pInstance->pEQNB_BandDefs;
+ }
+ }
+ if( /* N-Band Equaliser parameters */
+ ((pParams->EQNB_OperatingMode != LVM_EQNB_OFF) && (pParams->EQNB_OperatingMode != LVM_EQNB_ON)) ||
+ (pParams->EQNB_NBands > pInstance->InstParams.EQNB_NumBands))
+ {
+ return (LVM_OUTOFRANGE);
+ }
+ /* Band parameters*/
+ {
+ LVM_INT16 i;
+ for(i = 0; i < pParams->EQNB_NBands; i++)
+ {
+ if(((pParams->pEQNB_BandDefinition[i].Frequency < LVM_EQNB_MIN_BAND_FREQ) ||
+ (pParams->pEQNB_BandDefinition[i].Frequency > LVM_EQNB_MAX_BAND_FREQ)) ||
+ ((pParams->pEQNB_BandDefinition[i].Gain < LVM_EQNB_MIN_BAND_GAIN) ||
+ (pParams->pEQNB_BandDefinition[i].Gain > LVM_EQNB_MAX_BAND_GAIN)) ||
+ ((pParams->pEQNB_BandDefinition[i].QFactor < LVM_EQNB_MIN_QFACTOR) ||
+ (pParams->pEQNB_BandDefinition[i].QFactor > LVM_EQNB_MAX_QFACTOR)))
+ {
+ return (LVM_OUTOFRANGE);
+ }
+ }
+ }
+
+ /*
+ * Bass Enhancement parameters
+ */
+ if(((pParams->BE_OperatingMode != LVM_BE_OFF) && (pParams->BE_OperatingMode != LVM_BE_ON)) ||
+ ((pParams->BE_EffectLevel < LVM_BE_MIN_EFFECTLEVEL ) || (pParams->BE_EffectLevel > LVM_BE_MAX_EFFECTLEVEL ))||
+ ((pParams->BE_CentreFreq != LVM_BE_CENTRE_55Hz) && (pParams->BE_CentreFreq != LVM_BE_CENTRE_66Hz) &&
+ (pParams->BE_CentreFreq != LVM_BE_CENTRE_78Hz) && (pParams->BE_CentreFreq != LVM_BE_CENTRE_90Hz)) ||
+ ((pParams->BE_HPF != LVM_BE_HPF_OFF) && (pParams->BE_HPF != LVM_BE_HPF_ON)))
+ {
+ return (LVM_OUTOFRANGE);
+ }
+
+ /*
+ * Volume Control parameters
+ */
+ if((pParams->VC_EffectLevel < LVM_VC_MIN_EFFECTLEVEL ) || (pParams->VC_EffectLevel > LVM_VC_MAX_EFFECTLEVEL ))
+ {
+ return (LVM_OUTOFRANGE);
+ }
+ if((pParams->VC_Balance < LVM_VC_BALANCE_MIN ) || (pParams->VC_Balance > LVM_VC_BALANCE_MAX ))
+ {
+ return (LVM_OUTOFRANGE);
+ }
+
+ /*
+ * PSA parameters
+ */
+ if (((LVPSA_LevelDetectSpeed_en)pParams->PSA_PeakDecayRate > LVPSA_SPEED_HIGH) ||
+ (pParams->PSA_Enable > LVM_PSA_ON))
+ {
+ return (LVM_OUTOFRANGE);
+ }
+
+ /*
+ * Set the flag to indicate there are new parameters to use
+ *
+ * Protect the copy of the new parameters from interrupts to avoid possible problems
+ * with loss control parameters. This problem can occur if this control function is called more
+ * than once before a call to the process function. If the process function interrupts
+ * the copy to NewParams then one frame may have mixed parameters, some old and some new.
+ */
+ pInstance->ControlPending = LVM_TRUE;
+
+ return(LVM_SUCCESS);
+}
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVM_GetControlParameters */
+/* */
+/* DESCRIPTION: */
+/* Request the LifeVibes module parameters. The current parameter set is returned */
+/* via the parameter pointer. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance handle */
+/* pParams Pointer to an empty parameter structure */
+/* */
+/* RETURNS: */
+/* LVM_SUCCESS Succeeded */
+/* LVM_NULLADDRESS when any of hInstance or pParams is NULL */
+/* */
+/* NOTES: */
+/* 1. This function may be interrupted by the LVM_Process function */
+/* */
+/****************************************************************************************/
+
+LVM_ReturnStatus_en LVM_GetControlParameters(LVM_Handle_t hInstance,
+ LVM_ControlParams_t *pParams)
+{
+ LVM_Instance_t *pInstance =(LVM_Instance_t *)hInstance;
+
+ /*
+ * Check pointer
+ */
+ if ((pParams == LVM_NULL) || (hInstance == LVM_NULL))
+ {
+ return (LVM_NULLADDRESS);
+ }
+ *pParams = pInstance->NewParams;
+
+ /*
+ * Copy the filter definitions for the Equaliser
+ */
+ {
+ LVM_INT16 i;
+
+ if (pInstance->NewParams.EQNB_NBands != 0)
+ for (i=0; i<pInstance->NewParams.EQNB_NBands; i++)
+ {
+ pInstance->pEQNB_UserDefs[i] = pInstance->pEQNB_BandDefs[i];
+ }
+ pParams->pEQNB_BandDefinition = pInstance->pEQNB_UserDefs;
+ }
+
+ return(LVM_SUCCESS);
+}
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVM_SetTrebleBoost */
+/* */
+/* DESCRIPTION: */
+/* Enable the treble boost when the settings are appropriate, i.e. non-zero gain */
+/* and the sample rate is high enough for the effect to be heard. */
+/* */
+/* PARAMETERS: */
+/* pInstance Pointer to the instance structure */
+/* pParams Pointer to the parameters to use */
+/* */
+/****************************************************************************************/
+void LVM_SetTrebleBoost(LVM_Instance_t *pInstance,
+ LVM_ControlParams_t *pParams)
+{
+ extern FO_FLOAT_LShx_Coefs_t LVM_TrebleBoostCoefs[];
+
+ LVM_INT16 Offset;
+ LVM_INT16 EffectLevel = 0;
+
+ /*
+ * Load the coefficients
+ */
+ if ((pParams->TE_OperatingMode == LVM_TE_ON) &&
+ (pParams->SampleRate >= TrebleBoostMinRate) &&
+ (pParams->OperatingMode == LVM_MODE_ON) &&
+ (pParams->TE_EffectLevel > 0))
+ {
+ if((pParams->TE_EffectLevel == LVM_TE_LOW_MIPS) &&
+ ((pParams->SpeakerType == LVM_HEADPHONES)||
+ (pParams->SpeakerType == LVM_EX_HEADPHONES)))
+ {
+ pInstance->TE_Active = LVM_FALSE;
+ }
+ else
+ {
+ EffectLevel = pParams->TE_EffectLevel;
+ pInstance->TE_Active = LVM_TRUE;
+ }
+
+ if(pInstance->TE_Active == LVM_TRUE)
+ {
+ /*
+ * Load the coefficients and enabled the treble boost
+ */
+ Offset = (LVM_INT16)(EffectLevel - 1 + TrebleBoostSteps * (pParams->SampleRate - TrebleBoostMinRate));
+ FO_2I_D16F32Css_LShx_TRC_WRA_01_Init(&pInstance->pTE_State->TrebleBoost_State,
+ &pInstance->pTE_Taps->TrebleBoost_Taps,
+ &LVM_TrebleBoostCoefs[Offset]);
+
+ /*
+ * Clear the taps
+ */
+ LoadConst_Float((LVM_FLOAT)0, /* Value */
+ (LVM_FLOAT *)&pInstance->pTE_Taps->TrebleBoost_Taps, /* Destination.\
+ Cast to void: no dereferencing in function */
+ (LVM_UINT16)(sizeof(pInstance->pTE_Taps->TrebleBoost_Taps) / \
+ sizeof(LVM_FLOAT))); /* Number of words */
+ }
+ }
+ else
+ {
+ /*
+ * Disable the treble boost
+ */
+ pInstance->TE_Active = LVM_FALSE;
+ }
+
+ return;
+}
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVM_SetVolume */
+/* */
+/* DESCRIPTION: */
+/* Converts the input volume demand from dBs to linear. */
+/* */
+/* PARAMETERS: */
+/* pInstance Pointer to the instance */
+/* pParams Initialisation parameters */
+/* */
+/************************************************************************************/
+void LVM_SetVolume(LVM_Instance_t *pInstance,
+ LVM_ControlParams_t *pParams)
+{
+
+ LVM_UINT16 dBShifts; /* 6dB shifts */
+ LVM_UINT16 dBOffset; /* Table offset */
+ LVM_INT16 Volume = 0; /* Required volume in dBs */
+ LVM_FLOAT Temp;
+
+ /*
+ * Limit the gain to the maximum allowed
+ */
+ if (pParams->VC_EffectLevel > 0)
+ {
+ Volume = 0;
+ }
+ else
+ {
+ Volume = pParams->VC_EffectLevel;
+ }
+
+ /* Compensate this volume in PSA plot */
+ if(Volume > -60) /* Limit volume loss to PSA Limits*/
+ pInstance->PSA_GainOffset=(LVM_INT16)(-Volume);/* Loss is compensated by Gain*/
+ else
+ pInstance->PSA_GainOffset=(LVM_INT16)60;/* Loss is compensated by Gain*/
+
+ pInstance->VC_AVLFixedVolume = 0;
+
+ /*
+ * Set volume control and AVL volumes according to headroom and volume user setting
+ */
+ if(pParams->OperatingMode == LVM_MODE_ON)
+ {
+ /* Default Situation with no AVL and no RS */
+ if(pParams->EQNB_OperatingMode == LVM_EQNB_ON)
+ {
+ if(Volume > -pInstance->Headroom)
+ Volume = (LVM_INT16)-pInstance->Headroom;
+ }
+ }
+
+ /*
+ * Activate volume control if necessary
+ */
+ pInstance->VC_Active = LVM_TRUE;
+ if (Volume != 0)
+ {
+ pInstance->VC_VolumedB = Volume;
+ }
+ else
+ {
+ pInstance->VC_VolumedB = 0;
+ }
+
+ /*
+ * Calculate the required gain and shifts
+ */
+ dBOffset = (LVM_UINT16)((-Volume) % 6); /* Get the dBs 0-5 */
+ dBShifts = (LVM_UINT16)(Volume / -6); /* Get the 6dB shifts */
+
+ /*
+ * Set the parameters
+ */
+ if(dBShifts == 0)
+ {
+ LVC_Mixer_SetTarget(&pInstance->VC_Volume.MixerStream[0],
+ (LVM_FLOAT)LVM_VolumeTable[dBOffset]);
+ }
+ else
+ {
+ Temp = LVM_VolumeTable[dBOffset];
+ while(dBShifts) {
+ Temp = Temp / 2.0f;
+ dBShifts--;
+ }
+ LVC_Mixer_SetTarget(&pInstance->VC_Volume.MixerStream[0], Temp);
+ }
+ pInstance->VC_Volume.MixerStream[0].CallbackSet = 1;
+ if(pInstance->NoSmoothVolume == LVM_TRUE)
+ {
+ LVC_Mixer_SetTimeConstant(&pInstance->VC_Volume.MixerStream[0], 0,
+ pInstance->Params.SampleRate, 2);
+ }
+ else
+ {
+ LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_Volume.MixerStream[0],
+ LVM_VC_MIXER_TIME, pInstance->Params.SampleRate, 2);
+ }
+}
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVM_SetHeadroom */
+/* */
+/* DESCRIPTION: */
+/* Find suitable headroom based on EQ settings. */
+/* */
+/* PARAMETERS: */
+/* pInstance Pointer to the instance */
+/* pParams Initialisation parameters */
+/* */
+/* RETURNS: */
+/* void Nothing */
+/* */
+/* NOTES: */
+/* */
+/************************************************************************************/
+void LVM_SetHeadroom(LVM_Instance_t *pInstance,
+ LVM_ControlParams_t *pParams)
+{
+ LVM_INT16 ii, jj;
+ LVM_INT16 Headroom = 0;
+ LVM_INT16 MaxGain = 0;
+
+ if (((LVEQNB_Mode_en)pParams->EQNB_OperatingMode == LVEQNB_ON)
+ && (pInstance->HeadroomParams.Headroom_OperatingMode == LVM_HEADROOM_ON))
+ {
+ /* Find typical headroom value */
+ for(jj = 0; jj < pInstance->HeadroomParams.NHeadroomBands; jj++)
+ {
+ MaxGain = 0;
+ for( ii = 0; ii < pParams->EQNB_NBands; ii++)
+ {
+ if((pParams->pEQNB_BandDefinition[ii].Frequency >= pInstance->HeadroomParams.pHeadroomDefinition[jj].Limit_Low) &&
+ (pParams->pEQNB_BandDefinition[ii].Frequency <= pInstance->HeadroomParams.pHeadroomDefinition[jj].Limit_High))
+ {
+ if(pParams->pEQNB_BandDefinition[ii].Gain > MaxGain)
+ {
+ MaxGain = pParams->pEQNB_BandDefinition[ii].Gain;
+ }
+ }
+ }
+
+ if((MaxGain - pInstance->HeadroomParams.pHeadroomDefinition[jj].Headroom_Offset) > Headroom){
+ Headroom = (LVM_INT16)(MaxGain - pInstance->HeadroomParams.pHeadroomDefinition[jj].Headroom_Offset);
+ }
+ }
+
+ /* Saturate */
+ if(Headroom < 0)
+ Headroom = 0;
+ }
+ pInstance->Headroom = (LVM_UINT16)Headroom ;
+
+}
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVM_ApplyNewSettings */
+/* */
+/* DESCRIPTION: */
+/* Applies changes to parametres. This function makes no assumptions about what */
+/* each module needs for initialisation and hence passes all parameters to all the */
+/* the modules in turn. */
+/* */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance handle */
+/* */
+/* RETURNS: */
+/* LVM_Success Succeeded */
+/* */
+/****************************************************************************************/
+
+LVM_ReturnStatus_en LVM_ApplyNewSettings(LVM_Handle_t hInstance)
+{
+ LVM_Instance_t *pInstance =(LVM_Instance_t *)hInstance;
+ LVM_ControlParams_t LocalParams;
+ LVM_INT16 Count = 5;
+
+ /*
+ * Copy the new parameters but make sure they didn't change while copying
+ */
+ do
+ {
+ pInstance->ControlPending = LVM_FALSE;
+ LocalParams = pInstance->NewParams;
+ pInstance->HeadroomParams = pInstance->NewHeadroomParams;
+ Count--;
+ } while ((pInstance->ControlPending != LVM_FALSE) &&
+ (Count > 0));
+
+#ifdef SUPPORT_MC
+ pInstance->NrChannels = LocalParams.NrChannels;
+ pInstance->ChMask = LocalParams.ChMask;
+#endif
+
+ /* Clear all internal data if format change*/
+ if(LocalParams.SourceFormat != pInstance->Params.SourceFormat)
+ {
+ LVM_ClearAudioBuffers(pInstance);
+ pInstance->ControlPending = LVM_FALSE;
+ }
+
+ /*
+ * Update the treble boost if required
+ */
+ if ((pInstance->Params.SampleRate != LocalParams.SampleRate) ||
+ (pInstance->Params.TE_EffectLevel != LocalParams.TE_EffectLevel) ||
+ (pInstance->Params.TE_OperatingMode != LocalParams.TE_OperatingMode) ||
+ (pInstance->Params.OperatingMode != LocalParams.OperatingMode) ||
+ (pInstance->Params.SpeakerType != LocalParams.SpeakerType))
+ {
+ LVM_SetTrebleBoost(pInstance,
+ &LocalParams);
+ }
+
+ /*
+ * Update the headroom if required
+ */
+ LVM_SetHeadroom(pInstance, /* Instance pointer */
+ &LocalParams); /* New parameters */
+
+ /*
+ * Update the volume if required
+ */
+ {
+ LVM_SetVolume(pInstance, /* Instance pointer */
+ &LocalParams); /* New parameters */
+ }
+ /* Apply balance changes*/
+ if(pInstance->Params.VC_Balance != LocalParams.VC_Balance)
+ {
+ /* Configure Mixer module for gradual changes to volume*/
+ if(LocalParams.VC_Balance < 0)
+ {
+ LVM_FLOAT Target_Float;
+ /* Drop in right channel volume*/
+ Target_Float = LVM_MAXFLOAT;
+ LVC_Mixer_SetTarget(&pInstance->VC_BalanceMix.MixerStream[0], Target_Float);
+ LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[0],
+ LVM_VC_MIXER_TIME, LocalParams.SampleRate, 1);
+
+ Target_Float = dB_to_LinFloat((LVM_INT16)(LocalParams.VC_Balance << 4));
+ LVC_Mixer_SetTarget(&pInstance->VC_BalanceMix.MixerStream[1], Target_Float);
+ LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[1],
+ LVM_VC_MIXER_TIME, LocalParams.SampleRate, 1);
+ }
+ else if(LocalParams.VC_Balance >0)
+ {
+ LVM_FLOAT Target_Float;
+ /* Drop in left channel volume*/
+ Target_Float = dB_to_LinFloat((LVM_INT16)((-LocalParams.VC_Balance) << 4));
+ LVC_Mixer_SetTarget(&pInstance->VC_BalanceMix.MixerStream[0], Target_Float);
+ LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[0],
+ LVM_VC_MIXER_TIME, LocalParams.SampleRate, 1);
+
+ Target_Float = LVM_MAXFLOAT;
+ LVC_Mixer_SetTarget(&pInstance->VC_BalanceMix.MixerStream[1], Target_Float);
+ LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[1],
+ LVM_VC_MIXER_TIME, LocalParams.SampleRate, 1);
+ }
+ else
+ {
+ LVM_FLOAT Target_Float;
+ /* No drop*/
+ Target_Float = LVM_MAXFLOAT;
+ LVC_Mixer_SetTarget(&pInstance->VC_BalanceMix.MixerStream[0],Target_Float);
+ LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[0],
+ LVM_VC_MIXER_TIME,LocalParams.SampleRate, 1);
+
+ LVC_Mixer_SetTarget(&pInstance->VC_BalanceMix.MixerStream[1],Target_Float);
+ LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[1],
+ LVM_VC_MIXER_TIME,LocalParams.SampleRate, 1);
+ }
+ }
+ /*
+ * Update the bass enhancement
+ */
+ {
+ LVDBE_ReturnStatus_en DBE_Status;
+ LVDBE_Params_t DBE_Params;
+ LVDBE_Handle_t *hDBEInstance = (LVDBE_Handle_t *)pInstance->hDBEInstance;
+
+ /*
+ * Set the new parameters
+ */
+ if(LocalParams.OperatingMode == LVM_MODE_OFF)
+ {
+ DBE_Params.OperatingMode = LVDBE_OFF;
+ }
+ else
+ {
+ DBE_Params.OperatingMode = (LVDBE_Mode_en)LocalParams.BE_OperatingMode;
+ }
+ DBE_Params.SampleRate = (LVDBE_Fs_en)LocalParams.SampleRate;
+ DBE_Params.EffectLevel = LocalParams.BE_EffectLevel;
+ DBE_Params.CentreFrequency = (LVDBE_CentreFreq_en)LocalParams.BE_CentreFreq;
+ DBE_Params.HPFSelect = (LVDBE_FilterSelect_en)LocalParams.BE_HPF;
+ DBE_Params.HeadroomdB = 0;
+ DBE_Params.VolumeControl = LVDBE_VOLUME_OFF;
+ DBE_Params.VolumedB = 0;
+#ifdef SUPPORT_MC
+ DBE_Params.NrChannels = LocalParams.NrChannels;
+#endif
+
+ /*
+ * Make the changes
+ */
+ DBE_Status = LVDBE_Control(hDBEInstance,
+ &DBE_Params);
+
+ /*
+ * Quit if the changes were not accepted
+ */
+ if (DBE_Status != LVDBE_SUCCESS)
+ {
+ return((LVM_ReturnStatus_en)DBE_Status);
+ }
+
+ /*
+ * Set the control flag
+ */
+ pInstance->DBE_Active = LVM_TRUE;
+ }
+
+ /*
+ * Update the N-Band Equaliser
+ */
+ {
+ LVEQNB_ReturnStatus_en EQNB_Status;
+ LVEQNB_Params_t EQNB_Params;
+ LVEQNB_Handle_t *hEQNBInstance = (LVEQNB_Handle_t *)pInstance->hEQNBInstance;
+
+ /*
+ * Set the new parameters
+ */
+
+ if(LocalParams.OperatingMode == LVM_MODE_OFF)
+ {
+ EQNB_Params.OperatingMode = LVEQNB_BYPASS;
+ }
+ else
+ {
+ EQNB_Params.OperatingMode = (LVEQNB_Mode_en)LocalParams.EQNB_OperatingMode;
+ }
+
+ EQNB_Params.SampleRate = (LVEQNB_Fs_en)LocalParams.SampleRate;
+ EQNB_Params.NBands = LocalParams.EQNB_NBands;
+ EQNB_Params.pBandDefinition = (LVEQNB_BandDef_t *)LocalParams.pEQNB_BandDefinition;
+ if (LocalParams.SourceFormat == LVM_STEREO) /* Mono format not supported */
+ {
+ EQNB_Params.SourceFormat = LVEQNB_STEREO;
+ }
+#ifdef SUPPORT_MC
+ /* Note: Currently SourceFormat field of EQNB is not been
+ * used by the module.
+ */
+ else if (LocalParams.SourceFormat == LVM_MULTICHANNEL)
+ {
+ EQNB_Params.SourceFormat = LVEQNB_MULTICHANNEL;
+ }
+#endif
+ else
+ {
+ EQNB_Params.SourceFormat = LVEQNB_MONOINSTEREO; /* Force to Mono-in-Stereo mode */
+ }
+#ifdef SUPPORT_MC
+ EQNB_Params.NrChannels = LocalParams.NrChannels;
+#endif
+
+ /*
+ * Set the control flag
+ */
+ if ((LocalParams.OperatingMode == LVM_MODE_ON) &&
+ (LocalParams.EQNB_OperatingMode == LVM_EQNB_ON))
+ {
+ pInstance->EQNB_Active = LVM_TRUE;
+ }
+ else
+ {
+ EQNB_Params.OperatingMode = LVEQNB_BYPASS;
+ }
+
+ /*
+ * Make the changes
+ */
+ EQNB_Status = LVEQNB_Control(hEQNBInstance,
+ &EQNB_Params);
+
+ /*
+ * Quit if the changes were not accepted
+ */
+ if (EQNB_Status != LVEQNB_SUCCESS)
+ {
+ return((LVM_ReturnStatus_en)EQNB_Status);
+ }
+
+ }
+
+ /*
+ * Update concert sound
+ */
+ {
+ LVCS_ReturnStatus_en CS_Status;
+ LVCS_Params_t CS_Params;
+ LVCS_Handle_t *hCSInstance = (LVCS_Handle_t *)pInstance->hCSInstance;
+ LVM_Mode_en CompressorMode=LVM_MODE_ON;
+
+ /*
+ * Set the new parameters
+ */
+ if(LocalParams.VirtualizerOperatingMode == LVM_MODE_ON)
+ {
+ CS_Params.OperatingMode = LVCS_ON;
+ }
+ else
+ {
+ CS_Params.OperatingMode = LVCS_OFF;
+ }
+
+ if((LocalParams.TE_OperatingMode == LVM_TE_ON) && (LocalParams.TE_EffectLevel == LVM_TE_LOW_MIPS))
+ {
+ CS_Params.SpeakerType = LVCS_EX_HEADPHONES;
+ }
+ else
+ {
+ CS_Params.SpeakerType = LVCS_HEADPHONES;
+ }
+
+#ifdef SUPPORT_MC
+ /* Concert sound module processes only the left and right channels
+ * data. So the Source Format is set to LVCS_STEREO for multichannel
+ * input also.
+ */
+ if (LocalParams.SourceFormat == LVM_STEREO ||
+ LocalParams.SourceFormat == LVM_MULTICHANNEL)
+#else
+ if (LocalParams.SourceFormat == LVM_STEREO) /* Mono format not supported */
+#endif
+ {
+ CS_Params.SourceFormat = LVCS_STEREO;
+ }
+ else
+ {
+ CS_Params.SourceFormat = LVCS_MONOINSTEREO; /* Force to Mono-in-Stereo mode */
+ }
+ CS_Params.SampleRate = LocalParams.SampleRate;
+ CS_Params.ReverbLevel = LocalParams.VirtualizerReverbLevel;
+ CS_Params.EffectLevel = LocalParams.CS_EffectLevel;
+#ifdef SUPPORT_MC
+ CS_Params.NrChannels = LocalParams.NrChannels;
+#endif
+
+ /*
+ * Set the control flag
+ */
+ if (((LVM_Mode_en)LocalParams.OperatingMode == LVM_MODE_ON) &&
+ ((LVCS_Modes_en)LocalParams.VirtualizerOperatingMode != LVCS_OFF))
+ {
+ pInstance->CS_Active = LVM_TRUE;
+ }
+ else
+ {
+ CS_Params.OperatingMode = LVCS_OFF;
+ }
+
+ CS_Params.CompressorMode=CompressorMode;
+
+ /*
+ * Make the changes
+ */
+ CS_Status = LVCS_Control(hCSInstance,
+ &CS_Params);
+
+ /*
+ * Quit if the changes were not accepted
+ */
+ if (CS_Status != LVCS_SUCCESS)
+ {
+ return((LVM_ReturnStatus_en)CS_Status);
+ }
+
+ }
+
+ /*
+ * Update the Power Spectrum Analyser
+ */
+ {
+ LVPSA_RETURN PSA_Status;
+ LVPSA_ControlParams_t PSA_Params;
+ pLVPSA_Handle_t *hPSAInstance = (pLVPSA_Handle_t *)pInstance->hPSAInstance;
+
+ /*
+ * Set the new parameters
+ */
+ PSA_Params.Fs = LocalParams.SampleRate;
+ PSA_Params.LevelDetectionSpeed = (LVPSA_LevelDetectSpeed_en)LocalParams.PSA_PeakDecayRate;
+
+ /*
+ * Make the changes
+ */
+ if(pInstance->InstParams.PSA_Included==LVM_PSA_ON)
+ {
+ PSA_Status = LVPSA_Control(hPSAInstance,
+ &PSA_Params);
+
+ if (PSA_Status != LVPSA_OK)
+ {
+ return((LVM_ReturnStatus_en)PSA_Status);
+ }
+
+ /*
+ * Apply new settings
+ */
+ PSA_Status = LVPSA_ApplyNewSettings ((LVPSA_InstancePr_t*)hPSAInstance);
+ if(PSA_Status != LVPSA_OK)
+ {
+ return((LVM_ReturnStatus_en)PSA_Status);
+ }
+ }
+ }
+
+ /*
+ * Update the parameters and clear the flag
+ */
+ pInstance->NoSmoothVolume = LVM_FALSE;
+ pInstance->Params = LocalParams;
+
+ return(LVM_SUCCESS);
+}
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVM_SetHeadroomParams */
+/* */
+/* DESCRIPTION: */
+/* This function is used to set the automatiuc headroom management parameters. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance Handle */
+/* pHeadroomParams Pointer to headroom parameter structure */
+/* */
+/* RETURNS: */
+/* LVM_Success Succeeded */
+/* */
+/* NOTES: */
+/* 1. This function may be interrupted by the LVM_Process function */
+/* */
+/****************************************************************************************/
+
+LVM_ReturnStatus_en LVM_SetHeadroomParams(LVM_Handle_t hInstance,
+ LVM_HeadroomParams_t *pHeadroomParams)
+{
+ LVM_Instance_t *pInstance =(LVM_Instance_t *)hInstance;
+ LVM_UINT16 ii, NBands;
+
+ /* Check for NULL pointers */
+ if ((hInstance == LVM_NULL) || (pHeadroomParams == LVM_NULL))
+ {
+ return (LVM_NULLADDRESS);
+ }
+ if ((pHeadroomParams->NHeadroomBands != 0) && (pHeadroomParams->pHeadroomDefinition == LVM_NULL))
+ {
+ return (LVM_NULLADDRESS);
+ }
+
+ /* Consider only the LVM_HEADROOM_MAX_NBANDS first bands*/
+ if (pHeadroomParams->NHeadroomBands > LVM_HEADROOM_MAX_NBANDS)
+ {
+ NBands = LVM_HEADROOM_MAX_NBANDS;
+ }
+ else
+ {
+ NBands = pHeadroomParams->NHeadroomBands;
+ }
+ pInstance->NewHeadroomParams.NHeadroomBands = NBands;
+
+ /* Copy settings in memory */
+ for(ii = 0; ii < NBands; ii++)
+ {
+ pInstance->pHeadroom_BandDefs[ii] = pHeadroomParams->pHeadroomDefinition[ii];
+ }
+
+ pInstance->NewHeadroomParams.pHeadroomDefinition = pInstance->pHeadroom_BandDefs;
+ pInstance->NewHeadroomParams.Headroom_OperatingMode = pHeadroomParams->Headroom_OperatingMode;
+ pInstance->ControlPending = LVM_TRUE;
+
+ return(LVM_SUCCESS);
+}
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVM_GetHeadroomParams */
+/* */
+/* DESCRIPTION: */
+/* This function is used to get the automatic headroom management parameters. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance Handle */
+/* pHeadroomParams Pointer to headroom parameter structure (output) */
+/* */
+/* RETURNS: */
+/* LVM_SUCCESS Succeeded */
+/* LVM_NULLADDRESS When hInstance or pHeadroomParams are NULL */
+/* */
+/* NOTES: */
+/* 1. This function may be interrupted by the LVM_Process function */
+/* */
+/****************************************************************************************/
+
+LVM_ReturnStatus_en LVM_GetHeadroomParams(LVM_Handle_t hInstance,
+ LVM_HeadroomParams_t *pHeadroomParams)
+{
+ LVM_Instance_t *pInstance =(LVM_Instance_t *)hInstance;
+ LVM_UINT16 ii;
+
+ /* Check for NULL pointers */
+ if ((hInstance == LVM_NULL) || (pHeadroomParams == LVM_NULL))
+ {
+ return (LVM_NULLADDRESS);
+ }
+
+ pHeadroomParams->NHeadroomBands = pInstance->NewHeadroomParams.NHeadroomBands;
+
+ /* Copy settings in memory */
+ for(ii = 0; ii < pInstance->NewHeadroomParams.NHeadroomBands; ii++)
+ {
+ pInstance->pHeadroom_UserDefs[ii] = pInstance->pHeadroom_BandDefs[ii];
+ }
+
+ pHeadroomParams->pHeadroomDefinition = pInstance->pHeadroom_UserDefs;
+ pHeadroomParams->Headroom_OperatingMode = pInstance->NewHeadroomParams.Headroom_OperatingMode;
+ return(LVM_SUCCESS);
+}
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVM_AlgoCallBack */
+/* */
+/* DESCRIPTION: */
+/* This is the callback function of the algorithm. */
+/* */
+/* PARAMETERS: */
+/* pBundleHandle Pointer to the Instance Handle */
+/* pData Pointer to the data */
+/* callbackId ID of the callback */
+/* */
+/* NOTES: */
+/* 1. This function may be interrupted by the LVM_Process function */
+/* */
+/****************************************************************************************/
+LVM_INT32 LVM_AlgoCallBack( void *pBundleHandle,
+ void *pData,
+ LVM_INT16 callbackId)
+{
+ LVM_Instance_t *pInstance =(LVM_Instance_t *)pBundleHandle;
+
+ (void) pData;
+
+ switch(callbackId & 0xFF00){
+ case ALGORITHM_CS_ID:
+ switch(callbackId & 0x00FF)
+ {
+ case LVCS_EVENT_ALGOFF:
+ pInstance->CS_Active = LVM_FALSE;
+ break;
+ default:
+ break;
+ }
+ break;
+ case ALGORITHM_EQNB_ID:
+ switch(callbackId & 0x00FF)
+ {
+ case LVEQNB_EVENT_ALGOFF:
+ pInstance->EQNB_Active = LVM_FALSE;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVM_VCCallBack */
+/* */
+/* DESCRIPTION: */
+/* This is the callback function of the Volume control. */
+/* */
+/* PARAMETERS: */
+/* pBundleHandle Pointer to the Instance Handle */
+/* pGeneralPurpose Pointer to the data */
+/* CallBackParam ID of the callback */
+/* */
+/* NOTES: */
+/* 1. This function may be interrupted by the LVM_Process function */
+/* */
+/****************************************************************************************/
+LVM_INT32 LVM_VCCallBack(void* pBundleHandle,
+ void* pGeneralPurpose,
+ short CallBackParam)
+{
+ LVM_Instance_t *pInstance =(LVM_Instance_t *)pBundleHandle;
+ LVM_FLOAT Target;
+
+ (void) pGeneralPurpose;
+ (void) CallBackParam;
+
+ /* When volume mixer has reached 0 dB target then stop it to avoid
+ unnecessary processing. */
+ Target = LVC_Mixer_GetTarget(&pInstance->VC_Volume.MixerStream[0]);
+ if(Target == 1.0f)
+ {
+ pInstance->VC_Active = LVM_FALSE;
+ }
+ return 1;
+}
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Init.c b/media/libeffects/lvm/lib/Bundle/src/LVM_Init.c
deleted file mode 100644
index c57498e..0000000
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Init.c
+++ /dev/null
@@ -1,1163 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/************************************************************************************/
-/* */
-/* Includes */
-/* */
-/************************************************************************************/
-
-#include "LVM_Private.h"
-#include "LVM_Tables.h"
-#include "VectorArithmetic.h"
-#include "InstAlloc.h"
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVM_GetMemoryTable */
-/* */
-/* DESCRIPTION: */
-/* This function is used for memory allocation and free. It can be called in */
-/* two ways: */
-/* */
-/* hInstance = NULL Returns the memory requirements */
-/* hInstance = Instance handle Returns the memory requirements and */
-/* allocated base addresses for the instance */
-/* */
-/* When this function is called for memory allocation (hInstance=NULL) the memory */
-/* base address pointers are NULL on return. */
-/* */
-/* When the function is called for free (hInstance = Instance Handle) the memory */
-/* table returns the allocated memory and base addresses used during initialisation. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance Handle */
-/* pMemoryTable Pointer to an empty memory definition table */
-/* pCapabilities Pointer to the default capabilities */
-/* */
-/* RETURNS: */
-/* LVM_SUCCESS Succeeded */
-/* LVM_NULLADDRESS When one of pMemoryTable or pInstParams is NULL */
-/* LVM_OUTOFRANGE When any of the Instance parameters are out of range */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVM_Process function */
-/* 2. The scratch memory is the largest required by any of the sub-modules plus any */
-/* additional scratch requirements of the bundle */
-/* */
-/****************************************************************************************/
-
-/*
- * 4 Types of Memory Regions of LVM
- * TODO: Allocate on the fly.
- * i) LVM_MEMREGION_PERSISTENT_SLOW_DATA - For Instance Handles
- * ii) LVM_MEMREGION_PERSISTENT_FAST_DATA - Persistent Buffers
- * iii) LVM_MEMREGION_PERSISTENT_FAST_COEF - For Holding Structure values
- * iv) LVM_MEMREGION_TEMPORARY_FAST - For Holding Structure values
- *
- * LVM_MEMREGION_PERSISTENT_SLOW_DATA:
- * Total Memory size:
- * sizeof(LVM_Instance_t) + \
- * sizeof(LVM_Buffer_t) + \
- * sizeof(LVPSA_InstancePr_t) + \
- * sizeof(LVM_Buffer_t) - needed if buffer mode is LVM_MANAGED_BUFFER
- *
- * LVM_MEMREGION_PERSISTENT_FAST_DATA:
- * Total Memory size:
- * sizeof(LVM_TE_Data_t) + \
- * 2 * pInstParams->EQNB_NumBands * sizeof(LVM_EQNB_BandDef_t) + \
- * sizeof(LVCS_Data_t) + \
- * sizeof(LVDBE_Data_FLOAT_t) + \
- * sizeof(Biquad_2I_Order2_FLOAT_Taps_t) + \
- * sizeof(Biquad_2I_Order2_FLOAT_Taps_t) + \
- * pInstParams->EQNB_NumBands * sizeof(Biquad_2I_Order2_FLOAT_Taps_t) + \
- * pInstParams->EQNB_NumBands * sizeof(LVEQNB_BandDef_t) + \
- * pInstParams->EQNB_NumBands * sizeof(LVEQNB_BiquadType_en) + \
- * 2 * LVM_HEADROOM_MAX_NBANDS * sizeof(LVM_HeadroomBandDef_t) + \
- * PSA_InitParams.nBands * sizeof(Biquad_1I_Order2_Taps_t) + \
- * PSA_InitParams.nBands * sizeof(QPD_Taps_t)
- *
- * LVM_MEMREGION_PERSISTENT_FAST_COEF:
- * Total Memory size:
- * sizeof(LVM_TE_Coefs_t) + \
- * sizeof(LVCS_Coefficient_t) + \
- * sizeof(LVDBE_Coef_FLOAT_t) + \
- * sizeof(Biquad_FLOAT_Instance_t) + \
- * sizeof(Biquad_FLOAT_Instance_t) + \
- * pInstParams->EQNB_NumBands * sizeof(Biquad_FLOAT_Instance_t) + \
- * PSA_InitParams.nBands * sizeof(Biquad_Instance_t) + \
- * PSA_InitParams.nBands * sizeof(QPD_State_t)
- *
- * LVM_MEMREGION_TEMPORARY_FAST (Scratch):
- * Total Memory Size:
- * BundleScratchSize + \
- * MAX_INTERNAL_BLOCKSIZE * sizeof(LVM_FLOAT) + \
- * MaxScratchOf (CS, EQNB, DBE, PSA)
- *
- * a)BundleScratchSize:
- * 3 * LVM_MAX_CHANNELS \
- * * (MIN_INTERNAL_BLOCKSIZE + InternalBlockSize) * sizeof(LVM_FLOAT)
- * This Memory is allocated only when Buffer mode is LVM_MANAGED_BUFFER.
- * b)MaxScratchOf (CS, EQNB, DBE, PSA)
- * This Memory is needed for scratch usage for CS, EQNB, DBE, PSA.
- * CS = (LVCS_SCRATCHBUFFERS * sizeof(LVM_FLOAT)
- * * pCapabilities->MaxBlockSize)
- * EQNB = (LVEQNB_SCRATCHBUFFERS * sizeof(LVM_FLOAT)
- * * pCapabilities->MaxBlockSize)
- * DBE = (LVDBE_SCRATCHBUFFERS_INPLACE*sizeof(LVM_FLOAT)
- * * pCapabilities->MaxBlockSize)
- * PSA = (2 * pInitParams->MaxInputBlockSize * sizeof(LVM_FLOAT))
- * one MaxInputBlockSize for input and another for filter output
- * c)MAX_INTERNAL_BLOCKSIZE
- * This Memory is needed for PSAInput - Temp memory to store output
- * from McToMono block and given as input to PSA block
- */
-
-LVM_ReturnStatus_en LVM_GetMemoryTable(LVM_Handle_t hInstance,
- LVM_MemTab_t *pMemoryTable,
- LVM_InstParams_t *pInstParams)
-{
-
- LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
- LVM_UINT32 AlgScratchSize;
- LVM_UINT32 BundleScratchSize;
- LVM_UINT16 InternalBlockSize;
- INST_ALLOC AllocMem[LVM_NR_MEMORY_REGIONS];
- LVM_INT16 i;
-
-
- /*
- * Check parameters
- */
- if(pMemoryTable == LVM_NULL)
- {
- return LVM_NULLADDRESS;
- }
-
-
- /*
- * Return memory table if the instance has already been created
- */
- if (hInstance != LVM_NULL)
- {
- /* Read back memory allocation table */
- *pMemoryTable = pInstance->MemoryTable;
- return(LVM_SUCCESS);
- }
-
- if(pInstParams == LVM_NULL)
- {
- return LVM_NULLADDRESS;
- }
-
- /*
- * Power Spectrum Analyser
- */
- if(pInstParams->PSA_Included > LVM_PSA_ON)
- {
- return (LVM_OUTOFRANGE);
- }
-
- /*
- * Check the instance parameters
- */
- if( (pInstParams->BufferMode != LVM_MANAGED_BUFFERS) && (pInstParams->BufferMode != LVM_UNMANAGED_BUFFERS) )
- {
- return (LVM_OUTOFRANGE);
- }
-
- /* N-Band Equalizer */
- if( pInstParams->EQNB_NumBands > 32 )
- {
- return (LVM_OUTOFRANGE);
- }
-
- if(pInstParams->BufferMode == LVM_MANAGED_BUFFERS)
- {
- if( (pInstParams->MaxBlockSize < LVM_MIN_MAXBLOCKSIZE ) || (pInstParams->MaxBlockSize > LVM_MANAGED_MAX_MAXBLOCKSIZE ) )
- {
- return (LVM_OUTOFRANGE);
- }
- }
- else
- {
- if( (pInstParams->MaxBlockSize < LVM_MIN_MAXBLOCKSIZE ) || (pInstParams->MaxBlockSize > LVM_UNMANAGED_MAX_MAXBLOCKSIZE) )
- {
- return (LVM_OUTOFRANGE);
- }
- }
-
- /*
- * Initialise the AllocMem structures
- */
- for (i=0; i<LVM_NR_MEMORY_REGIONS; i++)
- {
- InstAlloc_Init(&AllocMem[i], LVM_NULL);
- }
- InternalBlockSize = (LVM_UINT16)((pInstParams->MaxBlockSize) & MIN_INTERNAL_BLOCKMASK); /* Force to a multiple of MIN_INTERNAL_BLOCKSIZE */
-
- if (InternalBlockSize < MIN_INTERNAL_BLOCKSIZE)
- {
- InternalBlockSize = MIN_INTERNAL_BLOCKSIZE;
- }
-
- /* Maximum Internal Black Size should not be more than MAX_INTERNAL_BLOCKSIZE*/
- if(InternalBlockSize > MAX_INTERNAL_BLOCKSIZE)
- {
- InternalBlockSize = MAX_INTERNAL_BLOCKSIZE;
- }
-
- /*
- * Bundle requirements
- */
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_SLOW_DATA],
- sizeof(LVM_Instance_t));
-
-
- /*
- * Set the algorithm and bundle scratch requirements
- */
- AlgScratchSize = 0;
- if (pInstParams->BufferMode == LVM_MANAGED_BUFFERS)
- {
-#ifdef BUILD_FLOAT
- BundleScratchSize = 3 * LVM_MAX_CHANNELS \
- * (MIN_INTERNAL_BLOCKSIZE + InternalBlockSize) \
- * sizeof(LVM_FLOAT);
-#else
- BundleScratchSize = 6 * (MIN_INTERNAL_BLOCKSIZE + InternalBlockSize) * sizeof(LVM_INT16);
-#endif
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST], /* Scratch buffer */
- BundleScratchSize);
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_SLOW_DATA],
- sizeof(LVM_Buffer_t));
- }
-
- /*
- * Treble Enhancement requirements
- */
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- sizeof(LVM_TE_Data_t));
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
- sizeof(LVM_TE_Coefs_t));
-
- /*
- * N-Band Equalizer requirements
- */
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA], /* Local storage */
- (pInstParams->EQNB_NumBands * sizeof(LVM_EQNB_BandDef_t)));
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA], /* User storage */
- (pInstParams->EQNB_NumBands * sizeof(LVM_EQNB_BandDef_t)));
-
- /*
- * Concert Sound requirements
- */
- {
- LVCS_MemTab_t CS_MemTab;
- LVCS_Capabilities_t CS_Capabilities;
-
- /*
- * Set the capabilities
- */
- CS_Capabilities.MaxBlockSize = InternalBlockSize;
-
- /*
- * Get the memory requirements
- */
- LVCS_Memory(LVM_NULL,
- &CS_MemTab,
- &CS_Capabilities);
-
- /*
- * Update the memory allocation structures
- */
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- CS_MemTab.Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].Size);
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
- CS_MemTab.Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].Size);
- if (CS_MemTab.Region[LVM_MEMREGION_TEMPORARY_FAST].Size > AlgScratchSize) AlgScratchSize = CS_MemTab.Region[LVM_MEMREGION_TEMPORARY_FAST].Size;
-
- }
-
-
- /*
- * Dynamic Bass Enhancement requirements
- */
- {
- LVDBE_MemTab_t DBE_MemTab;
- LVDBE_Capabilities_t DBE_Capabilities;
-
- /*
- * Set the capabilities
- */
-#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
- DBE_Capabilities.SampleRate = LVDBE_CAP_FS_8000 | LVDBE_CAP_FS_11025 |
- LVDBE_CAP_FS_12000 | LVDBE_CAP_FS_16000 |
- LVDBE_CAP_FS_22050 | LVDBE_CAP_FS_24000 |
- LVDBE_CAP_FS_32000 | LVDBE_CAP_FS_44100 |
- LVDBE_CAP_FS_48000 | LVDBE_CAP_FS_88200 |
- LVDBE_CAP_FS_96000 | LVDBE_CAP_FS_176400 |
- LVDBE_CAP_FS_192000;
-#else
- DBE_Capabilities.SampleRate = LVDBE_CAP_FS_8000 | LVDBE_CAP_FS_11025 | LVDBE_CAP_FS_12000 | LVDBE_CAP_FS_16000 | LVDBE_CAP_FS_22050 | LVDBE_CAP_FS_24000 | LVDBE_CAP_FS_32000 | LVDBE_CAP_FS_44100 | LVDBE_CAP_FS_48000;
-#endif
- DBE_Capabilities.CentreFrequency = LVDBE_CAP_CENTRE_55Hz | LVDBE_CAP_CENTRE_55Hz | LVDBE_CAP_CENTRE_66Hz | LVDBE_CAP_CENTRE_78Hz | LVDBE_CAP_CENTRE_90Hz;
- DBE_Capabilities.MaxBlockSize = InternalBlockSize;
-
- /*
- * Get the memory requirements
- */
- LVDBE_Memory(LVM_NULL,
- &DBE_MemTab,
-
- &DBE_Capabilities);
- /*
- * Update the bundle table
- */
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- DBE_MemTab.Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].Size);
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
- DBE_MemTab.Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].Size);
- if (DBE_MemTab.Region[LVM_MEMREGION_TEMPORARY_FAST].Size > AlgScratchSize) AlgScratchSize = DBE_MemTab.Region[LVM_MEMREGION_TEMPORARY_FAST].Size;
-
- }
-
-
- /*
- * N-Band equaliser requirements
- */
- {
- LVEQNB_MemTab_t EQNB_MemTab; /* For N-Band Equaliser */
- LVEQNB_Capabilities_t EQNB_Capabilities;
-
- /*
- * Set the capabilities
- */
-#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
- EQNB_Capabilities.SampleRate = LVEQNB_CAP_FS_8000 | LVEQNB_CAP_FS_11025 |
- LVEQNB_CAP_FS_12000 | LVEQNB_CAP_FS_16000 |
- LVEQNB_CAP_FS_22050 | LVEQNB_CAP_FS_24000 |
- LVEQNB_CAP_FS_32000 | LVEQNB_CAP_FS_44100 |
- LVEQNB_CAP_FS_48000 | LVEQNB_CAP_FS_88200 |
- LVEQNB_CAP_FS_96000 | LVEQNB_CAP_FS_176400 |
- LVEQNB_CAP_FS_192000;
-#else
- EQNB_Capabilities.SampleRate = LVEQNB_CAP_FS_8000 | LVEQNB_CAP_FS_11025 | LVEQNB_CAP_FS_12000 | LVEQNB_CAP_FS_16000 | LVEQNB_CAP_FS_22050 | LVEQNB_CAP_FS_24000 | LVEQNB_CAP_FS_32000 | LVEQNB_CAP_FS_44100 | LVEQNB_CAP_FS_48000;
-#endif
- EQNB_Capabilities.SourceFormat = LVEQNB_CAP_STEREO | LVEQNB_CAP_MONOINSTEREO;
- EQNB_Capabilities.MaxBlockSize = InternalBlockSize;
- EQNB_Capabilities.MaxBands = pInstParams->EQNB_NumBands;
-
- /*
- * Get the memory requirements
- */
- LVEQNB_Memory(LVM_NULL,
- &EQNB_MemTab,
- &EQNB_Capabilities);
-
- /*
- * Update the bundle table
- */
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- EQNB_MemTab.Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].Size);
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
- EQNB_MemTab.Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].Size);
- if (EQNB_MemTab.Region[LVM_MEMREGION_TEMPORARY_FAST].Size > AlgScratchSize) AlgScratchSize = EQNB_MemTab.Region[LVM_MEMREGION_TEMPORARY_FAST].Size;
-
- }
-
- /*
- * Headroom management memory allocation
- */
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- (LVM_HEADROOM_MAX_NBANDS * sizeof(LVM_HeadroomBandDef_t)));
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- (LVM_HEADROOM_MAX_NBANDS * sizeof(LVM_HeadroomBandDef_t)));
-
-
- /*
- * Spectrum Analyzer memory requirements
- */
- {
- pLVPSA_Handle_t hPSAInst = LVM_NULL;
- LVPSA_MemTab_t PSA_MemTab;
- LVPSA_InitParams_t PSA_InitParams;
- LVPSA_FilterParam_t FiltersParams[9];
- LVPSA_RETURN PSA_Status;
-
- if(pInstParams->PSA_Included == LVM_PSA_ON)
- {
- PSA_InitParams.SpectralDataBufferDuration = (LVM_UINT16) 500;
- PSA_InitParams.MaxInputBlockSize = (LVM_UINT16) 1000;
- PSA_InitParams.nBands = (LVM_UINT16) 9;
-
- PSA_InitParams.pFiltersParams = &FiltersParams[0];
- for(i = 0; i < PSA_InitParams.nBands; i++)
- {
- FiltersParams[i].CenterFrequency = (LVM_UINT16) 1000;
- FiltersParams[i].QFactor = (LVM_UINT16) 25;
- FiltersParams[i].PostGain = (LVM_INT16) 0;
- }
-
- /*
- * Get the memory requirements
- */
- PSA_Status = LVPSA_Memory (hPSAInst,
- &PSA_MemTab,
- &PSA_InitParams);
-
- if (PSA_Status != LVPSA_OK)
- {
- return((LVM_ReturnStatus_en) LVM_ALGORITHMPSA);
- }
-
- /*
- * Update the bundle table
- */
- /* Slow Data */
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_SLOW_DATA],
- PSA_MemTab.Region[LVM_PERSISTENT_SLOW_DATA].Size);
-
- /* Fast Data */
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- PSA_MemTab.Region[LVM_PERSISTENT_FAST_DATA].Size);
-
- /* Fast Coef */
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
- PSA_MemTab.Region[LVM_PERSISTENT_FAST_COEF].Size);
-
- /* Fast Temporary */
-#ifdef BUILD_FLOAT
- InstAlloc_AddMember(&AllocMem[LVM_TEMPORARY_FAST],
- MAX_INTERNAL_BLOCKSIZE * sizeof(LVM_FLOAT));
-#else
- InstAlloc_AddMember(&AllocMem[LVM_TEMPORARY_FAST],
- MAX_INTERNAL_BLOCKSIZE * sizeof(LVM_INT16));
-#endif
-
- if (PSA_MemTab.Region[LVM_TEMPORARY_FAST].Size > AlgScratchSize)
- {
- AlgScratchSize = PSA_MemTab.Region[LVM_TEMPORARY_FAST].Size;
- }
- }
- }
-
- /*
- * Return the memory table
- */
- pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_SLOW_DATA].Size = InstAlloc_GetTotal(&AllocMem[LVM_MEMREGION_PERSISTENT_SLOW_DATA]);
- pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_SLOW_DATA].Type = LVM_PERSISTENT_SLOW_DATA;
- pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_SLOW_DATA].pBaseAddress = LVM_NULL;
-
- pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].Size = InstAlloc_GetTotal(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA]);
- pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].Type = LVM_PERSISTENT_FAST_DATA;
- pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress = LVM_NULL;
- if (pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].Size < 4)
- {
- pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].Size = 0;
- }
-
- pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].Size = InstAlloc_GetTotal(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF]);
- pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].Type = LVM_PERSISTENT_FAST_COEF;
- pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress = LVM_NULL;
- if (pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].Size < 4)
- {
- pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].Size = 0;
- }
-
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST],
- AlgScratchSize);
- pMemoryTable->Region[LVM_MEMREGION_TEMPORARY_FAST].Size = InstAlloc_GetTotal(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST]);
- pMemoryTable->Region[LVM_MEMREGION_TEMPORARY_FAST].Type = LVM_TEMPORARY_FAST;
- pMemoryTable->Region[LVM_MEMREGION_TEMPORARY_FAST].pBaseAddress = LVM_NULL;
- if (pMemoryTable->Region[LVM_MEMREGION_TEMPORARY_FAST].Size < 4)
- {
- pMemoryTable->Region[LVM_MEMREGION_TEMPORARY_FAST].Size = 0;
- }
-
- return(LVM_SUCCESS);
-
-}
-
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVM_GetInstanceHandle */
-/* */
-/* DESCRIPTION: */
-/* This function is used to create a bundle instance. It returns the created instance */
-/* handle through phInstance. All parameters are set to their default, inactive state. */
-/* */
-/* PARAMETERS: */
-/* phInstance pointer to the instance handle */
-/* pMemoryTable Pointer to the memory definition table */
-/* pInstParams Pointer to the initialisation capabilities */
-/* */
-/* RETURNS: */
-/* LVM_SUCCESS Initialisation succeeded */
-/* LVM_OUTOFRANGE When any of the Instance parameters are out of range */
-/* LVM_NULLADDRESS When one of phInstance, pMemoryTable or pInstParams are NULL*/
-/* */
-/* NOTES: */
-/* 1. This function must not be interrupted by the LVM_Process function */
-/* */
-/****************************************************************************************/
-
-LVM_ReturnStatus_en LVM_GetInstanceHandle(LVM_Handle_t *phInstance,
- LVM_MemTab_t *pMemoryTable,
- LVM_InstParams_t *pInstParams)
-{
-
- LVM_ReturnStatus_en Status = LVM_SUCCESS;
- LVM_Instance_t *pInstance;
- INST_ALLOC AllocMem[LVM_NR_MEMORY_REGIONS];
- LVM_INT16 i;
- LVM_UINT16 InternalBlockSize;
- LVM_INT32 BundleScratchSize;
-
-
- /*
- * Check valid points have been given
- */
- if ((phInstance == LVM_NULL) || (pMemoryTable == LVM_NULL) || (pInstParams == LVM_NULL))
- {
- return (LVM_NULLADDRESS);
- }
-
- /*
- * Check the memory table for NULL pointers
- */
- for (i=0; i<LVM_NR_MEMORY_REGIONS; i++)
- {
- if ((pMemoryTable->Region[i].Size != 0) &&
- (pMemoryTable->Region[i].pBaseAddress==LVM_NULL))
- {
- return(LVM_NULLADDRESS);
- }
- }
-
- /*
- * Check the instance parameters
- */
- if( (pInstParams->BufferMode != LVM_MANAGED_BUFFERS) && (pInstParams->BufferMode != LVM_UNMANAGED_BUFFERS) )
- {
- return (LVM_OUTOFRANGE);
- }
-
- if( pInstParams->EQNB_NumBands > 32 )
- {
- return (LVM_OUTOFRANGE);
- }
-
- if(pInstParams->BufferMode == LVM_MANAGED_BUFFERS)
- {
- if( (pInstParams->MaxBlockSize < LVM_MIN_MAXBLOCKSIZE ) || (pInstParams->MaxBlockSize > LVM_MANAGED_MAX_MAXBLOCKSIZE ) )
- {
- return (LVM_OUTOFRANGE);
- }
- }
- else
- {
- if( (pInstParams->MaxBlockSize < LVM_MIN_MAXBLOCKSIZE ) || (pInstParams->MaxBlockSize > LVM_UNMANAGED_MAX_MAXBLOCKSIZE) )
- {
- return (LVM_OUTOFRANGE);
- }
- }
-
- if(pInstParams->PSA_Included > LVM_PSA_ON)
- {
- return (LVM_OUTOFRANGE);
- }
-
- /*
- * Initialise the AllocMem structures
- */
- for (i=0; i<LVM_NR_MEMORY_REGIONS; i++)
- {
- InstAlloc_Init(&AllocMem[i],
- pMemoryTable->Region[i].pBaseAddress);
- }
-
-
- /*
- * Set the instance handle
- */
- *phInstance = (LVM_Handle_t)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_SLOW_DATA],
- sizeof(LVM_Instance_t));
- pInstance =(LVM_Instance_t *)*phInstance;
-
-
- /*
- * Save the memory table, parameters and capabilities
- */
- pInstance->MemoryTable = *pMemoryTable;
- pInstance->InstParams = *pInstParams;
-
-
- /*
- * Set the bundle scratch memory and initialse the buffer management
- */
- InternalBlockSize = (LVM_UINT16)((pInstParams->MaxBlockSize) & MIN_INTERNAL_BLOCKMASK); /* Force to a multiple of MIN_INTERNAL_BLOCKSIZE */
- if (InternalBlockSize < MIN_INTERNAL_BLOCKSIZE)
- {
- InternalBlockSize = MIN_INTERNAL_BLOCKSIZE;
- }
-
- /* Maximum Internal Black Size should not be more than MAX_INTERNAL_BLOCKSIZE*/
- if(InternalBlockSize > MAX_INTERNAL_BLOCKSIZE)
- {
- InternalBlockSize = MAX_INTERNAL_BLOCKSIZE;
- }
- pInstance->InternalBlockSize = (LVM_INT16)InternalBlockSize;
-
-
- /*
- * Common settings for managed and unmanaged buffers
- */
- pInstance->SamplesToProcess = 0; /* No samples left to process */
- if (pInstParams->BufferMode == LVM_MANAGED_BUFFERS)
- {
- /*
- * Managed buffers required
- */
- pInstance->pBufferManagement = InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_SLOW_DATA],
- sizeof(LVM_Buffer_t));
-#ifdef BUILD_FLOAT
- BundleScratchSize = (LVM_INT32)
- (3 * LVM_MAX_CHANNELS \
- * (MIN_INTERNAL_BLOCKSIZE + InternalBlockSize) \
- * sizeof(LVM_FLOAT));
-#else
- BundleScratchSize = (LVM_INT32)(6 * (MIN_INTERNAL_BLOCKSIZE + InternalBlockSize) * sizeof(LVM_INT16));
-#endif
- pInstance->pBufferManagement->pScratch = InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST], /* Scratch 1 buffer */
- (LVM_UINT32)BundleScratchSize);
-#ifdef BUILD_FLOAT
- LoadConst_Float(0, /* Clear the input delay buffer */
- (LVM_FLOAT *)&pInstance->pBufferManagement->InDelayBuffer,
- (LVM_INT16)(LVM_MAX_CHANNELS * MIN_INTERNAL_BLOCKSIZE));
-#else
- LoadConst_16(0, /* Clear the input delay buffer */
- (LVM_INT16 *)&pInstance->pBufferManagement->InDelayBuffer,
- (LVM_INT16)(2 * MIN_INTERNAL_BLOCKSIZE));
-#endif
- pInstance->pBufferManagement->InDelaySamples = MIN_INTERNAL_BLOCKSIZE; /* Set the number of delay samples */
- pInstance->pBufferManagement->OutDelaySamples = 0; /* No samples in the output buffer */
- pInstance->pBufferManagement->BufferState = LVM_FIRSTCALL; /* Set the state ready for the first call */
- }
-
-
- /*
- * Set default parameters
- */
- pInstance->Params.OperatingMode = LVM_MODE_OFF;
- pInstance->Params.SampleRate = LVM_FS_8000;
- pInstance->Params.SourceFormat = LVM_MONO;
- pInstance->Params.SpeakerType = LVM_HEADPHONES;
- pInstance->Params.VC_EffectLevel = 0;
- pInstance->Params.VC_Balance = 0;
-
- /*
- * Set callback
- */
- pInstance->CallBack = LVM_AlgoCallBack;
-
-
- /*
- * DC removal filter
- */
-#ifdef SUPPORT_MC
- DC_Mc_D16_TRC_WRA_01_Init(&pInstance->DC_RemovalInstance);
-#else
- DC_2I_D16_TRC_WRA_01_Init(&pInstance->DC_RemovalInstance);
-#endif
-
- /*
- * Treble Enhancement
- */
- pInstance->pTE_Taps = (LVM_TE_Data_t *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- sizeof(LVM_TE_Data_t));
-
- pInstance->pTE_State = (LVM_TE_Coefs_t *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
- sizeof(LVM_TE_Coefs_t));
- pInstance->Params.TE_OperatingMode = LVM_TE_OFF;
- pInstance->Params.TE_EffectLevel = 0;
- pInstance->TE_Active = LVM_FALSE;
-
-
- /*
- * Set the volume control and initialise Current to Target
- */
- pInstance->VC_Volume.MixerStream[0].CallbackParam = 0;
- pInstance->VC_Volume.MixerStream[0].CallbackSet = 0;
- pInstance->VC_Volume.MixerStream[0].pCallbackHandle = pInstance;
- pInstance->VC_Volume.MixerStream[0].pCallBack = LVM_VCCallBack;
-
- /* In managed buffering, start with low signal level as delay in buffer management causes a click*/
- if (pInstParams->BufferMode == LVM_MANAGED_BUFFERS)
- {
-#ifdef BUILD_FLOAT
- LVC_Mixer_Init(&pInstance->VC_Volume.MixerStream[0], 0, 0);
-#else
- LVC_Mixer_Init(&pInstance->VC_Volume.MixerStream[0],0,0);
-#endif
- }
- else
- {
-#ifdef BUILD_FLOAT
- LVC_Mixer_Init(&pInstance->VC_Volume.MixerStream[0], LVM_MAXFLOAT, LVM_MAXFLOAT);
-#else
- LVC_Mixer_Init(&pInstance->VC_Volume.MixerStream[0],LVM_MAXINT_16,LVM_MAXINT_16);
-#endif
- }
-
-#ifdef BUILD_FLOAT
- LVC_Mixer_SetTimeConstant(&pInstance->VC_Volume.MixerStream[0],0,LVM_FS_8000,2);
-#else
- LVC_Mixer_SetTimeConstant(&pInstance->VC_Volume.MixerStream[0], 0, LVM_FS_8000, 2);
-#endif
-
- pInstance->VC_VolumedB = 0;
- pInstance->VC_AVLFixedVolume = 0;
- pInstance->VC_Active = LVM_FALSE;
-
- pInstance->VC_BalanceMix.MixerStream[0].CallbackParam = 0;
- pInstance->VC_BalanceMix.MixerStream[0].CallbackSet = 0;
- pInstance->VC_BalanceMix.MixerStream[0].pCallbackHandle = pInstance;
- pInstance->VC_BalanceMix.MixerStream[0].pCallBack = LVM_VCCallBack;
-#ifdef BUILD_FLOAT
- LVC_Mixer_Init(&pInstance->VC_BalanceMix.MixerStream[0], LVM_MAXFLOAT, LVM_MAXFLOAT);
-#else
- LVC_Mixer_Init(&pInstance->VC_BalanceMix.MixerStream[0],LVM_MAXINT_16,LVM_MAXINT_16);
-#endif
- LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[0],LVM_VC_MIXER_TIME,LVM_FS_8000,2);
-
- pInstance->VC_BalanceMix.MixerStream[1].CallbackParam = 0;
- pInstance->VC_BalanceMix.MixerStream[1].CallbackSet = 0;
- pInstance->VC_BalanceMix.MixerStream[1].pCallbackHandle = pInstance;
- pInstance->VC_BalanceMix.MixerStream[1].pCallBack = LVM_VCCallBack;
-#ifdef BUILD_FLOAT
- LVC_Mixer_Init(&pInstance->VC_BalanceMix.MixerStream[1], LVM_MAXFLOAT, LVM_MAXFLOAT);
-#else
- LVC_Mixer_Init(&pInstance->VC_BalanceMix.MixerStream[1],LVM_MAXINT_16,LVM_MAXINT_16);
-#endif
- LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[1],LVM_VC_MIXER_TIME,LVM_FS_8000,2);
-
- /*
- * Set the default EQNB pre-gain and pointer to the band definitions
- */
- pInstance->pEQNB_BandDefs = InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- (pInstParams->EQNB_NumBands * sizeof(LVM_EQNB_BandDef_t)));
- pInstance->pEQNB_UserDefs = InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- (pInstParams->EQNB_NumBands * sizeof(LVM_EQNB_BandDef_t)));
-
-
- /*
- * Initialise the Concert Sound module
- */
- {
- LVCS_Handle_t hCSInstance; /* Instance handle */
- LVCS_MemTab_t CS_MemTab; /* Memory table */
- LVCS_Capabilities_t CS_Capabilities; /* Initial capabilities */
- LVCS_ReturnStatus_en LVCS_Status; /* Function call status */
-
- /*
- * Set default parameters
- */
- pInstance->Params.VirtualizerReverbLevel = 100;
- pInstance->Params.VirtualizerType = LVM_CONCERTSOUND;
- pInstance->Params.VirtualizerOperatingMode = LVM_MODE_OFF;
- pInstance->CS_Active = LVM_FALSE;
-
- /*
- * Set the initialisation capabilities
- */
- CS_Capabilities.MaxBlockSize = (LVM_UINT16)InternalBlockSize;
- CS_Capabilities.CallBack = pInstance->CallBack;
- CS_Capabilities.pBundleInstance = (void*)pInstance;
-
-
- /*
- * Get the memory requirements and then set the address pointers, forcing alignment
- */
- LVCS_Status = LVCS_Memory(LVM_NULL, /* Get the memory requirements */
- &CS_MemTab,
- &CS_Capabilities);
- CS_MemTab.Region[LVCS_MEMREGION_PERSISTENT_SLOW_DATA].pBaseAddress = &pInstance->CS_Instance;
- CS_MemTab.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- CS_MemTab.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].Size);
- CS_MemTab.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
- CS_MemTab.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].Size);
- CS_MemTab.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST],
- 0);
-
- /*
- * Initialise the Concert Sound instance and save the instance handle
- */
- hCSInstance = LVM_NULL; /* Set to NULL to return handle */
- LVCS_Status = LVCS_Init(&hCSInstance, /* Initiailse */
- &CS_MemTab,
- &CS_Capabilities);
- if (LVCS_Status != LVCS_SUCCESS) return((LVM_ReturnStatus_en)LVCS_Status);
- pInstance->hCSInstance = hCSInstance; /* Save the instance handle */
-
- }
-
- /*
- * Initialise the Bass Enhancement module
- */
- {
- LVDBE_Handle_t hDBEInstance; /* Instance handle */
- LVDBE_MemTab_t DBE_MemTab; /* Memory table */
- LVDBE_Capabilities_t DBE_Capabilities; /* Initial capabilities */
- LVDBE_ReturnStatus_en LVDBE_Status; /* Function call status */
-
-
- /*
- * Set the initialisation parameters
- */
- pInstance->Params.BE_OperatingMode = LVM_BE_OFF;
- pInstance->Params.BE_CentreFreq = LVM_BE_CENTRE_55Hz;
- pInstance->Params.BE_EffectLevel = 0;
- pInstance->Params.BE_HPF = LVM_BE_HPF_OFF;
-
- pInstance->DBE_Active = LVM_FALSE;
-
-
-
- /*
- * Set the initialisation capabilities
- */
-#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
- DBE_Capabilities.SampleRate = LVDBE_CAP_FS_8000 | LVDBE_CAP_FS_11025 |
- LVDBE_CAP_FS_12000 | LVDBE_CAP_FS_16000 |
- LVDBE_CAP_FS_22050 | LVDBE_CAP_FS_24000 |
- LVDBE_CAP_FS_32000 | LVDBE_CAP_FS_44100 |
- LVDBE_CAP_FS_48000 | LVDBE_CAP_FS_88200 |
- LVDBE_CAP_FS_96000 | LVDBE_CAP_FS_176400 |
- LVDBE_CAP_FS_192000;
-#else
- DBE_Capabilities.SampleRate = LVDBE_CAP_FS_8000 | LVDBE_CAP_FS_11025 | LVDBE_CAP_FS_12000 | LVDBE_CAP_FS_16000 | LVDBE_CAP_FS_22050 | LVDBE_CAP_FS_24000 | LVDBE_CAP_FS_32000 | LVDBE_CAP_FS_44100 | LVDBE_CAP_FS_48000;
-#endif
- DBE_Capabilities.CentreFrequency = LVDBE_CAP_CENTRE_55Hz | LVDBE_CAP_CENTRE_55Hz | LVDBE_CAP_CENTRE_66Hz | LVDBE_CAP_CENTRE_78Hz | LVDBE_CAP_CENTRE_90Hz;
- DBE_Capabilities.MaxBlockSize = (LVM_UINT16)InternalBlockSize;
-
-
- /*
- * Get the memory requirements and then set the address pointers
- */
- LVDBE_Status = LVDBE_Memory(LVM_NULL, /* Get the memory requirements */
- &DBE_MemTab,
- &DBE_Capabilities);
- DBE_MemTab.Region[LVDBE_MEMREGION_INSTANCE].pBaseAddress = &pInstance->DBE_Instance;
- DBE_MemTab.Region[LVDBE_MEMREGION_PERSISTENT_DATA].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- DBE_MemTab.Region[LVDBE_MEMREGION_PERSISTENT_DATA].Size);
- DBE_MemTab.Region[LVDBE_MEMREGION_PERSISTENT_COEF].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
- DBE_MemTab.Region[LVDBE_MEMREGION_PERSISTENT_COEF].Size);
- DBE_MemTab.Region[LVDBE_MEMREGION_SCRATCH].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST],
- 0);
-
-
- /*
- * Initialise the Dynamic Bass Enhancement instance and save the instance handle
- */
- hDBEInstance = LVM_NULL; /* Set to NULL to return handle */
- LVDBE_Status = LVDBE_Init(&hDBEInstance, /* Initiailse */
- &DBE_MemTab,
- &DBE_Capabilities);
- if (LVDBE_Status != LVDBE_SUCCESS) return((LVM_ReturnStatus_en)LVDBE_Status);
- pInstance->hDBEInstance = hDBEInstance; /* Save the instance handle */
- }
-
-
- /*
- * Initialise the N-Band Equaliser module
- */
- {
- LVEQNB_Handle_t hEQNBInstance; /* Instance handle */
- LVEQNB_MemTab_t EQNB_MemTab; /* Memory table */
- LVEQNB_Capabilities_t EQNB_Capabilities; /* Initial capabilities */
- LVEQNB_ReturnStatus_en LVEQNB_Status; /* Function call status */
-
-
- /*
- * Set the initialisation parameters
- */
- pInstance->Params.EQNB_OperatingMode = LVM_EQNB_OFF;
- pInstance->Params.EQNB_NBands = 0;
- pInstance->Params.pEQNB_BandDefinition = LVM_NULL;
- pInstance->EQNB_Active = LVM_FALSE;
-
-
- /*
- * Set the initialisation capabilities
- */
-#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
- EQNB_Capabilities.SampleRate = LVEQNB_CAP_FS_8000 | LVEQNB_CAP_FS_11025 |
- LVEQNB_CAP_FS_12000 | LVEQNB_CAP_FS_16000 |
- LVEQNB_CAP_FS_22050 | LVEQNB_CAP_FS_24000 |
- LVEQNB_CAP_FS_32000 | LVEQNB_CAP_FS_44100 |
- LVEQNB_CAP_FS_48000 | LVEQNB_CAP_FS_88200 |
- LVEQNB_CAP_FS_96000 | LVEQNB_CAP_FS_176400 |
- LVEQNB_CAP_FS_192000;
-#else
- EQNB_Capabilities.SampleRate = LVEQNB_CAP_FS_8000 | LVEQNB_CAP_FS_11025 | LVEQNB_CAP_FS_12000 | LVEQNB_CAP_FS_16000 | LVEQNB_CAP_FS_22050 | LVEQNB_CAP_FS_24000 | LVEQNB_CAP_FS_32000 | LVEQNB_CAP_FS_44100 | LVEQNB_CAP_FS_48000;
-#endif
- EQNB_Capabilities.MaxBlockSize = (LVM_UINT16)InternalBlockSize;
- EQNB_Capabilities.MaxBands = pInstParams->EQNB_NumBands;
- EQNB_Capabilities.SourceFormat = LVEQNB_CAP_STEREO | LVEQNB_CAP_MONOINSTEREO;
- EQNB_Capabilities.CallBack = pInstance->CallBack;
- EQNB_Capabilities.pBundleInstance = (void*)pInstance;
-
-
- /*
- * Get the memory requirements and then set the address pointers, forcing alignment
- */
- LVEQNB_Status = LVEQNB_Memory(LVM_NULL, /* Get the memory requirements */
- &EQNB_MemTab,
- &EQNB_Capabilities);
- EQNB_MemTab.Region[LVEQNB_MEMREGION_INSTANCE].pBaseAddress = &pInstance->EQNB_Instance;
- EQNB_MemTab.Region[LVEQNB_MEMREGION_PERSISTENT_DATA].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- EQNB_MemTab.Region[LVEQNB_MEMREGION_PERSISTENT_DATA].Size);
- EQNB_MemTab.Region[LVEQNB_MEMREGION_PERSISTENT_COEF].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
- EQNB_MemTab.Region[LVEQNB_MEMREGION_PERSISTENT_COEF].Size);
- EQNB_MemTab.Region[LVEQNB_MEMREGION_SCRATCH].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST],
- 0);
-
-
- /*
- * Initialise the Dynamic Bass Enhancement instance and save the instance handle
- */
- hEQNBInstance = LVM_NULL; /* Set to NULL to return handle */
- LVEQNB_Status = LVEQNB_Init(&hEQNBInstance, /* Initiailse */
- &EQNB_MemTab,
- &EQNB_Capabilities);
- if (LVEQNB_Status != LVEQNB_SUCCESS) return((LVM_ReturnStatus_en)LVEQNB_Status);
- pInstance->hEQNBInstance = hEQNBInstance; /* Save the instance handle */
- }
-
- /*
- * Headroom management memory allocation
- */
- {
- pInstance->pHeadroom_BandDefs = InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- (LVM_HEADROOM_MAX_NBANDS * sizeof(LVM_HeadroomBandDef_t)));
- pInstance->pHeadroom_UserDefs = InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- (LVM_HEADROOM_MAX_NBANDS * sizeof(LVM_HeadroomBandDef_t)));
-
- /* Headroom management parameters initialisation */
- pInstance->NewHeadroomParams.NHeadroomBands = 2;
- pInstance->NewHeadroomParams.pHeadroomDefinition = pInstance->pHeadroom_BandDefs;
- pInstance->NewHeadroomParams.pHeadroomDefinition[0].Limit_Low = 20;
- pInstance->NewHeadroomParams.pHeadroomDefinition[0].Limit_High = 4999;
- pInstance->NewHeadroomParams.pHeadroomDefinition[0].Headroom_Offset = 3;
- pInstance->NewHeadroomParams.pHeadroomDefinition[1].Limit_Low = 5000;
- pInstance->NewHeadroomParams.pHeadroomDefinition[1].Limit_High = 24000;
- pInstance->NewHeadroomParams.pHeadroomDefinition[1].Headroom_Offset = 4;
- pInstance->NewHeadroomParams.Headroom_OperatingMode = LVM_HEADROOM_ON;
-
- pInstance->Headroom =0;
- }
-
-
- /*
- * Initialise the PSA module
- */
- {
- pLVPSA_Handle_t hPSAInstance = LVM_NULL; /* Instance handle */
- LVPSA_MemTab_t PSA_MemTab;
- LVPSA_RETURN PSA_Status; /* Function call status */
- LVPSA_FilterParam_t FiltersParams[9];
-
- if(pInstParams->PSA_Included==LVM_PSA_ON)
- {
- pInstance->PSA_InitParams.SpectralDataBufferDuration = (LVM_UINT16) 500;
- pInstance->PSA_InitParams.MaxInputBlockSize = (LVM_UINT16) 2048;
- pInstance->PSA_InitParams.nBands = (LVM_UINT16) 9;
- pInstance->PSA_InitParams.pFiltersParams = &FiltersParams[0];
- for(i = 0; i < pInstance->PSA_InitParams.nBands; i++)
- {
- FiltersParams[i].CenterFrequency = (LVM_UINT16) 1000;
- FiltersParams[i].QFactor = (LVM_UINT16) 100;
- FiltersParams[i].PostGain = (LVM_INT16) 0;
- }
-
- /*Get the memory requirements and then set the address pointers*/
- PSA_Status = LVPSA_Memory (hPSAInstance,
- &PSA_MemTab,
- &pInstance->PSA_InitParams);
-
- if (PSA_Status != LVPSA_OK)
- {
- return((LVM_ReturnStatus_en) LVM_ALGORITHMPSA);
- }
-
- /* Slow Data */
- PSA_MemTab.Region[LVM_PERSISTENT_SLOW_DATA].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_SLOW_DATA],
- PSA_MemTab.Region[LVM_PERSISTENT_SLOW_DATA].Size);
-
-
- /* Fast Data */
- PSA_MemTab.Region[LVM_PERSISTENT_FAST_DATA].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- PSA_MemTab.Region[LVM_PERSISTENT_FAST_DATA].Size);
-
-
- /* Fast Coef */
- PSA_MemTab.Region[LVM_PERSISTENT_FAST_COEF].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
- PSA_MemTab.Region[LVM_PERSISTENT_FAST_COEF].Size);
-
- /* Fast Temporary */
-#ifdef BUILD_FLOAT
- pInstance->pPSAInput = InstAlloc_AddMember(&AllocMem[LVM_TEMPORARY_FAST],
- (LVM_UINT32) MAX_INTERNAL_BLOCKSIZE * \
- sizeof(LVM_FLOAT));
-#else
- pInstance->pPSAInput = InstAlloc_AddMember(&AllocMem[LVM_TEMPORARY_FAST],
- (LVM_UINT32) MAX_INTERNAL_BLOCKSIZE * sizeof(LVM_INT16));
-#endif
- PSA_MemTab.Region[LVM_TEMPORARY_FAST].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST],0);
-
-
- /*Initialise PSA instance and save the instance handle*/
- pInstance->PSA_ControlParams.Fs = LVM_FS_48000;
- pInstance->PSA_ControlParams.LevelDetectionSpeed = LVPSA_SPEED_MEDIUM;
- PSA_Status = LVPSA_Init (&hPSAInstance,
- &pInstance->PSA_InitParams,
- &pInstance->PSA_ControlParams,
- &PSA_MemTab);
-
- if (PSA_Status != LVPSA_OK)
- {
- return((LVM_ReturnStatus_en) LVM_ALGORITHMPSA);
- }
-
- pInstance->hPSAInstance = hPSAInstance; /* Save the instance handle */
- pInstance->PSA_GainOffset = 0;
- }
- else
- {
- pInstance->hPSAInstance = LVM_NULL;
- }
-
- /*
- * Set the initialisation parameters.
- */
- pInstance->Params.PSA_PeakDecayRate = LVM_PSA_SPEED_MEDIUM;
- pInstance->Params.PSA_Enable = LVM_PSA_OFF;
- }
-
- /*
- * Copy the initial parameters to the new parameters for correct readback of
- * the settings.
- */
- pInstance->NewParams = pInstance->Params;
-
-
- /*
- * Create configuration number
- */
- pInstance->ConfigurationNumber = 0x00000000;
- pInstance->ConfigurationNumber += LVM_CS_MASK;
- pInstance->ConfigurationNumber += LVM_EQNB_MASK;
- pInstance->ConfigurationNumber += LVM_DBE_MASK;
- pInstance->ConfigurationNumber += LVM_VC_MASK;
- pInstance->ConfigurationNumber += LVM_PSA_MASK;
-
- if(((pInstance->ConfigurationNumber & LVM_CS_MASK)!=0) ||
- ((pInstance->ConfigurationNumber & LVM_DBE_MASK)!=0) ||
- ((pInstance->ConfigurationNumber & LVM_EQNB_MASK)!=0)||
- ((pInstance->ConfigurationNumber & LVM_TE_MASK)!=0) ||
- ((pInstance->ConfigurationNumber & LVM_VC_MASK)!=0))
- {
- pInstance->BlickSizeMultiple = 4;
- }
- else
- {
- pInstance->BlickSizeMultiple = 1;
- }
-
- return(Status);
-}
-
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVM_ClearAudioBuffers */
-/* */
-/* DESCRIPTION: */
-/* This function is used to clear the internal audio buffers of the bundle. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance handle */
-/* */
-/* RETURNS: */
-/* LVM_SUCCESS Initialisation succeeded */
-/* LVM_NULLADDRESS Instance or scratch memory has a NULL pointer */
-/* */
-/* NOTES: */
-/* 1. This function must not be interrupted by the LVM_Process function */
-/* */
-/****************************************************************************************/
-
-LVM_ReturnStatus_en LVM_ClearAudioBuffers(LVM_Handle_t hInstance)
-{
- LVM_MemTab_t MemTab; /* Memory table */
- LVM_InstParams_t InstParams; /* Instance parameters */
- LVM_ControlParams_t Params; /* Control Parameters */
- LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance; /* Pointer to Instance */
- LVM_HeadroomParams_t HeadroomParams;
-
-
- if(hInstance == LVM_NULL){
- return LVM_NULLADDRESS;
- }
-
- /* Save the control parameters */ /* coverity[unchecked_value] */ /* Do not check return value internal function calls */
- LVM_GetControlParameters(hInstance, &Params);
-
- /*Save the headroom parameters*/
- LVM_GetHeadroomParams(hInstance, &HeadroomParams);
-
- /* Retrieve allocated buffers in memtab */
- LVM_GetMemoryTable(hInstance, &MemTab, LVM_NULL);
-
- /* Save the instance parameters */
- InstParams = pInstance->InstParams;
-
- /* Call LVM_GetInstanceHandle to re-initialise the bundle */
- LVM_GetInstanceHandle( &hInstance,
- &MemTab,
- &InstParams);
-
- /* Restore control parameters */ /* coverity[unchecked_value] */ /* Do not check return value internal function calls */
- LVM_SetControlParameters(hInstance, &Params);
-
- /*Restore the headroom parameters*/
- LVM_SetHeadroomParams(hInstance, &HeadroomParams);
-
- /* DC removal filter */
-#ifdef SUPPORT_MC
- DC_Mc_D16_TRC_WRA_01_Init(&pInstance->DC_RemovalInstance);
-#else
- DC_2I_D16_TRC_WRA_01_Init(&pInstance->DC_RemovalInstance);
-#endif
-
- return LVM_SUCCESS;
-}
-
-
-
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Init.cpp b/media/libeffects/lvm/lib/Bundle/src/LVM_Init.cpp
new file mode 100644
index 0000000..5620529
--- /dev/null
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Init.cpp
@@ -0,0 +1,1074 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/************************************************************************************/
+/* */
+/* Includes */
+/* */
+/************************************************************************************/
+
+#include "LVM_Private.h"
+#include "LVM_Tables.h"
+#include "VectorArithmetic.h"
+#include "InstAlloc.h"
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVM_GetMemoryTable */
+/* */
+/* DESCRIPTION: */
+/* This function is used for memory allocation and free. It can be called in */
+/* two ways: */
+/* */
+/* hInstance = NULL Returns the memory requirements */
+/* hInstance = Instance handle Returns the memory requirements and */
+/* allocated base addresses for the instance */
+/* */
+/* When this function is called for memory allocation (hInstance=NULL) the memory */
+/* base address pointers are NULL on return. */
+/* */
+/* When the function is called for free (hInstance = Instance Handle) the memory */
+/* table returns the allocated memory and base addresses used during initialisation. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance Handle */
+/* pMemoryTable Pointer to an empty memory definition table */
+/* pCapabilities Pointer to the default capabilities */
+/* */
+/* RETURNS: */
+/* LVM_SUCCESS Succeeded */
+/* LVM_NULLADDRESS When one of pMemoryTable or pInstParams is NULL */
+/* LVM_OUTOFRANGE When any of the Instance parameters are out of range */
+/* */
+/* NOTES: */
+/* 1. This function may be interrupted by the LVM_Process function */
+/* 2. The scratch memory is the largest required by any of the sub-modules plus any */
+/* additional scratch requirements of the bundle */
+/* */
+/****************************************************************************************/
+
+/*
+ * 4 Types of Memory Regions of LVM
+ * TODO: Allocate on the fly.
+ * i) LVM_MEMREGION_PERSISTENT_SLOW_DATA - For Instance Handles
+ * ii) LVM_MEMREGION_PERSISTENT_FAST_DATA - Persistent Buffers
+ * iii) LVM_MEMREGION_PERSISTENT_FAST_COEF - For Holding Structure values
+ * iv) LVM_MEMREGION_TEMPORARY_FAST - For Holding Structure values
+ *
+ * LVM_MEMREGION_PERSISTENT_SLOW_DATA:
+ * Total Memory size:
+ * sizeof(LVM_Instance_t) + \
+ * sizeof(LVM_Buffer_t) + \
+ * sizeof(LVPSA_InstancePr_t) + \
+ * sizeof(LVM_Buffer_t) - needed if buffer mode is LVM_MANAGED_BUFFER
+ *
+ * LVM_MEMREGION_PERSISTENT_FAST_DATA:
+ * Total Memory size:
+ * sizeof(LVM_TE_Data_t) + \
+ * 2 * pInstParams->EQNB_NumBands * sizeof(LVM_EQNB_BandDef_t) + \
+ * sizeof(LVCS_Data_t) + \
+ * sizeof(LVDBE_Data_FLOAT_t) + \
+ * sizeof(Biquad_2I_Order2_FLOAT_Taps_t) + \
+ * sizeof(Biquad_2I_Order2_FLOAT_Taps_t) + \
+ * pInstParams->EQNB_NumBands * sizeof(Biquad_2I_Order2_FLOAT_Taps_t) + \
+ * pInstParams->EQNB_NumBands * sizeof(LVEQNB_BandDef_t) + \
+ * pInstParams->EQNB_NumBands * sizeof(LVEQNB_BiquadType_en) + \
+ * 2 * LVM_HEADROOM_MAX_NBANDS * sizeof(LVM_HeadroomBandDef_t) + \
+ * PSA_InitParams.nBands * sizeof(Biquad_1I_Order2_Taps_t) + \
+ * PSA_InitParams.nBands * sizeof(QPD_Taps_t)
+ *
+ * LVM_MEMREGION_PERSISTENT_FAST_COEF:
+ * Total Memory size:
+ * sizeof(LVM_TE_Coefs_t) + \
+ * sizeof(LVCS_Coefficient_t) + \
+ * sizeof(LVDBE_Coef_FLOAT_t) + \
+ * sizeof(Biquad_FLOAT_Instance_t) + \
+ * sizeof(Biquad_FLOAT_Instance_t) + \
+ * pInstParams->EQNB_NumBands * sizeof(Biquad_FLOAT_Instance_t) + \
+ * PSA_InitParams.nBands * sizeof(Biquad_Instance_t) + \
+ * PSA_InitParams.nBands * sizeof(QPD_State_t)
+ *
+ * LVM_MEMREGION_TEMPORARY_FAST (Scratch):
+ * Total Memory Size:
+ * BundleScratchSize + \
+ * MAX_INTERNAL_BLOCKSIZE * sizeof(LVM_FLOAT) + \
+ * MaxScratchOf (CS, EQNB, DBE, PSA)
+ *
+ * a)BundleScratchSize:
+ * 3 * LVM_MAX_CHANNELS \
+ * * (MIN_INTERNAL_BLOCKSIZE + InternalBlockSize) * sizeof(LVM_FLOAT)
+ * This Memory is allocated only when Buffer mode is LVM_MANAGED_BUFFER.
+ * b)MaxScratchOf (CS, EQNB, DBE, PSA)
+ * This Memory is needed for scratch usage for CS, EQNB, DBE, PSA.
+ * CS = (LVCS_SCRATCHBUFFERS * sizeof(LVM_FLOAT)
+ * * pCapabilities->MaxBlockSize)
+ * EQNB = (LVEQNB_SCRATCHBUFFERS * sizeof(LVM_FLOAT)
+ * * pCapabilities->MaxBlockSize)
+ * DBE = (LVDBE_SCRATCHBUFFERS_INPLACE*sizeof(LVM_FLOAT)
+ * * pCapabilities->MaxBlockSize)
+ * PSA = (2 * pInitParams->MaxInputBlockSize * sizeof(LVM_FLOAT))
+ * one MaxInputBlockSize for input and another for filter output
+ * c)MAX_INTERNAL_BLOCKSIZE
+ * This Memory is needed for PSAInput - Temp memory to store output
+ * from McToMono block and given as input to PSA block
+ */
+
+LVM_ReturnStatus_en LVM_GetMemoryTable(LVM_Handle_t hInstance,
+ LVM_MemTab_t *pMemoryTable,
+ LVM_InstParams_t *pInstParams)
+{
+
+ LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
+ LVM_UINT32 AlgScratchSize;
+ LVM_UINT32 BundleScratchSize;
+ LVM_UINT16 InternalBlockSize;
+ INST_ALLOC AllocMem[LVM_NR_MEMORY_REGIONS];
+ LVM_INT16 i;
+
+ /*
+ * Check parameters
+ */
+ if(pMemoryTable == LVM_NULL)
+ {
+ return LVM_NULLADDRESS;
+ }
+
+ /*
+ * Return memory table if the instance has already been created
+ */
+ if (hInstance != LVM_NULL)
+ {
+ /* Read back memory allocation table */
+ *pMemoryTable = pInstance->MemoryTable;
+ return(LVM_SUCCESS);
+ }
+
+ if(pInstParams == LVM_NULL)
+ {
+ return LVM_NULLADDRESS;
+ }
+
+ /*
+ * Power Spectrum Analyser
+ */
+ if(pInstParams->PSA_Included > LVM_PSA_ON)
+ {
+ return (LVM_OUTOFRANGE);
+ }
+
+ /*
+ * Check the instance parameters
+ */
+ if( (pInstParams->BufferMode != LVM_MANAGED_BUFFERS) && (pInstParams->BufferMode != LVM_UNMANAGED_BUFFERS) )
+ {
+ return (LVM_OUTOFRANGE);
+ }
+
+ /* N-Band Equalizer */
+ if( pInstParams->EQNB_NumBands > 32 )
+ {
+ return (LVM_OUTOFRANGE);
+ }
+
+ if(pInstParams->BufferMode == LVM_MANAGED_BUFFERS)
+ {
+ if( (pInstParams->MaxBlockSize < LVM_MIN_MAXBLOCKSIZE ) || (pInstParams->MaxBlockSize > LVM_MANAGED_MAX_MAXBLOCKSIZE ) )
+ {
+ return (LVM_OUTOFRANGE);
+ }
+ }
+ else
+ {
+ if( (pInstParams->MaxBlockSize < LVM_MIN_MAXBLOCKSIZE ) || (pInstParams->MaxBlockSize > LVM_UNMANAGED_MAX_MAXBLOCKSIZE) )
+ {
+ return (LVM_OUTOFRANGE);
+ }
+ }
+
+ /*
+ * Initialise the AllocMem structures
+ */
+ for (i=0; i<LVM_NR_MEMORY_REGIONS; i++)
+ {
+ InstAlloc_Init(&AllocMem[i], LVM_NULL);
+ }
+ InternalBlockSize = (LVM_UINT16)((pInstParams->MaxBlockSize) & MIN_INTERNAL_BLOCKMASK); /* Force to a multiple of MIN_INTERNAL_BLOCKSIZE */
+
+ if (InternalBlockSize < MIN_INTERNAL_BLOCKSIZE)
+ {
+ InternalBlockSize = MIN_INTERNAL_BLOCKSIZE;
+ }
+
+ /* Maximum Internal Black Size should not be more than MAX_INTERNAL_BLOCKSIZE*/
+ if(InternalBlockSize > MAX_INTERNAL_BLOCKSIZE)
+ {
+ InternalBlockSize = MAX_INTERNAL_BLOCKSIZE;
+ }
+
+ /*
+ * Bundle requirements
+ */
+ InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_SLOW_DATA],
+ sizeof(LVM_Instance_t));
+
+ /*
+ * Set the algorithm and bundle scratch requirements
+ */
+ AlgScratchSize = 0;
+ if (pInstParams->BufferMode == LVM_MANAGED_BUFFERS)
+ {
+ BundleScratchSize = 3 * LVM_MAX_CHANNELS \
+ * (MIN_INTERNAL_BLOCKSIZE + InternalBlockSize) \
+ * sizeof(LVM_FLOAT);
+ InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST], /* Scratch buffer */
+ BundleScratchSize);
+ InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_SLOW_DATA],
+ sizeof(LVM_Buffer_t));
+ }
+
+ /*
+ * Treble Enhancement requirements
+ */
+ InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
+ sizeof(LVM_TE_Data_t));
+ InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
+ sizeof(LVM_TE_Coefs_t));
+
+ /*
+ * N-Band Equalizer requirements
+ */
+ InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA], /* Local storage */
+ (pInstParams->EQNB_NumBands * sizeof(LVM_EQNB_BandDef_t)));
+ InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA], /* User storage */
+ (pInstParams->EQNB_NumBands * sizeof(LVM_EQNB_BandDef_t)));
+
+ /*
+ * Concert Sound requirements
+ */
+ {
+ LVCS_MemTab_t CS_MemTab;
+ LVCS_Capabilities_t CS_Capabilities;
+
+ /*
+ * Set the capabilities
+ */
+ CS_Capabilities.MaxBlockSize = InternalBlockSize;
+
+ /*
+ * Get the memory requirements
+ */
+ LVCS_Memory(LVM_NULL,
+ &CS_MemTab,
+ &CS_Capabilities);
+
+ /*
+ * Update the memory allocation structures
+ */
+ InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
+ CS_MemTab.Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].Size);
+ InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
+ CS_MemTab.Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].Size);
+ if (CS_MemTab.Region[LVM_MEMREGION_TEMPORARY_FAST].Size > AlgScratchSize) AlgScratchSize = CS_MemTab.Region[LVM_MEMREGION_TEMPORARY_FAST].Size;
+
+ }
+
+ /*
+ * Dynamic Bass Enhancement requirements
+ */
+ {
+ LVDBE_MemTab_t DBE_MemTab;
+ LVDBE_Capabilities_t DBE_Capabilities;
+
+ /*
+ * Set the capabilities
+ */
+ DBE_Capabilities.SampleRate = LVDBE_CAP_FS_8000 | LVDBE_CAP_FS_11025 |
+ LVDBE_CAP_FS_12000 | LVDBE_CAP_FS_16000 |
+ LVDBE_CAP_FS_22050 | LVDBE_CAP_FS_24000 |
+ LVDBE_CAP_FS_32000 | LVDBE_CAP_FS_44100 |
+ LVDBE_CAP_FS_48000 | LVDBE_CAP_FS_88200 |
+ LVDBE_CAP_FS_96000 | LVDBE_CAP_FS_176400 |
+ LVDBE_CAP_FS_192000;
+ DBE_Capabilities.CentreFrequency = LVDBE_CAP_CENTRE_55Hz | LVDBE_CAP_CENTRE_55Hz | LVDBE_CAP_CENTRE_66Hz | LVDBE_CAP_CENTRE_78Hz | LVDBE_CAP_CENTRE_90Hz;
+ DBE_Capabilities.MaxBlockSize = InternalBlockSize;
+
+ /*
+ * Get the memory requirements
+ */
+ LVDBE_Memory(LVM_NULL,
+ &DBE_MemTab,
+
+ &DBE_Capabilities);
+ /*
+ * Update the bundle table
+ */
+ InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
+ DBE_MemTab.Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].Size);
+ InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
+ DBE_MemTab.Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].Size);
+ if (DBE_MemTab.Region[LVM_MEMREGION_TEMPORARY_FAST].Size > AlgScratchSize) AlgScratchSize = DBE_MemTab.Region[LVM_MEMREGION_TEMPORARY_FAST].Size;
+
+ }
+
+ /*
+ * N-Band equaliser requirements
+ */
+ {
+ LVEQNB_MemTab_t EQNB_MemTab; /* For N-Band Equaliser */
+ LVEQNB_Capabilities_t EQNB_Capabilities;
+
+ /*
+ * Set the capabilities
+ */
+ EQNB_Capabilities.SampleRate = LVEQNB_CAP_FS_8000 | LVEQNB_CAP_FS_11025 |
+ LVEQNB_CAP_FS_12000 | LVEQNB_CAP_FS_16000 |
+ LVEQNB_CAP_FS_22050 | LVEQNB_CAP_FS_24000 |
+ LVEQNB_CAP_FS_32000 | LVEQNB_CAP_FS_44100 |
+ LVEQNB_CAP_FS_48000 | LVEQNB_CAP_FS_88200 |
+ LVEQNB_CAP_FS_96000 | LVEQNB_CAP_FS_176400 |
+ LVEQNB_CAP_FS_192000;
+ EQNB_Capabilities.SourceFormat = LVEQNB_CAP_STEREO | LVEQNB_CAP_MONOINSTEREO;
+ EQNB_Capabilities.MaxBlockSize = InternalBlockSize;
+ EQNB_Capabilities.MaxBands = pInstParams->EQNB_NumBands;
+
+ /*
+ * Get the memory requirements
+ */
+ LVEQNB_Memory(LVM_NULL,
+ &EQNB_MemTab,
+ &EQNB_Capabilities);
+
+ /*
+ * Update the bundle table
+ */
+ InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
+ EQNB_MemTab.Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].Size);
+ InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
+ EQNB_MemTab.Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].Size);
+ if (EQNB_MemTab.Region[LVM_MEMREGION_TEMPORARY_FAST].Size > AlgScratchSize) AlgScratchSize = EQNB_MemTab.Region[LVM_MEMREGION_TEMPORARY_FAST].Size;
+
+ }
+
+ /*
+ * Headroom management memory allocation
+ */
+ InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
+ (LVM_HEADROOM_MAX_NBANDS * sizeof(LVM_HeadroomBandDef_t)));
+ InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
+ (LVM_HEADROOM_MAX_NBANDS * sizeof(LVM_HeadroomBandDef_t)));
+
+ /*
+ * Spectrum Analyzer memory requirements
+ */
+ {
+ pLVPSA_Handle_t hPSAInst = LVM_NULL;
+ LVPSA_MemTab_t PSA_MemTab;
+ LVPSA_InitParams_t PSA_InitParams;
+ LVPSA_FilterParam_t FiltersParams[9];
+ LVPSA_RETURN PSA_Status;
+
+ if(pInstParams->PSA_Included == LVM_PSA_ON)
+ {
+ PSA_InitParams.SpectralDataBufferDuration = (LVM_UINT16) 500;
+ PSA_InitParams.MaxInputBlockSize = (LVM_UINT16) 1000;
+ PSA_InitParams.nBands = (LVM_UINT16) 9;
+
+ PSA_InitParams.pFiltersParams = &FiltersParams[0];
+ for(i = 0; i < PSA_InitParams.nBands; i++)
+ {
+ FiltersParams[i].CenterFrequency = (LVM_UINT16) 1000;
+ FiltersParams[i].QFactor = (LVM_UINT16) 25;
+ FiltersParams[i].PostGain = (LVM_INT16) 0;
+ }
+
+ /*
+ * Get the memory requirements
+ */
+ PSA_Status = LVPSA_Memory (hPSAInst,
+ &PSA_MemTab,
+ &PSA_InitParams);
+
+ if (PSA_Status != LVPSA_OK)
+ {
+ return((LVM_ReturnStatus_en) LVM_ALGORITHMPSA);
+ }
+
+ /*
+ * Update the bundle table
+ */
+ /* Slow Data */
+ InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_SLOW_DATA],
+ PSA_MemTab.Region[LVM_PERSISTENT_SLOW_DATA].Size);
+
+ /* Fast Data */
+ InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
+ PSA_MemTab.Region[LVM_PERSISTENT_FAST_DATA].Size);
+
+ /* Fast Coef */
+ InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
+ PSA_MemTab.Region[LVM_PERSISTENT_FAST_COEF].Size);
+
+ /* Fast Temporary */
+ InstAlloc_AddMember(&AllocMem[LVM_TEMPORARY_FAST],
+ MAX_INTERNAL_BLOCKSIZE * sizeof(LVM_FLOAT));
+
+ if (PSA_MemTab.Region[LVM_TEMPORARY_FAST].Size > AlgScratchSize)
+ {
+ AlgScratchSize = PSA_MemTab.Region[LVM_TEMPORARY_FAST].Size;
+ }
+ }
+ }
+
+ /*
+ * Return the memory table
+ */
+ pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_SLOW_DATA].Size = InstAlloc_GetTotal(&AllocMem[LVM_MEMREGION_PERSISTENT_SLOW_DATA]);
+ pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_SLOW_DATA].Type = LVM_PERSISTENT_SLOW_DATA;
+ pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_SLOW_DATA].pBaseAddress = LVM_NULL;
+
+ pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].Size = InstAlloc_GetTotal(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA]);
+ pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].Type = LVM_PERSISTENT_FAST_DATA;
+ pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress = LVM_NULL;
+ if (pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].Size < 4)
+ {
+ pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].Size = 0;
+ }
+
+ pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].Size = InstAlloc_GetTotal(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF]);
+ pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].Type = LVM_PERSISTENT_FAST_COEF;
+ pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress = LVM_NULL;
+ if (pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].Size < 4)
+ {
+ pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].Size = 0;
+ }
+
+ InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST],
+ AlgScratchSize);
+ pMemoryTable->Region[LVM_MEMREGION_TEMPORARY_FAST].Size = InstAlloc_GetTotal(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST]);
+ pMemoryTable->Region[LVM_MEMREGION_TEMPORARY_FAST].Type = LVM_TEMPORARY_FAST;
+ pMemoryTable->Region[LVM_MEMREGION_TEMPORARY_FAST].pBaseAddress = LVM_NULL;
+ if (pMemoryTable->Region[LVM_MEMREGION_TEMPORARY_FAST].Size < 4)
+ {
+ pMemoryTable->Region[LVM_MEMREGION_TEMPORARY_FAST].Size = 0;
+ }
+
+ return(LVM_SUCCESS);
+
+}
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVM_GetInstanceHandle */
+/* */
+/* DESCRIPTION: */
+/* This function is used to create a bundle instance. It returns the created instance */
+/* handle through phInstance. All parameters are set to their default, inactive state. */
+/* */
+/* PARAMETERS: */
+/* phInstance pointer to the instance handle */
+/* pMemoryTable Pointer to the memory definition table */
+/* pInstParams Pointer to the initialisation capabilities */
+/* */
+/* RETURNS: */
+/* LVM_SUCCESS Initialisation succeeded */
+/* LVM_OUTOFRANGE When any of the Instance parameters are out of range */
+/* LVM_NULLADDRESS When one of phInstance, pMemoryTable or pInstParams are NULL*/
+/* */
+/* NOTES: */
+/* 1. This function must not be interrupted by the LVM_Process function */
+/* */
+/****************************************************************************************/
+
+LVM_ReturnStatus_en LVM_GetInstanceHandle(LVM_Handle_t *phInstance,
+ LVM_MemTab_t *pMemoryTable,
+ LVM_InstParams_t *pInstParams)
+{
+
+ LVM_ReturnStatus_en Status = LVM_SUCCESS;
+ LVM_Instance_t *pInstance;
+ INST_ALLOC AllocMem[LVM_NR_MEMORY_REGIONS];
+ LVM_INT16 i;
+ LVM_UINT16 InternalBlockSize;
+ LVM_INT32 BundleScratchSize;
+
+ /*
+ * Check valid points have been given
+ */
+ if ((phInstance == LVM_NULL) || (pMemoryTable == LVM_NULL) || (pInstParams == LVM_NULL))
+ {
+ return (LVM_NULLADDRESS);
+ }
+
+ /*
+ * Check the memory table for NULL pointers
+ */
+ for (i=0; i<LVM_NR_MEMORY_REGIONS; i++)
+ {
+ if ((pMemoryTable->Region[i].Size != 0) &&
+ (pMemoryTable->Region[i].pBaseAddress==LVM_NULL))
+ {
+ return(LVM_NULLADDRESS);
+ }
+ }
+
+ /*
+ * Check the instance parameters
+ */
+ if( (pInstParams->BufferMode != LVM_MANAGED_BUFFERS) && (pInstParams->BufferMode != LVM_UNMANAGED_BUFFERS) )
+ {
+ return (LVM_OUTOFRANGE);
+ }
+
+ if( pInstParams->EQNB_NumBands > 32 )
+ {
+ return (LVM_OUTOFRANGE);
+ }
+
+ if(pInstParams->BufferMode == LVM_MANAGED_BUFFERS)
+ {
+ if( (pInstParams->MaxBlockSize < LVM_MIN_MAXBLOCKSIZE ) || (pInstParams->MaxBlockSize > LVM_MANAGED_MAX_MAXBLOCKSIZE ) )
+ {
+ return (LVM_OUTOFRANGE);
+ }
+ }
+ else
+ {
+ if( (pInstParams->MaxBlockSize < LVM_MIN_MAXBLOCKSIZE ) || (pInstParams->MaxBlockSize > LVM_UNMANAGED_MAX_MAXBLOCKSIZE) )
+ {
+ return (LVM_OUTOFRANGE);
+ }
+ }
+
+ if(pInstParams->PSA_Included > LVM_PSA_ON)
+ {
+ return (LVM_OUTOFRANGE);
+ }
+
+ /*
+ * Initialise the AllocMem structures
+ */
+ for (i=0; i<LVM_NR_MEMORY_REGIONS; i++)
+ {
+ InstAlloc_Init(&AllocMem[i],
+ pMemoryTable->Region[i].pBaseAddress);
+ }
+
+ /*
+ * Set the instance handle
+ */
+ *phInstance = (LVM_Handle_t)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_SLOW_DATA],
+ sizeof(LVM_Instance_t));
+ pInstance =(LVM_Instance_t *)*phInstance;
+
+ /*
+ * Save the memory table, parameters and capabilities
+ */
+ pInstance->MemoryTable = *pMemoryTable;
+ pInstance->InstParams = *pInstParams;
+
+ /*
+ * Set the bundle scratch memory and initialse the buffer management
+ */
+ InternalBlockSize = (LVM_UINT16)((pInstParams->MaxBlockSize) & MIN_INTERNAL_BLOCKMASK); /* Force to a multiple of MIN_INTERNAL_BLOCKSIZE */
+ if (InternalBlockSize < MIN_INTERNAL_BLOCKSIZE)
+ {
+ InternalBlockSize = MIN_INTERNAL_BLOCKSIZE;
+ }
+
+ /* Maximum Internal Black Size should not be more than MAX_INTERNAL_BLOCKSIZE*/
+ if(InternalBlockSize > MAX_INTERNAL_BLOCKSIZE)
+ {
+ InternalBlockSize = MAX_INTERNAL_BLOCKSIZE;
+ }
+ pInstance->InternalBlockSize = (LVM_INT16)InternalBlockSize;
+
+ /*
+ * Common settings for managed and unmanaged buffers
+ */
+ pInstance->SamplesToProcess = 0; /* No samples left to process */
+ if (pInstParams->BufferMode == LVM_MANAGED_BUFFERS)
+ {
+ /*
+ * Managed buffers required
+ */
+ pInstance->pBufferManagement = (LVM_Buffer_t *)
+ InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_SLOW_DATA],
+ sizeof(LVM_Buffer_t));
+ BundleScratchSize = (LVM_INT32)
+ (3 * LVM_MAX_CHANNELS \
+ * (MIN_INTERNAL_BLOCKSIZE + InternalBlockSize) \
+ * sizeof(LVM_FLOAT));
+ pInstance->pBufferManagement->pScratch = (LVM_FLOAT *)
+ InstAlloc_AddMember(
+ &AllocMem[LVM_MEMREGION_TEMPORARY_FAST], /* Scratch 1 buffer */
+ (LVM_UINT32)BundleScratchSize);
+ LoadConst_Float(0, /* Clear the input delay buffer */
+ (LVM_FLOAT *)&pInstance->pBufferManagement->InDelayBuffer,
+ (LVM_INT16)(LVM_MAX_CHANNELS * MIN_INTERNAL_BLOCKSIZE));
+ pInstance->pBufferManagement->InDelaySamples = MIN_INTERNAL_BLOCKSIZE; /* Set the number of delay samples */
+ pInstance->pBufferManagement->OutDelaySamples = 0; /* No samples in the output buffer */
+ pInstance->pBufferManagement->BufferState = LVM_FIRSTCALL; /* Set the state ready for the first call */
+ }
+
+ /*
+ * Set default parameters
+ */
+ pInstance->Params.OperatingMode = LVM_MODE_OFF;
+ pInstance->Params.SampleRate = LVM_FS_8000;
+ pInstance->Params.SourceFormat = LVM_MONO;
+ pInstance->Params.SpeakerType = LVM_HEADPHONES;
+ pInstance->Params.VC_EffectLevel = 0;
+ pInstance->Params.VC_Balance = 0;
+
+ /*
+ * Set callback
+ */
+ pInstance->CallBack = LVM_AlgoCallBack;
+
+ /*
+ * DC removal filter
+ */
+#ifdef SUPPORT_MC
+ DC_Mc_D16_TRC_WRA_01_Init(&pInstance->DC_RemovalInstance);
+#else
+ DC_2I_D16_TRC_WRA_01_Init(&pInstance->DC_RemovalInstance);
+#endif
+
+ /*
+ * Treble Enhancement
+ */
+ pInstance->pTE_Taps = (LVM_TE_Data_t *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
+ sizeof(LVM_TE_Data_t));
+
+ pInstance->pTE_State = (LVM_TE_Coefs_t *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
+ sizeof(LVM_TE_Coefs_t));
+ pInstance->Params.TE_OperatingMode = LVM_TE_OFF;
+ pInstance->Params.TE_EffectLevel = 0;
+ pInstance->TE_Active = LVM_FALSE;
+
+ /*
+ * Set the volume control and initialise Current to Target
+ */
+ pInstance->VC_Volume.MixerStream[0].CallbackParam = 0;
+ pInstance->VC_Volume.MixerStream[0].CallbackSet = 0;
+ pInstance->VC_Volume.MixerStream[0].pCallbackHandle = pInstance;
+ pInstance->VC_Volume.MixerStream[0].pCallBack = LVM_VCCallBack;
+
+ /* In managed buffering, start with low signal level as delay in buffer management causes a click*/
+ if (pInstParams->BufferMode == LVM_MANAGED_BUFFERS)
+ {
+ LVC_Mixer_Init(&pInstance->VC_Volume.MixerStream[0], 0, 0);
+ }
+ else
+ {
+ LVC_Mixer_Init(&pInstance->VC_Volume.MixerStream[0], LVM_MAXFLOAT, LVM_MAXFLOAT);
+ }
+
+ LVC_Mixer_SetTimeConstant(&pInstance->VC_Volume.MixerStream[0],0,LVM_FS_8000,2);
+
+ pInstance->VC_VolumedB = 0;
+ pInstance->VC_AVLFixedVolume = 0;
+ pInstance->VC_Active = LVM_FALSE;
+
+ pInstance->VC_BalanceMix.MixerStream[0].CallbackParam = 0;
+ pInstance->VC_BalanceMix.MixerStream[0].CallbackSet = 0;
+ pInstance->VC_BalanceMix.MixerStream[0].pCallbackHandle = pInstance;
+ pInstance->VC_BalanceMix.MixerStream[0].pCallBack = LVM_VCCallBack;
+ LVC_Mixer_Init(&pInstance->VC_BalanceMix.MixerStream[0], LVM_MAXFLOAT, LVM_MAXFLOAT);
+ LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[0],LVM_VC_MIXER_TIME,LVM_FS_8000,2);
+
+ pInstance->VC_BalanceMix.MixerStream[1].CallbackParam = 0;
+ pInstance->VC_BalanceMix.MixerStream[1].CallbackSet = 0;
+ pInstance->VC_BalanceMix.MixerStream[1].pCallbackHandle = pInstance;
+ pInstance->VC_BalanceMix.MixerStream[1].pCallBack = LVM_VCCallBack;
+ LVC_Mixer_Init(&pInstance->VC_BalanceMix.MixerStream[1], LVM_MAXFLOAT, LVM_MAXFLOAT);
+ LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[1],LVM_VC_MIXER_TIME,LVM_FS_8000,2);
+
+ /*
+ * Set the default EQNB pre-gain and pointer to the band definitions
+ */
+ pInstance->pEQNB_BandDefs =
+ (LVM_EQNB_BandDef_t *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
+ (pInstParams->EQNB_NumBands * sizeof(LVM_EQNB_BandDef_t)));
+ pInstance->pEQNB_UserDefs =
+ (LVM_EQNB_BandDef_t *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
+ (pInstParams->EQNB_NumBands * sizeof(LVM_EQNB_BandDef_t)));
+
+ /*
+ * Initialise the Concert Sound module
+ */
+ {
+ LVCS_Handle_t hCSInstance; /* Instance handle */
+ LVCS_MemTab_t CS_MemTab; /* Memory table */
+ LVCS_Capabilities_t CS_Capabilities; /* Initial capabilities */
+ LVCS_ReturnStatus_en LVCS_Status; /* Function call status */
+
+ /*
+ * Set default parameters
+ */
+ pInstance->Params.VirtualizerReverbLevel = 100;
+ pInstance->Params.VirtualizerType = LVM_CONCERTSOUND;
+ pInstance->Params.VirtualizerOperatingMode = LVM_MODE_OFF;
+ pInstance->CS_Active = LVM_FALSE;
+
+ /*
+ * Set the initialisation capabilities
+ */
+ CS_Capabilities.MaxBlockSize = (LVM_UINT16)InternalBlockSize;
+ CS_Capabilities.CallBack = pInstance->CallBack;
+ CS_Capabilities.pBundleInstance = (void*)pInstance;
+
+ /*
+ * Get the memory requirements and then set the address pointers, forcing alignment
+ */
+ LVCS_Status = LVCS_Memory(LVM_NULL, /* Get the memory requirements */
+ &CS_MemTab,
+ &CS_Capabilities);
+ CS_MemTab.Region[LVCS_MEMREGION_PERSISTENT_SLOW_DATA].pBaseAddress = &pInstance->CS_Instance;
+ CS_MemTab.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
+ CS_MemTab.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].Size);
+ CS_MemTab.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
+ CS_MemTab.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].Size);
+ CS_MemTab.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST],
+ 0);
+
+ /*
+ * Initialise the Concert Sound instance and save the instance handle
+ */
+ hCSInstance = LVM_NULL; /* Set to NULL to return handle */
+ LVCS_Status = LVCS_Init(&hCSInstance, /* Initiailse */
+ &CS_MemTab,
+ &CS_Capabilities);
+ if (LVCS_Status != LVCS_SUCCESS) return((LVM_ReturnStatus_en)LVCS_Status);
+ pInstance->hCSInstance = hCSInstance; /* Save the instance handle */
+
+ }
+
+ /*
+ * Initialise the Bass Enhancement module
+ */
+ {
+ LVDBE_Handle_t hDBEInstance; /* Instance handle */
+ LVDBE_MemTab_t DBE_MemTab; /* Memory table */
+ LVDBE_Capabilities_t DBE_Capabilities; /* Initial capabilities */
+ LVDBE_ReturnStatus_en LVDBE_Status; /* Function call status */
+
+ /*
+ * Set the initialisation parameters
+ */
+ pInstance->Params.BE_OperatingMode = LVM_BE_OFF;
+ pInstance->Params.BE_CentreFreq = LVM_BE_CENTRE_55Hz;
+ pInstance->Params.BE_EffectLevel = 0;
+ pInstance->Params.BE_HPF = LVM_BE_HPF_OFF;
+
+ pInstance->DBE_Active = LVM_FALSE;
+
+ /*
+ * Set the initialisation capabilities
+ */
+ DBE_Capabilities.SampleRate = LVDBE_CAP_FS_8000 | LVDBE_CAP_FS_11025 |
+ LVDBE_CAP_FS_12000 | LVDBE_CAP_FS_16000 |
+ LVDBE_CAP_FS_22050 | LVDBE_CAP_FS_24000 |
+ LVDBE_CAP_FS_32000 | LVDBE_CAP_FS_44100 |
+ LVDBE_CAP_FS_48000 | LVDBE_CAP_FS_88200 |
+ LVDBE_CAP_FS_96000 | LVDBE_CAP_FS_176400 |
+ LVDBE_CAP_FS_192000;
+ DBE_Capabilities.CentreFrequency = LVDBE_CAP_CENTRE_55Hz | LVDBE_CAP_CENTRE_55Hz | LVDBE_CAP_CENTRE_66Hz | LVDBE_CAP_CENTRE_78Hz | LVDBE_CAP_CENTRE_90Hz;
+ DBE_Capabilities.MaxBlockSize = (LVM_UINT16)InternalBlockSize;
+
+ /*
+ * Get the memory requirements and then set the address pointers
+ */
+ LVDBE_Status = LVDBE_Memory(LVM_NULL, /* Get the memory requirements */
+ &DBE_MemTab,
+ &DBE_Capabilities);
+ DBE_MemTab.Region[LVDBE_MEMREGION_INSTANCE].pBaseAddress = &pInstance->DBE_Instance;
+ DBE_MemTab.Region[LVDBE_MEMREGION_PERSISTENT_DATA].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
+ DBE_MemTab.Region[LVDBE_MEMREGION_PERSISTENT_DATA].Size);
+ DBE_MemTab.Region[LVDBE_MEMREGION_PERSISTENT_COEF].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
+ DBE_MemTab.Region[LVDBE_MEMREGION_PERSISTENT_COEF].Size);
+ DBE_MemTab.Region[LVDBE_MEMREGION_SCRATCH].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST],
+ 0);
+
+ /*
+ * Initialise the Dynamic Bass Enhancement instance and save the instance handle
+ */
+ hDBEInstance = LVM_NULL; /* Set to NULL to return handle */
+ LVDBE_Status = LVDBE_Init(&hDBEInstance, /* Initiailse */
+ &DBE_MemTab,
+ &DBE_Capabilities);
+ if (LVDBE_Status != LVDBE_SUCCESS) return((LVM_ReturnStatus_en)LVDBE_Status);
+ pInstance->hDBEInstance = hDBEInstance; /* Save the instance handle */
+ }
+
+ /*
+ * Initialise the N-Band Equaliser module
+ */
+ {
+ LVEQNB_Handle_t hEQNBInstance; /* Instance handle */
+ LVEQNB_MemTab_t EQNB_MemTab; /* Memory table */
+ LVEQNB_Capabilities_t EQNB_Capabilities; /* Initial capabilities */
+ LVEQNB_ReturnStatus_en LVEQNB_Status; /* Function call status */
+
+ /*
+ * Set the initialisation parameters
+ */
+ pInstance->Params.EQNB_OperatingMode = LVM_EQNB_OFF;
+ pInstance->Params.EQNB_NBands = 0;
+ pInstance->Params.pEQNB_BandDefinition = LVM_NULL;
+ pInstance->EQNB_Active = LVM_FALSE;
+
+ /*
+ * Set the initialisation capabilities
+ */
+ EQNB_Capabilities.SampleRate = LVEQNB_CAP_FS_8000 | LVEQNB_CAP_FS_11025 |
+ LVEQNB_CAP_FS_12000 | LVEQNB_CAP_FS_16000 |
+ LVEQNB_CAP_FS_22050 | LVEQNB_CAP_FS_24000 |
+ LVEQNB_CAP_FS_32000 | LVEQNB_CAP_FS_44100 |
+ LVEQNB_CAP_FS_48000 | LVEQNB_CAP_FS_88200 |
+ LVEQNB_CAP_FS_96000 | LVEQNB_CAP_FS_176400 |
+ LVEQNB_CAP_FS_192000;
+ EQNB_Capabilities.MaxBlockSize = (LVM_UINT16)InternalBlockSize;
+ EQNB_Capabilities.MaxBands = pInstParams->EQNB_NumBands;
+ EQNB_Capabilities.SourceFormat = LVEQNB_CAP_STEREO | LVEQNB_CAP_MONOINSTEREO;
+ EQNB_Capabilities.CallBack = pInstance->CallBack;
+ EQNB_Capabilities.pBundleInstance = (void*)pInstance;
+
+ /*
+ * Get the memory requirements and then set the address pointers, forcing alignment
+ */
+ LVEQNB_Status = LVEQNB_Memory(LVM_NULL, /* Get the memory requirements */
+ &EQNB_MemTab,
+ &EQNB_Capabilities);
+ EQNB_MemTab.Region[LVEQNB_MEMREGION_INSTANCE].pBaseAddress = &pInstance->EQNB_Instance;
+ EQNB_MemTab.Region[LVEQNB_MEMREGION_PERSISTENT_DATA].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
+ EQNB_MemTab.Region[LVEQNB_MEMREGION_PERSISTENT_DATA].Size);
+ EQNB_MemTab.Region[LVEQNB_MEMREGION_PERSISTENT_COEF].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
+ EQNB_MemTab.Region[LVEQNB_MEMREGION_PERSISTENT_COEF].Size);
+ EQNB_MemTab.Region[LVEQNB_MEMREGION_SCRATCH].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST],
+ 0);
+
+ /*
+ * Initialise the Dynamic Bass Enhancement instance and save the instance handle
+ */
+ hEQNBInstance = LVM_NULL; /* Set to NULL to return handle */
+ LVEQNB_Status = LVEQNB_Init(&hEQNBInstance, /* Initiailse */
+ &EQNB_MemTab,
+ &EQNB_Capabilities);
+ if (LVEQNB_Status != LVEQNB_SUCCESS) return((LVM_ReturnStatus_en)LVEQNB_Status);
+ pInstance->hEQNBInstance = hEQNBInstance; /* Save the instance handle */
+ }
+
+ /*
+ * Headroom management memory allocation
+ */
+ {
+ pInstance->pHeadroom_BandDefs = (LVM_HeadroomBandDef_t *)
+ InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
+ (LVM_HEADROOM_MAX_NBANDS * sizeof(LVM_HeadroomBandDef_t)));
+ pInstance->pHeadroom_UserDefs = (LVM_HeadroomBandDef_t *)
+ InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
+ (LVM_HEADROOM_MAX_NBANDS * sizeof(LVM_HeadroomBandDef_t)));
+
+ /* Headroom management parameters initialisation */
+ pInstance->NewHeadroomParams.NHeadroomBands = 2;
+ pInstance->NewHeadroomParams.pHeadroomDefinition = pInstance->pHeadroom_BandDefs;
+ pInstance->NewHeadroomParams.pHeadroomDefinition[0].Limit_Low = 20;
+ pInstance->NewHeadroomParams.pHeadroomDefinition[0].Limit_High = 4999;
+ pInstance->NewHeadroomParams.pHeadroomDefinition[0].Headroom_Offset = 3;
+ pInstance->NewHeadroomParams.pHeadroomDefinition[1].Limit_Low = 5000;
+ pInstance->NewHeadroomParams.pHeadroomDefinition[1].Limit_High = 24000;
+ pInstance->NewHeadroomParams.pHeadroomDefinition[1].Headroom_Offset = 4;
+ pInstance->NewHeadroomParams.Headroom_OperatingMode = LVM_HEADROOM_ON;
+
+ pInstance->Headroom =0;
+ }
+
+ /*
+ * Initialise the PSA module
+ */
+ {
+ pLVPSA_Handle_t hPSAInstance = LVM_NULL; /* Instance handle */
+ LVPSA_MemTab_t PSA_MemTab;
+ LVPSA_RETURN PSA_Status; /* Function call status */
+ LVPSA_FilterParam_t FiltersParams[9];
+
+ if(pInstParams->PSA_Included==LVM_PSA_ON)
+ {
+ pInstance->PSA_InitParams.SpectralDataBufferDuration = (LVM_UINT16) 500;
+ pInstance->PSA_InitParams.MaxInputBlockSize = (LVM_UINT16) 2048;
+ pInstance->PSA_InitParams.nBands = (LVM_UINT16) 9;
+ pInstance->PSA_InitParams.pFiltersParams = &FiltersParams[0];
+ for(i = 0; i < pInstance->PSA_InitParams.nBands; i++)
+ {
+ FiltersParams[i].CenterFrequency = (LVM_UINT16) 1000;
+ FiltersParams[i].QFactor = (LVM_UINT16) 100;
+ FiltersParams[i].PostGain = (LVM_INT16) 0;
+ }
+
+ /*Get the memory requirements and then set the address pointers*/
+ PSA_Status = LVPSA_Memory (hPSAInstance,
+ &PSA_MemTab,
+ &pInstance->PSA_InitParams);
+
+ if (PSA_Status != LVPSA_OK)
+ {
+ return((LVM_ReturnStatus_en) LVM_ALGORITHMPSA);
+ }
+
+ /* Slow Data */
+ PSA_MemTab.Region[LVM_PERSISTENT_SLOW_DATA].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_SLOW_DATA],
+ PSA_MemTab.Region[LVM_PERSISTENT_SLOW_DATA].Size);
+
+ /* Fast Data */
+ PSA_MemTab.Region[LVM_PERSISTENT_FAST_DATA].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
+ PSA_MemTab.Region[LVM_PERSISTENT_FAST_DATA].Size);
+
+ /* Fast Coef */
+ PSA_MemTab.Region[LVM_PERSISTENT_FAST_COEF].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
+ PSA_MemTab.Region[LVM_PERSISTENT_FAST_COEF].Size);
+
+ /* Fast Temporary */
+ pInstance->pPSAInput = (LVM_FLOAT *)InstAlloc_AddMember(&AllocMem[LVM_TEMPORARY_FAST],
+ (LVM_UINT32) MAX_INTERNAL_BLOCKSIZE * \
+ sizeof(LVM_FLOAT));
+ PSA_MemTab.Region[LVM_TEMPORARY_FAST].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST],0);
+
+ /*Initialise PSA instance and save the instance handle*/
+ pInstance->PSA_ControlParams.Fs = LVM_FS_48000;
+ pInstance->PSA_ControlParams.LevelDetectionSpeed = LVPSA_SPEED_MEDIUM;
+ PSA_Status = LVPSA_Init (&hPSAInstance,
+ &pInstance->PSA_InitParams,
+ &pInstance->PSA_ControlParams,
+ &PSA_MemTab);
+
+ if (PSA_Status != LVPSA_OK)
+ {
+ return((LVM_ReturnStatus_en) LVM_ALGORITHMPSA);
+ }
+
+ pInstance->hPSAInstance = hPSAInstance; /* Save the instance handle */
+ pInstance->PSA_GainOffset = 0;
+ }
+ else
+ {
+ pInstance->hPSAInstance = LVM_NULL;
+ }
+
+ /*
+ * Set the initialisation parameters.
+ */
+ pInstance->Params.PSA_PeakDecayRate = LVM_PSA_SPEED_MEDIUM;
+ pInstance->Params.PSA_Enable = LVM_PSA_OFF;
+ }
+
+ /*
+ * Copy the initial parameters to the new parameters for correct readback of
+ * the settings.
+ */
+ pInstance->NewParams = pInstance->Params;
+
+ /*
+ * Create configuration number
+ */
+ pInstance->ConfigurationNumber = 0x00000000;
+ pInstance->ConfigurationNumber += LVM_CS_MASK;
+ pInstance->ConfigurationNumber += LVM_EQNB_MASK;
+ pInstance->ConfigurationNumber += LVM_DBE_MASK;
+ pInstance->ConfigurationNumber += LVM_VC_MASK;
+ pInstance->ConfigurationNumber += LVM_PSA_MASK;
+
+ if(((pInstance->ConfigurationNumber & LVM_CS_MASK)!=0) ||
+ ((pInstance->ConfigurationNumber & LVM_DBE_MASK)!=0) ||
+ ((pInstance->ConfigurationNumber & LVM_EQNB_MASK)!=0)||
+ ((pInstance->ConfigurationNumber & LVM_TE_MASK)!=0) ||
+ ((pInstance->ConfigurationNumber & LVM_VC_MASK)!=0))
+ {
+ pInstance->BlickSizeMultiple = 4;
+ }
+ else
+ {
+ pInstance->BlickSizeMultiple = 1;
+ }
+
+ return(Status);
+}
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVM_ClearAudioBuffers */
+/* */
+/* DESCRIPTION: */
+/* This function is used to clear the internal audio buffers of the bundle. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance handle */
+/* */
+/* RETURNS: */
+/* LVM_SUCCESS Initialisation succeeded */
+/* LVM_NULLADDRESS Instance or scratch memory has a NULL pointer */
+/* */
+/* NOTES: */
+/* 1. This function must not be interrupted by the LVM_Process function */
+/* */
+/****************************************************************************************/
+
+LVM_ReturnStatus_en LVM_ClearAudioBuffers(LVM_Handle_t hInstance)
+{
+ LVM_MemTab_t MemTab; /* Memory table */
+ LVM_InstParams_t InstParams; /* Instance parameters */
+ LVM_ControlParams_t Params; /* Control Parameters */
+ LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance; /* Pointer to Instance */
+ LVM_HeadroomParams_t HeadroomParams;
+
+ if(hInstance == LVM_NULL){
+ return LVM_NULLADDRESS;
+ }
+
+ /* Save the control parameters */ /* coverity[unchecked_value] */ /* Do not check return value internal function calls */
+ LVM_GetControlParameters(hInstance, &Params);
+
+ /*Save the headroom parameters*/
+ LVM_GetHeadroomParams(hInstance, &HeadroomParams);
+
+ /* Retrieve allocated buffers in memtab */
+ LVM_GetMemoryTable(hInstance, &MemTab, LVM_NULL);
+
+ /* Save the instance parameters */
+ InstParams = pInstance->InstParams;
+
+ /* Call LVM_GetInstanceHandle to re-initialise the bundle */
+ LVM_GetInstanceHandle( &hInstance,
+ &MemTab,
+ &InstParams);
+
+ /* Restore control parameters */ /* coverity[unchecked_value] */ /* Do not check return value internal function calls */
+ LVM_SetControlParameters(hInstance, &Params);
+
+ /*Restore the headroom parameters*/
+ LVM_SetHeadroomParams(hInstance, &HeadroomParams);
+
+ /* DC removal filter */
+#ifdef SUPPORT_MC
+ DC_Mc_D16_TRC_WRA_01_Init(&pInstance->DC_RemovalInstance);
+#else
+ DC_2I_D16_TRC_WRA_01_Init(&pInstance->DC_RemovalInstance);
+#endif
+
+ return LVM_SUCCESS;
+}
+
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Private.h b/media/libeffects/lvm/lib/Bundle/src/LVM_Private.h
index cdd3134..ddaac99 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Private.h
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Private.h
@@ -27,11 +27,6 @@
#ifndef __LVM_PRIVATE_H__
#define __LVM_PRIVATE_H__
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-
/************************************************************************************/
/* */
/* Includes */
@@ -47,7 +42,6 @@
#include "LVEQNB_Private.h" /* N-Band equaliser */
#include "LVPSA_Private.h" /* Parametric Spectrum Analyzer */
-
/************************************************************************************/
/* */
/* Defines */
@@ -113,7 +107,6 @@
#define LVM_TE_MASK 32
#define LVM_PSA_MASK 2048
-
/************************************************************************************/
/* */
/* Structures */
@@ -129,16 +122,13 @@
void *pBaseAddress; /* Pointer to the region base address */
} LVM_IntMemoryRegion_t;
-
/* Memory table containing the region definitions */
typedef struct
{
LVM_IntMemoryRegion_t Region[LVM_NR_MEMORY_REGIONS]; /* One definition for each region */
} LVM_IntMemTab_t;
-
/* Buffer Management */
-#ifdef BUILD_FLOAT
typedef struct
{
LVM_FLOAT *pScratch; /* Bundle scratch buffer */
@@ -161,39 +151,17 @@
left and right */
LVM_INT16 SamplesToOutput; /* Samples to write to the output */
} LVM_Buffer_t;
-#else
-typedef struct
-{
- LVM_INT16 *pScratch; /* Bundle scratch buffer */
-
- LVM_INT16 BufferState; /* Buffer status */
- LVM_INT16 InDelayBuffer[6*MIN_INTERNAL_BLOCKSIZE]; /* Input buffer delay line, left and right */
- LVM_INT16 InDelaySamples; /* Number of samples in the input delay buffer */
-
- LVM_INT16 OutDelayBuffer[2*MIN_INTERNAL_BLOCKSIZE]; /* Output buffer delay line */
- LVM_INT16 OutDelaySamples; /* Number of samples in the output delay buffer, left and right */
- LVM_INT16 SamplesToOutput; /* Samples to write to the output */
-} LVM_Buffer_t;
-#endif
/* Filter taps */
typedef struct
{
-#ifdef BUILD_FLOAT
Biquad_2I_Order1_FLOAT_Taps_t TrebleBoost_Taps; /* Treble boost Taps */
-#else
- Biquad_2I_Order1_Taps_t TrebleBoost_Taps; /* Treble boost Taps */
-#endif
} LVM_TE_Data_t;
/* Coefficients */
typedef struct
{
-#ifdef BUILD_FLOAT
Biquad_FLOAT_Instance_t TrebleBoost_State; /* State for the treble boost filter */
-#else
- Biquad_Instance_t TrebleBoost_State; /* State for the treble boost filter */
-#endif
} LVM_TE_Coefs_t;
typedef struct
@@ -211,24 +179,15 @@
LVM_INT16 InternalBlockSize; /* Maximum internal block size */
LVM_Buffer_t *pBufferManagement; /* Buffer management variables */
LVM_INT16 SamplesToProcess; /* Input samples left to process */
-#ifdef BUILD_FLOAT
LVM_FLOAT *pInputSamples; /* External input sample pointer */
LVM_FLOAT *pOutputSamples; /* External output sample pointer */
-#else
- LVM_INT16 *pInputSamples; /* External input sample pointer */
- LVM_INT16 *pOutputSamples; /* External output sample pointer */
-#endif
/* Configuration number */
LVM_INT32 ConfigurationNumber;
LVM_INT32 BlickSizeMultiple;
/* DC removal */
-#ifdef BUILD_FLOAT
Biquad_FLOAT_Instance_t DC_RemovalInstance; /* DC removal filter instance */
-#else
- Biquad_Instance_t DC_RemovalInstance; /* DC removal filter instance */
-#endif
/* Concert Sound */
LVCS_Handle_t hCSInstance; /* Concert Sound instance handle */
@@ -248,16 +207,8 @@
LVM_INT16 DBE_Active; /* Control flag */
/* Volume Control */
-#ifdef BUILD_FLOAT
LVMixer3_1St_FLOAT_st VC_Volume; /* Volume scaler */
-#else
- LVMixer3_1St_st VC_Volume; /* Volume scaler */
-#endif
-#ifdef BUILD_FLOAT
LVMixer3_2St_FLOAT_st VC_BalanceMix; /* VC balance mixer */
-#else
- LVMixer3_2St_st VC_BalanceMix; /* VC balance mixer */
-#endif
LVM_INT16 VC_VolumedB; /* Gain in dB */
LVM_INT16 VC_Active; /* Control flag */
LVM_INT16 VC_AVLFixedVolume; /* AVL fixed volume */
@@ -281,11 +232,7 @@
LVPSA_ControlParams_t PSA_ControlParams; /* Spectrum Analyzer control parameters */
LVM_INT16 PSA_GainOffset; /* Tone control flag */
LVM_Callback CallBack;
-#ifdef BUILD_FLOAT
LVM_FLOAT *pPSAInput; /* PSA input pointer */
-#else
- LVM_INT16 *pPSAInput; /* PSA input pointer */
-#endif
LVM_INT16 NoSmoothVolume; /* Enable or disable smooth volume changes*/
@@ -296,7 +243,6 @@
} LVM_Instance_t;
-
/************************************************************************************/
/* */
/* Function Prototypes */
@@ -317,36 +263,18 @@
void LVM_SetHeadroom( LVM_Instance_t *pInstance,
LVM_ControlParams_t *pParams);
-#ifdef BUILD_FLOAT
void LVM_BufferIn( LVM_Handle_t hInstance,
const LVM_FLOAT *pInData,
LVM_FLOAT **pToProcess,
LVM_FLOAT **pProcessed,
LVM_UINT16 *pNumSamples);
-#else
-void LVM_BufferIn( LVM_Handle_t hInstance,
- const LVM_INT16 *pInData,
- LVM_INT16 **pToProcess,
- LVM_INT16 **pProcessed,
- LVM_UINT16 *pNumSamples);
-#endif
-#ifdef BUILD_FLOAT
void LVM_BufferOut( LVM_Handle_t hInstance,
LVM_FLOAT *pOutData,
LVM_UINT16 *pNumSamples);
-#else
-void LVM_BufferOut( LVM_Handle_t hInstance,
- LVM_INT16 *pOutData,
- LVM_UINT16 *pNumSamples);
-#endif
LVM_INT32 LVM_AlgoCallBack( void *pBundleHandle,
void *pData,
LVM_INT16 callbackId);
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
#endif /* __LVM_PRIVATE_H__ */
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Process.c b/media/libeffects/lvm/lib/Bundle/src/LVM_Process.c
deleted file mode 100644
index bc666a9..0000000
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Process.c
+++ /dev/null
@@ -1,558 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-/****************************************************************************************/
-/* */
-/* Includes */
-/* */
-/****************************************************************************************/
-#include <system/audio.h>
-
-#include "LVM_Private.h"
-#include "VectorArithmetic.h"
-#include "LVM_Coeffs.h"
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVM_Process */
-/* */
-/* DESCRIPTION: */
-/* Process function for the LifeVibes module. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance handle */
-/* pInData Pointer to the input data */
-/* pOutData Pointer to the output data */
-/* NumSamples Number of samples in the input buffer */
-/* AudioTime Audio Time of the current input buffer in ms */
-/* */
-/* RETURNS: */
-/* LVM_SUCCESS Succeeded */
-/* LVM_INVALIDNUMSAMPLES When the NumSamples is not a valied multiple in unmanaged */
-/* buffer mode */
-/* LVM_ALIGNMENTERROR When either the input our output buffers are not 32-bit */
-/* aligned in unmanaged mode */
-/* LVM_NULLADDRESS When one of hInstance, pInData or pOutData is NULL */
-/* */
-/* NOTES: */
-/* */
-/****************************************************************************************/
-#ifdef BUILD_FLOAT
-LVM_ReturnStatus_en LVM_Process(LVM_Handle_t hInstance,
- const LVM_FLOAT *pInData,
- LVM_FLOAT *pOutData,
- LVM_UINT16 NumSamples,
- LVM_UINT32 AudioTime)
-{
-
- LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
- LVM_UINT16 SampleCount = NumSamples;
- LVM_FLOAT *pInput = (LVM_FLOAT *)pInData;
- LVM_FLOAT *pToProcess = (LVM_FLOAT *)pInData;
- LVM_FLOAT *pProcessed = pOutData;
- LVM_ReturnStatus_en Status;
-#ifdef SUPPORT_MC
- LVM_INT32 NrChannels = pInstance->NrChannels;
- LVM_INT32 ChMask = pInstance->ChMask;
-#define NrFrames SampleCount // alias for clarity
-#endif
-
- /*
- * Check if the number of samples is zero
- */
- if (NumSamples == 0)
- {
- return(LVM_SUCCESS);
- }
-
-
- /*
- * Check valid points have been given
- */
- if ((hInstance == LVM_NULL) || (pInData == LVM_NULL) || (pOutData == LVM_NULL))
- {
- return (LVM_NULLADDRESS);
- }
-
- /*
- * For unmanaged mode only
- */
- if(pInstance->InstParams.BufferMode == LVM_UNMANAGED_BUFFERS)
- {
- /*
- * Check if the number of samples is a good multiple (unmanaged mode only)
- */
- if((NumSamples % pInstance->BlickSizeMultiple) != 0)
- {
- return(LVM_INVALIDNUMSAMPLES);
- }
-
- /*
- * Check the buffer alignment
- */
- if((((uintptr_t)pInData % 4) != 0) || (((uintptr_t)pOutData % 4) != 0))
- {
- return(LVM_ALIGNMENTERROR);
- }
- }
-
-
- /*
- * Update new parameters if necessary
- */
- if (pInstance->ControlPending == LVM_TRUE)
- {
- Status = LVM_ApplyNewSettings(hInstance);
-#ifdef SUPPORT_MC
- /* Update the local variable NrChannels from pInstance->NrChannels value */
- NrChannels = pInstance->NrChannels;
- ChMask = pInstance->ChMask;
-#endif
-
- if(Status != LVM_SUCCESS)
- {
- return Status;
- }
- }
-
-
- /*
- * Convert from Mono if necessary
- */
- if (pInstance->Params.SourceFormat == LVM_MONO)
- {
- MonoTo2I_Float(pInData, /* Source */
- pOutData, /* Destination */
- (LVM_INT16)NumSamples); /* Number of input samples */
- pInput = pOutData;
- pToProcess = pOutData;
-#ifdef SUPPORT_MC
- NrChannels = 2;
- ChMask = AUDIO_CHANNEL_OUT_STEREO;
-#endif
- }
-
-
- /*
- * Process the data with managed buffers
- */
- while (SampleCount != 0)
- {
- /*
- * Manage the input buffer and frame processing
- */
- LVM_BufferIn(hInstance,
- pInput,
- &pToProcess,
- &pProcessed,
- &SampleCount);
-
- /*
- * Only process data when SampleCount is none zero, a zero count can occur when
- * the BufferIn routine is working in managed mode.
- */
- if (SampleCount != 0)
- {
- /*
- * Apply ConcertSound if required
- */
- if (pInstance->CS_Active == LVM_TRUE)
- {
- (void)LVCS_Process(pInstance->hCSInstance, /* Concert Sound instance handle */
- pToProcess,
- pProcessed,
- SampleCount);
- pToProcess = pProcessed;
- }
-
- /*
- * Apply volume if required
- */
- if (pInstance->VC_Active!=0)
- {
-#ifdef SUPPORT_MC
- LVC_MixSoft_Mc_D16C31_SAT(&pInstance->VC_Volume,
- pToProcess,
- pProcessed,
- (LVM_INT16)(NrFrames),
- NrChannels);
-#else
- LVC_MixSoft_1St_D16C31_SAT(&pInstance->VC_Volume,
- pToProcess,
- pProcessed,
- (LVM_INT16)(2 * SampleCount)); /* Left and right*/
-#endif
- pToProcess = pProcessed;
- }
-
- /*
- * Call N-Band equaliser if enabled
- */
- if (pInstance->EQNB_Active == LVM_TRUE)
- {
- LVEQNB_Process(pInstance->hEQNBInstance, /* N-Band equaliser instance handle */
- pToProcess,
- pProcessed,
- SampleCount);
- pToProcess = pProcessed;
- }
-
- /*
- * Call bass enhancement if enabled
- */
- if (pInstance->DBE_Active == LVM_TRUE)
- {
- LVDBE_Process(pInstance->hDBEInstance, /* Dynamic Bass Enhancement \
- instance handle */
- pToProcess,
- pProcessed,
- SampleCount);
- pToProcess = pProcessed;
- }
-
- /*
- * Bypass mode or everything off, so copy the input to the output
- */
- if (pToProcess != pProcessed)
- {
-#ifdef SUPPORT_MC
- Copy_Float(pToProcess, /* Source */
- pProcessed, /* Destination */
- (LVM_INT16)(NrChannels * NrFrames)); /* Copy all samples */
-#else
- Copy_Float(pToProcess, /* Source */
- pProcessed, /* Destination */
- (LVM_INT16)(2 * SampleCount)); /* Left and right */
-#endif
- }
-
- /*
- * Apply treble boost if required
- */
- if (pInstance->TE_Active == LVM_TRUE)
- {
- /*
- * Apply the filter
- */
-#ifdef SUPPORT_MC
- FO_Mc_D16F32C15_LShx_TRC_WRA_01(&pInstance->pTE_State->TrebleBoost_State,
- pProcessed,
- pProcessed,
- (LVM_INT16)NrFrames,
- (LVM_INT16)NrChannels);
-#else
- FO_2I_D16F32C15_LShx_TRC_WRA_01(&pInstance->pTE_State->TrebleBoost_State,
- pProcessed,
- pProcessed,
- (LVM_INT16)SampleCount);
-#endif
-
- }
-#ifdef SUPPORT_MC
- /*
- * Volume balance
- */
- LVC_MixSoft_1St_MC_float_SAT(&pInstance->VC_BalanceMix,
- pProcessed,
- pProcessed,
- NrFrames,
- NrChannels,
- ChMask);
-#else
- /*
- * Volume balance
- */
- LVC_MixSoft_1St_2i_D16C31_SAT(&pInstance->VC_BalanceMix,
- pProcessed,
- pProcessed,
- SampleCount);
-#endif
-
- /*
- * Perform Parametric Spectum Analysis
- */
- if ((pInstance->Params.PSA_Enable == LVM_PSA_ON) &&
- (pInstance->InstParams.PSA_Included == LVM_PSA_ON))
- {
-#ifdef SUPPORT_MC
- FromMcToMono_Float(pProcessed,
- pInstance->pPSAInput,
- (LVM_INT16)(NrFrames),
- NrChannels);
-#else
- From2iToMono_Float(pProcessed,
- pInstance->pPSAInput,
- (LVM_INT16)(SampleCount));
-#endif
-
- LVPSA_Process(pInstance->hPSAInstance,
- pInstance->pPSAInput,
- (LVM_UINT16)(SampleCount),
- AudioTime);
- }
-
- /*
- * DC removal
- */
-#ifdef SUPPORT_MC
- DC_Mc_D16_TRC_WRA_01(&pInstance->DC_RemovalInstance,
- pProcessed,
- pProcessed,
- (LVM_INT16)NrFrames,
- NrChannels);
-#else
- DC_2I_D16_TRC_WRA_01(&pInstance->DC_RemovalInstance,
- pProcessed,
- pProcessed,
- (LVM_INT16)SampleCount);
-#endif
- }
- /*
- * Manage the output buffer
- */
- LVM_BufferOut(hInstance,
- pOutData,
- &SampleCount);
-
- }
-
- return(LVM_SUCCESS);
-}
-#else
-LVM_ReturnStatus_en LVM_Process(LVM_Handle_t hInstance,
- const LVM_INT16 *pInData,
- LVM_INT16 *pOutData,
- LVM_UINT16 NumSamples,
- LVM_UINT32 AudioTime)
-{
-
- LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
- LVM_UINT16 SampleCount = NumSamples;
- LVM_INT16 *pInput = (LVM_INT16 *)pInData;
- LVM_INT16 *pToProcess = (LVM_INT16 *)pInData;
- LVM_INT16 *pProcessed = pOutData;
- LVM_ReturnStatus_en Status;
-
- /*
- * Check if the number of samples is zero
- */
- if (NumSamples == 0)
- {
- return(LVM_SUCCESS);
- }
-
-
- /*
- * Check valid points have been given
- */
- if ((hInstance == LVM_NULL) || (pInData == LVM_NULL) || (pOutData == LVM_NULL))
- {
- return (LVM_NULLADDRESS);
- }
-
- /*
- * For unmanaged mode only
- */
- if(pInstance->InstParams.BufferMode == LVM_UNMANAGED_BUFFERS)
- {
- /*
- * Check if the number of samples is a good multiple (unmanaged mode only)
- */
- if((NumSamples % pInstance->BlickSizeMultiple) != 0)
- {
- return(LVM_INVALIDNUMSAMPLES);
- }
-
- /*
- * Check the buffer alignment
- */
- if((((uintptr_t)pInData % 4) != 0) || (((uintptr_t)pOutData % 4) != 0))
- {
- return(LVM_ALIGNMENTERROR);
- }
- }
-
-
- /*
- * Update new parameters if necessary
- */
- if (pInstance->ControlPending == LVM_TRUE)
- {
- Status = LVM_ApplyNewSettings(hInstance);
-
- if(Status != LVM_SUCCESS)
- {
- return Status;
- }
- }
-
-
- /*
- * Convert from Mono if necessary
- */
- if (pInstance->Params.SourceFormat == LVM_MONO)
- {
- MonoTo2I_16(pInData, /* Source */
- pOutData, /* Destination */
- (LVM_INT16)NumSamples); /* Number of input samples */
- pInput = pOutData;
- pToProcess = pOutData;
- }
-
-
- /*
- * Process the data with managed buffers
- */
- while (SampleCount != 0)
- {
- /*
- * Manage the input buffer and frame processing
- */
- LVM_BufferIn(hInstance,
- pInput,
- &pToProcess,
- &pProcessed,
- &SampleCount);
-
- /*
- * Only process data when SampleCount is none zero, a zero count can occur when
- * the BufferIn routine is working in managed mode.
- */
- if (SampleCount != 0)
- {
-
- /*
- * Apply ConcertSound if required
- */
- if (pInstance->CS_Active == LVM_TRUE)
- {
- (void)LVCS_Process(pInstance->hCSInstance, /* Concert Sound instance handle */
- pToProcess,
- pProcessed,
- SampleCount);
- pToProcess = pProcessed;
- }
-
- /*
- * Apply volume if required
- */
- if (pInstance->VC_Active!=0)
- {
- LVC_MixSoft_1St_D16C31_SAT(&pInstance->VC_Volume,
- pToProcess,
- pProcessed,
- (LVM_INT16)(2*SampleCount)); /* Left and right*/
- pToProcess = pProcessed;
- }
-
- /*
- * Call N-Band equaliser if enabled
- */
- if (pInstance->EQNB_Active == LVM_TRUE)
- {
- LVEQNB_Process(pInstance->hEQNBInstance, /* N-Band equaliser instance handle */
- pToProcess,
- pProcessed,
- SampleCount);
- pToProcess = pProcessed;
- }
-
- /*
- * Call bass enhancement if enabled
- */
- if (pInstance->DBE_Active == LVM_TRUE)
- {
- LVDBE_Process(pInstance->hDBEInstance, /* Dynamic Bass Enhancement instance handle */
- pToProcess,
- pProcessed,
- SampleCount);
- pToProcess = pProcessed;
- }
-
- /*
- * Bypass mode or everything off, so copy the input to the output
- */
- if (pToProcess != pProcessed)
- {
- Copy_16(pToProcess, /* Source */
- pProcessed, /* Destination */
- (LVM_INT16)(2*SampleCount)); /* Left and right */
- }
-
- /*
- * Apply treble boost if required
- */
- if (pInstance->TE_Active == LVM_TRUE)
- {
- /*
- * Apply the filter
- */
- FO_2I_D16F32C15_LShx_TRC_WRA_01(&pInstance->pTE_State->TrebleBoost_State,
- pProcessed,
- pProcessed,
- (LVM_INT16)SampleCount);
-
- }
-
- /*
- * Volume balance
- */
- LVC_MixSoft_1St_2i_D16C31_SAT(&pInstance->VC_BalanceMix,
- pProcessed,
- pProcessed,
- SampleCount);
-
- /*
- * Perform Parametric Spectum Analysis
- */
- if ((pInstance->Params.PSA_Enable == LVM_PSA_ON)&&(pInstance->InstParams.PSA_Included==LVM_PSA_ON))
- {
- From2iToMono_16(pProcessed,
- pInstance->pPSAInput,
- (LVM_INT16) (SampleCount));
-
- LVPSA_Process(pInstance->hPSAInstance,
- pInstance->pPSAInput,
- (LVM_UINT16) (SampleCount),
- AudioTime);
- }
-
-
- /*
- * DC removal
- */
- DC_2I_D16_TRC_WRA_01(&pInstance->DC_RemovalInstance,
- pProcessed,
- pProcessed,
- (LVM_INT16)SampleCount);
-
-
- }
-
- /*
- * Manage the output buffer
- */
- LVM_BufferOut(hInstance,
- pOutData,
- &SampleCount);
-
- }
-
- return(LVM_SUCCESS);
-}
-#endif
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Process.cpp b/media/libeffects/lvm/lib/Bundle/src/LVM_Process.cpp
new file mode 100644
index 0000000..dc86cfd
--- /dev/null
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Process.cpp
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/****************************************************************************************/
+/* */
+/* Includes */
+/* */
+/****************************************************************************************/
+#include <system/audio.h>
+
+#include "LVM_Private.h"
+#include "VectorArithmetic.h"
+#include "LVM_Coeffs.h"
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVM_Process */
+/* */
+/* DESCRIPTION: */
+/* Process function for the LifeVibes module. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance handle */
+/* pInData Pointer to the input data */
+/* pOutData Pointer to the output data */
+/* NumSamples Number of samples in the input buffer */
+/* AudioTime Audio Time of the current input buffer in ms */
+/* */
+/* RETURNS: */
+/* LVM_SUCCESS Succeeded */
+/* LVM_INVALIDNUMSAMPLES When the NumSamples is not a valied multiple in unmanaged */
+/* buffer mode */
+/* LVM_ALIGNMENTERROR When either the input our output buffers are not 32-bit */
+/* aligned in unmanaged mode */
+/* LVM_NULLADDRESS When one of hInstance, pInData or pOutData is NULL */
+/* */
+/* NOTES: */
+/* */
+/****************************************************************************************/
+LVM_ReturnStatus_en LVM_Process(LVM_Handle_t hInstance,
+ const LVM_FLOAT *pInData,
+ LVM_FLOAT *pOutData,
+ LVM_UINT16 NumSamples,
+ LVM_UINT32 AudioTime)
+{
+
+ LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
+ LVM_UINT16 SampleCount = NumSamples;
+ LVM_FLOAT *pInput = (LVM_FLOAT *)pInData;
+ LVM_FLOAT *pToProcess = (LVM_FLOAT *)pInData;
+ LVM_FLOAT *pProcessed = pOutData;
+ LVM_ReturnStatus_en Status;
+#ifdef SUPPORT_MC
+ LVM_INT32 NrChannels = pInstance->NrChannels;
+ LVM_INT32 ChMask = pInstance->ChMask;
+#define NrFrames SampleCount // alias for clarity
+#endif
+
+ /*
+ * Check if the number of samples is zero
+ */
+ if (NumSamples == 0)
+ {
+ return(LVM_SUCCESS);
+ }
+
+ /*
+ * Check valid points have been given
+ */
+ if ((hInstance == LVM_NULL) || (pInData == LVM_NULL) || (pOutData == LVM_NULL))
+ {
+ return (LVM_NULLADDRESS);
+ }
+
+ /*
+ * For unmanaged mode only
+ */
+ if(pInstance->InstParams.BufferMode == LVM_UNMANAGED_BUFFERS)
+ {
+ /*
+ * Check if the number of samples is a good multiple (unmanaged mode only)
+ */
+ if((NumSamples % pInstance->BlickSizeMultiple) != 0)
+ {
+ return(LVM_INVALIDNUMSAMPLES);
+ }
+
+ /*
+ * Check the buffer alignment
+ */
+ if((((uintptr_t)pInData % 4) != 0) || (((uintptr_t)pOutData % 4) != 0))
+ {
+ return(LVM_ALIGNMENTERROR);
+ }
+ }
+
+ /*
+ * Update new parameters if necessary
+ */
+ if (pInstance->ControlPending == LVM_TRUE)
+ {
+ Status = LVM_ApplyNewSettings(hInstance);
+#ifdef SUPPORT_MC
+ /* Update the local variable NrChannels from pInstance->NrChannels value */
+ NrChannels = pInstance->NrChannels;
+ ChMask = pInstance->ChMask;
+#endif
+
+ if(Status != LVM_SUCCESS)
+ {
+ return Status;
+ }
+ }
+
+ /*
+ * Convert from Mono if necessary
+ */
+ if (pInstance->Params.SourceFormat == LVM_MONO)
+ {
+ MonoTo2I_Float(pInData, /* Source */
+ pOutData, /* Destination */
+ (LVM_INT16)NumSamples); /* Number of input samples */
+ pInput = pOutData;
+ pToProcess = pOutData;
+#ifdef SUPPORT_MC
+ NrChannels = 2;
+ ChMask = AUDIO_CHANNEL_OUT_STEREO;
+#endif
+ }
+
+ /*
+ * Process the data with managed buffers
+ */
+ while (SampleCount != 0)
+ {
+ /*
+ * Manage the input buffer and frame processing
+ */
+ LVM_BufferIn(hInstance,
+ pInput,
+ &pToProcess,
+ &pProcessed,
+ &SampleCount);
+
+ /*
+ * Only process data when SampleCount is none zero, a zero count can occur when
+ * the BufferIn routine is working in managed mode.
+ */
+ if (SampleCount != 0)
+ {
+ /*
+ * Apply ConcertSound if required
+ */
+ if (pInstance->CS_Active == LVM_TRUE)
+ {
+ (void)LVCS_Process(pInstance->hCSInstance, /* Concert Sound instance handle */
+ pToProcess,
+ pProcessed,
+ SampleCount);
+ pToProcess = pProcessed;
+ }
+
+ /*
+ * Apply volume if required
+ */
+ if (pInstance->VC_Active!=0)
+ {
+#ifdef SUPPORT_MC
+ LVC_MixSoft_Mc_D16C31_SAT(&pInstance->VC_Volume,
+ pToProcess,
+ pProcessed,
+ (LVM_INT16)(NrFrames),
+ NrChannels);
+#else
+ LVC_MixSoft_1St_D16C31_SAT(&pInstance->VC_Volume,
+ pToProcess,
+ pProcessed,
+ (LVM_INT16)(2 * SampleCount)); /* Left and right*/
+#endif
+ pToProcess = pProcessed;
+ }
+
+ /*
+ * Call N-Band equaliser if enabled
+ */
+ if (pInstance->EQNB_Active == LVM_TRUE)
+ {
+ LVEQNB_Process(pInstance->hEQNBInstance, /* N-Band equaliser instance handle */
+ pToProcess,
+ pProcessed,
+ SampleCount);
+ pToProcess = pProcessed;
+ }
+
+ /*
+ * Call bass enhancement if enabled
+ */
+ if (pInstance->DBE_Active == LVM_TRUE)
+ {
+ LVDBE_Process(pInstance->hDBEInstance, /* Dynamic Bass Enhancement \
+ instance handle */
+ pToProcess,
+ pProcessed,
+ SampleCount);
+ pToProcess = pProcessed;
+ }
+
+ /*
+ * Bypass mode or everything off, so copy the input to the output
+ */
+ if (pToProcess != pProcessed)
+ {
+#ifdef SUPPORT_MC
+ Copy_Float(pToProcess, /* Source */
+ pProcessed, /* Destination */
+ (LVM_INT16)(NrChannels * NrFrames)); /* Copy all samples */
+#else
+ Copy_Float(pToProcess, /* Source */
+ pProcessed, /* Destination */
+ (LVM_INT16)(2 * SampleCount)); /* Left and right */
+#endif
+ }
+
+ /*
+ * Apply treble boost if required
+ */
+ if (pInstance->TE_Active == LVM_TRUE)
+ {
+ /*
+ * Apply the filter
+ */
+#ifdef SUPPORT_MC
+ FO_Mc_D16F32C15_LShx_TRC_WRA_01(&pInstance->pTE_State->TrebleBoost_State,
+ pProcessed,
+ pProcessed,
+ (LVM_INT16)NrFrames,
+ (LVM_INT16)NrChannels);
+#else
+ FO_2I_D16F32C15_LShx_TRC_WRA_01(&pInstance->pTE_State->TrebleBoost_State,
+ pProcessed,
+ pProcessed,
+ (LVM_INT16)SampleCount);
+#endif
+
+ }
+#ifdef SUPPORT_MC
+ /*
+ * Volume balance
+ */
+ LVC_MixSoft_1St_MC_float_SAT(&pInstance->VC_BalanceMix,
+ pProcessed,
+ pProcessed,
+ NrFrames,
+ NrChannels,
+ ChMask);
+#else
+ /*
+ * Volume balance
+ */
+ LVC_MixSoft_1St_2i_D16C31_SAT(&pInstance->VC_BalanceMix,
+ pProcessed,
+ pProcessed,
+ SampleCount);
+#endif
+
+ /*
+ * Perform Parametric Spectum Analysis
+ */
+ if ((pInstance->Params.PSA_Enable == LVM_PSA_ON) &&
+ (pInstance->InstParams.PSA_Included == LVM_PSA_ON))
+ {
+#ifdef SUPPORT_MC
+ FromMcToMono_Float(pProcessed,
+ pInstance->pPSAInput,
+ (LVM_INT16)(NrFrames),
+ NrChannels);
+#else
+ From2iToMono_Float(pProcessed,
+ pInstance->pPSAInput,
+ (LVM_INT16)(SampleCount));
+#endif
+
+ LVPSA_Process(pInstance->hPSAInstance,
+ pInstance->pPSAInput,
+ (LVM_UINT16)(SampleCount),
+ AudioTime);
+ }
+
+ /*
+ * DC removal
+ */
+#ifdef SUPPORT_MC
+ DC_Mc_D16_TRC_WRA_01(&pInstance->DC_RemovalInstance,
+ pProcessed,
+ pProcessed,
+ (LVM_INT16)NrFrames,
+ NrChannels);
+#else
+ DC_2I_D16_TRC_WRA_01(&pInstance->DC_RemovalInstance,
+ pProcessed,
+ pProcessed,
+ (LVM_INT16)SampleCount);
+#endif
+ }
+ /*
+ * Manage the output buffer
+ */
+ LVM_BufferOut(hInstance,
+ pOutData,
+ &SampleCount);
+
+ }
+
+ return(LVM_SUCCESS);
+}
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Tables.c b/media/libeffects/lvm/lib/Bundle/src/LVM_Tables.c
deleted file mode 100644
index a5356d2..0000000
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Tables.c
+++ /dev/null
@@ -1,830 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/************************************************************************************/
-/* */
-/* Includes */
-/* */
-/************************************************************************************/
-
-#include "LVM_Tables.h"
-#include "LVM_Coeffs.h"
-
-/************************************************************************************/
-/* */
-/* Treble Boost Filter Coefficients */
-/* */
-/************************************************************************************/
-#ifdef BUILD_FLOAT
-
-FO_FLOAT_LShx_Coefs_t LVM_TrebleBoostCoefs[] = {
-
- /* 22kHz sampling rate */
- {HPF_Fs22050_Gain1_A1, /* Gain setting 1 */
- HPF_Fs22050_Gain1_A0,
- -HPF_Fs22050_Gain1_B1},
- {HPF_Fs22050_Gain2_A1, /* Gain setting 2 */
- HPF_Fs22050_Gain2_A0,
- -HPF_Fs22050_Gain2_B1},
- {HPF_Fs22050_Gain3_A1, /* Gain setting 3 */
- HPF_Fs22050_Gain3_A0,
- -HPF_Fs22050_Gain3_B1},
- {HPF_Fs22050_Gain4_A1, /* Gain setting 4 */
- HPF_Fs22050_Gain4_A0,
- -HPF_Fs22050_Gain4_B1},
- {HPF_Fs22050_Gain5_A1, /* Gain setting 5 */
- HPF_Fs22050_Gain5_A0,
- -HPF_Fs22050_Gain5_B1},
- {HPF_Fs22050_Gain6_A1, /* Gain setting 6 */
- HPF_Fs22050_Gain6_A0,
- -HPF_Fs22050_Gain6_B1},
- {HPF_Fs22050_Gain7_A1, /* Gain setting 7 */
- HPF_Fs22050_Gain7_A0,
- -HPF_Fs22050_Gain7_B1},
- {HPF_Fs22050_Gain8_A1, /* Gain setting 8 */
- HPF_Fs22050_Gain8_A0,
- -HPF_Fs22050_Gain8_B1},
- {HPF_Fs22050_Gain9_A1, /* Gain setting 9 */
- HPF_Fs22050_Gain9_A0,
- -HPF_Fs22050_Gain9_B1},
- {HPF_Fs22050_Gain10_A1, /* Gain setting 10 */
- HPF_Fs22050_Gain10_A0,
- -HPF_Fs22050_Gain10_B1},
- {HPF_Fs22050_Gain11_A1, /* Gain setting 11 */
- HPF_Fs22050_Gain11_A0,
- -HPF_Fs22050_Gain11_B1},
- {HPF_Fs22050_Gain12_A1, /* Gain setting 12 */
- HPF_Fs22050_Gain12_A0,
- -HPF_Fs22050_Gain12_B1},
- {HPF_Fs22050_Gain13_A1, /* Gain setting 13 */
- HPF_Fs22050_Gain13_A0,
- -HPF_Fs22050_Gain13_B1},
- {HPF_Fs22050_Gain14_A1, /* Gain setting 14 */
- HPF_Fs22050_Gain14_A0,
- -HPF_Fs22050_Gain14_B1},
- {HPF_Fs22050_Gain15_A1, /* Gain setting 15 */
- HPF_Fs22050_Gain15_A0,
- -HPF_Fs22050_Gain15_B1},
-
- /* 24kHz sampling rate */
- {HPF_Fs24000_Gain1_A1, /* Gain setting 1 */
- HPF_Fs24000_Gain1_A0,
- -HPF_Fs24000_Gain1_B1},
- {HPF_Fs24000_Gain2_A1, /* Gain setting 2 */
- HPF_Fs24000_Gain2_A0,
- -HPF_Fs24000_Gain2_B1},
- {HPF_Fs24000_Gain3_A1, /* Gain setting 3 */
- HPF_Fs24000_Gain3_A0,
- -HPF_Fs24000_Gain3_B1},
- {HPF_Fs24000_Gain4_A1, /* Gain setting 4 */
- HPF_Fs24000_Gain4_A0,
- -HPF_Fs24000_Gain4_B1},
- {HPF_Fs24000_Gain5_A1, /* Gain setting 5 */
- HPF_Fs24000_Gain5_A0,
- -HPF_Fs24000_Gain5_B1},
- {HPF_Fs24000_Gain6_A1, /* Gain setting 6 */
- HPF_Fs24000_Gain6_A0,
- -HPF_Fs24000_Gain6_B1},
- {HPF_Fs24000_Gain7_A1, /* Gain setting 7 */
- HPF_Fs24000_Gain7_A0,
- -HPF_Fs24000_Gain7_B1},
- {HPF_Fs24000_Gain8_A1, /* Gain setting 8 */
- HPF_Fs24000_Gain8_A0,
- -HPF_Fs24000_Gain8_B1},
- {HPF_Fs24000_Gain9_A1, /* Gain setting 9 */
- HPF_Fs24000_Gain9_A0,
- -HPF_Fs24000_Gain9_B1},
- {HPF_Fs24000_Gain10_A1, /* Gain setting 10 */
- HPF_Fs24000_Gain10_A0,
- -HPF_Fs24000_Gain10_B1},
- {HPF_Fs24000_Gain11_A1, /* Gain setting 11 */
- HPF_Fs24000_Gain11_A0,
- -HPF_Fs24000_Gain11_B1},
- {HPF_Fs24000_Gain12_A1, /* Gain setting 12 */
- HPF_Fs24000_Gain12_A0,
- -HPF_Fs24000_Gain12_B1},
- {HPF_Fs24000_Gain13_A1, /* Gain setting 13 */
- HPF_Fs24000_Gain13_A0,
- -HPF_Fs24000_Gain13_B1},
- {HPF_Fs24000_Gain14_A1, /* Gain setting 14 */
- HPF_Fs24000_Gain14_A0,
- -HPF_Fs24000_Gain14_B1},
- {HPF_Fs24000_Gain15_A1, /* Gain setting 15 */
- HPF_Fs24000_Gain15_A0,
- -HPF_Fs24000_Gain15_B1},
-
- /* 32kHz sampling rate */
- {HPF_Fs32000_Gain1_A1, /* Gain setting 1 */
- HPF_Fs32000_Gain1_A0,
- -HPF_Fs32000_Gain1_B1},
- {HPF_Fs32000_Gain2_A1, /* Gain setting 2 */
- HPF_Fs32000_Gain2_A0,
- -HPF_Fs32000_Gain2_B1},
- {HPF_Fs32000_Gain3_A1, /* Gain setting 3 */
- HPF_Fs32000_Gain3_A0,
- -HPF_Fs32000_Gain3_B1},
- {HPF_Fs32000_Gain4_A1, /* Gain setting 4 */
- HPF_Fs32000_Gain4_A0,
- -HPF_Fs32000_Gain4_B1},
- {HPF_Fs32000_Gain5_A1, /* Gain setting 5 */
- HPF_Fs32000_Gain5_A0,
- -HPF_Fs32000_Gain5_B1},
- {HPF_Fs32000_Gain6_A1, /* Gain setting 6 */
- HPF_Fs32000_Gain6_A0,
- -HPF_Fs32000_Gain6_B1},
- {HPF_Fs32000_Gain7_A1, /* Gain setting 7 */
- HPF_Fs32000_Gain7_A0,
- -HPF_Fs32000_Gain7_B1},
- {HPF_Fs32000_Gain8_A1, /* Gain setting 8 */
- HPF_Fs32000_Gain8_A0,
- -HPF_Fs32000_Gain8_B1},
- {HPF_Fs32000_Gain9_A1, /* Gain setting 9 */
- HPF_Fs32000_Gain9_A0,
- -HPF_Fs32000_Gain9_B1},
- {HPF_Fs32000_Gain10_A1, /* Gain setting 10 */
- HPF_Fs32000_Gain10_A0,
- -HPF_Fs32000_Gain10_B1},
- {HPF_Fs32000_Gain11_A1, /* Gain setting 11 */
- HPF_Fs32000_Gain11_A0,
- -HPF_Fs32000_Gain11_B1},
- {HPF_Fs32000_Gain12_A1, /* Gain setting 12 */
- HPF_Fs32000_Gain12_A0,
- -HPF_Fs32000_Gain12_B1},
- {HPF_Fs32000_Gain13_A1, /* Gain setting 13 */
- HPF_Fs32000_Gain13_A0,
- -HPF_Fs32000_Gain13_B1},
- {HPF_Fs32000_Gain14_A1, /* Gain setting 14 */
- HPF_Fs32000_Gain14_A0,
- -HPF_Fs32000_Gain14_B1},
- {HPF_Fs32000_Gain15_A1, /* Gain setting 15 */
- HPF_Fs32000_Gain15_A0,
- -HPF_Fs32000_Gain15_B1},
-
- /* 44kHz sampling rate */
- {HPF_Fs44100_Gain1_A1, /* Gain setting 1 */
- HPF_Fs44100_Gain1_A0,
- -HPF_Fs44100_Gain1_B1,},
- {HPF_Fs44100_Gain2_A1, /* Gain setting 2 */
- HPF_Fs44100_Gain2_A0,
- -HPF_Fs44100_Gain2_B1},
- {HPF_Fs44100_Gain3_A1, /* Gain setting 3 */
- HPF_Fs44100_Gain3_A0,
- -HPF_Fs44100_Gain3_B1},
- {HPF_Fs44100_Gain4_A1, /* Gain setting 4 */
- HPF_Fs44100_Gain4_A0,
- -HPF_Fs44100_Gain4_B1},
- {HPF_Fs44100_Gain5_A1, /* Gain setting 5 */
- HPF_Fs44100_Gain5_A0,
- -HPF_Fs44100_Gain5_B1},
- {HPF_Fs44100_Gain6_A1, /* Gain setting 6 */
- HPF_Fs44100_Gain6_A0,
- -HPF_Fs44100_Gain6_B1},
- {HPF_Fs44100_Gain7_A1, /* Gain setting 7 */
- HPF_Fs44100_Gain7_A0,
- -HPF_Fs44100_Gain7_B1},
- {HPF_Fs44100_Gain8_A1, /* Gain setting 8 */
- HPF_Fs44100_Gain8_A0,
- -HPF_Fs44100_Gain8_B1},
- {HPF_Fs44100_Gain9_A1, /* Gain setting 9 */
- HPF_Fs44100_Gain9_A0,
- -HPF_Fs44100_Gain9_B1},
- {HPF_Fs44100_Gain10_A1, /* Gain setting 10 */
- HPF_Fs44100_Gain10_A0,
- -HPF_Fs44100_Gain10_B1},
- {HPF_Fs44100_Gain11_A1, /* Gain setting 11 */
- HPF_Fs44100_Gain11_A0,
- -HPF_Fs44100_Gain11_B1},
- {HPF_Fs44100_Gain12_A1, /* Gain setting 12 */
- HPF_Fs44100_Gain12_A0,
- -HPF_Fs44100_Gain12_B1},
- {HPF_Fs44100_Gain13_A1, /* Gain setting 13 */
- HPF_Fs44100_Gain13_A0,
- -HPF_Fs44100_Gain13_B1},
- {HPF_Fs44100_Gain14_A1, /* Gain setting 14 */
- HPF_Fs44100_Gain14_A0,
- -HPF_Fs44100_Gain14_B1},
- {HPF_Fs44100_Gain15_A1, /* Gain setting 15 */
- HPF_Fs44100_Gain15_A0,
- -HPF_Fs44100_Gain15_B1},
-
- /* 48kHz sampling rate */
- {HPF_Fs48000_Gain1_A1, /* Gain setting 1 */
- HPF_Fs48000_Gain1_A0,
- -HPF_Fs48000_Gain1_B1},
- {HPF_Fs48000_Gain2_A1, /* Gain setting 2 */
- HPF_Fs48000_Gain2_A0,
- -HPF_Fs48000_Gain2_B1},
- {HPF_Fs48000_Gain3_A1, /* Gain setting 3 */
- HPF_Fs48000_Gain3_A0,
- -HPF_Fs48000_Gain3_B1},
- {HPF_Fs48000_Gain4_A1, /* Gain setting 4 */
- HPF_Fs48000_Gain4_A0,
- -HPF_Fs48000_Gain4_B1},
- {HPF_Fs48000_Gain5_A1, /* Gain setting 5 */
- HPF_Fs48000_Gain5_A0,
- -HPF_Fs48000_Gain5_B1},
- {HPF_Fs48000_Gain6_A1, /* Gain setting 6 */
- HPF_Fs48000_Gain6_A0,
- -HPF_Fs48000_Gain6_B1},
- {HPF_Fs48000_Gain7_A1, /* Gain setting 7 */
- HPF_Fs48000_Gain7_A0,
- -HPF_Fs48000_Gain7_B1},
- {HPF_Fs48000_Gain8_A1, /* Gain setting 8 */
- HPF_Fs48000_Gain8_A0,
- -HPF_Fs48000_Gain8_B1},
- {HPF_Fs48000_Gain9_A1, /* Gain setting 9 */
- HPF_Fs48000_Gain9_A0,
- -HPF_Fs48000_Gain9_B1},
- {HPF_Fs48000_Gain10_A1, /* Gain setting 10 */
- HPF_Fs48000_Gain10_A0,
- -HPF_Fs48000_Gain10_B1},
- {HPF_Fs48000_Gain11_A1, /* Gain setting 11 */
- HPF_Fs48000_Gain11_A0,
- -HPF_Fs48000_Gain11_B1},
- {HPF_Fs48000_Gain12_A1, /* Gain setting 12 */
- HPF_Fs48000_Gain12_A0,
- -HPF_Fs48000_Gain12_B1},
- {HPF_Fs48000_Gain13_A1, /* Gain setting 13 */
- HPF_Fs48000_Gain13_A0,
- -HPF_Fs48000_Gain13_B1},
- {HPF_Fs48000_Gain14_A1, /* Gain setting 14 */
- HPF_Fs48000_Gain14_A0,
- -HPF_Fs48000_Gain14_B1},
- {HPF_Fs48000_Gain15_A1, /* Gain setting 15 */
- HPF_Fs48000_Gain15_A0,
- -HPF_Fs48000_Gain15_B1}
-#ifdef HIGHER_FS
- ,
- /* 88kHz Sampling rate */
- {HPF_Fs88200_Gain1_A1, /* Gain Setting 1 */
- HPF_Fs88200_Gain1_A0,
- -HPF_Fs88200_Gain1_B1},
- {HPF_Fs88200_Gain2_A1, /* Gain Setting 2 */
- HPF_Fs88200_Gain2_A0,
- -HPF_Fs88200_Gain2_B1},
- {HPF_Fs88200_Gain3_A1, /* Gain Setting 3 */
- HPF_Fs88200_Gain3_A0,
- -HPF_Fs88200_Gain3_B1},
- {HPF_Fs88200_Gain4_A1, /* Gain Setting 4 */
- HPF_Fs88200_Gain4_A0,
- -HPF_Fs88200_Gain4_B1},
- {HPF_Fs88200_Gain5_A1, /* Gain Setting 5 */
- HPF_Fs88200_Gain5_A0,
- -HPF_Fs88200_Gain5_B1},
- {HPF_Fs88200_Gain6_A1, /* Gain Setting 6 */
- HPF_Fs88200_Gain6_A0,
- -HPF_Fs88200_Gain6_B1},
- {HPF_Fs88200_Gain7_A1, /* Gain Setting 7 */
- HPF_Fs88200_Gain7_A0,
- -HPF_Fs88200_Gain7_B1},
- {HPF_Fs88200_Gain8_A1, /* Gain Setting 8 */
- HPF_Fs88200_Gain8_A0,
- -HPF_Fs88200_Gain8_B1},
- {HPF_Fs88200_Gain9_A1, /* Gain Setting 9 */
- HPF_Fs88200_Gain9_A0,
- -HPF_Fs88200_Gain9_B1},
- {HPF_Fs88200_Gain10_A1, /* Gain Setting 10 */
- HPF_Fs88200_Gain10_A0,
- -HPF_Fs88200_Gain10_B1},
- {HPF_Fs88200_Gain11_A1, /* Gain Setting 11 */
- HPF_Fs88200_Gain11_A0,
- -HPF_Fs88200_Gain11_B1},
- {HPF_Fs88200_Gain12_A1, /* Gain Setting 12 */
- HPF_Fs88200_Gain12_A0,
- -HPF_Fs88200_Gain12_B1},
- {HPF_Fs88200_Gain13_A1, /* Gain Setting 13 */
- HPF_Fs88200_Gain13_A0,
- -HPF_Fs88200_Gain13_B1},
- {HPF_Fs88200_Gain14_A1, /* Gain Setting 14 */
- HPF_Fs88200_Gain14_A0,
- -HPF_Fs88200_Gain14_B1},
- {HPF_Fs88200_Gain15_A1, /* Gain Setting 15 */
- HPF_Fs88200_Gain15_A0,
- -HPF_Fs88200_Gain15_B1},
-
- /* 96kHz sampling rate */
- {HPF_Fs96000_Gain1_A1, /* Gain setting 1 */
- HPF_Fs96000_Gain1_A0,
- -HPF_Fs96000_Gain1_B1},
- {HPF_Fs96000_Gain2_A1, /* Gain setting 2 */
- HPF_Fs96000_Gain2_A0,
- -HPF_Fs96000_Gain2_B1},
- {HPF_Fs96000_Gain3_A1, /* Gain setting 3 */
- HPF_Fs96000_Gain3_A0,
- -HPF_Fs96000_Gain3_B1},
- {HPF_Fs96000_Gain4_A1, /* Gain setting 4 */
- HPF_Fs96000_Gain4_A0,
- -HPF_Fs96000_Gain4_B1},
- {HPF_Fs96000_Gain5_A1, /* Gain setting 5 */
- HPF_Fs96000_Gain5_A0,
- -HPF_Fs96000_Gain5_B1},
- {HPF_Fs96000_Gain6_A1, /* Gain setting 6 */
- HPF_Fs96000_Gain6_A0,
- -HPF_Fs96000_Gain6_B1},
- {HPF_Fs96000_Gain7_A1, /* Gain setting 7 */
- HPF_Fs96000_Gain7_A0,
- -HPF_Fs96000_Gain7_B1},
- {HPF_Fs96000_Gain8_A1, /* Gain setting 8 */
- HPF_Fs96000_Gain8_A0,
- -HPF_Fs96000_Gain8_B1},
- {HPF_Fs96000_Gain9_A1, /* Gain setting 9 */
- HPF_Fs96000_Gain9_A0,
- -HPF_Fs96000_Gain9_B1},
- {HPF_Fs96000_Gain10_A1, /* Gain setting 10 */
- HPF_Fs96000_Gain10_A0,
- -HPF_Fs96000_Gain10_B1},
- {HPF_Fs96000_Gain11_A1, /* Gain setting 11 */
- HPF_Fs96000_Gain11_A0,
- -HPF_Fs96000_Gain11_B1},
- {HPF_Fs96000_Gain12_A1, /* Gain setting 12 */
- HPF_Fs96000_Gain12_A0,
- -HPF_Fs96000_Gain12_B1},
- {HPF_Fs96000_Gain13_A1, /* Gain setting 13 */
- HPF_Fs96000_Gain13_A0,
- -HPF_Fs96000_Gain13_B1},
- {HPF_Fs96000_Gain14_A1, /* Gain setting 14 */
- HPF_Fs96000_Gain14_A0,
- -HPF_Fs96000_Gain14_B1},
- {HPF_Fs96000_Gain15_A1, /* Gain setting 15 */
- HPF_Fs96000_Gain15_A0,
- -HPF_Fs96000_Gain15_B1},
-
- /* 176kHz Sampling rate */
- {HPF_Fs176400_Gain1_A1, /* Gain Setting 1 */
- HPF_Fs176400_Gain1_A0,
- -HPF_Fs176400_Gain1_B1},
- {HPF_Fs176400_Gain2_A1, /* Gain Setting 2 */
- HPF_Fs176400_Gain2_A0,
- -HPF_Fs176400_Gain2_B1},
- {HPF_Fs176400_Gain3_A1, /* Gain Setting 3 */
- HPF_Fs176400_Gain3_A0,
- -HPF_Fs176400_Gain3_B1},
- {HPF_Fs176400_Gain4_A1, /* Gain Setting 4 */
- HPF_Fs176400_Gain4_A0,
- -HPF_Fs176400_Gain4_B1},
- {HPF_Fs176400_Gain5_A1, /* Gain Setting 5 */
- HPF_Fs176400_Gain5_A0,
- -HPF_Fs176400_Gain5_B1},
- {HPF_Fs176400_Gain6_A1, /* Gain Setting 6 */
- HPF_Fs176400_Gain6_A0,
- -HPF_Fs176400_Gain6_B1},
- {HPF_Fs176400_Gain7_A1, /* Gain Setting 7 */
- HPF_Fs176400_Gain7_A0,
- -HPF_Fs176400_Gain7_B1},
- {HPF_Fs176400_Gain8_A1, /* Gain Setting 8 */
- HPF_Fs176400_Gain8_A0,
- -HPF_Fs176400_Gain8_B1},
- {HPF_Fs176400_Gain9_A1, /* Gain Setting 9 */
- HPF_Fs176400_Gain9_A0,
- -HPF_Fs176400_Gain9_B1},
- {HPF_Fs176400_Gain10_A1, /* Gain Setting 10 */
- HPF_Fs176400_Gain10_A0,
- -HPF_Fs176400_Gain10_B1},
- {HPF_Fs176400_Gain11_A1, /* Gain Setting 11 */
- HPF_Fs176400_Gain11_A0,
- -HPF_Fs176400_Gain11_B1},
- {HPF_Fs176400_Gain12_A1, /* Gain Setting 12 */
- HPF_Fs176400_Gain12_A0,
- -HPF_Fs176400_Gain12_B1},
- {HPF_Fs176400_Gain13_A1, /* Gain Setting 13 */
- HPF_Fs176400_Gain13_A0,
- -HPF_Fs176400_Gain13_B1},
- {HPF_Fs176400_Gain14_A1, /* Gain Setting 14 */
- HPF_Fs176400_Gain14_A0,
- -HPF_Fs176400_Gain14_B1},
- {HPF_Fs176400_Gain15_A1, /* Gain Setting 15 */
- HPF_Fs176400_Gain15_A0,
- -HPF_Fs176400_Gain15_B1},
-
- /* 192kHz sampling rate */
- {HPF_Fs192000_Gain1_A1, /* Gain setting 1 */
- HPF_Fs192000_Gain1_A0,
- -HPF_Fs192000_Gain1_B1},
- {HPF_Fs192000_Gain2_A1, /* Gain setting 2 */
- HPF_Fs192000_Gain2_A0,
- -HPF_Fs192000_Gain2_B1},
- {HPF_Fs192000_Gain3_A1, /* Gain setting 3 */
- HPF_Fs192000_Gain3_A0,
- -HPF_Fs192000_Gain3_B1},
- {HPF_Fs192000_Gain4_A1, /* Gain setting 4 */
- HPF_Fs192000_Gain4_A0,
- -HPF_Fs192000_Gain4_B1},
- {HPF_Fs192000_Gain5_A1, /* Gain setting 5 */
- HPF_Fs192000_Gain5_A0,
- -HPF_Fs192000_Gain5_B1},
- {HPF_Fs192000_Gain6_A1, /* Gain setting 6 */
- HPF_Fs192000_Gain6_A0,
- -HPF_Fs192000_Gain6_B1},
- {HPF_Fs192000_Gain7_A1, /* Gain setting 7 */
- HPF_Fs192000_Gain7_A0,
- -HPF_Fs192000_Gain7_B1},
- {HPF_Fs192000_Gain8_A1, /* Gain setting 8 */
- HPF_Fs192000_Gain8_A0,
- -HPF_Fs192000_Gain8_B1},
- {HPF_Fs192000_Gain9_A1, /* Gain setting 9 */
- HPF_Fs192000_Gain9_A0,
- -HPF_Fs192000_Gain9_B1},
- {HPF_Fs192000_Gain10_A1, /* Gain setting 10 */
- HPF_Fs192000_Gain10_A0,
- -HPF_Fs192000_Gain10_B1},
- {HPF_Fs192000_Gain11_A1, /* Gain setting 11 */
- HPF_Fs192000_Gain11_A0,
- -HPF_Fs192000_Gain11_B1},
- {HPF_Fs192000_Gain12_A1, /* Gain setting 12 */
- HPF_Fs192000_Gain12_A0,
- -HPF_Fs192000_Gain12_B1},
- {HPF_Fs192000_Gain13_A1, /* Gain setting 13 */
- HPF_Fs192000_Gain13_A0,
- -HPF_Fs192000_Gain13_B1},
- {HPF_Fs192000_Gain14_A1, /* Gain setting 14 */
- HPF_Fs192000_Gain14_A0,
- -HPF_Fs192000_Gain14_B1},
- {HPF_Fs192000_Gain15_A1, /* Gain setting 15 */
- HPF_Fs192000_Gain15_A0,
- -HPF_Fs192000_Gain15_B1}
-#endif
- };
-#else
-FO_C16_LShx_Coefs_t LVM_TrebleBoostCoefs[] = {
-
- /* 22kHz sampling rate */
- {HPF_Fs22050_Gain1_A1, /* Gain setting 1 */
- HPF_Fs22050_Gain1_A0,
- -HPF_Fs22050_Gain1_B1,
- HPF_Fs22050_Gain1_Shift},
- {HPF_Fs22050_Gain2_A1, /* Gain setting 2 */
- HPF_Fs22050_Gain2_A0,
- -HPF_Fs22050_Gain2_B1,
- HPF_Fs22050_Gain2_Shift},
- {HPF_Fs22050_Gain3_A1, /* Gain setting 3 */
- HPF_Fs22050_Gain3_A0,
- -HPF_Fs22050_Gain3_B1,
- HPF_Fs22050_Gain3_Shift},
- {HPF_Fs22050_Gain4_A1, /* Gain setting 4 */
- HPF_Fs22050_Gain4_A0,
- -HPF_Fs22050_Gain4_B1,
- HPF_Fs22050_Gain4_Shift},
- {HPF_Fs22050_Gain5_A1, /* Gain setting 5 */
- HPF_Fs22050_Gain5_A0,
- -HPF_Fs22050_Gain5_B1,
- HPF_Fs22050_Gain5_Shift},
- {HPF_Fs22050_Gain6_A1, /* Gain setting 6 */
- HPF_Fs22050_Gain6_A0,
- -HPF_Fs22050_Gain6_B1,
- HPF_Fs22050_Gain6_Shift},
- {HPF_Fs22050_Gain7_A1, /* Gain setting 7 */
- HPF_Fs22050_Gain7_A0,
- -HPF_Fs22050_Gain7_B1,
- HPF_Fs22050_Gain7_Shift},
- {HPF_Fs22050_Gain8_A1, /* Gain setting 8 */
- HPF_Fs22050_Gain8_A0,
- -HPF_Fs22050_Gain8_B1,
- HPF_Fs22050_Gain8_Shift},
- {HPF_Fs22050_Gain9_A1, /* Gain setting 9 */
- HPF_Fs22050_Gain9_A0,
- -HPF_Fs22050_Gain9_B1,
- HPF_Fs22050_Gain9_Shift},
- {HPF_Fs22050_Gain10_A1, /* Gain setting 10 */
- HPF_Fs22050_Gain10_A0,
- -HPF_Fs22050_Gain10_B1,
- HPF_Fs22050_Gain10_Shift},
- {HPF_Fs22050_Gain11_A1, /* Gain setting 11 */
- HPF_Fs22050_Gain11_A0,
- -HPF_Fs22050_Gain11_B1,
- HPF_Fs22050_Gain11_Shift},
- {HPF_Fs22050_Gain12_A1, /* Gain setting 12 */
- HPF_Fs22050_Gain12_A0,
- -HPF_Fs22050_Gain12_B1,
- HPF_Fs22050_Gain12_Shift},
- {HPF_Fs22050_Gain13_A1, /* Gain setting 13 */
- HPF_Fs22050_Gain13_A0,
- -HPF_Fs22050_Gain13_B1,
- HPF_Fs22050_Gain13_Shift},
- {HPF_Fs22050_Gain14_A1, /* Gain setting 14 */
- HPF_Fs22050_Gain14_A0,
- -HPF_Fs22050_Gain14_B1,
- HPF_Fs22050_Gain14_Shift},
- {HPF_Fs22050_Gain15_A1, /* Gain setting 15 */
- HPF_Fs22050_Gain15_A0,
- -HPF_Fs22050_Gain15_B1,
- HPF_Fs22050_Gain15_Shift},
-
- /* 24kHz sampling rate */
- {HPF_Fs24000_Gain1_A1, /* Gain setting 1 */
- HPF_Fs24000_Gain1_A0,
- -HPF_Fs24000_Gain1_B1,
- HPF_Fs24000_Gain1_Shift},
- {HPF_Fs24000_Gain2_A1, /* Gain setting 2 */
- HPF_Fs24000_Gain2_A0,
- -HPF_Fs24000_Gain2_B1,
- HPF_Fs24000_Gain2_Shift},
- {HPF_Fs24000_Gain3_A1, /* Gain setting 3 */
- HPF_Fs24000_Gain3_A0,
- -HPF_Fs24000_Gain3_B1,
- HPF_Fs24000_Gain3_Shift},
- {HPF_Fs24000_Gain4_A1, /* Gain setting 4 */
- HPF_Fs24000_Gain4_A0,
- -HPF_Fs24000_Gain4_B1,
- HPF_Fs24000_Gain4_Shift},
- {HPF_Fs24000_Gain5_A1, /* Gain setting 5 */
- HPF_Fs24000_Gain5_A0,
- -HPF_Fs24000_Gain5_B1,
- HPF_Fs24000_Gain5_Shift},
- {HPF_Fs24000_Gain6_A1, /* Gain setting 6 */
- HPF_Fs24000_Gain6_A0,
- -HPF_Fs24000_Gain6_B1,
- HPF_Fs24000_Gain6_Shift},
- {HPF_Fs24000_Gain7_A1, /* Gain setting 7 */
- HPF_Fs24000_Gain7_A0,
- -HPF_Fs24000_Gain7_B1,
- HPF_Fs24000_Gain7_Shift},
- {HPF_Fs24000_Gain8_A1, /* Gain setting 8 */
- HPF_Fs24000_Gain8_A0,
- -HPF_Fs24000_Gain8_B1,
- HPF_Fs24000_Gain8_Shift},
- {HPF_Fs24000_Gain9_A1, /* Gain setting 9 */
- HPF_Fs24000_Gain9_A0,
- -HPF_Fs24000_Gain9_B1,
- HPF_Fs24000_Gain9_Shift},
- {HPF_Fs24000_Gain10_A1, /* Gain setting 10 */
- HPF_Fs24000_Gain10_A0,
- -HPF_Fs24000_Gain10_B1,
- HPF_Fs24000_Gain10_Shift},
- {HPF_Fs24000_Gain11_A1, /* Gain setting 11 */
- HPF_Fs24000_Gain11_A0,
- -HPF_Fs24000_Gain11_B1,
- HPF_Fs24000_Gain11_Shift},
- {HPF_Fs24000_Gain12_A1, /* Gain setting 12 */
- HPF_Fs24000_Gain12_A0,
- -HPF_Fs24000_Gain12_B1,
- HPF_Fs24000_Gain12_Shift},
- {HPF_Fs24000_Gain13_A1, /* Gain setting 13 */
- HPF_Fs24000_Gain13_A0,
- -HPF_Fs24000_Gain13_B1,
- HPF_Fs24000_Gain13_Shift},
- {HPF_Fs24000_Gain14_A1, /* Gain setting 14 */
- HPF_Fs24000_Gain14_A0,
- -HPF_Fs24000_Gain14_B1,
- HPF_Fs24000_Gain14_Shift},
- {HPF_Fs24000_Gain15_A1, /* Gain setting 15 */
- HPF_Fs24000_Gain15_A0,
- -HPF_Fs24000_Gain15_B1,
- HPF_Fs24000_Gain15_Shift},
-
- /* 32kHz sampling rate */
- {HPF_Fs32000_Gain1_A1, /* Gain setting 1 */
- HPF_Fs32000_Gain1_A0,
- -HPF_Fs32000_Gain1_B1,
- HPF_Fs32000_Gain1_Shift},
- {HPF_Fs32000_Gain2_A1, /* Gain setting 2 */
- HPF_Fs32000_Gain2_A0,
- -HPF_Fs32000_Gain2_B1,
- HPF_Fs32000_Gain2_Shift},
- {HPF_Fs32000_Gain3_A1, /* Gain setting 3 */
- HPF_Fs32000_Gain3_A0,
- -HPF_Fs32000_Gain3_B1,
- HPF_Fs32000_Gain3_Shift},
- {HPF_Fs32000_Gain4_A1, /* Gain setting 4 */
- HPF_Fs32000_Gain4_A0,
- -HPF_Fs32000_Gain4_B1,
- HPF_Fs32000_Gain4_Shift},
- {HPF_Fs32000_Gain5_A1, /* Gain setting 5 */
- HPF_Fs32000_Gain5_A0,
- -HPF_Fs32000_Gain5_B1,
- HPF_Fs32000_Gain5_Shift},
- {HPF_Fs32000_Gain6_A1, /* Gain setting 6 */
- HPF_Fs32000_Gain6_A0,
- -HPF_Fs32000_Gain6_B1,
- HPF_Fs32000_Gain6_Shift},
- {HPF_Fs32000_Gain7_A1, /* Gain setting 7 */
- HPF_Fs32000_Gain7_A0,
- -HPF_Fs32000_Gain7_B1,
- HPF_Fs32000_Gain7_Shift},
- {HPF_Fs32000_Gain8_A1, /* Gain setting 8 */
- HPF_Fs32000_Gain8_A0,
- -HPF_Fs32000_Gain8_B1,
- HPF_Fs32000_Gain8_Shift},
- {HPF_Fs32000_Gain9_A1, /* Gain setting 9 */
- HPF_Fs32000_Gain9_A0,
- -HPF_Fs32000_Gain9_B1,
- HPF_Fs32000_Gain9_Shift},
- {HPF_Fs32000_Gain10_A1, /* Gain setting 10 */
- HPF_Fs32000_Gain10_A0,
- -HPF_Fs32000_Gain10_B1,
- HPF_Fs32000_Gain10_Shift},
- {HPF_Fs32000_Gain11_A1, /* Gain setting 11 */
- HPF_Fs32000_Gain11_A0,
- -HPF_Fs32000_Gain11_B1,
- HPF_Fs32000_Gain11_Shift},
- {HPF_Fs32000_Gain12_A1, /* Gain setting 12 */
- HPF_Fs32000_Gain12_A0,
- -HPF_Fs32000_Gain12_B1,
- HPF_Fs32000_Gain12_Shift},
- {HPF_Fs32000_Gain13_A1, /* Gain setting 13 */
- HPF_Fs32000_Gain13_A0,
- -HPF_Fs32000_Gain13_B1,
- HPF_Fs32000_Gain13_Shift},
- {HPF_Fs32000_Gain14_A1, /* Gain setting 14 */
- HPF_Fs32000_Gain14_A0,
- -HPF_Fs32000_Gain14_B1,
- HPF_Fs32000_Gain14_Shift},
- {HPF_Fs32000_Gain15_A1, /* Gain setting 15 */
- HPF_Fs32000_Gain15_A0,
- -HPF_Fs32000_Gain15_B1,
- HPF_Fs32000_Gain15_Shift},
-
- /* 44kHz sampling rate */
- {HPF_Fs44100_Gain1_A1, /* Gain setting 1 */
- HPF_Fs44100_Gain1_A0,
- -HPF_Fs44100_Gain1_B1,
- HPF_Fs44100_Gain1_Shift},
- {HPF_Fs44100_Gain2_A1, /* Gain setting 2 */
- HPF_Fs44100_Gain2_A0,
- -HPF_Fs44100_Gain2_B1,
- HPF_Fs44100_Gain2_Shift},
- {HPF_Fs44100_Gain3_A1, /* Gain setting 3 */
- HPF_Fs44100_Gain3_A0,
- -HPF_Fs44100_Gain3_B1,
- HPF_Fs44100_Gain3_Shift},
- {HPF_Fs44100_Gain4_A1, /* Gain setting 4 */
- HPF_Fs44100_Gain4_A0,
- -HPF_Fs44100_Gain4_B1,
- HPF_Fs44100_Gain4_Shift},
- {HPF_Fs44100_Gain5_A1, /* Gain setting 5 */
- HPF_Fs44100_Gain5_A0,
- -HPF_Fs44100_Gain5_B1,
- HPF_Fs44100_Gain5_Shift},
- {HPF_Fs44100_Gain6_A1, /* Gain setting 6 */
- HPF_Fs44100_Gain6_A0,
- -HPF_Fs44100_Gain6_B1,
- HPF_Fs44100_Gain6_Shift},
- {HPF_Fs44100_Gain7_A1, /* Gain setting 7 */
- HPF_Fs44100_Gain7_A0,
- -HPF_Fs44100_Gain7_B1,
- HPF_Fs44100_Gain7_Shift},
- {HPF_Fs44100_Gain8_A1, /* Gain setting 8 */
- HPF_Fs44100_Gain8_A0,
- -HPF_Fs44100_Gain8_B1,
- HPF_Fs44100_Gain8_Shift},
- {HPF_Fs44100_Gain9_A1, /* Gain setting 9 */
- HPF_Fs44100_Gain9_A0,
- -HPF_Fs44100_Gain9_B1,
- HPF_Fs44100_Gain9_Shift},
- {HPF_Fs44100_Gain10_A1, /* Gain setting 10 */
- HPF_Fs44100_Gain10_A0,
- -HPF_Fs44100_Gain10_B1,
- HPF_Fs44100_Gain10_Shift},
- {HPF_Fs44100_Gain11_A1, /* Gain setting 11 */
- HPF_Fs44100_Gain11_A0,
- -HPF_Fs44100_Gain11_B1,
- HPF_Fs44100_Gain11_Shift},
- {HPF_Fs44100_Gain12_A1, /* Gain setting 12 */
- HPF_Fs44100_Gain12_A0,
- -HPF_Fs44100_Gain12_B1,
- HPF_Fs44100_Gain12_Shift},
- {HPF_Fs44100_Gain13_A1, /* Gain setting 13 */
- HPF_Fs44100_Gain13_A0,
- -HPF_Fs44100_Gain13_B1,
- HPF_Fs44100_Gain13_Shift},
- {HPF_Fs44100_Gain14_A1, /* Gain setting 14 */
- HPF_Fs44100_Gain14_A0,
- -HPF_Fs44100_Gain14_B1,
- HPF_Fs44100_Gain14_Shift},
- {HPF_Fs44100_Gain15_A1, /* Gain setting 15 */
- HPF_Fs44100_Gain15_A0,
- -HPF_Fs44100_Gain15_B1,
- HPF_Fs44100_Gain15_Shift},
-
- /* 48kHz sampling rate */
- {HPF_Fs48000_Gain1_A1, /* Gain setting 1 */
- HPF_Fs48000_Gain1_A0,
- -HPF_Fs48000_Gain1_B1,
- HPF_Fs48000_Gain1_Shift},
- {HPF_Fs48000_Gain2_A1, /* Gain setting 2 */
- HPF_Fs48000_Gain2_A0,
- -HPF_Fs48000_Gain2_B1,
- HPF_Fs48000_Gain2_Shift},
- {HPF_Fs48000_Gain3_A1, /* Gain setting 3 */
- HPF_Fs48000_Gain3_A0,
- -HPF_Fs48000_Gain3_B1,
- HPF_Fs48000_Gain3_Shift},
- {HPF_Fs48000_Gain4_A1, /* Gain setting 4 */
- HPF_Fs48000_Gain4_A0,
- -HPF_Fs48000_Gain4_B1,
- HPF_Fs48000_Gain4_Shift},
- {HPF_Fs48000_Gain5_A1, /* Gain setting 5 */
- HPF_Fs48000_Gain5_A0,
- -HPF_Fs48000_Gain5_B1,
- HPF_Fs48000_Gain5_Shift},
- {HPF_Fs48000_Gain6_A1, /* Gain setting 6 */
- HPF_Fs48000_Gain6_A0,
- -HPF_Fs48000_Gain6_B1,
- HPF_Fs48000_Gain6_Shift},
- {HPF_Fs48000_Gain7_A1, /* Gain setting 7 */
- HPF_Fs48000_Gain7_A0,
- -HPF_Fs48000_Gain7_B1,
- HPF_Fs48000_Gain7_Shift},
- {HPF_Fs48000_Gain8_A1, /* Gain setting 8 */
- HPF_Fs48000_Gain8_A0,
- -HPF_Fs48000_Gain8_B1,
- HPF_Fs48000_Gain8_Shift},
- {HPF_Fs48000_Gain9_A1, /* Gain setting 9 */
- HPF_Fs48000_Gain9_A0,
- -HPF_Fs48000_Gain9_B1,
- HPF_Fs48000_Gain9_Shift},
- {HPF_Fs48000_Gain10_A1, /* Gain setting 10 */
- HPF_Fs48000_Gain10_A0,
- -HPF_Fs48000_Gain10_B1,
- HPF_Fs48000_Gain10_Shift},
- {HPF_Fs48000_Gain11_A1, /* Gain setting 11 */
- HPF_Fs48000_Gain11_A0,
- -HPF_Fs48000_Gain11_B1,
- HPF_Fs48000_Gain11_Shift},
- {HPF_Fs48000_Gain12_A1, /* Gain setting 12 */
- HPF_Fs48000_Gain12_A0,
- -HPF_Fs48000_Gain12_B1,
- HPF_Fs48000_Gain12_Shift},
- {HPF_Fs48000_Gain13_A1, /* Gain setting 13 */
- HPF_Fs48000_Gain13_A0,
- -HPF_Fs48000_Gain13_B1,
- HPF_Fs48000_Gain13_Shift},
- {HPF_Fs48000_Gain14_A1, /* Gain setting 14 */
- HPF_Fs48000_Gain14_A0,
- -HPF_Fs48000_Gain14_B1,
- HPF_Fs48000_Gain14_Shift},
- {HPF_Fs48000_Gain15_A1, /* Gain setting 15 */
- HPF_Fs48000_Gain15_A0,
- -HPF_Fs48000_Gain15_B1,
- HPF_Fs48000_Gain15_Shift}
- };
-#endif
-
-/************************************************************************************/
-/* */
-/* Volume control gain and time constant tables */
-/* */
-/************************************************************************************/
-
-/* dB to linear conversion table */
-#ifdef BUILD_FLOAT
-const LVM_FLOAT LVM_VolumeTable[] = {
- 1.000f, /* 0dB */
- 0.891f, /* -1dB */
- 0.794f, /* -2dB */
- 0.708f, /* -3dB */
- 0.631f, /* -4dB */
- 0.562f, /* -5dB */
- 0.501f}; /* -6dB */
-#else
-const LVM_INT16 LVM_VolumeTable[] = {
- 0x7FFF, /* 0dB */
- 0x7215, /* -1dB */
- 0x65AD, /* -2dB */
- 0x5A9E, /* -3dB */
- 0x50C3, /* -4dB */
- 0x47FB, /* -5dB */
- 0x4000}; /* -6dB */
-#endif
-
-/************************************************************************************/
-/* */
-/* Volume mixer time constants (100ms) */
-/* */
-/************************************************************************************/
-
-#define LVM_MIX_TC_Fs8000 32580 /* Floating point value 0.994262695 */
-#define LVM_MIX_TC_Fs11025 32632 /* Floating point value 0.995849609 */
-#define LVM_MIX_TC_Fs12000 32643 /* Floating point value 0.996185303 */
-#define LVM_MIX_TC_Fs16000 32674 /* Floating point value 0.997131348 */
-#define LVM_MIX_TC_Fs22050 32700 /* Floating point value 0.997924805 */
-#define LVM_MIX_TC_Fs24000 32705 /* Floating point value 0.998077393 */
-#define LVM_MIX_TC_Fs32000 32721 /* Floating point value 0.998565674 */
-#define LVM_MIX_TC_Fs44100 32734 /* Floating point value 0.998962402 */
-#define LVM_MIX_TC_Fs48000 32737 /* Floating point value 0.999053955 */
-
-
-const LVM_INT16 LVM_MixerTCTable[] = {
- LVM_MIX_TC_Fs8000,
- LVM_MIX_TC_Fs11025,
- LVM_MIX_TC_Fs12000,
- LVM_MIX_TC_Fs16000,
- LVM_MIX_TC_Fs22050,
- LVM_MIX_TC_Fs24000,
- LVM_MIX_TC_Fs32000,
- LVM_MIX_TC_Fs44100,
- LVM_MIX_TC_Fs48000};
-
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Tables.cpp b/media/libeffects/lvm/lib/Bundle/src/LVM_Tables.cpp
new file mode 100644
index 0000000..66392e2
--- /dev/null
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Tables.cpp
@@ -0,0 +1,501 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/************************************************************************************/
+/* */
+/* Includes */
+/* */
+/************************************************************************************/
+
+#include "LVM_Tables.h"
+#include "LVM_Coeffs.h"
+
+/************************************************************************************/
+/* */
+/* Treble Boost Filter Coefficients */
+/* */
+/************************************************************************************/
+
+FO_FLOAT_LShx_Coefs_t LVM_TrebleBoostCoefs[] = {
+
+ /* 22kHz sampling rate */
+ {HPF_Fs22050_Gain1_A1, /* Gain setting 1 */
+ HPF_Fs22050_Gain1_A0,
+ -HPF_Fs22050_Gain1_B1},
+ {HPF_Fs22050_Gain2_A1, /* Gain setting 2 */
+ HPF_Fs22050_Gain2_A0,
+ -HPF_Fs22050_Gain2_B1},
+ {HPF_Fs22050_Gain3_A1, /* Gain setting 3 */
+ HPF_Fs22050_Gain3_A0,
+ -HPF_Fs22050_Gain3_B1},
+ {HPF_Fs22050_Gain4_A1, /* Gain setting 4 */
+ HPF_Fs22050_Gain4_A0,
+ -HPF_Fs22050_Gain4_B1},
+ {HPF_Fs22050_Gain5_A1, /* Gain setting 5 */
+ HPF_Fs22050_Gain5_A0,
+ -HPF_Fs22050_Gain5_B1},
+ {HPF_Fs22050_Gain6_A1, /* Gain setting 6 */
+ HPF_Fs22050_Gain6_A0,
+ -HPF_Fs22050_Gain6_B1},
+ {HPF_Fs22050_Gain7_A1, /* Gain setting 7 */
+ HPF_Fs22050_Gain7_A0,
+ -HPF_Fs22050_Gain7_B1},
+ {HPF_Fs22050_Gain8_A1, /* Gain setting 8 */
+ HPF_Fs22050_Gain8_A0,
+ -HPF_Fs22050_Gain8_B1},
+ {HPF_Fs22050_Gain9_A1, /* Gain setting 9 */
+ HPF_Fs22050_Gain9_A0,
+ -HPF_Fs22050_Gain9_B1},
+ {HPF_Fs22050_Gain10_A1, /* Gain setting 10 */
+ HPF_Fs22050_Gain10_A0,
+ -HPF_Fs22050_Gain10_B1},
+ {HPF_Fs22050_Gain11_A1, /* Gain setting 11 */
+ HPF_Fs22050_Gain11_A0,
+ -HPF_Fs22050_Gain11_B1},
+ {HPF_Fs22050_Gain12_A1, /* Gain setting 12 */
+ HPF_Fs22050_Gain12_A0,
+ -HPF_Fs22050_Gain12_B1},
+ {HPF_Fs22050_Gain13_A1, /* Gain setting 13 */
+ HPF_Fs22050_Gain13_A0,
+ -HPF_Fs22050_Gain13_B1},
+ {HPF_Fs22050_Gain14_A1, /* Gain setting 14 */
+ HPF_Fs22050_Gain14_A0,
+ -HPF_Fs22050_Gain14_B1},
+ {HPF_Fs22050_Gain15_A1, /* Gain setting 15 */
+ HPF_Fs22050_Gain15_A0,
+ -HPF_Fs22050_Gain15_B1},
+
+ /* 24kHz sampling rate */
+ {HPF_Fs24000_Gain1_A1, /* Gain setting 1 */
+ HPF_Fs24000_Gain1_A0,
+ -HPF_Fs24000_Gain1_B1},
+ {HPF_Fs24000_Gain2_A1, /* Gain setting 2 */
+ HPF_Fs24000_Gain2_A0,
+ -HPF_Fs24000_Gain2_B1},
+ {HPF_Fs24000_Gain3_A1, /* Gain setting 3 */
+ HPF_Fs24000_Gain3_A0,
+ -HPF_Fs24000_Gain3_B1},
+ {HPF_Fs24000_Gain4_A1, /* Gain setting 4 */
+ HPF_Fs24000_Gain4_A0,
+ -HPF_Fs24000_Gain4_B1},
+ {HPF_Fs24000_Gain5_A1, /* Gain setting 5 */
+ HPF_Fs24000_Gain5_A0,
+ -HPF_Fs24000_Gain5_B1},
+ {HPF_Fs24000_Gain6_A1, /* Gain setting 6 */
+ HPF_Fs24000_Gain6_A0,
+ -HPF_Fs24000_Gain6_B1},
+ {HPF_Fs24000_Gain7_A1, /* Gain setting 7 */
+ HPF_Fs24000_Gain7_A0,
+ -HPF_Fs24000_Gain7_B1},
+ {HPF_Fs24000_Gain8_A1, /* Gain setting 8 */
+ HPF_Fs24000_Gain8_A0,
+ -HPF_Fs24000_Gain8_B1},
+ {HPF_Fs24000_Gain9_A1, /* Gain setting 9 */
+ HPF_Fs24000_Gain9_A0,
+ -HPF_Fs24000_Gain9_B1},
+ {HPF_Fs24000_Gain10_A1, /* Gain setting 10 */
+ HPF_Fs24000_Gain10_A0,
+ -HPF_Fs24000_Gain10_B1},
+ {HPF_Fs24000_Gain11_A1, /* Gain setting 11 */
+ HPF_Fs24000_Gain11_A0,
+ -HPF_Fs24000_Gain11_B1},
+ {HPF_Fs24000_Gain12_A1, /* Gain setting 12 */
+ HPF_Fs24000_Gain12_A0,
+ -HPF_Fs24000_Gain12_B1},
+ {HPF_Fs24000_Gain13_A1, /* Gain setting 13 */
+ HPF_Fs24000_Gain13_A0,
+ -HPF_Fs24000_Gain13_B1},
+ {HPF_Fs24000_Gain14_A1, /* Gain setting 14 */
+ HPF_Fs24000_Gain14_A0,
+ -HPF_Fs24000_Gain14_B1},
+ {HPF_Fs24000_Gain15_A1, /* Gain setting 15 */
+ HPF_Fs24000_Gain15_A0,
+ -HPF_Fs24000_Gain15_B1},
+
+ /* 32kHz sampling rate */
+ {HPF_Fs32000_Gain1_A1, /* Gain setting 1 */
+ HPF_Fs32000_Gain1_A0,
+ -HPF_Fs32000_Gain1_B1},
+ {HPF_Fs32000_Gain2_A1, /* Gain setting 2 */
+ HPF_Fs32000_Gain2_A0,
+ -HPF_Fs32000_Gain2_B1},
+ {HPF_Fs32000_Gain3_A1, /* Gain setting 3 */
+ HPF_Fs32000_Gain3_A0,
+ -HPF_Fs32000_Gain3_B1},
+ {HPF_Fs32000_Gain4_A1, /* Gain setting 4 */
+ HPF_Fs32000_Gain4_A0,
+ -HPF_Fs32000_Gain4_B1},
+ {HPF_Fs32000_Gain5_A1, /* Gain setting 5 */
+ HPF_Fs32000_Gain5_A0,
+ -HPF_Fs32000_Gain5_B1},
+ {HPF_Fs32000_Gain6_A1, /* Gain setting 6 */
+ HPF_Fs32000_Gain6_A0,
+ -HPF_Fs32000_Gain6_B1},
+ {HPF_Fs32000_Gain7_A1, /* Gain setting 7 */
+ HPF_Fs32000_Gain7_A0,
+ -HPF_Fs32000_Gain7_B1},
+ {HPF_Fs32000_Gain8_A1, /* Gain setting 8 */
+ HPF_Fs32000_Gain8_A0,
+ -HPF_Fs32000_Gain8_B1},
+ {HPF_Fs32000_Gain9_A1, /* Gain setting 9 */
+ HPF_Fs32000_Gain9_A0,
+ -HPF_Fs32000_Gain9_B1},
+ {HPF_Fs32000_Gain10_A1, /* Gain setting 10 */
+ HPF_Fs32000_Gain10_A0,
+ -HPF_Fs32000_Gain10_B1},
+ {HPF_Fs32000_Gain11_A1, /* Gain setting 11 */
+ HPF_Fs32000_Gain11_A0,
+ -HPF_Fs32000_Gain11_B1},
+ {HPF_Fs32000_Gain12_A1, /* Gain setting 12 */
+ HPF_Fs32000_Gain12_A0,
+ -HPF_Fs32000_Gain12_B1},
+ {HPF_Fs32000_Gain13_A1, /* Gain setting 13 */
+ HPF_Fs32000_Gain13_A0,
+ -HPF_Fs32000_Gain13_B1},
+ {HPF_Fs32000_Gain14_A1, /* Gain setting 14 */
+ HPF_Fs32000_Gain14_A0,
+ -HPF_Fs32000_Gain14_B1},
+ {HPF_Fs32000_Gain15_A1, /* Gain setting 15 */
+ HPF_Fs32000_Gain15_A0,
+ -HPF_Fs32000_Gain15_B1},
+
+ /* 44kHz sampling rate */
+ {HPF_Fs44100_Gain1_A1, /* Gain setting 1 */
+ HPF_Fs44100_Gain1_A0,
+ -HPF_Fs44100_Gain1_B1,},
+ {HPF_Fs44100_Gain2_A1, /* Gain setting 2 */
+ HPF_Fs44100_Gain2_A0,
+ -HPF_Fs44100_Gain2_B1},
+ {HPF_Fs44100_Gain3_A1, /* Gain setting 3 */
+ HPF_Fs44100_Gain3_A0,
+ -HPF_Fs44100_Gain3_B1},
+ {HPF_Fs44100_Gain4_A1, /* Gain setting 4 */
+ HPF_Fs44100_Gain4_A0,
+ -HPF_Fs44100_Gain4_B1},
+ {HPF_Fs44100_Gain5_A1, /* Gain setting 5 */
+ HPF_Fs44100_Gain5_A0,
+ -HPF_Fs44100_Gain5_B1},
+ {HPF_Fs44100_Gain6_A1, /* Gain setting 6 */
+ HPF_Fs44100_Gain6_A0,
+ -HPF_Fs44100_Gain6_B1},
+ {HPF_Fs44100_Gain7_A1, /* Gain setting 7 */
+ HPF_Fs44100_Gain7_A0,
+ -HPF_Fs44100_Gain7_B1},
+ {HPF_Fs44100_Gain8_A1, /* Gain setting 8 */
+ HPF_Fs44100_Gain8_A0,
+ -HPF_Fs44100_Gain8_B1},
+ {HPF_Fs44100_Gain9_A1, /* Gain setting 9 */
+ HPF_Fs44100_Gain9_A0,
+ -HPF_Fs44100_Gain9_B1},
+ {HPF_Fs44100_Gain10_A1, /* Gain setting 10 */
+ HPF_Fs44100_Gain10_A0,
+ -HPF_Fs44100_Gain10_B1},
+ {HPF_Fs44100_Gain11_A1, /* Gain setting 11 */
+ HPF_Fs44100_Gain11_A0,
+ -HPF_Fs44100_Gain11_B1},
+ {HPF_Fs44100_Gain12_A1, /* Gain setting 12 */
+ HPF_Fs44100_Gain12_A0,
+ -HPF_Fs44100_Gain12_B1},
+ {HPF_Fs44100_Gain13_A1, /* Gain setting 13 */
+ HPF_Fs44100_Gain13_A0,
+ -HPF_Fs44100_Gain13_B1},
+ {HPF_Fs44100_Gain14_A1, /* Gain setting 14 */
+ HPF_Fs44100_Gain14_A0,
+ -HPF_Fs44100_Gain14_B1},
+ {HPF_Fs44100_Gain15_A1, /* Gain setting 15 */
+ HPF_Fs44100_Gain15_A0,
+ -HPF_Fs44100_Gain15_B1},
+
+ /* 48kHz sampling rate */
+ {HPF_Fs48000_Gain1_A1, /* Gain setting 1 */
+ HPF_Fs48000_Gain1_A0,
+ -HPF_Fs48000_Gain1_B1},
+ {HPF_Fs48000_Gain2_A1, /* Gain setting 2 */
+ HPF_Fs48000_Gain2_A0,
+ -HPF_Fs48000_Gain2_B1},
+ {HPF_Fs48000_Gain3_A1, /* Gain setting 3 */
+ HPF_Fs48000_Gain3_A0,
+ -HPF_Fs48000_Gain3_B1},
+ {HPF_Fs48000_Gain4_A1, /* Gain setting 4 */
+ HPF_Fs48000_Gain4_A0,
+ -HPF_Fs48000_Gain4_B1},
+ {HPF_Fs48000_Gain5_A1, /* Gain setting 5 */
+ HPF_Fs48000_Gain5_A0,
+ -HPF_Fs48000_Gain5_B1},
+ {HPF_Fs48000_Gain6_A1, /* Gain setting 6 */
+ HPF_Fs48000_Gain6_A0,
+ -HPF_Fs48000_Gain6_B1},
+ {HPF_Fs48000_Gain7_A1, /* Gain setting 7 */
+ HPF_Fs48000_Gain7_A0,
+ -HPF_Fs48000_Gain7_B1},
+ {HPF_Fs48000_Gain8_A1, /* Gain setting 8 */
+ HPF_Fs48000_Gain8_A0,
+ -HPF_Fs48000_Gain8_B1},
+ {HPF_Fs48000_Gain9_A1, /* Gain setting 9 */
+ HPF_Fs48000_Gain9_A0,
+ -HPF_Fs48000_Gain9_B1},
+ {HPF_Fs48000_Gain10_A1, /* Gain setting 10 */
+ HPF_Fs48000_Gain10_A0,
+ -HPF_Fs48000_Gain10_B1},
+ {HPF_Fs48000_Gain11_A1, /* Gain setting 11 */
+ HPF_Fs48000_Gain11_A0,
+ -HPF_Fs48000_Gain11_B1},
+ {HPF_Fs48000_Gain12_A1, /* Gain setting 12 */
+ HPF_Fs48000_Gain12_A0,
+ -HPF_Fs48000_Gain12_B1},
+ {HPF_Fs48000_Gain13_A1, /* Gain setting 13 */
+ HPF_Fs48000_Gain13_A0,
+ -HPF_Fs48000_Gain13_B1},
+ {HPF_Fs48000_Gain14_A1, /* Gain setting 14 */
+ HPF_Fs48000_Gain14_A0,
+ -HPF_Fs48000_Gain14_B1},
+ {HPF_Fs48000_Gain15_A1, /* Gain setting 15 */
+ HPF_Fs48000_Gain15_A0,
+ -HPF_Fs48000_Gain15_B1}
+ ,
+ /* 88kHz Sampling rate */
+ {HPF_Fs88200_Gain1_A1, /* Gain Setting 1 */
+ HPF_Fs88200_Gain1_A0,
+ -HPF_Fs88200_Gain1_B1},
+ {HPF_Fs88200_Gain2_A1, /* Gain Setting 2 */
+ HPF_Fs88200_Gain2_A0,
+ -HPF_Fs88200_Gain2_B1},
+ {HPF_Fs88200_Gain3_A1, /* Gain Setting 3 */
+ HPF_Fs88200_Gain3_A0,
+ -HPF_Fs88200_Gain3_B1},
+ {HPF_Fs88200_Gain4_A1, /* Gain Setting 4 */
+ HPF_Fs88200_Gain4_A0,
+ -HPF_Fs88200_Gain4_B1},
+ {HPF_Fs88200_Gain5_A1, /* Gain Setting 5 */
+ HPF_Fs88200_Gain5_A0,
+ -HPF_Fs88200_Gain5_B1},
+ {HPF_Fs88200_Gain6_A1, /* Gain Setting 6 */
+ HPF_Fs88200_Gain6_A0,
+ -HPF_Fs88200_Gain6_B1},
+ {HPF_Fs88200_Gain7_A1, /* Gain Setting 7 */
+ HPF_Fs88200_Gain7_A0,
+ -HPF_Fs88200_Gain7_B1},
+ {HPF_Fs88200_Gain8_A1, /* Gain Setting 8 */
+ HPF_Fs88200_Gain8_A0,
+ -HPF_Fs88200_Gain8_B1},
+ {HPF_Fs88200_Gain9_A1, /* Gain Setting 9 */
+ HPF_Fs88200_Gain9_A0,
+ -HPF_Fs88200_Gain9_B1},
+ {HPF_Fs88200_Gain10_A1, /* Gain Setting 10 */
+ HPF_Fs88200_Gain10_A0,
+ -HPF_Fs88200_Gain10_B1},
+ {HPF_Fs88200_Gain11_A1, /* Gain Setting 11 */
+ HPF_Fs88200_Gain11_A0,
+ -HPF_Fs88200_Gain11_B1},
+ {HPF_Fs88200_Gain12_A1, /* Gain Setting 12 */
+ HPF_Fs88200_Gain12_A0,
+ -HPF_Fs88200_Gain12_B1},
+ {HPF_Fs88200_Gain13_A1, /* Gain Setting 13 */
+ HPF_Fs88200_Gain13_A0,
+ -HPF_Fs88200_Gain13_B1},
+ {HPF_Fs88200_Gain14_A1, /* Gain Setting 14 */
+ HPF_Fs88200_Gain14_A0,
+ -HPF_Fs88200_Gain14_B1},
+ {HPF_Fs88200_Gain15_A1, /* Gain Setting 15 */
+ HPF_Fs88200_Gain15_A0,
+ -HPF_Fs88200_Gain15_B1},
+
+ /* 96kHz sampling rate */
+ {HPF_Fs96000_Gain1_A1, /* Gain setting 1 */
+ HPF_Fs96000_Gain1_A0,
+ -HPF_Fs96000_Gain1_B1},
+ {HPF_Fs96000_Gain2_A1, /* Gain setting 2 */
+ HPF_Fs96000_Gain2_A0,
+ -HPF_Fs96000_Gain2_B1},
+ {HPF_Fs96000_Gain3_A1, /* Gain setting 3 */
+ HPF_Fs96000_Gain3_A0,
+ -HPF_Fs96000_Gain3_B1},
+ {HPF_Fs96000_Gain4_A1, /* Gain setting 4 */
+ HPF_Fs96000_Gain4_A0,
+ -HPF_Fs96000_Gain4_B1},
+ {HPF_Fs96000_Gain5_A1, /* Gain setting 5 */
+ HPF_Fs96000_Gain5_A0,
+ -HPF_Fs96000_Gain5_B1},
+ {HPF_Fs96000_Gain6_A1, /* Gain setting 6 */
+ HPF_Fs96000_Gain6_A0,
+ -HPF_Fs96000_Gain6_B1},
+ {HPF_Fs96000_Gain7_A1, /* Gain setting 7 */
+ HPF_Fs96000_Gain7_A0,
+ -HPF_Fs96000_Gain7_B1},
+ {HPF_Fs96000_Gain8_A1, /* Gain setting 8 */
+ HPF_Fs96000_Gain8_A0,
+ -HPF_Fs96000_Gain8_B1},
+ {HPF_Fs96000_Gain9_A1, /* Gain setting 9 */
+ HPF_Fs96000_Gain9_A0,
+ -HPF_Fs96000_Gain9_B1},
+ {HPF_Fs96000_Gain10_A1, /* Gain setting 10 */
+ HPF_Fs96000_Gain10_A0,
+ -HPF_Fs96000_Gain10_B1},
+ {HPF_Fs96000_Gain11_A1, /* Gain setting 11 */
+ HPF_Fs96000_Gain11_A0,
+ -HPF_Fs96000_Gain11_B1},
+ {HPF_Fs96000_Gain12_A1, /* Gain setting 12 */
+ HPF_Fs96000_Gain12_A0,
+ -HPF_Fs96000_Gain12_B1},
+ {HPF_Fs96000_Gain13_A1, /* Gain setting 13 */
+ HPF_Fs96000_Gain13_A0,
+ -HPF_Fs96000_Gain13_B1},
+ {HPF_Fs96000_Gain14_A1, /* Gain setting 14 */
+ HPF_Fs96000_Gain14_A0,
+ -HPF_Fs96000_Gain14_B1},
+ {HPF_Fs96000_Gain15_A1, /* Gain setting 15 */
+ HPF_Fs96000_Gain15_A0,
+ -HPF_Fs96000_Gain15_B1},
+
+ /* 176kHz Sampling rate */
+ {HPF_Fs176400_Gain1_A1, /* Gain Setting 1 */
+ HPF_Fs176400_Gain1_A0,
+ -HPF_Fs176400_Gain1_B1},
+ {HPF_Fs176400_Gain2_A1, /* Gain Setting 2 */
+ HPF_Fs176400_Gain2_A0,
+ -HPF_Fs176400_Gain2_B1},
+ {HPF_Fs176400_Gain3_A1, /* Gain Setting 3 */
+ HPF_Fs176400_Gain3_A0,
+ -HPF_Fs176400_Gain3_B1},
+ {HPF_Fs176400_Gain4_A1, /* Gain Setting 4 */
+ HPF_Fs176400_Gain4_A0,
+ -HPF_Fs176400_Gain4_B1},
+ {HPF_Fs176400_Gain5_A1, /* Gain Setting 5 */
+ HPF_Fs176400_Gain5_A0,
+ -HPF_Fs176400_Gain5_B1},
+ {HPF_Fs176400_Gain6_A1, /* Gain Setting 6 */
+ HPF_Fs176400_Gain6_A0,
+ -HPF_Fs176400_Gain6_B1},
+ {HPF_Fs176400_Gain7_A1, /* Gain Setting 7 */
+ HPF_Fs176400_Gain7_A0,
+ -HPF_Fs176400_Gain7_B1},
+ {HPF_Fs176400_Gain8_A1, /* Gain Setting 8 */
+ HPF_Fs176400_Gain8_A0,
+ -HPF_Fs176400_Gain8_B1},
+ {HPF_Fs176400_Gain9_A1, /* Gain Setting 9 */
+ HPF_Fs176400_Gain9_A0,
+ -HPF_Fs176400_Gain9_B1},
+ {HPF_Fs176400_Gain10_A1, /* Gain Setting 10 */
+ HPF_Fs176400_Gain10_A0,
+ -HPF_Fs176400_Gain10_B1},
+ {HPF_Fs176400_Gain11_A1, /* Gain Setting 11 */
+ HPF_Fs176400_Gain11_A0,
+ -HPF_Fs176400_Gain11_B1},
+ {HPF_Fs176400_Gain12_A1, /* Gain Setting 12 */
+ HPF_Fs176400_Gain12_A0,
+ -HPF_Fs176400_Gain12_B1},
+ {HPF_Fs176400_Gain13_A1, /* Gain Setting 13 */
+ HPF_Fs176400_Gain13_A0,
+ -HPF_Fs176400_Gain13_B1},
+ {HPF_Fs176400_Gain14_A1, /* Gain Setting 14 */
+ HPF_Fs176400_Gain14_A0,
+ -HPF_Fs176400_Gain14_B1},
+ {HPF_Fs176400_Gain15_A1, /* Gain Setting 15 */
+ HPF_Fs176400_Gain15_A0,
+ -HPF_Fs176400_Gain15_B1},
+
+ /* 192kHz sampling rate */
+ {HPF_Fs192000_Gain1_A1, /* Gain setting 1 */
+ HPF_Fs192000_Gain1_A0,
+ -HPF_Fs192000_Gain1_B1},
+ {HPF_Fs192000_Gain2_A1, /* Gain setting 2 */
+ HPF_Fs192000_Gain2_A0,
+ -HPF_Fs192000_Gain2_B1},
+ {HPF_Fs192000_Gain3_A1, /* Gain setting 3 */
+ HPF_Fs192000_Gain3_A0,
+ -HPF_Fs192000_Gain3_B1},
+ {HPF_Fs192000_Gain4_A1, /* Gain setting 4 */
+ HPF_Fs192000_Gain4_A0,
+ -HPF_Fs192000_Gain4_B1},
+ {HPF_Fs192000_Gain5_A1, /* Gain setting 5 */
+ HPF_Fs192000_Gain5_A0,
+ -HPF_Fs192000_Gain5_B1},
+ {HPF_Fs192000_Gain6_A1, /* Gain setting 6 */
+ HPF_Fs192000_Gain6_A0,
+ -HPF_Fs192000_Gain6_B1},
+ {HPF_Fs192000_Gain7_A1, /* Gain setting 7 */
+ HPF_Fs192000_Gain7_A0,
+ -HPF_Fs192000_Gain7_B1},
+ {HPF_Fs192000_Gain8_A1, /* Gain setting 8 */
+ HPF_Fs192000_Gain8_A0,
+ -HPF_Fs192000_Gain8_B1},
+ {HPF_Fs192000_Gain9_A1, /* Gain setting 9 */
+ HPF_Fs192000_Gain9_A0,
+ -HPF_Fs192000_Gain9_B1},
+ {HPF_Fs192000_Gain10_A1, /* Gain setting 10 */
+ HPF_Fs192000_Gain10_A0,
+ -HPF_Fs192000_Gain10_B1},
+ {HPF_Fs192000_Gain11_A1, /* Gain setting 11 */
+ HPF_Fs192000_Gain11_A0,
+ -HPF_Fs192000_Gain11_B1},
+ {HPF_Fs192000_Gain12_A1, /* Gain setting 12 */
+ HPF_Fs192000_Gain12_A0,
+ -HPF_Fs192000_Gain12_B1},
+ {HPF_Fs192000_Gain13_A1, /* Gain setting 13 */
+ HPF_Fs192000_Gain13_A0,
+ -HPF_Fs192000_Gain13_B1},
+ {HPF_Fs192000_Gain14_A1, /* Gain setting 14 */
+ HPF_Fs192000_Gain14_A0,
+ -HPF_Fs192000_Gain14_B1},
+ {HPF_Fs192000_Gain15_A1, /* Gain setting 15 */
+ HPF_Fs192000_Gain15_A0,
+ -HPF_Fs192000_Gain15_B1}
+ };
+
+/************************************************************************************/
+/* */
+/* Volume control gain and time constant tables */
+/* */
+/************************************************************************************/
+
+/* dB to linear conversion table */
+const LVM_FLOAT LVM_VolumeTable[] = {
+ 1.000f, /* 0dB */
+ 0.891f, /* -1dB */
+ 0.794f, /* -2dB */
+ 0.708f, /* -3dB */
+ 0.631f, /* -4dB */
+ 0.562f, /* -5dB */
+ 0.501f}; /* -6dB */
+
+/************************************************************************************/
+/* */
+/* Volume mixer time constants (100ms) */
+/* */
+/************************************************************************************/
+
+#define LVM_MIX_TC_Fs8000 32580 /* Floating point value 0.994262695 */
+#define LVM_MIX_TC_Fs11025 32632 /* Floating point value 0.995849609 */
+#define LVM_MIX_TC_Fs12000 32643 /* Floating point value 0.996185303 */
+#define LVM_MIX_TC_Fs16000 32674 /* Floating point value 0.997131348 */
+#define LVM_MIX_TC_Fs22050 32700 /* Floating point value 0.997924805 */
+#define LVM_MIX_TC_Fs24000 32705 /* Floating point value 0.998077393 */
+#define LVM_MIX_TC_Fs32000 32721 /* Floating point value 0.998565674 */
+#define LVM_MIX_TC_Fs44100 32734 /* Floating point value 0.998962402 */
+#define LVM_MIX_TC_Fs48000 32737 /* Floating point value 0.999053955 */
+
+const LVM_INT16 LVM_MixerTCTable[] = {
+ LVM_MIX_TC_Fs8000,
+ LVM_MIX_TC_Fs11025,
+ LVM_MIX_TC_Fs12000,
+ LVM_MIX_TC_Fs16000,
+ LVM_MIX_TC_Fs22050,
+ LVM_MIX_TC_Fs24000,
+ LVM_MIX_TC_Fs32000,
+ LVM_MIX_TC_Fs44100,
+ LVM_MIX_TC_Fs48000};
+
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Tables.h b/media/libeffects/lvm/lib/Bundle/src/LVM_Tables.h
index 4cf7119..fc82194 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Tables.h
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Tables.h
@@ -18,10 +18,6 @@
#ifndef __LVM_TABLES_H__
#define __LVM_TABLES_H__
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
/************************************************************************************/
/* */
/* Includes */
@@ -37,30 +33,16 @@
/* */
/************************************************************************************/
-#ifdef BUILD_FLOAT
extern FO_FLOAT_LShx_Coefs_t LVM_TrebleBoostCoefs[];
-#else
-extern FO_C16_LShx_Coefs_t LVM_TrebleBoostCoefs[];
-#endif
/************************************************************************************/
/* */
/* Volume control gain and time constant tables */
/* */
/************************************************************************************/
-#ifdef BUILD_FLOAT
extern const LVM_FLOAT LVM_VolumeTable[];
-#else
-extern const LVM_INT16 LVM_VolumeTable[];
-#endif
extern const LVM_INT16 LVM_MixerTCTable[];
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
#endif /* __LVM_TABLES_H__ */
-
diff --git a/media/libeffects/lvm/lib/Common/lib/AGC.h b/media/libeffects/lvm/lib/Common/lib/AGC.h
index 06e742e..bef7fa1 100644
--- a/media/libeffects/lvm/lib/Common/lib/AGC.h
+++ b/media/libeffects/lvm/lib/Common/lib/AGC.h
@@ -18,11 +18,6 @@
#ifndef __AGC_H__
#define __AGC_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
/**********************************************************************************/
/* */
/* Includes */
@@ -31,28 +26,11 @@
#include "LVM_Types.h"
-
/**********************************************************************************/
/* */
/* Types */
/* */
/**********************************************************************************/
-#ifndef BUILD_FLOAT
-typedef struct
-{
- LVM_INT32 AGC_Gain; /* The current AGC gain */
- LVM_INT32 AGC_MaxGain; /* The maximum AGC gain */
- LVM_INT32 Volume; /* The current volume setting */
- LVM_INT32 Target; /* The target volume setting */
- LVM_INT32 AGC_Target; /* AGC target level */
- LVM_INT16 AGC_Attack; /* AGC attack scaler */
- LVM_INT16 AGC_Decay; /* AGC decay scaler */
- LVM_INT16 AGC_GainShift; /* The gain shift */
- LVM_INT16 VolumeShift; /* Volume shift scaling */
- LVM_INT16 VolumeTC; /* Volume update time constant */
-
-} AGC_MIX_VOL_2St1Mon_D32_t;
-#else
typedef struct
{
LVM_FLOAT AGC_Gain; /* The current AGC gain */
@@ -65,14 +43,12 @@
LVM_FLOAT VolumeTC; /* Volume update time constant */
} AGC_MIX_VOL_2St1Mon_FLOAT_t;
-#endif
/**********************************************************************************/
/* */
/* Function Prototypes */
/* */
/**********************************************************************************/
-#ifdef BUILD_FLOAT
void AGC_MIX_VOL_2St1Mon_D32_WRA(AGC_MIX_VOL_2St1Mon_FLOAT_t *pInstance, /* Instance pointer */
const LVM_FLOAT *pStSrc, /* Stereo source */
const LVM_FLOAT *pMonoSrc, /* Mono source */
@@ -87,26 +63,5 @@
LVM_UINT16 NrChannels); /* Number of channels */
#endif
-#else
-void AGC_MIX_VOL_2St1Mon_D32_WRA(AGC_MIX_VOL_2St1Mon_D32_t *pInstance, /* Instance pointer */
- const LVM_INT32 *pStSrc, /* Stereo source */
- const LVM_INT32 *pMonoSrc, /* Mono source */
- LVM_INT32 *pDst, /* Stereo destination */
- LVM_UINT16 n); /* Number of samples */
-#endif
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-
#endif /* __AGC_H__ */
-
-
-
-
-
-
-
-
-
diff --git a/media/libeffects/lvm/lib/Common/lib/BIQUAD.h b/media/libeffects/lvm/lib/Common/lib/BIQUAD.h
index 01539b2..c050cd0 100644
--- a/media/libeffects/lvm/lib/Common/lib/BIQUAD.h
+++ b/media/libeffects/lvm/lib/Common/lib/BIQUAD.h
@@ -18,16 +18,10 @@
#ifndef _BIQUAD_H_
#define _BIQUAD_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
#include "LVM_Types.h"
/**********************************************************************************
INSTANCE MEMORY TYPE DEFINITION
***********************************************************************************/
-#ifdef BUILD_FLOAT
typedef struct
{
#ifdef SUPPORT_MC
@@ -42,19 +36,11 @@
LVM_FLOAT Storage[6];
#endif
} Biquad_FLOAT_Instance_t;
-#else
-typedef struct
-{
- LVM_INT32 Storage[6];
-
-} Biquad_Instance_t;
-#endif
/**********************************************************************************
COEFFICIENT TYPE DEFINITIONS
***********************************************************************************/
/*** Biquad coefficients **********************************************************/
-#ifdef BUILD_FLOAT
typedef struct
{
LVM_FLOAT A2; /* a2 */
@@ -63,93 +49,31 @@
LVM_FLOAT B2; /* -b2! */
LVM_FLOAT B1; /* -b1! */
} BQ_FLOAT_Coefs_t;
-#else
-typedef struct
-{
- LVM_INT16 A2; /* a2 */
- LVM_INT16 A1; /* a1 */
- LVM_INT16 A0; /* a0 */
- LVM_INT16 B2; /* -b2! */
- LVM_INT16 B1; /* -b1! */
-} BQ_C16_Coefs_t;
-
-typedef struct
-{
- LVM_INT32 A2; /* a2 */
- LVM_INT32 A1; /* a1 */
- LVM_INT32 A0; /* a0 */
- LVM_INT32 B2; /* -b2! */
- LVM_INT32 B1; /* -b1! */
-} BQ_C32_Coefs_t;
-#endif
/*** First order coefficients *****************************************************/
-#ifdef BUILD_FLOAT
typedef struct
{
LVM_FLOAT A1; /* a1 */
LVM_FLOAT A0; /* a0 */
LVM_FLOAT B1; /* -b1! */
} FO_FLOAT_Coefs_t;
-#else
-typedef struct
-{
- LVM_INT16 A1; /* a1 */
- LVM_INT16 A0; /* a0 */
- LVM_INT16 B1; /* -b1! */
-} FO_C16_Coefs_t;
-
-typedef struct
-{
- LVM_INT32 A1; /* a1 */
- LVM_INT32 A0; /* a0 */
- LVM_INT32 B1; /* -b1! */
-} FO_C32_Coefs_t;
-#endif
/*** First order coefficients with Shift*****************************************************/
-#ifdef BUILD_FLOAT
typedef struct
{
LVM_FLOAT A1; /* a1 */
LVM_FLOAT A0; /* a0 */
LVM_FLOAT B1; /* -b1! */
} FO_FLOAT_LShx_Coefs_t;
-#else
-typedef struct
-{
- LVM_INT16 A1; /* a1 */
- LVM_INT16 A0; /* a0 */
- LVM_INT16 B1; /* -b1! */
- LVM_INT16 Shift; /* Shift */
-} FO_C16_LShx_Coefs_t;
-#endif
/*** Band pass coefficients *******************************************************/
-#ifdef BUILD_FLOAT
typedef struct
{
LVM_FLOAT A0; /* a0 */
LVM_FLOAT B2; /* -b2! */
LVM_FLOAT B1; /* -b1! */
} BP_FLOAT_Coefs_t;
-#else
-typedef struct
-{
- LVM_INT16 A0; /* a0 */
- LVM_INT16 B2; /* -b2! */
- LVM_INT16 B1; /* -b1! */
-} BP_C16_Coefs_t;
-
-typedef struct
-{
- LVM_INT32 A0; /* a0 */
- LVM_INT32 B2; /* -b2! */
- LVM_INT32 B1; /* -b1! */
-} BP_C32_Coefs_t;
-#endif
/*** Peaking coefficients *********************************************************/
-#ifdef BUILD_FLOAT
typedef struct
{
LVM_FLOAT A0; /* a0 */
@@ -157,30 +81,12 @@
LVM_FLOAT B1; /* -b1! */
LVM_FLOAT G; /* Gain */
} PK_FLOAT_Coefs_t;
-#else
-typedef struct
-{
- LVM_INT16 A0; /* a0 */
- LVM_INT16 B2; /* -b2! */
- LVM_INT16 B1; /* -b1! */
- LVM_INT16 G; /* Gain */
-} PK_C16_Coefs_t;
-
-typedef struct
-{
- LVM_INT32 A0; /* a0 */
- LVM_INT32 B2; /* -b2! */
- LVM_INT32 B1; /* -b1! */
- LVM_INT16 G; /* Gain */
-} PK_C32_Coefs_t;
-#endif
/**********************************************************************************
TAPS TYPE DEFINITIONS
***********************************************************************************/
/*** Types used for first order and shelving filter *******************************/
-#ifdef BUILD_FLOAT
typedef struct
{
LVM_FLOAT Storage[ (1 * 2) ]; /* One channel, two taps of size LVM_INT32 */
@@ -195,20 +101,8 @@
LVM_FLOAT Storage[ (2 * 2) ]; /* Two channels, two taps of size LVM_FLOAT */
#endif
} Biquad_2I_Order1_FLOAT_Taps_t;
-#else
-typedef struct
-{
- LVM_INT32 Storage[ (1*2) ]; /* One channel, two taps of size LVM_INT32 */
-} Biquad_1I_Order1_Taps_t;
-
-typedef struct
-{
- LVM_INT32 Storage[ (2*2) ]; /* Two channels, two taps of size LVM_INT32 */
-} Biquad_2I_Order1_Taps_t;
-#endif
/*** Types used for biquad, band pass and peaking filter **************************/
-#ifdef BUILD_FLOAT
typedef struct
{
LVM_FLOAT Storage[ (1 * 4) ]; /* One channel, four taps of size LVM_FLOAT */
@@ -223,17 +117,6 @@
LVM_FLOAT Storage[ (2 * 4) ]; /* Two channels, four taps of size LVM_FLOAT */
#endif
} Biquad_2I_Order2_FLOAT_Taps_t;
-#else
-typedef struct
-{
- LVM_INT32 Storage[ (1*4) ]; /* One channel, four taps of size LVM_INT32 */
-} Biquad_1I_Order2_Taps_t;
-
-typedef struct
-{
- LVM_INT32 Storage[ (2*4) ]; /* Two channels, four taps of size LVM_INT32 */
-} Biquad_2I_Order2_Taps_t;
-#endif
/* The names of the functions are changed to satisfy QAC rules: Name should be Unique withing 16 characters*/
#define BQ_2I_D32F32Cll_TRC_WRA_01_Init Init_BQ_2I_D32F32Cll_TRC_WRA_01
#define BP_1I_D32F32C30_TRC_WRA_02 TWO_BP_1I_D32F32C30_TRC_WRA_02
@@ -244,140 +127,57 @@
/*** 16 bit data path *************************************************************/
-
-#ifdef BUILD_FLOAT
void BQ_2I_D16F32Css_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
Biquad_2I_Order2_FLOAT_Taps_t *pTaps,
BQ_FLOAT_Coefs_t *pCoef);
-#else
-void BQ_2I_D16F32Css_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
- Biquad_2I_Order2_Taps_t *pTaps,
- BQ_C16_Coefs_t *pCoef);
-#endif
-#ifdef BUILD_FLOAT
void BQ_2I_D16F32C15_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
LVM_FLOAT *pDataIn,
LVM_FLOAT *pDataOut,
LVM_INT16 NrSamples);
-#else
-void BQ_2I_D16F32C15_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
- LVM_INT16 *pDataIn,
- LVM_INT16 *pDataOut,
- LVM_INT16 NrSamples);
-#endif
-#ifdef BUILD_FLOAT
void BQ_2I_D16F32C14_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
LVM_FLOAT *pDataIn,
LVM_FLOAT *pDataOut,
LVM_INT16 NrSamples);
-#else
-void BQ_2I_D16F32C14_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
- LVM_INT16 *pDataIn,
- LVM_INT16 *pDataOut,
- LVM_INT16 NrSamples);
-#endif
-
-#ifdef BUILD_FLOAT
void BQ_2I_D16F32C13_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
LVM_FLOAT *pDataIn,
LVM_FLOAT *pDataOut,
LVM_INT16 NrSamples);
-#else
-void BQ_2I_D16F32C13_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
- LVM_INT16 *pDataIn,
- LVM_INT16 *pDataOut,
- LVM_INT16 NrSamples);
-#endif
-
-#ifdef BUILD_FLOAT
void BQ_2I_D16F16Css_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
Biquad_2I_Order2_FLOAT_Taps_t *pTaps,
BQ_FLOAT_Coefs_t *pCoef);
-#else
-void BQ_2I_D16F16Css_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
- Biquad_2I_Order2_Taps_t *pTaps,
- BQ_C16_Coefs_t *pCoef);
-#endif
-
-#ifdef BUILD_FLOAT
void BQ_2I_D16F16C15_TRC_WRA_01( Biquad_FLOAT_Instance_t *pInstance,
LVM_FLOAT *pDataIn,
LVM_FLOAT *pDataOut,
LVM_INT16 NrSamples);
-#else
-void BQ_2I_D16F16C15_TRC_WRA_01( Biquad_Instance_t *pInstance,
- LVM_INT16 *pDataIn,
- LVM_INT16 *pDataOut,
- LVM_INT16 NrSamples);
-#endif
-
-#ifdef BUILD_FLOAT
void BQ_2I_D16F16C14_TRC_WRA_01( Biquad_FLOAT_Instance_t *pInstance,
LVM_FLOAT *pDataIn,
LVM_FLOAT *pDataOut,
LVM_INT16 NrSamples);
-#else
-void BQ_2I_D16F16C14_TRC_WRA_01( Biquad_Instance_t *pInstance,
- LVM_INT16 *pDataIn,
- LVM_INT16 *pDataOut,
- LVM_INT16 NrSamples);
-#endif
-#ifdef BUILD_FLOAT
void BQ_1I_D16F16Css_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
Biquad_1I_Order2_FLOAT_Taps_t *pTaps,
BQ_FLOAT_Coefs_t *pCoef);
-#else
-void BQ_1I_D16F16Css_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
- Biquad_1I_Order2_Taps_t *pTaps,
- BQ_C16_Coefs_t *pCoef);
-#endif
-
-#ifdef BUILD_FLOAT
void BQ_1I_D16F16C15_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
LVM_FLOAT *pDataIn,
LVM_FLOAT *pDataOut,
LVM_INT16 NrSamples);
-#else
-void BQ_1I_D16F16C15_TRC_WRA_01( Biquad_Instance_t *pInstance,
- LVM_INT16 *pDataIn,
- LVM_INT16 *pDataOut,
- LVM_INT16 NrSamples);
-#endif
-
-#ifdef BUILD_FLOAT
void BQ_1I_D16F32Css_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
Biquad_1I_Order2_FLOAT_Taps_t *pTaps,
BQ_FLOAT_Coefs_t *pCoef);
-#else
-void BQ_1I_D16F32Css_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
- Biquad_1I_Order2_Taps_t *pTaps,
- BQ_C16_Coefs_t *pCoef);
-#endif
-
-#ifdef BUILD_FLOAT
void BQ_1I_D16F32C14_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
LVM_FLOAT *pDataIn,
LVM_FLOAT *pDataOut,
LVM_INT16 NrSamples);
-#else
-void BQ_1I_D16F32C14_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
- LVM_INT16 *pDataIn,
- LVM_INT16 *pDataOut,
- LVM_INT16 NrSamples);
-
-#endif
/*** 32 bit data path *************************************************************/
-#ifdef BUILD_FLOAT
void BQ_2I_D32F32Cll_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
Biquad_2I_Order2_FLOAT_Taps_t *pTaps,
BQ_FLOAT_Coefs_t *pCoef);
@@ -392,67 +192,30 @@
LVM_INT16 NrFrames,
LVM_INT16 NrChannels);
#endif
-#else
-void BQ_2I_D32F32Cll_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
- Biquad_2I_Order2_Taps_t *pTaps,
- BQ_C32_Coefs_t *pCoef);
-
-void BQ_2I_D32F32C30_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
- LVM_INT32 *pDataIn,
- LVM_INT32 *pDataOut,
- LVM_INT16 NrSamples);
-#endif
/**********************************************************************************
FUNCTION PROTOTYPES: FIRST ORDER FILTERS
***********************************************************************************/
/*** 16 bit data path *************************************************************/
-#ifdef BUILD_FLOAT
void FO_1I_D16F16Css_TRC_WRA_01_Init( Biquad_FLOAT_Instance_t *pInstance,
Biquad_1I_Order1_FLOAT_Taps_t *pTaps,
FO_FLOAT_Coefs_t *pCoef);
-#else
-void FO_1I_D16F16Css_TRC_WRA_01_Init( Biquad_Instance_t *pInstance,
- Biquad_1I_Order1_Taps_t *pTaps,
- FO_C16_Coefs_t *pCoef);
-#endif
-#ifdef BUILD_FLOAT
void FO_1I_D16F16C15_TRC_WRA_01( Biquad_FLOAT_Instance_t *pInstance,
LVM_FLOAT *pDataIn,
LVM_FLOAT *pDataOut,
LVM_INT16 NrSamples);
-#else
-void FO_1I_D16F16C15_TRC_WRA_01( Biquad_Instance_t *pInstance,
- LVM_INT16 *pDataIn,
- LVM_INT16 *pDataOut,
- LVM_INT16 NrSamples);
-#endif
-#ifdef BUILD_FLOAT
void FO_2I_D16F32Css_LShx_TRC_WRA_01_Init(Biquad_FLOAT_Instance_t *pInstance,
Biquad_2I_Order1_FLOAT_Taps_t *pTaps,
FO_FLOAT_LShx_Coefs_t *pCoef);
-#else
-void FO_2I_D16F32Css_LShx_TRC_WRA_01_Init(Biquad_Instance_t *pInstance,
- Biquad_2I_Order1_Taps_t *pTaps,
- FO_C16_LShx_Coefs_t *pCoef);
-#endif
-#ifdef BUILD_FLOAT
void FO_2I_D16F32C15_LShx_TRC_WRA_01(Biquad_FLOAT_Instance_t *pInstance,
LVM_FLOAT *pDataIn,
LVM_FLOAT *pDataOut,
LVM_INT16 NrSamples);
-#else
-void FO_2I_D16F32C15_LShx_TRC_WRA_01(Biquad_Instance_t *pInstance,
- LVM_INT16 *pDataIn,
- LVM_INT16 *pDataOut,
- LVM_INT16 NrSamples);
-#endif
/*** 32 bit data path *************************************************************/
-#ifdef BUILD_FLOAT
void FO_1I_D32F32Cll_TRC_WRA_01_Init( Biquad_FLOAT_Instance_t *pInstance,
Biquad_1I_Order1_FLOAT_Taps_t *pTaps,
FO_FLOAT_Coefs_t *pCoef);
@@ -467,22 +230,11 @@
LVM_INT16 NrFrames,
LVM_INT16 NrChannels);
#endif
-#else
-void FO_1I_D32F32Cll_TRC_WRA_01_Init( Biquad_Instance_t *pInstance,
- Biquad_1I_Order1_Taps_t *pTaps,
- FO_C32_Coefs_t *pCoef);
-
-void FO_1I_D32F32C31_TRC_WRA_01( Biquad_Instance_t *pInstance,
- LVM_INT32 *pDataIn,
- LVM_INT32 *pDataOut,
- LVM_INT16 NrSamples);
-#endif
/**********************************************************************************
FUNCTION PROTOTYPES: BAND PASS FILTERS
***********************************************************************************/
/*** 16 bit data path *************************************************************/
-#ifdef BUILD_FLOAT
void BP_1I_D16F16Css_TRC_WRA_01_Init( Biquad_FLOAT_Instance_t *pInstance,
Biquad_1I_Order2_FLOAT_Taps_t *pTaps,
BP_FLOAT_Coefs_t *pCoef);
@@ -497,27 +249,7 @@
LVM_FLOAT *pDataIn,
LVM_FLOAT *pDataOut,
LVM_INT16 NrSamples);
-#else
-void BP_1I_D16F16Css_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
- Biquad_1I_Order2_Taps_t *pTaps,
- BP_C16_Coefs_t *pCoef);
-
-void BP_1I_D16F16C14_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
- LVM_INT16 *pDataIn,
- LVM_INT16 *pDataOut,
- LVM_INT16 NrSamples);
-
-void BP_1I_D16F32Cll_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
- Biquad_1I_Order2_Taps_t *pTaps,
- BP_C32_Coefs_t *pCoef);
-
-void BP_1I_D16F32C30_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
- LVM_INT16 *pDataIn,
- LVM_INT16 *pDataOut,
- LVM_INT16 NrSamples);
-#endif
/*** 32 bit data path *************************************************************/
-#ifdef BUILD_FLOAT
void BP_1I_D32F32Cll_TRC_WRA_02_Init ( Biquad_FLOAT_Instance_t *pInstance,
Biquad_1I_Order2_FLOAT_Taps_t *pTaps,
BP_FLOAT_Coefs_t *pCoef);
@@ -525,37 +257,11 @@
LVM_FLOAT *pDataIn,
LVM_FLOAT *pDataOut,
LVM_INT16 NrSamples);
-#else
-void BP_1I_D32F32Cll_TRC_WRA_02_Init ( Biquad_Instance_t *pInstance,
- Biquad_1I_Order2_Taps_t *pTaps,
- BP_C32_Coefs_t *pCoef);
-
-void BP_1I_D32F32C30_TRC_WRA_02( Biquad_Instance_t *pInstance,
- LVM_INT32 *pDataIn,
- LVM_INT32 *pDataOut,
- LVM_INT16 NrSamples);
-#endif
/*** 32 bit data path STEREO ******************************************************/
-#ifndef BUILD_FLOAT
-void PK_2I_D32F32CllGss_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
- Biquad_2I_Order2_Taps_t *pTaps,
- PK_C32_Coefs_t *pCoef);
-void PK_2I_D32F32C30G11_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
- LVM_INT32 *pDataIn,
- LVM_INT32 *pDataOut,
- LVM_INT16 NrSamples);
-#endif
-#ifdef BUILD_FLOAT
void PK_2I_D32F32CssGss_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
Biquad_2I_Order2_FLOAT_Taps_t *pTaps,
PK_FLOAT_Coefs_t *pCoef);
-#else
-void PK_2I_D32F32CssGss_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
- Biquad_2I_Order2_Taps_t *pTaps,
- PK_C16_Coefs_t *pCoef);
-#endif
-#ifdef BUILD_FLOAT
void PK_2I_D32F32C14G11_TRC_WRA_01( Biquad_FLOAT_Instance_t *pInstance,
LVM_FLOAT *pDataIn,
LVM_FLOAT *pDataOut,
@@ -567,19 +273,12 @@
LVM_INT16 NrFrames,
LVM_INT16 NrChannels);
#endif
-#else
-void PK_2I_D32F32C14G11_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
- LVM_INT32 *pDataIn,
- LVM_INT32 *pDataOut,
- LVM_INT16 NrSamples);
-#endif
/**********************************************************************************
FUNCTION PROTOTYPES: DC REMOVAL FILTERS
***********************************************************************************/
/*** 16 bit data path STEREO ******************************************************/
-#ifdef BUILD_FLOAT
#ifdef SUPPORT_MC
void DC_Mc_D16_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance);
@@ -596,18 +295,6 @@
LVM_FLOAT *pDataOut,
LVM_INT16 NrSamples);
#endif
-#else
-void DC_2I_D16_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance);
-
-void DC_2I_D16_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
- LVM_INT16 *pDataIn,
- LVM_INT16 *pDataOut,
- LVM_INT16 NrSamples);
-#endif
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/lib/CompLim.h b/media/libeffects/lvm/lib/Common/lib/CompLim.h
index 498faa3..5b7cb1b 100644
--- a/media/libeffects/lvm/lib/Common/lib/CompLim.h
+++ b/media/libeffects/lvm/lib/Common/lib/CompLim.h
@@ -18,11 +18,6 @@
#ifndef _COMP_LIM_H
#define _COMP_LIM_H
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-
/************************************************************************************/
/* */
/* Includes */
@@ -31,7 +26,6 @@
#include "LVM_Types.h"
-
/************************************************************************************/
/* */
/* Structures */
@@ -57,31 +51,17 @@
LVM_INT32 CompIntSlow; /* Compressor slow integrator current value */
LVM_INT32 CompIntFast; /* Compressor fast integrator current value */
-
} CompLim_Instance_t;
-
/************************************************************************************/
/* */
/* Function Prototypes */
/* */
/************************************************************************************/
-#ifdef BUILD_FLOAT
void NonLinComp_Float(LVM_FLOAT Gain,
LVM_FLOAT *pDataIn,
LVM_FLOAT *pDataOut,
LVM_INT32 BlockLength);
-#else
-void NonLinComp_D16(LVM_INT16 Gain,
- LVM_INT16 *pSterBfIn,
- LVM_INT16 *pSterBfOut,
- LVM_INT32 BlockLength);
-#endif
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
#endif /* #ifndef _COMP_LIM_H */
-
-
diff --git a/media/libeffects/lvm/lib/Common/lib/Filter.h b/media/libeffects/lvm/lib/Common/lib/Filter.h
index 0c8955d..1eeb321 100644
--- a/media/libeffects/lvm/lib/Common/lib/Filter.h
+++ b/media/libeffects/lvm/lib/Common/lib/Filter.h
@@ -18,39 +18,27 @@
#ifndef _FILTER_H_
#define _FILTER_H_
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
/**********************************************************************************
INCLUDES
***********************************************************************************/
#include "LVM_Types.h"
#include "BIQUAD.h"
-
/**********************************************************************************
DEFINES
***********************************************************************************/
#define FILTER_LOSS 32730 /* -0.01dB loss to avoid wrapping due to band ripple */
-#ifdef BUILD_FLOAT
#define FILTER_LOSS_FLOAT 0.998849f
-#endif
/**********************************************************************************
FUNCTION PROTOTYPES
***********************************************************************************/
-#ifdef BUILD_FLOAT
LVM_FLOAT LVM_Power10( LVM_FLOAT X);
LVM_FLOAT LVM_Polynomial(LVM_UINT16 N,
LVM_FLOAT *pCoefficients,
LVM_FLOAT X);
-#ifdef HIGHER_FS
LVM_FLOAT LVM_GetOmega(LVM_UINT32 Fc,
-#else
-LVM_FLOAT LVM_GetOmega(LVM_UINT16 Fc,
-#endif
LVM_Fs_en SampleRate);
LVM_FLOAT LVM_FO_LPF( LVM_FLOAT w,
@@ -58,26 +46,7 @@
LVM_FLOAT LVM_FO_HPF( LVM_FLOAT w,
FO_FLOAT_Coefs_t *pCoeffs);
-#else
-LVM_INT32 LVM_Polynomial(LVM_UINT16 N,
- LVM_INT32 *pCoefficients,
- LVM_INT32 X);
-
-LVM_INT32 LVM_Power10( LVM_INT32 X);
-
-LVM_INT32 LVM_FO_LPF( LVM_INT32 w,
- FO_C32_Coefs_t *pCoeffs);
-
-LVM_INT32 LVM_FO_HPF( LVM_INT32 w,
- FO_C32_Coefs_t *pCoeffs);
-
-LVM_INT32 LVM_GetOmega(LVM_UINT16 Fc,
- LVM_Fs_en SampleRate);
-#endif
/**********************************************************************************/
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
#endif /** _FILTER_H_ **/
diff --git a/media/libeffects/lvm/lib/Common/lib/InstAlloc.h b/media/libeffects/lvm/lib/Common/lib/InstAlloc.h
index 7f725f4..bae84e7 100644
--- a/media/libeffects/lvm/lib/Common/lib/InstAlloc.h
+++ b/media/libeffects/lvm/lib/Common/lib/InstAlloc.h
@@ -18,10 +18,6 @@
#ifndef __INSTALLOC_H__
#define __INSTALLOC_H__
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
#include "LVM_Types.h"
/*######################################################################################*/
/* Type declarations */
@@ -32,7 +28,6 @@
uintptr_t pNextMember; /* Pointer to the next instance member to be allocated */
} INST_ALLOC;
-
/*######################################################################################*/
/* Function prototypes */
/*######################################################################################*/
@@ -48,7 +43,6 @@
void InstAlloc_Init( INST_ALLOC *pms, void *StartAddr );
-
/****************************************************************************************
* Name : InstAlloc_AddMember()
* Input : pms - Pointer to the INST_ALLOC instance
@@ -85,8 +79,4 @@
void InstAlloc_InitAll_NULL( INST_ALLOC *pms);
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
#endif /* __JBS_INSTALLOC_H__ */
diff --git a/media/libeffects/lvm/lib/Common/lib/LVM_Common.h b/media/libeffects/lvm/lib/Common/lib/LVM_Common.h
index ceccd7b..49f16ad 100644
--- a/media/libeffects/lvm/lib/Common/lib/LVM_Common.h
+++ b/media/libeffects/lvm/lib/Common/lib/LVM_Common.h
@@ -23,15 +23,9 @@
/* */
/****************************************************************************************/
-
#ifndef __LVM_COMMON_H__
#define __LVM_COMMON_H__
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-
/****************************************************************************************/
/* */
/* Includes */
@@ -39,7 +33,6 @@
/****************************************************************************************/
#include "LVM_Types.h"
-
/****************************************************************************************/
/* */
/* Definitions */
@@ -53,9 +46,5 @@
#define ALGORITHM_VC_ID 0x0500
#define ALGORITHM_TE_ID 0x0600
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
#endif /* __LVM_COMMON_H__ */
diff --git a/media/libeffects/lvm/lib/Common/lib/LVM_Macros.h b/media/libeffects/lvm/lib/Common/lib/LVM_Macros.h
index 97d13a5..1a15125 100644
--- a/media/libeffects/lvm/lib/Common/lib/LVM_Macros.h
+++ b/media/libeffects/lvm/lib/Common/lib/LVM_Macros.h
@@ -18,10 +18,6 @@
#ifndef _LVM_MACROS_H_
#define _LVM_MACROS_H_
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
/**********************************************************************************
MUL32x32INTO32(A,B,C,ShiftR)
C = (A * B) >> ShiftR
@@ -32,7 +28,6 @@
of overflow is undefined.
***********************************************************************************/
-#ifndef MUL32x32INTO32
#define MUL32x32INTO32(A,B,C,ShiftR) \
{LVM_INT32 MUL32x32INTO32_temp,MUL32x32INTO32_temp2,MUL32x32INTO32_mask,MUL32x32INTO32_HH,MUL32x32INTO32_HL,MUL32x32INTO32_LH,MUL32x32INTO32_LL;\
LVM_INT32 shiftValue;\
@@ -58,7 +53,6 @@
}\
(C) = MUL32x32INTO32_temp2;\
}
-#endif
/**********************************************************************************
MUL32x16INTO32(A,B,C,ShiftR)
@@ -71,7 +65,6 @@
of overflow is undefined.
***********************************************************************************/
-#ifndef MUL32x16INTO32
#define MUL32x16INTO32(A,B,C,ShiftR) \
{LVM_INT32 MUL32x16INTO32_mask,MUL32x16INTO32_HH,MUL32x16INTO32_LL;\
LVM_INT32 shiftValue;\
@@ -91,7 +84,6 @@
else {\
(C)=MUL32x16INTO32_HH>>(shiftValue-16);}\
}
-#endif
/**********************************************************************************
ADD2_SAT_32x32(A,B,C)
@@ -99,7 +91,6 @@
A,B and C are 32 bit SIGNED numbers.
***********************************************************************************/
-#ifndef ADD2_SAT_32x32
#define ADD2_SAT_32x32(A,B,C) \
{(C)=(A)+(B);\
if ((((C) ^ (A)) & ((C) ^ (B))) >> 31)\
@@ -110,12 +101,6 @@
(C)=0x7FFFFFFFl;\
}\
}
-#endif
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
#endif /* _LVM_MACROS_H_ */
diff --git a/media/libeffects/lvm/lib/Common/lib/LVM_Timer.h b/media/libeffects/lvm/lib/Common/lib/LVM_Timer.h
index a76354d..dbf9e6a 100644
--- a/media/libeffects/lvm/lib/Common/lib/LVM_Timer.h
+++ b/media/libeffects/lvm/lib/Common/lib/LVM_Timer.h
@@ -33,11 +33,6 @@
/* The timer currently does not suport changes in sampling rate while timing. */
/****************************************************************************************/
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
/****************************************************************************************/
/* TYPE DEFINITIONS */
/****************************************************************************************/
@@ -74,17 +69,11 @@
void LVM_Timer_Init ( LVM_Timer_Instance_t *pInstance,
LVM_Timer_Params_t *pParams );
-
void LVM_Timer ( LVM_Timer_Instance_t *pInstance,
LVM_INT16 BlockSize );
-
/****************************************************************************************/
/* END OF HEADER */
/****************************************************************************************/
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
#endif /* __LVM_TIMER_H__ */
diff --git a/media/libeffects/lvm/lib/Common/lib/LVM_Types.h b/media/libeffects/lvm/lib/Common/lib/LVM_Types.h
index fbfdd4d..8b687f6 100644
--- a/media/libeffects/lvm/lib/Common/lib/LVM_Types.h
+++ b/media/libeffects/lvm/lib/Common/lib/LVM_Types.h
@@ -25,10 +25,6 @@
#ifndef LVM_TYPES_H
#define LVM_TYPES_H
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
#include <stdint.h>
/****************************************************************************************/
@@ -96,32 +92,15 @@
typedef uint32_t LVM_UINT32; /* Unsigned 32-bit word */
typedef int64_t LVM_INT64; /* Signed 64-bit word */
-#ifdef BUILD_FLOAT
-
#define LVM_MAXFLOAT 1.f
typedef float LVM_FLOAT; /* single precision floating point */
-// If NATIVE_FLOAT_BUFFER is defined, we expose effects as floating point format;
-// otherwise we expose as integer 16 bit and translate to float for the effect libraries.
-// Hence, NATIVE_FLOAT_BUFFER should only be enabled under BUILD_FLOAT compilation.
-
-#define NATIVE_FLOAT_BUFFER
-
-#endif // BUILD_FLOAT
-
// Select whether we expose int16_t or float buffers.
-#ifdef NATIVE_FLOAT_BUFFER
#define EFFECT_BUFFER_FORMAT AUDIO_FORMAT_PCM_FLOAT
typedef float effect_buffer_t;
-#else // NATIVE_FLOAT_BUFFER
-
-#define EFFECT_BUFFER_FORMAT AUDIO_FORMAT_PCM_16_BIT
-typedef int16_t effect_buffer_t;
-
-#endif // NATIVE_FLOAT_BUFFER
#ifdef SUPPORT_MC
#define LVM_MAX_CHANNELS 8 // FCC_8
@@ -143,7 +122,6 @@
LVM_MODE_DUMMY = LVM_MAXENUM
} LVM_Mode_en;
-
/* Format */
typedef enum
{
@@ -156,7 +134,6 @@
LVM_SOURCE_DUMMY = LVM_MAXENUM
} LVM_Format_en;
-
/* LVM sampling rates */
typedef enum
{
@@ -169,17 +146,14 @@
LVM_FS_32000 = 6,
LVM_FS_44100 = 7,
LVM_FS_48000 = 8,
-#ifdef HIGHER_FS
LVM_FS_88200 = 9,
LVM_FS_96000 = 10,
LVM_FS_176400 = 11,
LVM_FS_192000 = 12,
-#endif
LVM_FS_INVALID = LVM_MAXENUM-1,
LVM_FS_DUMMY = LVM_MAXENUM
} LVM_Fs_en;
-
/* Memory Types */
typedef enum
{
@@ -190,7 +164,6 @@
LVM_MEMORYTYPE_DUMMY = LVM_MAXENUM
} LVM_MemoryTypes_en;
-
/* Memory region definition */
typedef struct
{
@@ -199,14 +172,12 @@
void *pBaseAddress; /* Pointer to the region base address */
} LVM_MemoryRegion_st;
-
/* Memory table containing the region definitions */
typedef struct
{
LVM_MemoryRegion_st Region[LVM_NR_MEMORY_REGIONS]; /* One definition for each region */
} LVM_MemoryTable_st;
-
/****************************************************************************************/
/* */
/* Standard Function Prototypes */
@@ -216,15 +187,10 @@
void *pGeneralPurpose, /* General purpose pointer (e.g. to a data structure needed in the callback) */
LVM_INT16 GeneralPurpose ); /* General purpose variable (e.g. to be used as callback ID) */
-
/****************************************************************************************/
/* */
/* End of file */
/* */
/****************************************************************************************/
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
#endif /* LVM_TYPES_H */
diff --git a/media/libeffects/lvm/lib/Common/lib/Mixer.h b/media/libeffects/lvm/lib/Common/lib/Mixer.h
index 07c53cd..b2e0195 100644
--- a/media/libeffects/lvm/lib/Common/lib/Mixer.h
+++ b/media/libeffects/lvm/lib/Common/lib/Mixer.h
@@ -18,19 +18,12 @@
#ifndef __MIXER_H__
#define __MIXER_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-
#include "LVM_Types.h"
/**********************************************************************************
INSTANCE MEMORY TYPE DEFINITION
***********************************************************************************/
-#ifdef BUILD_FLOAT /* BUILD_FLOAT*/
typedef struct
{
LVM_FLOAT Alpha; /* Time constant. Set by calling application. \
@@ -66,52 +59,11 @@
void *pGeneralPurpose2;
LVM_Callback pCallBack2;
} Mix_2St_Cll_FLOAT_t;
-#else
-typedef struct
-{
- LVM_INT32 Alpha; /* Time constant. Set by calling application. Can be changed at any time */
- LVM_INT32 Target; /* Target value. Set by calling application. Can be changed at any time */
- LVM_INT32 Current; /* Current value. Set by the mixer function. */
- LVM_INT16 CallbackSet; /* Boolean. Should be set by calling application each time the target value is updated */
- LVM_INT16 CallbackParam; /* Parameter that will be used in the calback function */
- void *pCallbackHandle; /* Pointer to the instance of the callback function */
- void *pGeneralPurpose; /* Pointer for general purpose usage */
- LVM_Callback pCallBack; /* Pointer to the callback function */
-} Mix_1St_Cll_t;
-
-typedef struct
-{
- LVM_INT32 Alpha1;
- LVM_INT32 Target1;
- LVM_INT32 Current1;
- LVM_INT16 CallbackSet1;
- LVM_INT16 CallbackParam1;
- void *pCallbackHandle1;
- void *pGeneralPurpose1;
- LVM_Callback pCallBack1;
-
- LVM_INT32 Alpha2; /* Warning the address of this location is passed as a pointer to Mix_1St_Cll_t in some functions */
- LVM_INT32 Target2;
- LVM_INT32 Current2;
- LVM_INT16 CallbackSet2;
- LVM_INT16 CallbackParam2;
- void *pCallbackHandle2;
- void *pGeneralPurpose2;
- LVM_Callback pCallBack2;
-
-} Mix_2St_Cll_t;
-
-#endif
/*** General functions ************************************************************/
-#ifdef BUILD_FLOAT
LVM_FLOAT LVM_Mixer_TimeConstant(LVM_UINT32 tc,
-#ifdef HIGHER_FS
LVM_UINT32 Fs,
-#else
- LVM_UINT16 Fs,
-#endif
LVM_UINT16 NumChannels);
void MixSoft_1St_D32C31_WRA( Mix_1St_Cll_FLOAT_t *pInstance,
@@ -129,34 +81,10 @@
const LVM_FLOAT *src,
LVM_FLOAT *dst,
LVM_INT16 n);
-#else
-LVM_UINT32 LVM_Mixer_TimeConstant(LVM_UINT32 tc,
- LVM_UINT16 Fs,
- LVM_UINT16 NumChannels);
-
-
-void MixSoft_1St_D32C31_WRA( Mix_1St_Cll_t *pInstance,
- const LVM_INT32 *src,
- LVM_INT32 *dst,
- LVM_INT16 n);
-
-void MixSoft_2St_D32C31_SAT( Mix_2St_Cll_t *pInstance,
- const LVM_INT32 *src1,
- const LVM_INT32 *src2,
- LVM_INT32 *dst,
- LVM_INT16 n);
-
-void MixInSoft_D32C31_SAT( Mix_1St_Cll_t *pInstance,
- const LVM_INT32 *src,
- LVM_INT32 *dst,
- LVM_INT16 n);
-
-#endif
/**********************************************************************************
FUNCTION PROTOTYPES (LOW LEVEL SUBFUNCTIONS)
***********************************************************************************/
-#ifdef BUILD_FLOAT
void Core_MixSoft_1St_D32C31_WRA( Mix_1St_Cll_FLOAT_t *pInstance,
const LVM_FLOAT *src,
LVM_FLOAT *dst,
@@ -170,27 +98,6 @@
const LVM_FLOAT *src,
LVM_FLOAT *dst,
LVM_INT16 n);
-#else
-void Core_MixSoft_1St_D32C31_WRA( Mix_1St_Cll_t *pInstance,
- const LVM_INT32 *src,
- LVM_INT32 *dst,
- LVM_INT16 n);
-
-void Core_MixHard_2St_D32C31_SAT( Mix_2St_Cll_t *pInstance,
- const LVM_INT32 *src1,
- const LVM_INT32 *src2,
- LVM_INT32 *dst,
- LVM_INT16 n);
-
-void Core_MixInSoft_D32C31_SAT( Mix_1St_Cll_t *pInstance,
- const LVM_INT32 *src,
- LVM_INT32 *dst,
- LVM_INT16 n);
-#endif
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/lib/ScalarArithmetic.h b/media/libeffects/lvm/lib/Common/lib/ScalarArithmetic.h
index cdb3837..ae54419 100644
--- a/media/libeffects/lvm/lib/Common/lib/ScalarArithmetic.h
+++ b/media/libeffects/lvm/lib/Common/lib/ScalarArithmetic.h
@@ -18,11 +18,6 @@
#ifndef __SCALARARITHMETIC_H__
#define __SCALARARITHMETIC_H__
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-
/*######################################################################################*/
/* Include files */
/*######################################################################################*/
@@ -35,11 +30,7 @@
/* Absolute value including the corner case for the extreme negative value */
-#ifdef BUILD_FLOAT
LVM_FLOAT Abs_Float(LVM_FLOAT input);
-#else
-LVM_INT32 Abs_32(LVM_INT32 input);
-#endif
/****************************************************************************************
* Name : dB_to_Lin32()
@@ -53,16 +44,7 @@
* (15->01) = decimal part
* Returns : Lin value format 1.16.15
****************************************************************************************/
-#ifdef BUILD_FLOAT
LVM_FLOAT dB_to_LinFloat(LVM_INT16 db_fix);
-#else
-LVM_INT32 dB_to_Lin32(LVM_INT16 db_fix);
-#endif
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
#endif /* __SCALARARITHMETIC_H__ */
-
diff --git a/media/libeffects/lvm/lib/Common/lib/VectorArithmetic.h b/media/libeffects/lvm/lib/Common/lib/VectorArithmetic.h
index 7468a90..b27bac5 100644
--- a/media/libeffects/lvm/lib/Common/lib/VectorArithmetic.h
+++ b/media/libeffects/lvm/lib/Common/lib/VectorArithmetic.h
@@ -18,32 +18,16 @@
#ifndef _VECTOR_ARITHMETIC_H_
#define _VECTOR_ARITHMETIC_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
#include "LVM_Types.h"
/**********************************************************************************
VARIOUS FUNCTIONS
***********************************************************************************/
-#ifdef BUILD_FLOAT
void LoadConst_Float( const LVM_FLOAT val,
LVM_FLOAT *dst,
LVM_INT16 n );
-#else
-void LoadConst_16( const LVM_INT16 val,
- LVM_INT16 *dst,
- LVM_INT16 n );
-void LoadConst_32( const LVM_INT32 val,
- LVM_INT32 *dst,
- LVM_INT16 n );
-#endif
-
-#ifdef BUILD_FLOAT
void Copy_Float( const LVM_FLOAT *src,
LVM_FLOAT *dst,
LVM_INT16 n );
@@ -53,15 +37,11 @@
LVM_INT16 NrFrames,
LVM_INT32 NrChannels);
void Copy_Float_Stereo_Mc( const LVM_FLOAT *src,
+ LVM_FLOAT *StereoOut,
LVM_FLOAT *dst,
LVM_INT16 NrFrames,
LVM_INT32 NrChannels);
#endif
-#else
-void Copy_16( const LVM_INT16 *src,
- LVM_INT16 *dst,
- LVM_INT16 n );
-#endif
/*********************************************************************************
* note: In Mult3s_16x16() saturation of result is not taken care when *
@@ -71,17 +51,10 @@
* This is the only case which will give wrong result. *
* For more information refer to Vector_Arithmetic.doc in /doc folder *
*********************************************************************************/
-#ifdef BUILD_FLOAT
void Mult3s_Float( const LVM_FLOAT *src,
const LVM_FLOAT val,
LVM_FLOAT *dst,
LVM_INT16 n);
-#else
-void Mult3s_16x16( const LVM_INT16 *src,
- const LVM_INT16 val,
- LVM_INT16 *dst,
- LVM_INT16 n);
-#endif
/*********************************************************************************
* note: In Mult3s_32x16() saturation of result is not taken care when *
@@ -95,55 +68,24 @@
const LVM_INT16 val,
LVM_INT32 *dst,
LVM_INT16 n);
-#ifdef BUILD_FLOAT
void DelayMix_Float(const LVM_FLOAT *src, /* Source 1, to be delayed */
LVM_FLOAT *delay, /* Delay buffer */
LVM_INT16 size, /* Delay size */
LVM_FLOAT *dst, /* Source/destination */
LVM_INT16 *pOffset, /* Delay offset */
LVM_INT16 n) ; /* Number of stereo samples */
-#else
-void DelayMix_16x16( const LVM_INT16 *src,
- LVM_INT16 *delay,
- LVM_INT16 size,
- LVM_INT16 *dst,
- LVM_INT16 *pOffset,
- LVM_INT16 n);
-#endif
void DelayWrite_32( const LVM_INT32 *src, /* Source 1, to be delayed */
LVM_INT32 *delay, /* Delay buffer */
LVM_UINT16 size, /* Delay size */
LVM_UINT16 *pOffset, /* Delay offset */
LVM_INT16 n);
-#ifdef BUILD_FLOAT
void Add2_Sat_Float( const LVM_FLOAT *src,
LVM_FLOAT *dst,
LVM_INT16 n );
-#else
-void Add2_Sat_16x16( const LVM_INT16 *src,
- LVM_INT16 *dst,
- LVM_INT16 n );
-
-void Add2_Sat_32x32( const LVM_INT32 *src,
- LVM_INT32 *dst,
- LVM_INT16 n );
-#endif
-#ifdef BUILD_FLOAT
void Mac3s_Sat_Float( const LVM_FLOAT *src,
const LVM_FLOAT val,
LVM_FLOAT *dst,
LVM_INT16 n);
-#else
-void Mac3s_Sat_16x16( const LVM_INT16 *src,
- const LVM_INT16 val,
- LVM_INT16 *dst,
- LVM_INT16 n);
-
-void Mac3s_Sat_32x16( const LVM_INT32 *src,
- const LVM_INT16 val,
- LVM_INT32 *dst,
- LVM_INT16 n);
-#endif
void DelayAllPass_Sat_32x16To32( LVM_INT32 *delay, /* Delay buffer */
LVM_UINT16 size, /* Delay size */
LVM_INT16 coeff, /* All pass filter coefficient */
@@ -155,39 +97,16 @@
/**********************************************************************************
SHIFT FUNCTIONS
***********************************************************************************/
-#ifdef BUILD_FLOAT
void Shift_Sat_Float (const LVM_INT16 val,
const LVM_FLOAT *src,
LVM_FLOAT *dst,
LVM_INT16 n);
-#else
-void Shift_Sat_v16xv16 ( const LVM_INT16 val,
- const LVM_INT16 *src,
- LVM_INT16 *dst,
- LVM_INT16 n);
-
-void Shift_Sat_v32xv32 ( const LVM_INT16 val,
- const LVM_INT32 *src,
- LVM_INT32 *dst,
- LVM_INT16 n);
-#endif
/**********************************************************************************
AUDIO FORMAT CONVERSION FUNCTIONS
***********************************************************************************/
-#ifdef BUILD_FLOAT
void MonoTo2I_Float( const LVM_FLOAT *src,
LVM_FLOAT *dst,
LVM_INT16 n);
-#else
-void MonoTo2I_16( const LVM_INT16 *src,
- LVM_INT16 *dst,
- LVM_INT16 n);
-
-void MonoTo2I_32( const LVM_INT32 *src,
- LVM_INT32 *dst,
- LVM_INT16 n);
-#endif
-#ifdef BUILD_FLOAT
void From2iToMono_Float( const LVM_FLOAT *src,
LVM_FLOAT *dst,
LVM_INT16 n);
@@ -197,47 +116,18 @@
LVM_INT16 NrFrames,
LVM_INT16 NrChannels);
#endif
-#else
-void From2iToMono_32( const LVM_INT32 *src,
- LVM_INT32 *dst,
- LVM_INT16 n);
-#endif
-#ifdef BUILD_FLOAT
void MSTo2i_Sat_Float( const LVM_FLOAT *srcM,
const LVM_FLOAT *srcS,
LVM_FLOAT *dst,
LVM_INT16 n );
-#else
-void MSTo2i_Sat_16x16( const LVM_INT16 *srcM,
- const LVM_INT16 *srcS,
- LVM_INT16 *dst,
- LVM_INT16 n );
-#endif
-#ifdef BUILD_FLOAT
void From2iToMS_Float( const LVM_FLOAT *src,
LVM_FLOAT *dstM,
LVM_FLOAT *dstS,
LVM_INT16 n );
-#else
-void From2iToMS_16x16( const LVM_INT16 *src,
- LVM_INT16 *dstM,
- LVM_INT16 *dstS,
- LVM_INT16 n );
-#endif
-#ifdef BUILD_FLOAT
void JoinTo2i_Float( const LVM_FLOAT *srcL,
const LVM_FLOAT *srcR,
LVM_FLOAT *dst,
LVM_INT16 n );
-#else
-void From2iToMono_16( const LVM_INT16 *src,
- LVM_INT16 *dst,
- LVM_INT16 n);
-void JoinTo2i_32x32( const LVM_INT32 *srcL,
- const LVM_INT32 *srcR,
- LVM_INT32 *dst,
- LVM_INT16 n );
-#endif
/**********************************************************************************
DATA TYPE CONVERSION FUNCTIONS
@@ -253,11 +143,6 @@
LVM_INT16 n,
LVM_INT16 shift );
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-
/**********************************************************************************/
#endif /* _VECTOR_ARITHMETIC_H_ */
diff --git a/media/libeffects/lvm/lib/Common/src/AGC_MIX_VOL_2St1Mon_D32_WRA.c b/media/libeffects/lvm/lib/Common/src/AGC_MIX_VOL_2St1Mon_D32_WRA.c
deleted file mode 100644
index 5c8655f..0000000
--- a/media/libeffects/lvm/lib/Common/src/AGC_MIX_VOL_2St1Mon_D32_WRA.c
+++ /dev/null
@@ -1,454 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/****************************************************************************************/
-/* */
-/* Includes */
-/* */
-/****************************************************************************************/
-
-#include "AGC.h"
-#include "ScalarArithmetic.h"
-
-
-/****************************************************************************************/
-/* */
-/* Defines */
-/* */
-/****************************************************************************************/
-
-#define VOL_TC_SHIFT 21 /* As a power of 2 */
-#define DECAY_SHIFT 10 /* As a power of 2 */
-#ifdef BUILD_FLOAT
-#define VOL_TC_FLOAT 2.0f /* As a power of 2 */
-#define DECAY_FAC_FLOAT 64.0f /* As a power of 2 */
-#endif
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: AGC_MIX_VOL_2St1Mon_D32_WRA */
-/* */
-/* DESCRIPTION: */
-/* Apply AGC and mix signals */
-/* */
-/* */
-/* StSrc ------------------| */
-/* | */
-/* ______ _|_ ________ */
-/* | | | | | | */
-/* MonoSrc -->| AGC |---->| + |----->| Volume |------------------------------+---> */
-/* | Gain | |___| | Gain | | */
-/* |______| |________| | */
-/* /|\ __________ ________ | */
-/* | | | | | | */
-/* |-------------------------------| AGC Gain |<--| Peak |<--| */
-/* | Update | | Detect | */
-/* |__________| |________| */
-/* */
-/* */
-/* PARAMETERS: */
-/* pInstance Instance pointer */
-/* pStereoIn Stereo source */
-/* pMonoIn Mono band pass source */
-/* pStereoOut Stereo destination */
-/* */
-/* RETURNS: */
-/* Void */
-/* */
-/* NOTES: */
-/* */
-/****************************************************************************************/
-#ifndef BUILD_FLOAT
-void AGC_MIX_VOL_2St1Mon_D32_WRA(AGC_MIX_VOL_2St1Mon_D32_t *pInstance, /* Instance pointer */
- const LVM_INT32 *pStSrc, /* Stereo source */
- const LVM_INT32 *pMonoSrc, /* Mono source */
- LVM_INT32 *pDst, /* Stereo destination */
- LVM_UINT16 NumSamples) /* Number of samples */
-{
-
- /*
- * General variables
- */
- LVM_UINT16 i; /* Sample index */
- LVM_INT32 Left; /* Left sample */
- LVM_INT32 Right; /* Right sample */
- LVM_INT32 Mono; /* Mono sample */
- LVM_INT32 AbsPeak; /* Absolute peak signal */
- LVM_INT32 HighWord; /* High word in intermediate calculations */
- LVM_INT32 LowWord; /* Low word in intermediate calculations */
- LVM_INT16 AGC_Mult; /* Short AGC gain */
- LVM_INT16 Vol_Mult; /* Short volume */
-
-
- /*
- * Instance control variables
- */
- LVM_INT32 AGC_Gain = pInstance->AGC_Gain; /* Get the current AGC gain */
- LVM_INT32 AGC_MaxGain = pInstance->AGC_MaxGain; /* Get maximum AGC gain */
- LVM_INT16 AGC_GainShift = pInstance->AGC_GainShift; /* Get the AGC shift */
- LVM_INT16 AGC_Attack = pInstance->AGC_Attack; /* Attack scaler */
- LVM_INT16 AGC_Decay = pInstance->AGC_Decay; /* Decay scaler */
- LVM_INT32 AGC_Target = pInstance->AGC_Target; /* Get the target level */
- LVM_INT32 Vol_Current = pInstance->Volume; /* Actual volume setting */
- LVM_INT32 Vol_Target = pInstance->Target; /* Target volume setting */
- LVM_INT16 Vol_Shift = pInstance->VolumeShift; /* Volume shift scaling */
- LVM_INT16 Vol_TC = pInstance->VolumeTC; /* Time constant */
-
-
- /*
- * Process on a sample by sample basis
- */
- for (i=0;i<NumSamples;i++) /* For each sample */
- {
-
- /*
- * Get the short scalers
- */
- AGC_Mult = (LVM_INT16)(AGC_Gain >> 16); /* Get the short AGC gain */
- Vol_Mult = (LVM_INT16)(Vol_Current >> 16); /* Get the short volume gain */
-
-
- /*
- * Get the input samples
- */
- Left = *pStSrc++; /* Get the left sample */
- Right = *pStSrc++; /* Get the right sample */
- Mono = *pMonoSrc++; /* Get the mono sample */
-
-
- /*
- * Apply the AGC gain to the mono input and mix with the stereo signal
- */
- HighWord = (AGC_Mult * (Mono >> 16)); /* signed long (Mono) by unsigned short (AGC_Mult) multiply */
- LowWord = (AGC_Mult * (Mono & 0xffff));
- Mono = (HighWord + (LowWord >> 16)) << (AGC_GainShift);
- Left += Mono; /* Mix in the mono signal */
- Right += Mono;
-
-
- /*
- * Apply the volume and write to the output stream
- */
- HighWord = (Vol_Mult * (Left >> 16)); /* signed long (Left) by unsigned short (Vol_Mult) multiply */
- LowWord = (Vol_Mult * (Left & 0xffff));
- Left = (HighWord + (LowWord >> 16)) << (Vol_Shift);
- HighWord = (Vol_Mult * (Right >> 16)); /* signed long (Right) by unsigned short (Vol_Mult) multiply */
- LowWord = (Vol_Mult * (Right & 0xffff));
- Right = (HighWord + (LowWord >> 16)) << (Vol_Shift);
- *pDst++ = Left; /* Save the results */
- *pDst++ = Right;
-
-
- /*
- * Update the AGC gain
- */
- AbsPeak = (Abs_32(Left)>Abs_32(Right)) ? Abs_32(Left) : Abs_32(Right); /* Get the absolute peak */
- if (AbsPeak > AGC_Target)
- {
- /*
- * The signal is too large so decrease the gain
- */
- HighWord = (AGC_Attack * (AGC_Gain >> 16)); /* signed long (AGC_Gain) by unsigned short (AGC_Attack) multiply */
- LowWord = (AGC_Attack * (AGC_Gain & 0xffff));
- AGC_Gain = (HighWord + (LowWord >> 16)) << 1;
- }
- else
- {
- /*
- * The signal is too small so increase the gain
- */
- if (AGC_Gain > AGC_MaxGain)
- {
- AGC_Gain -= (AGC_Decay << DECAY_SHIFT);
- }
- else
- {
- AGC_Gain += (AGC_Decay << DECAY_SHIFT);
- }
- }
-
- /*
- * Update the gain
- */
- Vol_Current += Vol_TC * ((Vol_Target - Vol_Current) >> VOL_TC_SHIFT);
- }
-
-
- /*
- * Update the parameters
- */
- pInstance->Volume = Vol_Current; /* Actual volume setting */
- pInstance->AGC_Gain = AGC_Gain;
-
- return;
-}
-#else
-void AGC_MIX_VOL_2St1Mon_D32_WRA(AGC_MIX_VOL_2St1Mon_FLOAT_t *pInstance, /* Instance pointer */
- const LVM_FLOAT *pStSrc, /* Stereo source */
- const LVM_FLOAT *pMonoSrc, /* Mono source */
- LVM_FLOAT *pDst, /* Stereo destination */
- LVM_UINT16 NumSamples) /* Number of samples */
-{
-
- /*
- * General variables
- */
- LVM_UINT16 i; /* Sample index */
- LVM_FLOAT Left; /* Left sample */
- LVM_FLOAT Right; /* Right sample */
- LVM_FLOAT Mono; /* Mono sample */
- LVM_FLOAT AbsPeak; /* Absolute peak signal */
- LVM_FLOAT AGC_Mult; /* Short AGC gain */
- LVM_FLOAT Vol_Mult; /* Short volume */
-
-
- /*
- * Instance control variables
- */
- LVM_FLOAT AGC_Gain = pInstance->AGC_Gain; /* Get the current AGC gain */
- LVM_FLOAT AGC_MaxGain = pInstance->AGC_MaxGain; /* Get maximum AGC gain */
- LVM_FLOAT AGC_Attack = pInstance->AGC_Attack; /* Attack scaler */
- LVM_FLOAT AGC_Decay = (pInstance->AGC_Decay * (1 << (DECAY_SHIFT)));/* Decay scaler */
- LVM_FLOAT AGC_Target = pInstance->AGC_Target; /* Get the target level */
- LVM_FLOAT Vol_Current = pInstance->Volume; /* Actual volume setting */
- LVM_FLOAT Vol_Target = pInstance->Target; /* Target volume setting */
- LVM_FLOAT Vol_TC = pInstance->VolumeTC; /* Time constant */
-
-
- /*
- * Process on a sample by sample basis
- */
- for (i = 0; i < NumSamples; i++) /* For each sample */
- {
-
- /*
- * Get the short scalers
- */
- AGC_Mult = (LVM_FLOAT)(AGC_Gain); /* Get the short AGC gain */
- Vol_Mult = (LVM_FLOAT)(Vol_Current); /* Get the short volume gain */
-
-
- /*
- * Get the input samples
- */
- Left = *pStSrc++; /* Get the left sample */
- Right = *pStSrc++; /* Get the right sample */
- Mono = *pMonoSrc++; /* Get the mono sample */
-
-
- /*
- * Apply the AGC gain to the mono input and mix with the stereo signal
- */
- Left += (Mono * AGC_Mult); /* Mix in the mono signal */
- Right += (Mono * AGC_Mult);
-
- /*
- * Apply the volume and write to the output stream
- */
- Left = Left * Vol_Mult;
- Right = Right * Vol_Mult;
- *pDst++ = Left; /* Save the results */
- *pDst++ = Right;
-
- /*
- * Update the AGC gain
- */
- AbsPeak = Abs_Float(Left) > Abs_Float(Right) ? Abs_Float(Left) : Abs_Float(Right);
- if (AbsPeak > AGC_Target)
- {
- /*
- * The signal is too large so decrease the gain
- */
- AGC_Gain = AGC_Gain * AGC_Attack;
- }
- else
- {
- /*
- * The signal is too small so increase the gain
- */
- if (AGC_Gain > AGC_MaxGain)
- {
- AGC_Gain -= (AGC_Decay);
- }
- else
- {
- AGC_Gain += (AGC_Decay);
- }
- }
-
- /*
- * Update the gain
- */
- Vol_Current += (Vol_Target - Vol_Current) * ((LVM_FLOAT)Vol_TC / VOL_TC_FLOAT);
- }
-
-
- /*
- * Update the parameters
- */
- pInstance->Volume = Vol_Current; /* Actual volume setting */
- pInstance->AGC_Gain = AGC_Gain;
-
- return;
-}
-#ifdef SUPPORT_MC
-/****************************************************************************************/
-/* */
-/* FUNCTION: AGC_MIX_VOL_Mc1Mon_D32_WRA */
-/* */
-/* DESCRIPTION: */
-/* Apply AGC and mix signals */
-/* */
-/* */
-/* McSrc ------------------| */
-/* | */
-/* ______ _|_ ________ */
-/* | | | | | | */
-/* MonoSrc -->| AGC |---->| + |----->| Volume |------------------------------+---> */
-/* | Gain | |___| | Gain | | */
-/* |______| |________| | */
-/* /|\ __________ ________ | */
-/* | | | | | | */
-/* |-------------------------------| AGC Gain |<--| Peak |<--| */
-/* | Update | | Detect | */
-/* |__________| |________| */
-/* */
-/* */
-/* PARAMETERS: */
-/* pInstance Instance pointer */
-/* pMcSrc Multichannel source */
-/* pMonoSrc Mono band pass source */
-/* pDst Multichannel destination */
-/* NrFrames Number of frames */
-/* NrChannels Number of channels */
-/* */
-/* RETURNS: */
-/* Void */
-/* */
-/* NOTES: */
-/* */
-/****************************************************************************************/
-void AGC_MIX_VOL_Mc1Mon_D32_WRA(AGC_MIX_VOL_2St1Mon_FLOAT_t *pInstance,
- const LVM_FLOAT *pMcSrc,
- const LVM_FLOAT *pMonoSrc,
- LVM_FLOAT *pDst,
- LVM_UINT16 NrFrames,
- LVM_UINT16 NrChannels)
-{
-
- /*
- * General variables
- */
- LVM_UINT16 i, jj; /* Sample index */
- LVM_FLOAT SampleVal; /* Sample value */
- LVM_FLOAT Mono; /* Mono sample */
- LVM_FLOAT AbsPeak; /* Absolute peak signal */
- LVM_FLOAT AGC_Mult; /* Short AGC gain */
- LVM_FLOAT Vol_Mult; /* Short volume */
-
-
- /*
- * Instance control variables
- */
- LVM_FLOAT AGC_Gain = pInstance->AGC_Gain; /* Get the current AGC gain */
- LVM_FLOAT AGC_MaxGain = pInstance->AGC_MaxGain; /* Get maximum AGC gain */
- LVM_FLOAT AGC_Attack = pInstance->AGC_Attack; /* Attack scaler */
- /* Decay scaler */
- LVM_FLOAT AGC_Decay = (pInstance->AGC_Decay * (1 << (DECAY_SHIFT)));
- LVM_FLOAT AGC_Target = pInstance->AGC_Target; /* Get the target level */
- LVM_FLOAT Vol_Current = pInstance->Volume; /* Actual volume setting */
- LVM_FLOAT Vol_Target = pInstance->Target; /* Target volume setting */
- LVM_FLOAT Vol_TC = pInstance->VolumeTC; /* Time constant */
-
-
- /*
- * Process on a sample by sample basis
- */
- for (i = 0; i < NrFrames; i++) /* For each frame */
- {
-
- /*
- * Get the scalers
- */
- AGC_Mult = (LVM_FLOAT)(AGC_Gain); /* Get the AGC gain */
- Vol_Mult = (LVM_FLOAT)(Vol_Current); /* Get the volume gain */
-
- AbsPeak = 0.0f;
- /*
- * Get the input samples
- */
- for (jj = 0; jj < NrChannels; jj++)
- {
- SampleVal = *pMcSrc++; /* Get the sample value of jj Channel*/
- Mono = *pMonoSrc; /* Get the mono sample */
-
- /*
- * Apply the AGC gain to the mono input and mix with the input signal
- */
- SampleVal += (Mono * AGC_Mult); /* Mix in the mono signal */
-
- /*
- * Apply the volume and write to the output stream
- */
- SampleVal = SampleVal * Vol_Mult;
-
- *pDst++ = SampleVal; /* Save the results */
-
- /*
- * Update the AGC gain
- */
- AbsPeak = Abs_Float(SampleVal) > AbsPeak ? Abs_Float(SampleVal) : AbsPeak;
- }
- if (AbsPeak > AGC_Target)
- {
- /*
- * The signal is too large so decrease the gain
- */
- AGC_Gain = AGC_Gain * AGC_Attack;
- }
- else
- {
- /*
- * The signal is too small so increase the gain
- */
- if (AGC_Gain > AGC_MaxGain)
- {
- AGC_Gain -= (AGC_Decay);
- }
- else
- {
- AGC_Gain += (AGC_Decay);
- }
- }
- pMonoSrc++;
- /*
- * Update the gain
- */
- Vol_Current += (Vol_Target - Vol_Current) * ((LVM_FLOAT)Vol_TC / VOL_TC_FLOAT);
- }
-
-
- /*
- * Update the parameters
- */
- pInstance->Volume = Vol_Current; /* Actual volume setting */
- pInstance->AGC_Gain = AGC_Gain;
-
- return;
-}
-#endif /*SUPPORT_MC*/
-#endif /*BUILD_FLOAT*/
diff --git a/media/libeffects/lvm/lib/Common/src/AGC_MIX_VOL_2St1Mon_D32_WRA.cpp b/media/libeffects/lvm/lib/Common/src/AGC_MIX_VOL_2St1Mon_D32_WRA.cpp
new file mode 100644
index 0000000..e18aa78
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/AGC_MIX_VOL_2St1Mon_D32_WRA.cpp
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/****************************************************************************************/
+/* */
+/* Includes */
+/* */
+/****************************************************************************************/
+
+#include "AGC.h"
+#include "ScalarArithmetic.h"
+
+/****************************************************************************************/
+/* */
+/* Defines */
+/* */
+/****************************************************************************************/
+
+#define VOL_TC_SHIFT 21 /* As a power of 2 */
+#define DECAY_SHIFT 10 /* As a power of 2 */
+#define VOL_TC_FLOAT 2.0f /* As a power of 2 */
+#define DECAY_FAC_FLOAT 64.0f /* As a power of 2 */
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: AGC_MIX_VOL_2St1Mon_D32_WRA */
+/* */
+/* DESCRIPTION: */
+/* Apply AGC and mix signals */
+/* */
+/* */
+/* StSrc ------------------| */
+/* | */
+/* ______ _|_ ________ */
+/* | | | | | | */
+/* MonoSrc -->| AGC |---->| + |----->| Volume |------------------------------+---> */
+/* | Gain | |___| | Gain | | */
+/* |______| |________| | */
+/* /|\ __________ ________ | */
+/* | | | | | | */
+/* |-------------------------------| AGC Gain |<--| Peak |<--| */
+/* | Update | | Detect | */
+/* |__________| |________| */
+/* */
+/* */
+/* PARAMETERS: */
+/* pInstance Instance pointer */
+/* pStereoIn Stereo source */
+/* pMonoIn Mono band pass source */
+/* pStereoOut Stereo destination */
+/* */
+/* RETURNS: */
+/* Void */
+/* */
+/* NOTES: */
+/* */
+/****************************************************************************************/
+void AGC_MIX_VOL_2St1Mon_D32_WRA(AGC_MIX_VOL_2St1Mon_FLOAT_t *pInstance, /* Instance pointer */
+ const LVM_FLOAT *pStSrc, /* Stereo source */
+ const LVM_FLOAT *pMonoSrc, /* Mono source */
+ LVM_FLOAT *pDst, /* Stereo destination */
+ LVM_UINT16 NumSamples) /* Number of samples */
+{
+
+ /*
+ * General variables
+ */
+ LVM_UINT16 i; /* Sample index */
+ LVM_FLOAT Left; /* Left sample */
+ LVM_FLOAT Right; /* Right sample */
+ LVM_FLOAT Mono; /* Mono sample */
+ LVM_FLOAT AbsPeak; /* Absolute peak signal */
+ LVM_FLOAT AGC_Mult; /* Short AGC gain */
+ LVM_FLOAT Vol_Mult; /* Short volume */
+
+ /*
+ * Instance control variables
+ */
+ LVM_FLOAT AGC_Gain = pInstance->AGC_Gain; /* Get the current AGC gain */
+ LVM_FLOAT AGC_MaxGain = pInstance->AGC_MaxGain; /* Get maximum AGC gain */
+ LVM_FLOAT AGC_Attack = pInstance->AGC_Attack; /* Attack scaler */
+ LVM_FLOAT AGC_Decay = (pInstance->AGC_Decay * (1 << (DECAY_SHIFT)));/* Decay scaler */
+ LVM_FLOAT AGC_Target = pInstance->AGC_Target; /* Get the target level */
+ LVM_FLOAT Vol_Current = pInstance->Volume; /* Actual volume setting */
+ LVM_FLOAT Vol_Target = pInstance->Target; /* Target volume setting */
+ LVM_FLOAT Vol_TC = pInstance->VolumeTC; /* Time constant */
+
+ /*
+ * Process on a sample by sample basis
+ */
+ for (i = 0; i < NumSamples; i++) /* For each sample */
+ {
+
+ /*
+ * Get the short scalers
+ */
+ AGC_Mult = (LVM_FLOAT)(AGC_Gain); /* Get the short AGC gain */
+ Vol_Mult = (LVM_FLOAT)(Vol_Current); /* Get the short volume gain */
+
+ /*
+ * Get the input samples
+ */
+ Left = *pStSrc++; /* Get the left sample */
+ Right = *pStSrc++; /* Get the right sample */
+ Mono = *pMonoSrc++; /* Get the mono sample */
+
+ /*
+ * Apply the AGC gain to the mono input and mix with the stereo signal
+ */
+ Left += (Mono * AGC_Mult); /* Mix in the mono signal */
+ Right += (Mono * AGC_Mult);
+
+ /*
+ * Apply the volume and write to the output stream
+ */
+ Left = Left * Vol_Mult;
+ Right = Right * Vol_Mult;
+ *pDst++ = Left; /* Save the results */
+ *pDst++ = Right;
+
+ /*
+ * Update the AGC gain
+ */
+ AbsPeak = Abs_Float(Left) > Abs_Float(Right) ? Abs_Float(Left) : Abs_Float(Right);
+ if (AbsPeak > AGC_Target)
+ {
+ /*
+ * The signal is too large so decrease the gain
+ */
+ AGC_Gain = AGC_Gain * AGC_Attack;
+ }
+ else
+ {
+ /*
+ * The signal is too small so increase the gain
+ */
+ if (AGC_Gain > AGC_MaxGain)
+ {
+ AGC_Gain -= (AGC_Decay);
+ }
+ else
+ {
+ AGC_Gain += (AGC_Decay);
+ }
+ }
+
+ /*
+ * Update the gain
+ */
+ Vol_Current += (Vol_Target - Vol_Current) * ((LVM_FLOAT)Vol_TC / VOL_TC_FLOAT);
+ }
+
+ /*
+ * Update the parameters
+ */
+ pInstance->Volume = Vol_Current; /* Actual volume setting */
+ pInstance->AGC_Gain = AGC_Gain;
+
+ return;
+}
+#ifdef SUPPORT_MC
+/****************************************************************************************/
+/* */
+/* FUNCTION: AGC_MIX_VOL_Mc1Mon_D32_WRA */
+/* */
+/* DESCRIPTION: */
+/* Apply AGC and mix signals */
+/* */
+/* */
+/* McSrc ------------------| */
+/* | */
+/* ______ _|_ ________ */
+/* | | | | | | */
+/* MonoSrc -->| AGC |---->| + |----->| Volume |------------------------------+---> */
+/* | Gain | |___| | Gain | | */
+/* |______| |________| | */
+/* /|\ __________ ________ | */
+/* | | | | | | */
+/* |-------------------------------| AGC Gain |<--| Peak |<--| */
+/* | Update | | Detect | */
+/* |__________| |________| */
+/* */
+/* */
+/* PARAMETERS: */
+/* pInstance Instance pointer */
+/* pMcSrc Multichannel source */
+/* pMonoSrc Mono band pass source */
+/* pDst Multichannel destination */
+/* NrFrames Number of frames */
+/* NrChannels Number of channels */
+/* */
+/* RETURNS: */
+/* Void */
+/* */
+/* NOTES: */
+/* */
+/****************************************************************************************/
+void AGC_MIX_VOL_Mc1Mon_D32_WRA(AGC_MIX_VOL_2St1Mon_FLOAT_t *pInstance,
+ const LVM_FLOAT *pMcSrc,
+ const LVM_FLOAT *pMonoSrc,
+ LVM_FLOAT *pDst,
+ LVM_UINT16 NrFrames,
+ LVM_UINT16 NrChannels)
+{
+
+ /*
+ * General variables
+ */
+ LVM_UINT16 i, jj; /* Sample index */
+ LVM_FLOAT SampleVal; /* Sample value */
+ LVM_FLOAT Mono; /* Mono sample */
+ LVM_FLOAT AbsPeak; /* Absolute peak signal */
+ LVM_FLOAT AGC_Mult; /* Short AGC gain */
+ LVM_FLOAT Vol_Mult; /* Short volume */
+
+ /*
+ * Instance control variables
+ */
+ LVM_FLOAT AGC_Gain = pInstance->AGC_Gain; /* Get the current AGC gain */
+ LVM_FLOAT AGC_MaxGain = pInstance->AGC_MaxGain; /* Get maximum AGC gain */
+ LVM_FLOAT AGC_Attack = pInstance->AGC_Attack; /* Attack scaler */
+ /* Decay scaler */
+ LVM_FLOAT AGC_Decay = (pInstance->AGC_Decay * (1 << (DECAY_SHIFT)));
+ LVM_FLOAT AGC_Target = pInstance->AGC_Target; /* Get the target level */
+ LVM_FLOAT Vol_Current = pInstance->Volume; /* Actual volume setting */
+ LVM_FLOAT Vol_Target = pInstance->Target; /* Target volume setting */
+ LVM_FLOAT Vol_TC = pInstance->VolumeTC; /* Time constant */
+
+ /*
+ * Process on a sample by sample basis
+ */
+ for (i = 0; i < NrFrames; i++) /* For each frame */
+ {
+
+ /*
+ * Get the scalers
+ */
+ AGC_Mult = (LVM_FLOAT)(AGC_Gain); /* Get the AGC gain */
+ Vol_Mult = (LVM_FLOAT)(Vol_Current); /* Get the volume gain */
+
+ AbsPeak = 0.0f;
+ /*
+ * Get the input samples
+ */
+ for (jj = 0; jj < NrChannels; jj++)
+ {
+ SampleVal = *pMcSrc++; /* Get the sample value of jj Channel*/
+ Mono = *pMonoSrc; /* Get the mono sample */
+
+ /*
+ * Apply the AGC gain to the mono input and mix with the input signal
+ */
+ SampleVal += (Mono * AGC_Mult); /* Mix in the mono signal */
+
+ /*
+ * Apply the volume and write to the output stream
+ */
+ SampleVal = SampleVal * Vol_Mult;
+
+ *pDst++ = SampleVal; /* Save the results */
+
+ /*
+ * Update the AGC gain
+ */
+ AbsPeak = Abs_Float(SampleVal) > AbsPeak ? Abs_Float(SampleVal) : AbsPeak;
+ }
+ if (AbsPeak > AGC_Target)
+ {
+ /*
+ * The signal is too large so decrease the gain
+ */
+ AGC_Gain = AGC_Gain * AGC_Attack;
+ }
+ else
+ {
+ /*
+ * The signal is too small so increase the gain
+ */
+ if (AGC_Gain > AGC_MaxGain)
+ {
+ AGC_Gain -= (AGC_Decay);
+ }
+ else
+ {
+ AGC_Gain += (AGC_Decay);
+ }
+ }
+ pMonoSrc++;
+ /*
+ * Update the gain
+ */
+ Vol_Current += (Vol_Target - Vol_Current) * ((LVM_FLOAT)Vol_TC / VOL_TC_FLOAT);
+ }
+
+ /*
+ * Update the parameters
+ */
+ pInstance->Volume = Vol_Current; /* Actual volume setting */
+ pInstance->AGC_Gain = AGC_Gain;
+
+ return;
+}
+#endif /*SUPPORT_MC*/
diff --git a/media/libeffects/lvm/lib/Common/src/Abs_32.c b/media/libeffects/lvm/lib/Common/src/Abs_32.c
deleted file mode 100644
index 84fabd8..0000000
--- a/media/libeffects/lvm/lib/Common/src/Abs_32.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*######################################################################################*/
-/* Include files */
-/*######################################################################################*/
-
-#include "ScalarArithmetic.h"
-
-/****************************************************************************************
- * Name : Abs_32()
- * Input : Signed 32-bit integer
- * Output :
- * Returns : Absolute value
- * Description : Absolute value with maximum negative value corner case
- * Remarks :
- ****************************************************************************************/
-
-LVM_INT32 Abs_32(LVM_INT32 input)
-{
- if(input < 0)
- {
- if (input == (LVM_INT32)(0x80000000U))
- {
- /* The corner case, so set to the maximum positive value */
- input=(LVM_INT32) 0x7fffffff;
- }
- else
- {
- /* Negative input, so invert */
- input = (LVM_INT32)(-input);
- }
- }
- return input;
-}
-#ifdef BUILD_FLOAT
-LVM_FLOAT Abs_Float(LVM_FLOAT input)
-{
- if(input < 0)
- {
- /* Negative input, so invert */
- input = (LVM_FLOAT)(-input);
- }
- return input;
-}
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/Abs_32.cpp b/media/libeffects/lvm/lib/Common/src/Abs_32.cpp
new file mode 100644
index 0000000..e013809
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/Abs_32.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*######################################################################################*/
+/* Include files */
+/*######################################################################################*/
+
+#include "ScalarArithmetic.h"
+
+/****************************************************************************************
+ * Name : Abs_32()
+ * Input : Signed 32-bit integer
+ * Output :
+ * Returns : Absolute value
+ * Description : Absolute value with maximum negative value corner case
+ * Remarks :
+ ****************************************************************************************/
+
+LVM_INT32 Abs_32(LVM_INT32 input)
+{
+ if(input < 0)
+ {
+ if (input == (LVM_INT32)(0x80000000U))
+ {
+ /* The corner case, so set to the maximum positive value */
+ input=(LVM_INT32) 0x7fffffff;
+ }
+ else
+ {
+ /* Negative input, so invert */
+ input = (LVM_INT32)(-input);
+ }
+ }
+ return input;
+}
+LVM_FLOAT Abs_Float(LVM_FLOAT input)
+{
+ if(input < 0)
+ {
+ /* Negative input, so invert */
+ input = (LVM_FLOAT)(-input);
+ }
+ return input;
+}
diff --git a/media/libeffects/lvm/lib/Common/src/Add2_Sat_16x16.c b/media/libeffects/lvm/lib/Common/src/Add2_Sat_16x16.cpp
similarity index 100%
rename from media/libeffects/lvm/lib/Common/src/Add2_Sat_16x16.c
rename to media/libeffects/lvm/lib/Common/src/Add2_Sat_16x16.cpp
diff --git a/media/libeffects/lvm/lib/Common/src/Add2_Sat_32x32.c b/media/libeffects/lvm/lib/Common/src/Add2_Sat_32x32.c
deleted file mode 100644
index 66d6adb..0000000
--- a/media/libeffects/lvm/lib/Common/src/Add2_Sat_32x32.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**********************************************************************************
- INCLUDE FILES
-***********************************************************************************/
-
-#include "VectorArithmetic.h"
-
-
-/**********************************************************************************
- FUNCTION ADD2_SAT_32X32
-***********************************************************************************/
-
-void Add2_Sat_32x32( const LVM_INT32 *src,
- LVM_INT32 *dst,
- LVM_INT16 n )
-{
- LVM_INT32 a,b,c;
- LVM_INT16 ii;
- for (ii = n; ii != 0; ii--)
- {
- a=*src;
- src++;
-
- b=*dst;
- c=a+b;
- if ((((c ^ a) & (c ^ b)) >> 31)!=0) /* overflow / underflow */
- {
- if(a<0)
- {
- c=0x80000000L;
- }
- else
- {
- c=0x7FFFFFFFL;
- }
- }
-
- *dst = c;
- dst++;
- }
- return;
-}
-
-#ifdef BUILD_FLOAT
-void Add2_Sat_Float( const LVM_FLOAT *src,
- LVM_FLOAT *dst,
- LVM_INT16 n )
-{
- LVM_FLOAT Temp;
- LVM_INT16 ii;
- for (ii = n; ii != 0; ii--)
- {
- Temp = ((LVM_FLOAT) *src) + ((LVM_FLOAT) *dst);
- src++;
-
- if (Temp > 1.000000f)
- {
- *dst = 1.000000f;
- }
- else if (Temp < -1.000000f)
- {
- *dst = -1.000000f;
- }
- else
- {
- *dst = Temp;
- }
- dst++;
- }
- return;
-}
-#endif
-/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/Add2_Sat_32x32.cpp b/media/libeffects/lvm/lib/Common/src/Add2_Sat_32x32.cpp
new file mode 100644
index 0000000..a48e668
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/Add2_Sat_32x32.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**********************************************************************************
+ INCLUDE FILES
+***********************************************************************************/
+
+#include "VectorArithmetic.h"
+
+/**********************************************************************************
+ FUNCTION ADD2_SAT_32X32
+***********************************************************************************/
+
+void Add2_Sat_32x32( const LVM_INT32 *src,
+ LVM_INT32 *dst,
+ LVM_INT16 n )
+{
+ LVM_INT32 a,b,c;
+ LVM_INT16 ii;
+ for (ii = n; ii != 0; ii--)
+ {
+ a=*src;
+ src++;
+
+ b=*dst;
+ c=a+b;
+ if ((((c ^ a) & (c ^ b)) >> 31)!=0) /* overflow / underflow */
+ {
+ if(a<0)
+ {
+ c=0x80000000L;
+ }
+ else
+ {
+ c=0x7FFFFFFFL;
+ }
+ }
+
+ *dst = c;
+ dst++;
+ }
+ return;
+}
+
+void Add2_Sat_Float( const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n )
+{
+ LVM_FLOAT Temp;
+ LVM_INT16 ii;
+ for (ii = n; ii != 0; ii--)
+ {
+ Temp = ((LVM_FLOAT) *src) + ((LVM_FLOAT) *dst);
+ src++;
+
+ if (Temp > 1.000000f)
+ {
+ *dst = 1.000000f;
+ }
+ else if (Temp < -1.000000f)
+ {
+ *dst = -1.000000f;
+ }
+ else
+ {
+ *dst = Temp;
+ }
+ dst++;
+ }
+ return;
+}
+/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/BP_1I_D16F16C14_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/BP_1I_D16F16C14_TRC_WRA_01.c
deleted file mode 100644
index 88f9986..0000000
--- a/media/libeffects/lvm/lib/Common/src/BP_1I_D16F16C14_TRC_WRA_01.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BIQUAD.h"
-#include "BP_1I_D16F16Css_TRC_WRA_01_Private.h"
-#include "LVM_Macros.h"
-
-
-/**************************************************************************
- ASSUMPTIONS:
- COEFS-
- pBiquadState->coefs[0] is A0,
- pBiquadState->coefs[1] is -B2,
- pBiquadState->coefs[2] is -B1, these are in Q14 format
-
- DELAYS-
- pBiquadState->pDelays[0] is x(n-1)L in Q0 format
- pBiquadState->pDelays[1] is x(n-2)L in Q0 format
- pBiquadState->pDelays[2] is y(n-1)L in Q0 format
- pBiquadState->pDelays[3] is y(n-2)L in Q0 format
-***************************************************************************/
-#ifdef BUILD_FLOAT
-void BP_1I_D16F16C14_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
- LVM_FLOAT *pDataIn,
- LVM_FLOAT *pDataOut,
- LVM_INT16 NrSamples)
-
-
- {
- LVM_FLOAT ynL;
- LVM_INT16 ii;
- PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
-
- for (ii = NrSamples; ii != 0; ii--)
- {
-
-
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
- // ynL= (A0 * (x(n)L - x(n-2)L ) )
- ynL = pBiquadState->coefs[0] * ((*pDataIn)-pBiquadState->pDelays[1]);
-
- // ynL+= ((-B2 * y(n-2)L ) )
- ynL += pBiquadState->coefs[1] * pBiquadState->pDelays[3];
-
- // ynL+= ((-B1 * y(n-1)L ) )
- ynL += pBiquadState->coefs[2] * pBiquadState->pDelays[2];
-
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[3] = pBiquadState->pDelays[2]; // y(n-2)L=y(n-1)L
- pBiquadState->pDelays[1] = pBiquadState->pDelays[0]; // x(n-2)L=x(n-1)L
- pBiquadState->pDelays[2] = ynL; // Update y(n-1)L
- pBiquadState->pDelays[0] = (*pDataIn++); // Update x(n-1)L
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut++=ynL; // Write Left output
-
- }
-
- }
-#else
-void BP_1I_D16F16C14_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
- LVM_INT16 *pDataIn,
- LVM_INT16 *pDataOut,
- LVM_INT16 NrSamples)
-
-
- {
- LVM_INT32 ynL;
- LVM_INT16 ii;
- PFilter_State pBiquadState = (PFilter_State) pInstance;
-
- for (ii = NrSamples; ii != 0; ii--)
- {
-
-
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
- // ynL= (A0 (Q14) * (x(n)L (Q0) - x(n-2)L (Q0) ) ) in Q14
- ynL=(LVM_INT32)pBiquadState->coefs[0]* ((*pDataIn)-pBiquadState->pDelays[1]);
-
- // ynL+= ((-B2 (Q14) * y(n-2)L (Q0) ) ) in Q14
- ynL+=(LVM_INT32)pBiquadState->coefs[1]*pBiquadState->pDelays[3];
-
- // ynL+= ((-B1 (Q30) * y(n-1)L (Q0) ) ) in Q14
- ynL+=(LVM_INT32)pBiquadState->coefs[2]*pBiquadState->pDelays[2];
-
- ynL=(LVM_INT16)(ynL>>14); // ynL in Q0
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[3]=pBiquadState->pDelays[2]; // y(n-2)L=y(n-1)L
- pBiquadState->pDelays[1]=pBiquadState->pDelays[0]; // x(n-2)L=x(n-1)L
- pBiquadState->pDelays[2]=ynL; // Update y(n-1)L in Q0
- pBiquadState->pDelays[0]=(*pDataIn++); // Update x(n-1)L in Q0
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut++=(LVM_INT16)ynL; // Write Left output in Q0
-
- }
-
- }
-#endif
-
diff --git a/media/libeffects/lvm/lib/Common/src/BP_1I_D16F16C14_TRC_WRA_01.cpp b/media/libeffects/lvm/lib/Common/src/BP_1I_D16F16C14_TRC_WRA_01.cpp
new file mode 100644
index 0000000..1a5e07f
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/BP_1I_D16F16C14_TRC_WRA_01.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BIQUAD.h"
+#include "BP_1I_D16F16Css_TRC_WRA_01_Private.h"
+#include "LVM_Macros.h"
+
+/**************************************************************************
+ ASSUMPTIONS:
+ COEFS-
+ pBiquadState->coefs[0] is A0,
+ pBiquadState->coefs[1] is -B2,
+ pBiquadState->coefs[2] is -B1, these are in Q14 format
+
+ DELAYS-
+ pBiquadState->pDelays[0] is x(n-1)L in Q0 format
+ pBiquadState->pDelays[1] is x(n-2)L in Q0 format
+ pBiquadState->pDelays[2] is y(n-1)L in Q0 format
+ pBiquadState->pDelays[3] is y(n-2)L in Q0 format
+***************************************************************************/
+void BP_1I_D16F16C14_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+
+ {
+ LVM_FLOAT ynL;
+ LVM_INT16 ii;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+
+ for (ii = NrSamples; ii != 0; ii--)
+ {
+
+ /**************************************************************************
+ PROCESSING OF THE LEFT CHANNEL
+ ***************************************************************************/
+ // ynL= (A0 * (x(n)L - x(n-2)L ) )
+ ynL = pBiquadState->coefs[0] * ((*pDataIn)-pBiquadState->pDelays[1]);
+
+ // ynL+= ((-B2 * y(n-2)L ) )
+ ynL += pBiquadState->coefs[1] * pBiquadState->pDelays[3];
+
+ // ynL+= ((-B1 * y(n-1)L ) )
+ ynL += pBiquadState->coefs[2] * pBiquadState->pDelays[2];
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[3] = pBiquadState->pDelays[2]; // y(n-2)L=y(n-1)L
+ pBiquadState->pDelays[1] = pBiquadState->pDelays[0]; // x(n-2)L=x(n-1)L
+ pBiquadState->pDelays[2] = ynL; // Update y(n-1)L
+ pBiquadState->pDelays[0] = (*pDataIn++); // Update x(n-1)L
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+ *pDataOut++=ynL; // Write Left output
+
+ }
+
+ }
+
diff --git a/media/libeffects/lvm/lib/Common/src/BP_1I_D16F16Css_TRC_WRA_01_Init.c b/media/libeffects/lvm/lib/Common/src/BP_1I_D16F16Css_TRC_WRA_01_Init.c
deleted file mode 100644
index 27ab57a..0000000
--- a/media/libeffects/lvm/lib/Common/src/BP_1I_D16F16Css_TRC_WRA_01_Init.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*-------------------------------------------------------------------------*/
-#include "BIQUAD.h"
-#include "BP_1I_D16F16Css_TRC_WRA_01_Private.h"
-
-
-/*-------------------------------------------------------------------------*/
-/* FUNCTION: */
-/* BP_1I_D16F16Css_TRC_WRA_01_Init */
-/* */
-/* DESCRIPTION: */
-/* These functions initializes a BIQUAD filter defined as a cascade of */
-/* biquadratic Filter Sections. */
-/* */
-/* PARAMETERS: */
-/* pInstance - output, returns the pointer to the State Variable */
-/* This state pointer must be passed to any subsequent */
-/* call to "Biquad" functions. */
-/* pTaps - input, pointer to the taps memory */
-/* pCoef - input, pointer to the coefficient structure */
-/* N - M coefficient factor of QM.N */
-/* RETURNS: */
-/* void return code */
-/*-------------------------------------------------------------------------*/
-#ifdef BUILD_FLOAT
-void BP_1I_D16F16Css_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
- Biquad_1I_Order2_FLOAT_Taps_t *pTaps,
- BP_FLOAT_Coefs_t *pCoef)
-{
- PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
- pBiquadState->pDelays = (LVM_FLOAT *) pTaps;
-
- pBiquadState->coefs[0] = pCoef->A0;
- pBiquadState->coefs[1] = pCoef->B2;
- pBiquadState->coefs[2] = pCoef->B1;
-}
-#else
-void BP_1I_D16F16Css_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
- Biquad_1I_Order2_Taps_t *pTaps,
- BP_C16_Coefs_t *pCoef)
-{
- PFilter_State pBiquadState = (PFilter_State) pInstance;
- pBiquadState->pDelays =(LVM_INT32 *) pTaps;
-
- pBiquadState->coefs[0]=pCoef->A0;
- pBiquadState->coefs[1]=pCoef->B2;
- pBiquadState->coefs[2]=pCoef->B1;
- }
-#endif
-/*-------------------------------------------------------------------------*/
-/* End Of File: BP_1I_D16F16Css_TRC_WRA_01_Init.c */
-
diff --git a/media/libeffects/lvm/lib/Common/src/BP_1I_D16F16Css_TRC_WRA_01_Init.cpp b/media/libeffects/lvm/lib/Common/src/BP_1I_D16F16Css_TRC_WRA_01_Init.cpp
new file mode 100644
index 0000000..60b6c16
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/BP_1I_D16F16Css_TRC_WRA_01_Init.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*-------------------------------------------------------------------------*/
+#include "BIQUAD.h"
+#include "BP_1I_D16F16Css_TRC_WRA_01_Private.h"
+
+/*-------------------------------------------------------------------------*/
+/* FUNCTION: */
+/* BP_1I_D16F16Css_TRC_WRA_01_Init */
+/* */
+/* DESCRIPTION: */
+/* These functions initializes a BIQUAD filter defined as a cascade of */
+/* biquadratic Filter Sections. */
+/* */
+/* PARAMETERS: */
+/* pInstance - output, returns the pointer to the State Variable */
+/* This state pointer must be passed to any subsequent */
+/* call to "Biquad" functions. */
+/* pTaps - input, pointer to the taps memory */
+/* pCoef - input, pointer to the coefficient structure */
+/* N - M coefficient factor of QM.N */
+/* RETURNS: */
+/* void return code */
+/*-------------------------------------------------------------------------*/
+void BP_1I_D16F16Css_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_1I_Order2_FLOAT_Taps_t *pTaps,
+ BP_FLOAT_Coefs_t *pCoef)
+{
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+ pBiquadState->pDelays = (LVM_FLOAT *) pTaps;
+
+ pBiquadState->coefs[0] = pCoef->A0;
+ pBiquadState->coefs[1] = pCoef->B2;
+ pBiquadState->coefs[2] = pCoef->B1;
+}
+/*-------------------------------------------------------------------------*/
+/* End Of File: BP_1I_D16F16Css_TRC_WRA_01_Init.c */
+
diff --git a/media/libeffects/lvm/lib/Common/src/BP_1I_D16F16Css_TRC_WRA_01_Private.h b/media/libeffects/lvm/lib/Common/src/BP_1I_D16F16Css_TRC_WRA_01_Private.h
index e194f92..8a000b6 100644
--- a/media/libeffects/lvm/lib/Common/src/BP_1I_D16F16Css_TRC_WRA_01_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/BP_1I_D16F16Css_TRC_WRA_01_Private.h
@@ -27,7 +27,6 @@
typedef Filter_State * PFilter_State ;
-#ifdef BUILD_FLOAT
typedef struct _Filter_State_FLOAT
{
@@ -35,5 +34,4 @@
LVM_FLOAT coefs[3]; /* pointer to the filter coefficients */
}Filter_State_FLOAT;
typedef Filter_State_FLOAT * PFilter_State_FLOAT ;
-#endif
#endif /*_BP_1I_D16F16CSS_TRC_WRA_01_PRIVATE_H_*/
diff --git a/media/libeffects/lvm/lib/Common/src/BP_1I_D16F32C30_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/BP_1I_D16F32C30_TRC_WRA_01.c
deleted file mode 100644
index 3abdd43..0000000
--- a/media/libeffects/lvm/lib/Common/src/BP_1I_D16F32C30_TRC_WRA_01.c
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BIQUAD.h"
-#include "BP_1I_D16F32Cll_TRC_WRA_01_Private.h"
-#include "LVM_Macros.h"
-
-
-/**************************************************************************
- ASSUMPTIONS:
- COEFS-
- pBiquadState->coefs[0] is A0,
- pBiquadState->coefs[1] is -B2,
- pBiquadState->coefs[2] is -B1, these are in Q30 format
-
- DELAYS-
- pBiquadState->pDelays[0] is x(n-1)L in Q0 format
- pBiquadState->pDelays[1] is x(n-2)L in Q0 format
- pBiquadState->pDelays[2] is y(n-1)L in Q16 format
- pBiquadState->pDelays[3] is y(n-2)L in Q16 format
-***************************************************************************/
-#ifdef BUILD_FLOAT
-void BP_1I_D16F32C30_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
- LVM_FLOAT *pDataIn,
- LVM_FLOAT *pDataOut,
- LVM_INT16 NrSamples)
-{
- LVM_FLOAT ynL,templ;
- LVM_INT16 ii;
- PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT)pInstance;
-
- for (ii = NrSamples; ii != 0; ii--)
- {
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
- // ynL= (A0 * (x(n)L - x(n-2)L ))
- templ = (LVM_FLOAT) *pDataIn - pBiquadState->pDelays[1];
- ynL = pBiquadState->coefs[0] * templ;
-
- // ynL+= ((-B2 * y(n-2)L ) )
- templ = pBiquadState->coefs[1] * pBiquadState->pDelays[3];
- ynL += templ;
-
- // ynL+= ((-B1 * y(n-1)L ))
- templ = pBiquadState->coefs[2] * pBiquadState->pDelays[2];
- ynL += templ;
-
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[3] = pBiquadState->pDelays[2]; // y(n-2)L=y(n-1)L
- pBiquadState->pDelays[1] = pBiquadState->pDelays[0]; // x(n-2)L=x(n-1)L
- pBiquadState->pDelays[2] = ynL; // Update y(n-1)L in Q16
- pBiquadState->pDelays[0] = (*pDataIn++); // Update x(n-1)L in Q0
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut++ = (ynL); // Write Left output
- }
-}
-#else
-void BP_1I_D16F32C30_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
- LVM_INT16 *pDataIn,
- LVM_INT16 *pDataOut,
- LVM_INT16 NrSamples)
-
-
- {
- LVM_INT32 ynL,templ;
- LVM_INT16 ii;
- PFilter_State pBiquadState = (PFilter_State) pInstance;
-
- for (ii = NrSamples; ii != 0; ii--)
- {
-
-
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
- // ynL= (A0 (Q30) * (x(n)L (Q0) - x(n-2)L (Q0) ) >>14) in Q16
- templ= (LVM_INT32) *pDataIn-pBiquadState->pDelays[1];
- MUL32x32INTO32(pBiquadState->coefs[0],templ,ynL,14)
-
- // ynL+= ((-B2 (Q30) * y(n-2)L (Q16) ) >>30) in Q16
- MUL32x32INTO32(pBiquadState->coefs[1],pBiquadState->pDelays[3],templ,30)
- ynL+=templ;
-
- // ynL+= ((-B1 (Q30) * y(n-1)L (Q16) ) >>30) in Q16
- MUL32x32INTO32(pBiquadState->coefs[2],pBiquadState->pDelays[2],templ,30)
- ynL+=templ;
-
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[3]=pBiquadState->pDelays[2]; // y(n-2)L=y(n-1)L
- pBiquadState->pDelays[1]=pBiquadState->pDelays[0]; // x(n-2)L=x(n-1)L
- pBiquadState->pDelays[2]=ynL; // Update y(n-1)L in Q16
- pBiquadState->pDelays[0]=(*pDataIn++); // Update x(n-1)L in Q0
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut++=(LVM_INT16)(ynL>>16); // Write Left output in Q0
-
- }
-
- }
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/BP_1I_D16F32C30_TRC_WRA_01.cpp b/media/libeffects/lvm/lib/Common/src/BP_1I_D16F32C30_TRC_WRA_01.cpp
new file mode 100644
index 0000000..c844d03
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/BP_1I_D16F32C30_TRC_WRA_01.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BIQUAD.h"
+#include "BP_1I_D16F32Cll_TRC_WRA_01_Private.h"
+#include "LVM_Macros.h"
+
+/**************************************************************************
+ ASSUMPTIONS:
+ COEFS-
+ pBiquadState->coefs[0] is A0,
+ pBiquadState->coefs[1] is -B2,
+ pBiquadState->coefs[2] is -B1, these are in Q30 format
+
+ DELAYS-
+ pBiquadState->pDelays[0] is x(n-1)L in Q0 format
+ pBiquadState->pDelays[1] is x(n-2)L in Q0 format
+ pBiquadState->pDelays[2] is y(n-1)L in Q16 format
+ pBiquadState->pDelays[3] is y(n-2)L in Q16 format
+***************************************************************************/
+void BP_1I_D16F32C30_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+{
+ LVM_FLOAT ynL,templ;
+ LVM_INT16 ii;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT)pInstance;
+
+ for (ii = NrSamples; ii != 0; ii--)
+ {
+ /**************************************************************************
+ PROCESSING OF THE LEFT CHANNEL
+ ***************************************************************************/
+ // ynL= (A0 * (x(n)L - x(n-2)L ))
+ templ = (LVM_FLOAT) *pDataIn - pBiquadState->pDelays[1];
+ ynL = pBiquadState->coefs[0] * templ;
+
+ // ynL+= ((-B2 * y(n-2)L ) )
+ templ = pBiquadState->coefs[1] * pBiquadState->pDelays[3];
+ ynL += templ;
+
+ // ynL+= ((-B1 * y(n-1)L ))
+ templ = pBiquadState->coefs[2] * pBiquadState->pDelays[2];
+ ynL += templ;
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[3] = pBiquadState->pDelays[2]; // y(n-2)L=y(n-1)L
+ pBiquadState->pDelays[1] = pBiquadState->pDelays[0]; // x(n-2)L=x(n-1)L
+ pBiquadState->pDelays[2] = ynL; // Update y(n-1)L in Q16
+ pBiquadState->pDelays[0] = (*pDataIn++); // Update x(n-1)L in Q0
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+ *pDataOut++ = (ynL); // Write Left output
+ }
+}
diff --git a/media/libeffects/lvm/lib/Common/src/BP_1I_D16F32Cll_TRC_WRA_01_Init.c b/media/libeffects/lvm/lib/Common/src/BP_1I_D16F32Cll_TRC_WRA_01_Init.c
deleted file mode 100644
index d6e047a..0000000
--- a/media/libeffects/lvm/lib/Common/src/BP_1I_D16F32Cll_TRC_WRA_01_Init.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*-------------------------------------------------------------------------*/
-#include "BIQUAD.h"
-#include "BP_1I_D16F32Cll_TRC_WRA_01_Private.h"
-
-
-/*-------------------------------------------------------------------------*/
-/* FUNCTION: */
-/* BP_1I_D16F32Cll_TRC_WRA_01_Init */
-/* */
-/* DESCRIPTION: */
-/* These functions initializes a Band pass filter (BIQUAD) */
-/* biquadratic Filter Sections. */
-/* */
-/* PARAMETERS: */
-/* pInstance - output, returns the pointer to the State Variable */
-/* This state pointer must be passed to any subsequent */
-/* call to "Biquad" functions. */
-/* pTaps - input, pointer to the taps memory */
-/* pCoef - input, pointer to the coefficient structure */
-/* N - M coefficient factor of QM.N */
-/* */
-/* The coefficients are modified in the init() function such that lower */
-/* half word is right shifted by one and most significant bit of the lower */
-/* word is made to be zero. */
-/* */
-/* Reason: For MIPS effciency,we are using DSP 32*16 multiplication */
-/* instruction. But we have 32*32 multiplication. This can be realized by two 32*16 */
-/* multiplication. But 16th bit in the 32 bit word is not a sign bit. So this is done */
-/* by putting 16th bit to zero and lossing one bit precision by division of lower */
-/* half word by 2. */
-/* RETURNS: */
-/* void return code */
-/*-------------------------------------------------------------------------*/
-#ifdef BUILD_FLOAT
-void BP_1I_D16F32Cll_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
- Biquad_1I_Order2_FLOAT_Taps_t *pTaps,
- BP_FLOAT_Coefs_t *pCoef)
-{
- PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
- pBiquadState->pDelays =(LVM_FLOAT *) pTaps;
-
-
- pBiquadState->coefs[0] = pCoef->A0;
- pBiquadState->coefs[1] = pCoef->B2;
- pBiquadState->coefs[2] = pCoef->B1;
-}
-#else
-void BP_1I_D16F32Cll_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
- Biquad_1I_Order2_Taps_t *pTaps,
- BP_C32_Coefs_t *pCoef)
-{
- PFilter_State pBiquadState = (PFilter_State) pInstance;
- pBiquadState->pDelays =(LVM_INT32 *) pTaps;
-
- pBiquadState->coefs[0] = pCoef->A0;
- pBiquadState->coefs[1] = pCoef->B2;
- pBiquadState->coefs[2] = pCoef->B1;
-}
-#endif
-/*-------------------------------------------------------------------------*/
-/* End Of File: BP_1I_D16F32Cll_TRC_WRA_01_Init.c */
-
diff --git a/media/libeffects/lvm/lib/Common/src/BP_1I_D16F32Cll_TRC_WRA_01_Init.cpp b/media/libeffects/lvm/lib/Common/src/BP_1I_D16F32Cll_TRC_WRA_01_Init.cpp
new file mode 100644
index 0000000..eb15032
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/BP_1I_D16F32Cll_TRC_WRA_01_Init.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*-------------------------------------------------------------------------*/
+#include "BIQUAD.h"
+#include "BP_1I_D16F32Cll_TRC_WRA_01_Private.h"
+
+/*-------------------------------------------------------------------------*/
+/* FUNCTION: */
+/* BP_1I_D16F32Cll_TRC_WRA_01_Init */
+/* */
+/* DESCRIPTION: */
+/* These functions initializes a Band pass filter (BIQUAD) */
+/* biquadratic Filter Sections. */
+/* */
+/* PARAMETERS: */
+/* pInstance - output, returns the pointer to the State Variable */
+/* This state pointer must be passed to any subsequent */
+/* call to "Biquad" functions. */
+/* pTaps - input, pointer to the taps memory */
+/* pCoef - input, pointer to the coefficient structure */
+/* N - M coefficient factor of QM.N */
+/* */
+/* The coefficients are modified in the init() function such that lower */
+/* half word is right shifted by one and most significant bit of the lower */
+/* word is made to be zero. */
+/* */
+/* Reason: For MIPS effciency,we are using DSP 32*16 multiplication */
+/* instruction. But we have 32*32 multiplication. This can be realized by two 32*16 */
+/* multiplication. But 16th bit in the 32 bit word is not a sign bit. So this is done */
+/* by putting 16th bit to zero and lossing one bit precision by division of lower */
+/* half word by 2. */
+/* RETURNS: */
+/* void return code */
+/*-------------------------------------------------------------------------*/
+void BP_1I_D16F32Cll_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_1I_Order2_FLOAT_Taps_t *pTaps,
+ BP_FLOAT_Coefs_t *pCoef)
+{
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+ pBiquadState->pDelays =(LVM_FLOAT *) pTaps;
+
+ pBiquadState->coefs[0] = pCoef->A0;
+ pBiquadState->coefs[1] = pCoef->B2;
+ pBiquadState->coefs[2] = pCoef->B1;
+}
+/*-------------------------------------------------------------------------*/
+/* End Of File: BP_1I_D16F32Cll_TRC_WRA_01_Init.c */
+
diff --git a/media/libeffects/lvm/lib/Common/src/BP_1I_D16F32Cll_TRC_WRA_01_Private.h b/media/libeffects/lvm/lib/Common/src/BP_1I_D16F32Cll_TRC_WRA_01_Private.h
index aa9e669..6d754e2 100644
--- a/media/libeffects/lvm/lib/Common/src/BP_1I_D16F32Cll_TRC_WRA_01_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/BP_1I_D16F32Cll_TRC_WRA_01_Private.h
@@ -26,12 +26,10 @@
}Filter_State;
typedef Filter_State * PFilter_State ;
-#ifdef BUILD_FLOAT
typedef struct _Filter_State_FLOAT
{
LVM_FLOAT * pDelays; /* pointer to the delayed samples (data of 32 bits) */
LVM_FLOAT coefs[3]; /* pointer to the filter coefficients */
}Filter_State_Float;
typedef Filter_State_Float * PFilter_State_FLOAT ;
-#endif
#endif /*_BP_1I_D16F32CLL_TRC_WRA_01_PRIVATE_H_*/
diff --git a/media/libeffects/lvm/lib/Common/src/BP_1I_D32F32C30_TRC_WRA_02.c b/media/libeffects/lvm/lib/Common/src/BP_1I_D32F32C30_TRC_WRA_02.c
deleted file mode 100644
index abdb2f7..0000000
--- a/media/libeffects/lvm/lib/Common/src/BP_1I_D32F32C30_TRC_WRA_02.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BIQUAD.h"
-#include "BP_1I_D32F32Cll_TRC_WRA_02_Private.h"
-#include "LVM_Macros.h"
-
-
-/**************************************************************************
- ASSUMPTIONS:
- COEFS-
- pBiquadState->coefs[0] is A0,
- pBiquadState->coefs[1] is -B2,
- pBiquadState->coefs[2] is -B1, these are in Q30 format
-
- DELAYS-
- pBiquadState->pDelays[0] is x(n-1)L in Q0 format
- pBiquadState->pDelays[1] is x(n-2)L in Q0 format
- pBiquadState->pDelays[2] is y(n-1)L in Q0 format
- pBiquadState->pDelays[3] is y(n-2)L in Q0 format
-***************************************************************************/
-#ifdef BUILD_FLOAT
-void BP_1I_D32F32C30_TRC_WRA_02 ( Biquad_FLOAT_Instance_t *pInstance,
- LVM_FLOAT *pDataIn,
- LVM_FLOAT *pDataOut,
- LVM_INT16 NrSamples)
- {
- LVM_FLOAT ynL,templ;
- LVM_INT16 ii;
- PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
-
- for (ii = NrSamples; ii != 0; ii--)
- {
-
-
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
- // ynL= (A0 * (x(n)L - x(n-2)L ) )
- templ = (*pDataIn) - pBiquadState->pDelays[1];
- ynL = pBiquadState->coefs[0] * templ;
-
- // ynL+= ((-B2 * y(n-2)L ) )
- templ = pBiquadState->coefs[1] * pBiquadState->pDelays[3];
- ynL += templ;
-
- // ynL+= ((-B1 * y(n-1)L ) )
- templ = pBiquadState->coefs[2] * pBiquadState->pDelays[2];
- ynL += templ;
-
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[3] = pBiquadState->pDelays[2]; // y(n-2)L=y(n-1)L
- pBiquadState->pDelays[1] = pBiquadState->pDelays[0]; // x(n-2)L=x(n-1)L
- pBiquadState->pDelays[2] = ynL; // Update y(n-1)L
- pBiquadState->pDelays[0] = (*pDataIn++); // Update x(n-1)L
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut++ = ynL; // Write Left output in Q0
-
- }
-
- }
-#else
-void BP_1I_D32F32C30_TRC_WRA_02 ( Biquad_Instance_t *pInstance,
- LVM_INT32 *pDataIn,
- LVM_INT32 *pDataOut,
- LVM_INT16 NrSamples)
- {
- LVM_INT32 ynL,templ;
- LVM_INT16 ii;
- PFilter_State pBiquadState = (PFilter_State) pInstance;
-
- for (ii = NrSamples; ii != 0; ii--)
- {
-
-
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
- // ynL= (A0 (Q30) * (x(n)L (Q0) - x(n-2)L (Q0) ) >>30) in Q0
- templ=(*pDataIn)-pBiquadState->pDelays[1];
- MUL32x32INTO32(pBiquadState->coefs[0],templ,ynL,30)
-
- // ynL+= ((-B2 (Q30) * y(n-2)L (Q0) ) >>30) in Q0
- MUL32x32INTO32(pBiquadState->coefs[1],pBiquadState->pDelays[3],templ,30)
- ynL+=templ;
-
- // ynL+= ((-B1 (Q30) * y(n-1)L (Q0) ) >>30) in Q0
- MUL32x32INTO32(pBiquadState->coefs[2],pBiquadState->pDelays[2],templ,30)
- ynL+=templ;
-
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[3]=pBiquadState->pDelays[2]; // y(n-2)L=y(n-1)L
- pBiquadState->pDelays[1]=pBiquadState->pDelays[0]; // x(n-2)L=x(n-1)L
- pBiquadState->pDelays[2]=ynL; // Update y(n-1)L in Q0
- pBiquadState->pDelays[0]=(*pDataIn++); // Update x(n-1)L in Q0
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut++=ynL; // Write Left output in Q0
-
- }
-
- }
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/BP_1I_D32F32C30_TRC_WRA_02.cpp b/media/libeffects/lvm/lib/Common/src/BP_1I_D32F32C30_TRC_WRA_02.cpp
new file mode 100644
index 0000000..d0ba206
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/BP_1I_D32F32C30_TRC_WRA_02.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BIQUAD.h"
+#include "BP_1I_D32F32Cll_TRC_WRA_02_Private.h"
+#include "LVM_Macros.h"
+
+/**************************************************************************
+ ASSUMPTIONS:
+ COEFS-
+ pBiquadState->coefs[0] is A0,
+ pBiquadState->coefs[1] is -B2,
+ pBiquadState->coefs[2] is -B1, these are in Q30 format
+
+ DELAYS-
+ pBiquadState->pDelays[0] is x(n-1)L in Q0 format
+ pBiquadState->pDelays[1] is x(n-2)L in Q0 format
+ pBiquadState->pDelays[2] is y(n-1)L in Q0 format
+ pBiquadState->pDelays[3] is y(n-2)L in Q0 format
+***************************************************************************/
+void BP_1I_D32F32C30_TRC_WRA_02 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+ {
+ LVM_FLOAT ynL,templ;
+ LVM_INT16 ii;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+
+ for (ii = NrSamples; ii != 0; ii--)
+ {
+
+ /**************************************************************************
+ PROCESSING OF THE LEFT CHANNEL
+ ***************************************************************************/
+ // ynL= (A0 * (x(n)L - x(n-2)L ) )
+ templ = (*pDataIn) - pBiquadState->pDelays[1];
+ ynL = pBiquadState->coefs[0] * templ;
+
+ // ynL+= ((-B2 * y(n-2)L ) )
+ templ = pBiquadState->coefs[1] * pBiquadState->pDelays[3];
+ ynL += templ;
+
+ // ynL+= ((-B1 * y(n-1)L ) )
+ templ = pBiquadState->coefs[2] * pBiquadState->pDelays[2];
+ ynL += templ;
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[3] = pBiquadState->pDelays[2]; // y(n-2)L=y(n-1)L
+ pBiquadState->pDelays[1] = pBiquadState->pDelays[0]; // x(n-2)L=x(n-1)L
+ pBiquadState->pDelays[2] = ynL; // Update y(n-1)L
+ pBiquadState->pDelays[0] = (*pDataIn++); // Update x(n-1)L
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+ *pDataOut++ = ynL; // Write Left output in Q0
+
+ }
+
+ }
diff --git a/media/libeffects/lvm/lib/Common/src/BP_1I_D32F32Cll_TRC_WRA_02_Init.c b/media/libeffects/lvm/lib/Common/src/BP_1I_D32F32Cll_TRC_WRA_02_Init.c
deleted file mode 100644
index 5590c32..0000000
--- a/media/libeffects/lvm/lib/Common/src/BP_1I_D32F32Cll_TRC_WRA_02_Init.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*-------------------------------------------------------------------------*/
-#include "BIQUAD.h"
-#include "BP_1I_D32F32Cll_TRC_WRA_02_Private.h"
-
-/*-------------------------------------------------------------------------*/
-/* FUNCTION: */
-/* BP_1I_D32F32Cll_TRC_WRA_02_Init */
-/* */
-/* DESCRIPTION: */
-/* These functions initializes a BIQUAD filter defined as a cascade of */
-/* biquadratic Filter Sections. */
-/* */
-/* PARAMETERS: */
-/* pInstance - output, returns the pointer to the State Variable */
-/* This state pointer must be passed to any subsequent */
-/* call to "Biquad" functions. */
-/* pTaps - input, pointer to the taps memory */
-/* pCoef - input, pointer to the coefficient structure */
-/* N - M coefficient factor of QM.N */
-/* RETURNS: */
-/* void return code */
-/*-------------------------------------------------------------------------*/
-#ifdef BUILD_FLOAT
-void BP_1I_D32F32Cll_TRC_WRA_02_Init ( Biquad_FLOAT_Instance_t *pInstance,
- Biquad_1I_Order2_FLOAT_Taps_t *pTaps,
- BP_FLOAT_Coefs_t *pCoef)
-{
- PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
- pBiquadState->pDelays =(LVM_FLOAT *) pTaps;
-
- pBiquadState->coefs[0] = pCoef->A0;
-
- pBiquadState->coefs[1] = pCoef->B2;
-
- pBiquadState->coefs[2] = pCoef->B1;
-}
-#else
-void BP_1I_D32F32Cll_TRC_WRA_02_Init ( Biquad_Instance_t *pInstance,
- Biquad_1I_Order2_Taps_t *pTaps,
- BP_C32_Coefs_t *pCoef)
-{
- PFilter_State pBiquadState = (PFilter_State) pInstance;
- pBiquadState->pDelays =(LVM_INT32 *) pTaps;
-
- pBiquadState->coefs[0]=pCoef->A0;
-
- pBiquadState->coefs[1]=pCoef->B2;
-
- pBiquadState->coefs[2]=pCoef->B1;
-}
-#endif
-/*-------------------------------------------------------------------------*/
-/* End Of File: BP_1I_D32F32Cll_TRC_WRA_02_Init.c */
-
diff --git a/media/libeffects/lvm/lib/Common/src/BP_1I_D32F32Cll_TRC_WRA_02_Init.cpp b/media/libeffects/lvm/lib/Common/src/BP_1I_D32F32Cll_TRC_WRA_02_Init.cpp
new file mode 100644
index 0000000..6f7d0b5
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/BP_1I_D32F32Cll_TRC_WRA_02_Init.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*-------------------------------------------------------------------------*/
+#include "BIQUAD.h"
+#include "BP_1I_D32F32Cll_TRC_WRA_02_Private.h"
+
+/*-------------------------------------------------------------------------*/
+/* FUNCTION: */
+/* BP_1I_D32F32Cll_TRC_WRA_02_Init */
+/* */
+/* DESCRIPTION: */
+/* These functions initializes a BIQUAD filter defined as a cascade of */
+/* biquadratic Filter Sections. */
+/* */
+/* PARAMETERS: */
+/* pInstance - output, returns the pointer to the State Variable */
+/* This state pointer must be passed to any subsequent */
+/* call to "Biquad" functions. */
+/* pTaps - input, pointer to the taps memory */
+/* pCoef - input, pointer to the coefficient structure */
+/* N - M coefficient factor of QM.N */
+/* RETURNS: */
+/* void return code */
+/*-------------------------------------------------------------------------*/
+void BP_1I_D32F32Cll_TRC_WRA_02_Init ( Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_1I_Order2_FLOAT_Taps_t *pTaps,
+ BP_FLOAT_Coefs_t *pCoef)
+{
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+ pBiquadState->pDelays =(LVM_FLOAT *) pTaps;
+
+ pBiquadState->coefs[0] = pCoef->A0;
+
+ pBiquadState->coefs[1] = pCoef->B2;
+
+ pBiquadState->coefs[2] = pCoef->B1;
+}
+/*-------------------------------------------------------------------------*/
+/* End Of File: BP_1I_D32F32Cll_TRC_WRA_02_Init.c */
+
diff --git a/media/libeffects/lvm/lib/Common/src/BP_1I_D32F32Cll_TRC_WRA_02_Private.h b/media/libeffects/lvm/lib/Common/src/BP_1I_D32F32Cll_TRC_WRA_02_Private.h
index 80c3920..9f1c66a 100644
--- a/media/libeffects/lvm/lib/Common/src/BP_1I_D32F32Cll_TRC_WRA_02_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/BP_1I_D32F32Cll_TRC_WRA_02_Private.h
@@ -26,13 +26,11 @@
}Filter_State;
typedef Filter_State * PFilter_State ;
-#ifdef BUILD_FLOAT
typedef struct _Filter_State_FLOAT
{
LVM_FLOAT * pDelays; /* pointer to the delayed samples (data of 32 bits) */
LVM_FLOAT coefs[3]; /* pointer to the filter coefficients */
}Filter_State_Float;
typedef Filter_State_Float* PFilter_State_FLOAT ;
-#endif
#endif /*_BP_1I_D32F32CLL_TRC_WRA_02_PRIVATE_H_*/
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F16C15_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F16C15_TRC_WRA_01.c
deleted file mode 100644
index ee9bf7a..0000000
--- a/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F16C15_TRC_WRA_01.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BIQUAD.h"
-#include "BQ_1I_D16F16Css_TRC_WRA_01_Private.h"
-#include "LVM_Macros.h"
-
-/**************************************************************************
- ASSUMPTIONS:
- COEFS-
- pBiquadState->coefs[0] is A2, pBiquadState->coefs[1] is A1
- pBiquadState->coefs[2] is A0, pBiquadState->coefs[3] is -B2
- pBiquadState->coefs[4] is -B1, these are in Q15 format
-
- DELAYS-
- pBiquadState->pDelays[0] is x(n-1)L in Q0 format
- pBiquadState->pDelays[1] is x(n-2)L in Q0 format
- pBiquadState->pDelays[2] is y(n-1)L in Q0 format
- pBiquadState->pDelays[3] is y(n-2)L in Q0 format
-***************************************************************************/
-#ifdef BUILD_FLOAT
-void BQ_1I_D16F16C15_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
- LVM_FLOAT *pDataIn,
- LVM_FLOAT *pDataOut,
- LVM_INT16 NrSamples)
- {
- LVM_FLOAT ynL;
- LVM_INT16 ii;
- PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
-
- for (ii = NrSamples; ii != 0; ii--)
- {
-
-
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
- // ynL=A2 * x(n-2)L
- ynL = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[1];
-
- // ynL+=A1 * x(n-1)L
- ynL += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[0];
-
- // ynL+=A0 * x(n)L
- ynL += (LVM_FLOAT)pBiquadState->coefs[2] * (*pDataIn);
-
- // ynL+= (-B2 * y(n-2)L )
- ynL += (LVM_FLOAT)pBiquadState->coefs[3] * pBiquadState->pDelays[3];
-
- // ynL+= (-B1 * y(n-1)L )
- ynL += (LVM_FLOAT)pBiquadState->coefs[4] * pBiquadState->pDelays[2];
-
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[3] = pBiquadState->pDelays[2]; // y(n-2)L=y(n-1)L
- pBiquadState->pDelays[1] = pBiquadState->pDelays[0]; // x(n-2)L=x(n-1)L
- pBiquadState->pDelays[2] = ynL; // Update y(n-1)L
- pBiquadState->pDelays[0] = (*pDataIn++); // Update x(n-1)L
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut++ = (LVM_FLOAT)ynL; // Write Left output in Q0
-
-
- }
-
- }
-#else
-void BQ_1I_D16F16C15_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
- LVM_INT16 *pDataIn,
- LVM_INT16 *pDataOut,
- LVM_INT16 NrSamples)
- {
- LVM_INT32 ynL;
- LVM_INT16 ii;
- PFilter_State pBiquadState = (PFilter_State) pInstance;
-
- for (ii = NrSamples; ii != 0; ii--)
- {
-
-
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
- // ynL=A2 (Q15) * x(n-2)L (Q0) in Q15
- ynL=(LVM_INT32)pBiquadState->coefs[0]* pBiquadState->pDelays[1];
-
- // ynL+=A1 (Q15) * x(n-1)L (Q0) in Q15
- ynL+=(LVM_INT32)pBiquadState->coefs[1]* pBiquadState->pDelays[0];
-
- // ynL+=A0 (Q15) * x(n)L (Q0) in Q15
- ynL+=(LVM_INT32)pBiquadState->coefs[2]* (*pDataIn);
-
- // ynL+= (-B2 (Q15) * y(n-2)L (Q0) ) in Q15
- ynL+=(LVM_INT32)pBiquadState->coefs[3]*pBiquadState->pDelays[3];
-
- // ynL+= (-B1 (Q15) * y(n-1)L (Q0) ) in Q15
- ynL+=(LVM_INT32)pBiquadState->coefs[4]*pBiquadState->pDelays[2];
-
- ynL=ynL>>15; // ynL in Q0 format
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[3]=pBiquadState->pDelays[2]; // y(n-2)L=y(n-1)L
- pBiquadState->pDelays[1]=pBiquadState->pDelays[0]; // x(n-2)L=x(n-1)L
- pBiquadState->pDelays[2]=ynL; // Update y(n-1)L in Q0
- pBiquadState->pDelays[0]=(*pDataIn++); // Update x(n-1)L in Q0
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut++=(LVM_INT16)ynL; // Write Left output in Q0
-
-
- }
-
- }
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F16C15_TRC_WRA_01.cpp b/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F16C15_TRC_WRA_01.cpp
new file mode 100644
index 0000000..9aecc40
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F16C15_TRC_WRA_01.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BIQUAD.h"
+#include "BQ_1I_D16F16Css_TRC_WRA_01_Private.h"
+#include "LVM_Macros.h"
+
+/**************************************************************************
+ ASSUMPTIONS:
+ COEFS-
+ pBiquadState->coefs[0] is A2, pBiquadState->coefs[1] is A1
+ pBiquadState->coefs[2] is A0, pBiquadState->coefs[3] is -B2
+ pBiquadState->coefs[4] is -B1, these are in Q15 format
+
+ DELAYS-
+ pBiquadState->pDelays[0] is x(n-1)L in Q0 format
+ pBiquadState->pDelays[1] is x(n-2)L in Q0 format
+ pBiquadState->pDelays[2] is y(n-1)L in Q0 format
+ pBiquadState->pDelays[3] is y(n-2)L in Q0 format
+***************************************************************************/
+void BQ_1I_D16F16C15_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+ {
+ LVM_FLOAT ynL;
+ LVM_INT16 ii;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+
+ for (ii = NrSamples; ii != 0; ii--)
+ {
+
+ /**************************************************************************
+ PROCESSING OF THE LEFT CHANNEL
+ ***************************************************************************/
+ // ynL=A2 * x(n-2)L
+ ynL = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[1];
+
+ // ynL+=A1 * x(n-1)L
+ ynL += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[0];
+
+ // ynL+=A0 * x(n)L
+ ynL += (LVM_FLOAT)pBiquadState->coefs[2] * (*pDataIn);
+
+ // ynL+= (-B2 * y(n-2)L )
+ ynL += (LVM_FLOAT)pBiquadState->coefs[3] * pBiquadState->pDelays[3];
+
+ // ynL+= (-B1 * y(n-1)L )
+ ynL += (LVM_FLOAT)pBiquadState->coefs[4] * pBiquadState->pDelays[2];
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[3] = pBiquadState->pDelays[2]; // y(n-2)L=y(n-1)L
+ pBiquadState->pDelays[1] = pBiquadState->pDelays[0]; // x(n-2)L=x(n-1)L
+ pBiquadState->pDelays[2] = ynL; // Update y(n-1)L
+ pBiquadState->pDelays[0] = (*pDataIn++); // Update x(n-1)L
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+ *pDataOut++ = (LVM_FLOAT)ynL; // Write Left output in Q0
+
+ }
+
+ }
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F16Css_TRC_WRA_01_Init.c b/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F16Css_TRC_WRA_01_Init.c
deleted file mode 100644
index 3d5befa..0000000
--- a/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F16Css_TRC_WRA_01_Init.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*-------------------------------------------------------------------------*/
-#include "BIQUAD.h"
-#include "BQ_1I_D16F16Css_TRC_WRA_01_Private.h"
-
-/*-------------------------------------------------------------------------*/
-/* FUNCTION: */
-/* BQ_1I_D16F16Css_TRC_WRA_01_Init */
-/* */
-/* DESCRIPTION: */
-/* These functions initializes a BIQUAD filter defined as a cascade of */
-/* biquadratic Filter Sections. */
-/* */
-/* PARAMETERS: */
-/* pInstance - output, returns the pointer to the State Variable */
-/* This state pointer must be passed to any subsequent */
-/* call to "Biquad" functions. */
-/* pTaps - input, pointer to the taps memory */
-/* pCoef - input, pointer to the coefficient structure */
-/* N - M coefficient factor of QM.N */
-/* RETURNS: */
-/* void return code */
-/*-------------------------------------------------------------------------*/
-#ifdef BUILD_FLOAT
-void BQ_1I_D16F16Css_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
- Biquad_1I_Order2_FLOAT_Taps_t *pTaps,
- BQ_FLOAT_Coefs_t *pCoef)
-{
- LVM_FLOAT temp;
- PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
- pBiquadState->pDelays = (LVM_FLOAT *) pTaps ;
- temp = pCoef->A2;
- pBiquadState->coefs[0] = temp;
- temp = pCoef->A1;
- pBiquadState->coefs[1] = temp;
- temp = pCoef->A0;
- pBiquadState->coefs[2] = temp;
- temp = pCoef->B2;
- pBiquadState->coefs[3] = temp;
- temp = pCoef->B1;
- pBiquadState->coefs[4] = temp;
-}
-#else
-void BQ_1I_D16F16Css_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
- Biquad_1I_Order2_Taps_t *pTaps,
- BQ_C16_Coefs_t *pCoef)
-{
- LVM_INT16 temp;
- PFilter_State pBiquadState = (PFilter_State) pInstance;
- pBiquadState->pDelays =(LVM_INT32 *) pTaps ;
-
- temp=pCoef->A2;
- pBiquadState->coefs[0]=temp;
- temp=pCoef->A1;
- pBiquadState->coefs[1]=temp;
- temp=pCoef->A0;
- pBiquadState->coefs[2]=temp;
- temp=pCoef->B2;
- pBiquadState->coefs[3]=temp;
- temp=pCoef->B1;
- pBiquadState->coefs[4]=temp;
-}
-#endif
-/*-------------------------------------------------------------------------*/
-/* End Of File: BQ_1I_D16F16Css_TRC_WRA_01_Init.c */
-
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F16Css_TRC_WRA_01_Init.cpp b/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F16Css_TRC_WRA_01_Init.cpp
new file mode 100644
index 0000000..f0b5d06
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F16Css_TRC_WRA_01_Init.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*-------------------------------------------------------------------------*/
+#include "BIQUAD.h"
+#include "BQ_1I_D16F16Css_TRC_WRA_01_Private.h"
+
+/*-------------------------------------------------------------------------*/
+/* FUNCTION: */
+/* BQ_1I_D16F16Css_TRC_WRA_01_Init */
+/* */
+/* DESCRIPTION: */
+/* These functions initializes a BIQUAD filter defined as a cascade of */
+/* biquadratic Filter Sections. */
+/* */
+/* PARAMETERS: */
+/* pInstance - output, returns the pointer to the State Variable */
+/* This state pointer must be passed to any subsequent */
+/* call to "Biquad" functions. */
+/* pTaps - input, pointer to the taps memory */
+/* pCoef - input, pointer to the coefficient structure */
+/* N - M coefficient factor of QM.N */
+/* RETURNS: */
+/* void return code */
+/*-------------------------------------------------------------------------*/
+void BQ_1I_D16F16Css_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_1I_Order2_FLOAT_Taps_t *pTaps,
+ BQ_FLOAT_Coefs_t *pCoef)
+{
+ LVM_FLOAT temp;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+ pBiquadState->pDelays = (LVM_FLOAT *) pTaps ;
+ temp = pCoef->A2;
+ pBiquadState->coefs[0] = temp;
+ temp = pCoef->A1;
+ pBiquadState->coefs[1] = temp;
+ temp = pCoef->A0;
+ pBiquadState->coefs[2] = temp;
+ temp = pCoef->B2;
+ pBiquadState->coefs[3] = temp;
+ temp = pCoef->B1;
+ pBiquadState->coefs[4] = temp;
+}
+/*-------------------------------------------------------------------------*/
+/* End Of File: BQ_1I_D16F16Css_TRC_WRA_01_Init.c */
+
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F16Css_TRC_WRA_01_Private.h b/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F16Css_TRC_WRA_01_Private.h
index 811da8b..fad345d 100644
--- a/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F16Css_TRC_WRA_01_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F16Css_TRC_WRA_01_Private.h
@@ -27,7 +27,6 @@
typedef Filter_State * PFilter_State ;
-#ifdef BUILD_FLOAT
typedef struct _Filter_State_FLOAT
{
LVM_FLOAT * pDelays; /* pointer to the delayed samples (data of 32 bits) */
@@ -35,5 +34,4 @@
}Filter_State_FLOAT;
typedef Filter_State_FLOAT * PFilter_State_FLOAT ;
-#endif
#endif /*_BQ_1I_D16F16CSS_TRC_WRA_01_PRIVATE_H_ */
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F32C14_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F32C14_TRC_WRA_01.c
deleted file mode 100644
index c74a137..0000000
--- a/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F32C14_TRC_WRA_01.c
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BIQUAD.h"
-#include "BQ_1I_D16F32Css_TRC_WRA_01_Private.h"
-#include "LVM_Macros.h"
-
-/**************************************************************************
- ASSUMPTIONS:
- COEFS-
- pBiquadState->coefs[0] is A2, pBiquadState->coefs[1] is A1
- pBiquadState->coefs[2] is A0, pBiquadState->coefs[3] is -B2
- pBiquadState->coefs[4] is -B1, these are in Q14 format
-
- DELAYS-
- pBiquadState->pDelays[0] is x(n-1)L in Q0 format
- pBiquadState->pDelays[1] is x(n-2)L in Q0 format
- pBiquadState->pDelays[2] is y(n-1)L in Q16 format
- pBiquadState->pDelays[3] is y(n-2)L in Q16 format
-***************************************************************************/
-#ifdef BUILD_FLOAT
-void BQ_1I_D16F32C14_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
- LVM_FLOAT *pDataIn,
- LVM_FLOAT *pDataOut,
- LVM_INT16 NrSamples)
- {
- LVM_FLOAT ynL;
- LVM_INT16 ii;
- PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
-
- for (ii = NrSamples; ii != 0; ii--)
- {
-
-
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
- // ynL=A2 * x(n-2)L
- ynL = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[1];
-
- // ynL+=A1 * x(n-1)L
- ynL += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[0];
-
- // ynL+=A0 * x(n)L
- ynL += (LVM_FLOAT)pBiquadState->coefs[2] * (*pDataIn);
-
- // ynL+= ( (-B2 * y(n-2)L )
- ynL += pBiquadState->pDelays[3] * pBiquadState->coefs[3];
-
- // ynL+= -B1 * y(n-1)L
- ynL += pBiquadState->pDelays[2] * pBiquadState->coefs[4];
-
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[3] = pBiquadState->pDelays[2]; // y(n-2)L=y(n-1)L
- pBiquadState->pDelays[1] = pBiquadState->pDelays[0]; // x(n-2)L=x(n-1)L
- pBiquadState->pDelays[2] = ynL; // Update y(n-1)L
- pBiquadState->pDelays[0] = (*pDataIn++); // Update x(n-1)L
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut++ = (LVM_FLOAT)(ynL); // Write Left output
-
- }
- }
-#else
-void BQ_1I_D16F32C14_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
- LVM_INT16 *pDataIn,
- LVM_INT16 *pDataOut,
- LVM_INT16 NrSamples)
- {
- LVM_INT32 ynL,templ;
- LVM_INT16 ii;
- PFilter_State pBiquadState = (PFilter_State) pInstance;
-
- for (ii = NrSamples; ii != 0; ii--)
- {
-
-
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
- // ynL=A2 (Q14) * x(n-2)L (Q0) in Q14
- ynL=(LVM_INT32)pBiquadState->coefs[0]* pBiquadState->pDelays[1];
-
- // ynL+=A1 (Q14) * x(n-1)L (Q0) in Q14
- ynL+=(LVM_INT32)pBiquadState->coefs[1]* pBiquadState->pDelays[0];
-
- // ynL+=A0 (Q14) * x(n)L (Q0) in Q14
- ynL+=(LVM_INT32)pBiquadState->coefs[2]* (*pDataIn);
-
- // ynL+= ( (-B2 (Q14) * y(n-2)L (Q16) )>>16) in Q14
- MUL32x16INTO32(pBiquadState->pDelays[3],pBiquadState->coefs[3],templ,16)
- ynL+=templ;
-
- // ynL+= ( (-B1 (Q14) * y(n-1)L (Q16) )>>16) in Q14
- MUL32x16INTO32(pBiquadState->pDelays[2],pBiquadState->coefs[4],templ,16)
- ynL+=templ;
-
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[3]=pBiquadState->pDelays[2]; // y(n-2)L=y(n-1)L
- pBiquadState->pDelays[1]=pBiquadState->pDelays[0]; // x(n-2)L=x(n-1)L
- pBiquadState->pDelays[2]=ynL<<2; // Update y(n-1)L in Q16
- pBiquadState->pDelays[0]=(*pDataIn++); // Update x(n-1)L in Q0
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut++=(LVM_INT16)(ynL>>14); // Write Left output in Q0
-
- }
- }
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F32C14_TRC_WRA_01.cpp b/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F32C14_TRC_WRA_01.cpp
new file mode 100644
index 0000000..043bc5f
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F32C14_TRC_WRA_01.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BIQUAD.h"
+#include "BQ_1I_D16F32Css_TRC_WRA_01_Private.h"
+#include "LVM_Macros.h"
+
+/**************************************************************************
+ ASSUMPTIONS:
+ COEFS-
+ pBiquadState->coefs[0] is A2, pBiquadState->coefs[1] is A1
+ pBiquadState->coefs[2] is A0, pBiquadState->coefs[3] is -B2
+ pBiquadState->coefs[4] is -B1, these are in Q14 format
+
+ DELAYS-
+ pBiquadState->pDelays[0] is x(n-1)L in Q0 format
+ pBiquadState->pDelays[1] is x(n-2)L in Q0 format
+ pBiquadState->pDelays[2] is y(n-1)L in Q16 format
+ pBiquadState->pDelays[3] is y(n-2)L in Q16 format
+***************************************************************************/
+void BQ_1I_D16F32C14_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+ {
+ LVM_FLOAT ynL;
+ LVM_INT16 ii;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+
+ for (ii = NrSamples; ii != 0; ii--)
+ {
+
+ /**************************************************************************
+ PROCESSING OF THE LEFT CHANNEL
+ ***************************************************************************/
+ // ynL=A2 * x(n-2)L
+ ynL = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[1];
+
+ // ynL+=A1 * x(n-1)L
+ ynL += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[0];
+
+ // ynL+=A0 * x(n)L
+ ynL += (LVM_FLOAT)pBiquadState->coefs[2] * (*pDataIn);
+
+ // ynL+= ( (-B2 * y(n-2)L )
+ ynL += pBiquadState->pDelays[3] * pBiquadState->coefs[3];
+
+ // ynL+= -B1 * y(n-1)L
+ ynL += pBiquadState->pDelays[2] * pBiquadState->coefs[4];
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[3] = pBiquadState->pDelays[2]; // y(n-2)L=y(n-1)L
+ pBiquadState->pDelays[1] = pBiquadState->pDelays[0]; // x(n-2)L=x(n-1)L
+ pBiquadState->pDelays[2] = ynL; // Update y(n-1)L
+ pBiquadState->pDelays[0] = (*pDataIn++); // Update x(n-1)L
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+ *pDataOut++ = (LVM_FLOAT)(ynL); // Write Left output
+
+ }
+ }
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F32Css_TRC_WRA_01_Private.h b/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F32Css_TRC_WRA_01_Private.h
index 9812274..6a61d9a 100644
--- a/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F32Css_TRC_WRA_01_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F32Css_TRC_WRA_01_Private.h
@@ -27,7 +27,6 @@
typedef Filter_State * PFilter_State ;
-#ifdef BUILD_FLOAT
typedef struct _Filter_State_FLOAT
{
LVM_FLOAT * pDelays; /* pointer to the delayed samples (data of 32 bits) */
@@ -35,5 +34,4 @@
}Filter_State_FLOAT;
typedef Filter_State_FLOAT * PFilter_State_FLOAT ;
-#endif
#endif /*_BQ_1I_D16F32CSS_TRC_WRA_01_PRIVATE_H_*/
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F32Css_TRC_WRA_01_init.c b/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F32Css_TRC_WRA_01_init.c
deleted file mode 100644
index feae20d..0000000
--- a/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F32Css_TRC_WRA_01_init.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*-------------------------------------------------------------------------*/
-#include "BIQUAD.h"
-#include "BQ_1I_D16F32Css_TRC_WRA_01_Private.h"
-
-
-/*-------------------------------------------------------------------------*/
-/* FUNCTION: */
-/* BQ_1I_D16F32Css_TRC_WRA_01_Init */
-/* */
-/* DESCRIPTION: */
-/* These functions initializes a BIQUAD filter defined as a cascade of */
-/* biquadratic Filter Sections. */
-/* */
-/* PARAMETERS: */
-/* pInstance - output, returns the pointer to the State Variable */
-/* This state pointer must be passed to any subsequent */
-/* call to "Biquad" functions. */
-/* pTaps - input, pointer to the taps memory */
-/* pCoef - input, pointer to the coefficient structure */
-/* N - M coefficient factor of QM.N */
-/* RETURNS: */
-/* void return code */
-/*-------------------------------------------------------------------------*/
-#ifdef BUILD_FLOAT
-void BQ_1I_D16F32Css_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
- Biquad_1I_Order2_FLOAT_Taps_t *pTaps,
- BQ_FLOAT_Coefs_t *pCoef)
-{
- LVM_FLOAT temp;
- PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
- pBiquadState->pDelays = (LVM_FLOAT *)pTaps;
-
- temp = pCoef->A2;
- pBiquadState->coefs[0] = temp;
- temp = pCoef->A1;
- pBiquadState->coefs[1] = temp;
- temp = pCoef->A0;
- pBiquadState->coefs[2] = temp;
- temp = pCoef->B2;
- pBiquadState->coefs[3] = temp;
- temp = pCoef->B1;
- pBiquadState->coefs[4] = temp;
-}
-#else
-void BQ_1I_D16F32Css_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
- Biquad_1I_Order2_Taps_t *pTaps,
- BQ_C16_Coefs_t *pCoef)
-{
- LVM_INT16 temp;
- PFilter_State pBiquadState = (PFilter_State) pInstance;
- pBiquadState->pDelays =(LVM_INT32 *) pTaps ;
-
- temp=pCoef->A2;
- pBiquadState->coefs[0]=temp;
- temp=pCoef->A1;
- pBiquadState->coefs[1]=temp;
- temp=pCoef->A0;
- pBiquadState->coefs[2]=temp;
- temp=pCoef->B2;
- pBiquadState->coefs[3]=temp;
- temp=pCoef->B1;
- pBiquadState->coefs[4]=temp;
-}
-#endif
-/*-------------------------------------------------------------------------*/
-/* End Of File: BQ_1I_D16F32Css_TRC_WRA_01_Init */
-
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F32Css_TRC_WRA_01_init.cpp b/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F32Css_TRC_WRA_01_init.cpp
new file mode 100644
index 0000000..2b80691
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/BQ_1I_D16F32Css_TRC_WRA_01_init.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*-------------------------------------------------------------------------*/
+#include "BIQUAD.h"
+#include "BQ_1I_D16F32Css_TRC_WRA_01_Private.h"
+
+/*-------------------------------------------------------------------------*/
+/* FUNCTION: */
+/* BQ_1I_D16F32Css_TRC_WRA_01_Init */
+/* */
+/* DESCRIPTION: */
+/* These functions initializes a BIQUAD filter defined as a cascade of */
+/* biquadratic Filter Sections. */
+/* */
+/* PARAMETERS: */
+/* pInstance - output, returns the pointer to the State Variable */
+/* This state pointer must be passed to any subsequent */
+/* call to "Biquad" functions. */
+/* pTaps - input, pointer to the taps memory */
+/* pCoef - input, pointer to the coefficient structure */
+/* N - M coefficient factor of QM.N */
+/* RETURNS: */
+/* void return code */
+/*-------------------------------------------------------------------------*/
+void BQ_1I_D16F32Css_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_1I_Order2_FLOAT_Taps_t *pTaps,
+ BQ_FLOAT_Coefs_t *pCoef)
+{
+ LVM_FLOAT temp;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+ pBiquadState->pDelays = (LVM_FLOAT *)pTaps;
+
+ temp = pCoef->A2;
+ pBiquadState->coefs[0] = temp;
+ temp = pCoef->A1;
+ pBiquadState->coefs[1] = temp;
+ temp = pCoef->A0;
+ pBiquadState->coefs[2] = temp;
+ temp = pCoef->B2;
+ pBiquadState->coefs[3] = temp;
+ temp = pCoef->B1;
+ pBiquadState->coefs[4] = temp;
+}
+/*-------------------------------------------------------------------------*/
+/* End Of File: BQ_1I_D16F32Css_TRC_WRA_01_Init */
+
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16C14_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16C14_TRC_WRA_01.c
deleted file mode 100644
index 9b0fde3..0000000
--- a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16C14_TRC_WRA_01.c
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BIQUAD.h"
-#include "BQ_2I_D16F16Css_TRC_WRA_01_Private.h"
-#include "LVM_Macros.h"
-
-
-/**************************************************************************
- ASSUMPTIONS:
- COEFS-
- pBiquadState->coefs[0] is A2, pBiquadState->coefs[1] is A1
- pBiquadState->coefs[2] is A0, pBiquadState->coefs[3] is -B2
- pBiquadState->coefs[4] is -B1, these are in Q14 format
-
- DELAYS-
- pBiquadState->pDelays[0] is x(n-1)L in Q0 format
- pBiquadState->pDelays[1] is x(n-1)R in Q0 format
- pBiquadState->pDelays[2] is x(n-2)L in Q0 format
- pBiquadState->pDelays[3] is x(n-2)R in Q0 format
- pBiquadState->pDelays[4] is y(n-1)L in Q0 format
- pBiquadState->pDelays[5] is y(n-1)R in Q0 format
- pBiquadState->pDelays[6] is y(n-2)L in Q0 format
- pBiquadState->pDelays[7] is y(n-2)R in Q0 format
-***************************************************************************/
-#ifdef BUILD_FLOAT
-void BQ_2I_D16F16C14_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
- LVM_FLOAT *pDataIn,
- LVM_FLOAT *pDataOut,
- LVM_INT16 NrSamples)
- {
- LVM_FLOAT ynL,ynR;
- LVM_INT16 ii;
- PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
-
- for (ii = NrSamples; ii != 0; ii--)
- {
-
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
- // ynL=A2 * x(n-2)L
- ynL = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[2];
-
- // ynL+=A1 * x(n-1)L
- ynL += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[0];
-
- // ynL+=A0 * x(n)L
- ynL += (LVM_FLOAT)pBiquadState->coefs[2] * (*pDataIn);
-
- // ynL+= ( -B2 * y(n-2)L )
- ynL += (LVM_FLOAT)pBiquadState->coefs[3] * pBiquadState->pDelays[6];
-
- // ynL+=( -B1 * y(n-1)L )
- ynL += (LVM_FLOAT)pBiquadState->coefs[4] * pBiquadState->pDelays[4];
-
-
-
- /**************************************************************************
- PROCESSING OF THE RIGHT CHANNEL
- ***************************************************************************/
- // ynR=A2 * x(n-2)R
- ynR = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[3];
-
- // ynR+=A1 * x(n-1)R
- ynR += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[1];
-
- // ynR+=A0 * x(n)R
- ynR += (LVM_FLOAT)pBiquadState->coefs[2] * (*(pDataIn+1));
-
- // ynR+= ( -B2 * y(n-2)R )
- ynR += (LVM_FLOAT)pBiquadState->coefs[3] * pBiquadState->pDelays[7];
-
- // ynR+=( -B1 * y(n-1)R )
- ynR += (LVM_FLOAT)pBiquadState->coefs[4] * pBiquadState->pDelays[5];
-
-
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[7] = pBiquadState->pDelays[5]; // y(n-2)R=y(n-1)R
- pBiquadState->pDelays[6] = pBiquadState->pDelays[4]; // y(n-2)L=y(n-1)L
- pBiquadState->pDelays[3] = pBiquadState->pDelays[1]; // x(n-2)R=x(n-1)R
- pBiquadState->pDelays[2] = pBiquadState->pDelays[0]; // x(n-2)L=x(n-1)L
- pBiquadState->pDelays[5] = ynR; // Update y(n-1)R
- pBiquadState->pDelays[4] = ynL; // Update y(n-1)L
- pBiquadState->pDelays[0] = (*pDataIn++); // Update x(n-1)L
- pBiquadState->pDelays[1] = (*pDataIn++); // Update x(n-1)R
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut++ = (LVM_FLOAT)ynL; // Write Left output
- *pDataOut++ = (LVM_FLOAT)ynR; // Write Right ouput
-
-
- }
-
- }
-#else
-void BQ_2I_D16F16C14_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
- LVM_INT16 *pDataIn,
- LVM_INT16 *pDataOut,
- LVM_INT16 NrSamples)
- {
- LVM_INT32 ynL,ynR;
- LVM_INT16 ii;
- PFilter_State pBiquadState = (PFilter_State) pInstance;
-
- for (ii = NrSamples; ii != 0; ii--)
- {
-
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
- // ynL=A2 (Q14) * x(n-2)L (Q0) in Q14
- ynL=(LVM_INT32)pBiquadState->coefs[0]* pBiquadState->pDelays[2];
-
- // ynL+=A1 (Q14) * x(n-1)L (Q0) in Q14
- ynL+=(LVM_INT32)pBiquadState->coefs[1]* pBiquadState->pDelays[0];
-
- // ynL+=A0 (Q14) * x(n)L (Q0) in Q14
- ynL+=(LVM_INT32)pBiquadState->coefs[2]* (*pDataIn);
-
- // ynL+= ( -B2 (Q14) * y(n-2)L (Q0) ) in Q14
- ynL+=(LVM_INT32)pBiquadState->coefs[3]*pBiquadState->pDelays[6];
-
- // ynL+=( -B1 (Q14) * y(n-1)L (Q0) ) in Q14
- ynL+=(LVM_INT32)pBiquadState->coefs[4]*pBiquadState->pDelays[4];
-
- ynL=ynL>>14; // ynL in Q0 format
-
- /**************************************************************************
- PROCESSING OF THE RIGHT CHANNEL
- ***************************************************************************/
- // ynR=A2 (Q14) * x(n-2)R (Q0) in Q14
- ynR=(LVM_INT32)pBiquadState->coefs[0]*pBiquadState->pDelays[3];
-
- // ynR+=A1 (Q14) * x(n-1)R (Q0) in Q14
- ynR+=(LVM_INT32)pBiquadState->coefs[1]*pBiquadState->pDelays[1];
-
- // ynR+=A0 (Q14) * x(n)R (Q0) in Q14
- ynR+=(LVM_INT32)pBiquadState->coefs[2]*(*(pDataIn+1));
-
- // ynR+= ( -B2 (Q14) * y(n-2)R (Q0) ) in Q14
- ynR+=(LVM_INT32)pBiquadState->coefs[3]*pBiquadState->pDelays[7];
-
- // ynR+=( -B1 (Q14) * y(n-1)R (Q0) ) in Q14
- ynR+=(LVM_INT32)pBiquadState->coefs[4]*pBiquadState->pDelays[5];
-
- ynR=ynR>>14; // ynL in Q0 format
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[7]=pBiquadState->pDelays[5]; // y(n-2)R=y(n-1)R
- pBiquadState->pDelays[6]=pBiquadState->pDelays[4]; // y(n-2)L=y(n-1)L
- pBiquadState->pDelays[3]=pBiquadState->pDelays[1]; // x(n-2)R=x(n-1)R
- pBiquadState->pDelays[2]=pBiquadState->pDelays[0]; // x(n-2)L=x(n-1)L
- pBiquadState->pDelays[5]=ynR; // Update y(n-1)R in Q0
- pBiquadState->pDelays[4]=ynL; // Update y(n-1)L in Q0
- pBiquadState->pDelays[0]=(*pDataIn++); // Update x(n-1)L in Q0
- pBiquadState->pDelays[1]=(*pDataIn++); // Update x(n-1)R in Q0
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut++=(LVM_INT16)ynL; // Write Left output in Q0
- *pDataOut++=(LVM_INT16)ynR; // Write Right ouput in Q0
-
-
- }
-
- }
-
-#endif
\ No newline at end of file
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16C14_TRC_WRA_01.cpp b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16C14_TRC_WRA_01.cpp
new file mode 100644
index 0000000..51cd918
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16C14_TRC_WRA_01.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BIQUAD.h"
+#include "BQ_2I_D16F16Css_TRC_WRA_01_Private.h"
+#include "LVM_Macros.h"
+
+/**************************************************************************
+ ASSUMPTIONS:
+ COEFS-
+ pBiquadState->coefs[0] is A2, pBiquadState->coefs[1] is A1
+ pBiquadState->coefs[2] is A0, pBiquadState->coefs[3] is -B2
+ pBiquadState->coefs[4] is -B1, these are in Q14 format
+
+ DELAYS-
+ pBiquadState->pDelays[0] is x(n-1)L in Q0 format
+ pBiquadState->pDelays[1] is x(n-1)R in Q0 format
+ pBiquadState->pDelays[2] is x(n-2)L in Q0 format
+ pBiquadState->pDelays[3] is x(n-2)R in Q0 format
+ pBiquadState->pDelays[4] is y(n-1)L in Q0 format
+ pBiquadState->pDelays[5] is y(n-1)R in Q0 format
+ pBiquadState->pDelays[6] is y(n-2)L in Q0 format
+ pBiquadState->pDelays[7] is y(n-2)R in Q0 format
+***************************************************************************/
+void BQ_2I_D16F16C14_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+ {
+ LVM_FLOAT ynL,ynR;
+ LVM_INT16 ii;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+
+ for (ii = NrSamples; ii != 0; ii--)
+ {
+
+ /**************************************************************************
+ PROCESSING OF THE LEFT CHANNEL
+ ***************************************************************************/
+ // ynL=A2 * x(n-2)L
+ ynL = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[2];
+
+ // ynL+=A1 * x(n-1)L
+ ynL += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[0];
+
+ // ynL+=A0 * x(n)L
+ ynL += (LVM_FLOAT)pBiquadState->coefs[2] * (*pDataIn);
+
+ // ynL+= ( -B2 * y(n-2)L )
+ ynL += (LVM_FLOAT)pBiquadState->coefs[3] * pBiquadState->pDelays[6];
+
+ // ynL+=( -B1 * y(n-1)L )
+ ynL += (LVM_FLOAT)pBiquadState->coefs[4] * pBiquadState->pDelays[4];
+
+ /**************************************************************************
+ PROCESSING OF THE RIGHT CHANNEL
+ ***************************************************************************/
+ // ynR=A2 * x(n-2)R
+ ynR = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[3];
+
+ // ynR+=A1 * x(n-1)R
+ ynR += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[1];
+
+ // ynR+=A0 * x(n)R
+ ynR += (LVM_FLOAT)pBiquadState->coefs[2] * (*(pDataIn+1));
+
+ // ynR+= ( -B2 * y(n-2)R )
+ ynR += (LVM_FLOAT)pBiquadState->coefs[3] * pBiquadState->pDelays[7];
+
+ // ynR+=( -B1 * y(n-1)R )
+ ynR += (LVM_FLOAT)pBiquadState->coefs[4] * pBiquadState->pDelays[5];
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[7] = pBiquadState->pDelays[5]; // y(n-2)R=y(n-1)R
+ pBiquadState->pDelays[6] = pBiquadState->pDelays[4]; // y(n-2)L=y(n-1)L
+ pBiquadState->pDelays[3] = pBiquadState->pDelays[1]; // x(n-2)R=x(n-1)R
+ pBiquadState->pDelays[2] = pBiquadState->pDelays[0]; // x(n-2)L=x(n-1)L
+ pBiquadState->pDelays[5] = ynR; // Update y(n-1)R
+ pBiquadState->pDelays[4] = ynL; // Update y(n-1)L
+ pBiquadState->pDelays[0] = (*pDataIn++); // Update x(n-1)L
+ pBiquadState->pDelays[1] = (*pDataIn++); // Update x(n-1)R
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+ *pDataOut++ = (LVM_FLOAT)ynL; // Write Left output
+ *pDataOut++ = (LVM_FLOAT)ynR; // Write Right ouput
+
+ }
+
+ }
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16C15_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16C15_TRC_WRA_01.c
deleted file mode 100644
index f24db8f..0000000
--- a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16C15_TRC_WRA_01.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BIQUAD.h"
-#include "BQ_2I_D16F16Css_TRC_WRA_01_Private.h"
-#include "LVM_Macros.h"
-
-
-/**************************************************************************
- ASSUMPTIONS:
- COEFS-
- pBiquadState->coefs[0] is A2, pBiquadState->coefs[1] is A1
- pBiquadState->coefs[2] is A0, pBiquadState->coefs[3] is -B2
- pBiquadState->coefs[4] is -B1, these are in Q15 format
-
- DELAYS-
- pBiquadState->pDelays[0] is x(n-1)L in Q0 format
- pBiquadState->pDelays[1] is x(n-1)R in Q0 format
- pBiquadState->pDelays[2] is x(n-2)L in Q0 format
- pBiquadState->pDelays[3] is x(n-2)R in Q0 format
- pBiquadState->pDelays[4] is y(n-1)L in Q0 format
- pBiquadState->pDelays[5] is y(n-1)R in Q0 format
- pBiquadState->pDelays[6] is y(n-2)L in Q0 format
- pBiquadState->pDelays[7] is y(n-2)R in Q0 format
-***************************************************************************/
-#ifdef BUILD_FLOAT
-void BQ_2I_D16F16C15_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
- LVM_FLOAT *pDataIn,
- LVM_FLOAT *pDataOut,
- LVM_INT16 NrSamples)
- {
- LVM_FLOAT ynL,ynR;
- LVM_INT16 ii;
- PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
-
- for (ii = NrSamples; ii != 0; ii--)
- {
-
-
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
- // ynL=A2 * x(n-2)L
- ynL = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[2];
-
- // ynL+=A1 * x(n-1)L
- ynL += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[0];
-
- // ynL+=A0 * x(n)L
- ynL += (LVM_FLOAT)pBiquadState->coefs[2] * (*pDataIn);
-
- // ynL+= ( -B2 * y(n-2)L
- ynL += (LVM_FLOAT)pBiquadState->coefs[3] * pBiquadState->pDelays[6];
-
- // ynL+=( -B1 * y(n-1)L
- ynL += (LVM_FLOAT)pBiquadState->coefs[4] * pBiquadState->pDelays[4];
-
-
-
- /**************************************************************************
- PROCESSING OF THE RIGHT CHANNEL
- ***************************************************************************/
- // ynR=A2 * x(n-2)R
- ynR = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[3];
-
- // ynR+=A1 * x(n-1)R
- ynR += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[1];
-
- // ynR+=A0 * x(n)R
- ynR += (LVM_FLOAT)pBiquadState->coefs[2] * (*(pDataIn+1));
-
- // ynR+= ( -B2 * y(n-2)R )
- ynR += (LVM_FLOAT)pBiquadState->coefs[3] * pBiquadState->pDelays[7];
-
- // ynR+=( -B1 * y(n-1)R )
- ynR += (LVM_FLOAT)pBiquadState->coefs[4] * pBiquadState->pDelays[5];
-
-
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[7] = pBiquadState->pDelays[5]; // y(n-2)R=y(n-1)R
- pBiquadState->pDelays[6] = pBiquadState->pDelays[4]; // y(n-2)L=y(n-1)L
- pBiquadState->pDelays[3] = pBiquadState->pDelays[1]; // x(n-2)R=x(n-1)R
- pBiquadState->pDelays[2] = pBiquadState->pDelays[0]; // x(n-2)L=x(n-1)L
- pBiquadState->pDelays[5] = ynR; // Update y(n-1)R
- pBiquadState->pDelays[4] = ynL; // Update y(n-1)L
- pBiquadState->pDelays[0] = (*pDataIn++); // Update x(n-1)L
- pBiquadState->pDelays[1] = (*pDataIn++); // Update x(n-1)R
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut++ = (LVM_FLOAT)ynL; // Write Left output
- *pDataOut++ = (LVM_FLOAT)ynR; // Write Right ouput
-
- }
-
- }
-#else
-void BQ_2I_D16F16C15_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
- LVM_INT16 *pDataIn,
- LVM_INT16 *pDataOut,
- LVM_INT16 NrSamples)
- {
- LVM_INT32 ynL,ynR;
- LVM_INT16 ii;
- PFilter_State pBiquadState = (PFilter_State) pInstance;
-
- for (ii = NrSamples; ii != 0; ii--)
- {
-
-
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
- // ynL=A2 (Q15) * x(n-2)L (Q0) in Q15
- ynL=(LVM_INT32)pBiquadState->coefs[0]* pBiquadState->pDelays[2];
-
- // ynL+=A1 (Q15) * x(n-1)L (Q0) in Q15
- ynL+=(LVM_INT32)pBiquadState->coefs[1]* pBiquadState->pDelays[0];
-
- // ynL+=A0 (Q15) * x(n)L (Q0) in Q15
- ynL+=(LVM_INT32)pBiquadState->coefs[2]* (*pDataIn);
-
- // ynL+= ( -B2 (Q15) * y(n-2)L (Q0) ) in Q15
- ynL+=(LVM_INT32)pBiquadState->coefs[3]*pBiquadState->pDelays[6];
-
- // ynL+=( -B1 (Q15) * y(n-1)L (Q0) ) in Q15
- ynL+=(LVM_INT32)pBiquadState->coefs[4]*pBiquadState->pDelays[4];
-
- ynL=ynL>>15; // ynL in Q0 format
-
- /**************************************************************************
- PROCESSING OF THE RIGHT CHANNEL
- ***************************************************************************/
- // ynR=A2 (Q15) * x(n-2)R (Q0) in Q15
- ynR=(LVM_INT32)pBiquadState->coefs[0]*pBiquadState->pDelays[3];
-
- // ynR+=A1 (Q15) * x(n-1)R (Q0) in Q15
- ynR+=(LVM_INT32)pBiquadState->coefs[1]*pBiquadState->pDelays[1];
-
- // ynR+=A0 (Q15) * x(n)R (Q0) in Q15
- ynR+=(LVM_INT32)pBiquadState->coefs[2]*(*(pDataIn+1));
-
- // ynR+= ( -B2 (Q15) * y(n-2)R (Q0) ) in Q15
- ynR+=(LVM_INT32)pBiquadState->coefs[3]*pBiquadState->pDelays[7];
-
- // ynR+=( -B1 (Q15) * y(n-1)R (Q0) ) in Q15
- ynR+=(LVM_INT32)pBiquadState->coefs[4]*pBiquadState->pDelays[5];
-
- ynR=ynR>>15; // ynL in Q0 format
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[7]=pBiquadState->pDelays[5]; // y(n-2)R=y(n-1)R
- pBiquadState->pDelays[6]=pBiquadState->pDelays[4]; // y(n-2)L=y(n-1)L
- pBiquadState->pDelays[3]=pBiquadState->pDelays[1]; // x(n-2)R=x(n-1)R
- pBiquadState->pDelays[2]=pBiquadState->pDelays[0]; // x(n-2)L=x(n-1)L
- pBiquadState->pDelays[5]=ynR; // Update y(n-1)R in Q0
- pBiquadState->pDelays[4]=ynL; // Update y(n-1)L in Q0
- pBiquadState->pDelays[0]=(*pDataIn++); // Update x(n-1)L in Q0
- pBiquadState->pDelays[1]=(*pDataIn++); // Update x(n-1)R in Q0
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut++=(LVM_INT16)ynL; // Write Left output in Q0
- *pDataOut++=(LVM_INT16)ynR; // Write Right ouput in Q0
-
- }
-
- }
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16C15_TRC_WRA_01.cpp b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16C15_TRC_WRA_01.cpp
new file mode 100644
index 0000000..8f74749
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16C15_TRC_WRA_01.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BIQUAD.h"
+#include "BQ_2I_D16F16Css_TRC_WRA_01_Private.h"
+#include "LVM_Macros.h"
+
+/**************************************************************************
+ ASSUMPTIONS:
+ COEFS-
+ pBiquadState->coefs[0] is A2, pBiquadState->coefs[1] is A1
+ pBiquadState->coefs[2] is A0, pBiquadState->coefs[3] is -B2
+ pBiquadState->coefs[4] is -B1, these are in Q15 format
+
+ DELAYS-
+ pBiquadState->pDelays[0] is x(n-1)L in Q0 format
+ pBiquadState->pDelays[1] is x(n-1)R in Q0 format
+ pBiquadState->pDelays[2] is x(n-2)L in Q0 format
+ pBiquadState->pDelays[3] is x(n-2)R in Q0 format
+ pBiquadState->pDelays[4] is y(n-1)L in Q0 format
+ pBiquadState->pDelays[5] is y(n-1)R in Q0 format
+ pBiquadState->pDelays[6] is y(n-2)L in Q0 format
+ pBiquadState->pDelays[7] is y(n-2)R in Q0 format
+***************************************************************************/
+void BQ_2I_D16F16C15_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+ {
+ LVM_FLOAT ynL,ynR;
+ LVM_INT16 ii;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+
+ for (ii = NrSamples; ii != 0; ii--)
+ {
+
+ /**************************************************************************
+ PROCESSING OF THE LEFT CHANNEL
+ ***************************************************************************/
+ // ynL=A2 * x(n-2)L
+ ynL = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[2];
+
+ // ynL+=A1 * x(n-1)L
+ ynL += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[0];
+
+ // ynL+=A0 * x(n)L
+ ynL += (LVM_FLOAT)pBiquadState->coefs[2] * (*pDataIn);
+
+ // ynL+= ( -B2 * y(n-2)L
+ ynL += (LVM_FLOAT)pBiquadState->coefs[3] * pBiquadState->pDelays[6];
+
+ // ynL+=( -B1 * y(n-1)L
+ ynL += (LVM_FLOAT)pBiquadState->coefs[4] * pBiquadState->pDelays[4];
+
+ /**************************************************************************
+ PROCESSING OF THE RIGHT CHANNEL
+ ***************************************************************************/
+ // ynR=A2 * x(n-2)R
+ ynR = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[3];
+
+ // ynR+=A1 * x(n-1)R
+ ynR += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[1];
+
+ // ynR+=A0 * x(n)R
+ ynR += (LVM_FLOAT)pBiquadState->coefs[2] * (*(pDataIn+1));
+
+ // ynR+= ( -B2 * y(n-2)R )
+ ynR += (LVM_FLOAT)pBiquadState->coefs[3] * pBiquadState->pDelays[7];
+
+ // ynR+=( -B1 * y(n-1)R )
+ ynR += (LVM_FLOAT)pBiquadState->coefs[4] * pBiquadState->pDelays[5];
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[7] = pBiquadState->pDelays[5]; // y(n-2)R=y(n-1)R
+ pBiquadState->pDelays[6] = pBiquadState->pDelays[4]; // y(n-2)L=y(n-1)L
+ pBiquadState->pDelays[3] = pBiquadState->pDelays[1]; // x(n-2)R=x(n-1)R
+ pBiquadState->pDelays[2] = pBiquadState->pDelays[0]; // x(n-2)L=x(n-1)L
+ pBiquadState->pDelays[5] = ynR; // Update y(n-1)R
+ pBiquadState->pDelays[4] = ynL; // Update y(n-1)L
+ pBiquadState->pDelays[0] = (*pDataIn++); // Update x(n-1)L
+ pBiquadState->pDelays[1] = (*pDataIn++); // Update x(n-1)R
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+ *pDataOut++ = (LVM_FLOAT)ynL; // Write Left output
+ *pDataOut++ = (LVM_FLOAT)ynR; // Write Right ouput
+
+ }
+
+ }
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16Css_TRC_WRA_01_Init.c b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16Css_TRC_WRA_01_Init.c
deleted file mode 100644
index 39e1bda..0000000
--- a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16Css_TRC_WRA_01_Init.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*-------------------------------------------------------------------------*/
-#include "BIQUAD.h"
-#include "BQ_2I_D16F16Css_TRC_WRA_01_Private.h"
-
-
-/*-------------------------------------------------------------------------*/
-/* FUNCTION: */
-/* BQ_2I_D16F16Css_TRC_WRA_01_Init */
-/* */
-/* DESCRIPTION: */
-/* These functions initializes a BIQUAD filter defined as a cascade of */
-/* biquadratic Filter Sections. */
-/* */
-/* PARAMETERS: */
-/* pInstance - output, returns the pointer to the State Variable */
-/* This state pointer must be passed to any subsequent */
-/* call to "Biquad" functions. */
-/* pTaps - input, pointer to the taps memory */
-/* pCoef - input, pointer to the coefficient structure */
-/* N - M coefficient factor of QM.N */
-/* RETURNS: */
-/* void return code */
-/*-------------------------------------------------------------------------*/
-#ifdef BUILD_FLOAT
-void BQ_2I_D16F16Css_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
- Biquad_2I_Order2_FLOAT_Taps_t *pTaps,
- BQ_FLOAT_Coefs_t *pCoef)
-{
- LVM_FLOAT temp;
- PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
- pBiquadState->pDelays = (LVM_FLOAT *) pTaps ;
-
- temp = pCoef->A2;
- pBiquadState->coefs[0] = temp;
- temp = pCoef->A1;
- pBiquadState->coefs[1] = temp;
- temp = pCoef->A0;
- pBiquadState->coefs[2] = temp;
- temp = pCoef->B2;
- pBiquadState->coefs[3] = temp;
- temp = pCoef->B1;
- pBiquadState->coefs[4] = temp;
-}
-#else
-void BQ_2I_D16F16Css_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
- Biquad_2I_Order2_Taps_t *pTaps,
- BQ_C16_Coefs_t *pCoef)
-{
- LVM_INT16 temp;
- PFilter_State pBiquadState = (PFilter_State) pInstance;
- pBiquadState->pDelays =(LVM_INT32 *) pTaps ;
-
- temp=pCoef->A2;
- pBiquadState->coefs[0]=temp;
- temp=pCoef->A1;
- pBiquadState->coefs[1]=temp;
- temp=pCoef->A0;
- pBiquadState->coefs[2]=temp;
- temp=pCoef->B2;
- pBiquadState->coefs[3]=temp;
- temp=pCoef->B1;
- pBiquadState->coefs[4]=temp;
-}
-#endif
-/*-------------------------------------------------------------------------*/
-/* End Of File: BQ_2I_D16F16Css_TRC_WRA_01_Init.c */
-
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16Css_TRC_WRA_01_Init.cpp b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16Css_TRC_WRA_01_Init.cpp
new file mode 100644
index 0000000..987cbcf
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16Css_TRC_WRA_01_Init.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*-------------------------------------------------------------------------*/
+#include "BIQUAD.h"
+#include "BQ_2I_D16F16Css_TRC_WRA_01_Private.h"
+
+/*-------------------------------------------------------------------------*/
+/* FUNCTION: */
+/* BQ_2I_D16F16Css_TRC_WRA_01_Init */
+/* */
+/* DESCRIPTION: */
+/* These functions initializes a BIQUAD filter defined as a cascade of */
+/* biquadratic Filter Sections. */
+/* */
+/* PARAMETERS: */
+/* pInstance - output, returns the pointer to the State Variable */
+/* This state pointer must be passed to any subsequent */
+/* call to "Biquad" functions. */
+/* pTaps - input, pointer to the taps memory */
+/* pCoef - input, pointer to the coefficient structure */
+/* N - M coefficient factor of QM.N */
+/* RETURNS: */
+/* void return code */
+/*-------------------------------------------------------------------------*/
+void BQ_2I_D16F16Css_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_2I_Order2_FLOAT_Taps_t *pTaps,
+ BQ_FLOAT_Coefs_t *pCoef)
+{
+ LVM_FLOAT temp;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+ pBiquadState->pDelays = (LVM_FLOAT *) pTaps ;
+
+ temp = pCoef->A2;
+ pBiquadState->coefs[0] = temp;
+ temp = pCoef->A1;
+ pBiquadState->coefs[1] = temp;
+ temp = pCoef->A0;
+ pBiquadState->coefs[2] = temp;
+ temp = pCoef->B2;
+ pBiquadState->coefs[3] = temp;
+ temp = pCoef->B1;
+ pBiquadState->coefs[4] = temp;
+}
+/*-------------------------------------------------------------------------*/
+/* End Of File: BQ_2I_D16F16Css_TRC_WRA_01_Init.c */
+
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16Css_TRC_WRA_01_Private.h b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16Css_TRC_WRA_01_Private.h
index 0691b8c..5a9a0e9 100644
--- a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16Css_TRC_WRA_01_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F16Css_TRC_WRA_01_Private.h
@@ -28,7 +28,6 @@
typedef Filter_State * PFilter_State ;
-#ifdef BUILD_FLOAT
typedef struct _Filter_State_FLOAT
{
LVM_FLOAT * pDelays; /* pointer to the delayed samples (data of 32 bits) */
@@ -36,6 +35,5 @@
}Filter_State_FLOAT;
typedef Filter_State_FLOAT * PFilter_State_FLOAT ;
-#endif
#endif /* _BQ_2I_D16F16CSS_TRC_WRA_01_PRIVATE_H_ */
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32C13_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32C13_TRC_WRA_01.c
deleted file mode 100644
index 61c07c7..0000000
--- a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32C13_TRC_WRA_01.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BIQUAD.h"
-#include "BQ_2I_D16F32Css_TRC_WRA_01_Private.h"
-#include "LVM_Macros.h"
-
-
-/**************************************************************************
- ASSUMPTIONS:
- COEFS-
- pBiquadState->coefs[0] is A2, pBiquadState->coefs[1] is A1
- pBiquadState->coefs[2] is A0, pBiquadState->coefs[3] is -B2
- pBiquadState->coefs[4] is -B1, these are in Q13 format
-
- DELAYS-
- pBiquadState->pDelays[0] is x(n-1)L in Q0 format
- pBiquadState->pDelays[1] is x(n-1)R in Q0 format
- pBiquadState->pDelays[2] is x(n-2)L in Q0 format
- pBiquadState->pDelays[3] is x(n-2)R in Q0 format
- pBiquadState->pDelays[4] is y(n-1)L in Q16 format
- pBiquadState->pDelays[5] is y(n-1)R in Q16 format
- pBiquadState->pDelays[6] is y(n-2)L in Q16 format
- pBiquadState->pDelays[7] is y(n-2)R in Q16 format
-***************************************************************************/
-#ifdef BUILD_FLOAT
-void BQ_2I_D16F32C13_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
- LVM_FLOAT *pDataIn,
- LVM_FLOAT *pDataOut,
- LVM_INT16 NrSamples)
- {
- LVM_FLOAT ynL,ynR;
- LVM_INT16 ii;
- PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
-
- for (ii = NrSamples; ii != 0; ii--)
- {
-
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
- /* ynL=A2 * x(n-2)L */
- ynL = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[2];
-
- /* ynL+=A1* x(n-1)L */
- ynL += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[0];
-
- /* ynL+=A0* x(n)L */
- ynL += (LVM_FLOAT)pBiquadState->coefs[2] * (*pDataIn);
-
- /* ynL+=-B2*y(n-2)L */
- ynL += pBiquadState->pDelays[6] * pBiquadState->coefs[3];
-
- /* ynL+=-B1*y(n-1)L */
- ynL += pBiquadState->pDelays[4] * pBiquadState->coefs[4];
-
- /**************************************************************************
- PROCESSING OF THE RIGHT CHANNEL
- ***************************************************************************/
- /* ynR=A2 * x(n-2)R */
- ynR = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[3];
-
- /* ynR+=A1* x(n-1)R */
- ynR += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[1];
-
- /* ynR+=A0* x(n)R */
- ynR += (LVM_FLOAT)pBiquadState->coefs[2] * (*(pDataIn+1));
-
- /* ynR+=-B2 * y(n-2)R */
- ynR += pBiquadState->pDelays[7] * pBiquadState->coefs[3];
-
- /* ynR+=-B1 * y(n-1)R */
- ynR += pBiquadState->pDelays[5] * pBiquadState->coefs[4];
-
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[7] = pBiquadState->pDelays[5]; /* y(n-2)R=y(n-1)R*/
- pBiquadState->pDelays[6] = pBiquadState->pDelays[4]; /* y(n-2)L=y(n-1)L*/
- pBiquadState->pDelays[3] = pBiquadState->pDelays[1]; /* x(n-2)R=x(n-1)R*/
- pBiquadState->pDelays[2] = pBiquadState->pDelays[0]; /* x(n-2)L=x(n-1)L*/
- pBiquadState->pDelays[5] = ynR; /* Update y(n-1)R */
- pBiquadState->pDelays[4] = ynL; /* Update y(n-1)L */
- pBiquadState->pDelays[0] = (*pDataIn); /* Update x(n-1)L */
- pDataIn++;
- pBiquadState->pDelays[1] = (*pDataIn); /* Update x(n-1)R */
- pDataIn++;
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut = (LVM_FLOAT)(ynL); /* Write Left output */
- pDataOut++;
- *pDataOut = (LVM_FLOAT)(ynR); /* Write Right ouput */
- pDataOut++;
- }
- }
-#else
-void BQ_2I_D16F32C13_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
- LVM_INT16 *pDataIn,
- LVM_INT16 *pDataOut,
- LVM_INT16 NrSamples)
- {
- LVM_INT32 ynL,ynR,templ;
- LVM_INT16 ii;
- PFilter_State pBiquadState = (PFilter_State) pInstance;
-
- for (ii = NrSamples; ii != 0; ii--)
- {
-
-
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
- /* ynL=A2 (Q13) * x(n-2)L (Q0) in Q13*/
- ynL=(LVM_INT32)pBiquadState->coefs[0]* pBiquadState->pDelays[2];
-
- /* ynL+=A1 (Q13) * x(n-1)L (Q0) in Q13*/
- ynL+=(LVM_INT32)pBiquadState->coefs[1]* pBiquadState->pDelays[0];
-
- /* ynL+=A0 (Q13) * x(n)L (Q0) in Q13*/
- ynL+=(LVM_INT32)pBiquadState->coefs[2]* (*pDataIn);
-
- /* ynL+= ( (-B2 (Q13) * y(n-2)L (Q16) )>>16) in Q13 */
- MUL32x16INTO32(pBiquadState->pDelays[6],pBiquadState->coefs[3],templ,16)
- ynL+=templ;
-
- /* ynL+=( (-B1 (Q13) * y(n-1)L (Q16) )>>16) in Q13 */
- MUL32x16INTO32(pBiquadState->pDelays[4],pBiquadState->coefs[4],templ,16)
- ynL+=templ;
-
- /**************************************************************************
- PROCESSING OF THE RIGHT CHANNEL
- ***************************************************************************/
- /* ynR=A2 (Q13) * x(n-2)R (Q0) in Q13*/
- ynR=(LVM_INT32)pBiquadState->coefs[0]*pBiquadState->pDelays[3];
-
- /* ynR+=A1 (Q13) * x(n-1)R (Q0) in Q13*/
- ynR+=(LVM_INT32)pBiquadState->coefs[1]*pBiquadState->pDelays[1];
-
- /* ynR+=A0 (Q13) * x(n)R (Q0) in Q13*/
- ynR+=(LVM_INT32)pBiquadState->coefs[2]*(*(pDataIn+1));
-
- /* ynR+= ( (-B2 (Q13) * y(n-2)R (Q16) )>>16) in Q13*/
- MUL32x16INTO32(pBiquadState->pDelays[7],pBiquadState->coefs[3],templ,16)
- ynR+=templ;
-
- /* ynR+=( (-B1 (Q13) * y(n-1)R (Q16) )>>16) in Q13 */
- MUL32x16INTO32(pBiquadState->pDelays[5],pBiquadState->coefs[4],templ,16)
- ynR+=templ;
-
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[7]=pBiquadState->pDelays[5]; /* y(n-2)R=y(n-1)R*/
- pBiquadState->pDelays[6]=pBiquadState->pDelays[4]; /* y(n-2)L=y(n-1)L*/
- pBiquadState->pDelays[3]=pBiquadState->pDelays[1]; /* x(n-2)R=x(n-1)R*/
- pBiquadState->pDelays[2]=pBiquadState->pDelays[0]; /* x(n-2)L=x(n-1)L*/
- pBiquadState->pDelays[5]=ynR<<3; /* Update y(n-1)R in Q16*/
- pBiquadState->pDelays[4]=ynL<<3; /* Update y(n-1)L in Q16*/
- pBiquadState->pDelays[0]=(*pDataIn); /* Update x(n-1)L in Q0*/
- pDataIn++;
- pBiquadState->pDelays[1]=(*pDataIn); /* Update x(n-1)R in Q0*/
- pDataIn++;
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut=(LVM_INT16)(ynL>>13); /* Write Left output in Q0*/
- pDataOut++;
- *pDataOut=(LVM_INT16)(ynR>>13); /* Write Right ouput in Q0*/
- pDataOut++;
- }
-
- }
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32C13_TRC_WRA_01.cpp b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32C13_TRC_WRA_01.cpp
new file mode 100644
index 0000000..331c97f
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32C13_TRC_WRA_01.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BIQUAD.h"
+#include "BQ_2I_D16F32Css_TRC_WRA_01_Private.h"
+#include "LVM_Macros.h"
+
+/**************************************************************************
+ ASSUMPTIONS:
+ COEFS-
+ pBiquadState->coefs[0] is A2, pBiquadState->coefs[1] is A1
+ pBiquadState->coefs[2] is A0, pBiquadState->coefs[3] is -B2
+ pBiquadState->coefs[4] is -B1, these are in Q13 format
+
+ DELAYS-
+ pBiquadState->pDelays[0] is x(n-1)L in Q0 format
+ pBiquadState->pDelays[1] is x(n-1)R in Q0 format
+ pBiquadState->pDelays[2] is x(n-2)L in Q0 format
+ pBiquadState->pDelays[3] is x(n-2)R in Q0 format
+ pBiquadState->pDelays[4] is y(n-1)L in Q16 format
+ pBiquadState->pDelays[5] is y(n-1)R in Q16 format
+ pBiquadState->pDelays[6] is y(n-2)L in Q16 format
+ pBiquadState->pDelays[7] is y(n-2)R in Q16 format
+***************************************************************************/
+void BQ_2I_D16F32C13_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+ {
+ LVM_FLOAT ynL,ynR;
+ LVM_INT16 ii;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+
+ for (ii = NrSamples; ii != 0; ii--)
+ {
+
+ /**************************************************************************
+ PROCESSING OF THE LEFT CHANNEL
+ ***************************************************************************/
+ /* ynL=A2 * x(n-2)L */
+ ynL = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[2];
+
+ /* ynL+=A1* x(n-1)L */
+ ynL += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[0];
+
+ /* ynL+=A0* x(n)L */
+ ynL += (LVM_FLOAT)pBiquadState->coefs[2] * (*pDataIn);
+
+ /* ynL+=-B2*y(n-2)L */
+ ynL += pBiquadState->pDelays[6] * pBiquadState->coefs[3];
+
+ /* ynL+=-B1*y(n-1)L */
+ ynL += pBiquadState->pDelays[4] * pBiquadState->coefs[4];
+
+ /**************************************************************************
+ PROCESSING OF THE RIGHT CHANNEL
+ ***************************************************************************/
+ /* ynR=A2 * x(n-2)R */
+ ynR = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[3];
+
+ /* ynR+=A1* x(n-1)R */
+ ynR += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[1];
+
+ /* ynR+=A0* x(n)R */
+ ynR += (LVM_FLOAT)pBiquadState->coefs[2] * (*(pDataIn+1));
+
+ /* ynR+=-B2 * y(n-2)R */
+ ynR += pBiquadState->pDelays[7] * pBiquadState->coefs[3];
+
+ /* ynR+=-B1 * y(n-1)R */
+ ynR += pBiquadState->pDelays[5] * pBiquadState->coefs[4];
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[7] = pBiquadState->pDelays[5]; /* y(n-2)R=y(n-1)R*/
+ pBiquadState->pDelays[6] = pBiquadState->pDelays[4]; /* y(n-2)L=y(n-1)L*/
+ pBiquadState->pDelays[3] = pBiquadState->pDelays[1]; /* x(n-2)R=x(n-1)R*/
+ pBiquadState->pDelays[2] = pBiquadState->pDelays[0]; /* x(n-2)L=x(n-1)L*/
+ pBiquadState->pDelays[5] = ynR; /* Update y(n-1)R */
+ pBiquadState->pDelays[4] = ynL; /* Update y(n-1)L */
+ pBiquadState->pDelays[0] = (*pDataIn); /* Update x(n-1)L */
+ pDataIn++;
+ pBiquadState->pDelays[1] = (*pDataIn); /* Update x(n-1)R */
+ pDataIn++;
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+ *pDataOut = (LVM_FLOAT)(ynL); /* Write Left output */
+ pDataOut++;
+ *pDataOut = (LVM_FLOAT)(ynR); /* Write Right ouput */
+ pDataOut++;
+ }
+ }
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32C14_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32C14_TRC_WRA_01.c
deleted file mode 100644
index cf19e06..0000000
--- a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32C14_TRC_WRA_01.c
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BIQUAD.h"
-#include "BQ_2I_D16F32Css_TRC_WRA_01_Private.h"
-#include "LVM_Macros.h"
-
-/**************************************************************************
- ASSUMPTIONS:
- COEFS-
- pBiquadState->coefs[0] is A2, pBiquadState->coefs[1] is A1
- pBiquadState->coefs[2] is A0, pBiquadState->coefs[3] is -B2
- pBiquadState->coefs[4] is -B1, these are in Q14 format
-
- DELAYS-
- pBiquadState->pDelays[0] is x(n-1)L in Q0 format
- pBiquadState->pDelays[1] is x(n-1)R in Q0 format
- pBiquadState->pDelays[2] is x(n-2)L in Q0 format
- pBiquadState->pDelays[3] is x(n-2)R in Q0 format
- pBiquadState->pDelays[4] is y(n-1)L in Q16 format
- pBiquadState->pDelays[5] is y(n-1)R in Q16 format
- pBiquadState->pDelays[6] is y(n-2)L in Q16 format
- pBiquadState->pDelays[7] is y(n-2)R in Q16 format
-***************************************************************************/
-#ifdef BUILD_FLOAT
-void BQ_2I_D16F32C14_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
- LVM_FLOAT *pDataIn,
- LVM_FLOAT *pDataOut,
- LVM_INT16 NrSamples)
- {
- LVM_FLOAT ynL,ynR;
- LVM_INT16 ii;
- PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
-
- for (ii = NrSamples; ii != 0; ii--)
- {
-
-
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
- /* ynL=A2 * x(n-2)L */
- ynL = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[2];
-
- /* ynL+=A1 * x(n-1)L */
- ynL += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[0];
-
- /* ynL+=A0 * x(n)L */
- ynL += (LVM_FLOAT)pBiquadState->coefs[2] * (*pDataIn);
-
- /* ynL+= ( (-B2 * y(n-2)L ))*/
- ynL += pBiquadState->pDelays[6] * pBiquadState->coefs[3];
-
-
- /* ynL+=( (-B1 * y(n-1)L )) */
- ynL += pBiquadState->pDelays[4] * pBiquadState->coefs[4];
-
- /**************************************************************************
- PROCESSING OF THE RIGHT CHANNEL
- ***************************************************************************/
- /* ynR=A2 * x(n-2)R */
- ynR = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[3];
-
- /* ynR+=A1 * x(n-1)R */
- ynR += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[1];
-
- /* ynR+=A0 * x(n)R */
- ynR += (LVM_FLOAT)pBiquadState->coefs[2] * (*(pDataIn+1));
-
- /* ynR+= ( (-B2 * y(n-2)R ))*/
- ynR += pBiquadState->pDelays[7] * pBiquadState->coefs[3];
-
- /* ynR+=( (-B1 * y(n-1)R )) */
- ynR += pBiquadState->pDelays[5] * pBiquadState->coefs[4];
-
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[7] = pBiquadState->pDelays[5]; /* y(n-2)R=y(n-1)R*/
- pBiquadState->pDelays[6] = pBiquadState->pDelays[4]; /* y(n-2)L=y(n-1)L*/
- pBiquadState->pDelays[3] = pBiquadState->pDelays[1]; /* x(n-2)R=x(n-1)R*/
- pBiquadState->pDelays[2] = pBiquadState->pDelays[0]; /* x(n-2)L=x(n-1)L*/
- pBiquadState->pDelays[5] = ynR; /* Update y(n-1)R */
- pBiquadState->pDelays[4] = ynL; /* Update y(n-1)L */
- pBiquadState->pDelays[0] = (*pDataIn); /* Update x(n-1)L */
- pDataIn++;
- pBiquadState->pDelays[1] = (*pDataIn); /* Update x(n-1)R */
- pDataIn++;
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut = (LVM_FLOAT)(ynL); /* Write Left output */
- pDataOut++;
- *pDataOut = (LVM_FLOAT)(ynR); /* Write Right ouput */
- pDataOut++;
- }
-
- }
-#else
-void BQ_2I_D16F32C14_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
- LVM_INT16 *pDataIn,
- LVM_INT16 *pDataOut,
- LVM_INT16 NrSamples)
- {
- LVM_INT32 ynL,ynR,templ;
- LVM_INT16 ii;
- PFilter_State pBiquadState = (PFilter_State) pInstance;
-
- for (ii = NrSamples; ii != 0; ii--)
- {
-
-
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
- /* ynL=A2 (Q14) * x(n-2)L (Q0) in Q14*/
- ynL=(LVM_INT32)pBiquadState->coefs[0]* pBiquadState->pDelays[2];
-
- /* ynL+=A1 (Q14) * x(n-1)L (Q0) in Q14*/
- ynL+=(LVM_INT32)pBiquadState->coefs[1]* pBiquadState->pDelays[0];
-
- /* ynL+=A0 (Q14) * x(n)L (Q0) in Q14*/
- ynL+=(LVM_INT32)pBiquadState->coefs[2]* (*pDataIn);
-
- /* ynL+= ( (-B2 (Q14) * y(n-2)L (Q16) )>>16) in Q14 */
- MUL32x16INTO32(pBiquadState->pDelays[6],pBiquadState->coefs[3],templ,16)
- ynL+=templ;
-
- /* ynL+=( (-B1 (Q14) * y(n-1)L (Q16) )>>16) in Q14 */
- MUL32x16INTO32(pBiquadState->pDelays[4],pBiquadState->coefs[4],templ,16)
- ynL+=templ;
-
- /**************************************************************************
- PROCESSING OF THE RIGHT CHANNEL
- ***************************************************************************/
- /* ynR=A2 (Q14) * x(n-2)R (Q0) in Q14*/
- ynR=(LVM_INT32)pBiquadState->coefs[0]*pBiquadState->pDelays[3];
-
- /* ynR+=A1 (Q14) * x(n-1)R (Q0) in Q14*/
- ynR+=(LVM_INT32)pBiquadState->coefs[1]*pBiquadState->pDelays[1];
-
- /* ynR+=A0 (Q14) * x(n)R (Q0) in Q14*/
- ynR+=(LVM_INT32)pBiquadState->coefs[2]*(*(pDataIn+1));
-
- /* ynR+= ( (-B2 (Q14) * y(n-2)R (Q16) )>>16) in Q14*/
- MUL32x16INTO32(pBiquadState->pDelays[7],pBiquadState->coefs[3],templ,16)
- ynR+=templ;
-
- /* ynR+=( (-B1 (Q14) * y(n-1)R (Q16) )>>16) in Q14 */
- MUL32x16INTO32(pBiquadState->pDelays[5],pBiquadState->coefs[4],templ,16)
- ynR+=templ;
-
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[7]=pBiquadState->pDelays[5]; /* y(n-2)R=y(n-1)R*/
- pBiquadState->pDelays[6]=pBiquadState->pDelays[4]; /* y(n-2)L=y(n-1)L*/
- pBiquadState->pDelays[3]=pBiquadState->pDelays[1]; /* x(n-2)R=x(n-1)R*/
- pBiquadState->pDelays[2]=pBiquadState->pDelays[0]; /* x(n-2)L=x(n-1)L*/
- pBiquadState->pDelays[5]=ynR<<2; /* Update y(n-1)R in Q16*/
- pBiquadState->pDelays[4]=ynL<<2; /* Update y(n-1)L in Q16*/
- pBiquadState->pDelays[0]=(*pDataIn); /* Update x(n-1)L in Q0*/
- pDataIn++;
- pBiquadState->pDelays[1]=(*pDataIn); /* Update x(n-1)R in Q0*/
- pDataIn++;
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut=(LVM_INT16)(ynL>>14); /* Write Left output in Q0*/
- pDataOut++;
- *pDataOut=(LVM_INT16)(ynR>>14); /* Write Right ouput in Q0*/
- pDataOut++;
- }
-
- }
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32C14_TRC_WRA_01.cpp b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32C14_TRC_WRA_01.cpp
new file mode 100644
index 0000000..3a396df
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32C14_TRC_WRA_01.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BIQUAD.h"
+#include "BQ_2I_D16F32Css_TRC_WRA_01_Private.h"
+#include "LVM_Macros.h"
+
+/**************************************************************************
+ ASSUMPTIONS:
+ COEFS-
+ pBiquadState->coefs[0] is A2, pBiquadState->coefs[1] is A1
+ pBiquadState->coefs[2] is A0, pBiquadState->coefs[3] is -B2
+ pBiquadState->coefs[4] is -B1, these are in Q14 format
+
+ DELAYS-
+ pBiquadState->pDelays[0] is x(n-1)L in Q0 format
+ pBiquadState->pDelays[1] is x(n-1)R in Q0 format
+ pBiquadState->pDelays[2] is x(n-2)L in Q0 format
+ pBiquadState->pDelays[3] is x(n-2)R in Q0 format
+ pBiquadState->pDelays[4] is y(n-1)L in Q16 format
+ pBiquadState->pDelays[5] is y(n-1)R in Q16 format
+ pBiquadState->pDelays[6] is y(n-2)L in Q16 format
+ pBiquadState->pDelays[7] is y(n-2)R in Q16 format
+***************************************************************************/
+void BQ_2I_D16F32C14_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+ {
+ LVM_FLOAT ynL,ynR;
+ LVM_INT16 ii;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+
+ for (ii = NrSamples; ii != 0; ii--)
+ {
+
+ /**************************************************************************
+ PROCESSING OF THE LEFT CHANNEL
+ ***************************************************************************/
+ /* ynL=A2 * x(n-2)L */
+ ynL = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[2];
+
+ /* ynL+=A1 * x(n-1)L */
+ ynL += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[0];
+
+ /* ynL+=A0 * x(n)L */
+ ynL += (LVM_FLOAT)pBiquadState->coefs[2] * (*pDataIn);
+
+ /* ynL+= ( (-B2 * y(n-2)L ))*/
+ ynL += pBiquadState->pDelays[6] * pBiquadState->coefs[3];
+
+ /* ynL+=( (-B1 * y(n-1)L )) */
+ ynL += pBiquadState->pDelays[4] * pBiquadState->coefs[4];
+
+ /**************************************************************************
+ PROCESSING OF THE RIGHT CHANNEL
+ ***************************************************************************/
+ /* ynR=A2 * x(n-2)R */
+ ynR = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[3];
+
+ /* ynR+=A1 * x(n-1)R */
+ ynR += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[1];
+
+ /* ynR+=A0 * x(n)R */
+ ynR += (LVM_FLOAT)pBiquadState->coefs[2] * (*(pDataIn+1));
+
+ /* ynR+= ( (-B2 * y(n-2)R ))*/
+ ynR += pBiquadState->pDelays[7] * pBiquadState->coefs[3];
+
+ /* ynR+=( (-B1 * y(n-1)R )) */
+ ynR += pBiquadState->pDelays[5] * pBiquadState->coefs[4];
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[7] = pBiquadState->pDelays[5]; /* y(n-2)R=y(n-1)R*/
+ pBiquadState->pDelays[6] = pBiquadState->pDelays[4]; /* y(n-2)L=y(n-1)L*/
+ pBiquadState->pDelays[3] = pBiquadState->pDelays[1]; /* x(n-2)R=x(n-1)R*/
+ pBiquadState->pDelays[2] = pBiquadState->pDelays[0]; /* x(n-2)L=x(n-1)L*/
+ pBiquadState->pDelays[5] = ynR; /* Update y(n-1)R */
+ pBiquadState->pDelays[4] = ynL; /* Update y(n-1)L */
+ pBiquadState->pDelays[0] = (*pDataIn); /* Update x(n-1)L */
+ pDataIn++;
+ pBiquadState->pDelays[1] = (*pDataIn); /* Update x(n-1)R */
+ pDataIn++;
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+ *pDataOut = (LVM_FLOAT)(ynL); /* Write Left output */
+ pDataOut++;
+ *pDataOut = (LVM_FLOAT)(ynR); /* Write Right ouput */
+ pDataOut++;
+ }
+
+ }
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32C15_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32C15_TRC_WRA_01.c
deleted file mode 100644
index 2611b19..0000000
--- a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32C15_TRC_WRA_01.c
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BIQUAD.h"
-#include "BQ_2I_D16F32Css_TRC_WRA_01_Private.h"
-#include "LVM_Macros.h"
-
-/**************************************************************************
- ASSUMPTIONS:
- COEFS-
- pBiquadState->coefs[0] is A2, pBiquadState->coefs[1] is A1
- pBiquadState->coefs[2] is A0, pBiquadState->coefs[3] is -B2
- pBiquadState->coefs[4] is -B1, these are in Q15 format
-
- DELAYS-
- pBiquadState->pDelays[0] is x(n-1)L in Q0 format
- pBiquadState->pDelays[1] is x(n-1)R in Q0 format
- pBiquadState->pDelays[2] is x(n-2)L in Q0 format
- pBiquadState->pDelays[3] is x(n-2)R in Q0 format
- pBiquadState->pDelays[4] is y(n-1)L in Q16 format
- pBiquadState->pDelays[5] is y(n-1)R in Q16 format
- pBiquadState->pDelays[6] is y(n-2)L in Q16 format
- pBiquadState->pDelays[7] is y(n-2)R in Q16 format
-***************************************************************************/
-#ifdef BUILD_FLOAT
-void BQ_2I_D16F32C15_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
- LVM_FLOAT *pDataIn,
- LVM_FLOAT *pDataOut,
- LVM_INT16 NrSamples)
- {
- LVM_FLOAT ynL,ynR;
- LVM_INT16 ii;
- PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
-
- for (ii = NrSamples; ii != 0; ii--)
- {
-
-
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
- /* ynL=A2 * x(n-2)L */
- ynL = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[2];
-
- /* ynL+=A1 * x(n-1)L */
- ynL += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[0];
-
- /* ynL+=A0 * x(n)L */
- ynL += (LVM_FLOAT)pBiquadState->coefs[2] * (*pDataIn);
-
- /* ynL+= ( (-B2 * y(n-2)L ) */
- ynL += pBiquadState->pDelays[6] * pBiquadState->coefs[3];
-
-
- /* ynL+=( (-B1 * y(n-1)L )) */
- ynL += pBiquadState->pDelays[4] * pBiquadState->coefs[4];
-
-
- /**************************************************************************
- PROCESSING OF THE RIGHT CHANNEL
- ***************************************************************************/
- /* ynR=A2 * x(n-2)R */
- ynR = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[3];
-
- /* ynR+=A1 * x(n-1)R */
- ynR += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[1];
-
- /* ynR+=A0 * x(n)R */
- ynR += (LVM_FLOAT)pBiquadState->coefs[2] * (*(pDataIn+1));
-
- /* ynR+= ( (-B2 * y(n-2)R ) */
- ynR += pBiquadState->pDelays[7] * pBiquadState->coefs[3];
-
-
- /* ynR+=( (-B1 * y(n-1)R )) in Q15 */
- ynR += pBiquadState->pDelays[5] * pBiquadState->coefs[4];
-
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[7] = pBiquadState->pDelays[5]; /* y(n-2)R=y(n-1)R*/
- pBiquadState->pDelays[6] = pBiquadState->pDelays[4]; /* y(n-2)L=y(n-1)L*/
- pBiquadState->pDelays[3] = pBiquadState->pDelays[1]; /* x(n-2)R=x(n-1)R*/
- pBiquadState->pDelays[2] = pBiquadState->pDelays[0]; /* x(n-2)L=x(n-1)L*/
- pBiquadState->pDelays[5] = ynR; /* Update y(n-1)R*/
- pBiquadState->pDelays[4] = ynL; /* Update y(n-1)L*/
- pBiquadState->pDelays[0] = (*pDataIn); /* Update x(n-1)L*/
- pDataIn++;
- pBiquadState->pDelays[1] = (*pDataIn); /* Update x(n-1)R*/
- pDataIn++;
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut = (LVM_FLOAT)(ynL); /* Write Left output*/
- pDataOut++;
- *pDataOut = (LVM_FLOAT)(ynR); /* Write Right ouput*/
- pDataOut++;
- }
-
- }
-#else
-void BQ_2I_D16F32C15_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
- LVM_INT16 *pDataIn,
- LVM_INT16 *pDataOut,
- LVM_INT16 NrSamples)
- {
- LVM_INT32 ynL,ynR,templ;
- LVM_INT16 ii;
- PFilter_State pBiquadState = (PFilter_State) pInstance;
-
- for (ii = NrSamples; ii != 0; ii--)
- {
-
-
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
- /* ynL=A2 (Q15) * x(n-2)L (Q0) in Q15*/
- ynL=(LVM_INT32)pBiquadState->coefs[0]* pBiquadState->pDelays[2];
-
- /* ynL+=A1 (Q15) * x(n-1)L (Q0) in Q15*/
- ynL+=(LVM_INT32)pBiquadState->coefs[1]* pBiquadState->pDelays[0];
-
- /* ynL+=A0 (Q15) * x(n)L (Q0) in Q15*/
- ynL+=(LVM_INT32)pBiquadState->coefs[2]* (*pDataIn);
-
- /* ynL+= ( (-B2 (Q15) * y(n-2)L (Q16) )>>16) in Q15 */
- MUL32x16INTO32(pBiquadState->pDelays[6],pBiquadState->coefs[3],templ,16)
- ynL+=templ;
-
- /* ynL+=( (-B1 (Q15) * y(n-1)L (Q16) )>>16) in Q15 */
- MUL32x16INTO32(pBiquadState->pDelays[4],pBiquadState->coefs[4],templ,16)
- ynL+=templ;
-
- /**************************************************************************
- PROCESSING OF THE RIGHT CHANNEL
- ***************************************************************************/
- /* ynR=A2 (Q15) * x(n-2)R (Q0) in Q15*/
- ynR=(LVM_INT32)pBiquadState->coefs[0]*pBiquadState->pDelays[3];
-
- /* ynR+=A1 (Q15) * x(n-1)R (Q0) in Q15*/
- ynR+=(LVM_INT32)pBiquadState->coefs[1]*pBiquadState->pDelays[1];
-
- /* ynR+=A0 (Q15) * x(n)R (Q0) in Q15*/
- ynR+=(LVM_INT32)pBiquadState->coefs[2]*(*(pDataIn+1));
-
- /* ynR+= ( (-B2 (Q15) * y(n-2)R (Q16) )>>16) in Q15 */
- MUL32x16INTO32(pBiquadState->pDelays[7],pBiquadState->coefs[3],templ,16)
- ynR+=templ;
-
- /* ynR+=( (-B1 (Q15) * y(n-1)R (Q16) )>>16) in Q15 */
- MUL32x16INTO32(pBiquadState->pDelays[5],pBiquadState->coefs[4],templ,16)
- ynR+=templ;
-
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[7]=pBiquadState->pDelays[5]; /* y(n-2)R=y(n-1)R*/
- pBiquadState->pDelays[6]=pBiquadState->pDelays[4]; /* y(n-2)L=y(n-1)L*/
- pBiquadState->pDelays[3]=pBiquadState->pDelays[1]; /* x(n-2)R=x(n-1)R*/
- pBiquadState->pDelays[2]=pBiquadState->pDelays[0]; /* x(n-2)L=x(n-1)L*/
- pBiquadState->pDelays[5]=ynR<<1; /* Update y(n-1)R in Q16*/
- pBiquadState->pDelays[4]=ynL<<1; /* Update y(n-1)L in Q16*/
- pBiquadState->pDelays[0]=(*pDataIn); /* Update x(n-1)L in Q0*/
- pDataIn++;
- pBiquadState->pDelays[1]=(*pDataIn); /* Update x(n-1)R in Q0*/
- pDataIn++;
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut=(LVM_INT16)(ynL>>15); /* Write Left output in Q0*/
- pDataOut++;
- *pDataOut=(LVM_INT16)(ynR>>15); /* Write Right ouput in Q0*/
- pDataOut++;
- }
-
- }
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32C15_TRC_WRA_01.cpp b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32C15_TRC_WRA_01.cpp
new file mode 100644
index 0000000..1cbff1a
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32C15_TRC_WRA_01.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BIQUAD.h"
+#include "BQ_2I_D16F32Css_TRC_WRA_01_Private.h"
+#include "LVM_Macros.h"
+
+/**************************************************************************
+ ASSUMPTIONS:
+ COEFS-
+ pBiquadState->coefs[0] is A2, pBiquadState->coefs[1] is A1
+ pBiquadState->coefs[2] is A0, pBiquadState->coefs[3] is -B2
+ pBiquadState->coefs[4] is -B1, these are in Q15 format
+
+ DELAYS-
+ pBiquadState->pDelays[0] is x(n-1)L in Q0 format
+ pBiquadState->pDelays[1] is x(n-1)R in Q0 format
+ pBiquadState->pDelays[2] is x(n-2)L in Q0 format
+ pBiquadState->pDelays[3] is x(n-2)R in Q0 format
+ pBiquadState->pDelays[4] is y(n-1)L in Q16 format
+ pBiquadState->pDelays[5] is y(n-1)R in Q16 format
+ pBiquadState->pDelays[6] is y(n-2)L in Q16 format
+ pBiquadState->pDelays[7] is y(n-2)R in Q16 format
+***************************************************************************/
+void BQ_2I_D16F32C15_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+ {
+ LVM_FLOAT ynL,ynR;
+ LVM_INT16 ii;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+
+ for (ii = NrSamples; ii != 0; ii--)
+ {
+
+ /**************************************************************************
+ PROCESSING OF THE LEFT CHANNEL
+ ***************************************************************************/
+ /* ynL=A2 * x(n-2)L */
+ ynL = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[2];
+
+ /* ynL+=A1 * x(n-1)L */
+ ynL += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[0];
+
+ /* ynL+=A0 * x(n)L */
+ ynL += (LVM_FLOAT)pBiquadState->coefs[2] * (*pDataIn);
+
+ /* ynL+= ( (-B2 * y(n-2)L ) */
+ ynL += pBiquadState->pDelays[6] * pBiquadState->coefs[3];
+
+ /* ynL+=( (-B1 * y(n-1)L )) */
+ ynL += pBiquadState->pDelays[4] * pBiquadState->coefs[4];
+
+ /**************************************************************************
+ PROCESSING OF THE RIGHT CHANNEL
+ ***************************************************************************/
+ /* ynR=A2 * x(n-2)R */
+ ynR = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[3];
+
+ /* ynR+=A1 * x(n-1)R */
+ ynR += (LVM_FLOAT)pBiquadState->coefs[1] * pBiquadState->pDelays[1];
+
+ /* ynR+=A0 * x(n)R */
+ ynR += (LVM_FLOAT)pBiquadState->coefs[2] * (*(pDataIn+1));
+
+ /* ynR+= ( (-B2 * y(n-2)R ) */
+ ynR += pBiquadState->pDelays[7] * pBiquadState->coefs[3];
+
+ /* ynR+=( (-B1 * y(n-1)R )) in Q15 */
+ ynR += pBiquadState->pDelays[5] * pBiquadState->coefs[4];
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[7] = pBiquadState->pDelays[5]; /* y(n-2)R=y(n-1)R*/
+ pBiquadState->pDelays[6] = pBiquadState->pDelays[4]; /* y(n-2)L=y(n-1)L*/
+ pBiquadState->pDelays[3] = pBiquadState->pDelays[1]; /* x(n-2)R=x(n-1)R*/
+ pBiquadState->pDelays[2] = pBiquadState->pDelays[0]; /* x(n-2)L=x(n-1)L*/
+ pBiquadState->pDelays[5] = ynR; /* Update y(n-1)R*/
+ pBiquadState->pDelays[4] = ynL; /* Update y(n-1)L*/
+ pBiquadState->pDelays[0] = (*pDataIn); /* Update x(n-1)L*/
+ pDataIn++;
+ pBiquadState->pDelays[1] = (*pDataIn); /* Update x(n-1)R*/
+ pDataIn++;
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+ *pDataOut = (LVM_FLOAT)(ynL); /* Write Left output*/
+ pDataOut++;
+ *pDataOut = (LVM_FLOAT)(ynR); /* Write Right ouput*/
+ pDataOut++;
+ }
+
+ }
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32Css_TRC_WRA_01_Private.h b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32Css_TRC_WRA_01_Private.h
index c0319c9..314388a 100644
--- a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32Css_TRC_WRA_01_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32Css_TRC_WRA_01_Private.h
@@ -28,7 +28,6 @@
typedef Filter_State * PFilter_State ;
-#ifdef BUILD_FLOAT
typedef struct _Filter_State_FLOAT
{
LVM_FLOAT * pDelays; /* pointer to the delayed samples \
@@ -36,6 +35,5 @@
LVM_FLOAT coefs[5]; /* pointer to the filter coefficients */
}Filter_State_FLOAT;
typedef Filter_State_FLOAT * PFilter_State_FLOAT ;
-#endif
#endif /* _BQ_2I_D16F32CSS_TRC_WRA_01_PRIVATE_H_ */
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32Css_TRC_WRA_01_init.c b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32Css_TRC_WRA_01_init.c
deleted file mode 100644
index 4d9bbfe..0000000
--- a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32Css_TRC_WRA_01_init.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BIQUAD.h"
-#include "BQ_2I_D16F32Css_TRC_WRA_01_Private.h"
-
-
-/*-------------------------------------------------------------------------*/
-/* FUNCTION: */
-/* BQ_2I_D16F32Css_TRC_WRA_01_Init */
-/* */
-/* DESCRIPTION: */
-/* These functions initializes a BIQUAD filter defined as a cascade of */
-/* biquadratic Filter Sections. */
-/* */
-/* PARAMETERS: */
-/* pInstance - output, returns the pointer to the State Variable */
-/* This state pointer must be passed to any subsequent */
-/* call to "Biquad" functions. */
-/* pTaps - input, pointer to the taps memory */
-/* pCoef - input, pointer to the coefficient structure */
-/* N - M coefficient factor of QM.N */
-/* RETURNS: */
-/* void return code */
-/*-------------------------------------------------------------------------*/
-#ifdef BUILD_FLOAT
-void BQ_2I_D16F32Css_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
- Biquad_2I_Order2_FLOAT_Taps_t *pTaps,
- BQ_FLOAT_Coefs_t *pCoef)
-{
- LVM_FLOAT temp;
- PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
- pBiquadState->pDelays = (LVM_FLOAT *) pTaps;
- temp = pCoef->A2;
- pBiquadState->coefs[0] = temp;
- temp = pCoef->A1;
- pBiquadState->coefs[1] = temp;
- temp = pCoef->A0;
- pBiquadState->coefs[2] = temp;
- temp = pCoef->B2;
- pBiquadState->coefs[3] = temp;
- temp = pCoef->B1;
- pBiquadState->coefs[4] = temp;
-}
-#else
-void BQ_2I_D16F32Css_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
- Biquad_2I_Order2_Taps_t *pTaps,
- BQ_C16_Coefs_t *pCoef)
-{
- LVM_INT16 temp;
- PFilter_State pBiquadState = (PFilter_State) pInstance;
- pBiquadState->pDelays =(LVM_INT32 *) pTaps ;
-
- temp=pCoef->A2;
- pBiquadState->coefs[0]=temp;
- temp=pCoef->A1;
- pBiquadState->coefs[1]=temp;
- temp=pCoef->A0;
- pBiquadState->coefs[2]=temp;
- temp=pCoef->B2;
- pBiquadState->coefs[3]=temp;
- temp=pCoef->B1;
- pBiquadState->coefs[4]=temp;
-}
-#endif
-/*-------------------------------------------------------------------------*/
-/* End Of File: BQ_2I_D16F32Css_TRC_WRA_01_Init */
-
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32Css_TRC_WRA_01_init.cpp b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32Css_TRC_WRA_01_init.cpp
new file mode 100644
index 0000000..058541a
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/BQ_2I_D16F32Css_TRC_WRA_01_init.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BIQUAD.h"
+#include "BQ_2I_D16F32Css_TRC_WRA_01_Private.h"
+
+/*-------------------------------------------------------------------------*/
+/* FUNCTION: */
+/* BQ_2I_D16F32Css_TRC_WRA_01_Init */
+/* */
+/* DESCRIPTION: */
+/* These functions initializes a BIQUAD filter defined as a cascade of */
+/* biquadratic Filter Sections. */
+/* */
+/* PARAMETERS: */
+/* pInstance - output, returns the pointer to the State Variable */
+/* This state pointer must be passed to any subsequent */
+/* call to "Biquad" functions. */
+/* pTaps - input, pointer to the taps memory */
+/* pCoef - input, pointer to the coefficient structure */
+/* N - M coefficient factor of QM.N */
+/* RETURNS: */
+/* void return code */
+/*-------------------------------------------------------------------------*/
+void BQ_2I_D16F32Css_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_2I_Order2_FLOAT_Taps_t *pTaps,
+ BQ_FLOAT_Coefs_t *pCoef)
+{
+ LVM_FLOAT temp;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+ pBiquadState->pDelays = (LVM_FLOAT *) pTaps;
+ temp = pCoef->A2;
+ pBiquadState->coefs[0] = temp;
+ temp = pCoef->A1;
+ pBiquadState->coefs[1] = temp;
+ temp = pCoef->A0;
+ pBiquadState->coefs[2] = temp;
+ temp = pCoef->B2;
+ pBiquadState->coefs[3] = temp;
+ temp = pCoef->B1;
+ pBiquadState->coefs[4] = temp;
+}
+/*-------------------------------------------------------------------------*/
+/* End Of File: BQ_2I_D16F32Css_TRC_WRA_01_Init */
+
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32C30_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32C30_TRC_WRA_01.c
deleted file mode 100644
index d63365c..0000000
--- a/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32C30_TRC_WRA_01.c
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BIQUAD.h"
-#include "BQ_2I_D32F32Cll_TRC_WRA_01_Private.h"
-#include "LVM_Macros.h"
-
-/**************************************************************************
- ASSUMPTIONS:
- COEFS-
- pBiquadState->coefs[0] is A2, pBiquadState->coefs[1] is A1
- pBiquadState->coefs[2] is A0, pBiquadState->coefs[3] is -B2
- pBiquadState->coefs[4] is -B1, these are in Q30 format
-
- DELAYS-
- pBiquadState->pDelays[0] is x(n-1)L in Q0 format
- pBiquadState->pDelays[1] is x(n-1)R in Q0 format
- pBiquadState->pDelays[2] is x(n-2)L in Q0 format
- pBiquadState->pDelays[3] is x(n-2)R in Q0 format
- pBiquadState->pDelays[4] is y(n-1)L in Q0 format
- pBiquadState->pDelays[5] is y(n-1)R in Q0 format
- pBiquadState->pDelays[6] is y(n-2)L in Q0 format
- pBiquadState->pDelays[7] is y(n-2)R in Q0 format
-***************************************************************************/
-#ifdef BUILD_FLOAT
-void BQ_2I_D32F32C30_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
- LVM_FLOAT *pDataIn,
- LVM_FLOAT *pDataOut,
- LVM_INT16 NrSamples)
-
-
- {
- LVM_FLOAT ynL,ynR,templ,tempd;
- LVM_INT16 ii;
- PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
-
- for (ii = NrSamples; ii != 0; ii--)
- {
-
-
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
- /* ynL= ( A2 * x(n-2)L ) */
- ynL = pBiquadState->coefs[0] * pBiquadState->pDelays[2];
-
- /* ynL+= ( A1 * x(n-1)L )*/
- templ = pBiquadState->coefs[1] * pBiquadState->pDelays[0];
- ynL += templ;
-
- /* ynL+= ( A0 * x(n)L ) */
- templ = pBiquadState->coefs[2] * (*pDataIn);
- ynL += templ;
-
- /* ynL+= (-B2 * y(n-2)L ) */
- templ = pBiquadState->coefs[3] * pBiquadState->pDelays[6];
- ynL += templ;
-
- /* ynL+= (-B1 * y(n-1)L )*/
- templ = pBiquadState->coefs[4] * pBiquadState->pDelays[4];
- ynL += templ;
-
- /**************************************************************************
- PROCESSING OF THE RIGHT CHANNEL
- ***************************************************************************/
- /* ynR= ( A2 * x(n-2)R ) */
- ynR = pBiquadState->coefs[0] * pBiquadState->pDelays[3];
-
- /* ynR+= ( A1 * x(n-1)R ) */
- templ = pBiquadState->coefs[1] * pBiquadState->pDelays[1];
- ynR += templ;
-
- /* ynR+= ( A0 * x(n)R ) */
- tempd =* (pDataIn+1);
- templ = pBiquadState->coefs[2] * tempd;
- ynR += templ;
-
- /* ynR+= (-B2 * y(n-2)R ) */
- templ = pBiquadState->coefs[3] * pBiquadState->pDelays[7];
- ynR += templ;
-
- /* ynR+= (-B1 * y(n-1)R ) */
- templ = pBiquadState->coefs[4] * pBiquadState->pDelays[5];
- ynR += templ;
-
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[7] = pBiquadState->pDelays[5]; /* y(n-2)R=y(n-1)R*/
- pBiquadState->pDelays[6] = pBiquadState->pDelays[4]; /* y(n-2)L=y(n-1)L*/
- pBiquadState->pDelays[3] = pBiquadState->pDelays[1]; /* x(n-2)R=x(n-1)R*/
- pBiquadState->pDelays[2] = pBiquadState->pDelays[0]; /* x(n-2)L=x(n-1)L*/
- pBiquadState->pDelays[5] = (LVM_FLOAT)ynR; /* Update y(n-1)R */
- pBiquadState->pDelays[4] = (LVM_FLOAT)ynL; /* Update y(n-1)L */
- pBiquadState->pDelays[0] = (*pDataIn); /* Update x(n-1)L */
- pDataIn++;
- pBiquadState->pDelays[1] = (*pDataIn); /* Update x(n-1)R */
- pDataIn++;
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut = (LVM_FLOAT)ynL; /* Write Left output */
- pDataOut++;
- *pDataOut = (LVM_FLOAT)ynR; /* Write Right ouput */
- pDataOut++;
-
-
- }
-
- }
-
-#ifdef SUPPORT_MC
-/**************************************************************************
- ASSUMPTIONS:
- COEFS-
- pBiquadState->coefs[0] is A2, pBiquadState->coefs[1] is A1
- pBiquadState->coefs[2] is A0, pBiquadState->coefs[3] is -B2
- pBiquadState->coefs[4] is -B1
-
- DELAYS-
- pBiquadState->pDelays[0] to
- pBiquadState->pDelays[NrChannels - 1] is x(n-1) for all NrChannels
-
- pBiquadState->pDelays[NrChannels] to
- pBiquadState->pDelays[2*NrChannels - 1] is x(n-2) for all NrChannels
-
- pBiquadState->pDelays[2*NrChannels] to
- pBiquadState->pDelays[3*NrChannels - 1] is y(n-1) for all NrChannels
-
- pBiquadState->pDelays[3*NrChannels] to
- pBiquadState->pDelays[4*NrChannels - 1] is y(n-2) for all NrChannels
-***************************************************************************/
-void BQ_MC_D32F32C30_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
- LVM_FLOAT *pDataIn,
- LVM_FLOAT *pDataOut,
- LVM_INT16 NrFrames,
- LVM_INT16 NrChannels)
-
-
- {
- LVM_FLOAT yn, temp;
- LVM_INT16 ii, jj;
- PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
-
- for (ii = NrFrames; ii != 0; ii--)
- {
- /**************************************************************************
- PROCESSING CHANNEL-WISE
- ***************************************************************************/
- for (jj = 0; jj < NrChannels; jj++)
- {
- /* yn= (A2 * x(n-2)) */
- yn = pBiquadState->coefs[0] * pBiquadState->pDelays[NrChannels + jj];
-
- /* yn+= (A1 * x(n-1)) */
- temp = pBiquadState->coefs[1] * pBiquadState->pDelays[jj];
- yn += temp;
-
- /* yn+= (A0 * x(n)) */
- temp = pBiquadState->coefs[2] * (*pDataIn);
- yn += temp;
-
- /* yn+= (-B2 * y(n-2)) */
- temp = pBiquadState->coefs[3] * pBiquadState->pDelays[NrChannels*3 + jj];
- yn += temp;
-
- /* yn+= (-B1 * y(n-1)) */
- temp = pBiquadState->coefs[4] * pBiquadState->pDelays[NrChannels*2 + jj];
- yn += temp;
-
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[NrChannels * 3 + jj] =
- pBiquadState->pDelays[NrChannels * 2 + jj]; /* y(n-2)=y(n-1)*/
- pBiquadState->pDelays[NrChannels * 1 + jj] =
- pBiquadState->pDelays[jj]; /* x(n-2)=x(n-1)*/
- pBiquadState->pDelays[NrChannels * 2 + jj] = (LVM_FLOAT)yn; /* Update y(n-1)*/
- pBiquadState->pDelays[jj] = (*pDataIn); /* Update x(n-1)*/
- pDataIn++;
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut = (LVM_FLOAT)yn; /* Write jj Channel output */
- pDataOut++;
- }
- }
-
- }
-#endif /*SUPPORT_MC*/
-
-#else
-void BQ_2I_D32F32C30_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
- LVM_INT32 *pDataIn,
- LVM_INT32 *pDataOut,
- LVM_INT16 NrSamples)
-
-
- {
- LVM_INT32 ynL,ynR,templ,tempd;
- LVM_INT16 ii;
- PFilter_State pBiquadState = (PFilter_State) pInstance;
-
- for (ii = NrSamples; ii != 0; ii--)
- {
-
-
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
- /* ynL= ( A2 (Q30) * x(n-2)L (Q0) ) >>30 in Q0*/
- MUL32x32INTO32(pBiquadState->coefs[0],pBiquadState->pDelays[2],ynL,30)
-
- /* ynL+= ( A1 (Q30) * x(n-1)L (Q0) ) >> 30 in Q0*/
- MUL32x32INTO32(pBiquadState->coefs[1],pBiquadState->pDelays[0],templ,30)
- ynL+=templ;
-
- /* ynL+= ( A0 (Q30) * x(n)L (Q0) ) >> 30 in Q0*/
- MUL32x32INTO32(pBiquadState->coefs[2],*pDataIn,templ,30)
- ynL+=templ;
-
- /* ynL+= (-B2 (Q30) * y(n-2)L (Q0) ) >> 30 in Q0*/
- MUL32x32INTO32(pBiquadState->coefs[3],pBiquadState->pDelays[6],templ,30)
- ynL+=templ;
-
- /* ynL+= (-B1 (Q30) * y(n-1)L (Q0) ) >> 30 in Q0 */
- MUL32x32INTO32(pBiquadState->coefs[4],pBiquadState->pDelays[4],templ,30)
- ynL+=templ;
-
- /**************************************************************************
- PROCESSING OF THE RIGHT CHANNEL
- ***************************************************************************/
- /* ynR= ( A2 (Q30) * x(n-2)R (Q0) ) >> 30 in Q0*/
- MUL32x32INTO32(pBiquadState->coefs[0],pBiquadState->pDelays[3],ynR,30)
-
- /* ynR+= ( A1 (Q30) * x(n-1)R (Q0) ) >> 30 in Q0*/
- MUL32x32INTO32(pBiquadState->coefs[1],pBiquadState->pDelays[1],templ,30)
- ynR+=templ;
-
- /* ynR+= ( A0 (Q30) * x(n)R (Q0) ) >> 30 in Q0*/
- tempd=*(pDataIn+1);
- MUL32x32INTO32(pBiquadState->coefs[2],tempd,templ,30)
- ynR+=templ;
-
- /* ynR+= (-B2 (Q30) * y(n-2)R (Q0) ) >> 30 in Q0*/
- MUL32x32INTO32(pBiquadState->coefs[3],pBiquadState->pDelays[7],templ,30)
- ynR+=templ;
-
- /* ynR+= (-B1 (Q30) * y(n-1)R (Q0) ) >> 30 in Q0 */
- MUL32x32INTO32(pBiquadState->coefs[4],pBiquadState->pDelays[5],templ,30)
- ynR+=templ;
-
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[7]=pBiquadState->pDelays[5]; /* y(n-2)R=y(n-1)R*/
- pBiquadState->pDelays[6]=pBiquadState->pDelays[4]; /* y(n-2)L=y(n-1)L*/
- pBiquadState->pDelays[3]=pBiquadState->pDelays[1]; /* x(n-2)R=x(n-1)R*/
- pBiquadState->pDelays[2]=pBiquadState->pDelays[0]; /* x(n-2)L=x(n-1)L*/
- pBiquadState->pDelays[5]=(LVM_INT32)ynR; /* Update y(n-1)R in Q0*/
- pBiquadState->pDelays[4]=(LVM_INT32)ynL; /* Update y(n-1)L in Q0*/
- pBiquadState->pDelays[0]=(*pDataIn); /* Update x(n-1)L in Q0*/
- pDataIn++;
- pBiquadState->pDelays[1]=(*pDataIn); /* Update x(n-1)R in Q0*/
- pDataIn++;
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut=(LVM_INT32)ynL; /* Write Left output in Q0*/
- pDataOut++;
- *pDataOut=(LVM_INT32)ynR; /* Write Right ouput in Q0*/
- pDataOut++;
-
-
- }
-
- }
-#endif /*BUILD_FLOAT*/
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32C30_TRC_WRA_01.cpp b/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32C30_TRC_WRA_01.cpp
new file mode 100644
index 0000000..78d1ba1
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32C30_TRC_WRA_01.cpp
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BIQUAD.h"
+#include "BQ_2I_D32F32Cll_TRC_WRA_01_Private.h"
+#include "LVM_Macros.h"
+
+/**************************************************************************
+ ASSUMPTIONS:
+ COEFS-
+ pBiquadState->coefs[0] is A2, pBiquadState->coefs[1] is A1
+ pBiquadState->coefs[2] is A0, pBiquadState->coefs[3] is -B2
+ pBiquadState->coefs[4] is -B1, these are in Q30 format
+
+ DELAYS-
+ pBiquadState->pDelays[0] is x(n-1)L in Q0 format
+ pBiquadState->pDelays[1] is x(n-1)R in Q0 format
+ pBiquadState->pDelays[2] is x(n-2)L in Q0 format
+ pBiquadState->pDelays[3] is x(n-2)R in Q0 format
+ pBiquadState->pDelays[4] is y(n-1)L in Q0 format
+ pBiquadState->pDelays[5] is y(n-1)R in Q0 format
+ pBiquadState->pDelays[6] is y(n-2)L in Q0 format
+ pBiquadState->pDelays[7] is y(n-2)R in Q0 format
+***************************************************************************/
+void BQ_2I_D32F32C30_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+
+ {
+ LVM_FLOAT ynL,ynR,templ,tempd;
+ LVM_INT16 ii;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+
+ for (ii = NrSamples; ii != 0; ii--)
+ {
+
+ /**************************************************************************
+ PROCESSING OF THE LEFT CHANNEL
+ ***************************************************************************/
+ /* ynL= ( A2 * x(n-2)L ) */
+ ynL = pBiquadState->coefs[0] * pBiquadState->pDelays[2];
+
+ /* ynL+= ( A1 * x(n-1)L )*/
+ templ = pBiquadState->coefs[1] * pBiquadState->pDelays[0];
+ ynL += templ;
+
+ /* ynL+= ( A0 * x(n)L ) */
+ templ = pBiquadState->coefs[2] * (*pDataIn);
+ ynL += templ;
+
+ /* ynL+= (-B2 * y(n-2)L ) */
+ templ = pBiquadState->coefs[3] * pBiquadState->pDelays[6];
+ ynL += templ;
+
+ /* ynL+= (-B1 * y(n-1)L )*/
+ templ = pBiquadState->coefs[4] * pBiquadState->pDelays[4];
+ ynL += templ;
+
+ /**************************************************************************
+ PROCESSING OF THE RIGHT CHANNEL
+ ***************************************************************************/
+ /* ynR= ( A2 * x(n-2)R ) */
+ ynR = pBiquadState->coefs[0] * pBiquadState->pDelays[3];
+
+ /* ynR+= ( A1 * x(n-1)R ) */
+ templ = pBiquadState->coefs[1] * pBiquadState->pDelays[1];
+ ynR += templ;
+
+ /* ynR+= ( A0 * x(n)R ) */
+ tempd =* (pDataIn+1);
+ templ = pBiquadState->coefs[2] * tempd;
+ ynR += templ;
+
+ /* ynR+= (-B2 * y(n-2)R ) */
+ templ = pBiquadState->coefs[3] * pBiquadState->pDelays[7];
+ ynR += templ;
+
+ /* ynR+= (-B1 * y(n-1)R ) */
+ templ = pBiquadState->coefs[4] * pBiquadState->pDelays[5];
+ ynR += templ;
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[7] = pBiquadState->pDelays[5]; /* y(n-2)R=y(n-1)R*/
+ pBiquadState->pDelays[6] = pBiquadState->pDelays[4]; /* y(n-2)L=y(n-1)L*/
+ pBiquadState->pDelays[3] = pBiquadState->pDelays[1]; /* x(n-2)R=x(n-1)R*/
+ pBiquadState->pDelays[2] = pBiquadState->pDelays[0]; /* x(n-2)L=x(n-1)L*/
+ pBiquadState->pDelays[5] = (LVM_FLOAT)ynR; /* Update y(n-1)R */
+ pBiquadState->pDelays[4] = (LVM_FLOAT)ynL; /* Update y(n-1)L */
+ pBiquadState->pDelays[0] = (*pDataIn); /* Update x(n-1)L */
+ pDataIn++;
+ pBiquadState->pDelays[1] = (*pDataIn); /* Update x(n-1)R */
+ pDataIn++;
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+ *pDataOut = (LVM_FLOAT)ynL; /* Write Left output */
+ pDataOut++;
+ *pDataOut = (LVM_FLOAT)ynR; /* Write Right ouput */
+ pDataOut++;
+
+ }
+
+ }
+
+#ifdef SUPPORT_MC
+/**************************************************************************
+ ASSUMPTIONS:
+ COEFS-
+ pBiquadState->coefs[0] is A2, pBiquadState->coefs[1] is A1
+ pBiquadState->coefs[2] is A0, pBiquadState->coefs[3] is -B2
+ pBiquadState->coefs[4] is -B1
+
+ DELAYS-
+ pBiquadState->pDelays[0] to
+ pBiquadState->pDelays[NrChannels - 1] is x(n-1) for all NrChannels
+
+ pBiquadState->pDelays[NrChannels] to
+ pBiquadState->pDelays[2*NrChannels - 1] is x(n-2) for all NrChannels
+
+ pBiquadState->pDelays[2*NrChannels] to
+ pBiquadState->pDelays[3*NrChannels - 1] is y(n-1) for all NrChannels
+
+ pBiquadState->pDelays[3*NrChannels] to
+ pBiquadState->pDelays[4*NrChannels - 1] is y(n-2) for all NrChannels
+***************************************************************************/
+void BQ_MC_D32F32C30_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrFrames,
+ LVM_INT16 NrChannels)
+
+ {
+ LVM_FLOAT yn, temp;
+ LVM_INT16 ii, jj;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+
+ for (ii = NrFrames; ii != 0; ii--)
+ {
+ /**************************************************************************
+ PROCESSING CHANNEL-WISE
+ ***************************************************************************/
+ for (jj = 0; jj < NrChannels; jj++)
+ {
+ /* yn= (A2 * x(n-2)) */
+ yn = pBiquadState->coefs[0] * pBiquadState->pDelays[NrChannels + jj];
+
+ /* yn+= (A1 * x(n-1)) */
+ temp = pBiquadState->coefs[1] * pBiquadState->pDelays[jj];
+ yn += temp;
+
+ /* yn+= (A0 * x(n)) */
+ temp = pBiquadState->coefs[2] * (*pDataIn);
+ yn += temp;
+
+ /* yn+= (-B2 * y(n-2)) */
+ temp = pBiquadState->coefs[3] * pBiquadState->pDelays[NrChannels*3 + jj];
+ yn += temp;
+
+ /* yn+= (-B1 * y(n-1)) */
+ temp = pBiquadState->coefs[4] * pBiquadState->pDelays[NrChannels*2 + jj];
+ yn += temp;
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[NrChannels * 3 + jj] =
+ pBiquadState->pDelays[NrChannels * 2 + jj]; /* y(n-2)=y(n-1)*/
+ pBiquadState->pDelays[NrChannels * 1 + jj] =
+ pBiquadState->pDelays[jj]; /* x(n-2)=x(n-1)*/
+ pBiquadState->pDelays[NrChannels * 2 + jj] = (LVM_FLOAT)yn; /* Update y(n-1)*/
+ pBiquadState->pDelays[jj] = (*pDataIn); /* Update x(n-1)*/
+ pDataIn++;
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+ *pDataOut = (LVM_FLOAT)yn; /* Write jj Channel output */
+ pDataOut++;
+ }
+ }
+
+ }
+#endif /*SUPPORT_MC*/
+
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32Cll_TRC_WRA_01_Init.c b/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32Cll_TRC_WRA_01_Init.c
deleted file mode 100644
index fff05ed..0000000
--- a/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32Cll_TRC_WRA_01_Init.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*-------------------------------------------------------------------------*/
-#include "BIQUAD.h"
-#include "BQ_2I_D32F32Cll_TRC_WRA_01_Private.h"
-
-/*-------------------------------------------------------------------------*/
-/* FUNCTION: */
-/* BQ_2I_D32F32Cll_TRC_WRA_01_Init */
-/* */
-/* DESCRIPTION: */
-/* These functions initializes a BIQUAD filter defined as a cascade of */
-/* biquadratic Filter Sections. */
-/* */
-/* PARAMETERS: */
-/* pInstance - output, returns the pointer to the State Variable */
-/* This state pointer must be passed to any subsequent */
-/* call to "Biquad" functions. */
-/* pTaps - input, pointer to the taps memory */
-/* pCoef - input, pointer to the coefficient structure */
-/* N - M coefficient factor of QM.N */
-/* RETURNS: */
-/* void return code */
-/*-------------------------------------------------------------------------*/
-#ifdef BUILD_FLOAT
-void BQ_2I_D32F32Cll_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
- Biquad_2I_Order2_FLOAT_Taps_t *pTaps,
- BQ_FLOAT_Coefs_t *pCoef)
-{
- LVM_FLOAT temp;
- PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
- pBiquadState->pDelays = (LVM_FLOAT *) pTaps;
- temp = pCoef->A2;
- pBiquadState->coefs[0] = temp;
- temp = pCoef->A1;
- pBiquadState->coefs[1] = temp;
- temp = pCoef->A0;
- pBiquadState->coefs[2] = temp;
- temp = pCoef->B2;
- pBiquadState->coefs[3] = temp;
- temp = pCoef->B1;
- pBiquadState->coefs[4] = temp;
-}
-#else
-void BQ_2I_D32F32Cll_TRC_WRA_01_Init ( Biquad_Instance_t *pInstance,
- Biquad_2I_Order2_Taps_t *pTaps,
- BQ_C32_Coefs_t *pCoef)
-{
- LVM_INT32 temp;
- PFilter_State pBiquadState = (PFilter_State) pInstance;
- pBiquadState->pDelays =(LVM_INT32 *) pTaps ;
-
- temp=pCoef->A2;
- pBiquadState->coefs[0]=temp;
- temp=pCoef->A1;
- pBiquadState->coefs[1]=temp;
- temp=pCoef->A0;
- pBiquadState->coefs[2]=temp;
- temp=pCoef->B2;
- pBiquadState->coefs[3]=temp;
- temp=pCoef->B1;
- pBiquadState->coefs[4]=temp;
-}
-#endif
-/*-------------------------------------------------------------------------*/
-/* End Of File: BQ_2I_D32F32C32_TRC_WRA_01_Init.c */
-
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32Cll_TRC_WRA_01_Init.cpp b/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32Cll_TRC_WRA_01_Init.cpp
new file mode 100644
index 0000000..492a9e0
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32Cll_TRC_WRA_01_Init.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*-------------------------------------------------------------------------*/
+#include "BIQUAD.h"
+#include "BQ_2I_D32F32Cll_TRC_WRA_01_Private.h"
+
+/*-------------------------------------------------------------------------*/
+/* FUNCTION: */
+/* BQ_2I_D32F32Cll_TRC_WRA_01_Init */
+/* */
+/* DESCRIPTION: */
+/* These functions initializes a BIQUAD filter defined as a cascade of */
+/* biquadratic Filter Sections. */
+/* */
+/* PARAMETERS: */
+/* pInstance - output, returns the pointer to the State Variable */
+/* This state pointer must be passed to any subsequent */
+/* call to "Biquad" functions. */
+/* pTaps - input, pointer to the taps memory */
+/* pCoef - input, pointer to the coefficient structure */
+/* N - M coefficient factor of QM.N */
+/* RETURNS: */
+/* void return code */
+/*-------------------------------------------------------------------------*/
+void BQ_2I_D32F32Cll_TRC_WRA_01_Init ( Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_2I_Order2_FLOAT_Taps_t *pTaps,
+ BQ_FLOAT_Coefs_t *pCoef)
+{
+ LVM_FLOAT temp;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+ pBiquadState->pDelays = (LVM_FLOAT *) pTaps;
+ temp = pCoef->A2;
+ pBiquadState->coefs[0] = temp;
+ temp = pCoef->A1;
+ pBiquadState->coefs[1] = temp;
+ temp = pCoef->A0;
+ pBiquadState->coefs[2] = temp;
+ temp = pCoef->B2;
+ pBiquadState->coefs[3] = temp;
+ temp = pCoef->B1;
+ pBiquadState->coefs[4] = temp;
+}
+/*-------------------------------------------------------------------------*/
+/* End Of File: BQ_2I_D32F32C32_TRC_WRA_01_Init.c */
+
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32Cll_TRC_WRA_01_Private.h b/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32Cll_TRC_WRA_01_Private.h
index c0f0dcc..7eb6474 100644
--- a/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32Cll_TRC_WRA_01_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32Cll_TRC_WRA_01_Private.h
@@ -18,7 +18,6 @@
#ifndef _BQ_2I_D32F32CLL_TRC_WRA_01_PRIVATE_H_
#define _BQ_2I_D32F32CLL_TRC_WRA_01_PRIVATE_H_
-
/* The internal state variables are implemented in a (for the user) hidden structure */
/* In this (private) file, the internal structure is declared fro private use. */
typedef struct _Filter_State_
@@ -29,7 +28,6 @@
typedef Filter_State * PFilter_State ;
-#ifdef BUILD_FLOAT
typedef struct _Filter_State_FLOAT
{
LVM_FLOAT * pDelays; /* pointer to the delayed samples \
@@ -37,6 +35,5 @@
LVM_FLOAT coefs[5]; /* pointer to the filter coefficients */
}Filter_State_FLOAT;
typedef Filter_State_FLOAT * PFilter_State_FLOAT ;
-#endif
#endif /* _BQ_2I_D32F32CLL_TRC_WRA_01_PRIVATE_H_*/
diff --git a/media/libeffects/lvm/lib/Common/src/Copy_16.c b/media/libeffects/lvm/lib/Common/src/Copy_16.c
deleted file mode 100644
index 3858450..0000000
--- a/media/libeffects/lvm/lib/Common/src/Copy_16.c
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**********************************************************************************
- INCLUDE FILES
-***********************************************************************************/
-
-#include "VectorArithmetic.h"
-
-/**********************************************************************************
- FUNCTION COPY_16
-***********************************************************************************/
-
-void Copy_16( const LVM_INT16 *src,
- LVM_INT16 *dst,
- LVM_INT16 n )
-{
- LVM_INT16 ii;
-
- if (src > dst)
- {
- for (ii = n; ii != 0; ii--)
- {
- *dst = *src;
- dst++;
- src++;
- }
- }
- else
- {
- src += n - 1;
- dst += n - 1;
- for (ii = n; ii != 0; ii--)
- {
- *dst = *src;
- dst--;
- src--;
- }
- }
-
- return;
-}
-#ifdef BUILD_FLOAT
-void Copy_Float( const LVM_FLOAT *src,
- LVM_FLOAT *dst,
- LVM_INT16 n )
-{
- LVM_INT16 ii;
-
- if (src > dst)
- {
- for (ii = n; ii != 0; ii--)
- {
- *dst = *src;
- dst++;
- src++;
- }
- }
- else
- {
- src += n - 1;
- dst += n - 1;
- for (ii = n; ii != 0; ii--)
- {
- *dst = *src;
- dst--;
- src--;
- }
- }
-
- return;
-}
-#ifdef SUPPORT_MC
-// Extract out the stereo channel pair from multichannel source.
-void Copy_Float_Mc_Stereo(const LVM_FLOAT *src,
- LVM_FLOAT *dst,
- LVM_INT16 NrFrames, /* Number of frames */
- LVM_INT32 NrChannels)
-{
- LVM_INT16 ii;
-
- if (NrChannels >= 2)
- {
- for (ii = NrFrames; ii != 0; ii--)
- {
- dst[0] = src[0];
- dst[1] = src[1];
- dst += 2;
- src += NrChannels;
- }
- }
- else if (NrChannels == 1)
- { // not expected to occur, provided for completeness.
- src += (NrFrames - 1);
- dst += 2 * (NrFrames - 1);
- for (ii = NrFrames; ii != 0; ii--)
- {
- dst[0] = src[0];
- dst[1] = src[0];
- dst -= 2;
- src --;
- }
- }
-}
-
-// Merge a multichannel source with stereo contained in dst, to dst.
-void Copy_Float_Stereo_Mc(const LVM_FLOAT *src,
- LVM_FLOAT *dst,
- LVM_INT16 NrFrames, /* Number of frames*/
- LVM_INT32 NrChannels)
-{
- LVM_INT16 ii, jj;
- LVM_FLOAT *src_st = dst + 2 * (NrFrames - 1);
-
- // repack dst which carries stereo information
- // together with the upper channels of src.
- dst += NrChannels * (NrFrames - 1);
- src += NrChannels * (NrFrames - 1);
- for (ii = NrFrames; ii != 0; ii--)
- {
- dst[1] = src_st[1];
- dst[0] = src_st[0]; // copy 1 before 0 is required for NrChannels == 3.
- for (jj = 2; jj < NrChannels; jj++)
- {
- dst[jj] = src[jj];
- }
- dst -= NrChannels;
- src -= NrChannels;
- src_st -= 2;
- }
-}
-#endif
-#endif
-/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/Copy_16.cpp b/media/libeffects/lvm/lib/Common/src/Copy_16.cpp
new file mode 100644
index 0000000..3a50554
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/Copy_16.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**********************************************************************************
+ INCLUDE FILES
+***********************************************************************************/
+
+#include "VectorArithmetic.h"
+
+/**********************************************************************************
+ FUNCTION COPY_16
+***********************************************************************************/
+
+void Copy_16( const LVM_INT16 *src,
+ LVM_INT16 *dst,
+ LVM_INT16 n )
+{
+ LVM_INT16 ii;
+
+ if (src > dst)
+ {
+ for (ii = n; ii != 0; ii--)
+ {
+ *dst = *src;
+ dst++;
+ src++;
+ }
+ }
+ else
+ {
+ src += n - 1;
+ dst += n - 1;
+ for (ii = n; ii != 0; ii--)
+ {
+ *dst = *src;
+ dst--;
+ src--;
+ }
+ }
+
+ return;
+}
+void Copy_Float( const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n )
+{
+ LVM_INT16 ii;
+
+ if (src > dst)
+ {
+ for (ii = n; ii != 0; ii--)
+ {
+ *dst = *src;
+ dst++;
+ src++;
+ }
+ }
+ else
+ {
+ src += n - 1;
+ dst += n - 1;
+ for (ii = n; ii != 0; ii--)
+ {
+ *dst = *src;
+ dst--;
+ src--;
+ }
+ }
+
+ return;
+}
+#ifdef SUPPORT_MC
+// Extract out the stereo channel pair from multichannel source.
+void Copy_Float_Mc_Stereo(const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 NrFrames, /* Number of frames */
+ LVM_INT32 NrChannels)
+{
+ LVM_INT16 ii;
+
+ if (NrChannels >= 2)
+ {
+ for (ii = NrFrames; ii != 0; ii--)
+ {
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst += 2;
+ src += NrChannels;
+ }
+ }
+ else if (NrChannels == 1)
+ { // not expected to occur, provided for completeness.
+ src += (NrFrames - 1);
+ dst += 2 * (NrFrames - 1);
+ for (ii = NrFrames; ii != 0; ii--)
+ {
+ dst[0] = src[0];
+ dst[1] = src[0];
+ dst -= 2;
+ src --;
+ }
+ }
+}
+
+// Merge a multichannel source with stereo contained in StereoOut, to dst.
+void Copy_Float_Stereo_Mc(const LVM_FLOAT *src,
+ LVM_FLOAT *StereoOut,
+ LVM_FLOAT *dst,
+ LVM_INT16 NrFrames, /* Number of frames*/
+ LVM_INT32 NrChannels)
+{
+ LVM_INT16 ii, jj;
+
+ // pack dst with stereo information of StereoOut
+ // together with the upper channels of src.
+ StereoOut += 2 * (NrFrames - 1);
+ dst += NrChannels * (NrFrames - 1);
+ src += NrChannels * (NrFrames - 1);
+ for (ii = NrFrames; ii != 0; ii--)
+ {
+ dst[1] = StereoOut[1];
+ dst[0] = StereoOut[0]; // copy 1 before 0 is required for NrChannels == 3.
+ for (jj = 2; jj < NrChannels; jj++)
+ {
+ dst[jj] = src[jj];
+ }
+ dst -= NrChannels;
+ src -= NrChannels;
+ StereoOut -= 2;
+ }
+}
+#endif
+/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/Core_MixHard_2St_D32C31_SAT.c b/media/libeffects/lvm/lib/Common/src/Core_MixHard_2St_D32C31_SAT.c
deleted file mode 100644
index ea98041..0000000
--- a/media/libeffects/lvm/lib/Common/src/Core_MixHard_2St_D32C31_SAT.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**********************************************************************************
- INCLUDE FILES
-***********************************************************************************/
-
-#include "Mixer_private.h"
-#include "LVM_Macros.h"
-
-/**********************************************************************************
- FUNCTION CORE_MIXHARD_2ST_D32C31_SAT
-***********************************************************************************/
-#ifdef BUILD_FLOAT
-void Core_MixHard_2St_D32C31_SAT( Mix_2St_Cll_FLOAT_t *pInstance,
- const LVM_FLOAT *src1,
- const LVM_FLOAT *src2,
- LVM_FLOAT *dst,
- LVM_INT16 n)
-{
- LVM_FLOAT Temp1,Temp2,Temp3;
- LVM_INT16 ii;
- LVM_FLOAT Current1Short;
- LVM_FLOAT Current2Short;
-
- Current1Short = (pInstance->Current1);
- Current2Short = (pInstance->Current2);
-
- for (ii = n; ii != 0; ii--){
- Temp1 = *src1++;
- Temp3 = Temp1 * Current1Short;
- Temp2 = *src2++;
- Temp1 = Temp2 * Current2Short;
- Temp2 = (Temp1 / 2.0f) + (Temp3 / 2.0f);
- if (Temp2 > 0.5f)
- Temp2 = 1.0f;
- else if (Temp2 < -0.5f )
- Temp2 = -1.0f;
- else
- Temp2 = (Temp2 * 2);
- *dst++ = Temp2;
- }
-}
-#else
-void Core_MixHard_2St_D32C31_SAT( Mix_2St_Cll_t *pInstance,
- const LVM_INT32 *src1,
- const LVM_INT32 *src2,
- LVM_INT32 *dst,
- LVM_INT16 n)
-{
- LVM_INT32 Temp1,Temp2,Temp3;
- LVM_INT16 ii;
- LVM_INT16 Current1Short;
- LVM_INT16 Current2Short;
-
- Current1Short = (LVM_INT16)(pInstance->Current1 >> 16);
- Current2Short = (LVM_INT16)(pInstance->Current2 >> 16);
-
- for (ii = n; ii != 0; ii--){
- Temp1=*src1++;
- MUL32x16INTO32(Temp1,Current1Short,Temp3,15)
- Temp2=*src2++;
- MUL32x16INTO32(Temp2,Current2Short,Temp1,15)
- Temp2=(Temp1>>1)+(Temp3>>1);
- if (Temp2 > 0x3FFFFFFF)
- Temp2 = 0x7FFFFFFF;
- else if (Temp2 < - 0x40000000)
- Temp2 = 0x80000000;
- else
- Temp2=(Temp2<<1);
- *dst++ = Temp2;
- }
-}
-#endif
-/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/Core_MixHard_2St_D32C31_SAT.cpp b/media/libeffects/lvm/lib/Common/src/Core_MixHard_2St_D32C31_SAT.cpp
new file mode 100644
index 0000000..5e77335
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/Core_MixHard_2St_D32C31_SAT.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**********************************************************************************
+ INCLUDE FILES
+***********************************************************************************/
+
+#include "Mixer_private.h"
+#include "LVM_Macros.h"
+
+/**********************************************************************************
+ FUNCTION CORE_MIXHARD_2ST_D32C31_SAT
+***********************************************************************************/
+void Core_MixHard_2St_D32C31_SAT( Mix_2St_Cll_FLOAT_t *pInstance,
+ const LVM_FLOAT *src1,
+ const LVM_FLOAT *src2,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ LVM_FLOAT Temp1,Temp2,Temp3;
+ LVM_INT16 ii;
+ LVM_FLOAT Current1Short;
+ LVM_FLOAT Current2Short;
+
+ Current1Short = (pInstance->Current1);
+ Current2Short = (pInstance->Current2);
+
+ for (ii = n; ii != 0; ii--){
+ Temp1 = *src1++;
+ Temp3 = Temp1 * Current1Short;
+ Temp2 = *src2++;
+ Temp1 = Temp2 * Current2Short;
+ Temp2 = (Temp1 / 2.0f) + (Temp3 / 2.0f);
+ if (Temp2 > 0.5f)
+ Temp2 = 1.0f;
+ else if (Temp2 < -0.5f )
+ Temp2 = -1.0f;
+ else
+ Temp2 = (Temp2 * 2);
+ *dst++ = Temp2;
+ }
+}
+/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/Core_MixInSoft_D32C31_SAT.c b/media/libeffects/lvm/lib/Common/src/Core_MixInSoft_D32C31_SAT.c
deleted file mode 100644
index 2814f19..0000000
--- a/media/libeffects/lvm/lib/Common/src/Core_MixInSoft_D32C31_SAT.c
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**********************************************************************************
- INCLUDE FILES
-***********************************************************************************/
-
-#include "Mixer_private.h"
-#include "LVM_Macros.h"
-
-/**********************************************************************************
- FUNCTION CORE_MIXSOFT_1ST_D32C31_WRA
-***********************************************************************************/
-
-#ifdef BUILD_FLOAT /* BUILD_FLOAT */
-void Core_MixInSoft_D32C31_SAT( Mix_1St_Cll_FLOAT_t *pInstance,
- const LVM_FLOAT *src,
- LVM_FLOAT *dst,
- LVM_INT16 n)
-{
- LVM_FLOAT Temp1,Temp2,Temp3;
- LVM_INT16 OutLoop;
- LVM_INT16 InLoop;
- LVM_FLOAT TargetTimesOneMinAlpha;
- LVM_FLOAT CurrentTimesAlpha;
- LVM_INT16 ii,jj;
-
-
- InLoop = (LVM_INT16)(n >> 2); /* Process per 4 samples */
- OutLoop = (LVM_INT16)(n - (InLoop << 2));
-
- TargetTimesOneMinAlpha = ((1.0f -pInstance->Alpha) * pInstance->Target);
- if (pInstance->Target >= pInstance->Current){
- TargetTimesOneMinAlpha +=(LVM_FLOAT)(2.0f / 2147483647.0f); /* Ceil*/
- }
-
- if (OutLoop){
-
- CurrentTimesAlpha = pInstance->Current * pInstance->Alpha;
- pInstance->Current = TargetTimesOneMinAlpha + CurrentTimesAlpha;
-
- for (ii = OutLoop; ii != 0; ii--){
- Temp1 = *src++;
- Temp2 = *dst;
-
- Temp3 = Temp1 * (pInstance->Current);
- Temp1 = Temp2 + Temp3;
-
- if (Temp1 > 1.0f)
- Temp1 = 1.0f;
- else if (Temp1 < -1.0f)
- Temp1 = -1.0f;
-
- *dst++ = Temp1;
- }
- }
-
- for (ii = InLoop; ii != 0; ii--){
-
- CurrentTimesAlpha = pInstance->Current * pInstance->Alpha;
- pInstance->Current = TargetTimesOneMinAlpha + CurrentTimesAlpha;
-
- for (jj = 4; jj!=0 ; jj--){
- Temp1 = *src++;
- Temp2 = *dst;
-
- Temp3 = Temp1 * (pInstance->Current);
- Temp1 = Temp2 + Temp3;
-
- if (Temp1 > 1.0f)
- Temp1 = 1.0f;
- else if (Temp1 < -1.0f)
- Temp1 = -1.0f;
- *dst++ = Temp1;
- }
- }
-}
-#else
-void Core_MixInSoft_D32C31_SAT( Mix_1St_Cll_t *pInstance,
- const LVM_INT32 *src,
- LVM_INT32 *dst,
- LVM_INT16 n)
-{
- LVM_INT32 Temp1,Temp2,Temp3;
- LVM_INT16 OutLoop;
- LVM_INT16 InLoop;
- LVM_INT32 TargetTimesOneMinAlpha;
- LVM_INT32 CurrentTimesAlpha;
- LVM_INT16 ii,jj;
- LVM_INT16 CurrentShort;
-
- InLoop = (LVM_INT16)(n >> 2); /* Process per 4 samples */
- OutLoop = (LVM_INT16)(n - (InLoop << 2));
-
- MUL32x32INTO32((0x7FFFFFFF-pInstance->Alpha),pInstance->Target,TargetTimesOneMinAlpha,31); /* Q31 * Q0 in Q0 */
- if (pInstance->Target >= pInstance->Current){
- TargetTimesOneMinAlpha +=2; /* Ceil*/
- }
-
- if (OutLoop){
- MUL32x32INTO32(pInstance->Current,pInstance->Alpha,CurrentTimesAlpha,31); /* Q0 * Q31 in Q0 */
- pInstance->Current = TargetTimesOneMinAlpha + CurrentTimesAlpha; /* Q0 + Q0 into Q0*/
- CurrentShort = (LVM_INT16)(pInstance->Current>>16); /* From Q31 to Q15*/
-
- for (ii = OutLoop; ii != 0; ii--){
- Temp1=*src++;
- Temp2=*dst;
- MUL32x16INTO32(Temp1,CurrentShort,Temp3,15)
- Temp1=(Temp2>>1)+(Temp3>>1);
-
- if (Temp1 > 0x3FFFFFFF)
- Temp1 = 0x7FFFFFFF;
- else if (Temp1 < - 0x40000000)
- Temp1 = 0x80000000;
- else
- Temp1=(Temp1<<1);
- *dst++ = Temp1;
- }
- }
-
- for (ii = InLoop; ii != 0; ii--){
- MUL32x32INTO32(pInstance->Current,pInstance->Alpha,CurrentTimesAlpha,31); /* Q0 * Q31 in Q0 */
- pInstance->Current = TargetTimesOneMinAlpha + CurrentTimesAlpha; /* Q0 + Q0 into Q0*/
- CurrentShort = (LVM_INT16)(pInstance->Current>>16); /* From Q31 to Q15*/
-
- for (jj = 4; jj!=0 ; jj--){
- Temp1=*src++;
- Temp2=*dst;
- MUL32x16INTO32(Temp1,CurrentShort,Temp3,15)
- Temp1=(Temp2>>1)+(Temp3>>1);
-
- if (Temp1 > 0x3FFFFFFF)
- Temp1 = 0x7FFFFFFF;
- else if (Temp1 < - 0x40000000)
- Temp1 = 0x80000000;
- else
- Temp1=(Temp1<<1);
- *dst++ = Temp1;
- }
- }
-}
-#endif
-/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/Core_MixInSoft_D32C31_SAT.cpp b/media/libeffects/lvm/lib/Common/src/Core_MixInSoft_D32C31_SAT.cpp
new file mode 100644
index 0000000..8f5c0ae
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/Core_MixInSoft_D32C31_SAT.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**********************************************************************************
+ INCLUDE FILES
+***********************************************************************************/
+
+#include "Mixer_private.h"
+#include "LVM_Macros.h"
+
+/**********************************************************************************
+ FUNCTION CORE_MIXSOFT_1ST_D32C31_WRA
+***********************************************************************************/
+
+void Core_MixInSoft_D32C31_SAT( Mix_1St_Cll_FLOAT_t *pInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ LVM_FLOAT Temp1,Temp2,Temp3;
+ LVM_INT16 OutLoop;
+ LVM_INT16 InLoop;
+ LVM_FLOAT TargetTimesOneMinAlpha;
+ LVM_FLOAT CurrentTimesAlpha;
+ LVM_INT16 ii,jj;
+
+ InLoop = (LVM_INT16)(n >> 2); /* Process per 4 samples */
+ OutLoop = (LVM_INT16)(n - (InLoop << 2));
+
+ TargetTimesOneMinAlpha = ((1.0f -pInstance->Alpha) * pInstance->Target);
+ if (pInstance->Target >= pInstance->Current){
+ TargetTimesOneMinAlpha +=(LVM_FLOAT)(2.0f / 2147483647.0f); /* Ceil*/
+ }
+
+ if (OutLoop){
+
+ CurrentTimesAlpha = pInstance->Current * pInstance->Alpha;
+ pInstance->Current = TargetTimesOneMinAlpha + CurrentTimesAlpha;
+
+ for (ii = OutLoop; ii != 0; ii--){
+ Temp1 = *src++;
+ Temp2 = *dst;
+
+ Temp3 = Temp1 * (pInstance->Current);
+ Temp1 = Temp2 + Temp3;
+
+ if (Temp1 > 1.0f)
+ Temp1 = 1.0f;
+ else if (Temp1 < -1.0f)
+ Temp1 = -1.0f;
+
+ *dst++ = Temp1;
+ }
+ }
+
+ for (ii = InLoop; ii != 0; ii--){
+
+ CurrentTimesAlpha = pInstance->Current * pInstance->Alpha;
+ pInstance->Current = TargetTimesOneMinAlpha + CurrentTimesAlpha;
+
+ for (jj = 4; jj!=0 ; jj--){
+ Temp1 = *src++;
+ Temp2 = *dst;
+
+ Temp3 = Temp1 * (pInstance->Current);
+ Temp1 = Temp2 + Temp3;
+
+ if (Temp1 > 1.0f)
+ Temp1 = 1.0f;
+ else if (Temp1 < -1.0f)
+ Temp1 = -1.0f;
+ *dst++ = Temp1;
+ }
+ }
+}
+/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/Core_MixSoft_1St_D32C31_WRA.c b/media/libeffects/lvm/lib/Common/src/Core_MixSoft_1St_D32C31_WRA.c
deleted file mode 100644
index 814ccee..0000000
--- a/media/libeffects/lvm/lib/Common/src/Core_MixSoft_1St_D32C31_WRA.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**********************************************************************************
- INCLUDE FILES
-***********************************************************************************/
-
-#include "Mixer_private.h"
-#include "LVM_Macros.h"
-
-/**********************************************************************************
- FUNCTION CORE_MIXSOFT_1ST_D32C31_WRA
-***********************************************************************************/
-#ifdef BUILD_FLOAT
-void Core_MixSoft_1St_D32C31_WRA( Mix_1St_Cll_FLOAT_t *pInstance,
- const LVM_FLOAT *src,
- LVM_FLOAT *dst,
- LVM_INT16 n)
-{
- LVM_FLOAT Temp1,Temp2;
- LVM_INT16 OutLoop;
- LVM_INT16 InLoop;
- LVM_FLOAT TargetTimesOneMinAlpha;
- LVM_FLOAT CurrentTimesAlpha;
-
- LVM_INT16 ii;
-
- InLoop = (LVM_INT16)(n >> 2); /* Process per 4 samples */
- OutLoop = (LVM_INT16)(n - (InLoop << 2));
-
- TargetTimesOneMinAlpha = (1.0f - pInstance->Alpha) * pInstance->Target; /* float * float in float */
- if (pInstance->Target >= pInstance->Current)
- {
- TargetTimesOneMinAlpha += (LVM_FLOAT)(2.0f / 2147483647.0f); /* Ceil*/
- }
-
- if (OutLoop != 0)
- {
- CurrentTimesAlpha = (pInstance->Current * pInstance->Alpha);
- pInstance->Current = TargetTimesOneMinAlpha + CurrentTimesAlpha;
-
- for (ii = OutLoop; ii != 0; ii--)
- {
- Temp1 = *src;
- src++;
-
- Temp2 = Temp1 * (pInstance->Current);
- *dst = Temp2;
- dst++;
- }
- }
-
- for (ii = InLoop; ii != 0; ii--)
- {
- CurrentTimesAlpha = pInstance->Current * pInstance->Alpha;
- pInstance->Current = TargetTimesOneMinAlpha + CurrentTimesAlpha;
-
- Temp1 = *src;
- src++;
-
- Temp2 = Temp1 * (pInstance->Current);
- *dst = Temp2;
- dst++;
-
- Temp1 = *src;
- src++;
-
- Temp2 = Temp1 * (pInstance->Current);
- *dst = Temp2;
- dst++;
-
- Temp1 = *src;
- src++;
-
- Temp2 = Temp1 * (pInstance->Current);
- *dst = Temp2;
- dst++;
-
- Temp1 = *src;
- src++;
- Temp2 = Temp1 * (pInstance->Current);
- *dst = Temp2;
- dst++;
- }
-}
-#else
-void Core_MixSoft_1St_D32C31_WRA( Mix_1St_Cll_t *pInstance,
- const LVM_INT32 *src,
- LVM_INT32 *dst,
- LVM_INT16 n)
-{
- LVM_INT32 Temp1,Temp2;
- LVM_INT16 OutLoop;
- LVM_INT16 InLoop;
- LVM_INT32 TargetTimesOneMinAlpha;
- LVM_INT32 CurrentTimesAlpha;
- LVM_INT16 CurrentShort;
- LVM_INT16 ii;
-
- InLoop = (LVM_INT16)(n >> 2); /* Process per 4 samples */
- OutLoop = (LVM_INT16)(n - (InLoop << 2));
-
- MUL32x32INTO32((0x7FFFFFFF-pInstance->Alpha),pInstance->Target,TargetTimesOneMinAlpha,31) /* Q31 * Q31 in Q31 */
- if (pInstance->Target >= pInstance->Current)
- {
- TargetTimesOneMinAlpha +=2; /* Ceil*/
- }
-
- if (OutLoop!=0)
- {
- MUL32x32INTO32(pInstance->Current,pInstance->Alpha,CurrentTimesAlpha,31) /* Q31 * Q31 in Q31 */
- pInstance->Current = TargetTimesOneMinAlpha + CurrentTimesAlpha; /* Q31 + Q31 into Q31*/
- CurrentShort = (LVM_INT16)(pInstance->Current>>16); /* From Q31 to Q15*/
-
- for (ii = OutLoop; ii != 0; ii--)
- {
- Temp1=*src;
- src++;
-
- MUL32x16INTO32(Temp1,CurrentShort,Temp2,15)
- *dst = Temp2;
- dst++;
- }
- }
-
- for (ii = InLoop; ii != 0; ii--)
- {
- MUL32x32INTO32(pInstance->Current,pInstance->Alpha,CurrentTimesAlpha,31) /* Q31 * Q31 in Q31 */
- pInstance->Current = TargetTimesOneMinAlpha + CurrentTimesAlpha; /* Q31 + Q31 into Q31*/
- CurrentShort = (LVM_INT16)(pInstance->Current>>16); /* From Q31 to Q15*/
- Temp1=*src;
- src++;
-
- MUL32x16INTO32(Temp1,CurrentShort,Temp2,15)
- *dst = Temp2;
- dst++;
-
- Temp1=*src;
- src++;
-
- MUL32x16INTO32(Temp1,CurrentShort,Temp2,15)
- *dst = Temp2;
- dst++;
-
- Temp1=*src;
- src++;
-
- MUL32x16INTO32(Temp1,CurrentShort,Temp2,15)
- *dst = Temp2;
- dst++;
-
- Temp1=*src;
- src++;
- MUL32x16INTO32(Temp1,CurrentShort,Temp2,15)
- *dst = Temp2;
- dst++;
- }
-}
-#endif
-/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/Core_MixSoft_1St_D32C31_WRA.cpp b/media/libeffects/lvm/lib/Common/src/Core_MixSoft_1St_D32C31_WRA.cpp
new file mode 100644
index 0000000..6ff7853
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/Core_MixSoft_1St_D32C31_WRA.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**********************************************************************************
+ INCLUDE FILES
+***********************************************************************************/
+
+#include "Mixer_private.h"
+#include "LVM_Macros.h"
+
+/**********************************************************************************
+ FUNCTION CORE_MIXSOFT_1ST_D32C31_WRA
+***********************************************************************************/
+void Core_MixSoft_1St_D32C31_WRA( Mix_1St_Cll_FLOAT_t *pInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ LVM_FLOAT Temp1,Temp2;
+ LVM_INT16 OutLoop;
+ LVM_INT16 InLoop;
+ LVM_FLOAT TargetTimesOneMinAlpha;
+ LVM_FLOAT CurrentTimesAlpha;
+
+ LVM_INT16 ii;
+
+ InLoop = (LVM_INT16)(n >> 2); /* Process per 4 samples */
+ OutLoop = (LVM_INT16)(n - (InLoop << 2));
+
+ TargetTimesOneMinAlpha = (1.0f - pInstance->Alpha) * pInstance->Target; /* float * float in float */
+ if (pInstance->Target >= pInstance->Current)
+ {
+ TargetTimesOneMinAlpha += (LVM_FLOAT)(2.0f / 2147483647.0f); /* Ceil*/
+ }
+
+ if (OutLoop != 0)
+ {
+ CurrentTimesAlpha = (pInstance->Current * pInstance->Alpha);
+ pInstance->Current = TargetTimesOneMinAlpha + CurrentTimesAlpha;
+
+ for (ii = OutLoop; ii != 0; ii--)
+ {
+ Temp1 = *src;
+ src++;
+
+ Temp2 = Temp1 * (pInstance->Current);
+ *dst = Temp2;
+ dst++;
+ }
+ }
+
+ for (ii = InLoop; ii != 0; ii--)
+ {
+ CurrentTimesAlpha = pInstance->Current * pInstance->Alpha;
+ pInstance->Current = TargetTimesOneMinAlpha + CurrentTimesAlpha;
+
+ Temp1 = *src;
+ src++;
+
+ Temp2 = Temp1 * (pInstance->Current);
+ *dst = Temp2;
+ dst++;
+
+ Temp1 = *src;
+ src++;
+
+ Temp2 = Temp1 * (pInstance->Current);
+ *dst = Temp2;
+ dst++;
+
+ Temp1 = *src;
+ src++;
+
+ Temp2 = Temp1 * (pInstance->Current);
+ *dst = Temp2;
+ dst++;
+
+ Temp1 = *src;
+ src++;
+ Temp2 = Temp1 * (pInstance->Current);
+ *dst = Temp2;
+ dst++;
+ }
+}
+/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01.c
deleted file mode 100644
index 13fac5e..0000000
--- a/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BIQUAD.h"
-#include "DC_2I_D16_TRC_WRA_01_Private.h"
-#include "LVM_Macros.h"
-#ifdef BUILD_FLOAT
-void DC_2I_D16_TRC_WRA_01( Biquad_FLOAT_Instance_t *pInstance,
- LVM_FLOAT *pDataIn,
- LVM_FLOAT *pDataOut,
- LVM_INT16 NrSamples)
- {
- LVM_FLOAT LeftDC,RightDC;
- LVM_FLOAT Diff;
- LVM_INT32 j;
- PFilter_FLOAT_State pBiquadState = (PFilter_FLOAT_State) pInstance;
-
- LeftDC = pBiquadState->LeftDC;
- RightDC = pBiquadState->RightDC;
- for(j = NrSamples-1; j >= 0; j--)
- {
- /* Subtract DC and saturate */
- Diff =* (pDataIn++) - (LeftDC);
- if (Diff > 1.0f) {
- Diff = 1.0f; }
- else if (Diff < -1.0f) {
- Diff = -1.0f; }
- *(pDataOut++) = (LVM_FLOAT)Diff;
- if (Diff < 0) {
- LeftDC -= DC_FLOAT_STEP; }
- else {
- LeftDC += DC_FLOAT_STEP; }
-
-
- /* Subtract DC an saturate */
- Diff =* (pDataIn++) - (RightDC);
- if (Diff > 1.0f) {
- Diff = 1.0f; }
- else if (Diff < -1.0f) {
- Diff = -1.0f; }
- *(pDataOut++) = (LVM_FLOAT)Diff;
- if (Diff < 0) {
- RightDC -= DC_FLOAT_STEP; }
- else {
- RightDC += DC_FLOAT_STEP; }
-
- }
- pBiquadState->LeftDC = LeftDC;
- pBiquadState->RightDC = RightDC;
-
-
- }
-#ifdef SUPPORT_MC
-/*
- * FUNCTION: DC_Mc_D16_TRC_WRA_01
- *
- * DESCRIPTION:
- * DC removal from all channels of a multichannel input
- *
- * PARAMETERS:
- * pInstance Instance pointer
- * pDataIn Input/Source
- * pDataOut Output/Destination
- * NrFrames Number of frames
- * NrChannels Number of channels
- *
- * RETURNS:
- * void
- *
- */
-void DC_Mc_D16_TRC_WRA_01(Biquad_FLOAT_Instance_t *pInstance,
- LVM_FLOAT *pDataIn,
- LVM_FLOAT *pDataOut,
- LVM_INT16 NrFrames,
- LVM_INT16 NrChannels)
- {
- LVM_FLOAT *ChDC;
- LVM_FLOAT Diff;
- LVM_INT32 j;
- LVM_INT32 i;
- PFilter_FLOAT_State_Mc pBiquadState = (PFilter_FLOAT_State_Mc) pInstance;
-
- ChDC = &pBiquadState->ChDC[0];
- for (j = NrFrames - 1; j >= 0; j--)
- {
- /* Subtract DC and saturate */
- for (i = NrChannels - 1; i >= 0; i--)
- {
- Diff = *(pDataIn++) - (ChDC[i]);
- if (Diff > 1.0f) {
- Diff = 1.0f;
- } else if (Diff < -1.0f) {
- Diff = -1.0f; }
- *(pDataOut++) = (LVM_FLOAT)Diff;
- if (Diff < 0) {
- ChDC[i] -= DC_FLOAT_STEP;
- } else {
- ChDC[i] += DC_FLOAT_STEP; }
- }
-
- }
-
- }
-#endif
-#else
-void DC_2I_D16_TRC_WRA_01( Biquad_Instance_t *pInstance,
- LVM_INT16 *pDataIn,
- LVM_INT16 *pDataOut,
- LVM_INT16 NrSamples)
- {
- LVM_INT32 LeftDC,RightDC;
- LVM_INT32 Diff;
- LVM_INT32 j;
- PFilter_State pBiquadState = (PFilter_State) pInstance;
-
- LeftDC = pBiquadState->LeftDC;
- RightDC = pBiquadState->RightDC;
- for(j=NrSamples-1;j>=0;j--)
- {
- /* Subtract DC an saturate */
- Diff=*(pDataIn++)-(LeftDC>>16);
- if (Diff > 32767) {
- Diff = 32767; }
- else if (Diff < -32768) {
- Diff = -32768; }
- *(pDataOut++)=(LVM_INT16)Diff;
- if (Diff < 0) {
- LeftDC -= DC_D16_STEP; }
- else {
- LeftDC += DC_D16_STEP; }
-
-
- /* Subtract DC an saturate */
- Diff=*(pDataIn++)-(RightDC>>16);
- if (Diff > 32767) {
- Diff = 32767; }
- else if (Diff < -32768) {
- Diff = -32768; }
- *(pDataOut++)=(LVM_INT16)Diff;
- if (Diff < 0) {
- RightDC -= DC_D16_STEP; }
- else {
- RightDC += DC_D16_STEP; }
-
- }
- pBiquadState->LeftDC = LeftDC;
- pBiquadState->RightDC = RightDC;
-
-
- }
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01.cpp b/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01.cpp
new file mode 100644
index 0000000..a7ce4d3
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BIQUAD.h"
+#include "DC_2I_D16_TRC_WRA_01_Private.h"
+#include "LVM_Macros.h"
+void DC_2I_D16_TRC_WRA_01( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+ {
+ LVM_FLOAT LeftDC,RightDC;
+ LVM_FLOAT Diff;
+ LVM_INT32 j;
+ PFilter_FLOAT_State pBiquadState = (PFilter_FLOAT_State) pInstance;
+
+ LeftDC = pBiquadState->LeftDC;
+ RightDC = pBiquadState->RightDC;
+ for(j = NrSamples-1; j >= 0; j--)
+ {
+ /* Subtract DC and saturate */
+ Diff =* (pDataIn++) - (LeftDC);
+ if (Diff > 1.0f) {
+ Diff = 1.0f; }
+ else if (Diff < -1.0f) {
+ Diff = -1.0f; }
+ *(pDataOut++) = (LVM_FLOAT)Diff;
+ if (Diff < 0) {
+ LeftDC -= DC_FLOAT_STEP; }
+ else {
+ LeftDC += DC_FLOAT_STEP; }
+
+ /* Subtract DC an saturate */
+ Diff =* (pDataIn++) - (RightDC);
+ if (Diff > 1.0f) {
+ Diff = 1.0f; }
+ else if (Diff < -1.0f) {
+ Diff = -1.0f; }
+ *(pDataOut++) = (LVM_FLOAT)Diff;
+ if (Diff < 0) {
+ RightDC -= DC_FLOAT_STEP; }
+ else {
+ RightDC += DC_FLOAT_STEP; }
+
+ }
+ pBiquadState->LeftDC = LeftDC;
+ pBiquadState->RightDC = RightDC;
+
+ }
+#ifdef SUPPORT_MC
+/*
+ * FUNCTION: DC_Mc_D16_TRC_WRA_01
+ *
+ * DESCRIPTION:
+ * DC removal from all channels of a multichannel input
+ *
+ * PARAMETERS:
+ * pInstance Instance pointer
+ * pDataIn Input/Source
+ * pDataOut Output/Destination
+ * NrFrames Number of frames
+ * NrChannels Number of channels
+ *
+ * RETURNS:
+ * void
+ *
+ */
+void DC_Mc_D16_TRC_WRA_01(Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrFrames,
+ LVM_INT16 NrChannels)
+ {
+ LVM_FLOAT *ChDC;
+ LVM_FLOAT Diff;
+ LVM_INT32 j;
+ LVM_INT32 i;
+ PFilter_FLOAT_State_Mc pBiquadState = (PFilter_FLOAT_State_Mc) pInstance;
+
+ ChDC = &pBiquadState->ChDC[0];
+ for (j = NrFrames - 1; j >= 0; j--)
+ {
+ /* Subtract DC and saturate */
+ for (i = NrChannels - 1; i >= 0; i--)
+ {
+ Diff = *(pDataIn++) - (ChDC[i]);
+ if (Diff > 1.0f) {
+ Diff = 1.0f;
+ } else if (Diff < -1.0f) {
+ Diff = -1.0f; }
+ *(pDataOut++) = (LVM_FLOAT)Diff;
+ if (Diff < 0) {
+ ChDC[i] -= DC_FLOAT_STEP;
+ } else {
+ ChDC[i] += DC_FLOAT_STEP; }
+ }
+
+ }
+
+ }
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01_Init.c b/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01_Init.c
deleted file mode 100644
index 0f941a0..0000000
--- a/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01_Init.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BIQUAD.h"
-#include "DC_2I_D16_TRC_WRA_01_Private.h"
-#ifdef BUILD_FLOAT
-void DC_2I_D16_TRC_WRA_01_Init(Biquad_FLOAT_Instance_t *pInstance)
-{
- PFilter_FLOAT_State pBiquadState = (PFilter_FLOAT_State) pInstance;
- pBiquadState->LeftDC = 0.0f;
- pBiquadState->RightDC = 0.0f;
-}
-#ifdef SUPPORT_MC
-void DC_Mc_D16_TRC_WRA_01_Init(Biquad_FLOAT_Instance_t *pInstance)
-{
- PFilter_FLOAT_State_Mc pBiquadState = (PFilter_FLOAT_State_Mc) pInstance;
- LVM_INT32 i;
- for (i = 0; i < LVM_MAX_CHANNELS; i++)
- {
- pBiquadState->ChDC[i] = 0.0f;
- }
-}
-#endif
-#else
-void DC_2I_D16_TRC_WRA_01_Init(Biquad_Instance_t *pInstance)
-{
- PFilter_State pBiquadState = (PFilter_State) pInstance;
- pBiquadState->LeftDC = 0;
- pBiquadState->RightDC = 0;
-}
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01_Init.cpp b/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01_Init.cpp
new file mode 100644
index 0000000..beee112
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01_Init.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BIQUAD.h"
+#include "DC_2I_D16_TRC_WRA_01_Private.h"
+void DC_2I_D16_TRC_WRA_01_Init(Biquad_FLOAT_Instance_t *pInstance)
+{
+ PFilter_FLOAT_State pBiquadState = (PFilter_FLOAT_State) pInstance;
+ pBiquadState->LeftDC = 0.0f;
+ pBiquadState->RightDC = 0.0f;
+}
+#ifdef SUPPORT_MC
+void DC_Mc_D16_TRC_WRA_01_Init(Biquad_FLOAT_Instance_t *pInstance)
+{
+ PFilter_FLOAT_State_Mc pBiquadState = (PFilter_FLOAT_State_Mc) pInstance;
+ LVM_INT32 i;
+ for (i = 0; i < LVM_MAX_CHANNELS; i++)
+ {
+ pBiquadState->ChDC[i] = 0.0f;
+ }
+}
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01_Private.h b/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01_Private.h
index db3a6d3..6508b73 100644
--- a/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01_Private.h
@@ -18,16 +18,10 @@
#ifndef _DC_2I_D16_TRC_WRA_01_PRIVATE_H_
#define _DC_2I_D16_TRC_WRA_01_PRIVATE_H_
-#ifdef BUILD_FLOAT
#define DC_FLOAT_STEP 0.0000002384f;
-#else
-#define DC_D16_STEP 0x200;
-#endif
-
/* The internal state variables are implemented in a (for the user) hidden structure */
/* In this (private) file, the internal structure is declared fro private use.*/
-#ifdef BUILD_FLOAT
typedef struct _Filter_FLOAT_State_
{
LVM_FLOAT LeftDC; /* LeftDC */
@@ -41,13 +35,4 @@
} Filter_FLOAT_State_Mc;
typedef Filter_FLOAT_State_Mc * PFilter_FLOAT_State_Mc ;
#endif
-#else
-typedef struct _Filter_State_
-{
- LVM_INT32 LeftDC; /* LeftDC */
- LVM_INT32 RightDC; /* RightDC */
-}Filter_State;
-
-typedef Filter_State * PFilter_State ;
-#endif
#endif /* _DC_2I_D16_TRC_WRA_01_PRIVATE_H_ */
diff --git a/media/libeffects/lvm/lib/Common/src/DelayAllPass_Sat_32x16To32.c b/media/libeffects/lvm/lib/Common/src/DelayAllPass_Sat_32x16To32.c
deleted file mode 100644
index b04e98e..0000000
--- a/media/libeffects/lvm/lib/Common/src/DelayAllPass_Sat_32x16To32.c
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**********************************************************************************
- INCLUDE FILES
-***********************************************************************************/
-
-#include "LVM_Types.h"
-#include "LVM_Macros.h"
-#include "VectorArithmetic.h"
-
-/**********************************************************************************
- FUNCTION DelayAllPass_32x32
-***********************************************************************************/
-
-void DelayAllPass_Sat_32x16To32( LVM_INT32 *delay, /* Delay buffer */
- LVM_UINT16 size, /* Delay size */
- LVM_INT16 coeff, /* All pass filter coefficient */
- LVM_UINT16 DelayOffset, /* Simple delay offset */
- LVM_UINT16 *pAllPassOffset, /* All pass filter delay offset */
- LVM_INT32 *dst, /* Source/destination */
- LVM_INT16 n) /* Number of samples */
-{
- LVM_INT16 i;
- LVM_UINT16 AllPassOffset = *pAllPassOffset;
- LVM_INT32 temp;
- LVM_INT32 a,b,c;
-
- for (i = 0; i < n; i++)
- {
-
- MUL32x16INTO32(delay[AllPassOffset], coeff, temp, 15)
- a = temp;
- b = delay[DelayOffset];
- DelayOffset++;
-
- c = a + b;
- if ((((c ^ a) & (c ^ b)) >> 31) != 0) /* overflow / underflow */
- {
- if(a < 0)
- {
- c = 0x80000000L;
- }
- else
- {
- c = 0x7FFFFFFFL;
- }
- }
- *dst = c;
- dst++;
-
-
- MUL32x16INTO32(c, -coeff, temp, 15)
- a = temp;
- b = delay[AllPassOffset];
- c = a + b;
- if ((((c ^ a) & (c ^ b)) >> 31)!=0) /* overflow / underflow */
- {
- if(a < 0)
- {
- c = 0x80000000L;
- }
- else
- {
- c = 0x7FFFFFFFL;
- }
- }
- delay[AllPassOffset] = c;
- AllPassOffset++;
-
- /* Make the delay buffer a circular buffer */
- if (DelayOffset >= size)
- {
- DelayOffset = 0;
- }
-
- if (AllPassOffset >= size)
- {
- AllPassOffset = 0;
- }
- }
-
- /* Update the offset */
- *pAllPassOffset = AllPassOffset;
-
- return;
-}
-
-/**********************************************************************************/
-
diff --git a/media/libeffects/lvm/lib/Common/src/DelayAllPass_Sat_32x16To32.cpp b/media/libeffects/lvm/lib/Common/src/DelayAllPass_Sat_32x16To32.cpp
new file mode 100644
index 0000000..771fae2
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/DelayAllPass_Sat_32x16To32.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**********************************************************************************
+ INCLUDE FILES
+***********************************************************************************/
+
+#include "LVM_Types.h"
+#include "LVM_Macros.h"
+#include "VectorArithmetic.h"
+
+/**********************************************************************************
+ FUNCTION DelayAllPass_32x32
+***********************************************************************************/
+
+void DelayAllPass_Sat_32x16To32( LVM_INT32 *delay, /* Delay buffer */
+ LVM_UINT16 size, /* Delay size */
+ LVM_INT16 coeff, /* All pass filter coefficient */
+ LVM_UINT16 DelayOffset, /* Simple delay offset */
+ LVM_UINT16 *pAllPassOffset, /* All pass filter delay offset */
+ LVM_INT32 *dst, /* Source/destination */
+ LVM_INT16 n) /* Number of samples */
+{
+ LVM_INT16 i;
+ LVM_UINT16 AllPassOffset = *pAllPassOffset;
+ LVM_INT32 temp;
+ LVM_INT32 a,b,c;
+
+ for (i = 0; i < n; i++)
+ {
+
+ MUL32x16INTO32(delay[AllPassOffset], coeff, temp, 15)
+ a = temp;
+ b = delay[DelayOffset];
+ DelayOffset++;
+
+ c = a + b;
+ if ((((c ^ a) & (c ^ b)) >> 31) != 0) /* overflow / underflow */
+ {
+ if(a < 0)
+ {
+ c = 0x80000000L;
+ }
+ else
+ {
+ c = 0x7FFFFFFFL;
+ }
+ }
+ *dst = c;
+ dst++;
+
+ MUL32x16INTO32(c, -coeff, temp, 15)
+ a = temp;
+ b = delay[AllPassOffset];
+ c = a + b;
+ if ((((c ^ a) & (c ^ b)) >> 31)!=0) /* overflow / underflow */
+ {
+ if(a < 0)
+ {
+ c = 0x80000000L;
+ }
+ else
+ {
+ c = 0x7FFFFFFFL;
+ }
+ }
+ delay[AllPassOffset] = c;
+ AllPassOffset++;
+
+ /* Make the delay buffer a circular buffer */
+ if (DelayOffset >= size)
+ {
+ DelayOffset = 0;
+ }
+
+ if (AllPassOffset >= size)
+ {
+ AllPassOffset = 0;
+ }
+ }
+
+ /* Update the offset */
+ *pAllPassOffset = AllPassOffset;
+
+ return;
+}
+
+/**********************************************************************************/
+
diff --git a/media/libeffects/lvm/lib/Common/src/DelayMix_16x16.c b/media/libeffects/lvm/lib/Common/src/DelayMix_16x16.c
deleted file mode 100644
index f502716..0000000
--- a/media/libeffects/lvm/lib/Common/src/DelayMix_16x16.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**********************************************************************************
- INCLUDE FILES
-***********************************************************************************/
-
-#include "VectorArithmetic.h"
-
-/**********************************************************************************
- FUNCTION DelayMix_16x16
-***********************************************************************************/
-
-void DelayMix_16x16(const LVM_INT16 *src, /* Source 1, to be delayed */
- LVM_INT16 *delay, /* Delay buffer */
- LVM_INT16 size, /* Delay size */
- LVM_INT16 *dst, /* Source/destination */
- LVM_INT16 *pOffset, /* Delay offset */
- LVM_INT16 n) /* Number of stereo samples */
-{
- LVM_INT16 i;
- LVM_INT16 Offset = *pOffset;
- LVM_INT16 temp;
-
- for (i = 0; i < n; i++)
- {
- /* Left channel */
- temp = (LVM_INT16)((LVM_UINT32)((LVM_INT32)(*dst) + (LVM_INT32)delay[Offset]) >> 1);
- *dst = temp;
- dst++;
-
- delay[Offset] = *src;
- Offset++;
- src++;
-
-
- /* Right channel */
- temp = (LVM_INT16)((LVM_UINT32)((LVM_INT32)(*dst) - (LVM_INT32)delay[Offset]) >> 1);
- *dst = temp;
- dst++;
-
- delay[Offset] = *src;
- Offset++;
- src++;
-
- /* Make the reverb delay buffer a circular buffer */
- if (Offset >= size)
- {
- Offset = 0;
- }
- }
-
- /* Update the offset */
- *pOffset = Offset;
-
- return;
-}
-#ifdef BUILD_FLOAT
-void DelayMix_Float(const LVM_FLOAT *src, /* Source 1, to be delayed */
- LVM_FLOAT *delay, /* Delay buffer */
- LVM_INT16 size, /* Delay size */
- LVM_FLOAT *dst, /* Source/destination */
- LVM_INT16 *pOffset, /* Delay offset */
- LVM_INT16 n) /* Number of stereo samples */
-{
- LVM_INT16 i;
- LVM_INT16 Offset = *pOffset;
- LVM_FLOAT temp;
-
- for (i=0; i<n; i++)
- {
- /* Left channel */
- temp = (LVM_FLOAT)((LVM_FLOAT)(*dst + (LVM_FLOAT)delay[Offset]) / 2.0f);
- *dst = temp;
- dst++;
-
- delay[Offset] = *src;
- Offset++;
- src++;
-
-
- /* Right channel */
- temp = (LVM_FLOAT)((LVM_FLOAT)(*dst - (LVM_FLOAT)delay[Offset]) / 2.0f);
- *dst = temp;
- dst++;
-
- delay[Offset] = *src;
- Offset++;
- src++;
-
- /* Make the reverb delay buffer a circular buffer */
- if (Offset >= size)
- {
- Offset = 0;
- }
- }
-
- /* Update the offset */
- *pOffset = Offset;
-
- return;
-}
-#endif
-/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/DelayMix_16x16.cpp b/media/libeffects/lvm/lib/Common/src/DelayMix_16x16.cpp
new file mode 100644
index 0000000..52d263f
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/DelayMix_16x16.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**********************************************************************************
+ INCLUDE FILES
+***********************************************************************************/
+
+#include "VectorArithmetic.h"
+
+/**********************************************************************************
+ FUNCTION DelayMix_16x16
+***********************************************************************************/
+
+void DelayMix_16x16(const LVM_INT16 *src, /* Source 1, to be delayed */
+ LVM_INT16 *delay, /* Delay buffer */
+ LVM_INT16 size, /* Delay size */
+ LVM_INT16 *dst, /* Source/destination */
+ LVM_INT16 *pOffset, /* Delay offset */
+ LVM_INT16 n) /* Number of stereo samples */
+{
+ LVM_INT16 i;
+ LVM_INT16 Offset = *pOffset;
+ LVM_INT16 temp;
+
+ for (i = 0; i < n; i++)
+ {
+ /* Left channel */
+ temp = (LVM_INT16)((LVM_UINT32)((LVM_INT32)(*dst) + (LVM_INT32)delay[Offset]) >> 1);
+ *dst = temp;
+ dst++;
+
+ delay[Offset] = *src;
+ Offset++;
+ src++;
+
+ /* Right channel */
+ temp = (LVM_INT16)((LVM_UINT32)((LVM_INT32)(*dst) - (LVM_INT32)delay[Offset]) >> 1);
+ *dst = temp;
+ dst++;
+
+ delay[Offset] = *src;
+ Offset++;
+ src++;
+
+ /* Make the reverb delay buffer a circular buffer */
+ if (Offset >= size)
+ {
+ Offset = 0;
+ }
+ }
+
+ /* Update the offset */
+ *pOffset = Offset;
+
+ return;
+}
+void DelayMix_Float(const LVM_FLOAT *src, /* Source 1, to be delayed */
+ LVM_FLOAT *delay, /* Delay buffer */
+ LVM_INT16 size, /* Delay size */
+ LVM_FLOAT *dst, /* Source/destination */
+ LVM_INT16 *pOffset, /* Delay offset */
+ LVM_INT16 n) /* Number of stereo samples */
+{
+ LVM_INT16 i;
+ LVM_INT16 Offset = *pOffset;
+ LVM_FLOAT temp;
+
+ for (i=0; i<n; i++)
+ {
+ /* Left channel */
+ temp = (LVM_FLOAT)((LVM_FLOAT)(*dst + (LVM_FLOAT)delay[Offset]) / 2.0f);
+ *dst = temp;
+ dst++;
+
+ delay[Offset] = *src;
+ Offset++;
+ src++;
+
+ /* Right channel */
+ temp = (LVM_FLOAT)((LVM_FLOAT)(*dst - (LVM_FLOAT)delay[Offset]) / 2.0f);
+ *dst = temp;
+ dst++;
+
+ delay[Offset] = *src;
+ Offset++;
+ src++;
+
+ /* Make the reverb delay buffer a circular buffer */
+ if (Offset >= size)
+ {
+ Offset = 0;
+ }
+ }
+
+ /* Update the offset */
+ *pOffset = Offset;
+
+ return;
+}
+/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/DelayWrite_32.c b/media/libeffects/lvm/lib/Common/src/DelayWrite_32.cpp
similarity index 100%
rename from media/libeffects/lvm/lib/Common/src/DelayWrite_32.c
rename to media/libeffects/lvm/lib/Common/src/DelayWrite_32.cpp
diff --git a/media/libeffects/lvm/lib/Common/src/FO_1I_D16F16C15_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/FO_1I_D16F16C15_TRC_WRA_01.c
deleted file mode 100644
index 039c88c..0000000
--- a/media/libeffects/lvm/lib/Common/src/FO_1I_D16F16C15_TRC_WRA_01.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BIQUAD.h"
-#include "FO_1I_D16F16Css_TRC_WRA_01_Private.h"
-#include "LVM_Macros.h"
-
-/**************************************************************************
- ASSUMPTIONS:
- COEFS-
- pBiquadState->coefs[0] is A1,
- pBiquadState->coefs[1] is A0,
- pBiquadState->coefs[2] is -B1, these are in Q15 format
-
- DELAYS-
- pBiquadState->pDelays[0] is x(n-1)L in Q0 format
- pBiquadState->pDelays[1] is y(n-1)L in Q0 format
-***************************************************************************/
-
-#ifdef BUILD_FLOAT
-void FO_1I_D16F16C15_TRC_WRA_01( Biquad_FLOAT_Instance_t *pInstance,
- LVM_FLOAT *pDataIn,
- LVM_FLOAT *pDataOut,
- LVM_INT16 NrSamples)
- {
- LVM_FLOAT ynL;
- LVM_INT16 ii;
- PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
-
- for (ii = NrSamples; ii != 0; ii--)
- {
-
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
- // ynL=A1 * x(n-1)L
- ynL = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[0];
-
- // ynL+=A0 * x(n)L
- ynL += (LVM_FLOAT)pBiquadState->coefs[1] * (*pDataIn);
-
- // ynL+= (-B1 * y(n-1)L
- ynL += (LVM_FLOAT)pBiquadState->coefs[2] * pBiquadState->pDelays[1];
-
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[1] = ynL; // Update y(n-1)L
- pBiquadState->pDelays[0] = (*pDataIn++); // Update x(n-1)L
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut++ = (LVM_FLOAT)ynL; // Write Left output
-
- }
-
- }
-#else
-void FO_1I_D16F16C15_TRC_WRA_01( Biquad_Instance_t *pInstance,
- LVM_INT16 *pDataIn,
- LVM_INT16 *pDataOut,
- LVM_INT16 NrSamples)
- {
- LVM_INT32 ynL;
- LVM_INT16 ii;
- PFilter_State pBiquadState = (PFilter_State) pInstance;
-
- for (ii = NrSamples; ii != 0; ii--)
- {
-
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
- // ynL=A1 (Q15) * x(n-1)L (Q0) in Q15
- ynL=(LVM_INT32)pBiquadState->coefs[0]* pBiquadState->pDelays[0];
-
- // ynL+=A0 (Q15) * x(n)L (Q0) in Q15
- ynL+=(LVM_INT32)pBiquadState->coefs[1]* (*pDataIn);
-
- // ynL+= (-B1 (Q15) * y(n-1)L (Q0) ) in Q15
- ynL+=(LVM_INT32)pBiquadState->coefs[2]*pBiquadState->pDelays[1];
-
-
- ynL=(LVM_INT16)(ynL>>15); // ynL in Q0 format
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[1]=ynL; // Update y(n-1)L in Q0
- pBiquadState->pDelays[0]=(*pDataIn++); // Update x(n-1)L in Q0
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut++=(LVM_INT16)ynL; // Write Left output in Q0
-
- }
-
- }
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/FO_1I_D16F16C15_TRC_WRA_01.cpp b/media/libeffects/lvm/lib/Common/src/FO_1I_D16F16C15_TRC_WRA_01.cpp
new file mode 100644
index 0000000..bef0d62
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/FO_1I_D16F16C15_TRC_WRA_01.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BIQUAD.h"
+#include "FO_1I_D16F16Css_TRC_WRA_01_Private.h"
+#include "LVM_Macros.h"
+
+/**************************************************************************
+ ASSUMPTIONS:
+ COEFS-
+ pBiquadState->coefs[0] is A1,
+ pBiquadState->coefs[1] is A0,
+ pBiquadState->coefs[2] is -B1, these are in Q15 format
+
+ DELAYS-
+ pBiquadState->pDelays[0] is x(n-1)L in Q0 format
+ pBiquadState->pDelays[1] is y(n-1)L in Q0 format
+***************************************************************************/
+
+void FO_1I_D16F16C15_TRC_WRA_01( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+ {
+ LVM_FLOAT ynL;
+ LVM_INT16 ii;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+
+ for (ii = NrSamples; ii != 0; ii--)
+ {
+
+ /**************************************************************************
+ PROCESSING OF THE LEFT CHANNEL
+ ***************************************************************************/
+ // ynL=A1 * x(n-1)L
+ ynL = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[0];
+
+ // ynL+=A0 * x(n)L
+ ynL += (LVM_FLOAT)pBiquadState->coefs[1] * (*pDataIn);
+
+ // ynL+= (-B1 * y(n-1)L
+ ynL += (LVM_FLOAT)pBiquadState->coefs[2] * pBiquadState->pDelays[1];
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[1] = ynL; // Update y(n-1)L
+ pBiquadState->pDelays[0] = (*pDataIn++); // Update x(n-1)L
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+ *pDataOut++ = (LVM_FLOAT)ynL; // Write Left output
+
+ }
+
+ }
diff --git a/media/libeffects/lvm/lib/Common/src/FO_1I_D16F16Css_TRC_WRA_01_Init.c b/media/libeffects/lvm/lib/Common/src/FO_1I_D16F16Css_TRC_WRA_01_Init.c
deleted file mode 100644
index b21b8a4..0000000
--- a/media/libeffects/lvm/lib/Common/src/FO_1I_D16F16Css_TRC_WRA_01_Init.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*-------------------------------------------------------------------------*/
-#include "BIQUAD.h"
-#include "FO_1I_D16F16Css_TRC_WRA_01_Private.h"
-
-
-/*-------------------------------------------------------------------------*/
-/* FUNCTION: */
-/* FO_1I_D16F16Css_TRC_WRA_01_Init */
-/* */
-/* DESCRIPTION: */
-/* These functions initializes a BIQUAD filter defined as a cascade of */
-/* biquadratic Filter Sections. */
-/* */
-/* PARAMETERS: */
-/* pInstance - output, returns the pointer to the State Variable */
-/* This state pointer must be passed to any subsequent */
-/* call to "Biquad" functions. */
-/* pTaps - input, pointer to the taps memory */
-/* pCoef - input, pointer to the coefficient structure */
-/* N - M coefficient factor of QM.N */
-/* RETURNS: */
-/* void return code */
-/*-------------------------------------------------------------------------*/
-#ifdef BUILD_FLOAT
-void FO_1I_D16F16Css_TRC_WRA_01_Init( Biquad_FLOAT_Instance_t *pInstance,
- Biquad_1I_Order1_FLOAT_Taps_t *pTaps,
- FO_FLOAT_Coefs_t *pCoef)
-{
- LVM_FLOAT temp;
- PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
- pBiquadState->pDelays = (LVM_FLOAT *)pTaps;
- temp = pCoef->A1;
- pBiquadState->coefs[0] = temp;
- temp = pCoef->A0;
- pBiquadState->coefs[1] = temp;
- temp = pCoef->B1;
- pBiquadState->coefs[2] = temp;
-}
-#else
-void FO_1I_D16F16Css_TRC_WRA_01_Init( Biquad_Instance_t *pInstance,
- Biquad_1I_Order1_Taps_t *pTaps,
- FO_C16_Coefs_t *pCoef)
-{
- LVM_INT16 temp;
- PFilter_State pBiquadState = (PFilter_State) pInstance;
- pBiquadState->pDelays =(LVM_INT32 *) pTaps;
-
- temp=pCoef->A1;
- pBiquadState->coefs[0]=temp;
- temp=pCoef->A0;
- pBiquadState->coefs[1]=temp;
- temp=pCoef->B1;
- pBiquadState->coefs[2]=temp;
-}
-#endif
-/*------------------------------------------------*/
-/* End Of File: FO_1I_D16F16Css_TRC_WRA_01_Init.c */
-
diff --git a/media/libeffects/lvm/lib/Common/src/FO_1I_D16F16Css_TRC_WRA_01_Init.cpp b/media/libeffects/lvm/lib/Common/src/FO_1I_D16F16Css_TRC_WRA_01_Init.cpp
new file mode 100644
index 0000000..161225e
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/FO_1I_D16F16Css_TRC_WRA_01_Init.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*-------------------------------------------------------------------------*/
+#include "BIQUAD.h"
+#include "FO_1I_D16F16Css_TRC_WRA_01_Private.h"
+
+/*-------------------------------------------------------------------------*/
+/* FUNCTION: */
+/* FO_1I_D16F16Css_TRC_WRA_01_Init */
+/* */
+/* DESCRIPTION: */
+/* These functions initializes a BIQUAD filter defined as a cascade of */
+/* biquadratic Filter Sections. */
+/* */
+/* PARAMETERS: */
+/* pInstance - output, returns the pointer to the State Variable */
+/* This state pointer must be passed to any subsequent */
+/* call to "Biquad" functions. */
+/* pTaps - input, pointer to the taps memory */
+/* pCoef - input, pointer to the coefficient structure */
+/* N - M coefficient factor of QM.N */
+/* RETURNS: */
+/* void return code */
+/*-------------------------------------------------------------------------*/
+void FO_1I_D16F16Css_TRC_WRA_01_Init( Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_1I_Order1_FLOAT_Taps_t *pTaps,
+ FO_FLOAT_Coefs_t *pCoef)
+{
+ LVM_FLOAT temp;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+ pBiquadState->pDelays = (LVM_FLOAT *)pTaps;
+ temp = pCoef->A1;
+ pBiquadState->coefs[0] = temp;
+ temp = pCoef->A0;
+ pBiquadState->coefs[1] = temp;
+ temp = pCoef->B1;
+ pBiquadState->coefs[2] = temp;
+}
+/*------------------------------------------------*/
+/* End Of File: FO_1I_D16F16Css_TRC_WRA_01_Init.c */
+
diff --git a/media/libeffects/lvm/lib/Common/src/FO_1I_D16F16Css_TRC_WRA_01_Private.h b/media/libeffects/lvm/lib/Common/src/FO_1I_D16F16Css_TRC_WRA_01_Private.h
index 6fdb039..34f3df9 100644
--- a/media/libeffects/lvm/lib/Common/src/FO_1I_D16F16Css_TRC_WRA_01_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/FO_1I_D16F16Css_TRC_WRA_01_Private.h
@@ -28,7 +28,6 @@
typedef Filter_State * PFilter_State ;
-#ifdef BUILD_FLOAT
typedef struct _Filter_State_FLOAT
{
LVM_FLOAT * pDelays; /* pointer to the delayed samples \
@@ -37,5 +36,4 @@
}Filter_State_FLOAT;
typedef Filter_State_FLOAT * PFilter_State_FLOAT ;
-#endif
#endif /* _FO_1I_D16F16CSS_TRC_WRA_01_PRIVATE_H_ */
diff --git a/media/libeffects/lvm/lib/Common/src/FO_1I_D32F32C31_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/FO_1I_D32F32C31_TRC_WRA_01.c
deleted file mode 100644
index 416e8eb..0000000
--- a/media/libeffects/lvm/lib/Common/src/FO_1I_D32F32C31_TRC_WRA_01.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BIQUAD.h"
-#include "FO_1I_D32F32Cll_TRC_WRA_01_Private.h"
-#include "LVM_Macros.h"
-
-
-/**************************************************************************
- ASSUMPTIONS:
- COEFS-
- pBiquadState->coefs[0] is A1,
- pBiquadState->coefs[1] is A0,
- pBiquadState->coefs[2] is -B1, these are in Q31 format
-
- DELAYS-
- pBiquadState->pDelays[0] is x(n-1)L in Q0 format
- pBiquadState->pDelays[1] is y(n-1)L in Q0 format
-***************************************************************************/
-#ifdef BUILD_FLOAT
-void FO_1I_D32F32C31_TRC_WRA_01( Biquad_FLOAT_Instance_t *pInstance,
- LVM_FLOAT *pDataIn,
- LVM_FLOAT *pDataOut,
- LVM_INT16 NrSamples)
- {
- LVM_FLOAT ynL,templ;
- LVM_INT16 ii;
- PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
-
- for (ii = NrSamples; ii != 0; ii--)
- {
-
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
- // ynL=A1 * x(n-1)L
- ynL = pBiquadState->coefs[0] * pBiquadState->pDelays[0];
-
- // ynL+=A0 * x(n)L
- templ = pBiquadState->coefs[1] * (*pDataIn);
- ynL += templ;
-
- // ynL+= (-B1 * y(n-1)L
- templ = pBiquadState->coefs[2] * pBiquadState->pDelays[1];
- ynL += templ;
-
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[1] = ynL; // Update y(n-1)L
- pBiquadState->pDelays[0] = (*pDataIn++); // Update x(n-1)L
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut++ = (LVM_FLOAT)ynL; // Write Left output in Q0
- }
-
- }
-#else
-void FO_1I_D32F32C31_TRC_WRA_01( Biquad_Instance_t *pInstance,
- LVM_INT32 *pDataIn,
- LVM_INT32 *pDataOut,
- LVM_INT16 NrSamples)
- {
- LVM_INT32 ynL,templ;
- LVM_INT16 ii;
- PFilter_State pBiquadState = (PFilter_State) pInstance;
-
- for (ii = NrSamples; ii != 0; ii--)
- {
-
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
- // ynL=A1 (Q31) * x(n-1)L (Q0) >>31 in Q0
- MUL32x32INTO32(pBiquadState->coefs[0],pBiquadState->pDelays[0],ynL,31)
-
- // ynL+=A0 (Q31) * x(n)L (Q0) >> 31 in Q0
- MUL32x32INTO32(pBiquadState->coefs[1],*pDataIn,templ,31)
- ynL+=templ;
-
- // ynL+= (-B1 (Q31) * y(n-1)L (Q0) ) >> 31 in Q0
- MUL32x32INTO32(pBiquadState->coefs[2],pBiquadState->pDelays[1],templ,31)
- ynL+=templ;
-
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[1]=ynL; // Update y(n-1)L in Q0
- pBiquadState->pDelays[0]=(*pDataIn++); // Update x(n-1)L in Q0
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut++=(LVM_INT32)ynL; // Write Left output in Q0
- }
-
- }
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/FO_1I_D32F32C31_TRC_WRA_01.cpp b/media/libeffects/lvm/lib/Common/src/FO_1I_D32F32C31_TRC_WRA_01.cpp
new file mode 100644
index 0000000..e3efad7
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/FO_1I_D32F32C31_TRC_WRA_01.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BIQUAD.h"
+#include "FO_1I_D32F32Cll_TRC_WRA_01_Private.h"
+#include "LVM_Macros.h"
+
+/**************************************************************************
+ ASSUMPTIONS:
+ COEFS-
+ pBiquadState->coefs[0] is A1,
+ pBiquadState->coefs[1] is A0,
+ pBiquadState->coefs[2] is -B1, these are in Q31 format
+
+ DELAYS-
+ pBiquadState->pDelays[0] is x(n-1)L in Q0 format
+ pBiquadState->pDelays[1] is y(n-1)L in Q0 format
+***************************************************************************/
+void FO_1I_D32F32C31_TRC_WRA_01( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+ {
+ LVM_FLOAT ynL,templ;
+ LVM_INT16 ii;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+
+ for (ii = NrSamples; ii != 0; ii--)
+ {
+
+ /**************************************************************************
+ PROCESSING OF THE LEFT CHANNEL
+ ***************************************************************************/
+ // ynL=A1 * x(n-1)L
+ ynL = pBiquadState->coefs[0] * pBiquadState->pDelays[0];
+
+ // ynL+=A0 * x(n)L
+ templ = pBiquadState->coefs[1] * (*pDataIn);
+ ynL += templ;
+
+ // ynL+= (-B1 * y(n-1)L
+ templ = pBiquadState->coefs[2] * pBiquadState->pDelays[1];
+ ynL += templ;
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[1] = ynL; // Update y(n-1)L
+ pBiquadState->pDelays[0] = (*pDataIn++); // Update x(n-1)L
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+ *pDataOut++ = (LVM_FLOAT)ynL; // Write Left output in Q0
+ }
+
+ }
diff --git a/media/libeffects/lvm/lib/Common/src/FO_1I_D32F32Cll_TRC_WRA_01_Init.c b/media/libeffects/lvm/lib/Common/src/FO_1I_D32F32Cll_TRC_WRA_01_Init.c
deleted file mode 100644
index f33d24d..0000000
--- a/media/libeffects/lvm/lib/Common/src/FO_1I_D32F32Cll_TRC_WRA_01_Init.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BIQUAD.h"
-#include "FO_1I_D32F32Cll_TRC_WRA_01_Private.h"
-
-
-/*-------------------------------------------------------------------------*/
-/* FUNCTION: */
-/* FO_1I_D32F32Cll_TRC_WRA_01_Init */
-/* */
-/* DESCRIPTION: */
-/* These functions initializes a BIQUAD filter defined as a cascade of */
-/* biquadratic Filter Sections. */
-/* */
-/* PARAMETERS: */
-/* pInstance - output, returns the pointer to the State Variable */
-/* This state pointer must be passed to any subsequent */
-/* call to "Biquad" functions. */
-/* pTaps - input, pointer to the taps memory */
-/* pCoef - input, pointer to the coefficient structure */
-/* N - M coefficient factor of QM.N */
-/* RETURNS: */
-/* void return code */
-/*-------------------------------------------------------------------------*/
-#ifdef BUILD_FLOAT
-void FO_1I_D32F32Cll_TRC_WRA_01_Init( Biquad_FLOAT_Instance_t *pInstance,
- Biquad_1I_Order1_FLOAT_Taps_t *pTaps,
- FO_FLOAT_Coefs_t *pCoef)
-{
- LVM_FLOAT temp;
- PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
- pBiquadState->pDelays = (LVM_FLOAT *) pTaps;
-
- temp = pCoef->A1;
- pBiquadState->coefs[0] = temp;
- temp = pCoef->A0;
- pBiquadState->coefs[1] = temp;
- temp = pCoef->B1;
- pBiquadState->coefs[2] = temp;
-}
-#else
-void FO_1I_D32F32Cll_TRC_WRA_01_Init( Biquad_Instance_t *pInstance,
- Biquad_1I_Order1_Taps_t *pTaps,
- FO_C32_Coefs_t *pCoef)
-{
- LVM_INT32 temp;
- PFilter_State pBiquadState = (PFilter_State) pInstance;
- pBiquadState->pDelays = (LVM_INT32 *) pTaps;
-
- temp=pCoef->A1;
- pBiquadState->coefs[0]=temp;
- temp=pCoef->A0;
- pBiquadState->coefs[1]=temp;
- temp=pCoef->B1;
- pBiquadState->coefs[2]=temp;
-}
-#endif
-/*------------------------------------------------*/
-/* End Of File: FO_1I_D32F32Cll_TRC_WRA_01_Init.c */
-
diff --git a/media/libeffects/lvm/lib/Common/src/FO_1I_D32F32Cll_TRC_WRA_01_Init.cpp b/media/libeffects/lvm/lib/Common/src/FO_1I_D32F32Cll_TRC_WRA_01_Init.cpp
new file mode 100644
index 0000000..bb5295c
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/FO_1I_D32F32Cll_TRC_WRA_01_Init.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BIQUAD.h"
+#include "FO_1I_D32F32Cll_TRC_WRA_01_Private.h"
+
+/*-------------------------------------------------------------------------*/
+/* FUNCTION: */
+/* FO_1I_D32F32Cll_TRC_WRA_01_Init */
+/* */
+/* DESCRIPTION: */
+/* These functions initializes a BIQUAD filter defined as a cascade of */
+/* biquadratic Filter Sections. */
+/* */
+/* PARAMETERS: */
+/* pInstance - output, returns the pointer to the State Variable */
+/* This state pointer must be passed to any subsequent */
+/* call to "Biquad" functions. */
+/* pTaps - input, pointer to the taps memory */
+/* pCoef - input, pointer to the coefficient structure */
+/* N - M coefficient factor of QM.N */
+/* RETURNS: */
+/* void return code */
+/*-------------------------------------------------------------------------*/
+void FO_1I_D32F32Cll_TRC_WRA_01_Init( Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_1I_Order1_FLOAT_Taps_t *pTaps,
+ FO_FLOAT_Coefs_t *pCoef)
+{
+ LVM_FLOAT temp;
+ PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+ pBiquadState->pDelays = (LVM_FLOAT *) pTaps;
+
+ temp = pCoef->A1;
+ pBiquadState->coefs[0] = temp;
+ temp = pCoef->A0;
+ pBiquadState->coefs[1] = temp;
+ temp = pCoef->B1;
+ pBiquadState->coefs[2] = temp;
+}
+/*------------------------------------------------*/
+/* End Of File: FO_1I_D32F32Cll_TRC_WRA_01_Init.c */
+
diff --git a/media/libeffects/lvm/lib/Common/src/FO_1I_D32F32Cll_TRC_WRA_01_Private.h b/media/libeffects/lvm/lib/Common/src/FO_1I_D32F32Cll_TRC_WRA_01_Private.h
index fdb528b..67d1384 100644
--- a/media/libeffects/lvm/lib/Common/src/FO_1I_D32F32Cll_TRC_WRA_01_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/FO_1I_D32F32Cll_TRC_WRA_01_Private.h
@@ -18,7 +18,6 @@
#ifndef _FO_1I_D32F32CLL_TRC_WRA_01_PRIVATE_H_
#define _FO_1I_D32F32CLL_TRC_WRA_01_PRIVATE_H_
-
/* The internal state variables are implemented in a (for the user) hidden structure */
/* In this (private) file, the internal structure is declared fro private use. */
typedef struct _Filter_State_
@@ -29,7 +28,6 @@
typedef Filter_State * PFilter_State ;
-#ifdef BUILD_FLOAT
typedef struct _Filter_State_FLOAT_
{
LVM_FLOAT * pDelays; /* pointer to the delayed samples (data of 32 bits) */
@@ -37,5 +35,4 @@
}Filter_State_FLOAT;
typedef Filter_State_FLOAT * PFilter_State_FLOAT ;
-#endif
#endif /* _FO_1I_D32F32CLL_TRC_WRA_01_PRIVATE_H_ */
diff --git a/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32C15_LShx_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32C15_LShx_TRC_WRA_01.c
deleted file mode 100644
index 2a50f18..0000000
--- a/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32C15_LShx_TRC_WRA_01.c
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BIQUAD.h"
-#include "FO_2I_D16F32Css_LShx_TRC_WRA_01_Private.h"
-#include "LVM_Macros.h"
-
-/**************************************************************************
-ASSUMPTIONS:
-COEFS-
-pBiquadState->coefs[0] is A1,
-pBiquadState->coefs[1] is A0,
-pBiquadState->coefs[2] is -B1, these are in Q15 format
-pBiquadState->Shift is Shift value
-DELAYS-
-pBiquadState->pDelays[0] is x(n-1)L in Q15 format
-pBiquadState->pDelays[1] is y(n-1)L in Q30 format
-pBiquadState->pDelays[2] is x(n-1)R in Q15 format
-pBiquadState->pDelays[3] is y(n-1)R in Q30 format
-***************************************************************************/
-#ifdef BUILD_FLOAT
-void FO_2I_D16F32C15_LShx_TRC_WRA_01(Biquad_FLOAT_Instance_t *pInstance,
- LVM_FLOAT *pDataIn,
- LVM_FLOAT *pDataOut,
- LVM_INT16 NrSamples)
- {
- LVM_FLOAT ynL,ynR;
- LVM_FLOAT Temp;
- LVM_FLOAT NegSatValue;
- LVM_INT16 ii;
-
- PFilter_Float_State pBiquadState = (PFilter_Float_State) pInstance;
-
- NegSatValue = -1.0f;
-
- for (ii = NrSamples; ii != 0; ii--)
- {
-
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
-
- // ynL =A1 * x(n-1)L
- ynL = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[0];
- // ynR =A1 * x(n-1)R
- ynR = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[2];
-
-
- // ynL+=A0 * x(n)L
- ynL += (LVM_FLOAT)pBiquadState->coefs[1] * (*pDataIn);
- // ynR+=A0 * x(n)L
- ynR += (LVM_FLOAT)pBiquadState->coefs[1] * (*(pDataIn+1));
-
-
- // ynL += (-B1 * y(n-1)L )
- Temp = pBiquadState->pDelays[1] * pBiquadState->coefs[2];
- ynL += Temp;
- // ynR += (-B1 * y(n-1)R ) )
- Temp = pBiquadState->pDelays[3] * pBiquadState->coefs[2];
- ynR += Temp;
-
-
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[1] = ynL; // Update y(n-1)L
- pBiquadState->pDelays[0] = (*pDataIn++); // Update x(n-1)L
-
- pBiquadState->pDelays[3] = ynR; // Update y(n-1)R
- pBiquadState->pDelays[2] = (*pDataIn++); // Update x(n-1)R
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
-
- /*Saturate results*/
- if(ynL > 1.0f)
- {
- ynL = 1.0f;
- }
- else
- {
- if(ynL < NegSatValue)
- {
- ynL = NegSatValue;
- }
- }
-
- if(ynR > 1.0f)
- {
- ynR = 1.0f;
- }
- else
- {
- if(ynR < NegSatValue)
- {
- ynR = NegSatValue;
- }
- }
-
- *pDataOut++ = (LVM_FLOAT)ynL;
- *pDataOut++ = (LVM_FLOAT)ynR;
- }
-
- }
-#ifdef SUPPORT_MC
-/**************************************************************************
-ASSUMPTIONS:
-COEFS-
-pBiquadState->coefs[0] is A1,
-pBiquadState->coefs[1] is A0,
-pBiquadState->coefs[2] is -B1,
-DELAYS-
-pBiquadState->pDelays[2*ch + 0] is x(n-1) of the 'ch' - channel
-pBiquadState->pDelays[2*ch + 1] is y(n-1) of the 'ch' - channel
-The index 'ch' runs from 0 to (NrChannels - 1)
-
-PARAMETERS:
- pInstance Pointer Instance
- pDataIn Input/Source
- pDataOut Output/Destination
- NrFrames Number of frames
- NrChannels Number of channels
-
-RETURNS:
- void
-***************************************************************************/
-void FO_Mc_D16F32C15_LShx_TRC_WRA_01(Biquad_FLOAT_Instance_t *pInstance,
- LVM_FLOAT *pDataIn,
- LVM_FLOAT *pDataOut,
- LVM_INT16 NrFrames,
- LVM_INT16 NrChannels)
- {
- LVM_FLOAT yn;
- LVM_FLOAT Temp;
- LVM_INT16 ii;
- LVM_INT16 ch;
- PFilter_Float_State pBiquadState = (PFilter_Float_State) pInstance;
-
- LVM_FLOAT *pDelays = pBiquadState->pDelays;
- LVM_FLOAT *pCoefs = &pBiquadState->coefs[0];
- LVM_FLOAT A0 = pCoefs[1];
- LVM_FLOAT A1 = pCoefs[0];
- LVM_FLOAT B1 = pCoefs[2];
-
-
-
-
- for (ii = NrFrames; ii != 0; ii--)
- {
-
- /**************************************************************************
- PROCESSING OF THE CHANNELS
- ***************************************************************************/
- for (ch = 0; ch < NrChannels; ch++)
- {
- // yn =A1 * x(n-1)
- yn = (LVM_FLOAT)A1 * pDelays[0];
-
- // yn+=A0 * x(n)
- yn += (LVM_FLOAT)A0 * (*pDataIn);
-
- // yn += (-B1 * y(n-1))
- Temp = B1 * pDelays[1];
- yn += Temp;
-
-
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pDelays[1] = yn; // Update y(n-1)
- pDelays[0] = (*pDataIn++); // Update x(n-1)
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
-
- /*Saturate results*/
- if (yn > 1.0f)
- {
- yn = 1.0f;
- } else if (yn < -1.0f) {
- yn = -1.0f;
- }
-
- *pDataOut++ = (LVM_FLOAT)yn;
- pDelays += 2;
- }
- pDelays -= NrChannels * 2;
- }
- }
-#endif
-#else
-void FO_2I_D16F32C15_LShx_TRC_WRA_01(Biquad_Instance_t *pInstance,
- LVM_INT16 *pDataIn,
- LVM_INT16 *pDataOut,
- LVM_INT16 NrSamples)
- {
- LVM_INT32 ynL,ynR;
- LVM_INT32 Temp;
- LVM_INT32 NegSatValue;
- LVM_INT16 ii;
- LVM_INT16 Shift;
- PFilter_State pBiquadState = (PFilter_State) pInstance;
-
- NegSatValue = LVM_MAXINT_16 +1;
- NegSatValue = -NegSatValue;
-
- Shift = pBiquadState->Shift;
-
-
- for (ii = NrSamples; ii != 0; ii--)
- {
-
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
-
- // ynL =A1 (Q15) * x(n-1)L (Q15) in Q30
- ynL=(LVM_INT32)pBiquadState->coefs[0]* pBiquadState->pDelays[0];
- // ynR =A1 (Q15) * x(n-1)R (Q15) in Q30
- ynR=(LVM_INT32)pBiquadState->coefs[0]* pBiquadState->pDelays[2];
-
-
- // ynL+=A0 (Q15) * x(n)L (Q15) in Q30
- ynL+=(LVM_INT32)pBiquadState->coefs[1]* (*pDataIn);
- // ynR+=A0 (Q15) * x(n)L (Q15) in Q30
- ynR+=(LVM_INT32)pBiquadState->coefs[1]* (*(pDataIn+1));
-
-
- // ynL += (-B1 (Q15) * y(n-1)L (Q30) ) in Q30
- MUL32x16INTO32(pBiquadState->pDelays[1],pBiquadState->coefs[2],Temp,15);
- ynL +=Temp;
- // ynR += (-B1 (Q15) * y(n-1)R (Q30) ) in Q30
- MUL32x16INTO32(pBiquadState->pDelays[3],pBiquadState->coefs[2],Temp,15);
- ynR +=Temp;
-
-
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[1]=ynL; // Update y(n-1)L in Q30
- pBiquadState->pDelays[0]=(*pDataIn++); // Update x(n-1)L in Q15
-
- pBiquadState->pDelays[3]=ynR; // Update y(n-1)R in Q30
- pBiquadState->pDelays[2]=(*pDataIn++); // Update x(n-1)R in Q15
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- /*Apply shift: Instead of left shift on 16-bit result, right shift of (15-shift) is applied
- for better SNR*/
- ynL = ynL>>(15-Shift);
- ynR = ynR>>(15-Shift);
-
- /*Saturate results*/
- if(ynL > LVM_MAXINT_16)
- {
- ynL = LVM_MAXINT_16;
- }
- else
- {
- if(ynL < NegSatValue)
- {
- ynL = NegSatValue;
- }
- }
-
- if(ynR > LVM_MAXINT_16)
- {
- ynR = LVM_MAXINT_16;
- }
- else
- {
- if(ynR < NegSatValue)
- {
- ynR = NegSatValue;
- }
- }
-
- *pDataOut++=(LVM_INT16)ynL;
- *pDataOut++=(LVM_INT16)ynR;
- }
-
- }
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32C15_LShx_TRC_WRA_01.cpp b/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32C15_LShx_TRC_WRA_01.cpp
new file mode 100644
index 0000000..6ca819a
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32C15_LShx_TRC_WRA_01.cpp
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BIQUAD.h"
+#include "FO_2I_D16F32Css_LShx_TRC_WRA_01_Private.h"
+#include "LVM_Macros.h"
+
+/**************************************************************************
+ASSUMPTIONS:
+COEFS-
+pBiquadState->coefs[0] is A1,
+pBiquadState->coefs[1] is A0,
+pBiquadState->coefs[2] is -B1, these are in Q15 format
+pBiquadState->Shift is Shift value
+DELAYS-
+pBiquadState->pDelays[0] is x(n-1)L in Q15 format
+pBiquadState->pDelays[1] is y(n-1)L in Q30 format
+pBiquadState->pDelays[2] is x(n-1)R in Q15 format
+pBiquadState->pDelays[3] is y(n-1)R in Q30 format
+***************************************************************************/
+void FO_2I_D16F32C15_LShx_TRC_WRA_01(Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+ {
+ LVM_FLOAT ynL,ynR;
+ LVM_FLOAT Temp;
+ LVM_FLOAT NegSatValue;
+ LVM_INT16 ii;
+
+ PFilter_Float_State pBiquadState = (PFilter_Float_State) pInstance;
+
+ NegSatValue = -1.0f;
+
+ for (ii = NrSamples; ii != 0; ii--)
+ {
+
+ /**************************************************************************
+ PROCESSING OF THE LEFT CHANNEL
+ ***************************************************************************/
+
+ // ynL =A1 * x(n-1)L
+ ynL = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[0];
+ // ynR =A1 * x(n-1)R
+ ynR = (LVM_FLOAT)pBiquadState->coefs[0] * pBiquadState->pDelays[2];
+
+ // ynL+=A0 * x(n)L
+ ynL += (LVM_FLOAT)pBiquadState->coefs[1] * (*pDataIn);
+ // ynR+=A0 * x(n)L
+ ynR += (LVM_FLOAT)pBiquadState->coefs[1] * (*(pDataIn+1));
+
+ // ynL += (-B1 * y(n-1)L )
+ Temp = pBiquadState->pDelays[1] * pBiquadState->coefs[2];
+ ynL += Temp;
+ // ynR += (-B1 * y(n-1)R ) )
+ Temp = pBiquadState->pDelays[3] * pBiquadState->coefs[2];
+ ynR += Temp;
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[1] = ynL; // Update y(n-1)L
+ pBiquadState->pDelays[0] = (*pDataIn++); // Update x(n-1)L
+
+ pBiquadState->pDelays[3] = ynR; // Update y(n-1)R
+ pBiquadState->pDelays[2] = (*pDataIn++); // Update x(n-1)R
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+
+ /*Saturate results*/
+ if(ynL > 1.0f)
+ {
+ ynL = 1.0f;
+ }
+ else
+ {
+ if(ynL < NegSatValue)
+ {
+ ynL = NegSatValue;
+ }
+ }
+
+ if(ynR > 1.0f)
+ {
+ ynR = 1.0f;
+ }
+ else
+ {
+ if(ynR < NegSatValue)
+ {
+ ynR = NegSatValue;
+ }
+ }
+
+ *pDataOut++ = (LVM_FLOAT)ynL;
+ *pDataOut++ = (LVM_FLOAT)ynR;
+ }
+
+ }
+#ifdef SUPPORT_MC
+/**************************************************************************
+ASSUMPTIONS:
+COEFS-
+pBiquadState->coefs[0] is A1,
+pBiquadState->coefs[1] is A0,
+pBiquadState->coefs[2] is -B1,
+DELAYS-
+pBiquadState->pDelays[2*ch + 0] is x(n-1) of the 'ch' - channel
+pBiquadState->pDelays[2*ch + 1] is y(n-1) of the 'ch' - channel
+The index 'ch' runs from 0 to (NrChannels - 1)
+
+PARAMETERS:
+ pInstance Pointer Instance
+ pDataIn Input/Source
+ pDataOut Output/Destination
+ NrFrames Number of frames
+ NrChannels Number of channels
+
+RETURNS:
+ void
+***************************************************************************/
+void FO_Mc_D16F32C15_LShx_TRC_WRA_01(Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrFrames,
+ LVM_INT16 NrChannels)
+ {
+ LVM_FLOAT yn;
+ LVM_FLOAT Temp;
+ LVM_INT16 ii;
+ LVM_INT16 ch;
+ PFilter_Float_State pBiquadState = (PFilter_Float_State) pInstance;
+
+ LVM_FLOAT *pDelays = pBiquadState->pDelays;
+ LVM_FLOAT *pCoefs = &pBiquadState->coefs[0];
+ LVM_FLOAT A0 = pCoefs[1];
+ LVM_FLOAT A1 = pCoefs[0];
+ LVM_FLOAT B1 = pCoefs[2];
+
+ for (ii = NrFrames; ii != 0; ii--)
+ {
+
+ /**************************************************************************
+ PROCESSING OF THE CHANNELS
+ ***************************************************************************/
+ for (ch = 0; ch < NrChannels; ch++)
+ {
+ // yn =A1 * x(n-1)
+ yn = (LVM_FLOAT)A1 * pDelays[0];
+
+ // yn+=A0 * x(n)
+ yn += (LVM_FLOAT)A0 * (*pDataIn);
+
+ // yn += (-B1 * y(n-1))
+ Temp = B1 * pDelays[1];
+ yn += Temp;
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pDelays[1] = yn; // Update y(n-1)
+ pDelays[0] = (*pDataIn++); // Update x(n-1)
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+
+ /*Saturate results*/
+ if (yn > 1.0f)
+ {
+ yn = 1.0f;
+ } else if (yn < -1.0f) {
+ yn = -1.0f;
+ }
+
+ *pDataOut++ = (LVM_FLOAT)yn;
+ pDelays += 2;
+ }
+ pDelays -= NrChannels * 2;
+ }
+ }
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32Css_LShx_TRC_WRA_01_Init.c b/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32Css_LShx_TRC_WRA_01_Init.c
deleted file mode 100644
index 33ca6cf..0000000
--- a/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32Css_LShx_TRC_WRA_01_Init.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*-------------------------------------------------------------------------*/
-#include "BIQUAD.h"
-#include "FO_2I_D16F32Css_LShx_TRC_WRA_01_Private.h"
-
-/*-------------------------------------------------------------------------*/
-/* FUNCTION: */
-/* FO_2I_D16F32Css_LShx_TRC_WRA_01_Init */
-/* */
-/* DESCRIPTION: */
-/* These functions initializes a BIQUAD filter defined as a cascade of */
-/* biquadratic Filter Sections. */
-/* */
-/* PARAMETERS: */
-/* pInstance - output, returns the pointer to the State Variable */
-/* This state pointer must be passed to any subsequent */
-/* call to "Biquad" functions. */
-/* pTaps - input, pointer to the taps memory */
-/* pCoef - input, pointer to the coefficient structure */
-/* N - M coefficient factor of QM.N */
-/* RETURNS: */
-/* void return code */
-/*-------------------------------------------------------------------------*/
-#ifdef BUILD_FLOAT
-void FO_2I_D16F32Css_LShx_TRC_WRA_01_Init(Biquad_FLOAT_Instance_t *pInstance,
- Biquad_2I_Order1_FLOAT_Taps_t *pTaps,
- FO_FLOAT_LShx_Coefs_t *pCoef)
-{
- LVM_FLOAT temp;
- PFilter_Float_State pBiquadState = (PFilter_Float_State) pInstance;
- pBiquadState->pDelays = (LVM_FLOAT *) pTaps ;
-
- temp = pCoef->A1;
- pBiquadState->coefs[0] = temp;
- temp = pCoef->A0;
- pBiquadState->coefs[1] = temp;
- temp = pCoef->B1;
- pBiquadState->coefs[2] = temp;
-}
-#else
-void FO_2I_D16F32Css_LShx_TRC_WRA_01_Init(Biquad_Instance_t *pInstance,
- Biquad_2I_Order1_Taps_t *pTaps,
- FO_C16_LShx_Coefs_t *pCoef)
-{
- LVM_INT16 temp;
- PFilter_State pBiquadState = (PFilter_State) pInstance;
- pBiquadState->pDelays =(LVM_INT32 *) pTaps ;
-
- temp=pCoef->A1;
- pBiquadState->coefs[0]=temp;
- temp=pCoef->A0;
- pBiquadState->coefs[1]=temp;
- temp=pCoef->B1;
- pBiquadState->coefs[2]=temp;
-
- temp=pCoef->Shift;
- pBiquadState->Shift = temp;
-}
-#endif
-/*-------------------------------------------------------------------------*/
-/* End Of File: FO_2I_D16F32Css_LShx_TRC_WRA_01_Init.c */
-
diff --git a/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32Css_LShx_TRC_WRA_01_Init.cpp b/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32Css_LShx_TRC_WRA_01_Init.cpp
new file mode 100644
index 0000000..b81b976
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32Css_LShx_TRC_WRA_01_Init.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*-------------------------------------------------------------------------*/
+#include "BIQUAD.h"
+#include "FO_2I_D16F32Css_LShx_TRC_WRA_01_Private.h"
+
+/*-------------------------------------------------------------------------*/
+/* FUNCTION: */
+/* FO_2I_D16F32Css_LShx_TRC_WRA_01_Init */
+/* */
+/* DESCRIPTION: */
+/* These functions initializes a BIQUAD filter defined as a cascade of */
+/* biquadratic Filter Sections. */
+/* */
+/* PARAMETERS: */
+/* pInstance - output, returns the pointer to the State Variable */
+/* This state pointer must be passed to any subsequent */
+/* call to "Biquad" functions. */
+/* pTaps - input, pointer to the taps memory */
+/* pCoef - input, pointer to the coefficient structure */
+/* N - M coefficient factor of QM.N */
+/* RETURNS: */
+/* void return code */
+/*-------------------------------------------------------------------------*/
+void FO_2I_D16F32Css_LShx_TRC_WRA_01_Init(Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_2I_Order1_FLOAT_Taps_t *pTaps,
+ FO_FLOAT_LShx_Coefs_t *pCoef)
+{
+ LVM_FLOAT temp;
+ PFilter_Float_State pBiquadState = (PFilter_Float_State) pInstance;
+ pBiquadState->pDelays = (LVM_FLOAT *) pTaps ;
+
+ temp = pCoef->A1;
+ pBiquadState->coefs[0] = temp;
+ temp = pCoef->A0;
+ pBiquadState->coefs[1] = temp;
+ temp = pCoef->B1;
+ pBiquadState->coefs[2] = temp;
+}
+/*-------------------------------------------------------------------------*/
+/* End Of File: FO_2I_D16F32Css_LShx_TRC_WRA_01_Init.c */
+
diff --git a/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32Css_LShx_TRC_WRA_01_Private.h b/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32Css_LShx_TRC_WRA_01_Private.h
index 368bfce..5022500 100644
--- a/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32Css_LShx_TRC_WRA_01_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32Css_LShx_TRC_WRA_01_Private.h
@@ -20,7 +20,6 @@
/* The internal state variables are implemented in a (for the user) hidden structure */
/* In this (private) file, the internal structure is declared fro private use. */
-#ifdef BUILD_FLOAT
typedef struct _Filter_State_
{
LVM_FLOAT *pDelays; /* pointer to the delayed samples (data of 32 bits) */
@@ -28,14 +27,4 @@
}Filter_Float_State;
typedef Filter_Float_State * PFilter_Float_State ;
-#else
-typedef struct _Filter_State_
-{
- LVM_INT32 *pDelays; /* pointer to the delayed samples (data of 32 bits) */
- LVM_INT16 coefs[3]; /* pointer to the filter coefficients */
- LVM_INT16 Shift; /* Shift value*/
-}Filter_State;
-
-typedef Filter_State * PFilter_State ;
-#endif
#endif /* _FO_2I_D16F32CSS_LSHX_TRC_WRA_01_PRIVATE_H_ */
diff --git a/media/libeffects/lvm/lib/Common/src/Filters.h b/media/libeffects/lvm/lib/Common/src/Filters.h
index b1fde0c..b5db8f4 100644
--- a/media/libeffects/lvm/lib/Common/src/Filters.h
+++ b/media/libeffects/lvm/lib/Common/src/Filters.h
@@ -18,10 +18,6 @@
#ifndef FILTERS_H
#define FILTERS_H
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
#include "LVM_Types.h"
/************************************************************************************/
@@ -34,17 +30,6 @@
* Biquad with coefficients A0, A1, A2, B1 and B2 coefficients
*/
/* Single precision (16-bit) Biquad section coefficients */
-#ifndef BUILD_FLOAT
-typedef struct
-{
- LVM_INT16 A0;
- LVM_INT16 A1;
- LVM_INT16 A2;
- LVM_INT16 B1;
- LVM_INT16 B2;
- LVM_UINT16 Scale;
-} BiquadA012B12CoefsSP_t;
-#else
typedef struct
{
LVM_FLOAT A0;
@@ -54,20 +39,10 @@
LVM_FLOAT B2;
LVM_UINT16 Scale;
} BiquadA012B12CoefsSP_t;
-#endif
/*
* Biquad with coefficients A0, A1 and B1 coefficients
*/
/* Single precision (16-bit) Biquad section coefficients */
-#ifndef BUILD_FLOAT
-typedef struct
-{
- LVM_INT16 A0;
- LVM_INT16 A1;
- LVM_INT16 B1;
- LVM_UINT16 Scale;
-} BiquadA01B1CoefsSP_t;
-#else
typedef struct
{
LVM_FLOAT A0;
@@ -75,10 +50,6 @@
LVM_FLOAT B1;
LVM_UINT16 Scale;
} BiquadA01B1CoefsSP_t;
-#endif
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
#endif /* FILTERS_H */
diff --git a/media/libeffects/lvm/lib/Common/src/From2iToMS_16x16.c b/media/libeffects/lvm/lib/Common/src/From2iToMS_16x16.c
deleted file mode 100644
index 2c6e6c3..0000000
--- a/media/libeffects/lvm/lib/Common/src/From2iToMS_16x16.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**********************************************************************************
- INCLUDE FILES
-***********************************************************************************/
-
-#include "VectorArithmetic.h"
-
-/**********************************************************************************
- FUNCTION From2iToMS_16x16
-***********************************************************************************/
-
-void From2iToMS_16x16( const LVM_INT16 *src,
- LVM_INT16 *dstM,
- LVM_INT16 *dstS,
- LVM_INT16 n )
-{
- LVM_INT32 temp1,left,right;
- LVM_INT16 ii;
- for (ii = n; ii != 0; ii--)
- {
- left = (LVM_INT32)*src;
- src++;
-
- right = (LVM_INT32)*src;
- src++;
-
- /* Compute M signal*/
- temp1 = (left+right)>>1;
- *dstM = (LVM_INT16)temp1;
- dstM++;
-
- /* Compute S signal*/
- temp1 = (left-right)>>1;
- *dstS = (LVM_INT16)temp1;
- dstS++;
- }
-
- return;
-}
-#ifdef BUILD_FLOAT
-void From2iToMS_Float( const LVM_FLOAT *src,
- LVM_FLOAT *dstM,
- LVM_FLOAT *dstS,
- LVM_INT16 n )
-{
- LVM_FLOAT temp1,left,right;
- LVM_INT16 ii;
- for (ii = n; ii != 0; ii--)
- {
- left = (LVM_FLOAT)*src;
- src++;
-
- right = (LVM_FLOAT)*src;
- src++;
-
- /* Compute M signal*/
- temp1 = (left + right) / 2.0f;
- *dstM = (LVM_FLOAT)temp1;
- dstM++;
-
- /* Compute S signal*/
- temp1 = (left - right) / 2.0f;
- *dstS = (LVM_FLOAT)temp1;
- dstS++;
- }
-
- return;
-}
-#endif
-/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/From2iToMS_16x16.cpp b/media/libeffects/lvm/lib/Common/src/From2iToMS_16x16.cpp
new file mode 100644
index 0000000..c3f6648
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/From2iToMS_16x16.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**********************************************************************************
+ INCLUDE FILES
+***********************************************************************************/
+
+#include "VectorArithmetic.h"
+
+/**********************************************************************************
+ FUNCTION From2iToMS_16x16
+***********************************************************************************/
+
+void From2iToMS_16x16( const LVM_INT16 *src,
+ LVM_INT16 *dstM,
+ LVM_INT16 *dstS,
+ LVM_INT16 n )
+{
+ LVM_INT32 temp1,left,right;
+ LVM_INT16 ii;
+ for (ii = n; ii != 0; ii--)
+ {
+ left = (LVM_INT32)*src;
+ src++;
+
+ right = (LVM_INT32)*src;
+ src++;
+
+ /* Compute M signal*/
+ temp1 = (left+right)>>1;
+ *dstM = (LVM_INT16)temp1;
+ dstM++;
+
+ /* Compute S signal*/
+ temp1 = (left-right)>>1;
+ *dstS = (LVM_INT16)temp1;
+ dstS++;
+ }
+
+ return;
+}
+void From2iToMS_Float( const LVM_FLOAT *src,
+ LVM_FLOAT *dstM,
+ LVM_FLOAT *dstS,
+ LVM_INT16 n )
+{
+ LVM_FLOAT temp1,left,right;
+ LVM_INT16 ii;
+ for (ii = n; ii != 0; ii--)
+ {
+ left = (LVM_FLOAT)*src;
+ src++;
+
+ right = (LVM_FLOAT)*src;
+ src++;
+
+ /* Compute M signal*/
+ temp1 = (left + right) / 2.0f;
+ *dstM = (LVM_FLOAT)temp1;
+ dstM++;
+
+ /* Compute S signal*/
+ temp1 = (left - right) / 2.0f;
+ *dstS = (LVM_FLOAT)temp1;
+ dstS++;
+ }
+
+ return;
+}
+/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/From2iToMono_16.c b/media/libeffects/lvm/lib/Common/src/From2iToMono_16.cpp
similarity index 100%
rename from media/libeffects/lvm/lib/Common/src/From2iToMono_16.c
rename to media/libeffects/lvm/lib/Common/src/From2iToMono_16.cpp
diff --git a/media/libeffects/lvm/lib/Common/src/From2iToMono_32.c b/media/libeffects/lvm/lib/Common/src/From2iToMono_32.c
deleted file mode 100644
index d02af88..0000000
--- a/media/libeffects/lvm/lib/Common/src/From2iToMono_32.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**********************************************************************************
- INCLUDE FILES
-***********************************************************************************/
-
-#include "VectorArithmetic.h"
-
-/**********************************************************************************
- FUNCTION From2iToMono_32
-***********************************************************************************/
-
-void From2iToMono_32( const LVM_INT32 *src,
- LVM_INT32 *dst,
- LVM_INT16 n)
-{
- LVM_INT16 ii;
- LVM_INT32 Temp;
-
- for (ii = n; ii != 0; ii--)
- {
- Temp = (*src>>1);
- src++;
-
- Temp +=(*src>>1);
- src++;
-
- *dst = Temp;
- dst++;
- }
-
- return;
-}
-#ifdef BUILD_FLOAT
-void From2iToMono_Float( const LVM_FLOAT *src,
- LVM_FLOAT *dst,
- LVM_INT16 n)
-{
- LVM_INT16 ii;
- LVM_FLOAT Temp;
-
- for (ii = n; ii != 0; ii--)
- {
- Temp = (*src);
- src++;
-
- Temp += (*src);
- src++;
-
- *dst = Temp / 2.0f;
- dst++;
- }
-
- return;
-}
-#ifdef SUPPORT_MC
-/*
- * FUNCTION: FromMcToMono_Float
- *
- * DESCRIPTION:
- * Creates a mono stream from a multichannel input taking the avergae of
- * sample values of all channels
- *
- * PARAMETERS:
- * src Source
- * dst Destination
- * NrFrames Number of frames
- * NrChannels Number of channels
- *
- * RETURNS:
- * void
- *
- */
-void FromMcToMono_Float(const LVM_FLOAT *src,
- LVM_FLOAT *dst,
- LVM_INT16 NrFrames,
- LVM_INT16 NrChannels)
-{
- LVM_INT16 ii, jj;
- LVM_FLOAT Temp;
-
- for (ii = NrFrames; ii != 0; ii--)
- {
- Temp = 0.0f;
- for (jj = NrChannels; jj !=0; jj--)
- {
- Temp += (*src);
- src++;
- }
- *dst = Temp / NrChannels;
- dst++;
- }
-
- return;
-}
-#endif
-
-#endif
-/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/From2iToMono_32.cpp b/media/libeffects/lvm/lib/Common/src/From2iToMono_32.cpp
new file mode 100644
index 0000000..a8688b4
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/From2iToMono_32.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**********************************************************************************
+ INCLUDE FILES
+***********************************************************************************/
+
+#include "VectorArithmetic.h"
+
+/**********************************************************************************
+ FUNCTION From2iToMono_32
+***********************************************************************************/
+
+void From2iToMono_32( const LVM_INT32 *src,
+ LVM_INT32 *dst,
+ LVM_INT16 n)
+{
+ LVM_INT16 ii;
+ LVM_INT32 Temp;
+
+ for (ii = n; ii != 0; ii--)
+ {
+ Temp = (*src>>1);
+ src++;
+
+ Temp +=(*src>>1);
+ src++;
+
+ *dst = Temp;
+ dst++;
+ }
+
+ return;
+}
+void From2iToMono_Float( const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ LVM_INT16 ii;
+ LVM_FLOAT Temp;
+
+ for (ii = n; ii != 0; ii--)
+ {
+ Temp = (*src);
+ src++;
+
+ Temp += (*src);
+ src++;
+
+ *dst = Temp / 2.0f;
+ dst++;
+ }
+
+ return;
+}
+#ifdef SUPPORT_MC
+/*
+ * FUNCTION: FromMcToMono_Float
+ *
+ * DESCRIPTION:
+ * Creates a mono stream from a multichannel input taking the avergae of
+ * sample values of all channels
+ *
+ * PARAMETERS:
+ * src Source
+ * dst Destination
+ * NrFrames Number of frames
+ * NrChannels Number of channels
+ *
+ * RETURNS:
+ * void
+ *
+ */
+void FromMcToMono_Float(const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 NrFrames,
+ LVM_INT16 NrChannels)
+{
+ LVM_INT16 ii, jj;
+ LVM_FLOAT Temp;
+
+ for (ii = NrFrames; ii != 0; ii--)
+ {
+ Temp = 0.0f;
+ for (jj = NrChannels; jj !=0; jj--)
+ {
+ Temp += (*src);
+ src++;
+ }
+ *dst = Temp / NrChannels;
+ dst++;
+ }
+
+ return;
+}
+#endif
+
+/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/InstAlloc.c b/media/libeffects/lvm/lib/Common/src/InstAlloc.c
deleted file mode 100644
index a89a5c3..0000000
--- a/media/libeffects/lvm/lib/Common/src/InstAlloc.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "InstAlloc.h"
-
-/****************************************************************************************
- * Name : InstAlloc_Init()
- * Input : pms - Pointer to the INST_ALLOC instance
- StartAddr - Base address of the instance memory
- * Returns : Error code
- * Description : Initializes the instance distribution and memory size calculation function
- * Remarks :
- ****************************************************************************************/
-
-void InstAlloc_Init( INST_ALLOC *pms,
- void *StartAddr )
-{
- pms->TotalSize = 3;
- pms->pNextMember = (((uintptr_t)StartAddr + 3) & (uintptr_t)~3);
-}
-
-
-/****************************************************************************************
- * Name : InstAlloc_AddMember()
- * Input : pms - Pointer to the INST_ALLOC instance
- Size - The size in bytes of the new added member
- * Returns : A pointer to the new added member
- * Description : Allocates space for a new member in the instance memory and returns
- a pointer to this new member. The start address of all members will
- be 32 bit alligned.
- * Remarks :
- ****************************************************************************************/
-
-void* InstAlloc_AddMember( INST_ALLOC *pms,
- LVM_UINT32 Size )
-{
- void *NewMemberAddress; /* Variable to temporarily store the return value */
- NewMemberAddress = (void*)pms->pNextMember;
-
- Size = ((Size + 3) & (LVM_UINT32)~3); /* Ceil the size to a multiple of four */
-
- pms->TotalSize += Size;
- pms->pNextMember += Size;
-
- return(NewMemberAddress);
-}
-
-
-/****************************************************************************************
- * Name : InstAlloc_GetTotal()
- * Input : pms - Pointer to the INST_ALLOC instance
- * Returns : The instance memory size
- * Description : This functions returns the calculated instance memory size
- * Remarks :
- ****************************************************************************************/
-
-LVM_UINT32 InstAlloc_GetTotal( INST_ALLOC *pms)
-{
- if (pms->TotalSize > 3)
- {
- return(pms->TotalSize);
- }
- else
- {
- return 0; /* No memory added */
- }
-}
-
-
-void InstAlloc_InitAll( INST_ALLOC *pms,
- LVM_MemoryTable_st *pMemoryTable)
-{
- uintptr_t StartAddr;
-
- StartAddr = (uintptr_t)pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].pBaseAddress;
-
- pms[0].TotalSize = 3;
- pms[0].pNextMember = ((StartAddr + 3) & (uintptr_t)~3);
-
-
- StartAddr = (uintptr_t)pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].pBaseAddress;
-
- pms[1].TotalSize = 3;
- pms[1].pNextMember = ((StartAddr + 3) & (uintptr_t)~3);
-
-
- StartAddr = (uintptr_t)pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].pBaseAddress;
-
- pms[2].TotalSize = 3;
- pms[2].pNextMember = ((StartAddr + 3) & (uintptr_t)~3);
-
-
- StartAddr = (uintptr_t)pMemoryTable->Region[LVM_TEMPORARY_FAST].pBaseAddress;
-
- pms[3].TotalSize = 3;
- pms[3].pNextMember = ((StartAddr + 3) & (uintptr_t)~3);
-
-}
-
-/****************************************************************************************
- * Name : InstAlloc_InitAll_NULL()
- * Input : pms - Pointer to array of four INST_ALLOC instances
- * Returns : Nothing
- * Description : This function reserves Size of 3 bytes for all memory regions and
- * intializes pNextMember for all regions to 0
- * Remarks :
- ****************************************************************************************/
-
-void InstAlloc_InitAll_NULL( INST_ALLOC *pms)
-{
- pms[0].TotalSize = 3;
- pms[0].pNextMember = 0;
-
-
- pms[1].TotalSize = 3;
- pms[1].pNextMember = 0;
-
- pms[2].TotalSize = 3;
- pms[2].pNextMember = 0;
-
- pms[3].TotalSize = 3;
- pms[3].pNextMember = 0;
-
-}
-
-
-void* InstAlloc_AddMemberAll( INST_ALLOC *pms,
- LVM_UINT32 Size[],
- LVM_MemoryTable_st *pMemoryTable)
-{
- void *NewMemberAddress; /* Variable to temporarily store the return value */
-
- /* coverity[returned_pointer] Ignore coverity warning that ptr is not used */
- NewMemberAddress = InstAlloc_AddMember(&pms[LVM_PERSISTENT_SLOW_DATA], Size[LVM_PERSISTENT_SLOW_DATA]);
-
- pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].Size = InstAlloc_GetTotal(&pms[LVM_PERSISTENT_SLOW_DATA]);
- pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].Type = LVM_PERSISTENT_SLOW_DATA;
- pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].pBaseAddress = LVM_NULL;
-
- NewMemberAddress = InstAlloc_AddMember(&pms[LVM_PERSISTENT_FAST_DATA], Size[LVM_PERSISTENT_FAST_DATA]);
-
- pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].Size = InstAlloc_GetTotal(&pms[LVM_PERSISTENT_FAST_DATA]);
- pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].Type = LVM_PERSISTENT_FAST_DATA;
- pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].pBaseAddress = LVM_NULL;
-
- NewMemberAddress = InstAlloc_AddMember(&pms[LVM_PERSISTENT_FAST_COEF], Size[LVM_PERSISTENT_FAST_COEF]);
-
- pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].Size = InstAlloc_GetTotal(&pms[LVM_PERSISTENT_FAST_COEF]);
- pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].Type = LVM_PERSISTENT_FAST_COEF;
- pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].pBaseAddress = LVM_NULL;
-
- NewMemberAddress = InstAlloc_AddMember(&pms[LVM_TEMPORARY_FAST], Size[LVM_TEMPORARY_FAST]);
-
- pMemoryTable->Region[LVM_TEMPORARY_FAST].Size = InstAlloc_GetTotal(&pms[LVM_TEMPORARY_FAST]);
- pMemoryTable->Region[LVM_TEMPORARY_FAST].Type = LVM_TEMPORARY_FAST;
- pMemoryTable->Region[LVM_TEMPORARY_FAST].pBaseAddress = LVM_NULL;
-
- return(NewMemberAddress);
-}
-
-
-void* InstAlloc_AddMemberAllRet( INST_ALLOC *pms,
- LVM_UINT32 Size[],
- void **ptr)
-{
- ptr[0] = InstAlloc_AddMember(&pms[LVM_PERSISTENT_SLOW_DATA], Size[LVM_PERSISTENT_SLOW_DATA]);
- ptr[1] = InstAlloc_AddMember(&pms[LVM_PERSISTENT_FAST_DATA], Size[LVM_PERSISTENT_FAST_DATA]);
- ptr[2] = InstAlloc_AddMember(&pms[LVM_PERSISTENT_FAST_COEF], Size[LVM_PERSISTENT_FAST_COEF]);
- ptr[3] = InstAlloc_AddMember(&pms[LVM_TEMPORARY_FAST], Size[LVM_TEMPORARY_FAST]);
-
- return (ptr[0]);
-}
diff --git a/media/libeffects/lvm/lib/Common/src/InstAlloc.cpp b/media/libeffects/lvm/lib/Common/src/InstAlloc.cpp
new file mode 100644
index 0000000..a039bf5
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/InstAlloc.cpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "InstAlloc.h"
+
+/****************************************************************************************
+ * Name : InstAlloc_Init()
+ * Input : pms - Pointer to the INST_ALLOC instance
+ StartAddr - Base address of the instance memory
+ * Returns : Error code
+ * Description : Initializes the instance distribution and memory size calculation function
+ * Remarks :
+ ****************************************************************************************/
+
+void InstAlloc_Init( INST_ALLOC *pms,
+ void *StartAddr )
+{
+ pms->TotalSize = 3;
+ pms->pNextMember = (((uintptr_t)StartAddr + 3) & (uintptr_t)~3);
+}
+
+/****************************************************************************************
+ * Name : InstAlloc_AddMember()
+ * Input : pms - Pointer to the INST_ALLOC instance
+ Size - The size in bytes of the new added member
+ * Returns : A pointer to the new added member
+ * Description : Allocates space for a new member in the instance memory and returns
+ a pointer to this new member. The start address of all members will
+ be 32 bit alligned.
+ * Remarks :
+ ****************************************************************************************/
+
+void* InstAlloc_AddMember( INST_ALLOC *pms,
+ LVM_UINT32 Size )
+{
+ void *NewMemberAddress; /* Variable to temporarily store the return value */
+ NewMemberAddress = (void*)pms->pNextMember;
+
+ Size = ((Size + 3) & (LVM_UINT32)~3); /* Ceil the size to a multiple of four */
+
+ pms->TotalSize += Size;
+ pms->pNextMember += Size;
+
+ return(NewMemberAddress);
+}
+
+/****************************************************************************************
+ * Name : InstAlloc_GetTotal()
+ * Input : pms - Pointer to the INST_ALLOC instance
+ * Returns : The instance memory size
+ * Description : This functions returns the calculated instance memory size
+ * Remarks :
+ ****************************************************************************************/
+
+LVM_UINT32 InstAlloc_GetTotal( INST_ALLOC *pms)
+{
+ if (pms->TotalSize > 3)
+ {
+ return(pms->TotalSize);
+ }
+ else
+ {
+ return 0; /* No memory added */
+ }
+}
+
+void InstAlloc_InitAll( INST_ALLOC *pms,
+ LVM_MemoryTable_st *pMemoryTable)
+{
+ uintptr_t StartAddr;
+
+ StartAddr = (uintptr_t)pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].pBaseAddress;
+
+ pms[0].TotalSize = 3;
+ pms[0].pNextMember = ((StartAddr + 3) & (uintptr_t)~3);
+
+ StartAddr = (uintptr_t)pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].pBaseAddress;
+
+ pms[1].TotalSize = 3;
+ pms[1].pNextMember = ((StartAddr + 3) & (uintptr_t)~3);
+
+ StartAddr = (uintptr_t)pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].pBaseAddress;
+
+ pms[2].TotalSize = 3;
+ pms[2].pNextMember = ((StartAddr + 3) & (uintptr_t)~3);
+
+ StartAddr = (uintptr_t)pMemoryTable->Region[LVM_TEMPORARY_FAST].pBaseAddress;
+
+ pms[3].TotalSize = 3;
+ pms[3].pNextMember = ((StartAddr + 3) & (uintptr_t)~3);
+
+}
+
+/****************************************************************************************
+ * Name : InstAlloc_InitAll_NULL()
+ * Input : pms - Pointer to array of four INST_ALLOC instances
+ * Returns : Nothing
+ * Description : This function reserves Size of 3 bytes for all memory regions and
+ * intializes pNextMember for all regions to 0
+ * Remarks :
+ ****************************************************************************************/
+
+void InstAlloc_InitAll_NULL( INST_ALLOC *pms)
+{
+ pms[0].TotalSize = 3;
+ pms[0].pNextMember = 0;
+
+ pms[1].TotalSize = 3;
+ pms[1].pNextMember = 0;
+
+ pms[2].TotalSize = 3;
+ pms[2].pNextMember = 0;
+
+ pms[3].TotalSize = 3;
+ pms[3].pNextMember = 0;
+
+}
+
+void* InstAlloc_AddMemberAll( INST_ALLOC *pms,
+ LVM_UINT32 Size[],
+ LVM_MemoryTable_st *pMemoryTable)
+{
+ void *NewMemberAddress; /* Variable to temporarily store the return value */
+
+ /* coverity[returned_pointer] Ignore coverity warning that ptr is not used */
+ NewMemberAddress = InstAlloc_AddMember(&pms[LVM_PERSISTENT_SLOW_DATA], Size[LVM_PERSISTENT_SLOW_DATA]);
+
+ pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].Size = InstAlloc_GetTotal(&pms[LVM_PERSISTENT_SLOW_DATA]);
+ pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].Type = LVM_PERSISTENT_SLOW_DATA;
+ pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].pBaseAddress = LVM_NULL;
+
+ NewMemberAddress = InstAlloc_AddMember(&pms[LVM_PERSISTENT_FAST_DATA], Size[LVM_PERSISTENT_FAST_DATA]);
+
+ pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].Size = InstAlloc_GetTotal(&pms[LVM_PERSISTENT_FAST_DATA]);
+ pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].Type = LVM_PERSISTENT_FAST_DATA;
+ pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].pBaseAddress = LVM_NULL;
+
+ NewMemberAddress = InstAlloc_AddMember(&pms[LVM_PERSISTENT_FAST_COEF], Size[LVM_PERSISTENT_FAST_COEF]);
+
+ pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].Size = InstAlloc_GetTotal(&pms[LVM_PERSISTENT_FAST_COEF]);
+ pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].Type = LVM_PERSISTENT_FAST_COEF;
+ pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].pBaseAddress = LVM_NULL;
+
+ NewMemberAddress = InstAlloc_AddMember(&pms[LVM_TEMPORARY_FAST], Size[LVM_TEMPORARY_FAST]);
+
+ pMemoryTable->Region[LVM_TEMPORARY_FAST].Size = InstAlloc_GetTotal(&pms[LVM_TEMPORARY_FAST]);
+ pMemoryTable->Region[LVM_TEMPORARY_FAST].Type = LVM_TEMPORARY_FAST;
+ pMemoryTable->Region[LVM_TEMPORARY_FAST].pBaseAddress = LVM_NULL;
+
+ return(NewMemberAddress);
+}
+
+void* InstAlloc_AddMemberAllRet( INST_ALLOC *pms,
+ LVM_UINT32 Size[],
+ void **ptr)
+{
+ ptr[0] = InstAlloc_AddMember(&pms[LVM_PERSISTENT_SLOW_DATA], Size[LVM_PERSISTENT_SLOW_DATA]);
+ ptr[1] = InstAlloc_AddMember(&pms[LVM_PERSISTENT_FAST_DATA], Size[LVM_PERSISTENT_FAST_DATA]);
+ ptr[2] = InstAlloc_AddMember(&pms[LVM_PERSISTENT_FAST_COEF], Size[LVM_PERSISTENT_FAST_COEF]);
+ ptr[3] = InstAlloc_AddMember(&pms[LVM_TEMPORARY_FAST], Size[LVM_TEMPORARY_FAST]);
+
+ return (ptr[0]);
+}
diff --git a/media/libeffects/lvm/lib/Common/src/Int16LShiftToInt32_16x32.c b/media/libeffects/lvm/lib/Common/src/Int16LShiftToInt32_16x32.cpp
similarity index 100%
rename from media/libeffects/lvm/lib/Common/src/Int16LShiftToInt32_16x32.c
rename to media/libeffects/lvm/lib/Common/src/Int16LShiftToInt32_16x32.cpp
diff --git a/media/libeffects/lvm/lib/Common/src/Int32RShiftToInt16_Sat_32x16.c b/media/libeffects/lvm/lib/Common/src/Int32RShiftToInt16_Sat_32x16.cpp
similarity index 100%
rename from media/libeffects/lvm/lib/Common/src/Int32RShiftToInt16_Sat_32x16.c
rename to media/libeffects/lvm/lib/Common/src/Int32RShiftToInt16_Sat_32x16.cpp
diff --git a/media/libeffects/lvm/lib/Common/src/JoinTo2i_32x32.c b/media/libeffects/lvm/lib/Common/src/JoinTo2i_32x32.c
deleted file mode 100644
index ebc477e..0000000
--- a/media/libeffects/lvm/lib/Common/src/JoinTo2i_32x32.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**********************************************************************************
- INCLUDE FILES
-***********************************************************************************/
-
-#include "VectorArithmetic.h"
-
-/**********************************************************************************
- FUNCTION JoinTo2i_32x32
-***********************************************************************************/
-
-void JoinTo2i_32x32( const LVM_INT32 *srcL,
- const LVM_INT32 *srcR,
- LVM_INT32 *dst,
- LVM_INT16 n )
-{
- LVM_INT16 ii;
-
- srcL += n-1;
- srcR += n-1;
- dst += ((2*n)-1);
-
- for (ii = n; ii != 0; ii--)
- {
- *dst = *srcR;
- dst--;
- srcR--;
-
- *dst = *srcL;
- dst--;
- srcL--;
- }
-
- return;
-}
-#ifdef BUILD_FLOAT
-void JoinTo2i_Float( const LVM_FLOAT *srcL,
- const LVM_FLOAT *srcR,
- LVM_FLOAT *dst,
- LVM_INT16 n )
-{
- LVM_INT16 ii;
-
- srcL += n - 1;
- srcR += n - 1;
- dst += ((2 * n) - 1);
-
- for (ii = n; ii != 0; ii--)
- {
- *dst = *srcR;
- dst--;
- srcR--;
-
- *dst = *srcL;
- dst--;
- srcL--;
- }
-
- return;
-}
-#endif
-/**********************************************************************************/
-
diff --git a/media/libeffects/lvm/lib/Common/src/JoinTo2i_32x32.cpp b/media/libeffects/lvm/lib/Common/src/JoinTo2i_32x32.cpp
new file mode 100644
index 0000000..05df656
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/JoinTo2i_32x32.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**********************************************************************************
+ INCLUDE FILES
+***********************************************************************************/
+
+#include "VectorArithmetic.h"
+
+/**********************************************************************************
+ FUNCTION JoinTo2i_32x32
+***********************************************************************************/
+
+void JoinTo2i_32x32( const LVM_INT32 *srcL,
+ const LVM_INT32 *srcR,
+ LVM_INT32 *dst,
+ LVM_INT16 n )
+{
+ LVM_INT16 ii;
+
+ srcL += n-1;
+ srcR += n-1;
+ dst += ((2*n)-1);
+
+ for (ii = n; ii != 0; ii--)
+ {
+ *dst = *srcR;
+ dst--;
+ srcR--;
+
+ *dst = *srcL;
+ dst--;
+ srcL--;
+ }
+
+ return;
+}
+void JoinTo2i_Float( const LVM_FLOAT *srcL,
+ const LVM_FLOAT *srcR,
+ LVM_FLOAT *dst,
+ LVM_INT16 n )
+{
+ LVM_INT16 ii;
+
+ srcL += n - 1;
+ srcR += n - 1;
+ dst += ((2 * n) - 1);
+
+ for (ii = n; ii != 0; ii--)
+ {
+ *dst = *srcR;
+ dst--;
+ srcR--;
+
+ *dst = *srcL;
+ dst--;
+ srcL--;
+ }
+
+ return;
+}
+/**********************************************************************************/
+
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixHard_1St_2i_D16C31_SAT.c b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixHard_1St_2i_D16C31_SAT.c
deleted file mode 100644
index db76cd1..0000000
--- a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixHard_1St_2i_D16C31_SAT.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**********************************************************************************
- INCLUDE FILES
-***********************************************************************************/
-
-#include "LVC_Mixer_Private.h"
-#include "LVM_Macros.h"
-#include "ScalarArithmetic.h"
-
-
-/**********************************************************************************
- FUNCTION LVC_Core_MixHard_1St_2i_D16C31_SAT
-***********************************************************************************/
-#ifdef BUILD_FLOAT
-void LVC_Core_MixHard_1St_2i_D16C31_SAT( LVMixer3_FLOAT_st *ptrInstance1,
- LVMixer3_FLOAT_st *ptrInstance2,
- const LVM_FLOAT *src,
- LVM_FLOAT *dst,
- LVM_INT16 n)
-{
- LVM_FLOAT Temp;
- LVM_INT16 ii;
- Mix_Private_FLOAT_st *pInstance1 = (Mix_Private_FLOAT_st *)(ptrInstance1->PrivateParams);
- Mix_Private_FLOAT_st *pInstance2 = (Mix_Private_FLOAT_st *)(ptrInstance2->PrivateParams);
- for (ii = n; ii != 0; ii--)
- {
- Temp = ((LVM_FLOAT)*(src++) * (LVM_FLOAT)pInstance1->Current);
- if (Temp > 1.0f)
- *dst++ = 1.0f;
- else if (Temp < -1.0f)
- *dst++ = -1.0f;
- else
- *dst++ = (LVM_FLOAT)Temp;
-
- Temp = ((LVM_FLOAT)*(src++) * (LVM_FLOAT)pInstance2->Current);
- if (Temp > 1.0f)
- *dst++ = 1.0f;
- else if (Temp < -1.0f)
- *dst++ = -1.0f;
- else
- *dst++ = (LVM_FLOAT)Temp;
- }
-
-
-}
-#ifdef SUPPORT_MC
-void LVC_Core_MixHard_1St_MC_float_SAT (Mix_Private_FLOAT_st **ptrInstance,
- const LVM_FLOAT *src,
- LVM_FLOAT *dst,
- LVM_INT16 NrFrames,
- LVM_INT16 NrChannels)
-{
- LVM_FLOAT Temp;
- LVM_INT16 ii, jj;
- for (ii = NrFrames; ii != 0; ii--)
- {
- for (jj = 0; jj < NrChannels; jj++)
- {
- Mix_Private_FLOAT_st *pInstance1 = (Mix_Private_FLOAT_st *)(ptrInstance[jj]);
- Temp = ((LVM_FLOAT)*(src++) * (LVM_FLOAT)pInstance1->Current);
- if (Temp > 1.0f)
- *dst++ = 1.0f;
- else if (Temp < -1.0f)
- *dst++ = -1.0f;
- else
- *dst++ = (LVM_FLOAT)Temp;
- }
- }
-}
-#endif
-#else
-void LVC_Core_MixHard_1St_2i_D16C31_SAT( LVMixer3_st *ptrInstance1,
- LVMixer3_st *ptrInstance2,
- const LVM_INT16 *src,
- LVM_INT16 *dst,
- LVM_INT16 n)
-{
- LVM_INT32 Temp;
- LVM_INT16 ii;
- LVM_INT16 Current1Short;
- LVM_INT16 Current2Short;
- Mix_Private_st *pInstance1=(Mix_Private_st *)(ptrInstance1->PrivateParams);
- Mix_Private_st *pInstance2=(Mix_Private_st *)(ptrInstance2->PrivateParams);
-
-
- Current1Short = (LVM_INT16)(pInstance1->Current >> 16);
- Current2Short = (LVM_INT16)(pInstance2->Current >> 16);
-
- for (ii = n; ii != 0; ii--)
- {
- Temp = ((LVM_INT32)*(src++) * (LVM_INT32)Current1Short)>>15;
- if (Temp > 0x00007FFF)
- *dst++ = 0x7FFF;
- else if (Temp < -0x00008000)
- *dst++ = - 0x8000;
- else
- *dst++ = (LVM_INT16)Temp;
-
- Temp = ((LVM_INT32)*(src++) * (LVM_INT32)Current2Short)>>15;
- if (Temp > 0x00007FFF)
- *dst++ = 0x7FFF;
- else if (Temp < -0x00008000)
- *dst++ = - 0x8000;
- else
- *dst++ = (LVM_INT16)Temp;
- }
-
-
-}
-#endif
-/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixHard_1St_2i_D16C31_SAT.cpp b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixHard_1St_2i_D16C31_SAT.cpp
new file mode 100644
index 0000000..14d61bd
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixHard_1St_2i_D16C31_SAT.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**********************************************************************************
+ INCLUDE FILES
+***********************************************************************************/
+
+#include "LVC_Mixer_Private.h"
+#include "LVM_Macros.h"
+#include "ScalarArithmetic.h"
+
+/**********************************************************************************
+ FUNCTION LVC_Core_MixHard_1St_2i_D16C31_SAT
+***********************************************************************************/
+void LVC_Core_MixHard_1St_2i_D16C31_SAT( LVMixer3_FLOAT_st *ptrInstance1,
+ LVMixer3_FLOAT_st *ptrInstance2,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ LVM_FLOAT Temp;
+ LVM_INT16 ii;
+ Mix_Private_FLOAT_st *pInstance1 = (Mix_Private_FLOAT_st *)(ptrInstance1->PrivateParams);
+ Mix_Private_FLOAT_st *pInstance2 = (Mix_Private_FLOAT_st *)(ptrInstance2->PrivateParams);
+ for (ii = n; ii != 0; ii--)
+ {
+ Temp = ((LVM_FLOAT)*(src++) * (LVM_FLOAT)pInstance1->Current);
+ if (Temp > 1.0f)
+ *dst++ = 1.0f;
+ else if (Temp < -1.0f)
+ *dst++ = -1.0f;
+ else
+ *dst++ = (LVM_FLOAT)Temp;
+
+ Temp = ((LVM_FLOAT)*(src++) * (LVM_FLOAT)pInstance2->Current);
+ if (Temp > 1.0f)
+ *dst++ = 1.0f;
+ else if (Temp < -1.0f)
+ *dst++ = -1.0f;
+ else
+ *dst++ = (LVM_FLOAT)Temp;
+ }
+
+}
+#ifdef SUPPORT_MC
+void LVC_Core_MixHard_1St_MC_float_SAT (Mix_Private_FLOAT_st **ptrInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 NrFrames,
+ LVM_INT16 NrChannels)
+{
+ LVM_FLOAT Temp;
+ LVM_INT16 ii, jj;
+ for (ii = NrFrames; ii != 0; ii--)
+ {
+ for (jj = 0; jj < NrChannels; jj++)
+ {
+ Mix_Private_FLOAT_st *pInstance1 = (Mix_Private_FLOAT_st *)(ptrInstance[jj]);
+ Temp = ((LVM_FLOAT)*(src++) * (LVM_FLOAT)pInstance1->Current);
+ if (Temp > 1.0f)
+ *dst++ = 1.0f;
+ else if (Temp < -1.0f)
+ *dst++ = -1.0f;
+ else
+ *dst++ = (LVM_FLOAT)Temp;
+ }
+ }
+}
+#endif
+/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixHard_2St_D16C31_SAT.c b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixHard_2St_D16C31_SAT.c
deleted file mode 100644
index ec0baaf..0000000
--- a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixHard_2St_D16C31_SAT.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**********************************************************************************
- INCLUDE FILES
-***********************************************************************************/
-
-#include "LVC_Mixer_Private.h"
-
-/**********************************************************************************
- FUNCTION LVCore_MIXHARD_2ST_D16C31_SAT
-***********************************************************************************/
-#ifdef BUILD_FLOAT
-void LVC_Core_MixHard_2St_D16C31_SAT( LVMixer3_FLOAT_st *ptrInstance1,
- LVMixer3_FLOAT_st *ptrInstance2,
- const LVM_FLOAT *src1,
- const LVM_FLOAT *src2,
- LVM_FLOAT *dst,
- LVM_INT16 n)
-{
- LVM_FLOAT Temp;
- LVM_INT16 ii;
- LVM_FLOAT Current1;
- LVM_FLOAT Current2;
- Mix_Private_FLOAT_st *pInstance1 = (Mix_Private_FLOAT_st *)(ptrInstance1->PrivateParams);
- Mix_Private_FLOAT_st *pInstance2 = (Mix_Private_FLOAT_st *)(ptrInstance2->PrivateParams);
-
-
- Current1 = (pInstance1->Current);
- Current2 = (pInstance2->Current);
-
- for (ii = n; ii != 0; ii--){
- Temp = (((LVM_FLOAT)*(src1++) * (LVM_FLOAT)Current1)) +
- (((LVM_FLOAT)*(src2++) * (LVM_FLOAT)Current2));
- if (Temp > 1.0f)
- *dst++ = 1.0f;
- else if (Temp < -1.0f)
- *dst++ = -1.0f;
- else
- *dst++ = Temp;
- }
-}
-#else
-void LVC_Core_MixHard_2St_D16C31_SAT( LVMixer3_st *ptrInstance1,
- LVMixer3_st *ptrInstance2,
- const LVM_INT16 *src1,
- const LVM_INT16 *src2,
- LVM_INT16 *dst,
- LVM_INT16 n)
-{
- LVM_INT32 Temp;
- LVM_INT16 ii;
- LVM_INT16 Current1Short;
- LVM_INT16 Current2Short;
- Mix_Private_st *pInstance1=(Mix_Private_st *)(ptrInstance1->PrivateParams);
- Mix_Private_st *pInstance2=(Mix_Private_st *)(ptrInstance2->PrivateParams);
-
-
- Current1Short = (LVM_INT16)(pInstance1->Current >> 16);
- Current2Short = (LVM_INT16)(pInstance2->Current >> 16);
-
- for (ii = n; ii != 0; ii--){
- Temp = (((LVM_INT32)*(src1++) * (LVM_INT32)Current1Short)>>15) +
- (((LVM_INT32)*(src2++) * (LVM_INT32)Current2Short)>>15);
- if (Temp > 0x00007FFF)
- *dst++ = 0x7FFF;
- else if (Temp < -0x00008000)
- *dst++ = - 0x8000;
- else
- *dst++ = (LVM_INT16)Temp;
- }
-}
-#endif
-/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixHard_2St_D16C31_SAT.cpp b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixHard_2St_D16C31_SAT.cpp
new file mode 100644
index 0000000..841fa1e
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixHard_2St_D16C31_SAT.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**********************************************************************************
+ INCLUDE FILES
+***********************************************************************************/
+
+#include "LVC_Mixer_Private.h"
+
+/**********************************************************************************
+ FUNCTION LVCore_MIXHARD_2ST_D16C31_SAT
+***********************************************************************************/
+void LVC_Core_MixHard_2St_D16C31_SAT( LVMixer3_FLOAT_st *ptrInstance1,
+ LVMixer3_FLOAT_st *ptrInstance2,
+ const LVM_FLOAT *src1,
+ const LVM_FLOAT *src2,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ LVM_FLOAT Temp;
+ LVM_INT16 ii;
+ LVM_FLOAT Current1;
+ LVM_FLOAT Current2;
+ Mix_Private_FLOAT_st *pInstance1 = (Mix_Private_FLOAT_st *)(ptrInstance1->PrivateParams);
+ Mix_Private_FLOAT_st *pInstance2 = (Mix_Private_FLOAT_st *)(ptrInstance2->PrivateParams);
+
+ Current1 = (pInstance1->Current);
+ Current2 = (pInstance2->Current);
+
+ for (ii = n; ii != 0; ii--){
+ Temp = (((LVM_FLOAT)*(src1++) * (LVM_FLOAT)Current1)) +
+ (((LVM_FLOAT)*(src2++) * (LVM_FLOAT)Current2));
+ if (Temp > 1.0f)
+ *dst++ = 1.0f;
+ else if (Temp < -1.0f)
+ *dst++ = -1.0f;
+ else
+ *dst++ = Temp;
+ }
+}
+/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixInSoft_D16C31_SAT.c b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixInSoft_D16C31_SAT.c
deleted file mode 100644
index 419c7c5..0000000
--- a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixInSoft_D16C31_SAT.c
+++ /dev/null
@@ -1,349 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**********************************************************************************
- INCLUDE FILES
-***********************************************************************************/
-
-#include "LVC_Mixer_Private.h"
-#include "LVM_Macros.h"
-
-/**********************************************************************************
- FUNCTION LVCore_MIXSOFT_1ST_D16C31_WRA
-***********************************************************************************/
-#ifdef BUILD_FLOAT
-void LVC_Core_MixInSoft_D16C31_SAT(LVMixer3_FLOAT_st *ptrInstance,
- const LVM_FLOAT *src,
- LVM_FLOAT *dst,
- LVM_INT16 n)
-{
-
- LVM_INT16 OutLoop;
- LVM_INT16 InLoop;
- LVM_INT32 ii,jj;
- Mix_Private_FLOAT_st *pInstance = (Mix_Private_FLOAT_st *)(ptrInstance->PrivateParams);
- LVM_FLOAT Delta = pInstance->Delta;
- LVM_FLOAT Current = pInstance->Current;
- LVM_FLOAT Target = pInstance->Target;
- LVM_FLOAT Temp;
-
- InLoop = (LVM_INT16)(n >> 2); /* Process per 4 samples */
- OutLoop = (LVM_INT16)(n - (InLoop << 2));
-
- if(Current < Target){
- if (OutLoop){
- Temp = Current + Delta;
- Current = Temp;
- if (Current > Target)
- Current = Target;
-
- for (ii = OutLoop; ii != 0; ii--){
- Temp = ((LVM_FLOAT)*dst) + (((LVM_FLOAT)*(src++) * Current));
- if (Temp > 1.0f)
- *dst++ = 1.0f;
- else if (Temp < -1.0f)
- *dst++ = -1.0f;
- else
- *dst++ = (LVM_FLOAT)Temp;
- }
- }
-
- for (ii = InLoop; ii != 0; ii--){
- Temp = Current + Delta;
- Current = Temp;
- if (Current > Target)
- Current = Target;
-
- for (jj = 4; jj != 0 ; jj--){
- Temp = ((LVM_FLOAT)*dst) + (((LVM_FLOAT)*(src++) * Current));
- if (Temp > 1.0f)
- *dst++ = 1.0f;
- else if (Temp < -1.0f)
- *dst++ = -1.0f;
- else
- *dst++ = (LVM_FLOAT)Temp;
- }
- }
- }
- else{
- if (OutLoop){
- Current -= Delta;
- if (Current < Target)
- Current = Target;
-
- for (ii = OutLoop; ii != 0; ii--){
- Temp = ((LVM_FLOAT)*dst) + (((LVM_FLOAT)*(src++) * Current));
- if (Temp > 1.0f)
- *dst++ = 1.0f;
- else if (Temp < -1.0f)
- *dst++ = -1.0f;
- else
- *dst++ = (LVM_FLOAT)Temp;
- }
- }
-
- for (ii = InLoop; ii != 0; ii--){
- Current -= Delta;
- if (Current < Target)
- Current = Target;
-
- for (jj = 4; jj != 0 ; jj--){
- Temp = ((LVM_FLOAT)*dst) + (((LVM_FLOAT)*(src++) * Current));
- if (Temp > 1.0f)
- *dst++ = 1.0f;
- else if (Temp < -1.0f)
- *dst++ = -1.0f;
- else
- *dst++ = (LVM_FLOAT)Temp;
- }
- }
- }
- pInstance->Current = Current;
-}
-#ifdef SUPPORT_MC
-/*
- * FUNCTION: LVC_Core_MixInSoft_Mc_D16C31_SAT
- *
- * DESCRIPTION:
- * Mixer function with support for processing multichannel input.
- *
- * PARAMETERS:
- * ptrInstance Instance pointer
- * src Source
- * dst Destination
- * NrFrames Number of frames
- * NrChannels Number of channels
- *
- * RETURNS:
- * void
- *
- */
-void LVC_Core_MixInSoft_Mc_D16C31_SAT(LVMixer3_FLOAT_st *ptrInstance,
- const LVM_FLOAT *src,
- LVM_FLOAT *dst,
- LVM_INT16 NrFrames,
- LVM_INT16 NrChannels)
-{
-
- LVM_INT16 OutLoop;
- LVM_INT16 InLoop;
- LVM_INT32 ii, jj;
- Mix_Private_FLOAT_st *pInstance = (Mix_Private_FLOAT_st *)(ptrInstance->PrivateParams);
- LVM_FLOAT Delta = pInstance->Delta;
- LVM_FLOAT Current = pInstance->Current;
- LVM_FLOAT Target = pInstance->Target;
- LVM_FLOAT Temp;
-
- /*
- * Same operation is performed on consecutive frames.
- * So two frames are processed in one iteration and
- * the loop will run only for half the NrFrames value times.
- */
- InLoop = (LVM_INT16)(NrFrames >> 1);
- /* OutLoop is calculated to handle cases where NrFrames value can be odd.*/
- OutLoop = (LVM_INT16)(NrFrames - (InLoop << 1));
-
- if (Current < Target) {
- if (OutLoop) {
- Temp = Current + Delta;
- Current = Temp;
- if (Current > Target)
- Current = Target;
-
- for (ii = OutLoop*NrChannels; ii != 0; ii--) {
- Temp = (*dst) + (*(src++) * Current);
- if (Temp > 1.0f)
- *dst++ = 1.0f;
- else if (Temp < -1.0f)
- *dst++ = -1.0f;
- else
- *dst++ = Temp;
- }
- }
-
- for (ii = InLoop; ii != 0; ii--) {
- Temp = Current + Delta;
- Current = Temp;
- if (Current > Target)
- Current = Target;
-
- for (jj = NrChannels; jj != 0 ; jj--) {
- Temp = (*dst) + (*(src++) * Current);
- if (Temp > 1.0f)
- *dst++ = 1.0f;
- else if (Temp < -1.0f)
- *dst++ = -1.0f;
- else
- *dst++ = Temp;
-
- Temp = (*dst) + (*(src++) * Current);
- if (Temp > 1.0f)
- *dst++ = 1.0f;
- else if (Temp < -1.0f)
- *dst++ = -1.0f;
- else
- *dst++ = Temp;
-
- }
- }
- }
- else{
- if (OutLoop) {
- Current -= Delta;
- if (Current < Target)
- Current = Target;
-
- for (ii = OutLoop*NrChannels; ii != 0; ii--) {
- Temp = (*dst) + (*(src++) * Current);
- if (Temp > 1.0f)
- *dst++ = 1.0f;
- else if (Temp < -1.0f)
- *dst++ = -1.0f;
- else
- *dst++ = Temp;
- }
- }
-
- for (ii = InLoop; ii != 0; ii--) {
- Current -= Delta;
- if (Current < Target)
- Current = Target;
-
- for (jj = NrChannels; jj != 0 ; jj--) {
- Temp = (*dst) + (*(src++) * Current);
- if (Temp > 1.0f)
- *dst++ = 1.0f;
- else if (Temp < -1.0f)
- *dst++ = -1.0f;
- else
- *dst++ = Temp;
-
- Temp = (*dst) + (*(src++) * Current);
- if (Temp > 1.0f)
- *dst++ = 1.0f;
- else if (Temp < -1.0f)
- *dst++ = -1.0f;
- else
- *dst++ = Temp;
-
- }
- }
- }
- pInstance->Current = Current;
-}
-
-#endif
-#else
-void LVC_Core_MixInSoft_D16C31_SAT( LVMixer3_st *ptrInstance,
- const LVM_INT16 *src,
- LVM_INT16 *dst,
- LVM_INT16 n)
-{
-
- LVM_INT16 OutLoop;
- LVM_INT16 InLoop;
- LVM_INT16 CurrentShort;
- LVM_INT32 ii,jj;
- Mix_Private_st *pInstance=(Mix_Private_st *)(ptrInstance->PrivateParams);
- LVM_INT32 Delta=pInstance->Delta;
- LVM_INT32 Current=pInstance->Current;
- LVM_INT32 Target=pInstance->Target;
- LVM_INT32 Temp;
-
- InLoop = (LVM_INT16)(n >> 2); /* Process per 4 samples */
- OutLoop = (LVM_INT16)(n - (InLoop << 2));
-
- if(Current<Target){
- if (OutLoop){
- ADD2_SAT_32x32(Current,Delta,Temp); /* Q31 + Q31 into Q31*/
- Current=Temp;
- if (Current > Target)
- Current = Target;
-
- CurrentShort = (LVM_INT16)(Current>>16); /* From Q31 to Q15*/
-
- for (ii = OutLoop; ii != 0; ii--){
- Temp = ((LVM_INT32)*dst) + (((LVM_INT32)*(src++) * CurrentShort)>>15); /* Q15 + Q15*Q15>>15 into Q15 */
- if (Temp > 0x00007FFF)
- *dst++ = 0x7FFF;
- else if (Temp < -0x00008000)
- *dst++ = - 0x8000;
- else
- *dst++ = (LVM_INT16)Temp;
- }
- }
-
- for (ii = InLoop; ii != 0; ii--){
- ADD2_SAT_32x32(Current,Delta,Temp); /* Q31 + Q31 into Q31*/
- Current=Temp;
- if (Current > Target)
- Current = Target;
-
- CurrentShort = (LVM_INT16)(Current>>16); /* From Q31 to Q15*/
-
- for (jj = 4; jj!=0 ; jj--){
- Temp = ((LVM_INT32)*dst) + (((LVM_INT32)*(src++) * CurrentShort)>>15); /* Q15 + Q15*Q15>>15 into Q15 */
- if (Temp > 0x00007FFF)
- *dst++ = 0x7FFF;
- else if (Temp < -0x00008000)
- *dst++ = - 0x8000;
- else
- *dst++ = (LVM_INT16)Temp;
- }
- }
- }
- else{
- if (OutLoop){
- Current -= Delta; /* Q31 + Q31 into Q31*/
- if (Current < Target)
- Current = Target;
-
- CurrentShort = (LVM_INT16)(Current>>16); /* From Q31 to Q15*/
-
- for (ii = OutLoop; ii != 0; ii--){
- Temp = ((LVM_INT32)*dst) + (((LVM_INT32)*(src++) * CurrentShort)>>15); /* Q15 + Q15*Q15>>15 into Q15 */
- if (Temp > 0x00007FFF)
- *dst++ = 0x7FFF;
- else if (Temp < -0x00008000)
- *dst++ = - 0x8000;
- else
- *dst++ = (LVM_INT16)Temp;
- }
- }
-
- for (ii = InLoop; ii != 0; ii--){
- Current -= Delta; /* Q31 + Q31 into Q31*/
- if (Current < Target)
- Current = Target;
-
- CurrentShort = (LVM_INT16)(Current>>16); /* From Q31 to Q15*/
-
- for (jj = 4; jj!=0 ; jj--){
- Temp = ((LVM_INT32)*dst) + (((LVM_INT32)*(src++) * CurrentShort)>>15); /* Q15 + Q15*Q15>>15 into Q15 */
- if (Temp > 0x00007FFF)
- *dst++ = 0x7FFF;
- else if (Temp < -0x00008000)
- *dst++ = - 0x8000;
- else
- *dst++ = (LVM_INT16)Temp;
- }
- }
- }
- pInstance->Current=Current;
-}
-#endif
-/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixInSoft_D16C31_SAT.cpp b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixInSoft_D16C31_SAT.cpp
new file mode 100644
index 0000000..318138d
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixInSoft_D16C31_SAT.cpp
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**********************************************************************************
+ INCLUDE FILES
+***********************************************************************************/
+
+#include "LVC_Mixer_Private.h"
+#include "LVM_Macros.h"
+
+/**********************************************************************************
+ FUNCTION LVCore_MIXSOFT_1ST_D16C31_WRA
+***********************************************************************************/
+void LVC_Core_MixInSoft_D16C31_SAT(LVMixer3_FLOAT_st *ptrInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+
+ LVM_INT16 OutLoop;
+ LVM_INT16 InLoop;
+ LVM_INT32 ii,jj;
+ Mix_Private_FLOAT_st *pInstance = (Mix_Private_FLOAT_st *)(ptrInstance->PrivateParams);
+ LVM_FLOAT Delta = pInstance->Delta;
+ LVM_FLOAT Current = pInstance->Current;
+ LVM_FLOAT Target = pInstance->Target;
+ LVM_FLOAT Temp;
+
+ InLoop = (LVM_INT16)(n >> 2); /* Process per 4 samples */
+ OutLoop = (LVM_INT16)(n - (InLoop << 2));
+
+ if(Current < Target){
+ if (OutLoop){
+ Temp = Current + Delta;
+ Current = Temp;
+ if (Current > Target)
+ Current = Target;
+
+ for (ii = OutLoop; ii != 0; ii--){
+ Temp = ((LVM_FLOAT)*dst) + (((LVM_FLOAT)*(src++) * Current));
+ if (Temp > 1.0f)
+ *dst++ = 1.0f;
+ else if (Temp < -1.0f)
+ *dst++ = -1.0f;
+ else
+ *dst++ = (LVM_FLOAT)Temp;
+ }
+ }
+
+ for (ii = InLoop; ii != 0; ii--){
+ Temp = Current + Delta;
+ Current = Temp;
+ if (Current > Target)
+ Current = Target;
+
+ for (jj = 4; jj != 0 ; jj--){
+ Temp = ((LVM_FLOAT)*dst) + (((LVM_FLOAT)*(src++) * Current));
+ if (Temp > 1.0f)
+ *dst++ = 1.0f;
+ else if (Temp < -1.0f)
+ *dst++ = -1.0f;
+ else
+ *dst++ = (LVM_FLOAT)Temp;
+ }
+ }
+ }
+ else{
+ if (OutLoop){
+ Current -= Delta;
+ if (Current < Target)
+ Current = Target;
+
+ for (ii = OutLoop; ii != 0; ii--){
+ Temp = ((LVM_FLOAT)*dst) + (((LVM_FLOAT)*(src++) * Current));
+ if (Temp > 1.0f)
+ *dst++ = 1.0f;
+ else if (Temp < -1.0f)
+ *dst++ = -1.0f;
+ else
+ *dst++ = (LVM_FLOAT)Temp;
+ }
+ }
+
+ for (ii = InLoop; ii != 0; ii--){
+ Current -= Delta;
+ if (Current < Target)
+ Current = Target;
+
+ for (jj = 4; jj != 0 ; jj--){
+ Temp = ((LVM_FLOAT)*dst) + (((LVM_FLOAT)*(src++) * Current));
+ if (Temp > 1.0f)
+ *dst++ = 1.0f;
+ else if (Temp < -1.0f)
+ *dst++ = -1.0f;
+ else
+ *dst++ = (LVM_FLOAT)Temp;
+ }
+ }
+ }
+ pInstance->Current = Current;
+}
+#ifdef SUPPORT_MC
+/*
+ * FUNCTION: LVC_Core_MixInSoft_Mc_D16C31_SAT
+ *
+ * DESCRIPTION:
+ * Mixer function with support for processing multichannel input.
+ *
+ * PARAMETERS:
+ * ptrInstance Instance pointer
+ * src Source
+ * dst Destination
+ * NrFrames Number of frames
+ * NrChannels Number of channels
+ *
+ * RETURNS:
+ * void
+ *
+ */
+void LVC_Core_MixInSoft_Mc_D16C31_SAT(LVMixer3_FLOAT_st *ptrInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 NrFrames,
+ LVM_INT16 NrChannels)
+{
+
+ LVM_INT16 OutLoop;
+ LVM_INT16 InLoop;
+ LVM_INT32 ii, jj;
+ Mix_Private_FLOAT_st *pInstance = (Mix_Private_FLOAT_st *)(ptrInstance->PrivateParams);
+ LVM_FLOAT Delta = pInstance->Delta;
+ LVM_FLOAT Current = pInstance->Current;
+ LVM_FLOAT Target = pInstance->Target;
+ LVM_FLOAT Temp;
+
+ /*
+ * Same operation is performed on consecutive frames.
+ * So two frames are processed in one iteration and
+ * the loop will run only for half the NrFrames value times.
+ */
+ InLoop = (LVM_INT16)(NrFrames >> 1);
+ /* OutLoop is calculated to handle cases where NrFrames value can be odd.*/
+ OutLoop = (LVM_INT16)(NrFrames - (InLoop << 1));
+
+ if (Current < Target) {
+ if (OutLoop) {
+ Temp = Current + Delta;
+ Current = Temp;
+ if (Current > Target)
+ Current = Target;
+
+ for (ii = OutLoop*NrChannels; ii != 0; ii--) {
+ Temp = (*dst) + (*(src++) * Current);
+ if (Temp > 1.0f)
+ *dst++ = 1.0f;
+ else if (Temp < -1.0f)
+ *dst++ = -1.0f;
+ else
+ *dst++ = Temp;
+ }
+ }
+
+ for (ii = InLoop; ii != 0; ii--) {
+ Temp = Current + Delta;
+ Current = Temp;
+ if (Current > Target)
+ Current = Target;
+
+ for (jj = NrChannels; jj != 0 ; jj--) {
+ Temp = (*dst) + (*(src++) * Current);
+ if (Temp > 1.0f)
+ *dst++ = 1.0f;
+ else if (Temp < -1.0f)
+ *dst++ = -1.0f;
+ else
+ *dst++ = Temp;
+
+ Temp = (*dst) + (*(src++) * Current);
+ if (Temp > 1.0f)
+ *dst++ = 1.0f;
+ else if (Temp < -1.0f)
+ *dst++ = -1.0f;
+ else
+ *dst++ = Temp;
+
+ }
+ }
+ }
+ else{
+ if (OutLoop) {
+ Current -= Delta;
+ if (Current < Target)
+ Current = Target;
+
+ for (ii = OutLoop*NrChannels; ii != 0; ii--) {
+ Temp = (*dst) + (*(src++) * Current);
+ if (Temp > 1.0f)
+ *dst++ = 1.0f;
+ else if (Temp < -1.0f)
+ *dst++ = -1.0f;
+ else
+ *dst++ = Temp;
+ }
+ }
+
+ for (ii = InLoop; ii != 0; ii--) {
+ Current -= Delta;
+ if (Current < Target)
+ Current = Target;
+
+ for (jj = NrChannels; jj != 0 ; jj--) {
+ Temp = (*dst) + (*(src++) * Current);
+ if (Temp > 1.0f)
+ *dst++ = 1.0f;
+ else if (Temp < -1.0f)
+ *dst++ = -1.0f;
+ else
+ *dst++ = Temp;
+
+ Temp = (*dst) + (*(src++) * Current);
+ if (Temp > 1.0f)
+ *dst++ = 1.0f;
+ else if (Temp < -1.0f)
+ *dst++ = -1.0f;
+ else
+ *dst++ = Temp;
+
+ }
+ }
+ }
+ pInstance->Current = Current;
+}
+
+#endif
+/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_2i_D16C31_WRA.c b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_2i_D16C31_WRA.c
deleted file mode 100644
index 56b5dae..0000000
--- a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_2i_D16C31_WRA.c
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**********************************************************************************
- INCLUDE FILES
-***********************************************************************************/
-
-#include "LVC_Mixer_Private.h"
-#include "ScalarArithmetic.h"
-#include "LVM_Macros.h"
-
-/**********************************************************************************
- FUNCTION LVC_Core_MixSoft_1St_2i_D16C31_WRA
-***********************************************************************************/
-#ifdef BUILD_FLOAT
-static LVM_FLOAT ADD2_SAT_FLOAT(LVM_FLOAT a,
- LVM_FLOAT b,
- LVM_FLOAT c)
-{
- LVM_FLOAT temp;
- temp = a + b ;
- if (temp < -1.0f)
- c = -1.0f;
- else if (temp > 1.0f)
- c = 1.0f;
- else
- c = temp;
- return c;
-}
-void LVC_Core_MixSoft_1St_2i_D16C31_WRA( LVMixer3_FLOAT_st *ptrInstance1,
- LVMixer3_FLOAT_st *ptrInstance2,
- const LVM_FLOAT *src,
- LVM_FLOAT *dst,
- LVM_INT16 n)
-{
- LVM_INT16 OutLoop;
- LVM_INT16 InLoop;
- LVM_INT32 ii;
- Mix_Private_FLOAT_st *pInstanceL = (Mix_Private_FLOAT_st *)(ptrInstance1->PrivateParams);
- Mix_Private_FLOAT_st *pInstanceR = (Mix_Private_FLOAT_st *)(ptrInstance2->PrivateParams);
-
- LVM_FLOAT DeltaL = pInstanceL->Delta;
- LVM_FLOAT CurrentL = pInstanceL->Current;
- LVM_FLOAT TargetL = pInstanceL->Target;
-
- LVM_FLOAT DeltaR = pInstanceR->Delta;
- LVM_FLOAT CurrentR = pInstanceR->Current;
- LVM_FLOAT TargetR = pInstanceR->Target;
-
- LVM_FLOAT Temp = 0;
-
- InLoop = (LVM_INT16)(n >> 2); /* Process per 4 samples */
- OutLoop = (LVM_INT16)(n - (InLoop << 2));
-
- if (OutLoop)
- {
- if(CurrentL < TargetL)
- {
- ADD2_SAT_FLOAT(CurrentL, DeltaL, Temp);
- CurrentL = Temp;
- if (CurrentL > TargetL)
- CurrentL = TargetL;
- }
- else
- {
- CurrentL -= DeltaL;
- if (CurrentL < TargetL)
- CurrentL = TargetL;
- }
-
- if(CurrentR < TargetR)
- {
- ADD2_SAT_FLOAT(CurrentR, DeltaR, Temp);
- CurrentR = Temp;
- if (CurrentR > TargetR)
- CurrentR = TargetR;
- }
- else
- {
- CurrentR -= DeltaR;
- if (CurrentR < TargetR)
- CurrentR = TargetR;
- }
-
- for (ii = OutLoop * 2; ii != 0; ii -= 2)
- {
- *(dst++) = (LVM_FLOAT)(((LVM_FLOAT)*(src++) * (LVM_FLOAT)CurrentL));
- *(dst++) = (LVM_FLOAT)(((LVM_FLOAT)*(src++) * (LVM_FLOAT)CurrentR));
- }
- }
-
- for (ii = InLoop * 2; ii != 0; ii-=2)
- {
- if(CurrentL < TargetL)
- {
- ADD2_SAT_FLOAT(CurrentL, DeltaL, Temp);
- CurrentL = Temp;
- if (CurrentL > TargetL)
- CurrentL = TargetL;
- }
- else
- {
- CurrentL -= DeltaL;
- if (CurrentL < TargetL)
- CurrentL = TargetL;
- }
-
- if(CurrentR < TargetR)
- {
- ADD2_SAT_FLOAT(CurrentR, DeltaR, Temp);
- CurrentR = Temp;
- if (CurrentR > TargetR)
- CurrentR = TargetR;
- }
- else
- {
- CurrentR -= DeltaR;
- if (CurrentR < TargetR)
- CurrentR = TargetR;
- }
-
- *(dst++) = (LVM_FLOAT)(((LVM_FLOAT)*(src++) * (LVM_FLOAT)CurrentL));
- *(dst++) = (LVM_FLOAT)(((LVM_FLOAT)*(src++) * (LVM_FLOAT)CurrentR));
- *(dst++) = (LVM_FLOAT)(((LVM_FLOAT)*(src++) * (LVM_FLOAT)CurrentL));
- *(dst++) = (LVM_FLOAT)(((LVM_FLOAT)*(src++) * (LVM_FLOAT)CurrentR));
- *(dst++) = (LVM_FLOAT)(((LVM_FLOAT)*(src++) * (LVM_FLOAT)CurrentL));
- *(dst++) = (LVM_FLOAT)(((LVM_FLOAT)*(src++) * (LVM_FLOAT)CurrentR));
- *(dst++) = (LVM_FLOAT)(((LVM_FLOAT)*(src++) * (LVM_FLOAT)CurrentL));
- *(dst++) = (LVM_FLOAT)(((LVM_FLOAT)*(src++) * (LVM_FLOAT)CurrentR));
- }
- pInstanceL->Current = CurrentL;
- pInstanceR->Current = CurrentR;
-
-}
-#ifdef SUPPORT_MC
-void LVC_Core_MixSoft_1St_MC_float_WRA (Mix_Private_FLOAT_st **ptrInstance,
- const LVM_FLOAT *src,
- LVM_FLOAT *dst,
- LVM_INT16 NrFrames,
- LVM_INT16 NrChannels)
-{
- LVM_INT32 ii, ch;
- LVM_FLOAT Temp =0.0f;
- LVM_FLOAT tempCurrent[NrChannels];
- for (ch = 0; ch < NrChannels; ch++)
- {
- tempCurrent[ch] = ptrInstance[ch]->Current;
- }
- for (ii = NrFrames; ii > 0; ii--)
- {
- for (ch = 0; ch < NrChannels; ch++)
- {
- Mix_Private_FLOAT_st *pInstance = ptrInstance[ch];
- const LVM_FLOAT Delta = pInstance->Delta;
- LVM_FLOAT Current = tempCurrent[ch];
- const LVM_FLOAT Target = pInstance->Target;
- if (Current < Target)
- {
- ADD2_SAT_FLOAT(Current, Delta, Temp);
- Current = Temp;
- if (Current > Target)
- Current = Target;
- }
- else
- {
- Current -= Delta;
- if (Current < Target)
- Current = Target;
- }
- *dst++ = *src++ * Current;
- tempCurrent[ch] = Current;
- }
- }
- for (ch = 0; ch < NrChannels; ch++)
- {
- ptrInstance[ch]->Current = tempCurrent[ch];
- }
-}
-#endif
-#else
-void LVC_Core_MixSoft_1St_2i_D16C31_WRA( LVMixer3_st *ptrInstance1,
- LVMixer3_st *ptrInstance2,
- const LVM_INT16 *src,
- LVM_INT16 *dst,
- LVM_INT16 n)
-{
- LVM_INT16 OutLoop;
- LVM_INT16 InLoop;
- LVM_INT16 CurrentShortL;
- LVM_INT16 CurrentShortR;
- LVM_INT32 ii;
- Mix_Private_st *pInstanceL=(Mix_Private_st *)(ptrInstance1->PrivateParams);
- Mix_Private_st *pInstanceR=(Mix_Private_st *)(ptrInstance2->PrivateParams);
-
- LVM_INT32 DeltaL=pInstanceL->Delta;
- LVM_INT32 CurrentL=pInstanceL->Current;
- LVM_INT32 TargetL=pInstanceL->Target;
-
- LVM_INT32 DeltaR=pInstanceR->Delta;
- LVM_INT32 CurrentR=pInstanceR->Current;
- LVM_INT32 TargetR=pInstanceR->Target;
-
- LVM_INT32 Temp;
-
- InLoop = (LVM_INT16)(n >> 2); /* Process per 4 samples */
- OutLoop = (LVM_INT16)(n - (InLoop << 2));
-
- if (OutLoop)
- {
- if(CurrentL<TargetL)
- {
- ADD2_SAT_32x32(CurrentL,DeltaL,Temp); /* Q31 + Q31 into Q31*/
- CurrentL=Temp;
- if (CurrentL > TargetL)
- CurrentL = TargetL;
- }
- else
- {
- CurrentL -= DeltaL; /* Q31 + Q31 into Q31*/
- if (CurrentL < TargetL)
- CurrentL = TargetL;
- }
-
- if(CurrentR<TargetR)
- {
- ADD2_SAT_32x32(CurrentR,DeltaR,Temp); /* Q31 + Q31 into Q31*/
- CurrentR=Temp;
- if (CurrentR > TargetR)
- CurrentR = TargetR;
- }
- else
- {
- CurrentR -= DeltaR; /* Q31 + Q31 into Q31*/
- if (CurrentR < TargetR)
- CurrentR = TargetR;
- }
-
- CurrentShortL = (LVM_INT16)(CurrentL>>16); /* From Q31 to Q15*/
- CurrentShortR = (LVM_INT16)(CurrentR>>16); /* From Q31 to Q15*/
-
- for (ii = OutLoop*2; ii != 0; ii-=2)
- {
- *(dst++) = (LVM_INT16)(((LVM_INT32)*(src++) * (LVM_INT32)CurrentShortL)>>15); /* Q15*Q15>>15 into Q15 */
- *(dst++) = (LVM_INT16)(((LVM_INT32)*(src++) * (LVM_INT32)CurrentShortR)>>15); /* Q15*Q15>>15 into Q15 */
- }
- }
-
- for (ii = InLoop*2; ii != 0; ii-=2)
- {
- if(CurrentL<TargetL)
- {
- ADD2_SAT_32x32(CurrentL,DeltaL,Temp); /* Q31 + Q31 into Q31*/
- CurrentL=Temp;
- if (CurrentL > TargetL)
- CurrentL = TargetL;
- }
- else
- {
- CurrentL -= DeltaL; /* Q31 + Q31 into Q31*/
- if (CurrentL < TargetL)
- CurrentL = TargetL;
- }
-
- if(CurrentR<TargetR)
- {
- ADD2_SAT_32x32(CurrentR,DeltaR,Temp); /* Q31 + Q31 into Q31*/
- CurrentR=Temp;
- if (CurrentR > TargetR)
- CurrentR = TargetR;
- }
- else
- {
- CurrentR -= DeltaR; /* Q31 + Q31 into Q31*/
- if (CurrentR < TargetR)
- CurrentR = TargetR;
- }
-
- CurrentShortL = (LVM_INT16)(CurrentL>>16); /* From Q31 to Q15*/
- CurrentShortR = (LVM_INT16)(CurrentR>>16); /* From Q31 to Q15*/
-
- *(dst++) = (LVM_INT16)(((LVM_INT32)*(src++) * (LVM_INT32)CurrentShortL)>>15); /* Q15*Q15>>15 into Q15 */
- *(dst++) = (LVM_INT16)(((LVM_INT32)*(src++) * (LVM_INT32)CurrentShortR)>>15); /* Q15*Q15>>15 into Q15 */
- *(dst++) = (LVM_INT16)(((LVM_INT32)*(src++) * (LVM_INT32)CurrentShortL)>>15);
- *(dst++) = (LVM_INT16)(((LVM_INT32)*(src++) * (LVM_INT32)CurrentShortR)>>15);
- *(dst++) = (LVM_INT16)(((LVM_INT32)*(src++) * (LVM_INT32)CurrentShortL)>>15);
- *(dst++) = (LVM_INT16)(((LVM_INT32)*(src++) * (LVM_INT32)CurrentShortR)>>15);
- *(dst++) = (LVM_INT16)(((LVM_INT32)*(src++) * (LVM_INT32)CurrentShortL)>>15);
- *(dst++) = (LVM_INT16)(((LVM_INT32)*(src++) * (LVM_INT32)CurrentShortR)>>15);
- }
- pInstanceL->Current=CurrentL;
- pInstanceR->Current=CurrentR;
-
-}
-#endif
-/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_2i_D16C31_WRA.cpp b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_2i_D16C31_WRA.cpp
new file mode 100644
index 0000000..1f4b08a
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_2i_D16C31_WRA.cpp
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**********************************************************************************
+ INCLUDE FILES
+***********************************************************************************/
+
+#include "LVC_Mixer_Private.h"
+#include "ScalarArithmetic.h"
+#include "LVM_Macros.h"
+
+/**********************************************************************************
+ FUNCTION LVC_Core_MixSoft_1St_2i_D16C31_WRA
+***********************************************************************************/
+static LVM_FLOAT ADD2_SAT_FLOAT(LVM_FLOAT a,
+ LVM_FLOAT b,
+ LVM_FLOAT c)
+{
+ LVM_FLOAT temp;
+ temp = a + b ;
+ if (temp < -1.0f)
+ c = -1.0f;
+ else if (temp > 1.0f)
+ c = 1.0f;
+ else
+ c = temp;
+ return c;
+}
+void LVC_Core_MixSoft_1St_2i_D16C31_WRA( LVMixer3_FLOAT_st *ptrInstance1,
+ LVMixer3_FLOAT_st *ptrInstance2,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ LVM_INT16 OutLoop;
+ LVM_INT16 InLoop;
+ LVM_INT32 ii;
+ Mix_Private_FLOAT_st *pInstanceL = (Mix_Private_FLOAT_st *)(ptrInstance1->PrivateParams);
+ Mix_Private_FLOAT_st *pInstanceR = (Mix_Private_FLOAT_st *)(ptrInstance2->PrivateParams);
+
+ LVM_FLOAT DeltaL = pInstanceL->Delta;
+ LVM_FLOAT CurrentL = pInstanceL->Current;
+ LVM_FLOAT TargetL = pInstanceL->Target;
+
+ LVM_FLOAT DeltaR = pInstanceR->Delta;
+ LVM_FLOAT CurrentR = pInstanceR->Current;
+ LVM_FLOAT TargetR = pInstanceR->Target;
+
+ LVM_FLOAT Temp = 0;
+
+ InLoop = (LVM_INT16)(n >> 2); /* Process per 4 samples */
+ OutLoop = (LVM_INT16)(n - (InLoop << 2));
+
+ if (OutLoop)
+ {
+ if(CurrentL < TargetL)
+ {
+ ADD2_SAT_FLOAT(CurrentL, DeltaL, Temp);
+ CurrentL = Temp;
+ if (CurrentL > TargetL)
+ CurrentL = TargetL;
+ }
+ else
+ {
+ CurrentL -= DeltaL;
+ if (CurrentL < TargetL)
+ CurrentL = TargetL;
+ }
+
+ if(CurrentR < TargetR)
+ {
+ ADD2_SAT_FLOAT(CurrentR, DeltaR, Temp);
+ CurrentR = Temp;
+ if (CurrentR > TargetR)
+ CurrentR = TargetR;
+ }
+ else
+ {
+ CurrentR -= DeltaR;
+ if (CurrentR < TargetR)
+ CurrentR = TargetR;
+ }
+
+ for (ii = OutLoop * 2; ii != 0; ii -= 2)
+ {
+ *(dst++) = (LVM_FLOAT)(((LVM_FLOAT)*(src++) * (LVM_FLOAT)CurrentL));
+ *(dst++) = (LVM_FLOAT)(((LVM_FLOAT)*(src++) * (LVM_FLOAT)CurrentR));
+ }
+ }
+
+ for (ii = InLoop * 2; ii != 0; ii-=2)
+ {
+ if(CurrentL < TargetL)
+ {
+ ADD2_SAT_FLOAT(CurrentL, DeltaL, Temp);
+ CurrentL = Temp;
+ if (CurrentL > TargetL)
+ CurrentL = TargetL;
+ }
+ else
+ {
+ CurrentL -= DeltaL;
+ if (CurrentL < TargetL)
+ CurrentL = TargetL;
+ }
+
+ if(CurrentR < TargetR)
+ {
+ ADD2_SAT_FLOAT(CurrentR, DeltaR, Temp);
+ CurrentR = Temp;
+ if (CurrentR > TargetR)
+ CurrentR = TargetR;
+ }
+ else
+ {
+ CurrentR -= DeltaR;
+ if (CurrentR < TargetR)
+ CurrentR = TargetR;
+ }
+
+ *(dst++) = (LVM_FLOAT)(((LVM_FLOAT)*(src++) * (LVM_FLOAT)CurrentL));
+ *(dst++) = (LVM_FLOAT)(((LVM_FLOAT)*(src++) * (LVM_FLOAT)CurrentR));
+ *(dst++) = (LVM_FLOAT)(((LVM_FLOAT)*(src++) * (LVM_FLOAT)CurrentL));
+ *(dst++) = (LVM_FLOAT)(((LVM_FLOAT)*(src++) * (LVM_FLOAT)CurrentR));
+ *(dst++) = (LVM_FLOAT)(((LVM_FLOAT)*(src++) * (LVM_FLOAT)CurrentL));
+ *(dst++) = (LVM_FLOAT)(((LVM_FLOAT)*(src++) * (LVM_FLOAT)CurrentR));
+ *(dst++) = (LVM_FLOAT)(((LVM_FLOAT)*(src++) * (LVM_FLOAT)CurrentL));
+ *(dst++) = (LVM_FLOAT)(((LVM_FLOAT)*(src++) * (LVM_FLOAT)CurrentR));
+ }
+ pInstanceL->Current = CurrentL;
+ pInstanceR->Current = CurrentR;
+
+}
+#ifdef SUPPORT_MC
+void LVC_Core_MixSoft_1St_MC_float_WRA (Mix_Private_FLOAT_st **ptrInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 NrFrames,
+ LVM_INT16 NrChannels)
+{
+ LVM_INT32 ii, ch;
+ LVM_FLOAT Temp =0.0f;
+ LVM_FLOAT tempCurrent[NrChannels];
+ for (ch = 0; ch < NrChannels; ch++)
+ {
+ tempCurrent[ch] = ptrInstance[ch]->Current;
+ }
+ for (ii = NrFrames; ii > 0; ii--)
+ {
+ for (ch = 0; ch < NrChannels; ch++)
+ {
+ Mix_Private_FLOAT_st *pInstance = ptrInstance[ch];
+ const LVM_FLOAT Delta = pInstance->Delta;
+ LVM_FLOAT Current = tempCurrent[ch];
+ const LVM_FLOAT Target = pInstance->Target;
+ if (Current < Target)
+ {
+ ADD2_SAT_FLOAT(Current, Delta, Temp);
+ Current = Temp;
+ if (Current > Target)
+ Current = Target;
+ }
+ else
+ {
+ Current -= Delta;
+ if (Current < Target)
+ Current = Target;
+ }
+ *dst++ = *src++ * Current;
+ tempCurrent[ch] = Current;
+ }
+ }
+ for (ch = 0; ch < NrChannels; ch++)
+ {
+ ptrInstance[ch]->Current = tempCurrent[ch];
+ }
+}
+#endif
+/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_D16C31_WRA.c b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_D16C31_WRA.c
deleted file mode 100644
index 5bfdad8..0000000
--- a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_D16C31_WRA.c
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**********************************************************************************
- INCLUDE FILES
-***********************************************************************************/
-
-#include "LVC_Mixer_Private.h"
-#include "LVM_Macros.h"
-#include "ScalarArithmetic.h"
-
-/**********************************************************************************
- FUNCTION LVCore_MIXSOFT_1ST_D16C31_WRA
-***********************************************************************************/
-#ifdef BUILD_FLOAT
-void LVC_Core_MixSoft_1St_D16C31_WRA(LVMixer3_FLOAT_st *ptrInstance,
- const LVM_FLOAT *src,
- LVM_FLOAT *dst,
- LVM_INT16 n)
-{
- LVM_INT16 OutLoop;
- LVM_INT16 InLoop;
- LVM_INT32 ii;
- Mix_Private_FLOAT_st *pInstance=(Mix_Private_FLOAT_st *)(ptrInstance->PrivateParams);
- LVM_FLOAT Delta= (LVM_FLOAT)pInstance->Delta;
- LVM_FLOAT Current = (LVM_FLOAT)pInstance->Current;
- LVM_FLOAT Target= (LVM_FLOAT)pInstance->Target;
- LVM_FLOAT Temp;
-
- InLoop = (LVM_INT16)(n >> 2); /* Process per 4 samples */
- OutLoop = (LVM_INT16)(n - (InLoop << 2));
-
- if(Current<Target){
- if (OutLoop){
-
- Temp = Current + Delta;
- if (Temp > 1.0f)
- Temp = 1.0f;
- else if (Temp < -1.0f)
- Temp = -1.0f;
-
- Current=Temp;
- if (Current > Target)
- Current = Target;
-
- for (ii = OutLoop; ii != 0; ii--){
- *(dst++) = (((LVM_FLOAT)*(src++) * (LVM_FLOAT)Current));
- }
- }
-
- for (ii = InLoop; ii != 0; ii--){
-
- Temp = Current + Delta;
-
- if (Temp > 1.0f)
- Temp = 1.0f;
- else if (Temp < -1.0f)
- Temp = -1.0f;
-
- Current=Temp;
- if (Current > Target)
- Current = Target;
-
- *(dst++) = (((LVM_FLOAT)*(src++) * Current) );
- *(dst++) = (((LVM_FLOAT)*(src++) * Current) );
- *(dst++) = (((LVM_FLOAT)*(src++) * Current) );
- *(dst++) = (((LVM_FLOAT)*(src++) * Current) );
- }
- }
- else{
- if (OutLoop){
- Current -= Delta;
- if (Current < Target)
- Current = Target;
-
- for (ii = OutLoop; ii != 0; ii--){
- *(dst++) = (((LVM_FLOAT)*(src++) * Current));
- }
- }
-
- for (ii = InLoop; ii != 0; ii--){
- Current -= Delta;
- if (Current < Target)
- Current = Target;
-
- *(dst++) = (((LVM_FLOAT)*(src++) * Current));
- *(dst++) = (((LVM_FLOAT)*(src++) * Current));
- *(dst++) = (((LVM_FLOAT)*(src++) * Current));
- *(dst++) = (((LVM_FLOAT)*(src++) * Current));
- }
- }
- pInstance->Current=Current;
-}
-
-
-#ifdef SUPPORT_MC
-/*
- * FUNCTION: LVC_Core_MixSoft_Mc_D16C31_WRA
- *
- * DESCRIPTION:
- * Mixer function with support for processing multichannel input
- *
- * PARAMETERS:
- * ptrInstance Instance pointer
- * src Source
- * dst Destination
- * NrFrames Number of frames
- * NrChannels Number of channels
- *
- * RETURNS:
- * void
- *
- */
-void LVC_Core_MixSoft_Mc_D16C31_WRA(LVMixer3_FLOAT_st *ptrInstance,
- const LVM_FLOAT *src,
- LVM_FLOAT *dst,
- LVM_INT16 NrFrames,
- LVM_INT16 NrChannels)
-{
- LVM_INT16 OutLoop;
- LVM_INT16 InLoop;
- LVM_INT32 ii, jj;
- Mix_Private_FLOAT_st *pInstance=(Mix_Private_FLOAT_st *)(ptrInstance->PrivateParams);
- LVM_FLOAT Delta= (LVM_FLOAT)pInstance->Delta;
- LVM_FLOAT Current = (LVM_FLOAT)pInstance->Current;
- LVM_FLOAT Target= (LVM_FLOAT)pInstance->Target;
- LVM_FLOAT Temp;
-
- /*
- * Same operation is performed on consecutive frames.
- * So two frames are processed in one iteration and
- * the loop will run only for half the NrFrames value times.
- */
- InLoop = (LVM_INT16)(NrFrames >> 1);
- /* OutLoop is calculated to handle cases where NrFrames value can be odd.*/
- OutLoop = (LVM_INT16)(NrFrames - (InLoop << 1));
-
- if (Current<Target) {
- if (OutLoop) {
-
- Temp = Current + Delta;
- if (Temp > 1.0f)
- Temp = 1.0f;
- else if (Temp < -1.0f)
- Temp = -1.0f;
-
- Current=Temp;
- if (Current > Target)
- Current = Target;
-
- for (ii = OutLoop; ii != 0; ii--) {
- for (jj = NrChannels; jj !=0; jj--) {
- *(dst++) = (((LVM_FLOAT)*(src++) * (LVM_FLOAT)Current));
- }
- }
- }
-
- for (ii = InLoop; ii != 0; ii--) {
-
- Temp = Current + Delta;
-
- if (Temp > 1.0f)
- Temp = 1.0f;
- else if (Temp < -1.0f)
- Temp = -1.0f;
-
- Current=Temp;
- if (Current > Target)
- Current = Target;
-
- for (jj = NrChannels; jj != 0 ; jj--)
- {
- *(dst++) = (((LVM_FLOAT)*(src++) * Current));
- *(dst++) = (((LVM_FLOAT)*(src++) * Current));
- }
- }
- }
- else{
- if (OutLoop) {
- Current -= Delta;
- if (Current < Target)
- Current = Target;
-
- for (ii = OutLoop; ii != 0; ii--) {
- for (jj = NrChannels; jj !=0; jj--) {
- *(dst++) = (((LVM_FLOAT)*(src++) * (LVM_FLOAT)Current));
- }
- }
- }
-
- for (ii = InLoop; ii != 0; ii--) {
- Current -= Delta;
- if (Current < Target)
- Current = Target;
-
- for (jj = NrChannels; jj != 0 ; jj--)
- {
- *(dst++) = (((LVM_FLOAT)*(src++) * Current));
- *(dst++) = (((LVM_FLOAT)*(src++) * Current));
- }
- }
- }
- pInstance->Current=Current;
-}
-#endif
-
-#else
-void LVC_Core_MixSoft_1St_D16C31_WRA( LVMixer3_st *ptrInstance,
- const LVM_INT16 *src,
- LVM_INT16 *dst,
- LVM_INT16 n)
-{
- LVM_INT16 OutLoop;
- LVM_INT16 InLoop;
- LVM_INT16 CurrentShort;
- LVM_INT32 ii;
- Mix_Private_st *pInstance=(Mix_Private_st *)(ptrInstance->PrivateParams);
- LVM_INT32 Delta=pInstance->Delta;
- LVM_INT32 Current=pInstance->Current;
- LVM_INT32 Target=pInstance->Target;
- LVM_INT32 Temp;
-
- InLoop = (LVM_INT16)(n >> 2); /* Process per 4 samples */
- OutLoop = (LVM_INT16)(n - (InLoop << 2));
-
- if(Current<Target){
- if (OutLoop){
- ADD2_SAT_32x32(Current,Delta,Temp); /* Q31 + Q31 into Q31*/
- Current=Temp;
- if (Current > Target)
- Current = Target;
-
- CurrentShort = (LVM_INT16)(Current>>16); /* From Q31 to Q15*/
-
- for (ii = OutLoop; ii != 0; ii--){
- *(dst++) = (LVM_INT16)(((LVM_INT32)*(src++) * (LVM_INT32)CurrentShort)>>15); /* Q15*Q15>>15 into Q15 */
- }
- }
-
- for (ii = InLoop; ii != 0; ii--){
- ADD2_SAT_32x32(Current,Delta,Temp); /* Q31 + Q31 into Q31*/
- Current=Temp;
- if (Current > Target)
- Current = Target;
-
- CurrentShort = (LVM_INT16)(Current>>16); /* From Q31 to Q15*/
-
- *(dst++) = (LVM_INT16)(((LVM_INT32)*(src++) * (LVM_INT32)CurrentShort)>>15); /* Q15*Q15>>15 into Q15 */
- *(dst++) = (LVM_INT16)(((LVM_INT32)*(src++) * (LVM_INT32)CurrentShort)>>15);
- *(dst++) = (LVM_INT16)(((LVM_INT32)*(src++) * (LVM_INT32)CurrentShort)>>15);
- *(dst++) = (LVM_INT16)(((LVM_INT32)*(src++) * (LVM_INT32)CurrentShort)>>15);
- }
- }
- else{
- if (OutLoop){
- Current -= Delta; /* Q31 + Q31 into Q31*/
- if (Current < Target)
- Current = Target;
-
- CurrentShort = (LVM_INT16)(Current>>16); /* From Q31 to Q15*/
-
- for (ii = OutLoop; ii != 0; ii--){
- *(dst++) = (LVM_INT16)(((LVM_INT32)*(src++) * (LVM_INT32)CurrentShort)>>15); /* Q15*Q15>>15 into Q15 */
- }
- }
-
- for (ii = InLoop; ii != 0; ii--){
- Current -= Delta; /* Q31 + Q31 into Q31*/
- if (Current < Target)
- Current = Target;
-
- CurrentShort = (LVM_INT16)(Current>>16); /* From Q31 to Q15*/
-
- *(dst++) = (LVM_INT16)(((LVM_INT32)*(src++) * (LVM_INT32)CurrentShort)>>15); /* Q15*Q15>>15 into Q15 */
- *(dst++) = (LVM_INT16)(((LVM_INT32)*(src++) * (LVM_INT32)CurrentShort)>>15);
- *(dst++) = (LVM_INT16)(((LVM_INT32)*(src++) * (LVM_INT32)CurrentShort)>>15);
- *(dst++) = (LVM_INT16)(((LVM_INT32)*(src++) * (LVM_INT32)CurrentShort)>>15);
- }
- }
- pInstance->Current=Current;
-}
-#endif
-/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_D16C31_WRA.cpp b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_D16C31_WRA.cpp
new file mode 100644
index 0000000..5d8aadc
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_D16C31_WRA.cpp
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**********************************************************************************
+ INCLUDE FILES
+***********************************************************************************/
+
+#include "LVC_Mixer_Private.h"
+#include "LVM_Macros.h"
+#include "ScalarArithmetic.h"
+
+/**********************************************************************************
+ FUNCTION LVCore_MIXSOFT_1ST_D16C31_WRA
+***********************************************************************************/
+void LVC_Core_MixSoft_1St_D16C31_WRA(LVMixer3_FLOAT_st *ptrInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ LVM_INT16 OutLoop;
+ LVM_INT16 InLoop;
+ LVM_INT32 ii;
+ Mix_Private_FLOAT_st *pInstance=(Mix_Private_FLOAT_st *)(ptrInstance->PrivateParams);
+ LVM_FLOAT Delta= (LVM_FLOAT)pInstance->Delta;
+ LVM_FLOAT Current = (LVM_FLOAT)pInstance->Current;
+ LVM_FLOAT Target= (LVM_FLOAT)pInstance->Target;
+ LVM_FLOAT Temp;
+
+ InLoop = (LVM_INT16)(n >> 2); /* Process per 4 samples */
+ OutLoop = (LVM_INT16)(n - (InLoop << 2));
+
+ if(Current<Target){
+ if (OutLoop){
+
+ Temp = Current + Delta;
+ if (Temp > 1.0f)
+ Temp = 1.0f;
+ else if (Temp < -1.0f)
+ Temp = -1.0f;
+
+ Current=Temp;
+ if (Current > Target)
+ Current = Target;
+
+ for (ii = OutLoop; ii != 0; ii--){
+ *(dst++) = (((LVM_FLOAT)*(src++) * (LVM_FLOAT)Current));
+ }
+ }
+
+ for (ii = InLoop; ii != 0; ii--){
+
+ Temp = Current + Delta;
+
+ if (Temp > 1.0f)
+ Temp = 1.0f;
+ else if (Temp < -1.0f)
+ Temp = -1.0f;
+
+ Current=Temp;
+ if (Current > Target)
+ Current = Target;
+
+ *(dst++) = (((LVM_FLOAT)*(src++) * Current) );
+ *(dst++) = (((LVM_FLOAT)*(src++) * Current) );
+ *(dst++) = (((LVM_FLOAT)*(src++) * Current) );
+ *(dst++) = (((LVM_FLOAT)*(src++) * Current) );
+ }
+ }
+ else{
+ if (OutLoop){
+ Current -= Delta;
+ if (Current < Target)
+ Current = Target;
+
+ for (ii = OutLoop; ii != 0; ii--){
+ *(dst++) = (((LVM_FLOAT)*(src++) * Current));
+ }
+ }
+
+ for (ii = InLoop; ii != 0; ii--){
+ Current -= Delta;
+ if (Current < Target)
+ Current = Target;
+
+ *(dst++) = (((LVM_FLOAT)*(src++) * Current));
+ *(dst++) = (((LVM_FLOAT)*(src++) * Current));
+ *(dst++) = (((LVM_FLOAT)*(src++) * Current));
+ *(dst++) = (((LVM_FLOAT)*(src++) * Current));
+ }
+ }
+ pInstance->Current=Current;
+}
+
+#ifdef SUPPORT_MC
+/*
+ * FUNCTION: LVC_Core_MixSoft_Mc_D16C31_WRA
+ *
+ * DESCRIPTION:
+ * Mixer function with support for processing multichannel input
+ *
+ * PARAMETERS:
+ * ptrInstance Instance pointer
+ * src Source
+ * dst Destination
+ * NrFrames Number of frames
+ * NrChannels Number of channels
+ *
+ * RETURNS:
+ * void
+ *
+ */
+void LVC_Core_MixSoft_Mc_D16C31_WRA(LVMixer3_FLOAT_st *ptrInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 NrFrames,
+ LVM_INT16 NrChannels)
+{
+ LVM_INT16 OutLoop;
+ LVM_INT16 InLoop;
+ LVM_INT32 ii, jj;
+ Mix_Private_FLOAT_st *pInstance=(Mix_Private_FLOAT_st *)(ptrInstance->PrivateParams);
+ LVM_FLOAT Delta= (LVM_FLOAT)pInstance->Delta;
+ LVM_FLOAT Current = (LVM_FLOAT)pInstance->Current;
+ LVM_FLOAT Target= (LVM_FLOAT)pInstance->Target;
+ LVM_FLOAT Temp;
+
+ /*
+ * Same operation is performed on consecutive frames.
+ * So two frames are processed in one iteration and
+ * the loop will run only for half the NrFrames value times.
+ */
+ InLoop = (LVM_INT16)(NrFrames >> 1);
+ /* OutLoop is calculated to handle cases where NrFrames value can be odd.*/
+ OutLoop = (LVM_INT16)(NrFrames - (InLoop << 1));
+
+ if (Current<Target) {
+ if (OutLoop) {
+
+ Temp = Current + Delta;
+ if (Temp > 1.0f)
+ Temp = 1.0f;
+ else if (Temp < -1.0f)
+ Temp = -1.0f;
+
+ Current=Temp;
+ if (Current > Target)
+ Current = Target;
+
+ for (ii = OutLoop; ii != 0; ii--) {
+ for (jj = NrChannels; jj !=0; jj--) {
+ *(dst++) = (((LVM_FLOAT)*(src++) * (LVM_FLOAT)Current));
+ }
+ }
+ }
+
+ for (ii = InLoop; ii != 0; ii--) {
+
+ Temp = Current + Delta;
+
+ if (Temp > 1.0f)
+ Temp = 1.0f;
+ else if (Temp < -1.0f)
+ Temp = -1.0f;
+
+ Current=Temp;
+ if (Current > Target)
+ Current = Target;
+
+ for (jj = NrChannels; jj != 0 ; jj--)
+ {
+ *(dst++) = (((LVM_FLOAT)*(src++) * Current));
+ *(dst++) = (((LVM_FLOAT)*(src++) * Current));
+ }
+ }
+ }
+ else{
+ if (OutLoop) {
+ Current -= Delta;
+ if (Current < Target)
+ Current = Target;
+
+ for (ii = OutLoop; ii != 0; ii--) {
+ for (jj = NrChannels; jj !=0; jj--) {
+ *(dst++) = (((LVM_FLOAT)*(src++) * (LVM_FLOAT)Current));
+ }
+ }
+ }
+
+ for (ii = InLoop; ii != 0; ii--) {
+ Current -= Delta;
+ if (Current < Target)
+ Current = Target;
+
+ for (jj = NrChannels; jj != 0 ; jj--)
+ {
+ *(dst++) = (((LVM_FLOAT)*(src++) * Current));
+ *(dst++) = (((LVM_FLOAT)*(src++) * Current));
+ }
+ }
+ }
+ pInstance->Current=Current;
+}
+#endif
+
+/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_MixInSoft_D16C31_SAT.c b/media/libeffects/lvm/lib/Common/src/LVC_MixInSoft_D16C31_SAT.c
deleted file mode 100644
index 65956f7..0000000
--- a/media/libeffects/lvm/lib/Common/src/LVC_MixInSoft_D16C31_SAT.c
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**********************************************************************************
- INCLUDE FILES
-***********************************************************************************/
-
-#include "LVC_Mixer_Private.h"
-#include "VectorArithmetic.h"
-#include "ScalarArithmetic.h"
-
-/**********************************************************************************
- DEFINITIONS
-***********************************************************************************/
-
-#define TRUE 1
-#define FALSE 0
-
-/**********************************************************************************
- FUNCTION MIXINSOFT_D16C31_SAT
-***********************************************************************************/
-#ifdef BUILD_FLOAT
-void LVC_MixInSoft_D16C31_SAT(LVMixer3_1St_FLOAT_st *ptrInstance,
- const LVM_FLOAT *src,
- LVM_FLOAT *dst,
- LVM_INT16 n)
-{
- char HardMixing = TRUE;
- LVM_FLOAT TargetGain;
- Mix_Private_FLOAT_st *pInstance = \
- (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[0].PrivateParams);
-
- if(n <= 0) return;
-
- /******************************************************************************
- SOFT MIXING
- *******************************************************************************/
- if (pInstance->Current != pInstance->Target)
- {
- if(pInstance->Delta == 1.0f){
- pInstance->Current = pInstance->Target;
- TargetGain = pInstance->Target;
- LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
- }else if (Abs_Float(pInstance->Current - pInstance->Target) < pInstance->Delta){
- pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
- Make them equal. */
- TargetGain = pInstance->Target;
- LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
- }else{
- /* Soft mixing has to be applied */
- HardMixing = FALSE;
- LVC_Core_MixInSoft_D16C31_SAT(&(ptrInstance->MixerStream[0]), src, dst, n);
- }
- }
-
- /******************************************************************************
- HARD MIXING
- *******************************************************************************/
-
- if (HardMixing){
- if (pInstance->Target != 0){ /* Nothing to do in case Target = 0 */
- if ((pInstance->Target) == 1.0f){
- Add2_Sat_Float(src, dst, n);
- }
- else{
- Mac3s_Sat_Float(src, (pInstance->Target), dst, n);
- /* In case the LVCore function would have changed the Current value */
- pInstance->Current = pInstance->Target;
- }
- }
- }
-
-
- /******************************************************************************
- CALL BACK
- *******************************************************************************/
-
- if (ptrInstance->MixerStream[0].CallbackSet){
- if (Abs_Float(pInstance->Current - pInstance->Target) < pInstance->Delta){
- pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
- Make them equal. */
- TargetGain = pInstance->Target;
- LVC_Mixer_SetTarget(ptrInstance->MixerStream, TargetGain);
- ptrInstance->MixerStream[0].CallbackSet = FALSE;
- if (ptrInstance->MixerStream[0].pCallBack != 0){
- (*ptrInstance->MixerStream[0].pCallBack) ( \
- ptrInstance->MixerStream[0].pCallbackHandle,
- ptrInstance->MixerStream[0].pGeneralPurpose,
- ptrInstance->MixerStream[0].CallbackParam );
- }
- }
- }
-
-}
-
-
-
-#ifdef SUPPORT_MC
-/*
- * FUNCTION: LVC_MixInSoft_Mc_D16C31_SAT
- *
- * DESCRIPTION:
- * Mixer function with support for processing multichannel input
- *
- * PARAMETERS:
- * ptrInstance Instance pointer
- * src Source
- * dst Destination
- * NrFrames Number of frames
- * NrChannels Number of channels
- *
- * RETURNS:
- * void
- *
- */
-void LVC_MixInSoft_Mc_D16C31_SAT(LVMixer3_1St_FLOAT_st *ptrInstance,
- const LVM_FLOAT *src,
- LVM_FLOAT *dst,
- LVM_INT16 NrFrames,
- LVM_INT16 NrChannels)
-{
- char HardMixing = TRUE;
- LVM_FLOAT TargetGain;
- Mix_Private_FLOAT_st *pInstance = \
- (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[0].PrivateParams);
-
- if (NrFrames <= 0) return;
-
- /******************************************************************************
- SOFT MIXING
- *******************************************************************************/
- if (pInstance->Current != pInstance->Target)
- {
- if (pInstance->Delta == 1.0f) {
- pInstance->Current = pInstance->Target;
- TargetGain = pInstance->Target;
- LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
- }else if (Abs_Float(pInstance->Current - pInstance->Target) < pInstance->Delta) {
- pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
- Make them equal. */
- TargetGain = pInstance->Target;
- LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
- }else{
- /* Soft mixing has to be applied */
- HardMixing = FALSE;
- LVC_Core_MixInSoft_Mc_D16C31_SAT(&(ptrInstance->MixerStream[0]),
- src,
- dst,
- NrFrames,
- NrChannels);
- }
- }
-
- /******************************************************************************
- HARD MIXING
- *******************************************************************************/
-
- if (HardMixing) {
- if (pInstance->Target != 0) { /* Nothing to do in case Target = 0 */
- if ((pInstance->Target) == 1.0f) {
- Add2_Sat_Float(src, dst, NrFrames*NrChannels);
- }
- else{
- Mac3s_Sat_Float(src,
- (pInstance->Target),
- dst,
- NrFrames * NrChannels);
- /* In case the LVCore function would have changed the Current value */
- pInstance->Current = pInstance->Target;
- }
- }
- }
-
-
- /******************************************************************************
- CALL BACK
- *******************************************************************************/
-
- if (ptrInstance->MixerStream[0].CallbackSet) {
- if (Abs_Float(pInstance->Current - pInstance->Target) < pInstance->Delta) {
- pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
- Make them equal. */
- TargetGain = pInstance->Target;
- LVC_Mixer_SetTarget(ptrInstance->MixerStream, TargetGain);
- ptrInstance->MixerStream[0].CallbackSet = FALSE;
- if (ptrInstance->MixerStream[0].pCallBack != 0) {
- (*ptrInstance->MixerStream[0].pCallBack) (\
- ptrInstance->MixerStream[0].pCallbackHandle,
- ptrInstance->MixerStream[0].pGeneralPurpose,
- ptrInstance->MixerStream[0].CallbackParam);
- }
- }
- }
-
-}
-#endif
-
-
-#else
-void LVC_MixInSoft_D16C31_SAT( LVMixer3_1St_st *ptrInstance,
- LVM_INT16 *src,
- LVM_INT16 *dst,
- LVM_INT16 n)
-{
- char HardMixing = TRUE;
- LVM_INT32 TargetGain;
- Mix_Private_st *pInstance=(Mix_Private_st *)(ptrInstance->MixerStream[0].PrivateParams);
-
- if(n<=0) return;
-
- /******************************************************************************
- SOFT MIXING
- *******************************************************************************/
- if (pInstance->Current != pInstance->Target)
- {
- if(pInstance->Delta == 0x7FFFFFFF){
- pInstance->Current = pInstance->Target;
- TargetGain=pInstance->Target>>(16-pInstance->Shift); // TargetGain in Q16.15 format
- LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]),TargetGain);
- }else if (Abs_32(pInstance->Current-pInstance->Target) < pInstance->Delta){
- pInstance->Current = pInstance->Target; /* Difference is not significant anymore. Make them equal. */
- TargetGain=pInstance->Target>>(16-pInstance->Shift); // TargetGain in Q16.15 format
- LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]),TargetGain);
- }else{
- /* Soft mixing has to be applied */
- HardMixing = FALSE;
- if(pInstance->Shift!=0){
- Shift_Sat_v16xv16 ((LVM_INT16)pInstance->Shift,src,src,n);
- LVC_Core_MixInSoft_D16C31_SAT( &(ptrInstance->MixerStream[0]), src, dst, n);
- }
- else
- LVC_Core_MixInSoft_D16C31_SAT( &(ptrInstance->MixerStream[0]), src, dst, n);
- }
- }
-
- /******************************************************************************
- HARD MIXING
- *******************************************************************************/
-
- if (HardMixing){
- if (pInstance->Target != 0){ /* Nothing to do in case Target = 0 */
- if ((pInstance->Target>>16) == 0x7FFF){
- if(pInstance->Shift!=0)
- Shift_Sat_v16xv16 ((LVM_INT16)pInstance->Shift,src,src,n);
- Add2_Sat_16x16( src, dst, n );
- }
- else{
- if(pInstance->Shift!=0)
- Shift_Sat_v16xv16 ((LVM_INT16)pInstance->Shift,src,src,n);
- Mac3s_Sat_16x16(src,(LVM_INT16)(pInstance->Target>>16),dst,n);
- pInstance->Current = pInstance->Target; /* In case the LVCore function would have changed the Current value */
- }
- }
- }
-
-
- /******************************************************************************
- CALL BACK
- *******************************************************************************/
-
- if (ptrInstance->MixerStream[0].CallbackSet){
- if (Abs_32(pInstance->Current-pInstance->Target) < pInstance->Delta){
- pInstance->Current = pInstance->Target; /* Difference is not significant anymore. Make them equal. */
- TargetGain=pInstance->Target>>(16-pInstance->Shift); // TargetGain in Q16.15 format
- LVC_Mixer_SetTarget(ptrInstance->MixerStream,TargetGain);
- ptrInstance->MixerStream[0].CallbackSet = FALSE;
- if (ptrInstance->MixerStream[0].pCallBack != 0){
- (*ptrInstance->MixerStream[0].pCallBack) ( ptrInstance->MixerStream[0].pCallbackHandle, ptrInstance->MixerStream[0].pGeneralPurpose,ptrInstance->MixerStream[0].CallbackParam );
- }
- }
- }
-
-}
-#endif
-/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_MixInSoft_D16C31_SAT.cpp b/media/libeffects/lvm/lib/Common/src/LVC_MixInSoft_D16C31_SAT.cpp
new file mode 100644
index 0000000..2bec3be
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/LVC_MixInSoft_D16C31_SAT.cpp
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**********************************************************************************
+ INCLUDE FILES
+***********************************************************************************/
+
+#include "LVC_Mixer_Private.h"
+#include "VectorArithmetic.h"
+#include "ScalarArithmetic.h"
+
+/**********************************************************************************
+ DEFINITIONS
+***********************************************************************************/
+
+#define TRUE 1
+#define FALSE 0
+
+/**********************************************************************************
+ FUNCTION MIXINSOFT_D16C31_SAT
+***********************************************************************************/
+void LVC_MixInSoft_D16C31_SAT(LVMixer3_1St_FLOAT_st *ptrInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ char HardMixing = TRUE;
+ LVM_FLOAT TargetGain;
+ Mix_Private_FLOAT_st *pInstance = \
+ (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[0].PrivateParams);
+
+ if(n <= 0) return;
+
+ /******************************************************************************
+ SOFT MIXING
+ *******************************************************************************/
+ if (pInstance->Current != pInstance->Target)
+ {
+ if(pInstance->Delta == 1.0f){
+ pInstance->Current = pInstance->Target;
+ TargetGain = pInstance->Target;
+ LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
+ }else if (Abs_Float(pInstance->Current - pInstance->Target) < pInstance->Delta){
+ pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
+ Make them equal. */
+ TargetGain = pInstance->Target;
+ LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
+ }else{
+ /* Soft mixing has to be applied */
+ HardMixing = FALSE;
+ LVC_Core_MixInSoft_D16C31_SAT(&(ptrInstance->MixerStream[0]), src, dst, n);
+ }
+ }
+
+ /******************************************************************************
+ HARD MIXING
+ *******************************************************************************/
+
+ if (HardMixing){
+ if (pInstance->Target != 0){ /* Nothing to do in case Target = 0 */
+ if ((pInstance->Target) == 1.0f){
+ Add2_Sat_Float(src, dst, n);
+ }
+ else{
+ Mac3s_Sat_Float(src, (pInstance->Target), dst, n);
+ /* In case the LVCore function would have changed the Current value */
+ pInstance->Current = pInstance->Target;
+ }
+ }
+ }
+
+ /******************************************************************************
+ CALL BACK
+ *******************************************************************************/
+
+ if (ptrInstance->MixerStream[0].CallbackSet){
+ if (Abs_Float(pInstance->Current - pInstance->Target) < pInstance->Delta){
+ pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
+ Make them equal. */
+ TargetGain = pInstance->Target;
+ LVC_Mixer_SetTarget(ptrInstance->MixerStream, TargetGain);
+ ptrInstance->MixerStream[0].CallbackSet = FALSE;
+ if (ptrInstance->MixerStream[0].pCallBack != 0){
+ (*ptrInstance->MixerStream[0].pCallBack) ( \
+ ptrInstance->MixerStream[0].pCallbackHandle,
+ ptrInstance->MixerStream[0].pGeneralPurpose,
+ ptrInstance->MixerStream[0].CallbackParam );
+ }
+ }
+ }
+
+}
+
+#ifdef SUPPORT_MC
+/*
+ * FUNCTION: LVC_MixInSoft_Mc_D16C31_SAT
+ *
+ * DESCRIPTION:
+ * Mixer function with support for processing multichannel input
+ *
+ * PARAMETERS:
+ * ptrInstance Instance pointer
+ * src Source
+ * dst Destination
+ * NrFrames Number of frames
+ * NrChannels Number of channels
+ *
+ * RETURNS:
+ * void
+ *
+ */
+void LVC_MixInSoft_Mc_D16C31_SAT(LVMixer3_1St_FLOAT_st *ptrInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 NrFrames,
+ LVM_INT16 NrChannels)
+{
+ char HardMixing = TRUE;
+ LVM_FLOAT TargetGain;
+ Mix_Private_FLOAT_st *pInstance = \
+ (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[0].PrivateParams);
+
+ if (NrFrames <= 0) return;
+
+ /******************************************************************************
+ SOFT MIXING
+ *******************************************************************************/
+ if (pInstance->Current != pInstance->Target)
+ {
+ if (pInstance->Delta == 1.0f) {
+ pInstance->Current = pInstance->Target;
+ TargetGain = pInstance->Target;
+ LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
+ }else if (Abs_Float(pInstance->Current - pInstance->Target) < pInstance->Delta) {
+ pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
+ Make them equal. */
+ TargetGain = pInstance->Target;
+ LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
+ }else{
+ /* Soft mixing has to be applied */
+ HardMixing = FALSE;
+ LVC_Core_MixInSoft_Mc_D16C31_SAT(&(ptrInstance->MixerStream[0]),
+ src,
+ dst,
+ NrFrames,
+ NrChannels);
+ }
+ }
+
+ /******************************************************************************
+ HARD MIXING
+ *******************************************************************************/
+
+ if (HardMixing) {
+ if (pInstance->Target != 0) { /* Nothing to do in case Target = 0 */
+ if ((pInstance->Target) == 1.0f) {
+ Add2_Sat_Float(src, dst, NrFrames*NrChannels);
+ }
+ else{
+ Mac3s_Sat_Float(src,
+ (pInstance->Target),
+ dst,
+ NrFrames * NrChannels);
+ /* In case the LVCore function would have changed the Current value */
+ pInstance->Current = pInstance->Target;
+ }
+ }
+ }
+
+ /******************************************************************************
+ CALL BACK
+ *******************************************************************************/
+
+ if (ptrInstance->MixerStream[0].CallbackSet) {
+ if (Abs_Float(pInstance->Current - pInstance->Target) < pInstance->Delta) {
+ pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
+ Make them equal. */
+ TargetGain = pInstance->Target;
+ LVC_Mixer_SetTarget(ptrInstance->MixerStream, TargetGain);
+ ptrInstance->MixerStream[0].CallbackSet = FALSE;
+ if (ptrInstance->MixerStream[0].pCallBack != 0) {
+ (*ptrInstance->MixerStream[0].pCallBack) (\
+ ptrInstance->MixerStream[0].pCallbackHandle,
+ ptrInstance->MixerStream[0].pGeneralPurpose,
+ ptrInstance->MixerStream[0].CallbackParam);
+ }
+ }
+ }
+
+}
+#endif
+
+/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_2i_D16C31_SAT.c b/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_2i_D16C31_SAT.c
deleted file mode 100644
index a4682d3..0000000
--- a/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_2i_D16C31_SAT.c
+++ /dev/null
@@ -1,482 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**********************************************************************************
- INCLUDE FILES
-***********************************************************************************/
-
-#include <system/audio.h>
-
-#include "LVC_Mixer_Private.h"
-#include "VectorArithmetic.h"
-#include "ScalarArithmetic.h"
-
-/**********************************************************************************
- DEFINITIONS
-***********************************************************************************/
-
-#define TRUE 1
-#define FALSE 0
-
-#define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof(*(a))))
-
-/**********************************************************************************
- FUNCTION LVC_MixSoft_1St_2i_D16C31_SAT
-***********************************************************************************/
-#ifdef BUILD_FLOAT
-#ifdef SUPPORT_MC
-/* This threshold is used to decide on the processing to be applied on
- * front center and back center channels
- */
-#define LVM_VOL_BAL_THR (0.000016f)
-void LVC_MixSoft_1St_MC_float_SAT (LVMixer3_2St_FLOAT_st *ptrInstance,
- const LVM_FLOAT *src,
- LVM_FLOAT *dst,
- LVM_INT16 NrFrames,
- LVM_INT32 NrChannels,
- LVM_INT32 ChMask)
-{
- char HardMixing = TRUE;
- LVM_FLOAT TargetGain;
- Mix_Private_FLOAT_st Target_lfe = {LVM_MAXFLOAT, LVM_MAXFLOAT, LVM_MAXFLOAT};
- Mix_Private_FLOAT_st Target_ctr = {LVM_MAXFLOAT, LVM_MAXFLOAT, LVM_MAXFLOAT};
- Mix_Private_FLOAT_st *pInstance1 = \
- (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[0].PrivateParams);
- Mix_Private_FLOAT_st *pInstance2 = \
- (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[1].PrivateParams);
- Mix_Private_FLOAT_st *pMixPrivInst[4] = {pInstance1, pInstance2, &Target_ctr, &Target_lfe};
- Mix_Private_FLOAT_st *pInstance[NrChannels];
-
- if (audio_channel_mask_get_representation(ChMask)
- == AUDIO_CHANNEL_REPRESENTATION_INDEX)
- {
- for (int i = 0; i < 2; i++)
- {
- pInstance[i] = pMixPrivInst[i];
- }
- for (int i = 2; i < NrChannels; i++)
- {
- pInstance[i] = pMixPrivInst[2];
- }
- }
- else
- {
- // TODO: Combine with system/media/audio_utils/Balance.cpp
- // Constants in system/media/audio/include/system/audio-base.h
- // 'mixInstIdx' is used to map the appropriate mixer instance for each channel.
- const int mixInstIdx[] = {
- 0, // AUDIO_CHANNEL_OUT_FRONT_LEFT = 0x1u,
- 1, // AUDIO_CHANNEL_OUT_FRONT_RIGHT = 0x2u,
- 2, // AUDIO_CHANNEL_OUT_FRONT_CENTER = 0x4u,
- 3, // AUDIO_CHANNEL_OUT_LOW_FREQUENCY = 0x8u,
- 0, // AUDIO_CHANNEL_OUT_BACK_LEFT = 0x10u,
- 1, // AUDIO_CHANNEL_OUT_BACK_RIGHT = 0x20u,
- 0, // AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x40u,
- 1, // AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x80u,
- 2, // AUDIO_CHANNEL_OUT_BACK_CENTER = 0x100u,
- 0, // AUDIO_CHANNEL_OUT_SIDE_LEFT = 0x200u,
- 1, // AUDIO_CHANNEL_OUT_SIDE_RIGHT = 0x400u,
- 2, // AUDIO_CHANNEL_OUT_TOP_CENTER = 0x800u,
- 0, // AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT = 0x1000u,
- 2, // AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER = 0x2000u,
- 1, // AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT = 0x4000u,
- 0, // AUDIO_CHANNEL_OUT_TOP_BACK_LEFT = 0x8000u,
- 2, // AUDIO_CHANNEL_OUT_TOP_BACK_CENTER = 0x10000u,
- 1, // AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT = 0x20000u,
- 0, // AUDIO_CHANNEL_OUT_TOP_SIDE_LEFT = 0x40000u,
- 1, // AUDIO_CHANNEL_OUT_TOP_SIDE_RIGHT = 0x80000u
- };
- if (pInstance1->Target <= LVM_VOL_BAL_THR ||
- pInstance2->Target <= LVM_VOL_BAL_THR)
- {
- Target_ctr.Target = 0.0f;
- Target_ctr.Current = 0.0f;
- Target_ctr.Delta = 0.0f;
- }
- const unsigned int idxArrSize = ARRAY_SIZE(mixInstIdx);
- for (unsigned int i = 0, channel = ChMask; channel !=0 ; ++i)
- {
- const unsigned int idx = __builtin_ctz(channel);
- if (idx < idxArrSize)
- {
- pInstance[i] = pMixPrivInst[mixInstIdx[idx]];
- }
- else
- {
- pInstance[i] = pMixPrivInst[2];
- }
- channel &= ~(1 << idx);
- }
- }
-
- if (NrFrames <= 0) return;
-
- /******************************************************************************
- SOFT MIXING
- *******************************************************************************/
-
- if ((pInstance1->Current != pInstance1->Target) ||
- (pInstance2->Current != pInstance2->Target))
- {
- // TODO: combine similar checks below.
- if (pInstance1->Delta == LVM_MAXFLOAT
- || Abs_Float(pInstance1->Current - pInstance1->Target) < pInstance1->Delta)
- {
- /* Difference is not significant anymore. Make them equal. */
- pInstance1->Current = pInstance1->Target;
- TargetGain = pInstance1->Target;
- LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
- }
- else
- {
- /* Soft mixing has to be applied */
- HardMixing = FALSE;
- }
-
- if (HardMixing == TRUE)
- {
- if (pInstance2->Delta == LVM_MAXFLOAT
- || Abs_Float(pInstance2->Current - pInstance2->Target) < pInstance2->Delta)
- {
- /* Difference is not significant anymore. Make them equal. */
- pInstance2->Current = pInstance2->Target;
- TargetGain = pInstance2->Target;
- LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[1]), TargetGain);
- }
- else
- {
- /* Soft mixing has to be applied */
- HardMixing = FALSE;
- }
- }
-
- if (HardMixing == FALSE)
- {
- LVC_Core_MixSoft_1St_MC_float_WRA (&pInstance[0],
- src, dst, NrFrames, NrChannels);
- }
- }
-
- /******************************************************************************
- HARD MIXING
- *******************************************************************************/
-
- if (HardMixing == TRUE)
- {
- if ((pInstance1->Target == LVM_MAXFLOAT) && (pInstance2->Target == LVM_MAXFLOAT))
- {
- if (src != dst)
- {
- Copy_Float(src, dst, NrFrames*NrChannels);
- }
- }
- else
- {
- LVC_Core_MixHard_1St_MC_float_SAT(&(pInstance[0]),
- src, dst, NrFrames, NrChannels);
- }
- }
-
- /******************************************************************************
- CALL BACK
- *******************************************************************************/
-
- if (ptrInstance->MixerStream[0].CallbackSet)
- {
- if (Abs_Float(pInstance1->Current - pInstance1->Target) < pInstance1->Delta)
- {
- pInstance1->Current = pInstance1->Target; /* Difference is not significant anymore. \
- Make them equal. */
- TargetGain = pInstance1->Target;
- LVC_Mixer_SetTarget(&ptrInstance->MixerStream[0], TargetGain);
- ptrInstance->MixerStream[0].CallbackSet = FALSE;
- if (ptrInstance->MixerStream[0].pCallBack != 0)
- {
- (*ptrInstance->MixerStream[0].pCallBack) (\
- ptrInstance->MixerStream[0].pCallbackHandle,
- ptrInstance->MixerStream[0].pGeneralPurpose,
- ptrInstance->MixerStream[0].CallbackParam);
- }
- }
- }
- if (ptrInstance->MixerStream[1].CallbackSet)
- {
- if (Abs_Float(pInstance2->Current - pInstance2->Target) < pInstance2->Delta)
- {
- pInstance2->Current = pInstance2->Target; /* Difference is not significant anymore.
- Make them equal. */
- TargetGain = pInstance2->Target;
- LVC_Mixer_SetTarget(&ptrInstance->MixerStream[1], TargetGain);
- ptrInstance->MixerStream[1].CallbackSet = FALSE;
- if (ptrInstance->MixerStream[1].pCallBack != 0)
- {
- (*ptrInstance->MixerStream[1].pCallBack) (\
- ptrInstance->MixerStream[1].pCallbackHandle,
- ptrInstance->MixerStream[1].pGeneralPurpose,
- ptrInstance->MixerStream[1].CallbackParam);
- }
- }
- }
-}
-#endif
-void LVC_MixSoft_1St_2i_D16C31_SAT( LVMixer3_2St_FLOAT_st *ptrInstance,
- const LVM_FLOAT *src,
- LVM_FLOAT *dst,
- LVM_INT16 n)
-{
- char HardMixing = TRUE;
- LVM_FLOAT TargetGain;
- Mix_Private_FLOAT_st *pInstance1 = \
- (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[0].PrivateParams);
- Mix_Private_FLOAT_st *pInstance2 = \
- (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[1].PrivateParams);
-
- if(n <= 0) return;
-
- /******************************************************************************
- SOFT MIXING
- *******************************************************************************/
- if ((pInstance1->Current != pInstance1->Target) || (pInstance2->Current != pInstance2->Target))
- {
- if(pInstance1->Delta == 1.0f)
- {
- pInstance1->Current = pInstance1->Target;
- TargetGain = pInstance1->Target;
- LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
- }
- else if (Abs_Float(pInstance1->Current - pInstance1->Target) < pInstance1->Delta)
- {
- pInstance1->Current = pInstance1->Target; /* Difference is not significant anymore. \
- Make them equal. */
- TargetGain = pInstance1->Target;
- LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
- }
- else
- {
- /* Soft mixing has to be applied */
- HardMixing = FALSE;
- }
-
- if(HardMixing == TRUE)
- {
- if(pInstance2->Delta == 1.0f)
- {
- pInstance2->Current = pInstance2->Target;
- TargetGain = pInstance2->Target;
- LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[1]), TargetGain);
- }
- else if (Abs_Float(pInstance2->Current - pInstance2->Target) < pInstance2->Delta)
- {
- pInstance2->Current = pInstance2->Target; /* Difference is not significant anymore. \
- Make them equal. */
- TargetGain = pInstance2->Target;
- LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[1]), TargetGain);
- }
- else
- {
- /* Soft mixing has to be applied */
- HardMixing = FALSE;
- }
- }
-
- if(HardMixing == FALSE)
- {
- LVC_Core_MixSoft_1St_2i_D16C31_WRA( &(ptrInstance->MixerStream[0]),
- &(ptrInstance->MixerStream[1]),
- src, dst, n);
- }
- }
-
- /******************************************************************************
- HARD MIXING
- *******************************************************************************/
-
- if (HardMixing)
- {
- if ((pInstance1->Target == 1.0f) && (pInstance2->Target == 1.0f))
- {
- if(src != dst)
- {
- Copy_Float(src, dst, n);
- }
- }
- else
- {
- LVC_Core_MixHard_1St_2i_D16C31_SAT(&(ptrInstance->MixerStream[0]),
- &(ptrInstance->MixerStream[1]),
- src, dst, n);
- }
- }
-
- /******************************************************************************
- CALL BACK
- *******************************************************************************/
-
- if (ptrInstance->MixerStream[0].CallbackSet)
- {
- if (Abs_Float(pInstance1->Current - pInstance1->Target) < pInstance1->Delta)
- {
- pInstance1->Current = pInstance1->Target; /* Difference is not significant anymore. \
- Make them equal. */
- TargetGain = pInstance1->Target;
- LVC_Mixer_SetTarget(&ptrInstance->MixerStream[0], TargetGain);
- ptrInstance->MixerStream[0].CallbackSet = FALSE;
- if (ptrInstance->MixerStream[0].pCallBack != 0)
- {
- (*ptrInstance->MixerStream[0].pCallBack) ( \
- ptrInstance->MixerStream[0].pCallbackHandle,
- ptrInstance->MixerStream[0].pGeneralPurpose,
- ptrInstance->MixerStream[0].CallbackParam );
- }
- }
- }
- if (ptrInstance->MixerStream[1].CallbackSet)
- {
- if (Abs_Float(pInstance2->Current - pInstance2->Target) < pInstance2->Delta)
- {
- pInstance2->Current = pInstance2->Target; /* Difference is not significant anymore.
- Make them equal. */
- TargetGain = pInstance2->Target;
- LVC_Mixer_SetTarget(&ptrInstance->MixerStream[1], TargetGain);
- ptrInstance->MixerStream[1].CallbackSet = FALSE;
- if (ptrInstance->MixerStream[1].pCallBack != 0)
- {
- (*ptrInstance->MixerStream[1].pCallBack) (
- ptrInstance->MixerStream[1].pCallbackHandle,
- ptrInstance->MixerStream[1].pGeneralPurpose,
- ptrInstance->MixerStream[1].CallbackParam );
- }
- }
- }
-}
-#else
-void LVC_MixSoft_1St_2i_D16C31_SAT( LVMixer3_2St_st *ptrInstance,
- const LVM_INT16 *src,
- LVM_INT16 *dst,
- LVM_INT16 n)
-{
- char HardMixing = TRUE;
- LVM_INT32 TargetGain;
- Mix_Private_st *pInstance1=(Mix_Private_st *)(ptrInstance->MixerStream[0].PrivateParams);
- Mix_Private_st *pInstance2=(Mix_Private_st *)(ptrInstance->MixerStream[1].PrivateParams);
-
- if(n<=0) return;
-
- /******************************************************************************
- SOFT MIXING
- *******************************************************************************/
- if ((pInstance1->Current != pInstance1->Target)||(pInstance2->Current != pInstance2->Target))
- {
- if(pInstance1->Delta == 0x7FFFFFFF)
- {
- pInstance1->Current = pInstance1->Target;
- TargetGain=pInstance1->Target>>16; // TargetGain in Q16.15 format, no integer part
- LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]),TargetGain);
- }
- else if (Abs_32(pInstance1->Current-pInstance1->Target) < pInstance1->Delta)
- {
- pInstance1->Current = pInstance1->Target; /* Difference is not significant anymore. Make them equal. */
- TargetGain=pInstance1->Target>>16; // TargetGain in Q16.15 format, no integer part
- LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]),TargetGain);
- }
- else
- {
- /* Soft mixing has to be applied */
- HardMixing = FALSE;
- }
-
- if(HardMixing == TRUE)
- {
- if(pInstance2->Delta == 0x7FFFFFFF)
- {
- pInstance2->Current = pInstance2->Target;
- TargetGain=pInstance2->Target>>16; // TargetGain in Q16.15 format, no integer part
- LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[1]),TargetGain);
- }
- else if (Abs_32(pInstance2->Current-pInstance2->Target) < pInstance2->Delta)
- {
- pInstance2->Current = pInstance2->Target; /* Difference is not significant anymore. Make them equal. */
- TargetGain=pInstance2->Target>>16; // TargetGain in Q16.15 format, no integer part
- LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[1]),TargetGain);
- }
- else
- {
- /* Soft mixing has to be applied */
- HardMixing = FALSE;
- }
- }
-
- if(HardMixing == FALSE)
- {
- LVC_Core_MixSoft_1St_2i_D16C31_WRA( &(ptrInstance->MixerStream[0]),&(ptrInstance->MixerStream[1]), src, dst, n);
- }
- }
-
- /******************************************************************************
- HARD MIXING
- *******************************************************************************/
-
- if (HardMixing)
- {
- if (((pInstance1->Target>>16) == 0x7FFF)&&((pInstance2->Target>>16) == 0x7FFF))
- {
- if(src!=dst)
- {
- Copy_16(src, dst, n);
- }
- }
- else
- {
- LVC_Core_MixHard_1St_2i_D16C31_SAT(&(ptrInstance->MixerStream[0]),&(ptrInstance->MixerStream[1]), src, dst, n);
- }
- }
-
- /******************************************************************************
- CALL BACK
- *******************************************************************************/
-
- if (ptrInstance->MixerStream[0].CallbackSet)
- {
- if (Abs_32(pInstance1->Current-pInstance1->Target) < pInstance1->Delta)
- {
- pInstance1->Current = pInstance1->Target; /* Difference is not significant anymore. Make them equal. */
- TargetGain=pInstance1->Target>>(16-pInstance1->Shift); // TargetGain in Q16.15 format
- LVC_Mixer_SetTarget(&ptrInstance->MixerStream[0],TargetGain);
- ptrInstance->MixerStream[0].CallbackSet = FALSE;
- if (ptrInstance->MixerStream[0].pCallBack != 0)
- {
- (*ptrInstance->MixerStream[0].pCallBack) ( ptrInstance->MixerStream[0].pCallbackHandle, ptrInstance->MixerStream[0].pGeneralPurpose,ptrInstance->MixerStream[0].CallbackParam );
- }
- }
- }
- if (ptrInstance->MixerStream[1].CallbackSet)
- {
- if (Abs_32(pInstance2->Current-pInstance2->Target) < pInstance2->Delta)
- {
- pInstance2->Current = pInstance2->Target; /* Difference is not significant anymore. Make them equal. */
- TargetGain=pInstance2->Target>>(16-pInstance2->Shift); // TargetGain in Q16.15 format
- LVC_Mixer_SetTarget(&ptrInstance->MixerStream[1],TargetGain);
- ptrInstance->MixerStream[1].CallbackSet = FALSE;
- if (ptrInstance->MixerStream[1].pCallBack != 0)
- {
- (*ptrInstance->MixerStream[1].pCallBack) ( ptrInstance->MixerStream[1].pCallbackHandle, ptrInstance->MixerStream[1].pGeneralPurpose,ptrInstance->MixerStream[1].CallbackParam );
- }
- }
- }
-}
-#endif
-/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_2i_D16C31_SAT.cpp b/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_2i_D16C31_SAT.cpp
new file mode 100644
index 0000000..3153ada
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_2i_D16C31_SAT.cpp
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**********************************************************************************
+ INCLUDE FILES
+***********************************************************************************/
+
+#include <system/audio.h>
+
+#include "LVC_Mixer_Private.h"
+#include "VectorArithmetic.h"
+#include "ScalarArithmetic.h"
+
+/**********************************************************************************
+ DEFINITIONS
+***********************************************************************************/
+
+#define TRUE 1
+#define FALSE 0
+
+#define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof(*(a))))
+
+/**********************************************************************************
+ FUNCTION LVC_MixSoft_1St_2i_D16C31_SAT
+***********************************************************************************/
+#ifdef SUPPORT_MC
+/* This threshold is used to decide on the processing to be applied on
+ * front center and back center channels
+ */
+#define LVM_VOL_BAL_THR (0.000016f)
+void LVC_MixSoft_1St_MC_float_SAT (LVMixer3_2St_FLOAT_st *ptrInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 NrFrames,
+ LVM_INT32 NrChannels,
+ LVM_INT32 ChMask)
+{
+ char HardMixing = TRUE;
+ LVM_FLOAT TargetGain;
+ Mix_Private_FLOAT_st Target_lfe = {LVM_MAXFLOAT, LVM_MAXFLOAT, LVM_MAXFLOAT};
+ Mix_Private_FLOAT_st Target_ctr = {LVM_MAXFLOAT, LVM_MAXFLOAT, LVM_MAXFLOAT};
+ Mix_Private_FLOAT_st *pInstance1 = \
+ (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[0].PrivateParams);
+ Mix_Private_FLOAT_st *pInstance2 = \
+ (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[1].PrivateParams);
+ Mix_Private_FLOAT_st *pMixPrivInst[4] = {pInstance1, pInstance2, &Target_ctr, &Target_lfe};
+ Mix_Private_FLOAT_st *pInstance[NrChannels];
+
+ if (audio_channel_mask_get_representation(ChMask)
+ == AUDIO_CHANNEL_REPRESENTATION_INDEX)
+ {
+ for (int i = 0; i < 2; i++)
+ {
+ pInstance[i] = pMixPrivInst[i];
+ }
+ for (int i = 2; i < NrChannels; i++)
+ {
+ pInstance[i] = pMixPrivInst[2];
+ }
+ }
+ else
+ {
+ // TODO: Combine with system/media/audio_utils/Balance.cpp
+ // Constants in system/media/audio/include/system/audio-base.h
+ // 'mixInstIdx' is used to map the appropriate mixer instance for each channel.
+ const int mixInstIdx[] = {
+ 0, // AUDIO_CHANNEL_OUT_FRONT_LEFT = 0x1u,
+ 1, // AUDIO_CHANNEL_OUT_FRONT_RIGHT = 0x2u,
+ 2, // AUDIO_CHANNEL_OUT_FRONT_CENTER = 0x4u,
+ 3, // AUDIO_CHANNEL_OUT_LOW_FREQUENCY = 0x8u,
+ 0, // AUDIO_CHANNEL_OUT_BACK_LEFT = 0x10u,
+ 1, // AUDIO_CHANNEL_OUT_BACK_RIGHT = 0x20u,
+ 0, // AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x40u,
+ 1, // AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x80u,
+ 2, // AUDIO_CHANNEL_OUT_BACK_CENTER = 0x100u,
+ 0, // AUDIO_CHANNEL_OUT_SIDE_LEFT = 0x200u,
+ 1, // AUDIO_CHANNEL_OUT_SIDE_RIGHT = 0x400u,
+ 2, // AUDIO_CHANNEL_OUT_TOP_CENTER = 0x800u,
+ 0, // AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT = 0x1000u,
+ 2, // AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER = 0x2000u,
+ 1, // AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT = 0x4000u,
+ 0, // AUDIO_CHANNEL_OUT_TOP_BACK_LEFT = 0x8000u,
+ 2, // AUDIO_CHANNEL_OUT_TOP_BACK_CENTER = 0x10000u,
+ 1, // AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT = 0x20000u,
+ 0, // AUDIO_CHANNEL_OUT_TOP_SIDE_LEFT = 0x40000u,
+ 1, // AUDIO_CHANNEL_OUT_TOP_SIDE_RIGHT = 0x80000u
+ };
+ if (pInstance1->Target <= LVM_VOL_BAL_THR ||
+ pInstance2->Target <= LVM_VOL_BAL_THR)
+ {
+ Target_ctr.Target = 0.0f;
+ Target_ctr.Current = 0.0f;
+ Target_ctr.Delta = 0.0f;
+ }
+ const unsigned int idxArrSize = ARRAY_SIZE(mixInstIdx);
+ for (unsigned int i = 0, channel = ChMask; channel !=0 ; ++i)
+ {
+ const unsigned int idx = __builtin_ctz(channel);
+ if (idx < idxArrSize)
+ {
+ pInstance[i] = pMixPrivInst[mixInstIdx[idx]];
+ }
+ else
+ {
+ pInstance[i] = pMixPrivInst[2];
+ }
+ channel &= ~(1 << idx);
+ }
+ }
+
+ if (NrFrames <= 0) return;
+
+ /******************************************************************************
+ SOFT MIXING
+ *******************************************************************************/
+
+ if ((pInstance1->Current != pInstance1->Target) ||
+ (pInstance2->Current != pInstance2->Target))
+ {
+ // TODO: combine similar checks below.
+ if (pInstance1->Delta == LVM_MAXFLOAT
+ || Abs_Float(pInstance1->Current - pInstance1->Target) < pInstance1->Delta)
+ {
+ /* Difference is not significant anymore. Make them equal. */
+ pInstance1->Current = pInstance1->Target;
+ TargetGain = pInstance1->Target;
+ LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
+ }
+ else
+ {
+ /* Soft mixing has to be applied */
+ HardMixing = FALSE;
+ }
+
+ if (HardMixing == TRUE)
+ {
+ if (pInstance2->Delta == LVM_MAXFLOAT
+ || Abs_Float(pInstance2->Current - pInstance2->Target) < pInstance2->Delta)
+ {
+ /* Difference is not significant anymore. Make them equal. */
+ pInstance2->Current = pInstance2->Target;
+ TargetGain = pInstance2->Target;
+ LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[1]), TargetGain);
+ }
+ else
+ {
+ /* Soft mixing has to be applied */
+ HardMixing = FALSE;
+ }
+ }
+
+ if (HardMixing == FALSE)
+ {
+ LVC_Core_MixSoft_1St_MC_float_WRA (&pInstance[0],
+ src, dst, NrFrames, NrChannels);
+ }
+ }
+
+ /******************************************************************************
+ HARD MIXING
+ *******************************************************************************/
+
+ if (HardMixing == TRUE)
+ {
+ if ((pInstance1->Target == LVM_MAXFLOAT) && (pInstance2->Target == LVM_MAXFLOAT))
+ {
+ if (src != dst)
+ {
+ Copy_Float(src, dst, NrFrames*NrChannels);
+ }
+ }
+ else
+ {
+ LVC_Core_MixHard_1St_MC_float_SAT(&(pInstance[0]),
+ src, dst, NrFrames, NrChannels);
+ }
+ }
+
+ /******************************************************************************
+ CALL BACK
+ *******************************************************************************/
+
+ if (ptrInstance->MixerStream[0].CallbackSet)
+ {
+ if (Abs_Float(pInstance1->Current - pInstance1->Target) < pInstance1->Delta)
+ {
+ pInstance1->Current = pInstance1->Target; /* Difference is not significant anymore. \
+ Make them equal. */
+ TargetGain = pInstance1->Target;
+ LVC_Mixer_SetTarget(&ptrInstance->MixerStream[0], TargetGain);
+ ptrInstance->MixerStream[0].CallbackSet = FALSE;
+ if (ptrInstance->MixerStream[0].pCallBack != 0)
+ {
+ (*ptrInstance->MixerStream[0].pCallBack) (\
+ ptrInstance->MixerStream[0].pCallbackHandle,
+ ptrInstance->MixerStream[0].pGeneralPurpose,
+ ptrInstance->MixerStream[0].CallbackParam);
+ }
+ }
+ }
+ if (ptrInstance->MixerStream[1].CallbackSet)
+ {
+ if (Abs_Float(pInstance2->Current - pInstance2->Target) < pInstance2->Delta)
+ {
+ pInstance2->Current = pInstance2->Target; /* Difference is not significant anymore.
+ Make them equal. */
+ TargetGain = pInstance2->Target;
+ LVC_Mixer_SetTarget(&ptrInstance->MixerStream[1], TargetGain);
+ ptrInstance->MixerStream[1].CallbackSet = FALSE;
+ if (ptrInstance->MixerStream[1].pCallBack != 0)
+ {
+ (*ptrInstance->MixerStream[1].pCallBack) (\
+ ptrInstance->MixerStream[1].pCallbackHandle,
+ ptrInstance->MixerStream[1].pGeneralPurpose,
+ ptrInstance->MixerStream[1].CallbackParam);
+ }
+ }
+ }
+}
+#endif
+void LVC_MixSoft_1St_2i_D16C31_SAT( LVMixer3_2St_FLOAT_st *ptrInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ char HardMixing = TRUE;
+ LVM_FLOAT TargetGain;
+ Mix_Private_FLOAT_st *pInstance1 = \
+ (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[0].PrivateParams);
+ Mix_Private_FLOAT_st *pInstance2 = \
+ (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[1].PrivateParams);
+
+ if(n <= 0) return;
+
+ /******************************************************************************
+ SOFT MIXING
+ *******************************************************************************/
+ if ((pInstance1->Current != pInstance1->Target) || (pInstance2->Current != pInstance2->Target))
+ {
+ if(pInstance1->Delta == 1.0f)
+ {
+ pInstance1->Current = pInstance1->Target;
+ TargetGain = pInstance1->Target;
+ LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
+ }
+ else if (Abs_Float(pInstance1->Current - pInstance1->Target) < pInstance1->Delta)
+ {
+ pInstance1->Current = pInstance1->Target; /* Difference is not significant anymore. \
+ Make them equal. */
+ TargetGain = pInstance1->Target;
+ LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
+ }
+ else
+ {
+ /* Soft mixing has to be applied */
+ HardMixing = FALSE;
+ }
+
+ if(HardMixing == TRUE)
+ {
+ if(pInstance2->Delta == 1.0f)
+ {
+ pInstance2->Current = pInstance2->Target;
+ TargetGain = pInstance2->Target;
+ LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[1]), TargetGain);
+ }
+ else if (Abs_Float(pInstance2->Current - pInstance2->Target) < pInstance2->Delta)
+ {
+ pInstance2->Current = pInstance2->Target; /* Difference is not significant anymore. \
+ Make them equal. */
+ TargetGain = pInstance2->Target;
+ LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[1]), TargetGain);
+ }
+ else
+ {
+ /* Soft mixing has to be applied */
+ HardMixing = FALSE;
+ }
+ }
+
+ if(HardMixing == FALSE)
+ {
+ LVC_Core_MixSoft_1St_2i_D16C31_WRA( &(ptrInstance->MixerStream[0]),
+ &(ptrInstance->MixerStream[1]),
+ src, dst, n);
+ }
+ }
+
+ /******************************************************************************
+ HARD MIXING
+ *******************************************************************************/
+
+ if (HardMixing)
+ {
+ if ((pInstance1->Target == 1.0f) && (pInstance2->Target == 1.0f))
+ {
+ if(src != dst)
+ {
+ Copy_Float(src, dst, n);
+ }
+ }
+ else
+ {
+ LVC_Core_MixHard_1St_2i_D16C31_SAT(&(ptrInstance->MixerStream[0]),
+ &(ptrInstance->MixerStream[1]),
+ src, dst, n);
+ }
+ }
+
+ /******************************************************************************
+ CALL BACK
+ *******************************************************************************/
+
+ if (ptrInstance->MixerStream[0].CallbackSet)
+ {
+ if (Abs_Float(pInstance1->Current - pInstance1->Target) < pInstance1->Delta)
+ {
+ pInstance1->Current = pInstance1->Target; /* Difference is not significant anymore. \
+ Make them equal. */
+ TargetGain = pInstance1->Target;
+ LVC_Mixer_SetTarget(&ptrInstance->MixerStream[0], TargetGain);
+ ptrInstance->MixerStream[0].CallbackSet = FALSE;
+ if (ptrInstance->MixerStream[0].pCallBack != 0)
+ {
+ (*ptrInstance->MixerStream[0].pCallBack) ( \
+ ptrInstance->MixerStream[0].pCallbackHandle,
+ ptrInstance->MixerStream[0].pGeneralPurpose,
+ ptrInstance->MixerStream[0].CallbackParam );
+ }
+ }
+ }
+ if (ptrInstance->MixerStream[1].CallbackSet)
+ {
+ if (Abs_Float(pInstance2->Current - pInstance2->Target) < pInstance2->Delta)
+ {
+ pInstance2->Current = pInstance2->Target; /* Difference is not significant anymore.
+ Make them equal. */
+ TargetGain = pInstance2->Target;
+ LVC_Mixer_SetTarget(&ptrInstance->MixerStream[1], TargetGain);
+ ptrInstance->MixerStream[1].CallbackSet = FALSE;
+ if (ptrInstance->MixerStream[1].pCallBack != 0)
+ {
+ (*ptrInstance->MixerStream[1].pCallBack) (
+ ptrInstance->MixerStream[1].pCallbackHandle,
+ ptrInstance->MixerStream[1].pGeneralPurpose,
+ ptrInstance->MixerStream[1].CallbackParam );
+ }
+ }
+ }
+}
+/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_D16C31_SAT.c b/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_D16C31_SAT.c
deleted file mode 100644
index 0678ae0..0000000
--- a/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_D16C31_SAT.c
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**********************************************************************************
- INCLUDE FILES
-***********************************************************************************/
-
-#include "LVC_Mixer_Private.h"
-#include "VectorArithmetic.h"
-#include "ScalarArithmetic.h"
-
-/**********************************************************************************
- DEFINITIONS
-***********************************************************************************/
-
-#define TRUE 1
-#define FALSE 0
-
-/**********************************************************************************
- FUNCTION LVMixer3_MIXSOFT_1ST_D16C31_SAT
-***********************************************************************************/
-#ifdef BUILD_FLOAT
-void LVC_MixSoft_1St_D16C31_SAT( LVMixer3_1St_FLOAT_st *ptrInstance,
- const LVM_FLOAT *src,
- LVM_FLOAT *dst,
- LVM_INT16 n)
-{
- char HardMixing = TRUE;
- LVM_FLOAT TargetGain;
- Mix_Private_FLOAT_st *pInstance = \
- (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[0].PrivateParams);
-
- if(n <= 0) return;
-
- /******************************************************************************
- SOFT MIXING
- *******************************************************************************/
- if (pInstance->Current != pInstance->Target)
- {
- if(pInstance->Delta == 1.0f){
- pInstance->Current = pInstance->Target;
- TargetGain = pInstance->Target;
- LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
- }else if (Abs_Float(pInstance->Current - pInstance->Target) < pInstance->Delta){
- pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
- Make them equal. */
- TargetGain = pInstance->Target;
- LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
- }else{
- /* Soft mixing has to be applied */
- HardMixing = FALSE;
- LVC_Core_MixSoft_1St_D16C31_WRA(&(ptrInstance->MixerStream[0]), src, dst, n);
- }
- }
-
- /******************************************************************************
- HARD MIXING
- *******************************************************************************/
-
- if (HardMixing){
- if (pInstance->Target == 0)
- LoadConst_Float(0.0, dst, n);
- else {
- if ((pInstance->Target) != 1.0f)
- Mult3s_Float(src, (pInstance->Target), dst, n);
- else if(src != dst)
- Copy_Float(src, dst, n);
- }
-
- }
-
- /******************************************************************************
- CALL BACK
- *******************************************************************************/
-
- if (ptrInstance->MixerStream[0].CallbackSet){
- if (Abs_Float(pInstance->Current - pInstance->Target) < pInstance->Delta){
- pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
- Make them equal. */
- TargetGain = pInstance->Target;
- LVC_Mixer_SetTarget(ptrInstance->MixerStream, TargetGain);
- ptrInstance->MixerStream[0].CallbackSet = FALSE;
- if (ptrInstance->MixerStream[0].pCallBack != 0){
- (*ptrInstance->MixerStream[0].pCallBack) ( \
- ptrInstance->MixerStream[0].pCallbackHandle,
- ptrInstance->MixerStream[0].pGeneralPurpose,
- ptrInstance->MixerStream[0].CallbackParam );
- }
- }
- }
-}
-#ifdef SUPPORT_MC
-/*
- * FUNCTION: LVC_MixSoft_Mc_D16C31_SAT
- *
- * DESCRIPTION:
- * Mixer function with support for processing multichannel input
- *
- * PARAMETERS:
- * ptrInstance Instance pointer
- * src Source
- * dst Destination
- * NrFrames Number of Frames
- * NrChannels Number of channels
- *
- * RETURNS:
- * void
- *
- */
-void LVC_MixSoft_Mc_D16C31_SAT(LVMixer3_1St_FLOAT_st *ptrInstance,
- const LVM_FLOAT *src,
- LVM_FLOAT *dst,
- LVM_INT16 NrFrames,
- LVM_INT16 NrChannels)
-{
- char HardMixing = TRUE;
- LVM_FLOAT TargetGain;
- Mix_Private_FLOAT_st *pInstance = \
- (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[0].PrivateParams);
-
- if (NrFrames <= 0) return;
-
- /******************************************************************************
- SOFT MIXING
- *******************************************************************************/
- if (pInstance->Current != pInstance->Target)
- {
- if (pInstance->Delta == 1.0f) {
- pInstance->Current = pInstance->Target;
- TargetGain = pInstance->Target;
- LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
- }else if (Abs_Float(pInstance->Current - pInstance->Target) < pInstance->Delta) {
- pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
- Make them equal. */
- TargetGain = pInstance->Target;
- LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
- }else{
- /* Soft mixing has to be applied */
- HardMixing = FALSE;
- LVC_Core_MixSoft_Mc_D16C31_WRA(&(ptrInstance->MixerStream[0]),
- src,
- dst,
- NrFrames,
- NrChannels);
- }
- }
-
- /******************************************************************************
- HARD MIXING
- *******************************************************************************/
-
- if (HardMixing) {
- if (pInstance->Target == 0)
- LoadConst_Float(0.0, dst, NrFrames * NrChannels);
- else {
- if ((pInstance->Target) != 1.0f)
- Mult3s_Float(src, (pInstance->Target), dst, NrFrames * NrChannels);
- else if (src != dst)
- Copy_Float(src, dst, NrFrames * NrChannels);
- }
-
- }
-
- /******************************************************************************
- CALL BACK
- *******************************************************************************/
-
- if (ptrInstance->MixerStream[0].CallbackSet) {
- if (Abs_Float(pInstance->Current - pInstance->Target) < pInstance->Delta) {
- pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
- Make them equal. */
- TargetGain = pInstance->Target;
- LVC_Mixer_SetTarget(ptrInstance->MixerStream, TargetGain);
- ptrInstance->MixerStream[0].CallbackSet = FALSE;
- if (ptrInstance->MixerStream[0].pCallBack != 0) {
- (*ptrInstance->MixerStream[0].pCallBack) (\
- ptrInstance->MixerStream[0].pCallbackHandle,
- ptrInstance->MixerStream[0].pGeneralPurpose,
- ptrInstance->MixerStream[0].CallbackParam);
- }
- }
- }
-}
-
-#endif
-
-#else
-void LVC_MixSoft_1St_D16C31_SAT( LVMixer3_1St_st *ptrInstance,
- const LVM_INT16 *src,
- LVM_INT16 *dst,
- LVM_INT16 n)
-{
- char HardMixing = TRUE;
- LVM_INT32 TargetGain;
- Mix_Private_st *pInstance=(Mix_Private_st *)(ptrInstance->MixerStream[0].PrivateParams);
-
- if(n<=0) return;
-
- /******************************************************************************
- SOFT MIXING
- *******************************************************************************/
- if (pInstance->Current != pInstance->Target)
- {
- if(pInstance->Delta == 0x7FFFFFFF){
- pInstance->Current = pInstance->Target;
- TargetGain=pInstance->Target>>(16-pInstance->Shift); // TargetGain in Q16.15 format
- LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]),TargetGain);
- }else if (Abs_32(pInstance->Current-pInstance->Target) < pInstance->Delta){
- pInstance->Current = pInstance->Target; /* Difference is not significant anymore. Make them equal. */
- TargetGain=pInstance->Target>>(16-pInstance->Shift); // TargetGain in Q16.15 format
- LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]),TargetGain);
- }else{
- /* Soft mixing has to be applied */
- HardMixing = FALSE;
- if(pInstance->Shift!=0){
- Shift_Sat_v16xv16 ((LVM_INT16)pInstance->Shift,src,dst,n);
- LVC_Core_MixSoft_1St_D16C31_WRA( &(ptrInstance->MixerStream[0]), dst, dst, n);
- }
- else
- LVC_Core_MixSoft_1St_D16C31_WRA( &(ptrInstance->MixerStream[0]), src, dst, n);
- }
- }
-
- /******************************************************************************
- HARD MIXING
- *******************************************************************************/
-
- if (HardMixing){
- if (pInstance->Target == 0)
- LoadConst_16(0, dst, n);
- else if(pInstance->Shift!=0){
- Shift_Sat_v16xv16 ((LVM_INT16)pInstance->Shift,src,dst,n);
- if ((pInstance->Target>>16) != 0x7FFF)
- Mult3s_16x16( dst, (LVM_INT16)(pInstance->Target>>16), dst, n );
- }
- else {
- if ((pInstance->Target>>16) != 0x7FFF)
- Mult3s_16x16( src, (LVM_INT16)(pInstance->Target>>16), dst, n );
- else if(src!=dst)
- Copy_16(src, dst, n);
- }
-
- }
-
- /******************************************************************************
- CALL BACK
- *******************************************************************************/
-
- if (ptrInstance->MixerStream[0].CallbackSet){
- if (Abs_32(pInstance->Current-pInstance->Target) < pInstance->Delta){
- pInstance->Current = pInstance->Target; /* Difference is not significant anymore. Make them equal. */
- TargetGain=pInstance->Target>>(16-pInstance->Shift); // TargetGain in Q16.15 format
- LVC_Mixer_SetTarget(ptrInstance->MixerStream,TargetGain);
- ptrInstance->MixerStream[0].CallbackSet = FALSE;
- if (ptrInstance->MixerStream[0].pCallBack != 0){
- (*ptrInstance->MixerStream[0].pCallBack) ( ptrInstance->MixerStream[0].pCallbackHandle, ptrInstance->MixerStream[0].pGeneralPurpose,ptrInstance->MixerStream[0].CallbackParam );
- }
- }
- }
-}
-#endif/*BUILD_FLOAT*/
-/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_D16C31_SAT.cpp b/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_D16C31_SAT.cpp
new file mode 100644
index 0000000..4d229da
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_D16C31_SAT.cpp
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**********************************************************************************
+ INCLUDE FILES
+***********************************************************************************/
+
+#include "LVC_Mixer_Private.h"
+#include "VectorArithmetic.h"
+#include "ScalarArithmetic.h"
+
+/**********************************************************************************
+ DEFINITIONS
+***********************************************************************************/
+
+#define TRUE 1
+#define FALSE 0
+
+/**********************************************************************************
+ FUNCTION LVMixer3_MIXSOFT_1ST_D16C31_SAT
+***********************************************************************************/
+void LVC_MixSoft_1St_D16C31_SAT( LVMixer3_1St_FLOAT_st *ptrInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ char HardMixing = TRUE;
+ LVM_FLOAT TargetGain;
+ Mix_Private_FLOAT_st *pInstance = \
+ (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[0].PrivateParams);
+
+ if(n <= 0) return;
+
+ /******************************************************************************
+ SOFT MIXING
+ *******************************************************************************/
+ if (pInstance->Current != pInstance->Target)
+ {
+ if(pInstance->Delta == 1.0f){
+ pInstance->Current = pInstance->Target;
+ TargetGain = pInstance->Target;
+ LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
+ }else if (Abs_Float(pInstance->Current - pInstance->Target) < pInstance->Delta){
+ pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
+ Make them equal. */
+ TargetGain = pInstance->Target;
+ LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
+ }else{
+ /* Soft mixing has to be applied */
+ HardMixing = FALSE;
+ LVC_Core_MixSoft_1St_D16C31_WRA(&(ptrInstance->MixerStream[0]), src, dst, n);
+ }
+ }
+
+ /******************************************************************************
+ HARD MIXING
+ *******************************************************************************/
+
+ if (HardMixing){
+ if (pInstance->Target == 0)
+ LoadConst_Float(0.0, dst, n);
+ else {
+ if ((pInstance->Target) != 1.0f)
+ Mult3s_Float(src, (pInstance->Target), dst, n);
+ else if(src != dst)
+ Copy_Float(src, dst, n);
+ }
+
+ }
+
+ /******************************************************************************
+ CALL BACK
+ *******************************************************************************/
+
+ if (ptrInstance->MixerStream[0].CallbackSet){
+ if (Abs_Float(pInstance->Current - pInstance->Target) < pInstance->Delta){
+ pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
+ Make them equal. */
+ TargetGain = pInstance->Target;
+ LVC_Mixer_SetTarget(ptrInstance->MixerStream, TargetGain);
+ ptrInstance->MixerStream[0].CallbackSet = FALSE;
+ if (ptrInstance->MixerStream[0].pCallBack != 0){
+ (*ptrInstance->MixerStream[0].pCallBack) ( \
+ ptrInstance->MixerStream[0].pCallbackHandle,
+ ptrInstance->MixerStream[0].pGeneralPurpose,
+ ptrInstance->MixerStream[0].CallbackParam );
+ }
+ }
+ }
+}
+#ifdef SUPPORT_MC
+/*
+ * FUNCTION: LVC_MixSoft_Mc_D16C31_SAT
+ *
+ * DESCRIPTION:
+ * Mixer function with support for processing multichannel input
+ *
+ * PARAMETERS:
+ * ptrInstance Instance pointer
+ * src Source
+ * dst Destination
+ * NrFrames Number of Frames
+ * NrChannels Number of channels
+ *
+ * RETURNS:
+ * void
+ *
+ */
+void LVC_MixSoft_Mc_D16C31_SAT(LVMixer3_1St_FLOAT_st *ptrInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 NrFrames,
+ LVM_INT16 NrChannels)
+{
+ char HardMixing = TRUE;
+ LVM_FLOAT TargetGain;
+ Mix_Private_FLOAT_st *pInstance = \
+ (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[0].PrivateParams);
+
+ if (NrFrames <= 0) return;
+
+ /******************************************************************************
+ SOFT MIXING
+ *******************************************************************************/
+ if (pInstance->Current != pInstance->Target)
+ {
+ if (pInstance->Delta == 1.0f) {
+ pInstance->Current = pInstance->Target;
+ TargetGain = pInstance->Target;
+ LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
+ }else if (Abs_Float(pInstance->Current - pInstance->Target) < pInstance->Delta) {
+ pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
+ Make them equal. */
+ TargetGain = pInstance->Target;
+ LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
+ }else{
+ /* Soft mixing has to be applied */
+ HardMixing = FALSE;
+ LVC_Core_MixSoft_Mc_D16C31_WRA(&(ptrInstance->MixerStream[0]),
+ src,
+ dst,
+ NrFrames,
+ NrChannels);
+ }
+ }
+
+ /******************************************************************************
+ HARD MIXING
+ *******************************************************************************/
+
+ if (HardMixing) {
+ if (pInstance->Target == 0)
+ LoadConst_Float(0.0, dst, NrFrames * NrChannels);
+ else {
+ if ((pInstance->Target) != 1.0f)
+ Mult3s_Float(src, (pInstance->Target), dst, NrFrames * NrChannels);
+ else if (src != dst)
+ Copy_Float(src, dst, NrFrames * NrChannels);
+ }
+
+ }
+
+ /******************************************************************************
+ CALL BACK
+ *******************************************************************************/
+
+ if (ptrInstance->MixerStream[0].CallbackSet) {
+ if (Abs_Float(pInstance->Current - pInstance->Target) < pInstance->Delta) {
+ pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
+ Make them equal. */
+ TargetGain = pInstance->Target;
+ LVC_Mixer_SetTarget(ptrInstance->MixerStream, TargetGain);
+ ptrInstance->MixerStream[0].CallbackSet = FALSE;
+ if (ptrInstance->MixerStream[0].pCallBack != 0) {
+ (*ptrInstance->MixerStream[0].pCallBack) (\
+ ptrInstance->MixerStream[0].pCallbackHandle,
+ ptrInstance->MixerStream[0].pGeneralPurpose,
+ ptrInstance->MixerStream[0].CallbackParam);
+ }
+ }
+ }
+}
+
+#endif
+
+/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_2St_D16C31_SAT.c b/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_2St_D16C31_SAT.c
deleted file mode 100644
index 8a89de1..0000000
--- a/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_2St_D16C31_SAT.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**********************************************************************************
- INCLUDE FILES
-***********************************************************************************/
-
-#include "LVC_Mixer_Private.h"
-#include "VectorArithmetic.h"
-
-/**********************************************************************************
- FUNCTION LVC_MixSoft_2St_D16C31_SAT.c
-***********************************************************************************/
-#ifdef BUILD_FLOAT
-void LVC_MixSoft_2St_D16C31_SAT(LVMixer3_2St_FLOAT_st *ptrInstance,
- const LVM_FLOAT *src1,
- const LVM_FLOAT *src2,
- LVM_FLOAT *dst,
- LVM_INT16 n)
-{
- Mix_Private_FLOAT_st *pInstance1 = \
- (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[0].PrivateParams);
- Mix_Private_FLOAT_st *pInstance2 = \
- (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[1].PrivateParams);
-
- if(n <= 0) return;
-
- /******************************************************************************
- SOFT MIXING
- *******************************************************************************/
- if ((pInstance1->Current == pInstance1->Target) && (pInstance1->Current == 0)){
- LVC_MixSoft_1St_D16C31_SAT((LVMixer3_1St_FLOAT_st *)(&ptrInstance->MixerStream[1]),
- src2, dst, n);
- }
- else if ((pInstance2->Current == pInstance2->Target) && (pInstance2->Current == 0)){
- LVC_MixSoft_1St_D16C31_SAT((LVMixer3_1St_FLOAT_st *)(&ptrInstance->MixerStream[0]),
- src1, dst, n);
- }
- else if ((pInstance1->Current != pInstance1->Target) || \
- (pInstance2->Current != pInstance2->Target))
- {
- LVC_MixSoft_1St_D16C31_SAT((LVMixer3_1St_FLOAT_st *)(&ptrInstance->MixerStream[0]),
- src1, dst, n);
- LVC_MixInSoft_D16C31_SAT((LVMixer3_1St_FLOAT_st *)(&ptrInstance->MixerStream[1]),
- src2, dst, n);
- }
- else{
- /******************************************************************************
- HARD MIXING
- *******************************************************************************/
- LVC_Core_MixHard_2St_D16C31_SAT( &ptrInstance->MixerStream[0],
- &ptrInstance->MixerStream[1],
- src1, src2, dst, n);
- }
-}
-
-#ifdef SUPPORT_MC
-/*
- * FUNCTION: LVC_MixSoft_2Mc_D16C31_SAT
- *
- * DESCRIPTION:
- * 2 stream Mixer function with support for processing multichannel input
- *
- * PARAMETERS:
- * ptrInstance Instance pointer
- * src1 First multichannel source
- * src2 Second multichannel source
- * dst Destination
- * NrFrames Number of frames
- * NrChannels Number of channels
- *
- * RETURNS:
- * void
- *
- */
-void LVC_MixSoft_2Mc_D16C31_SAT(LVMixer3_2St_FLOAT_st *ptrInstance,
- const LVM_FLOAT *src1,
- const LVM_FLOAT *src2,
- LVM_FLOAT *dst,
- LVM_INT16 NrFrames,
- LVM_INT16 NrChannels)
-{
- Mix_Private_FLOAT_st *pInstance1 = \
- (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[0].PrivateParams);
- Mix_Private_FLOAT_st *pInstance2 = \
- (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[1].PrivateParams);
-
- if (NrFrames <= 0) return;
-
- /******************************************************************************
- SOFT MIXING
- *******************************************************************************/
- if ((pInstance1->Current == pInstance1->Target) && (pInstance1->Current == 0)) {
- LVC_MixSoft_Mc_D16C31_SAT((LVMixer3_1St_FLOAT_st *)(&ptrInstance->MixerStream[1]),
- src2, dst, NrFrames, NrChannels);
- }
- else if ((pInstance2->Current == pInstance2->Target) && (pInstance2->Current == 0)) {
- LVC_MixSoft_Mc_D16C31_SAT((LVMixer3_1St_FLOAT_st *)(&ptrInstance->MixerStream[0]),
- src1, dst, NrFrames, NrChannels);
- }
- else if ((pInstance1->Current != pInstance1->Target) || \
- (pInstance2->Current != pInstance2->Target))
- {
- LVC_MixSoft_Mc_D16C31_SAT((LVMixer3_1St_FLOAT_st *)(&ptrInstance->MixerStream[0]),
- src1, dst, NrFrames, NrChannels);
- LVC_MixInSoft_Mc_D16C31_SAT((LVMixer3_1St_FLOAT_st *)(&ptrInstance->MixerStream[1]),
- src2, dst, NrFrames, NrChannels);
- }
- else{
- /******************************************************************************
- HARD MIXING
- *******************************************************************************/
- LVC_Core_MixHard_2St_D16C31_SAT(&ptrInstance->MixerStream[0],
- &ptrInstance->MixerStream[1],
- src1, src2, dst, NrFrames * NrChannels);
- }
-}
-#endif
-
-#else
-void LVC_MixSoft_2St_D16C31_SAT( LVMixer3_2St_st *ptrInstance,
- const LVM_INT16 *src1,
- LVM_INT16 *src2,
- LVM_INT16 *dst,
- LVM_INT16 n)
-{
- Mix_Private_st *pInstance1=(Mix_Private_st *)(ptrInstance->MixerStream[0].PrivateParams);
- Mix_Private_st *pInstance2=(Mix_Private_st *)(ptrInstance->MixerStream[1].PrivateParams);
-
- if(n<=0) return;
-
- /******************************************************************************
- SOFT MIXING
- *******************************************************************************/
- if ((pInstance1->Current == pInstance1->Target)&&(pInstance1->Current == 0)){
- LVC_MixSoft_1St_D16C31_SAT( (LVMixer3_1St_st *)(&ptrInstance->MixerStream[1]), src2, dst, n);
- }
- else if ((pInstance2->Current == pInstance2->Target)&&(pInstance2->Current == 0)){
- LVC_MixSoft_1St_D16C31_SAT( (LVMixer3_1St_st *)(&ptrInstance->MixerStream[0]), src1, dst, n);
- }
- else if ((pInstance1->Current != pInstance1->Target) || (pInstance2->Current != pInstance2->Target))
- {
- LVC_MixSoft_1St_D16C31_SAT((LVMixer3_1St_st *)(&ptrInstance->MixerStream[0]), src1, dst, n);
- LVC_MixInSoft_D16C31_SAT( (LVMixer3_1St_st *)(&ptrInstance->MixerStream[1]), src2, dst, n);
- }
- else{
- /******************************************************************************
- HARD MIXING
- *******************************************************************************/
- if(pInstance2->Shift!=0)
- Shift_Sat_v16xv16 ((LVM_INT16)pInstance2->Shift,src2,src2,n);
- if(pInstance1->Shift!=0)
- {
- Shift_Sat_v16xv16 ((LVM_INT16)pInstance1->Shift,src1,dst,n);
- LVC_Core_MixHard_2St_D16C31_SAT( &ptrInstance->MixerStream[0], &ptrInstance->MixerStream[1], dst, src2, dst, n);
- }
- else
- LVC_Core_MixHard_2St_D16C31_SAT( &ptrInstance->MixerStream[0], &ptrInstance->MixerStream[1], src1, src2, dst, n);
- }
-}
-#endif /*BUILD_FLOAT*/
-/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_2St_D16C31_SAT.cpp b/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_2St_D16C31_SAT.cpp
new file mode 100644
index 0000000..54ab79d
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_2St_D16C31_SAT.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**********************************************************************************
+ INCLUDE FILES
+***********************************************************************************/
+
+#include "LVC_Mixer_Private.h"
+#include "VectorArithmetic.h"
+
+/**********************************************************************************
+ FUNCTION LVC_MixSoft_2St_D16C31_SAT.c
+***********************************************************************************/
+void LVC_MixSoft_2St_D16C31_SAT(LVMixer3_2St_FLOAT_st *ptrInstance,
+ const LVM_FLOAT *src1,
+ const LVM_FLOAT *src2,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ Mix_Private_FLOAT_st *pInstance1 = \
+ (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[0].PrivateParams);
+ Mix_Private_FLOAT_st *pInstance2 = \
+ (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[1].PrivateParams);
+
+ if(n <= 0) return;
+
+ /******************************************************************************
+ SOFT MIXING
+ *******************************************************************************/
+ if ((pInstance1->Current == pInstance1->Target) && (pInstance1->Current == 0)){
+ LVC_MixSoft_1St_D16C31_SAT((LVMixer3_1St_FLOAT_st *)(&ptrInstance->MixerStream[1]),
+ src2, dst, n);
+ }
+ else if ((pInstance2->Current == pInstance2->Target) && (pInstance2->Current == 0)){
+ LVC_MixSoft_1St_D16C31_SAT((LVMixer3_1St_FLOAT_st *)(&ptrInstance->MixerStream[0]),
+ src1, dst, n);
+ }
+ else if ((pInstance1->Current != pInstance1->Target) || \
+ (pInstance2->Current != pInstance2->Target))
+ {
+ LVC_MixSoft_1St_D16C31_SAT((LVMixer3_1St_FLOAT_st *)(&ptrInstance->MixerStream[0]),
+ src1, dst, n);
+ LVC_MixInSoft_D16C31_SAT((LVMixer3_1St_FLOAT_st *)(&ptrInstance->MixerStream[1]),
+ src2, dst, n);
+ }
+ else{
+ /******************************************************************************
+ HARD MIXING
+ *******************************************************************************/
+ LVC_Core_MixHard_2St_D16C31_SAT( &ptrInstance->MixerStream[0],
+ &ptrInstance->MixerStream[1],
+ src1, src2, dst, n);
+ }
+}
+
+#ifdef SUPPORT_MC
+/*
+ * FUNCTION: LVC_MixSoft_2Mc_D16C31_SAT
+ *
+ * DESCRIPTION:
+ * 2 stream Mixer function with support for processing multichannel input
+ *
+ * PARAMETERS:
+ * ptrInstance Instance pointer
+ * src1 First multichannel source
+ * src2 Second multichannel source
+ * dst Destination
+ * NrFrames Number of frames
+ * NrChannels Number of channels
+ *
+ * RETURNS:
+ * void
+ *
+ */
+void LVC_MixSoft_2Mc_D16C31_SAT(LVMixer3_2St_FLOAT_st *ptrInstance,
+ const LVM_FLOAT *src1,
+ const LVM_FLOAT *src2,
+ LVM_FLOAT *dst,
+ LVM_INT16 NrFrames,
+ LVM_INT16 NrChannels)
+{
+ Mix_Private_FLOAT_st *pInstance1 = \
+ (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[0].PrivateParams);
+ Mix_Private_FLOAT_st *pInstance2 = \
+ (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[1].PrivateParams);
+
+ if (NrFrames <= 0) return;
+
+ /******************************************************************************
+ SOFT MIXING
+ *******************************************************************************/
+ if ((pInstance1->Current == pInstance1->Target) && (pInstance1->Current == 0)) {
+ LVC_MixSoft_Mc_D16C31_SAT((LVMixer3_1St_FLOAT_st *)(&ptrInstance->MixerStream[1]),
+ src2, dst, NrFrames, NrChannels);
+ }
+ else if ((pInstance2->Current == pInstance2->Target) && (pInstance2->Current == 0)) {
+ LVC_MixSoft_Mc_D16C31_SAT((LVMixer3_1St_FLOAT_st *)(&ptrInstance->MixerStream[0]),
+ src1, dst, NrFrames, NrChannels);
+ }
+ else if ((pInstance1->Current != pInstance1->Target) || \
+ (pInstance2->Current != pInstance2->Target))
+ {
+ LVC_MixSoft_Mc_D16C31_SAT((LVMixer3_1St_FLOAT_st *)(&ptrInstance->MixerStream[0]),
+ src1, dst, NrFrames, NrChannels);
+ LVC_MixInSoft_Mc_D16C31_SAT((LVMixer3_1St_FLOAT_st *)(&ptrInstance->MixerStream[1]),
+ src2, dst, NrFrames, NrChannels);
+ }
+ else{
+ /******************************************************************************
+ HARD MIXING
+ *******************************************************************************/
+ LVC_Core_MixHard_2St_D16C31_SAT(&ptrInstance->MixerStream[0],
+ &ptrInstance->MixerStream[1],
+ src1, src2, dst, NrFrames * NrChannels);
+ }
+}
+#endif
+
+/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Mixer.h b/media/libeffects/lvm/lib/Common/src/LVC_Mixer.h
index 199d529..ce42d2e 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_Mixer.h
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Mixer.h
@@ -18,12 +18,6 @@
#ifndef __LVC_MIXER_H__
#define __LVC_MIXER_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-
#include "LVM_Types.h"
/**********************************************************************************
@@ -31,7 +25,6 @@
***********************************************************************************/
/* LVMixer3_st structure stores Instance parameters for one audio stream */
-#ifdef BUILD_FLOAT
typedef struct
{
LVM_FLOAT PrivateParams[3]; /* Private Instance params for \
@@ -43,45 +36,14 @@
void *pGeneralPurpose; /* Pointer for general purpose usage */
LVM_Callback pCallBack; /* Pointer to the callback function */
} LVMixer3_FLOAT_st;
-#else
-typedef struct
-{
- LVM_INT32 PrivateParams[4]; /* Private Instance params for Audio Stream */
- LVM_INT16 CallbackSet; /* Boolean. Should be set by calling application each time the target value is updated */
- LVM_INT16 CallbackParam; /* Parameter that will be used in the calback function */
- void *pCallbackHandle; /* Pointer to the instance of the callback function */
- void *pGeneralPurpose; /* Pointer for general purpose usage */
- LVM_Callback pCallBack; /* Pointer to the callback function */
-} LVMixer3_st;
-#endif
-#ifdef BUILD_FLOAT
typedef struct
{
LVMixer3_FLOAT_st MixerStream[1]; /* Instance Params for one Audio Stream */
} LVMixer3_1St_FLOAT_st;
-#else
-typedef struct
-{
- LVMixer3_st MixerStream[1]; /* Instance Params for one Audio Stream */
-} LVMixer3_1St_st;
-#endif
-#ifdef BUILD_FLOAT
typedef struct
{
LVMixer3_FLOAT_st MixerStream[2]; /* Instance Params for two Audio Streams */
} LVMixer3_2St_FLOAT_st;
-#else
-typedef struct
-{
- LVMixer3_st MixerStream[2]; /* Instance Params for two Audio Streams */
-} LVMixer3_2St_st;
-#endif
-#ifndef BUILD_FLOAT
-typedef struct
-{
- LVMixer3_st MixerStream[3]; /* Instance Params for three Audio Streams */
-} LVMixer3_3St_st;
-#endif
/**********************************************************************************
FUNCTION PROTOTYPES (HIGH LEVEL FUNCTIONS)
***********************************************************************************/
@@ -92,7 +54,6 @@
#define LVMixer3_MixSoft_2St_D16C31_SAT LVMixer3_2St_D16C31_SAT_MixSoft
#define LVMixer3_MixSoft_3St_D16C31_SAT LVMixer3_3St_D16C31_SAT_MixSoft
-
/*** General functions ************************************************************/
/**********************************************************************************/
@@ -101,62 +62,28 @@
/* then the calculation will give an incorrect value for alpha, see the mixer */
/* documentation for further details. */
/* ********************************************************************************/
-#ifdef BUILD_FLOAT
void LVC_Mixer_SetTarget( LVMixer3_FLOAT_st *pStream,
LVM_FLOAT TargetGain);
-#else
-void LVC_Mixer_SetTarget( LVMixer3_st *pStream,
- LVM_INT32 TargetGain);
-#endif
-#ifdef BUILD_FLOAT
LVM_FLOAT LVC_Mixer_GetTarget( LVMixer3_FLOAT_st *pStream);
-#else
-LVM_INT32 LVC_Mixer_GetTarget( LVMixer3_st *pStream);
-#endif
-#ifdef BUILD_FLOAT
LVM_FLOAT LVC_Mixer_GetCurrent( LVMixer3_FLOAT_st *pStream);
-#else
-LVM_INT32 LVC_Mixer_GetCurrent( LVMixer3_st *pStream);
-#endif
-#ifdef BUILD_FLOAT
void LVC_Mixer_Init( LVMixer3_FLOAT_st *pStream,
LVM_FLOAT TargetGain,
LVM_FLOAT CurrentGain);
-#else
-void LVC_Mixer_Init( LVMixer3_st *pStream,
- LVM_INT32 TargetGain,
- LVM_INT32 CurrentGain);
-#endif
-#ifdef BUILD_FLOAT
void LVC_Mixer_SetTimeConstant( LVMixer3_FLOAT_st *pStream,
LVM_INT32 Tc_millisec,
LVM_Fs_en Fs,
LVM_INT16 NumChannels);
-#else
-void LVC_Mixer_SetTimeConstant( LVMixer3_st *pStream,
- LVM_INT32 Tc_millisec,
- LVM_Fs_en Fs,
- LVM_INT16 NumChannels);
-#endif
-#ifdef BUILD_FLOAT
void LVC_Mixer_VarSlope_SetTimeConstant( LVMixer3_FLOAT_st *pStream,
LVM_INT32 Tc_millisec,
LVM_Fs_en Fs,
LVM_INT16 NumChannels);
-#else
-void LVC_Mixer_VarSlope_SetTimeConstant( LVMixer3_st *pStream,
- LVM_INT32 Tc_millisec,
- LVM_Fs_en Fs,
- LVM_INT16 NumChannels);
-#endif
/*** 16 bit functions *************************************************************/
-#ifdef BUILD_FLOAT
void LVC_MixSoft_1St_D16C31_SAT(LVMixer3_1St_FLOAT_st *pInstance,
const LVM_FLOAT *src,
LVM_FLOAT *dst,
@@ -169,14 +96,6 @@
LVM_INT16 NrChannels);
#endif
-#else
-void LVC_MixSoft_1St_D16C31_SAT( LVMixer3_1St_st *pInstance,
- const LVM_INT16 *src,
- LVM_INT16 *dst,
- LVM_INT16 n);
-#endif
-
-#ifdef BUILD_FLOAT
void LVC_MixInSoft_D16C31_SAT(LVMixer3_1St_FLOAT_st *pInstance,
const LVM_FLOAT *src,
LVM_FLOAT *dst,
@@ -189,14 +108,6 @@
LVM_INT16 NrChannels);
#endif
-#else
-void LVC_MixInSoft_D16C31_SAT( LVMixer3_1St_st *pInstance,
- LVM_INT16 *src,
- LVM_INT16 *dst,
- LVM_INT16 n);
-#endif
-
-#ifdef BUILD_FLOAT
void LVC_MixSoft_2St_D16C31_SAT(LVMixer3_2St_FLOAT_st *pInstance,
const LVM_FLOAT *src1,
const LVM_FLOAT *src2,
@@ -210,20 +121,12 @@
LVM_INT16 NrFrames,
LVM_INT16 NrChannels);
#endif
-#else
-void LVC_MixSoft_2St_D16C31_SAT( LVMixer3_2St_st *pInstance,
- const LVM_INT16 *src1,
- LVM_INT16 *src2,
- LVM_INT16 *dst, /* dst cannot be equal to src2 */
- LVM_INT16 n);
-#endif
/**********************************************************************************/
/* For applying different gains to Left and right chennals */
/* MixerStream[0] applies to Left channel */
/* MixerStream[1] applies to Right channel */
/* Gain values should not be more that 1.0 */
/**********************************************************************************/
-#ifdef BUILD_FLOAT
#ifdef SUPPORT_MC
void LVC_MixSoft_1St_MC_float_SAT(LVMixer3_2St_FLOAT_st *pInstance,
const LVM_FLOAT *src,
@@ -236,15 +139,6 @@
const LVM_FLOAT *src,
LVM_FLOAT *dst, /* dst can be equal to src */
LVM_INT16 n); /* Number of stereo samples */
-#else
-void LVC_MixSoft_1St_2i_D16C31_SAT( LVMixer3_2St_st *pInstance,
- const LVM_INT16 *src,
- LVM_INT16 *dst, /* dst can be equal to src */
- LVM_INT16 n); /* Number of stereo samples */
-#endif
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_GetCurrent.c b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_GetCurrent.c
deleted file mode 100644
index 5990412..0000000
--- a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_GetCurrent.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "LVM_Types.h"
-#include "LVM_Macros.h"
-#include "LVC_Mixer_Private.h"
-
-
-/************************************************************************/
-/* FUNCTION: */
-/* LVMixer3_GetCurrent */
-/* */
-/* DESCRIPTION: */
-/* This function returns the CurrentGain in Q16.15 format */
-/* */
-/* RETURNS: */
-/* CurrentGain - CurrentGain value in Q 16.15 format */
-/* */
-/************************************************************************/
-#ifdef BUILD_FLOAT
-LVM_FLOAT LVC_Mixer_GetCurrent( LVMixer3_FLOAT_st *pStream)
-{
- LVM_FLOAT CurrentGain;
- Mix_Private_FLOAT_st *pInstance = (Mix_Private_FLOAT_st *)pStream->PrivateParams;
- CurrentGain = pInstance->Current; // CurrentGain
- return CurrentGain;
-}
-#else
-LVM_INT32 LVC_Mixer_GetCurrent( LVMixer3_st *pStream)
-{
- LVM_INT32 CurrentGain;
- Mix_Private_st *pInstance=(Mix_Private_st *)pStream->PrivateParams;
- CurrentGain=pInstance->Current>>(16-pInstance->Shift); // CurrentGain in Q16.15 format
- return CurrentGain;
-}
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_GetCurrent.cpp b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_GetCurrent.cpp
new file mode 100644
index 0000000..d0b50e6
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_GetCurrent.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LVM_Types.h"
+#include "LVM_Macros.h"
+#include "LVC_Mixer_Private.h"
+
+/************************************************************************/
+/* FUNCTION: */
+/* LVMixer3_GetCurrent */
+/* */
+/* DESCRIPTION: */
+/* This function returns the CurrentGain in Q16.15 format */
+/* */
+/* RETURNS: */
+/* CurrentGain - CurrentGain value in Q 16.15 format */
+/* */
+/************************************************************************/
+LVM_FLOAT LVC_Mixer_GetCurrent( LVMixer3_FLOAT_st *pStream)
+{
+ LVM_FLOAT CurrentGain;
+ Mix_Private_FLOAT_st *pInstance = (Mix_Private_FLOAT_st *)pStream->PrivateParams;
+ CurrentGain = pInstance->Current; // CurrentGain
+ return CurrentGain;
+}
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_GetTarget.c b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_GetTarget.c
deleted file mode 100644
index 507eefa..0000000
--- a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_GetTarget.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "LVM_Types.h"
-#include "LVM_Macros.h"
-#include "LVC_Mixer_Private.h"
-
-/************************************************************************/
-/* FUNCTION: */
-/* LVMixer3_GetTarget */
-/* */
-/* DESCRIPTION: */
-/* This function returns the TargetGain in Q16.15 format */
-/* */
-/* RETURNS: */
-/* TargetGain - TargetGain value in Q 16.15 format */
-/* */
-/************************************************************************/
-#ifdef BUILD_FLOAT
-LVM_FLOAT LVC_Mixer_GetTarget( LVMixer3_FLOAT_st *pStream)
-{
- LVM_FLOAT TargetGain;
- Mix_Private_FLOAT_st *pInstance = (Mix_Private_FLOAT_st *)pStream->PrivateParams;
-
- TargetGain = pInstance->Target; // TargetGain
- return TargetGain;
-}
-#else
-LVM_INT32 LVC_Mixer_GetTarget( LVMixer3_st *pStream)
-{
- LVM_INT32 TargetGain;
- Mix_Private_st *pInstance=(Mix_Private_st *)pStream->PrivateParams;
-
- TargetGain=pInstance->Target>>(16-pInstance->Shift); // TargetGain in Q16.15 format
-
- return TargetGain;
-}
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_GetTarget.cpp b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_GetTarget.cpp
new file mode 100644
index 0000000..3ae5ba4
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_GetTarget.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LVM_Types.h"
+#include "LVM_Macros.h"
+#include "LVC_Mixer_Private.h"
+
+/************************************************************************/
+/* FUNCTION: */
+/* LVMixer3_GetTarget */
+/* */
+/* DESCRIPTION: */
+/* This function returns the TargetGain in Q16.15 format */
+/* */
+/* RETURNS: */
+/* TargetGain - TargetGain value in Q 16.15 format */
+/* */
+/************************************************************************/
+LVM_FLOAT LVC_Mixer_GetTarget( LVMixer3_FLOAT_st *pStream)
+{
+ LVM_FLOAT TargetGain;
+ Mix_Private_FLOAT_st *pInstance = (Mix_Private_FLOAT_st *)pStream->PrivateParams;
+
+ TargetGain = pInstance->Target; // TargetGain
+ return TargetGain;
+}
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_Init.c b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_Init.c
deleted file mode 100644
index 737e26b..0000000
--- a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_Init.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "LVM_Types.h"
-#include "LVM_Macros.h"
-#include "LVC_Mixer_Private.h"
-
-/************************************************************************/
-/* FUNCTION: */
-/* LVMixer3_Init */
-/* */
-/* DESCRIPTION: */
-/* This intialization function intializes the private instance */
-/* paramters for a given Audio Stream based on TargetGain and */
-/* CurrentGain */
-/* This function caclulates the "Shift" required to provide the */
-/* integer part of TargetGain and fractional gain values "Target" and */
-/* "Current" based on maximum(TargetGain,CurrentGain) */
-/* E.g. CurrentGain=1.9 and TargetGain=2.5 then based on */
-/* MaxGain of 2.5, Shift = 2, Current=1.9/4=0.475, Target=2.5/4=0.625 */
-/* Therefore integer gain of 4 is provided by Left Shift of 2 and */
-/* fraction gain is provided through Current=0.475 and Target=0.625 */
-/* PARAMETERS: */
-/* pStream - ptr to Instance Parameter Structure LVMixer3_st for an*/
-/* Audio Stream */
-/* TargetGain - TargetGain value in Q 16.15 format */
-/* CurrentGain - CurrentGain value in Q 16.15 format */
-/* */
-/* RETURNS: */
-/* void */
-/* */
-/************************************************************************/
-#ifdef BUILD_FLOAT
-void LVC_Mixer_Init( LVMixer3_FLOAT_st *pStream,
- LVM_FLOAT TargetGain,
- LVM_FLOAT CurrentGain)
-{
- LVM_FLOAT MaxGain = TargetGain;
- Mix_Private_FLOAT_st *pInstance = (Mix_Private_FLOAT_st *)pStream->PrivateParams;
- if(CurrentGain > MaxGain)
- MaxGain = CurrentGain;
- pInstance->Target = TargetGain; // Update fractional gain Target
- pInstance->Current = CurrentGain; // Update fractional gain Current
-}
-#else
-void LVC_Mixer_Init( LVMixer3_st *pStream,
- LVM_INT32 TargetGain,
- LVM_INT32 CurrentGain)
-{
- LVM_INT16 Shift=0;
- LVM_INT32 MaxGain=TargetGain; // MaxGain is in Q16.15 format
- Mix_Private_st *pInstance=(Mix_Private_st *)pStream->PrivateParams;
- if(CurrentGain>MaxGain)
- MaxGain=CurrentGain; // MaxGain=max(CurrentGain,TargetGain)
-
- MaxGain=MaxGain>>15; // MaxGain in Q31.0 format i.e Integer part only
- while(MaxGain>0){ // Update Shift required to provide integer gain
- Shift++;
- MaxGain=MaxGain>>1;
- }
- pInstance->Target=TargetGain<<(16-Shift); // Update fractional gain Target
- pInstance->Current=CurrentGain<<(16-Shift); // Update fractional gain Current
- pInstance->Shift=Shift; // Update Shift
-}
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_Init.cpp b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_Init.cpp
new file mode 100644
index 0000000..c9fd344
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_Init.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LVM_Types.h"
+#include "LVM_Macros.h"
+#include "LVC_Mixer_Private.h"
+
+/************************************************************************/
+/* FUNCTION: */
+/* LVMixer3_Init */
+/* */
+/* DESCRIPTION: */
+/* This intialization function intializes the private instance */
+/* paramters for a given Audio Stream based on TargetGain and */
+/* CurrentGain */
+/* This function caclulates the "Shift" required to provide the */
+/* integer part of TargetGain and fractional gain values "Target" and */
+/* "Current" based on maximum(TargetGain,CurrentGain) */
+/* E.g. CurrentGain=1.9 and TargetGain=2.5 then based on */
+/* MaxGain of 2.5, Shift = 2, Current=1.9/4=0.475, Target=2.5/4=0.625 */
+/* Therefore integer gain of 4 is provided by Left Shift of 2 and */
+/* fraction gain is provided through Current=0.475 and Target=0.625 */
+/* PARAMETERS: */
+/* pStream - ptr to Instance Parameter Structure LVMixer3_st for an*/
+/* Audio Stream */
+/* TargetGain - TargetGain value in Q 16.15 format */
+/* CurrentGain - CurrentGain value in Q 16.15 format */
+/* */
+/* RETURNS: */
+/* void */
+/* */
+/************************************************************************/
+void LVC_Mixer_Init( LVMixer3_FLOAT_st *pStream,
+ LVM_FLOAT TargetGain,
+ LVM_FLOAT CurrentGain)
+{
+ LVM_FLOAT MaxGain = TargetGain;
+ Mix_Private_FLOAT_st *pInstance = (Mix_Private_FLOAT_st *)pStream->PrivateParams;
+ if(CurrentGain > MaxGain)
+ MaxGain = CurrentGain;
+ pInstance->Target = TargetGain; // Update fractional gain Target
+ pInstance->Current = CurrentGain; // Update fractional gain Current
+}
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_Private.h b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_Private.h
index 453a6a5..123d22b 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_Private.h
@@ -26,7 +26,6 @@
#include "VectorArithmetic.h"
/* Instance parameter structure */
-#ifdef BUILD_FLOAT
typedef struct
{
/* General */
@@ -34,16 +33,6 @@
LVM_FLOAT Current; /*number specifying value of Current Gain */
LVM_FLOAT Delta; /*number specifying value of Delta Gain */
} Mix_Private_FLOAT_st;
-#else
-typedef struct
-{
- /* General */
- LVM_INT32 Target; /* 32 bit number specifying fractional value of Target Gain */
- LVM_INT32 Current; /* 32 bit number specifying fractional valude of Current Gain */
- LVM_INT32 Shift; /* Left Shift for Integer part of Gain */
- LVM_INT32 Delta; /* 32 bit number specifying the fractional value of Delta Gain */
-} Mix_Private_st;
-#endif
/**********************************************************************************
DEFINITIONS
@@ -57,7 +46,6 @@
***********************************************************************************/
/*** 16 bit functions *************************************************************/
-#ifdef BUILD_FLOAT
void LVC_Core_MixInSoft_D16C31_SAT( LVMixer3_FLOAT_st *ptrInstance,
const LVM_FLOAT *src,
LVM_FLOAT *dst,
@@ -69,13 +57,6 @@
LVM_INT16 NrFrames,
LVM_INT16 NrChannels);
#endif
-#else
-void LVC_Core_MixInSoft_D16C31_SAT( LVMixer3_st *pInstance,
- const LVM_INT16 *src,
- LVM_INT16 *dst,
- LVM_INT16 n);
-#endif
-#ifdef BUILD_FLOAT
void LVC_Core_MixSoft_1St_D16C31_WRA( LVMixer3_FLOAT_st *ptrInstance,
const LVM_FLOAT *src,
LVM_FLOAT *dst,
@@ -87,27 +68,12 @@
LVM_INT16 NrFrames,
LVM_INT16 NrChannels);
#endif
-#else
-void LVC_Core_MixSoft_1St_D16C31_WRA( LVMixer3_st *pInstance,
- const LVM_INT16 *src,
- LVM_INT16 *dst,
- LVM_INT16 n);
-#endif
-#ifdef BUILD_FLOAT
void LVC_Core_MixHard_2St_D16C31_SAT( LVMixer3_FLOAT_st *pInstance1,
LVMixer3_FLOAT_st *pInstance2,
const LVM_FLOAT *src1,
const LVM_FLOAT *src2,
LVM_FLOAT *dst,
LVM_INT16 n);
-#else
-void LVC_Core_MixHard_2St_D16C31_SAT( LVMixer3_st *pInstance1,
- LVMixer3_st *pInstance2,
- const LVM_INT16 *src1,
- const LVM_INT16 *src2,
- LVM_INT16 *dst,
- LVM_INT16 n);
-#endif
/**********************************************************************************/
/* For applying different gains to Left and right chennals */
@@ -115,7 +81,6 @@
/* ptrInstance2 applies to Right channel */
/* Gain values should not be more that 1.0 */
/**********************************************************************************/
-#ifdef BUILD_FLOAT
#ifdef SUPPORT_MC
void LVC_Core_MixSoft_1St_MC_float_WRA(Mix_Private_FLOAT_st **ptrInstance,
const LVM_FLOAT *src,
@@ -128,13 +93,6 @@
const LVM_FLOAT *src,
LVM_FLOAT *dst,
LVM_INT16 n);
-#else
-void LVC_Core_MixSoft_1St_2i_D16C31_WRA( LVMixer3_st *ptrInstance1,
- LVMixer3_st *ptrInstance2,
- const LVM_INT16 *src,
- LVM_INT16 *dst, /* dst can be equal to src */
- LVM_INT16 n); /* Number of stereo samples */
-#endif
/**********************************************************************************/
/* For applying different gains to Left and right chennals */
@@ -142,7 +100,6 @@
/* ptrInstance2 applies to Right channel */
/* Gain values should not be more that 1.0 */
/**********************************************************************************/
-#ifdef BUILD_FLOAT
#ifdef SUPPORT_MC
void LVC_Core_MixHard_1St_MC_float_SAT(Mix_Private_FLOAT_st **ptrInstance,
const LVM_FLOAT *src,
@@ -155,43 +112,9 @@
const LVM_FLOAT *src,
LVM_FLOAT *dst,
LVM_INT16 n);
-#else
-void LVC_Core_MixHard_1St_2i_D16C31_SAT( LVMixer3_st *ptrInstance1,
- LVMixer3_st *ptrInstance2,
- const LVM_INT16 *src,
- LVM_INT16 *dst, /* dst can be equal to src */
- LVM_INT16 n); /* Number of stereo samples */
-#endif
/*** 32 bit functions *************************************************************/
-#ifndef BUILD_FLOAT
-void LVC_Core_MixInSoft_D32C31_SAT( LVMixer3_st *pInstance,
- const LVM_INT32 *src,
- LVM_INT32 *dst,
- LVM_INT16 n);
-
-void LVC_Core_MixSoft_1St_D32C31_WRA( LVMixer3_st *pInstance,
- const LVM_INT32 *src,
- LVM_INT32 *dst,
- LVM_INT16 n);
-
-void LVC_Core_MixHard_2St_D32C31_SAT( LVMixer3_st *pInstance1,
- LVMixer3_st *pInstance2,
- const LVM_INT32 *src1,
- const LVM_INT32 *src2,
- LVM_INT32 *dst,
- LVM_INT16 n);
-#endif
/**********************************************************************************/
#endif //#ifndef __LVC_MIXER_PRIVATE_H__
-
-
-
-
-
-
-
-
-
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_SetTarget.c b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_SetTarget.c
deleted file mode 100644
index 577179d..0000000
--- a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_SetTarget.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "LVM_Types.h"
-#include "LVM_Macros.h"
-#include "LVC_Mixer_Private.h"
-
-/************************************************************************/
-/* FUNCTION: */
-/* LVMixer3_SetTarget */
-/* */
-/* DESCRIPTION: */
-/* This function updates the private instance parameters: Shift,Target,*/
-/* Current for a given Audio Stream based on new value of TargetGain */
-/* */
-/* This function caclulates the "Shift" required to provide the */
-/* integer part of TargetGain and fractional gain values "Target" and */
-/* "Current" based on maximum(TargetGain,CurrentGain) */
-/* E.g. CurrentGain=1.9 and TargetGain=2.5 then based on */
-/* MaxGain of 2.5, Shift = 2, Current=1.9/4=0.475, Target=2.5/4=0.625 */
-/* Therefore integer gain of 4 is provided by Left Shift of 2 and */
-/* fraction gain is provided through Current=0.475 and Target=0.625 */
-/* PARAMETERS: */
-/* pStream - ptr to Instance Parameter Structure LVMixer3_st */
-/* for an Audio Stream */
-/* TargetGain - TargetGain value in Q 16.15 format */
-/* */
-/* RETURNS: */
-/* void */
-/* */
-/************************************************************************/
-#ifdef BUILD_FLOAT
-void LVC_Mixer_SetTarget(LVMixer3_FLOAT_st *pStream,
- LVM_FLOAT TargetGain)
-{
- Mix_Private_FLOAT_st *pInstance = (Mix_Private_FLOAT_st *)pStream->PrivateParams;
- pInstance->Target = TargetGain; // Update gain Target
-}
-#else
-void LVC_Mixer_SetTarget(LVMixer3_st *pStream,
- LVM_INT32 TargetGain)
-{
- LVM_INT32 Shift=0;
- LVM_INT32 CurrentGain;
- LVM_INT32 MaxGain=TargetGain; // MaxGain is in Q16.15 format
- Mix_Private_st *pInstance=(Mix_Private_st *)pStream->PrivateParams;
- CurrentGain=pInstance->Current>>(16-pInstance->Shift); // CurrentGain in Q16.15 format
- if(CurrentGain>MaxGain)
- MaxGain=CurrentGain; // MaxGain=max(CurrentGain,TargetGain)
-
- MaxGain=MaxGain>>15; // MaxGain in Q31.0 format i.e Integer part only
- while(MaxGain>0){ // Update Shift required to provide integer gain
- Shift++;
- MaxGain=MaxGain>>1;
- }
- pInstance->Target=TargetGain<<(16-Shift); // Update fractional gain Target
- pInstance->Current=CurrentGain<<(16-Shift); // Update fractional gain Current
- pInstance->Shift=Shift; // Update Shift
-}
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_SetTarget.cpp b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_SetTarget.cpp
new file mode 100644
index 0000000..47b0cec
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_SetTarget.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LVM_Types.h"
+#include "LVM_Macros.h"
+#include "LVC_Mixer_Private.h"
+
+/************************************************************************/
+/* FUNCTION: */
+/* LVMixer3_SetTarget */
+/* */
+/* DESCRIPTION: */
+/* This function updates the private instance parameters: Shift,Target,*/
+/* Current for a given Audio Stream based on new value of TargetGain */
+/* */
+/* This function caclulates the "Shift" required to provide the */
+/* integer part of TargetGain and fractional gain values "Target" and */
+/* "Current" based on maximum(TargetGain,CurrentGain) */
+/* E.g. CurrentGain=1.9 and TargetGain=2.5 then based on */
+/* MaxGain of 2.5, Shift = 2, Current=1.9/4=0.475, Target=2.5/4=0.625 */
+/* Therefore integer gain of 4 is provided by Left Shift of 2 and */
+/* fraction gain is provided through Current=0.475 and Target=0.625 */
+/* PARAMETERS: */
+/* pStream - ptr to Instance Parameter Structure LVMixer3_st */
+/* for an Audio Stream */
+/* TargetGain - TargetGain value in Q 16.15 format */
+/* */
+/* RETURNS: */
+/* void */
+/* */
+/************************************************************************/
+void LVC_Mixer_SetTarget(LVMixer3_FLOAT_st *pStream,
+ LVM_FLOAT TargetGain)
+{
+ Mix_Private_FLOAT_st *pInstance = (Mix_Private_FLOAT_st *)pStream->PrivateParams;
+ pInstance->Target = TargetGain; // Update gain Target
+}
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_SetTimeConstant.c b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_SetTimeConstant.c
deleted file mode 100644
index 9d3ee88..0000000
--- a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_SetTimeConstant.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "LVM_Types.h"
-#include "LVM_Macros.h"
-#include "LVC_Mixer_Private.h"
-
-/************************************************************************/
-/* FUNCTION: */
-/* LVMixer3_SetTimeConstant */
-/* */
-/* DESCRIPTION: */
-/* This function calculates the step change for fractional gain for a */
-/* given time constant, sample rate and num channels */
-/* Delta=(2147483647*4*1000)/(NumChannels*SampleRate*Tc_millisec) */
-/* in Q 0.31 format */
-/* */
-/* PARAMETERS: */
-/* pStream - ptr to Instance Parameter Structure LVMixer3_st for an*/
-/* Audio Stream */
-/* Tc_millisec - TimeConstant i.e time required in milli second to */
-/* go from linear fractional gain of 0 to 0.99999999 */
-/* Fs - LVM_Fs_en enumerator for Sampling Frequency */
-/* NumChannels - Number of channels in Audio Stream 1=Mono, 2=Stereo */
-/* */
-/* UPDATES: */
-/* Delta - the step change for fractional gain per 4 samples */
-/* in Q0.31 format for a given Time Constant, */
-/* Sample Rate and NumChannels */
-/* RETURNS: */
-/* void */
-/************************************************************************/
-#ifdef BUILD_FLOAT
-void LVC_Mixer_SetTimeConstant(LVMixer3_FLOAT_st *pStream,
- LVM_INT32 Tc_millisec,
- LVM_Fs_en Fs,
- LVM_INT16 NumChannels)
-{
-#ifdef HIGHER_FS
- LVM_FLOAT DeltaTable[13] = {0.500000f,/*8000*/
- 0.362812f,/*11025*/
- 0.333333f,/*12000*/
- 0.250000f,/*16000*/
- 0.181406f,/*22050*/
- 0.166666f,/*24000*/
- 0.125000f,/*32000*/
- 0.090703f,/*44100*/
- 0.083333f,/*48000*/
- 0.045352f,/*88200*/
- 0.041667f,/*96000*/
- 0.022676f,/*176400*/
- 0.020833f};/*192000*/
-#else
- LVM_FLOAT DeltaTable[9] = {0.500000f,/*8000*/
- 0.362812f,/*11025*/
- 0.333333f,/*12000*/
- 0.250000f,/*16000*/
- 0.181406f,/*22050*/
- 0.166666f,/*24000*/
- 0.125000f,/*32000*/
- 0.090703f,/*44100*/
- 0.083333f};/*48000*/
-#endif
-
- Mix_Private_FLOAT_st *pInstance = (Mix_Private_FLOAT_st *)pStream->PrivateParams;
- LVM_FLOAT Delta = DeltaTable[Fs];
- Delta = Delta / (NumChannels);
-
- if(Tc_millisec == 0)
- Delta = 1.000000f;
- else
- Delta = Delta / Tc_millisec;
-
- if(Delta == 0)
- Delta = 0.0000000005f; /* If Time Constant is so large that Delta is 0, \
- assign minimum value to Delta */
- pInstance->Delta = Delta; // Delta=(2147483647*4*1000)/(NumChannels*SampleRate*Tc_millisec)
-}
-#else
-void LVC_Mixer_SetTimeConstant(LVMixer3_st *pStream,
- LVM_INT32 Tc_millisec,
- LVM_Fs_en Fs,
- LVM_INT16 NumChannels)
-{
- LVM_INT32 DeltaTable[9]={1073741824,
- 779132389,
- 715827882,
- 536870912,
- 389566194,
- 357913941,
- 268435456,
- 194783097,
- 178956971};
- Mix_Private_st *pInstance=(Mix_Private_st *)pStream->PrivateParams;
- LVM_INT32 Delta=DeltaTable[Fs];
- Delta=Delta>>(NumChannels-1);
-
- if(Tc_millisec==0)
- Delta=0x7FFFFFFF;
- else
- Delta=Delta/Tc_millisec;
-
- if(Delta==0)
- Delta=1; // If Time Constant is so large that Delta is 0, assign minimum value to Delta
-
- pInstance->Delta=Delta; // Delta=(2147483647*4*1000)/(NumChannels*SampleRate*Tc_millisec) in Q 0.31 format
-}
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_SetTimeConstant.cpp b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_SetTimeConstant.cpp
new file mode 100644
index 0000000..1a8da7a
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_SetTimeConstant.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LVM_Types.h"
+#include "LVM_Macros.h"
+#include "LVC_Mixer_Private.h"
+
+/************************************************************************/
+/* FUNCTION: */
+/* LVMixer3_SetTimeConstant */
+/* */
+/* DESCRIPTION: */
+/* This function calculates the step change for fractional gain for a */
+/* given time constant, sample rate and num channels */
+/* Delta=(2147483647*4*1000)/(NumChannels*SampleRate*Tc_millisec) */
+/* in Q 0.31 format */
+/* */
+/* PARAMETERS: */
+/* pStream - ptr to Instance Parameter Structure LVMixer3_st for an*/
+/* Audio Stream */
+/* Tc_millisec - TimeConstant i.e time required in milli second to */
+/* go from linear fractional gain of 0 to 0.99999999 */
+/* Fs - LVM_Fs_en enumerator for Sampling Frequency */
+/* NumChannels - Number of channels in Audio Stream 1=Mono, 2=Stereo */
+/* */
+/* UPDATES: */
+/* Delta - the step change for fractional gain per 4 samples */
+/* in Q0.31 format for a given Time Constant, */
+/* Sample Rate and NumChannels */
+/* RETURNS: */
+/* void */
+/************************************************************************/
+void LVC_Mixer_SetTimeConstant(LVMixer3_FLOAT_st *pStream,
+ LVM_INT32 Tc_millisec,
+ LVM_Fs_en Fs,
+ LVM_INT16 NumChannels)
+{
+ LVM_FLOAT DeltaTable[13] = {0.500000f,/*8000*/
+ 0.362812f,/*11025*/
+ 0.333333f,/*12000*/
+ 0.250000f,/*16000*/
+ 0.181406f,/*22050*/
+ 0.166666f,/*24000*/
+ 0.125000f,/*32000*/
+ 0.090703f,/*44100*/
+ 0.083333f,/*48000*/
+ 0.045352f,/*88200*/
+ 0.041667f,/*96000*/
+ 0.022676f,/*176400*/
+ 0.020833f};/*192000*/
+
+ Mix_Private_FLOAT_st *pInstance = (Mix_Private_FLOAT_st *)pStream->PrivateParams;
+ LVM_FLOAT Delta = DeltaTable[Fs];
+ Delta = Delta / (NumChannels);
+
+ if(Tc_millisec == 0)
+ Delta = 1.000000f;
+ else
+ Delta = Delta / Tc_millisec;
+
+ if(Delta == 0)
+ Delta = 0.0000000005f; /* If Time Constant is so large that Delta is 0, \
+ assign minimum value to Delta */
+ pInstance->Delta = Delta; // Delta=(2147483647*4*1000)/(NumChannels*SampleRate*Tc_millisec)
+}
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_VarSlope_SetTimeConstant.c b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_VarSlope_SetTimeConstant.c
deleted file mode 100644
index 0e0acf1..0000000
--- a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_VarSlope_SetTimeConstant.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "LVM_Types.h"
-#include "LVM_Macros.h"
-#include "LVC_Mixer_Private.h"
-
-
-/************************************************************************/
-/* FUNCTION: */
-/* LVMixer3_VarSlope_SetTimeConstant */
-/* */
-/* DESCRIPTION: */
-/* This function calculates the step change for fractional gain for a */
-/* given time constant, sample rate and num channels */
-/* Delta=(2147483647*4*1000)/(NumChannels*SampleRate*Tc_millisec) */
-/* in Q 0.31 format */
-/* */
-/* PARAMETERS: */
-/* pStream - ptr to Instance Parameter Structure LVMixer3_st for an*/
-/* Audio Stream */
-/* Tc_millisec - TimeConstant i.e time required in milli second to */
-/* go from linear fractional gain of 0 to 0.99999999 */
-/* Fs - LVM_Fs_en enumerator for Sampling Frequency */
-/* NumChannels - Number of channels in Audio Stream 1=Mono, 2=Stereo */
-/* */
-/* UPDATES: */
-/* Delta - the step change for fractional gain per 4 samples */
-/* in Q0.31 format for a given Time Constant, */
-/* Sample Rate and NumChannels */
-/* RETURNS: */
-/* void */
-/************************************************************************/
-#ifdef BUILD_FLOAT
-void LVC_Mixer_VarSlope_SetTimeConstant( LVMixer3_FLOAT_st *pStream,
- LVM_INT32 Tc_millisec,
- LVM_Fs_en Fs,
- LVM_INT16 NumChannels)
-{
-#ifdef HIGHER_FS
- LVM_FLOAT DeltaTable[13] = {0.500000f,/*8000*/
- 0.362812f,/*11025*/
- 0.333333f,/*12000*/
- 0.250000f,/*16000*/
- 0.181406f,/*22050*/
- 0.166666f,/*24000*/
- 0.125000f,/*32000*/
- 0.090703f,/*44100*/
- 0.083333f,/*48000*/
- 0.045352f,/*88200*/
- 0.041666f,/*96000*/
- 0.022676f,/*176400*/
- 0.020833f};/*192000*/
-#else
- LVM_FLOAT DeltaTable[9] = {0.500000f,/*8000*/
- 0.362812f,/*11025*/
- 0.333333f,/*12000*/
- 0.250000f,/*16000*/
- 0.181406f,/*22050*/
- 0.166666f,/*24000*/
- 0.125000f,/*32000*/
- 0.090703f,/*44100*/
- 0.083333f};/*48000*/
-#endif
- LVM_FLOAT Tc_millisec_float;
- Mix_Private_FLOAT_st *pInstance = (Mix_Private_FLOAT_st *)pStream->PrivateParams;
- LVM_FLOAT Delta = DeltaTable[Fs];
-
- LVM_FLOAT Current;
- LVM_FLOAT Target;
-
- Delta=Delta / (NumChannels);
-
- /* Get gain values */
- Current = pInstance->Current;
- Target = pInstance->Target;
-
- if (Current != Target)
- {
- Tc_millisec_float = (LVM_FLOAT)(Tc_millisec) / (Current - Target);
- if (Tc_millisec_float < 0)
- Tc_millisec_float = -Tc_millisec_float;
-
- if(Tc_millisec == 0)
- Delta = 1.000000f;
- else
- Delta = Delta / Tc_millisec_float;
-
- if(Delta == 0)
- Delta = 0.0000000005f; /* If Time Constant is so large that Delta is 0, \
- assign minimum value to Delta */
- }
- else
- {
- Delta = 0.0000000005f; /* Minimum value for proper call-backs \
- (setting it to zero has some problems, to be corrected) */
- }
-
- pInstance->Delta = Delta; // Delta=(2147483647*4*1000)/(NumChannels*SampleRate*Tc_millisec)
-}
-#else
-void LVC_Mixer_VarSlope_SetTimeConstant( LVMixer3_st *pStream,
- LVM_INT32 Tc_millisec,
- LVM_Fs_en Fs,
- LVM_INT16 NumChannels)
-{
- LVM_INT32 DeltaTable[9]={1073741824,
- 779132389,
- 715827882,
- 536870912,
- 389566194,
- 357913941,
- 268435456,
- 194783097,
- 178956971};
- Mix_Private_st *pInstance=(Mix_Private_st *)pStream->PrivateParams;
- LVM_INT32 Delta=DeltaTable[Fs];
-
- LVM_INT32 Current;
- LVM_INT32 Target;
-
- Delta=Delta>>(NumChannels-1);
-
- /* Get gain values */
- Current = LVC_Mixer_GetCurrent( pStream );
- Target = LVC_Mixer_GetTarget( pStream );
-
- if (Current != Target)
- {
- Tc_millisec = Tc_millisec * 32767 / (Current - Target);
- if (Tc_millisec<0) Tc_millisec = -Tc_millisec;
-
- if(Tc_millisec==0)
- Delta=0x7FFFFFFF;
- else
- Delta=Delta/Tc_millisec;
-
- if(Delta==0)
- Delta=1; // If Time Constant is so large that Delta is 0, assign minimum value to Delta
- }
- else
- {
- Delta =1; // Minimum value for proper call-backs (setting it to zero has some problems, to be corrected)
- }
-
-
- pInstance->Delta=Delta; // Delta=(2147483647*4*1000)/(NumChannels*SampleRate*Tc_millisec) in Q 0.31 format
-}
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_VarSlope_SetTimeConstant.cpp b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_VarSlope_SetTimeConstant.cpp
new file mode 100644
index 0000000..f335a1e
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_VarSlope_SetTimeConstant.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LVM_Types.h"
+#include "LVM_Macros.h"
+#include "LVC_Mixer_Private.h"
+
+/************************************************************************/
+/* FUNCTION: */
+/* LVMixer3_VarSlope_SetTimeConstant */
+/* */
+/* DESCRIPTION: */
+/* This function calculates the step change for fractional gain for a */
+/* given time constant, sample rate and num channels */
+/* Delta=(2147483647*4*1000)/(NumChannels*SampleRate*Tc_millisec) */
+/* in Q 0.31 format */
+/* */
+/* PARAMETERS: */
+/* pStream - ptr to Instance Parameter Structure LVMixer3_st for an*/
+/* Audio Stream */
+/* Tc_millisec - TimeConstant i.e time required in milli second to */
+/* go from linear fractional gain of 0 to 0.99999999 */
+/* Fs - LVM_Fs_en enumerator for Sampling Frequency */
+/* NumChannels - Number of channels in Audio Stream 1=Mono, 2=Stereo */
+/* */
+/* UPDATES: */
+/* Delta - the step change for fractional gain per 4 samples */
+/* in Q0.31 format for a given Time Constant, */
+/* Sample Rate and NumChannels */
+/* RETURNS: */
+/* void */
+/************************************************************************/
+void LVC_Mixer_VarSlope_SetTimeConstant( LVMixer3_FLOAT_st *pStream,
+ LVM_INT32 Tc_millisec,
+ LVM_Fs_en Fs,
+ LVM_INT16 NumChannels)
+{
+ LVM_FLOAT DeltaTable[13] = {0.500000f,/*8000*/
+ 0.362812f,/*11025*/
+ 0.333333f,/*12000*/
+ 0.250000f,/*16000*/
+ 0.181406f,/*22050*/
+ 0.166666f,/*24000*/
+ 0.125000f,/*32000*/
+ 0.090703f,/*44100*/
+ 0.083333f,/*48000*/
+ 0.045352f,/*88200*/
+ 0.041666f,/*96000*/
+ 0.022676f,/*176400*/
+ 0.020833f};/*192000*/
+ LVM_FLOAT Tc_millisec_float;
+ Mix_Private_FLOAT_st *pInstance = (Mix_Private_FLOAT_st *)pStream->PrivateParams;
+ LVM_FLOAT Delta = DeltaTable[Fs];
+
+ LVM_FLOAT Current;
+ LVM_FLOAT Target;
+
+ Delta=Delta / (NumChannels);
+
+ /* Get gain values */
+ Current = pInstance->Current;
+ Target = pInstance->Target;
+
+ if (Current != Target)
+ {
+ Tc_millisec_float = (LVM_FLOAT)(Tc_millisec) / (Current - Target);
+ if (Tc_millisec_float < 0)
+ Tc_millisec_float = -Tc_millisec_float;
+
+ if(Tc_millisec == 0)
+ Delta = 1.000000f;
+ else
+ Delta = Delta / Tc_millisec_float;
+
+ if(Delta == 0)
+ Delta = 0.0000000005f; /* If Time Constant is so large that Delta is 0, \
+ assign minimum value to Delta */
+ }
+ else
+ {
+ Delta = 0.0000000005f; /* Minimum value for proper call-backs \
+ (setting it to zero has some problems, to be corrected) */
+ }
+
+ pInstance->Delta = Delta; // Delta=(2147483647*4*1000)/(NumChannels*SampleRate*Tc_millisec)
+}
diff --git a/media/libeffects/lvm/lib/Common/src/LVM_FO_HPF.c b/media/libeffects/lvm/lib/Common/src/LVM_FO_HPF.c
deleted file mode 100644
index 9094622..0000000
--- a/media/libeffects/lvm/lib/Common/src/LVM_FO_HPF.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "LVM_Types.h"
-#include "LVM_Macros.h"
-#include "ScalarArithmetic.h"
-#include "BIQUAD.h"
-#include "Filter.h"
-
-
-/*-------------------------------------------------------------------------*/
-/* FUNCTION: */
-/* void LVM_FO_LPF( LVM_INT32 w , */
-/* FO_C32_Coefs_t *pCoeffs); */
-/* */
-/* */
-/* DESCRIPTION: */
-/* This function calculates the coefficient of first order low pass */
-/* filter. It uses the equations: */
-/* */
-/* B1 = (tan(w/2) - 1 ) / (tan(w/2) + 1 ) */
-/* A0 = (1 - B1) / 2 */
-/* A1 = A0 */
-/* */
-/* The value of B1 is then calculated directly from the value w by a */
-/* polynomial expansion using a 9th order polynomial. It uses the */
-/* following table of 32-bit integer polynomial coefficients: */
-/* */
-/* Coefficient Value */
-/* A0 -8388571 */
-/* A1 33547744 */
-/* A2 -66816791 */
-/* A3 173375308 */
-/* A4 -388437573 */
-/* A5 752975383 */
-/* A6 -1103016663 */
-/* A7 1121848567 */
-/* A8 -688078159 */
-/* A9 194669577 */
-/* A10 8 */
-/* */
-/* Y = (A0 + A1*X + A2*X2 + A3*X3 + �.. + AN*xN) << AN+1 */
-/* */
-/* */
-/* PARAMETERS: */
-/* */
-/* w Sample rate in radians, where: */
-/* w = 2 * Pi * Fc / Fs */
-/* Fc is the corner frequency in Hz */
-/* Fs is the sample rate in Hz */
-/* w is in Q2.29 format and data range is [0 Pi] */
-/* pCoeffs Points to the filter coefficients calculated here */
-/* in Q1.30 format */
-/* RETURNS: */
-/* */
-/*-------------------------------------------------------------------------*/
-#ifdef BUILD_FLOAT
-LVM_FLOAT LVM_FO_HPF( LVM_FLOAT w,
- FO_FLOAT_Coefs_t *pCoeffs)
-{
- LVM_FLOAT Y,Coefficients[13] = {-0.999996f,
- 0.999801f,
- -0.497824f,
- 0.322937f,
- -0.180880f,
- 0.087658f,
- -0.032102f,
- 0.008163f,
- -0.001252f,
- 0.000089f,
- 0,
- 0,
- 0};
- Y=LVM_Polynomial((LVM_UINT16)9, Coefficients, w);
-
- pCoeffs->B1 = -Y; /* Store -B1 in filter structure instead of B1!*/
- /* A0=(1-B1)/2= B1/2 - 0.5*/
- Y = Y / 2.0f; /* A0=Y=B1/2*/
- Y = Y - 0.5f; /* A0=Y=(B1/2 - 0.5)*/
-
- pCoeffs->A0 = Y * FILTER_LOSS_FLOAT; /* Apply loss to avoid overflow*/
- pCoeffs->A1 = -pCoeffs->A0; /* Store A1=-A0*/
-
- return 1;
-}
-#else
-LVM_INT32 LVM_FO_HPF( LVM_INT32 w,
- FO_C32_Coefs_t *pCoeffs)
-{
- LVM_INT32 Y,Coefficients[13]={ -8388571,
- 33547744,
- -66816791,
- 173375308,
- -388437573,
- 752975383,
- -1103016663,
- 1121848567,
- -688078159,
- 194669577,
- 8,
- 0,
- 0};
- Y=LVM_Polynomial( (LVM_UINT16)9,
- Coefficients,
- w);
- pCoeffs->B1=-Y; /* Store -B1 in filter structure instead of B1!*/
- /* A0=(1-B1)/2= B1/2 - 0.5*/
- Y=Y>>1; /* A0=Y=B1/2*/
- Y=Y-0x40000000; /* A0=Y=(B1/2 - 0.5)*/
- MUL32x16INTO32(Y, FILTER_LOSS ,pCoeffs->A0 ,15) /* Apply loss to avoid overflow*/
- pCoeffs->A1=-pCoeffs->A0; /* Store A1=-A0*/
-
- return 1;
-}
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/LVM_FO_HPF.cpp b/media/libeffects/lvm/lib/Common/src/LVM_FO_HPF.cpp
new file mode 100644
index 0000000..2497d29
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/LVM_FO_HPF.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LVM_Types.h"
+#include "LVM_Macros.h"
+#include "ScalarArithmetic.h"
+#include "BIQUAD.h"
+#include "Filter.h"
+
+/*-------------------------------------------------------------------------*/
+/* FUNCTION: */
+/* void LVM_FO_LPF( LVM_INT32 w , */
+/* FO_C32_Coefs_t *pCoeffs); */
+/* */
+/* */
+/* DESCRIPTION: */
+/* This function calculates the coefficient of first order low pass */
+/* filter. It uses the equations: */
+/* */
+/* B1 = (tan(w/2) - 1 ) / (tan(w/2) + 1 ) */
+/* A0 = (1 - B1) / 2 */
+/* A1 = A0 */
+/* */
+/* The value of B1 is then calculated directly from the value w by a */
+/* polynomial expansion using a 9th order polynomial. It uses the */
+/* following table of 32-bit integer polynomial coefficients: */
+/* */
+/* Coefficient Value */
+/* A0 -8388571 */
+/* A1 33547744 */
+/* A2 -66816791 */
+/* A3 173375308 */
+/* A4 -388437573 */
+/* A5 752975383 */
+/* A6 -1103016663 */
+/* A7 1121848567 */
+/* A8 -688078159 */
+/* A9 194669577 */
+/* A10 8 */
+/* */
+/* Y = (A0 + A1*X + A2*X2 + A3*X3 + �.. + AN*xN) << AN+1 */
+/* */
+/* */
+/* PARAMETERS: */
+/* */
+/* w Sample rate in radians, where: */
+/* w = 2 * Pi * Fc / Fs */
+/* Fc is the corner frequency in Hz */
+/* Fs is the sample rate in Hz */
+/* w is in Q2.29 format and data range is [0 Pi] */
+/* pCoeffs Points to the filter coefficients calculated here */
+/* in Q1.30 format */
+/* RETURNS: */
+/* */
+/*-------------------------------------------------------------------------*/
+LVM_FLOAT LVM_FO_HPF( LVM_FLOAT w,
+ FO_FLOAT_Coefs_t *pCoeffs)
+{
+ LVM_FLOAT Y,Coefficients[13] = {-0.999996f,
+ 0.999801f,
+ -0.497824f,
+ 0.322937f,
+ -0.180880f,
+ 0.087658f,
+ -0.032102f,
+ 0.008163f,
+ -0.001252f,
+ 0.000089f,
+ 0,
+ 0,
+ 0};
+ Y=LVM_Polynomial((LVM_UINT16)9, Coefficients, w);
+
+ pCoeffs->B1 = -Y; /* Store -B1 in filter structure instead of B1!*/
+ /* A0=(1-B1)/2= B1/2 - 0.5*/
+ Y = Y / 2.0f; /* A0=Y=B1/2*/
+ Y = Y - 0.5f; /* A0=Y=(B1/2 - 0.5)*/
+
+ pCoeffs->A0 = Y * FILTER_LOSS_FLOAT; /* Apply loss to avoid overflow*/
+ pCoeffs->A1 = -pCoeffs->A0; /* Store A1=-A0*/
+
+ return 1;
+}
diff --git a/media/libeffects/lvm/lib/Common/src/LVM_FO_LPF.c b/media/libeffects/lvm/lib/Common/src/LVM_FO_LPF.c
deleted file mode 100644
index 9fe67f8..0000000
--- a/media/libeffects/lvm/lib/Common/src/LVM_FO_LPF.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "LVM_Types.h"
-#include "LVM_Macros.h"
-#include "ScalarArithmetic.h"
-#include "BIQUAD.h"
-#include "Filter.h"
-
-
-/*-------------------------------------------------------------------------*/
-/* FUNCTION: */
-/* void LVM_FO_LPF( LVM_INT32 w , */
-/* FO_C32_Coefs_t *pCoeffs); */
-/* */
-/* */
-/* DESCRIPTION: */
-/* This function calculates the coefficient of first order low pass */
-/* filter. It uses the equations: */
-/* */
-/* B1 = (tan(w/2) - 1 ) / (tan(w/2) + 1 ) */
-/* A0 = (1 + B1) / 2 */
-/* A1 = A0 */
-/* */
-/* The value of B1 is then calculated directly from the value w by a */
-/* polynomial expansion using a 9th order polynomial. It uses the */
-/* following table of 32-bit integer polynomial coefficients: */
-/* */
-/* Coefficient Value */
-/* A0 -8388571 */
-/* A1 33547744 */
-/* A2 -66816791 */
-/* A3 173375308 */
-/* A4 -388437573 */
-/* A5 752975383 */
-/* A6 -1103016663 */
-/* A7 1121848567 */
-/* A8 -688078159 */
-/* A9 194669577 */
-/* A10 8 */
-/* */
-/* Y = (A0 + A1*X + A2*X2 + A3*X3 + �.. + AN*xN) << AN+1 */
-/* */
-/* */
-/* PARAMETERS: */
-/* */
-/* w Sample rate in radians, where: */
-/* w = 2 * Pi * Fc / Fs */
-/* Fc is the corner frequency in Hz */
-/* Fs is the sample rate in Hz */
-/* w is in Q2.29 format and data range is [0 Pi] */
-/* pCoeffs Points to the filter coefficients calculated here */
-/* in Q1.30 format */
-/* RETURNS: */
-/* */
-/*-------------------------------------------------------------------------*/
-#ifdef BUILD_FLOAT
-LVM_FLOAT LVM_FO_LPF( LVM_FLOAT w,
- FO_FLOAT_Coefs_t *pCoeffs)
-{
- LVM_FLOAT Y,Coefficients[13] = {-0.999996f,
- 0.999801f,
- -0.497824f,
- 0.322937f,
- -0.180880f,
- 0.087658f,
- -0.032102f,
- 0.008163f,
- -0.001252f,
- 0.000089f,
- 0};
- Y=LVM_Polynomial((LVM_UINT16)9, Coefficients, w);
- pCoeffs->B1 = -Y; // Store -B1 in filter structure instead of B1!
- // A0=(1+B1)/2= B1/2 + 0.5
- Y = Y / 2.0f; // A0=Y=B1/2
- Y = Y + 0.5f; // A0=Y=(B1/2 + 0.5)
-
- pCoeffs->A0 = Y * FILTER_LOSS_FLOAT;
- pCoeffs->A1 = pCoeffs->A0;
-
- return 1;
-}
-#else
-LVM_INT32 LVM_FO_LPF( LVM_INT32 w,
- FO_C32_Coefs_t *pCoeffs)
-{
- LVM_INT32 Y,Coefficients[13]={ -8388571,
- 33547744,
- -66816791,
- 173375308,
- -388437573,
- 752975383,
- -1103016663,
- 1121848567,
- -688078159,
- 194669577,
- 8};
- Y=LVM_Polynomial( (LVM_UINT16)9,
- Coefficients,
- w);
- pCoeffs->B1=-Y; // Store -B1 in filter structure instead of B1!
- // A0=(1+B1)/2= B1/2 + 0.5
- Y=Y>>1; // A0=Y=B1/2
- Y=Y+0x40000000; // A0=Y=(B1/2 + 0.5)
- MUL32x16INTO32(Y, FILTER_LOSS ,pCoeffs->A0 ,15) // Apply loss to avoid overflow
- pCoeffs->A1=pCoeffs->A0;
- return 1;
-}
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/LVM_FO_LPF.cpp b/media/libeffects/lvm/lib/Common/src/LVM_FO_LPF.cpp
new file mode 100644
index 0000000..7bc6046
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/LVM_FO_LPF.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LVM_Types.h"
+#include "LVM_Macros.h"
+#include "ScalarArithmetic.h"
+#include "BIQUAD.h"
+#include "Filter.h"
+
+/*-------------------------------------------------------------------------*/
+/* FUNCTION: */
+/* void LVM_FO_LPF( LVM_INT32 w , */
+/* FO_C32_Coefs_t *pCoeffs); */
+/* */
+/* */
+/* DESCRIPTION: */
+/* This function calculates the coefficient of first order low pass */
+/* filter. It uses the equations: */
+/* */
+/* B1 = (tan(w/2) - 1 ) / (tan(w/2) + 1 ) */
+/* A0 = (1 + B1) / 2 */
+/* A1 = A0 */
+/* */
+/* The value of B1 is then calculated directly from the value w by a */
+/* polynomial expansion using a 9th order polynomial. It uses the */
+/* following table of 32-bit integer polynomial coefficients: */
+/* */
+/* Coefficient Value */
+/* A0 -8388571 */
+/* A1 33547744 */
+/* A2 -66816791 */
+/* A3 173375308 */
+/* A4 -388437573 */
+/* A5 752975383 */
+/* A6 -1103016663 */
+/* A7 1121848567 */
+/* A8 -688078159 */
+/* A9 194669577 */
+/* A10 8 */
+/* */
+/* Y = (A0 + A1*X + A2*X2 + A3*X3 + �.. + AN*xN) << AN+1 */
+/* */
+/* */
+/* PARAMETERS: */
+/* */
+/* w Sample rate in radians, where: */
+/* w = 2 * Pi * Fc / Fs */
+/* Fc is the corner frequency in Hz */
+/* Fs is the sample rate in Hz */
+/* w is in Q2.29 format and data range is [0 Pi] */
+/* pCoeffs Points to the filter coefficients calculated here */
+/* in Q1.30 format */
+/* RETURNS: */
+/* */
+/*-------------------------------------------------------------------------*/
+LVM_FLOAT LVM_FO_LPF( LVM_FLOAT w,
+ FO_FLOAT_Coefs_t *pCoeffs)
+{
+ LVM_FLOAT Y,Coefficients[13] = {-0.999996f,
+ 0.999801f,
+ -0.497824f,
+ 0.322937f,
+ -0.180880f,
+ 0.087658f,
+ -0.032102f,
+ 0.008163f,
+ -0.001252f,
+ 0.000089f,
+ 0};
+ Y=LVM_Polynomial((LVM_UINT16)9, Coefficients, w);
+ pCoeffs->B1 = -Y; // Store -B1 in filter structure instead of B1!
+ // A0=(1+B1)/2= B1/2 + 0.5
+ Y = Y / 2.0f; // A0=Y=B1/2
+ Y = Y + 0.5f; // A0=Y=(B1/2 + 0.5)
+
+ pCoeffs->A0 = Y * FILTER_LOSS_FLOAT;
+ pCoeffs->A1 = pCoeffs->A0;
+
+ return 1;
+}
diff --git a/media/libeffects/lvm/lib/Common/src/LVM_GetOmega.c b/media/libeffects/lvm/lib/Common/src/LVM_GetOmega.c
deleted file mode 100644
index 6307e68..0000000
--- a/media/libeffects/lvm/lib/Common/src/LVM_GetOmega.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "LVM_Types.h"
-#include "Filter.h"
-#include "LVM_Macros.h"
-
-/************************************************************************************/
-/* */
-/* Defines and Tables for 2*Pi/Fs */
-/* */
-/************************************************************************************/
-
-#define LVVDL_2PiBy_8000 1727108826 /* In Q41 format */
-#define LVVDL_2PiBy_11025 1253230894 /* In Q41 format */
-#define LVVDL_2PiBy_12000 1151405884 /* In Q41 format */
-
-#define LVVDL_2PiByFs_SHIFT1 12 /* Qformat shift for 8kHz, 11.025kHz and 12kHz i.e. 12=41-29 */
-#define LVVDL_2PiByFs_SHIFT2 13 /* Qformat shift for 16kHz, 22.050kHz and 24kHz i.e. 13=42-29 */
-#define LVVDL_2PiByFs_SHIFT3 14 /* Qformat shift for 32kHz, 44.1kHz and 48kHz i.e. 14=43-29 */
-#ifndef BUILD_FLOAT
-const LVM_INT32 LVVDL_2PiOnFsTable[] = {LVVDL_2PiBy_8000 , /* 8kHz in Q41, 16kHz in Q42, 32kHz in Q43 */
- LVVDL_2PiBy_11025, /* 11025 Hz in Q41, 22050Hz in Q42, 44100 Hz in Q43*/
- LVVDL_2PiBy_12000}; /* 12kHz in Q41, 24kHz in Q42, 48kHz in Q43 */
-#endif
-
-const LVM_INT32 LVVDL_2PiOnFsShiftTable[]={LVVDL_2PiByFs_SHIFT1 , /* 8kHz, 11025Hz, 12kHz */
- LVVDL_2PiByFs_SHIFT2, /* 16kHz, 22050Hz, 24kHz*/
- LVVDL_2PiByFs_SHIFT3}; /* 32kHz, 44100Hz, 48kHz */
-#ifdef BUILD_FLOAT
-#define LVVDL_2PiBy_8000_f 0.000785398f
-#define LVVDL_2PiBy_11025_f 0.000569903f
-#define LVVDL_2PiBy_12000_f 0.000523599f
-#define LVVDL_2PiBy_16000_f 0.000392700f
-#define LVVDL_2PiBy_22050_f 0.000284952f
-#define LVVDL_2PiBy_24000_f 0.000261800f
-#define LVVDL_2PiBy_32000_f 0.000196350f
-#define LVVDL_2PiBy_44100_f 0.000142476f
-#define LVVDL_2PiBy_48000_f 0.000130900f
-
-#ifdef HIGHER_FS
-#define LVVDL_2PiBy_88200_f 0.000071238f
-#define LVVDL_2PiBy_96000_f 0.000065450f
-#define LVVDL_2PiBy_176400_f 0.000035619f
-#define LVVDL_2PiBy_192000_f 0.000032725f
-#endif
-const LVM_FLOAT LVVDL_2PiOnFsTable[] = {LVVDL_2PiBy_8000_f,
- LVVDL_2PiBy_11025_f,
- LVVDL_2PiBy_12000_f,
- LVVDL_2PiBy_16000_f,
- LVVDL_2PiBy_22050_f,
- LVVDL_2PiBy_24000_f,
- LVVDL_2PiBy_32000_f,
- LVVDL_2PiBy_44100_f,
- LVVDL_2PiBy_48000_f
-#ifdef HIGHER_FS
- ,LVVDL_2PiBy_88200_f
- ,LVVDL_2PiBy_96000_f
- ,LVVDL_2PiBy_176400_f
- ,LVVDL_2PiBy_192000_f
-#endif
- };
-#endif
-/*-------------------------------------------------------------------------*/
-/* FUNCTION: */
-/* LVM_GetOmega */
-/* */
-/* LVM_INT32 LVM_GetOmega(LVM_UINT16 Fc, */
-/* LVM_Fs_en Fs) */
-/* */
-/* DESCRIPTION: */
-/* This function calculates the value of w using Fc and Fs */
-/* */
-/* PARAMETERS: */
-/* */
-/* LVM_UINT16 Fc The corner frequency in Hz Q16.0 format */
-/* LVM_Fs_en Fs The SampleRate */
-/* RETURNS: */
-/* w=2*pi*Fc/Fs in Q2.29 format */
-/*-------------------------------------------------------------------------*/
-#ifdef BUILD_FLOAT
-#ifdef HIGHER_FS
-LVM_FLOAT LVM_GetOmega(LVM_UINT32 Fc,
- LVM_Fs_en Fs)
-#else
-LVM_FLOAT LVM_GetOmega(LVM_UINT16 Fc,
- LVM_Fs_en Fs)
-#endif
-{
- LVM_FLOAT w;
- w = (LVM_FLOAT)Fc * LVVDL_2PiOnFsTable[Fs];
- return w;
-}
-#else
-LVM_INT32 LVM_GetOmega(LVM_UINT16 Fc,
- LVM_Fs_en Fs)
-{
- LVM_INT32 w;
- MUL32x32INTO32((LVM_INT32)Fc,LVVDL_2PiOnFsTable[Fs%3],w,LVVDL_2PiOnFsShiftTable[Fs/3])
- return w;
-}
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/LVM_GetOmega.cpp b/media/libeffects/lvm/lib/Common/src/LVM_GetOmega.cpp
new file mode 100644
index 0000000..2a7cca2
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/LVM_GetOmega.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LVM_Types.h"
+#include "Filter.h"
+#include "LVM_Macros.h"
+
+/************************************************************************************/
+/* */
+/* Defines and Tables for 2*Pi/Fs */
+/* */
+/************************************************************************************/
+
+#define LVVDL_2PiBy_8000 1727108826 /* In Q41 format */
+#define LVVDL_2PiBy_11025 1253230894 /* In Q41 format */
+#define LVVDL_2PiBy_12000 1151405884 /* In Q41 format */
+
+#define LVVDL_2PiByFs_SHIFT1 12 /* Qformat shift for 8kHz, 11.025kHz and 12kHz i.e. 12=41-29 */
+#define LVVDL_2PiByFs_SHIFT2 13 /* Qformat shift for 16kHz, 22.050kHz and 24kHz i.e. 13=42-29 */
+#define LVVDL_2PiByFs_SHIFT3 14 /* Qformat shift for 32kHz, 44.1kHz and 48kHz i.e. 14=43-29 */
+#define LVVDL_2PiBy_8000_f 0.000785398f
+#define LVVDL_2PiBy_11025_f 0.000569903f
+#define LVVDL_2PiBy_12000_f 0.000523599f
+#define LVVDL_2PiBy_16000_f 0.000392700f
+#define LVVDL_2PiBy_22050_f 0.000284952f
+#define LVVDL_2PiBy_24000_f 0.000261800f
+#define LVVDL_2PiBy_32000_f 0.000196350f
+#define LVVDL_2PiBy_44100_f 0.000142476f
+#define LVVDL_2PiBy_48000_f 0.000130900f
+
+#define LVVDL_2PiBy_88200_f 0.000071238f
+#define LVVDL_2PiBy_96000_f 0.000065450f
+#define LVVDL_2PiBy_176400_f 0.000035619f
+#define LVVDL_2PiBy_192000_f 0.000032725f
+const LVM_FLOAT LVVDL_2PiOnFsTable[] = {LVVDL_2PiBy_8000_f,
+ LVVDL_2PiBy_11025_f,
+ LVVDL_2PiBy_12000_f,
+ LVVDL_2PiBy_16000_f,
+ LVVDL_2PiBy_22050_f,
+ LVVDL_2PiBy_24000_f,
+ LVVDL_2PiBy_32000_f,
+ LVVDL_2PiBy_44100_f,
+ LVVDL_2PiBy_48000_f
+ ,LVVDL_2PiBy_88200_f
+ ,LVVDL_2PiBy_96000_f
+ ,LVVDL_2PiBy_176400_f
+ ,LVVDL_2PiBy_192000_f
+ };
+/*-------------------------------------------------------------------------*/
+/* FUNCTION: */
+/* LVM_GetOmega */
+/* */
+/* LVM_INT32 LVM_GetOmega(LVM_UINT16 Fc, */
+/* LVM_Fs_en Fs) */
+/* */
+/* DESCRIPTION: */
+/* This function calculates the value of w using Fc and Fs */
+/* */
+/* PARAMETERS: */
+/* */
+/* LVM_UINT16 Fc The corner frequency in Hz Q16.0 format */
+/* LVM_Fs_en Fs The SampleRate */
+/* RETURNS: */
+/* w=2*pi*Fc/Fs in Q2.29 format */
+/*-------------------------------------------------------------------------*/
+LVM_FLOAT LVM_GetOmega(LVM_UINT32 Fc,
+ LVM_Fs_en Fs)
+{
+ LVM_FLOAT w;
+ w = (LVM_FLOAT)Fc * LVVDL_2PiOnFsTable[Fs];
+ return w;
+}
diff --git a/media/libeffects/lvm/lib/Common/src/LVM_Mixer_FilterCoeffs.h b/media/libeffects/lvm/lib/Common/src/LVM_Mixer_FilterCoeffs.h
index f1e45fa..244f09d 100644
--- a/media/libeffects/lvm/lib/Common/src/LVM_Mixer_FilterCoeffs.h
+++ b/media/libeffects/lvm/lib/Common/src/LVM_Mixer_FilterCoeffs.h
@@ -27,7 +27,6 @@
#ifndef __LVM_MIXER_FILTER_COEFFS_H__
#define __LVM_MIXER_FILTER_COEFFS_H__
-
/************************************************************************************/
/* */
/* Alpha Time Constant table */
@@ -87,7 +86,6 @@
#define ALPHA_49 0 /* Floating point Alpha = 0.000000 */
#define ALPHA_50 0 /* Floating point Alpha = 0.000000 */
-#ifdef BUILD_FLOAT /* BUILD_FLOAT */
#define ALPHA_Float_0 0.999999f
#define ALPHA_Float_1 0.999998f
#define ALPHA_Float_2 0.999997f
@@ -139,6 +137,5 @@
#define ALPHA_Float_48 0.000000f
#define ALPHA_Float_49 0.000000f
#define ALPHA_Float_50 0.000000f
-#endif
#endif
diff --git a/media/libeffects/lvm/lib/Common/src/LVM_Mixer_TimeConstant.c b/media/libeffects/lvm/lib/Common/src/LVM_Mixer_TimeConstant.c
deleted file mode 100644
index 18b2782..0000000
--- a/media/libeffects/lvm/lib/Common/src/LVM_Mixer_TimeConstant.c
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "LVM_Types.h"
-#include "LVM_Macros.h"
-#include "Mixer.h"
-#include "LVM_Mixer_FilterCoeffs.h"
-
-
-/************************************************************************/
-/* FUNCTION: */
-/* LVM_Mix_GetTimeConstant */
-/* */
-/* DESCRIPTION: */
-/* This function calculates the filter coefficient using the following */
-/* equation: */
-/* Alpha = exp(ln(0.1)/ (tc * Update + 1.0)) */
-/* */
-/* This is to be used with the follow first order filter, called at a */
-/* rate of Update times a second. tc is the required time constant in */
-/* units of 100us. */
-/* */
-/* Output(n) = Alpha * Output(n-1) + (1 - Alpha) * Target(n) */
-/* */
-/* The function assumes the block size is large, i.e. the update rate */
-/* is approximately a fixed, and correct factor of the value of Fs */
-/* given in the call. This is especially not true when the block size */
-/* is very small, see the mixer documentation for further details. */
-/* */
-/* The function does not support all possible combinations of input */
-/* values: */
-/* */
-/* 1. NumChannels is limited to the values 1 (Mono) and 2 (Stereo) */
-/* 2. The product tc * Fs is limited approximately to the range */
-/* 8 < (tc * Fs) < 2^35 */
-/* */
-/* PARAMETERS: */
-/* tc - the time constant in 100us steps, i.e. 10 = 1ms */
-/* Fs - the filter update rate in Hz */
-/* NumChannels - Number of channels 1=Mono, 2=Stereo */
-/* */
-/* RETURNS: */
-/* Alpha - the filter coefficient Q31 format */
-/* */
-/************************************************************************/
-#ifdef BUILD_FLOAT
-LVM_FLOAT LVM_Mixer_TimeConstant(LVM_UINT32 tc,
-#ifdef HIGHER_FS
- LVM_UINT32 Fs,
-#else
- LVM_UINT16 Fs,
-#endif
- LVM_UINT16 NumChannels)
-{
-
- LVM_UINT32 Product;
- LVM_FLOAT ProductFloat;
- LVM_INT16 InterpolateShort;
- LVM_FLOAT Interpolate;
- LVM_UINT16 Shift;
- LVM_FLOAT Diff;
- LVM_FLOAT Table[] = {ALPHA_Float_0, /* Log spaced look-up table */
- ALPHA_Float_1,
- ALPHA_Float_2,
- ALPHA_Float_3,
- ALPHA_Float_4,
- ALPHA_Float_5,
- ALPHA_Float_6,
- ALPHA_Float_7,
- ALPHA_Float_8,
- ALPHA_Float_9,
- ALPHA_Float_10,
- ALPHA_Float_11,
- ALPHA_Float_12,
- ALPHA_Float_13,
- ALPHA_Float_14,
- ALPHA_Float_15,
- ALPHA_Float_16,
- ALPHA_Float_17,
- ALPHA_Float_18,
- ALPHA_Float_19,
- ALPHA_Float_20,
- ALPHA_Float_21,
- ALPHA_Float_22,
- ALPHA_Float_23,
- ALPHA_Float_24,
- ALPHA_Float_25,
- ALPHA_Float_26,
- ALPHA_Float_27,
- ALPHA_Float_28,
- ALPHA_Float_29,
- ALPHA_Float_30,
- ALPHA_Float_31,
- ALPHA_Float_32,
- ALPHA_Float_33,
- ALPHA_Float_34,
- ALPHA_Float_35,
- ALPHA_Float_36,
- ALPHA_Float_37,
- ALPHA_Float_38,
- ALPHA_Float_39,
- ALPHA_Float_40,
- ALPHA_Float_41,
- ALPHA_Float_42,
- ALPHA_Float_43,
- ALPHA_Float_44,
- ALPHA_Float_45,
- ALPHA_Float_46,
- ALPHA_Float_47,
- ALPHA_Float_48,
- ALPHA_Float_49,
- ALPHA_Float_50};
-
- /* Calculate the product of the time constant and the sample rate */
- Product = ((tc >> 16) * (LVM_UINT32)Fs) << 13; /* Stereo value */
- Product = Product + (((tc & 0x0000FFFF) * (LVM_UINT32)Fs) >> 3);
-
- if (NumChannels == 1)
- {
- Product = Product >> 1; /* Mono value */
- }
-
- /* Normalize to get the table index and interpolation factor */
- for (Shift = 0; Shift < ((Alpha_TableSize - 1) / 2); Shift++)
- {
- if ((Product & 0x80000000) != 0)
- {
- break;
- }
-
- Product = Product << 1;
- }
- Shift = (LVM_UINT16)((Shift << 1));
-
- if ((Product & 0x40000000)==0)
- {
- Shift++;
- }
-
- InterpolateShort = (LVM_INT16)((Product >> 15) & 0x00007FFF);
- Interpolate = (LVM_FLOAT)InterpolateShort / 32768.0f;
-
- Diff = (Table[Shift] - Table[Shift + 1]);
- Diff = Diff * Interpolate;
- ProductFloat = Table[Shift + 1] + Diff;
-
- return ProductFloat;
-}
-#else
-LVM_UINT32 LVM_Mixer_TimeConstant(LVM_UINT32 tc,
- LVM_UINT16 Fs,
- LVM_UINT16 NumChannels)
-{
-
- LVM_UINT32 Product;
- LVM_INT16 Interpolate;
- LVM_UINT16 Shift;
- LVM_INT32 Diff;
- LVM_UINT32 Table[] = {ALPHA_0, /* Log spaced look-up table */
- ALPHA_1,
- ALPHA_2,
- ALPHA_3,
- ALPHA_4,
- ALPHA_5,
- ALPHA_6,
- ALPHA_7,
- ALPHA_8,
- ALPHA_9,
- ALPHA_10,
- ALPHA_11,
- ALPHA_12,
- ALPHA_13,
- ALPHA_14,
- ALPHA_15,
- ALPHA_16,
- ALPHA_17,
- ALPHA_18,
- ALPHA_19,
- ALPHA_20,
- ALPHA_21,
- ALPHA_22,
- ALPHA_23,
- ALPHA_24,
- ALPHA_25,
- ALPHA_26,
- ALPHA_27,
- ALPHA_28,
- ALPHA_29,
- ALPHA_30,
- ALPHA_31,
- ALPHA_32,
- ALPHA_33,
- ALPHA_34,
- ALPHA_35,
- ALPHA_36,
- ALPHA_37,
- ALPHA_38,
- ALPHA_39,
- ALPHA_40,
- ALPHA_41,
- ALPHA_42,
- ALPHA_43,
- ALPHA_44,
- ALPHA_45,
- ALPHA_46,
- ALPHA_47,
- ALPHA_48,
- ALPHA_49,
- ALPHA_50};
-
-
- /* Calculate the product of the time constant and the sample rate */
- Product = ((tc >> 16) * (LVM_UINT32)Fs) << 13; /* Stereo value */
- Product = Product + (((tc & 0x0000FFFF) * (LVM_UINT32)Fs) >> 3);
-
- if (NumChannels == 1)
- {
- Product = Product >> 1; /* Mono value */
- }
-
- /* Normalize to get the table index and interpolation factor */
- for (Shift=0; Shift<((Alpha_TableSize-1)/2); Shift++)
- {
- if ((Product & 0x80000000)!=0)
- {
- break;
- }
-
- Product = Product << 1;
- }
- Shift = (LVM_UINT16)((Shift << 1));
-
- if ((Product & 0x40000000)==0)
- {
- Shift++;
- }
-
- Interpolate = (LVM_INT16)((Product >> 15) & 0x00007FFF);
-
- Diff = (LVM_INT32)(Table[Shift] - Table[Shift+1]);
- MUL32x16INTO32(Diff,Interpolate,Diff,15)
- Product = Table[Shift+1] + (LVM_UINT32)Diff;
-
- return Product;
-}
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/LVM_Mixer_TimeConstant.cpp b/media/libeffects/lvm/lib/Common/src/LVM_Mixer_TimeConstant.cpp
new file mode 100644
index 0000000..73da2cf
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/LVM_Mixer_TimeConstant.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LVM_Types.h"
+#include "LVM_Macros.h"
+#include "Mixer.h"
+#include "LVM_Mixer_FilterCoeffs.h"
+
+/************************************************************************/
+/* FUNCTION: */
+/* LVM_Mix_GetTimeConstant */
+/* */
+/* DESCRIPTION: */
+/* This function calculates the filter coefficient using the following */
+/* equation: */
+/* Alpha = exp(ln(0.1)/ (tc * Update + 1.0)) */
+/* */
+/* This is to be used with the follow first order filter, called at a */
+/* rate of Update times a second. tc is the required time constant in */
+/* units of 100us. */
+/* */
+/* Output(n) = Alpha * Output(n-1) + (1 - Alpha) * Target(n) */
+/* */
+/* The function assumes the block size is large, i.e. the update rate */
+/* is approximately a fixed, and correct factor of the value of Fs */
+/* given in the call. This is especially not true when the block size */
+/* is very small, see the mixer documentation for further details. */
+/* */
+/* The function does not support all possible combinations of input */
+/* values: */
+/* */
+/* 1. NumChannels is limited to the values 1 (Mono) and 2 (Stereo) */
+/* 2. The product tc * Fs is limited approximately to the range */
+/* 8 < (tc * Fs) < 2^35 */
+/* */
+/* PARAMETERS: */
+/* tc - the time constant in 100us steps, i.e. 10 = 1ms */
+/* Fs - the filter update rate in Hz */
+/* NumChannels - Number of channels 1=Mono, 2=Stereo */
+/* */
+/* RETURNS: */
+/* Alpha - the filter coefficient Q31 format */
+/* */
+/************************************************************************/
+LVM_FLOAT LVM_Mixer_TimeConstant(LVM_UINT32 tc,
+ LVM_UINT32 Fs,
+ LVM_UINT16 NumChannels)
+{
+
+ LVM_UINT32 Product;
+ LVM_FLOAT ProductFloat;
+ LVM_INT16 InterpolateShort;
+ LVM_FLOAT Interpolate;
+ LVM_UINT16 Shift;
+ LVM_FLOAT Diff;
+ LVM_FLOAT Table[] = {ALPHA_Float_0, /* Log spaced look-up table */
+ ALPHA_Float_1,
+ ALPHA_Float_2,
+ ALPHA_Float_3,
+ ALPHA_Float_4,
+ ALPHA_Float_5,
+ ALPHA_Float_6,
+ ALPHA_Float_7,
+ ALPHA_Float_8,
+ ALPHA_Float_9,
+ ALPHA_Float_10,
+ ALPHA_Float_11,
+ ALPHA_Float_12,
+ ALPHA_Float_13,
+ ALPHA_Float_14,
+ ALPHA_Float_15,
+ ALPHA_Float_16,
+ ALPHA_Float_17,
+ ALPHA_Float_18,
+ ALPHA_Float_19,
+ ALPHA_Float_20,
+ ALPHA_Float_21,
+ ALPHA_Float_22,
+ ALPHA_Float_23,
+ ALPHA_Float_24,
+ ALPHA_Float_25,
+ ALPHA_Float_26,
+ ALPHA_Float_27,
+ ALPHA_Float_28,
+ ALPHA_Float_29,
+ ALPHA_Float_30,
+ ALPHA_Float_31,
+ ALPHA_Float_32,
+ ALPHA_Float_33,
+ ALPHA_Float_34,
+ ALPHA_Float_35,
+ ALPHA_Float_36,
+ ALPHA_Float_37,
+ ALPHA_Float_38,
+ ALPHA_Float_39,
+ ALPHA_Float_40,
+ ALPHA_Float_41,
+ ALPHA_Float_42,
+ ALPHA_Float_43,
+ ALPHA_Float_44,
+ ALPHA_Float_45,
+ ALPHA_Float_46,
+ ALPHA_Float_47,
+ ALPHA_Float_48,
+ ALPHA_Float_49,
+ ALPHA_Float_50};
+
+ /* Calculate the product of the time constant and the sample rate */
+ Product = ((tc >> 16) * (LVM_UINT32)Fs) << 13; /* Stereo value */
+ Product = Product + (((tc & 0x0000FFFF) * (LVM_UINT32)Fs) >> 3);
+
+ if (NumChannels == 1)
+ {
+ Product = Product >> 1; /* Mono value */
+ }
+
+ /* Normalize to get the table index and interpolation factor */
+ for (Shift = 0; Shift < ((Alpha_TableSize - 1) / 2); Shift++)
+ {
+ if ((Product & 0x80000000) != 0)
+ {
+ break;
+ }
+
+ Product = Product << 1;
+ }
+ Shift = (LVM_UINT16)((Shift << 1));
+
+ if ((Product & 0x40000000)==0)
+ {
+ Shift++;
+ }
+
+ InterpolateShort = (LVM_INT16)((Product >> 15) & 0x00007FFF);
+ Interpolate = (LVM_FLOAT)InterpolateShort / 32768.0f;
+
+ Diff = (Table[Shift] - Table[Shift + 1]);
+ Diff = Diff * Interpolate;
+ ProductFloat = Table[Shift + 1] + Diff;
+
+ return ProductFloat;
+}
diff --git a/media/libeffects/lvm/lib/Common/src/LVM_Polynomial.c b/media/libeffects/lvm/lib/Common/src/LVM_Polynomial.c
deleted file mode 100644
index cd57767..0000000
--- a/media/libeffects/lvm/lib/Common/src/LVM_Polynomial.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "LVM_Types.h"
-#include "LVM_Macros.h"
-#include "ScalarArithmetic.h"
-
-/*-------------------------------------------------------------------------*/
-/* FUNCTION: */
-/* LVM_Polynomial */
-/* */
-/* DESCRIPTION: */
-/* This function performs polynomial expansion */
-/* Y = (A0 + A1*X + A2*X2 + A3*X3 + �.. + AN*xN) << AN+1 */
-/* */
-/* LVM_INT32 LVM_Polynomial(LVM_UINT16 N, */
-/* LVM_INT32 *pCoefficients, */
-/* LVM_INT32 X) */
-/* */
-/* PARAMETERS: */
-/* */
-/* N is the polynomial order */
-/* pCoefficients is the ptr to polynomial coefficients A0,A1.. in Q.31 */
-/* X is the input variable */
-/* */
-/* RETURNS: */
-/* The result of the polynomial expansion in Q1.31 format */
-/*-------------------------------------------------------------------------*/
-#ifdef BUILD_FLOAT
-LVM_FLOAT LVM_Polynomial(LVM_UINT16 N,
- LVM_FLOAT *pCoefficients,
- LVM_FLOAT X)
-{
- LVM_INT32 i;
- LVM_FLOAT Y,A,XTemp,Temp,sign;
-
- Y = *pCoefficients; /* Y=A0*/
- pCoefficients++;
-
- if(X == -1.0f)
- {
- Temp = -1;
- sign = Temp;
- for(i = 1; i <= N; i++)
- {
- Y += ((*pCoefficients) * sign);
- pCoefficients++;
- sign *= Temp;
- }
-
-
- }
- else
- {
- XTemp = X;
- for(i = N-1; i >= 0; i--)
- {
- A = *pCoefficients;
- pCoefficients++;
-
- Temp = A * XTemp;
- Y += Temp;
-
- Temp = XTemp * X;
- XTemp = Temp;
- }
- }
- return Y;
-}
-#else
-LVM_INT32 LVM_Polynomial(LVM_UINT16 N,
- LVM_INT32 *pCoefficients,
- LVM_INT32 X)
-{
- LVM_INT32 i;
- LVM_INT32 Y,A,XTemp,Temp,sign;
-
- Y=*pCoefficients; /* Y=A0*/
- pCoefficients++;
-
- if((LVM_UINT32)X==0x80000000)
- {
- Temp=-1;
- sign=Temp;
- for(i=1;i<=N;i++)
- {
- Y+=((*pCoefficients)*sign);
- pCoefficients++;
- sign*=Temp;
- }
-
-
- }
- else
- {
- XTemp=X;
- for(i=N-1;i>=0;i--)
- {
- A=*pCoefficients;
- pCoefficients++;
-
- MUL32x32INTO32(A,XTemp,Temp,31)
- Y+=Temp;
-
- MUL32x32INTO32(XTemp,X,Temp,31)
- XTemp=Temp;
- }
- }
- A=*pCoefficients;
- pCoefficients++;
-
- if(A<0)
- {
- A=Abs_32(A);
- Y=Y>>A;
- }
- else
- {
- Y = Y<<A;
- }
- return Y;
-}
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/LVM_Polynomial.cpp b/media/libeffects/lvm/lib/Common/src/LVM_Polynomial.cpp
new file mode 100644
index 0000000..2c3e9ec
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/LVM_Polynomial.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LVM_Types.h"
+#include "LVM_Macros.h"
+#include "ScalarArithmetic.h"
+
+/*-------------------------------------------------------------------------*/
+/* FUNCTION: */
+/* LVM_Polynomial */
+/* */
+/* DESCRIPTION: */
+/* This function performs polynomial expansion */
+/* Y = (A0 + A1*X + A2*X2 + A3*X3 + �.. + AN*xN) << AN+1 */
+/* */
+/* LVM_INT32 LVM_Polynomial(LVM_UINT16 N, */
+/* LVM_INT32 *pCoefficients, */
+/* LVM_INT32 X) */
+/* */
+/* PARAMETERS: */
+/* */
+/* N is the polynomial order */
+/* pCoefficients is the ptr to polynomial coefficients A0,A1.. in Q.31 */
+/* X is the input variable */
+/* */
+/* RETURNS: */
+/* The result of the polynomial expansion in Q1.31 format */
+/*-------------------------------------------------------------------------*/
+LVM_FLOAT LVM_Polynomial(LVM_UINT16 N,
+ LVM_FLOAT *pCoefficients,
+ LVM_FLOAT X)
+{
+ LVM_INT32 i;
+ LVM_FLOAT Y,A,XTemp,Temp,sign;
+
+ Y = *pCoefficients; /* Y=A0*/
+ pCoefficients++;
+
+ if(X == -1.0f)
+ {
+ Temp = -1;
+ sign = Temp;
+ for(i = 1; i <= N; i++)
+ {
+ Y += ((*pCoefficients) * sign);
+ pCoefficients++;
+ sign *= Temp;
+ }
+
+ }
+ else
+ {
+ XTemp = X;
+ for(i = N-1; i >= 0; i--)
+ {
+ A = *pCoefficients;
+ pCoefficients++;
+
+ Temp = A * XTemp;
+ Y += Temp;
+
+ Temp = XTemp * X;
+ XTemp = Temp;
+ }
+ }
+ return Y;
+}
diff --git a/media/libeffects/lvm/lib/Common/src/LVM_Power10.c b/media/libeffects/lvm/lib/Common/src/LVM_Power10.c
deleted file mode 100644
index 8785594..0000000
--- a/media/libeffects/lvm/lib/Common/src/LVM_Power10.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "LVM_Types.h"
-#include "LVM_Macros.h"
-#include "ScalarArithmetic.h"
-#include "Filter.h"
-
-
-/*-------------------------------------------------------------------------*/
-/* FUNCTION: */
-/* LVM_Power10 */
-/* */
-/* DESCRIPTION: */
-/* This function calculates 10X using an 11th order polynomial. It uses */
-/* the following table of 32-bit integer polynomial coefficients: */
-/* */
-/* Coefficient Value */
-/* A0 67102543 */
-/* A1 309032995 */
-/* A2 712096127 */
-/* A3 1092797331 */
-/* A4 1251625137 */
-/* A5 1154649460 */
-/* A6 915654800 */
-/* A7 597883683 */
-/* A8 284378230 */
-/* A9 150262097 */
-/* A10 124894471 */
-/* A11 50477244 */
-/* A12 -2 */
-/* */
-/* Y = (A0 + A1*X + A2*X2 + A3*X3 + �.. + AN*xN) << AN+1 */
-/* */
-/* */
-/* PARAMETERS: */
-/* */
-/* X is the input variable in Q2.30 format */
-/* */
-/* RETURNS: */
-/* The result of the 10x expansion in Q8.24 format */
-/*-------------------------------------------------------------------------*/
-#ifdef BUILD_FLOAT
-LVM_FLOAT LVM_Power10(LVM_FLOAT X)
-{
- LVM_FLOAT Y,Coefficients[13]={0.999906f,
- 2.302475f,
- 2.652765f,
- 2.035494f,
- 1.165667f,
- 0.537676f,
- 0.213192f,
- 0.069603f,
- 0.016553f,
- 0.004373f,
- 0.001817f,
- 0.000367f,
- 0};
- Y=LVM_Polynomial((LVM_UINT16)11,
- Coefficients,
- X);
- return Y;
-}
-#else
-LVM_INT32 LVM_Power10(LVM_INT32 X)
-{
- LVM_INT32 Y,Coefficients[13]={ 16775636,
- 77258249,
- 178024032,
- 273199333,
- 312906284,
- 288662365,
- 228913700,
- 149470921,
- 71094558,
- 37565524,
- 31223618,
- 12619311,
- 0};
- Y=LVM_Polynomial((LVM_UINT16)11,
- Coefficients,
- X);
- return Y;
-}
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/LVM_Power10.cpp b/media/libeffects/lvm/lib/Common/src/LVM_Power10.cpp
new file mode 100644
index 0000000..ae8e9d1
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/LVM_Power10.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LVM_Types.h"
+#include "LVM_Macros.h"
+#include "ScalarArithmetic.h"
+#include "Filter.h"
+
+/*-------------------------------------------------------------------------*/
+/* FUNCTION: */
+/* LVM_Power10 */
+/* */
+/* DESCRIPTION: */
+/* This function calculates 10X using an 11th order polynomial. It uses */
+/* the following table of 32-bit integer polynomial coefficients: */
+/* */
+/* Coefficient Value */
+/* A0 67102543 */
+/* A1 309032995 */
+/* A2 712096127 */
+/* A3 1092797331 */
+/* A4 1251625137 */
+/* A5 1154649460 */
+/* A6 915654800 */
+/* A7 597883683 */
+/* A8 284378230 */
+/* A9 150262097 */
+/* A10 124894471 */
+/* A11 50477244 */
+/* A12 -2 */
+/* */
+/* Y = (A0 + A1*X + A2*X2 + A3*X3 + �.. + AN*xN) << AN+1 */
+/* */
+/* */
+/* PARAMETERS: */
+/* */
+/* X is the input variable in Q2.30 format */
+/* */
+/* RETURNS: */
+/* The result of the 10x expansion in Q8.24 format */
+/*-------------------------------------------------------------------------*/
+LVM_FLOAT LVM_Power10(LVM_FLOAT X)
+{
+ LVM_FLOAT Y,Coefficients[13]={0.999906f,
+ 2.302475f,
+ 2.652765f,
+ 2.035494f,
+ 1.165667f,
+ 0.537676f,
+ 0.213192f,
+ 0.069603f,
+ 0.016553f,
+ 0.004373f,
+ 0.001817f,
+ 0.000367f,
+ 0};
+ Y=LVM_Polynomial((LVM_UINT16)11,
+ Coefficients,
+ X);
+ return Y;
+}
diff --git a/media/libeffects/lvm/lib/Common/src/LVM_Timer.c b/media/libeffects/lvm/lib/Common/src/LVM_Timer.cpp
similarity index 100%
rename from media/libeffects/lvm/lib/Common/src/LVM_Timer.c
rename to media/libeffects/lvm/lib/Common/src/LVM_Timer.cpp
diff --git a/media/libeffects/lvm/lib/Common/src/LVM_Timer_Init.c b/media/libeffects/lvm/lib/Common/src/LVM_Timer_Init.c
deleted file mode 100644
index a935cfe..0000000
--- a/media/libeffects/lvm/lib/Common/src/LVM_Timer_Init.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/****************************************************************************************/
-/* INCLUDE FILES */
-/****************************************************************************************/
-
-#include "LVM_Timer.h"
-#include "LVM_Timer_Private.h"
-#include "LVM_Macros.h"
-
-/****************************************************************************************/
-/* DEFINITIONS */
-/****************************************************************************************/
-
-#define OneOverThousandInQ24 16777
-
-/****************************************************************************************/
-/* INIT FUNCTION */
-/****************************************************************************************/
-
-void LVM_Timer_Init ( LVM_Timer_Instance_t *pInstance,
- LVM_Timer_Params_t *pParams ){
-
- LVM_Timer_Instance_Private_t *pInstancePr;
- pInstancePr = (LVM_Timer_Instance_Private_t *)pInstance;
-
- pInstancePr->CallBackParam = pParams->CallBackParam;
- pInstancePr->pCallBackParams = pParams->pCallBackParams;
- pInstancePr->pCallbackInstance = pParams->pCallbackInstance;
- pInstancePr->pCallBack = pParams->pCallBack;
- pInstancePr->TimerArmed = 1;
-
- MUL32x16INTO32(pParams->SamplingRate,OneOverThousandInQ24,pInstancePr->RemainingTimeInSamples,16); /* (Q0 * Q24) >>16 into Q8*/
- MUL32x16INTO32(pInstancePr->RemainingTimeInSamples,pParams->TimeInMs,pInstancePr->RemainingTimeInSamples,8); /* (Q8 * Q0) >>8 into Q0*/
-}
-
-/****************************************************************************************/
-/* END OF FILE */
-/****************************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVM_Timer_Init.cpp b/media/libeffects/lvm/lib/Common/src/LVM_Timer_Init.cpp
new file mode 100644
index 0000000..3015057
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/LVM_Timer_Init.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/****************************************************************************************/
+/* INCLUDE FILES */
+/****************************************************************************************/
+
+#include "LVM_Timer.h"
+#include "LVM_Timer_Private.h"
+#include "LVM_Macros.h"
+
+/****************************************************************************************/
+/* DEFINITIONS */
+/****************************************************************************************/
+
+#define OneOverThousandInQ24 16777
+
+/****************************************************************************************/
+/* INIT FUNCTION */
+/****************************************************************************************/
+
+void LVM_Timer_Init ( LVM_Timer_Instance_t *pInstance,
+ LVM_Timer_Params_t *pParams ){
+
+ LVM_Timer_Instance_Private_t *pInstancePr;
+ pInstancePr = (LVM_Timer_Instance_Private_t *)pInstance;
+
+ pInstancePr->CallBackParam = pParams->CallBackParam;
+ pInstancePr->pCallBackParams = (LVM_INT32 *)pParams->pCallBackParams;
+ pInstancePr->pCallbackInstance = pParams->pCallbackInstance;
+ pInstancePr->pCallBack = pParams->pCallBack;
+ pInstancePr->TimerArmed = 1;
+
+ MUL32x16INTO32(pParams->SamplingRate,OneOverThousandInQ24,pInstancePr->RemainingTimeInSamples,16); /* (Q0 * Q24) >>16 into Q8*/
+ MUL32x16INTO32(pInstancePr->RemainingTimeInSamples,pParams->TimeInMs,pInstancePr->RemainingTimeInSamples,8); /* (Q8 * Q0) >>8 into Q0*/
+}
+
+/****************************************************************************************/
+/* END OF FILE */
+/****************************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVM_Timer_Private.h b/media/libeffects/lvm/lib/Common/src/LVM_Timer_Private.h
index 480944f..a372b82 100644
--- a/media/libeffects/lvm/lib/Common/src/LVM_Timer_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/LVM_Timer_Private.h
@@ -18,12 +18,6 @@
#ifndef LVM_TIMER_PRIVATE_H
#define LVM_TIMER_PRIVATE_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-
#include "LVM_Types.h"
/****************************************************************************************/
@@ -45,8 +39,4 @@
/* END OF HEADER */
/****************************************************************************************/
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
#endif /* LVM_TIMER_PRIVATE_H */
diff --git a/media/libeffects/lvm/lib/Common/src/LoadConst_16.c b/media/libeffects/lvm/lib/Common/src/LoadConst_16.cpp
similarity index 100%
rename from media/libeffects/lvm/lib/Common/src/LoadConst_16.c
rename to media/libeffects/lvm/lib/Common/src/LoadConst_16.cpp
diff --git a/media/libeffects/lvm/lib/Common/src/LoadConst_32.c b/media/libeffects/lvm/lib/Common/src/LoadConst_32.c
deleted file mode 100644
index 9e14c3b..0000000
--- a/media/libeffects/lvm/lib/Common/src/LoadConst_32.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**********************************************************************************
- INCLUDE FILES
-***********************************************************************************/
-
-#include "VectorArithmetic.h"
-
-/**********************************************************************************
- FUNCTION LoadConst_32
-***********************************************************************************/
-#ifdef BUILD_FLOAT
-void LoadConst_Float(const LVM_FLOAT val,
- LVM_FLOAT *dst,
- LVM_INT16 n )
-{
- LVM_INT16 ii;
-
- for (ii = n; ii != 0; ii--)
- {
- *dst = val;
- dst++;
- }
-
- return;
-}
-#else
-void LoadConst_32(const LVM_INT32 val,
- LVM_INT32 *dst,
- LVM_INT16 n )
-{
- LVM_INT16 ii;
-
- for (ii = n; ii != 0; ii--)
- {
- *dst = val;
- dst++;
- }
-
- return;
-}
-#endif
-
-/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LoadConst_32.cpp b/media/libeffects/lvm/lib/Common/src/LoadConst_32.cpp
new file mode 100644
index 0000000..c789756
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/LoadConst_32.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**********************************************************************************
+ INCLUDE FILES
+***********************************************************************************/
+
+#include "VectorArithmetic.h"
+
+/**********************************************************************************
+ FUNCTION LoadConst_32
+***********************************************************************************/
+void LoadConst_Float(const LVM_FLOAT val,
+ LVM_FLOAT *dst,
+ LVM_INT16 n )
+{
+ LVM_INT16 ii;
+
+ for (ii = n; ii != 0; ii--)
+ {
+ *dst = val;
+ dst++;
+ }
+
+ return;
+}
+
+/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/MSTo2i_Sat_16x16.c b/media/libeffects/lvm/lib/Common/src/MSTo2i_Sat_16x16.c
deleted file mode 100644
index 02c906a..0000000
--- a/media/libeffects/lvm/lib/Common/src/MSTo2i_Sat_16x16.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**********************************************************************************
- INCLUDE FILES
-***********************************************************************************/
-
-#include "VectorArithmetic.h"
-
-/**********************************************************************************
- FUNCTION MSTO2I_SAT_16X16
-***********************************************************************************/
-
-void MSTo2i_Sat_16x16(const LVM_INT16 *srcM,
- const LVM_INT16 *srcS,
- LVM_INT16 *dst,
- LVM_INT16 n )
-{
- LVM_INT32 temp,mVal,sVal;
- LVM_INT16 ii;
-
-
- for (ii = n; ii != 0; ii--)
- {
- mVal=(LVM_INT32)*srcM;
- srcM++;
-
- sVal=(LVM_INT32)*srcS;
- srcS++;
-
- temp = mVal + sVal;
-
- if (temp > 0x00007FFF)
- {
- *dst = 0x7FFF;
- }
- else if (temp < -0x00008000)
- {
- *dst = - 0x8000;
- }
- else
- {
- *dst = (LVM_INT16)temp;
- }
- dst++;
-
- temp = mVal - sVal;
-
- if (temp > 0x00007FFF)
- {
- *dst = 0x7FFF;
- }
- else if (temp < -0x00008000)
- {
- *dst = - 0x8000;
- }
- else
- {
- *dst = (LVM_INT16)temp;
- }
- dst++;
- }
-
- return;
-}
-#ifdef BUILD_FLOAT
-void MSTo2i_Sat_Float(const LVM_FLOAT *srcM,
- const LVM_FLOAT *srcS,
- LVM_FLOAT *dst,
- LVM_INT16 n )
-{
- LVM_FLOAT temp,mVal,sVal;
- LVM_INT16 ii;
-
-
- for (ii = n; ii != 0; ii--)
- {
- mVal = (LVM_FLOAT)*srcM;
- srcM++;
-
- sVal = (LVM_FLOAT)*srcS;
- srcS++;
-
- temp = mVal + sVal;
-
- if (temp > 1.0f)
- {
- *dst = 1.0f;
- }
- else if (temp < -1.0f)
- {
- *dst = -1.0f;
- }
- else
- {
- *dst = (LVM_FLOAT)temp;
- }
- dst++;
-
- temp = mVal - sVal;
-
- if (temp > 1.0f)
- {
- *dst = 1.0f;
- }
- else if (temp < -1.0f)
- {
- *dst = - 1.0f;
- }
- else
- {
- *dst = (LVM_FLOAT)temp;
- }
- dst++;
- }
-
- return;
-}
-#endif
-/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/MSTo2i_Sat_16x16.cpp b/media/libeffects/lvm/lib/Common/src/MSTo2i_Sat_16x16.cpp
new file mode 100644
index 0000000..1ea765a
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/MSTo2i_Sat_16x16.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**********************************************************************************
+ INCLUDE FILES
+***********************************************************************************/
+
+#include "VectorArithmetic.h"
+
+/**********************************************************************************
+ FUNCTION MSTO2I_SAT_16X16
+***********************************************************************************/
+
+void MSTo2i_Sat_16x16(const LVM_INT16 *srcM,
+ const LVM_INT16 *srcS,
+ LVM_INT16 *dst,
+ LVM_INT16 n )
+{
+ LVM_INT32 temp,mVal,sVal;
+ LVM_INT16 ii;
+
+ for (ii = n; ii != 0; ii--)
+ {
+ mVal=(LVM_INT32)*srcM;
+ srcM++;
+
+ sVal=(LVM_INT32)*srcS;
+ srcS++;
+
+ temp = mVal + sVal;
+
+ if (temp > 0x00007FFF)
+ {
+ *dst = 0x7FFF;
+ }
+ else if (temp < -0x00008000)
+ {
+ *dst = - 0x8000;
+ }
+ else
+ {
+ *dst = (LVM_INT16)temp;
+ }
+ dst++;
+
+ temp = mVal - sVal;
+
+ if (temp > 0x00007FFF)
+ {
+ *dst = 0x7FFF;
+ }
+ else if (temp < -0x00008000)
+ {
+ *dst = - 0x8000;
+ }
+ else
+ {
+ *dst = (LVM_INT16)temp;
+ }
+ dst++;
+ }
+
+ return;
+}
+void MSTo2i_Sat_Float(const LVM_FLOAT *srcM,
+ const LVM_FLOAT *srcS,
+ LVM_FLOAT *dst,
+ LVM_INT16 n )
+{
+ LVM_FLOAT temp,mVal,sVal;
+ LVM_INT16 ii;
+
+ for (ii = n; ii != 0; ii--)
+ {
+ mVal = (LVM_FLOAT)*srcM;
+ srcM++;
+
+ sVal = (LVM_FLOAT)*srcS;
+ srcS++;
+
+ temp = mVal + sVal;
+
+ if (temp > 1.0f)
+ {
+ *dst = 1.0f;
+ }
+ else if (temp < -1.0f)
+ {
+ *dst = -1.0f;
+ }
+ else
+ {
+ *dst = (LVM_FLOAT)temp;
+ }
+ dst++;
+
+ temp = mVal - sVal;
+
+ if (temp > 1.0f)
+ {
+ *dst = 1.0f;
+ }
+ else if (temp < -1.0f)
+ {
+ *dst = - 1.0f;
+ }
+ else
+ {
+ *dst = (LVM_FLOAT)temp;
+ }
+ dst++;
+ }
+
+ return;
+}
+/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/Mac3s_Sat_16x16.c b/media/libeffects/lvm/lib/Common/src/Mac3s_Sat_16x16.c
deleted file mode 100644
index ef04ae8..0000000
--- a/media/libeffects/lvm/lib/Common/src/Mac3s_Sat_16x16.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**********************************************************************************
-
- %created_by: sra % (CM/S)
- %name: Mac3s_Sat_16x16.c % (CM/S)
- %version: 1 % (CM/S)
- %date_created: Fri Nov 13 12:07:13 2009 % (CM/S)
-
-***********************************************************************************/
-
-/**********************************************************************************
- INCLUDE FILES
-***********************************************************************************/
-
-#include "VectorArithmetic.h"
-#include "LVM_Macros.h"
-
-/**********************************************************************************
- FUNCTION Mac3S_16X16
-***********************************************************************************/
-
-void Mac3s_Sat_16x16( const LVM_INT16 *src,
- const LVM_INT16 val,
- LVM_INT16 *dst,
- LVM_INT16 n)
-{
- LVM_INT16 ii;
- LVM_INT16 srcval;
- LVM_INT32 Temp,dInVal;
-
-
- for (ii = n; ii != 0; ii--)
- {
- srcval=*src;
- src++;
-
- Temp = (srcval *val)>>15;
-
- dInVal = (LVM_INT32)*dst;
-
- Temp = Temp + dInVal;
-
- if (Temp > 0x00007FFF)
- {
- *dst = 0x7FFF;
- }
- else if (Temp < -0x00008000)
- {
- *dst = - 0x8000;
- }
- else
- {
- *dst = (LVM_INT16)Temp;
- }
-
- dst++;
- }
-
- return;
-}
-
-/**********************************************************************************/
-
-
-
diff --git a/media/libeffects/lvm/lib/Common/src/Mac3s_Sat_16x16.cpp b/media/libeffects/lvm/lib/Common/src/Mac3s_Sat_16x16.cpp
new file mode 100644
index 0000000..6584251
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/Mac3s_Sat_16x16.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**********************************************************************************
+
+ %created_by: sra % (CM/S)
+ %name: Mac3s_Sat_16x16.c % (CM/S)
+ %version: 1 % (CM/S)
+ %date_created: Fri Nov 13 12:07:13 2009 % (CM/S)
+
+***********************************************************************************/
+
+/**********************************************************************************
+ INCLUDE FILES
+***********************************************************************************/
+
+#include "VectorArithmetic.h"
+#include "LVM_Macros.h"
+
+/**********************************************************************************
+ FUNCTION Mac3S_16X16
+***********************************************************************************/
+
+void Mac3s_Sat_16x16( const LVM_INT16 *src,
+ const LVM_INT16 val,
+ LVM_INT16 *dst,
+ LVM_INT16 n)
+{
+ LVM_INT16 ii;
+ LVM_INT16 srcval;
+ LVM_INT32 Temp,dInVal;
+
+ for (ii = n; ii != 0; ii--)
+ {
+ srcval=*src;
+ src++;
+
+ Temp = (srcval *val)>>15;
+
+ dInVal = (LVM_INT32)*dst;
+
+ Temp = Temp + dInVal;
+
+ if (Temp > 0x00007FFF)
+ {
+ *dst = 0x7FFF;
+ }
+ else if (Temp < -0x00008000)
+ {
+ *dst = - 0x8000;
+ }
+ else
+ {
+ *dst = (LVM_INT16)Temp;
+ }
+
+ dst++;
+ }
+
+ return;
+}
+
+/**********************************************************************************/
+
diff --git a/media/libeffects/lvm/lib/Common/src/Mac3s_Sat_32x16.c b/media/libeffects/lvm/lib/Common/src/Mac3s_Sat_32x16.c
deleted file mode 100644
index 17fd833..0000000
--- a/media/libeffects/lvm/lib/Common/src/Mac3s_Sat_32x16.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**********************************************************************************
- INCLUDE FILES
-***********************************************************************************/
-
-#include "VectorArithmetic.h"
-#include "LVM_Macros.h"
-
-/**********************************************************************************
- FUNCTION MAC3S_16X16
-***********************************************************************************/
-
-void Mac3s_Sat_32x16( const LVM_INT32 *src,
- const LVM_INT16 val,
- LVM_INT32 *dst,
- LVM_INT16 n)
-{
- LVM_INT16 ii;
- LVM_INT32 srcval,temp, dInVal, dOutVal;
-
-
- for (ii = n; ii != 0; ii--)
- {
- srcval=*src;
- src++;
-
- MUL32x16INTO32(srcval,val,temp,15)
-
- dInVal = *dst;
- dOutVal = temp + dInVal;
-
-
- if ((((dOutVal ^ temp) & (dOutVal ^ dInVal)) >> 31)!=0) /* overflow / underflow */
- {
- if(temp<0)
- {
- dOutVal=0x80000000L;
- }
- else
- {
- dOutVal=0x7FFFFFFFL;
- }
- }
-
- *dst = dOutVal;
- dst++;
- }
-
- return;
-}
-#ifdef BUILD_FLOAT
-void Mac3s_Sat_Float(const LVM_FLOAT *src,
- const LVM_FLOAT val,
- LVM_FLOAT *dst,
- LVM_INT16 n)
-{
- LVM_INT16 ii;
- LVM_FLOAT srcval;
- LVM_FLOAT Temp,dInVal;
-
- for (ii = n; ii != 0; ii--)
- {
- srcval = *src;
- src++;
-
- Temp = srcval * val;
-
- dInVal = (LVM_FLOAT)*dst;
- Temp = Temp + dInVal;
-
- if (Temp > 1.000000f)
- {
- *dst = 1.000000f;
- }
- else if (Temp < -1.000000f)
- {
- *dst = -1.000000f;
- }
- else
- {
- *dst = Temp;
- }
- dst++;
- }
-
- return;
-}
-#endif
-/**********************************************************************************/
-
-
-
diff --git a/media/libeffects/lvm/lib/Common/src/Mac3s_Sat_32x16.cpp b/media/libeffects/lvm/lib/Common/src/Mac3s_Sat_32x16.cpp
new file mode 100644
index 0000000..5d5564f
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/Mac3s_Sat_32x16.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**********************************************************************************
+ INCLUDE FILES
+***********************************************************************************/
+
+#include "VectorArithmetic.h"
+#include "LVM_Macros.h"
+
+/**********************************************************************************
+ FUNCTION MAC3S_16X16
+***********************************************************************************/
+
+void Mac3s_Sat_32x16( const LVM_INT32 *src,
+ const LVM_INT16 val,
+ LVM_INT32 *dst,
+ LVM_INT16 n)
+{
+ LVM_INT16 ii;
+ LVM_INT32 srcval,temp, dInVal, dOutVal;
+
+ for (ii = n; ii != 0; ii--)
+ {
+ srcval=*src;
+ src++;
+
+ MUL32x16INTO32(srcval,val,temp,15)
+
+ dInVal = *dst;
+ dOutVal = temp + dInVal;
+
+ if ((((dOutVal ^ temp) & (dOutVal ^ dInVal)) >> 31)!=0) /* overflow / underflow */
+ {
+ if(temp<0)
+ {
+ dOutVal=0x80000000L;
+ }
+ else
+ {
+ dOutVal=0x7FFFFFFFL;
+ }
+ }
+
+ *dst = dOutVal;
+ dst++;
+ }
+
+ return;
+}
+void Mac3s_Sat_Float(const LVM_FLOAT *src,
+ const LVM_FLOAT val,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ LVM_INT16 ii;
+ LVM_FLOAT srcval;
+ LVM_FLOAT Temp,dInVal;
+
+ for (ii = n; ii != 0; ii--)
+ {
+ srcval = *src;
+ src++;
+
+ Temp = srcval * val;
+
+ dInVal = (LVM_FLOAT)*dst;
+ Temp = Temp + dInVal;
+
+ if (Temp > 1.000000f)
+ {
+ *dst = 1.000000f;
+ }
+ else if (Temp < -1.000000f)
+ {
+ *dst = -1.000000f;
+ }
+ else
+ {
+ *dst = Temp;
+ }
+ dst++;
+ }
+
+ return;
+}
+/**********************************************************************************/
+
diff --git a/media/libeffects/lvm/lib/Common/src/MixInSoft_D32C31_SAT.c b/media/libeffects/lvm/lib/Common/src/MixInSoft_D32C31_SAT.c
deleted file mode 100644
index 16e367b..0000000
--- a/media/libeffects/lvm/lib/Common/src/MixInSoft_D32C31_SAT.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**********************************************************************************
- INCLUDE FILES
-***********************************************************************************/
-
-#include "Mixer_private.h"
-#include "VectorArithmetic.h"
-
-/**********************************************************************************
- DEFINITIONS
-***********************************************************************************/
-
-#define TRUE 1
-#define FALSE 0
-
-/**********************************************************************************
- FUNCTION MIXINSOFT_D32C31_SAT
-***********************************************************************************/
-#ifdef BUILD_FLOAT
-void MixInSoft_D32C31_SAT( Mix_1St_Cll_FLOAT_t *pInstance,
- const LVM_FLOAT *src,
- LVM_FLOAT *dst,
- LVM_INT16 n)
-{
- char HardMixing = TRUE;
-
- if(n <= 0) return;
-
- /******************************************************************************
- SOFT MIXING
- *******************************************************************************/
- if (pInstance->Current != pInstance->Target)
- {
- if(pInstance->Alpha == 0){
- pInstance->Current = pInstance->Target;
- }else if ((pInstance->Current-pInstance->Target < POINT_ZERO_ONE_DB_FLOAT) &&
- (pInstance->Current-pInstance->Target > -POINT_ZERO_ONE_DB_FLOAT)){
- pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
- Make them equal. */
- }else{
- /* Soft mixing has to be applied */
- HardMixing = FALSE;
- Core_MixInSoft_D32C31_SAT(pInstance, src, dst, n);
- }
- }
-
- /******************************************************************************
- HARD MIXING
- *******************************************************************************/
-
- if (HardMixing){
- if (pInstance->Target != 0){ /* Nothing to do in case Target = 0 */
- if ((pInstance->Target) == 1.0f)
- Add2_Sat_Float(src, dst, n);
- else{
- Core_MixInSoft_D32C31_SAT(pInstance, src, dst, n);
- pInstance->Current = pInstance->Target; /* In case the core function would \
- have changed the Current value */
- }
- }
- }
-
- /******************************************************************************
- CALL BACK
- *******************************************************************************/
- /* Call back before the hard mixing, because in this case, hard mixing makes
- use of the core soft mix function which can change the Current value! */
-
- if (pInstance->CallbackSet){
- if ((pInstance->Current - pInstance->Target < POINT_ZERO_ONE_DB_FLOAT) &&
- (pInstance->Current - pInstance->Target > -POINT_ZERO_ONE_DB_FLOAT)){
- pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
- Make them equal. */
- pInstance->CallbackSet = FALSE;
- if (pInstance->pCallBack != 0){
- (*pInstance->pCallBack) ( pInstance->pCallbackHandle,
- pInstance->pGeneralPurpose,
- pInstance->CallbackParam );
- }
- }
- }
-}
-#else
-void MixInSoft_D32C31_SAT( Mix_1St_Cll_t *pInstance,
- const LVM_INT32 *src,
- LVM_INT32 *dst,
- LVM_INT16 n)
-{
- char HardMixing = TRUE;
-
- if(n<=0) return;
-
- /******************************************************************************
- SOFT MIXING
- *******************************************************************************/
- if (pInstance->Current != pInstance->Target)
- {
- if(pInstance->Alpha == 0){
- pInstance->Current = pInstance->Target;
- }else if ((pInstance->Current-pInstance->Target <POINT_ZERO_ONE_DB)&&
- (pInstance->Current-pInstance->Target > -POINT_ZERO_ONE_DB)){
- pInstance->Current = pInstance->Target; /* Difference is not significant anymore. Make them equal. */
- }else{
- /* Soft mixing has to be applied */
- HardMixing = FALSE;
- Core_MixInSoft_D32C31_SAT( pInstance, src, dst, n);
- }
- }
-
- /******************************************************************************
- HARD MIXING
- *******************************************************************************/
-
- if (HardMixing){
- if (pInstance->Target != 0){ /* Nothing to do in case Target = 0 */
- if ((pInstance->Target>>16) == 0x7FFF)
- Add2_Sat_32x32( src, dst, n );
- else{
- Core_MixInSoft_D32C31_SAT( pInstance, src, dst, n);
- pInstance->Current = pInstance->Target; /* In case the core function would have changed the Current value */
- }
- }
- }
-
- /******************************************************************************
- CALL BACK
- *******************************************************************************/
- /* Call back before the hard mixing, because in this case, hard mixing makes
- use of the core soft mix function which can change the Current value! */
-
- if (pInstance->CallbackSet){
- if ((pInstance->Current-pInstance->Target <POINT_ZERO_ONE_DB)&&
- (pInstance->Current-pInstance->Target > -POINT_ZERO_ONE_DB)){
- pInstance->Current = pInstance->Target; /* Difference is not significant anymore. Make them equal. */
- pInstance->CallbackSet = FALSE;
- if (pInstance->pCallBack != 0){
- (*pInstance->pCallBack) ( pInstance->pCallbackHandle, pInstance->pGeneralPurpose,pInstance->CallbackParam );
- }
- }
- }
-}
-#endif
-/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/MixInSoft_D32C31_SAT.cpp b/media/libeffects/lvm/lib/Common/src/MixInSoft_D32C31_SAT.cpp
new file mode 100644
index 0000000..7c7b36f
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/MixInSoft_D32C31_SAT.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**********************************************************************************
+ INCLUDE FILES
+***********************************************************************************/
+
+#include "Mixer_private.h"
+#include "VectorArithmetic.h"
+
+/**********************************************************************************
+ DEFINITIONS
+***********************************************************************************/
+
+#define TRUE 1
+#define FALSE 0
+
+/**********************************************************************************
+ FUNCTION MIXINSOFT_D32C31_SAT
+***********************************************************************************/
+void MixInSoft_D32C31_SAT( Mix_1St_Cll_FLOAT_t *pInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ char HardMixing = TRUE;
+
+ if(n <= 0) return;
+
+ /******************************************************************************
+ SOFT MIXING
+ *******************************************************************************/
+ if (pInstance->Current != pInstance->Target)
+ {
+ if(pInstance->Alpha == 0){
+ pInstance->Current = pInstance->Target;
+ }else if ((pInstance->Current-pInstance->Target < POINT_ZERO_ONE_DB_FLOAT) &&
+ (pInstance->Current-pInstance->Target > -POINT_ZERO_ONE_DB_FLOAT)){
+ pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
+ Make them equal. */
+ }else{
+ /* Soft mixing has to be applied */
+ HardMixing = FALSE;
+ Core_MixInSoft_D32C31_SAT(pInstance, src, dst, n);
+ }
+ }
+
+ /******************************************************************************
+ HARD MIXING
+ *******************************************************************************/
+
+ if (HardMixing){
+ if (pInstance->Target != 0){ /* Nothing to do in case Target = 0 */
+ if ((pInstance->Target) == 1.0f)
+ Add2_Sat_Float(src, dst, n);
+ else{
+ Core_MixInSoft_D32C31_SAT(pInstance, src, dst, n);
+ pInstance->Current = pInstance->Target; /* In case the core function would \
+ have changed the Current value */
+ }
+ }
+ }
+
+ /******************************************************************************
+ CALL BACK
+ *******************************************************************************/
+ /* Call back before the hard mixing, because in this case, hard mixing makes
+ use of the core soft mix function which can change the Current value! */
+
+ if (pInstance->CallbackSet){
+ if ((pInstance->Current - pInstance->Target < POINT_ZERO_ONE_DB_FLOAT) &&
+ (pInstance->Current - pInstance->Target > -POINT_ZERO_ONE_DB_FLOAT)){
+ pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
+ Make them equal. */
+ pInstance->CallbackSet = FALSE;
+ if (pInstance->pCallBack != 0){
+ (*pInstance->pCallBack) ( pInstance->pCallbackHandle,
+ pInstance->pGeneralPurpose,
+ pInstance->CallbackParam );
+ }
+ }
+ }
+}
+/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/MixSoft_1St_D32C31_WRA.c b/media/libeffects/lvm/lib/Common/src/MixSoft_1St_D32C31_WRA.c
deleted file mode 100644
index 869293b..0000000
--- a/media/libeffects/lvm/lib/Common/src/MixSoft_1St_D32C31_WRA.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**********************************************************************************
- INCLUDE FILES
-***********************************************************************************/
-
-#include "Mixer_private.h"
-#include "VectorArithmetic.h"
-
-/**********************************************************************************
- DEFINITIONS
-***********************************************************************************/
-
-#define TRUE 1
-#define FALSE 0
-
-
-
-/**********************************************************************************
- FUNCTION MIXSOFT_1ST_D32C31_WRA
-***********************************************************************************/
-#ifdef BUILD_FLOAT
-void MixSoft_1St_D32C31_WRA( Mix_1St_Cll_FLOAT_t *pInstance,
- const LVM_FLOAT *src,
- LVM_FLOAT *dst,
- LVM_INT16 n)
-{
- char HardMixing = TRUE;
-
- if(n <= 0) return;
-
- /******************************************************************************
- SOFT MIXING
- *******************************************************************************/
- if (pInstance->Current != pInstance->Target)
- {
- if(pInstance->Alpha == 0){
- pInstance->Current = pInstance->Target;
- }else if ((pInstance->Current - pInstance->Target < POINT_ZERO_ONE_DB_FLOAT) &&
- (pInstance->Current - pInstance->Target > -POINT_ZERO_ONE_DB_FLOAT)){
- pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
- Make them equal. */
- }else{
- /* Soft mixing has to be applied */
- HardMixing = FALSE;
- Core_MixSoft_1St_D32C31_WRA(pInstance, src, dst, n);
- }
- }
-
- /******************************************************************************
- HARD MIXING
- *******************************************************************************/
-
- if (HardMixing){
- if (pInstance->Target == 0)
- LoadConst_Float(0, dst, n);
- else if ((pInstance->Target) == 1.0f){
- if (src != dst)
- Copy_Float((LVM_FLOAT*)src, (LVM_FLOAT*)dst, (LVM_INT16)(n));
- }
- else
- Mult3s_Float(src, pInstance->Current, dst, n);
- }
-
- /******************************************************************************
- CALL BACK
- *******************************************************************************/
-
- if (pInstance->CallbackSet){
- if ((pInstance->Current - pInstance->Target < POINT_ZERO_ONE_DB_FLOAT) &&
- (pInstance->Current - pInstance->Target > -POINT_ZERO_ONE_DB_FLOAT)){
- pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
- Make them equal. */
- pInstance->CallbackSet = FALSE;
- if (pInstance->pCallBack != 0){
- (*pInstance->pCallBack) ( pInstance->pCallbackHandle,
- pInstance->pGeneralPurpose,
- pInstance->CallbackParam );
- }
- }
- }
-}
-#else
-void MixSoft_1St_D32C31_WRA( Mix_1St_Cll_t *pInstance,
- const LVM_INT32 *src,
- LVM_INT32 *dst,
- LVM_INT16 n)
-{
- char HardMixing = TRUE;
-
- if(n<=0) return;
-
- /******************************************************************************
- SOFT MIXING
- *******************************************************************************/
- if (pInstance->Current != pInstance->Target)
- {
- if(pInstance->Alpha == 0){
- pInstance->Current = pInstance->Target;
- }else if ((pInstance->Current-pInstance->Target <POINT_ZERO_ONE_DB)&&
- (pInstance->Current-pInstance->Target > -POINT_ZERO_ONE_DB)){
- pInstance->Current = pInstance->Target; /* Difference is not significant anymore. Make them equal. */
- }else{
- /* Soft mixing has to be applied */
- HardMixing = FALSE;
- Core_MixSoft_1St_D32C31_WRA( pInstance, src, dst, n);
- }
- }
-
- /******************************************************************************
- HARD MIXING
- *******************************************************************************/
-
- if (HardMixing){
- if (pInstance->Target == 0)
- LoadConst_32(0, dst, n);
- else if ((pInstance->Target>>16) == 0x7FFF){
- if (src != dst)
- Copy_16((LVM_INT16*)src, (LVM_INT16*)dst, (LVM_INT16)(n * 2));
- }
- else
- Mult3s_32x16( src, (LVM_INT16)(pInstance->Current>>16), dst, n );
- }
-
- /******************************************************************************
- CALL BACK
- *******************************************************************************/
-
- if (pInstance->CallbackSet){
- if ((pInstance->Current-pInstance->Target <POINT_ZERO_ONE_DB)&&
- (pInstance->Current-pInstance->Target > -POINT_ZERO_ONE_DB)){
- pInstance->Current = pInstance->Target; /* Difference is not significant anymore. Make them equal. */
- pInstance->CallbackSet = FALSE;
- if (pInstance->pCallBack != 0){
- (*pInstance->pCallBack) ( pInstance->pCallbackHandle, pInstance->pGeneralPurpose,pInstance->CallbackParam );
- }
- }
- }
-}
-#endif
-/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/MixSoft_1St_D32C31_WRA.cpp b/media/libeffects/lvm/lib/Common/src/MixSoft_1St_D32C31_WRA.cpp
new file mode 100644
index 0000000..d3325ec
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/MixSoft_1St_D32C31_WRA.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**********************************************************************************
+ INCLUDE FILES
+***********************************************************************************/
+
+#include "Mixer_private.h"
+#include "VectorArithmetic.h"
+
+/**********************************************************************************
+ DEFINITIONS
+***********************************************************************************/
+
+#define TRUE 1
+#define FALSE 0
+
+/**********************************************************************************
+ FUNCTION MIXSOFT_1ST_D32C31_WRA
+***********************************************************************************/
+void MixSoft_1St_D32C31_WRA( Mix_1St_Cll_FLOAT_t *pInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ char HardMixing = TRUE;
+
+ if(n <= 0) return;
+
+ /******************************************************************************
+ SOFT MIXING
+ *******************************************************************************/
+ if (pInstance->Current != pInstance->Target)
+ {
+ if(pInstance->Alpha == 0){
+ pInstance->Current = pInstance->Target;
+ }else if ((pInstance->Current - pInstance->Target < POINT_ZERO_ONE_DB_FLOAT) &&
+ (pInstance->Current - pInstance->Target > -POINT_ZERO_ONE_DB_FLOAT)){
+ pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
+ Make them equal. */
+ }else{
+ /* Soft mixing has to be applied */
+ HardMixing = FALSE;
+ Core_MixSoft_1St_D32C31_WRA(pInstance, src, dst, n);
+ }
+ }
+
+ /******************************************************************************
+ HARD MIXING
+ *******************************************************************************/
+
+ if (HardMixing){
+ if (pInstance->Target == 0)
+ LoadConst_Float(0, dst, n);
+ else if ((pInstance->Target) == 1.0f){
+ if (src != dst)
+ Copy_Float((LVM_FLOAT*)src, (LVM_FLOAT*)dst, (LVM_INT16)(n));
+ }
+ else
+ Mult3s_Float(src, pInstance->Current, dst, n);
+ }
+
+ /******************************************************************************
+ CALL BACK
+ *******************************************************************************/
+
+ if (pInstance->CallbackSet){
+ if ((pInstance->Current - pInstance->Target < POINT_ZERO_ONE_DB_FLOAT) &&
+ (pInstance->Current - pInstance->Target > -POINT_ZERO_ONE_DB_FLOAT)){
+ pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
+ Make them equal. */
+ pInstance->CallbackSet = FALSE;
+ if (pInstance->pCallBack != 0){
+ (*pInstance->pCallBack) ( pInstance->pCallbackHandle,
+ pInstance->pGeneralPurpose,
+ pInstance->CallbackParam );
+ }
+ }
+ }
+}
+/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/MixSoft_2St_D32C31_SAT.c b/media/libeffects/lvm/lib/Common/src/MixSoft_2St_D32C31_SAT.c
deleted file mode 100644
index 6fc1b92..0000000
--- a/media/libeffects/lvm/lib/Common/src/MixSoft_2St_D32C31_SAT.c
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**********************************************************************************
- INCLUDE FILES
-***********************************************************************************/
-
-#include "Mixer_private.h"
-#include "VectorArithmetic.h"
-
-
-/**********************************************************************************
- FUNCTION MIXSOFT_2ST_D32C31_SAT
-***********************************************************************************/
-#ifdef BUILD_FLOAT
-void MixSoft_2St_D32C31_SAT( Mix_2St_Cll_FLOAT_t *pInstance,
- const LVM_FLOAT *src1,
- const LVM_FLOAT *src2,
- LVM_FLOAT *dst,
- LVM_INT16 n)
-{
-
- if(n <= 0) return;
-
- /******************************************************************************
- SOFT MIXING
- *******************************************************************************/
- if ((pInstance->Current1 != pInstance->Target1) || (pInstance->Current2 != pInstance->Target2))
- {
- MixSoft_1St_D32C31_WRA((Mix_1St_Cll_FLOAT_t*)pInstance, src1, dst, n);
- MixInSoft_D32C31_SAT((void *)&pInstance->Alpha2, /* Cast to void: \
- no dereferencing in function*/
- src2, dst, n);
- }
-
- /******************************************************************************
- HARD MIXING
- *******************************************************************************/
-
- else
- {
- if (pInstance->Current1 == 0)
- MixSoft_1St_D32C31_WRA((void *) &pInstance->Alpha2, /* Cast to void: no \
- dereferencing in function*/
- src2, dst, n);
- else if (pInstance->Current2 == 0)
- MixSoft_1St_D32C31_WRA((Mix_1St_Cll_FLOAT_t*) pInstance, src1, dst, n);
- else
- Core_MixHard_2St_D32C31_SAT(pInstance, src1, src2, dst, n);
- }
-}
-#else
-void MixSoft_2St_D32C31_SAT( Mix_2St_Cll_t *pInstance,
- const LVM_INT32 *src1,
- const LVM_INT32 *src2,
- LVM_INT32 *dst,
- LVM_INT16 n)
-{
-
- if(n<=0) return;
-
- /******************************************************************************
- SOFT MIXING
- *******************************************************************************/
- if ((pInstance->Current1 != pInstance->Target1) || (pInstance->Current2 != pInstance->Target2))
- {
- MixSoft_1St_D32C31_WRA( (Mix_1St_Cll_t*) pInstance, src1, dst, n);
- MixInSoft_D32C31_SAT( (void *) &pInstance->Alpha2, /* Cast to void: no dereferencing in function*/
- src2, dst, n);
- }
-
- /******************************************************************************
- HARD MIXING
- *******************************************************************************/
-
- else
- {
- if (pInstance->Current1 == 0)
- MixSoft_1St_D32C31_WRA( (void *) &pInstance->Alpha2, /* Cast to void: no dereferencing in function*/
- src2, dst, n);
- else if (pInstance->Current2 == 0)
- MixSoft_1St_D32C31_WRA( (Mix_1St_Cll_t*) pInstance, src1, dst, n);
- else
- Core_MixHard_2St_D32C31_SAT( pInstance, src1, src2, dst, n);
- }
-}
-#endif
-/**********************************************************************************/
-
diff --git a/media/libeffects/lvm/lib/Common/src/MixSoft_2St_D32C31_SAT.cpp b/media/libeffects/lvm/lib/Common/src/MixSoft_2St_D32C31_SAT.cpp
new file mode 100644
index 0000000..b002738
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/MixSoft_2St_D32C31_SAT.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**********************************************************************************
+ INCLUDE FILES
+***********************************************************************************/
+
+#include "Mixer_private.h"
+#include "VectorArithmetic.h"
+
+/**********************************************************************************
+ FUNCTION MIXSOFT_2ST_D32C31_SAT
+***********************************************************************************/
+void MixSoft_2St_D32C31_SAT( Mix_2St_Cll_FLOAT_t *pInstance,
+ const LVM_FLOAT *src1,
+ const LVM_FLOAT *src2,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+
+ if(n <= 0) return;
+
+ /******************************************************************************
+ SOFT MIXING
+ *******************************************************************************/
+ if ((pInstance->Current1 != pInstance->Target1) || (pInstance->Current2 != pInstance->Target2))
+ {
+ MixSoft_1St_D32C31_WRA((Mix_1St_Cll_FLOAT_t*)pInstance, src1, dst, n);
+ MixInSoft_D32C31_SAT((Mix_1St_Cll_FLOAT_t *)&pInstance->Alpha2, /* Cast to void: \
+ no dereferencing in function*/
+ src2, dst, n);
+ }
+
+ /******************************************************************************
+ HARD MIXING
+ *******************************************************************************/
+
+ else
+ {
+ if (pInstance->Current1 == 0)
+ MixSoft_1St_D32C31_WRA(
+ (Mix_1St_Cll_FLOAT_t *) &pInstance->Alpha2, /* Cast to void: no \
+ dereferencing in function*/
+ src2, dst, n);
+ else if (pInstance->Current2 == 0)
+ MixSoft_1St_D32C31_WRA((Mix_1St_Cll_FLOAT_t*) pInstance, src1, dst, n);
+ else
+ Core_MixHard_2St_D32C31_SAT(pInstance, src1, src2, dst, n);
+ }
+}
+/**********************************************************************************/
+
diff --git a/media/libeffects/lvm/lib/Common/src/Mixer_private.h b/media/libeffects/lvm/lib/Common/src/Mixer_private.h
index 00d55ed..1d653bb 100644
--- a/media/libeffects/lvm/lib/Common/src/Mixer_private.h
+++ b/media/libeffects/lvm/lib/Common/src/Mixer_private.h
@@ -26,10 +26,8 @@
#define POINT_ZERO_ONE_DB 2473805 /* 0.01 dB on a full scale signal = (10^(0.01/20) -1) * 2^31 */
-#ifdef BUILD_FLOAT
#define POINT_ZERO_ONE_DB_FLOAT 0.001152 /* 0.01 dB on a full scale \
signal = (10^(0.01/20) -1) * 2^31 */
-#endif
/**********************************************************************************
DEFINITIONS
***********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/MonoTo2I_16.c b/media/libeffects/lvm/lib/Common/src/MonoTo2I_16.cpp
similarity index 100%
rename from media/libeffects/lvm/lib/Common/src/MonoTo2I_16.c
rename to media/libeffects/lvm/lib/Common/src/MonoTo2I_16.cpp
diff --git a/media/libeffects/lvm/lib/Common/src/MonoTo2I_32.c b/media/libeffects/lvm/lib/Common/src/MonoTo2I_32.c
deleted file mode 100644
index 796a15c..0000000
--- a/media/libeffects/lvm/lib/Common/src/MonoTo2I_32.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**********************************************************************************
- INCLUDE FILES
-***********************************************************************************/
-
-#include "VectorArithmetic.h"
-
-/**********************************************************************************
- FUNCTION MonoTo2I_32
-***********************************************************************************/
-
-void MonoTo2I_32( const LVM_INT32 *src,
- LVM_INT32 *dst,
- LVM_INT16 n)
-{
- LVM_INT16 ii;
- src += (n-1);
- dst += ((n*2)-1);
-
- for (ii = n; ii != 0; ii--)
- {
- *dst = *src;
- dst--;
-
- *dst = *src;
- dst--;
- src--;
- }
-
- return;
-}
-#ifdef BUILD_FLOAT
-void MonoTo2I_Float( const LVM_FLOAT *src,
- LVM_FLOAT *dst,
- LVM_INT16 n)
-{
- LVM_INT16 ii;
- src += (n - 1);
- dst += ((n * 2) - 1);
-
- for (ii = n; ii != 0; ii--)
- {
- *dst = *src;
- dst--;
-
- *dst = *src;
- dst--;
- src--;
- }
-
- return;
-}
-#endif
-/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/MonoTo2I_32.cpp b/media/libeffects/lvm/lib/Common/src/MonoTo2I_32.cpp
new file mode 100644
index 0000000..603d1fc
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/MonoTo2I_32.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**********************************************************************************
+ INCLUDE FILES
+***********************************************************************************/
+
+#include "VectorArithmetic.h"
+
+/**********************************************************************************
+ FUNCTION MonoTo2I_32
+***********************************************************************************/
+
+void MonoTo2I_32( const LVM_INT32 *src,
+ LVM_INT32 *dst,
+ LVM_INT16 n)
+{
+ LVM_INT16 ii;
+ src += (n-1);
+ dst += ((n*2)-1);
+
+ for (ii = n; ii != 0; ii--)
+ {
+ *dst = *src;
+ dst--;
+
+ *dst = *src;
+ dst--;
+ src--;
+ }
+
+ return;
+}
+void MonoTo2I_Float( const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ LVM_INT16 ii;
+ src += (n - 1);
+ dst += ((n * 2) - 1);
+
+ for (ii = n; ii != 0; ii--)
+ {
+ *dst = *src;
+ dst--;
+
+ *dst = *src;
+ dst--;
+ src--;
+ }
+
+ return;
+}
+/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/Mult3s_32x16.c b/media/libeffects/lvm/lib/Common/src/Mult3s_32x16.c
deleted file mode 100644
index c758560..0000000
--- a/media/libeffects/lvm/lib/Common/src/Mult3s_32x16.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**********************************************************************************
- INCLUDE FILES
-***********************************************************************************/
-
-#include "VectorArithmetic.h"
-#include "LVM_Macros.h"
-
-/**********************************************************************************
-FUNCTION MULT3S_16X16
-***********************************************************************************/
-
-void Mult3s_32x16( const LVM_INT32 *src,
- const LVM_INT16 val,
- LVM_INT32 *dst,
- LVM_INT16 n)
-{
- LVM_INT16 ii;
- LVM_INT32 srcval,temp;
-
- for (ii = n; ii != 0; ii--)
- {
- srcval=*src;
- src++;
-
- MUL32x16INTO32(srcval,val,temp,15)
-
- *dst = temp;
- dst++;
- }
-
- return;
-}
-#ifdef BUILD_FLOAT
-void Mult3s_Float( const LVM_FLOAT *src,
- const LVM_FLOAT val,
- LVM_FLOAT *dst,
- LVM_INT16 n)
-{
- LVM_INT16 ii;
- LVM_FLOAT temp;
-
- for (ii = n; ii != 0; ii--)
- {
- temp = (*src) * val;
- src++;
- *dst = temp;
- dst++;
- }
- return;
-}
-#endif
-/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/Mult3s_32x16.cpp b/media/libeffects/lvm/lib/Common/src/Mult3s_32x16.cpp
new file mode 100644
index 0000000..370c39a
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/Mult3s_32x16.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**********************************************************************************
+ INCLUDE FILES
+***********************************************************************************/
+
+#include "VectorArithmetic.h"
+#include "LVM_Macros.h"
+
+/**********************************************************************************
+FUNCTION MULT3S_16X16
+***********************************************************************************/
+
+void Mult3s_32x16( const LVM_INT32 *src,
+ const LVM_INT16 val,
+ LVM_INT32 *dst,
+ LVM_INT16 n)
+{
+ LVM_INT16 ii;
+ LVM_INT32 srcval,temp;
+
+ for (ii = n; ii != 0; ii--)
+ {
+ srcval=*src;
+ src++;
+
+ MUL32x16INTO32(srcval,val,temp,15)
+
+ *dst = temp;
+ dst++;
+ }
+
+ return;
+}
+void Mult3s_Float( const LVM_FLOAT *src,
+ const LVM_FLOAT val,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ LVM_INT16 ii;
+ LVM_FLOAT temp;
+
+ for (ii = n; ii != 0; ii--)
+ {
+ temp = (*src) * val;
+ src++;
+ *dst = temp;
+ dst++;
+ }
+ return;
+}
+/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/NonLinComp_D16.c b/media/libeffects/lvm/lib/Common/src/NonLinComp_D16.c
deleted file mode 100644
index 5156edc..0000000
--- a/media/libeffects/lvm/lib/Common/src/NonLinComp_D16.c
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/****************************************************************************************/
-/* */
-/* Includes */
-/* */
-/****************************************************************************************/
-
-#include "CompLim_private.h"
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: NonLinComp_D16 */
-/* */
-/* DESCRIPTION: */
-/* Non-linear compression by companding. The function works on a sample by sample */
-/* basis by increasing the level near the zero crossing. This gives a ttrade-off */
-/* between THD and compression. It uses the equation: */
-/* */
-/* Output = Input + K * (Input - Input^2) if Input > 0 */
-/* = Input + K * (Input + Input^2) if Input <= 0 */
-/* */
-/* The value of K controls the amount of compression and as a side effect the amount */
-/* distortion introduced. The amount of compression is signal dependent and the values */
-/* given below are approximate. */
-/* */
-/* Gain (fractional) Gain (integer) Compression Pk-Pk THD */
-/* 1.0 32767 +6dB 16dB */
-/* 0.78 25559 +5dB 19dB */
-/* 0.6 19661 +4dB 21dB */
-/* 0.41 13435 +3dB 24dB */
-/* 0.26 8520 +2dB 28dB */
-/* 0.12 3932 +1dB 34dB */
-/* 0.0 0 +0dB 98dB */
-/* */
-/* PARAMETERS: */
-/* Gain - compression control parameter */
-/* pDataIn - pointer to the input data buffer */
-/* pDataOut - pointer to the output data buffer */
-/* BlockLength - number of samples to process */
-/* */
-/* RETURNS: */
-/* None */
-/* */
-/* NOTES: */
-/* */
-/****************************************************************************************/
-
-void NonLinComp_D16(LVM_INT16 Gain,
- LVM_INT16 *pDataIn,
- LVM_INT16 *pDataOut,
- LVM_INT32 BlockLength)
-{
-
- LVM_INT16 Sample; /* Input samples */
- LVM_INT32 SampleNo; /* Sample index */
- LVM_INT16 Temp;
-
-
- /*
- * Process a block of samples
- */
- for(SampleNo = 0; SampleNo<BlockLength; SampleNo++)
- {
-
- /*
- * Read the input
- */
- Sample = *pDataIn;
- pDataIn++;
-
-
- /*
- * Apply the compander, this compresses the signal at the expense of
- * harmonic distortion. The amount of compression is control by the
- * gain factor
- */
- if ((LVM_INT32)Sample != -32768)
- {
- Temp = (LVM_INT16)((Sample * Sample) >> 15);
- if(Sample >0)
- {
- Sample = (LVM_INT16)(Sample + ((Gain * (Sample - Temp)) >> 15));
- }
- else
- {
- Sample = (LVM_INT16)(Sample + ((Gain * (Sample + Temp)) >> 15));
- }
- }
-
-
- /*
- * Save the output
- */
- *pDataOut = Sample;
- pDataOut++;
-
-
- }
-
-}
-#ifdef BUILD_FLOAT
-void NonLinComp_Float(LVM_FLOAT Gain,
- LVM_FLOAT *pDataIn,
- LVM_FLOAT *pDataOut,
- LVM_INT32 BlockLength)
-{
-
- LVM_FLOAT Sample; /* Input samples */
- LVM_INT32 SampleNo; /* Sample index */
- LVM_FLOAT Temp;
-
-
- /*
- * Process a block of samples
- */
- for(SampleNo = 0; SampleNo < BlockLength; SampleNo++)
- {
- /*
- * Read the input
- */
- Sample = *pDataIn;
- pDataIn++;
-
-
- /*
- * Apply the compander, this compresses the signal at the expense of
- * harmonic distortion. The amount of compression is control by the
- * gain factor
- */
- if (Sample != -1.0f)
- {
- Temp = ((Sample * Sample));
- if(Sample > 0)
- {
- Sample = (Sample + ((Gain * (Sample - Temp)) ));
- }
- else
- {
- Sample = (Sample + ((Gain * (Sample + Temp)) ));
- }
- }
-
-
- /*
- * Save the output
- */
- *pDataOut = Sample;
- pDataOut++;
- }
-}
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/NonLinComp_D16.cpp b/media/libeffects/lvm/lib/Common/src/NonLinComp_D16.cpp
new file mode 100644
index 0000000..36d1149
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/NonLinComp_D16.cpp
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/****************************************************************************************/
+/* */
+/* Includes */
+/* */
+/****************************************************************************************/
+
+#include "CompLim_private.h"
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: NonLinComp_D16 */
+/* */
+/* DESCRIPTION: */
+/* Non-linear compression by companding. The function works on a sample by sample */
+/* basis by increasing the level near the zero crossing. This gives a ttrade-off */
+/* between THD and compression. It uses the equation: */
+/* */
+/* Output = Input + K * (Input - Input^2) if Input > 0 */
+/* = Input + K * (Input + Input^2) if Input <= 0 */
+/* */
+/* The value of K controls the amount of compression and as a side effect the amount */
+/* distortion introduced. The amount of compression is signal dependent and the values */
+/* given below are approximate. */
+/* */
+/* Gain (fractional) Gain (integer) Compression Pk-Pk THD */
+/* 1.0 32767 +6dB 16dB */
+/* 0.78 25559 +5dB 19dB */
+/* 0.6 19661 +4dB 21dB */
+/* 0.41 13435 +3dB 24dB */
+/* 0.26 8520 +2dB 28dB */
+/* 0.12 3932 +1dB 34dB */
+/* 0.0 0 +0dB 98dB */
+/* */
+/* PARAMETERS: */
+/* Gain - compression control parameter */
+/* pDataIn - pointer to the input data buffer */
+/* pDataOut - pointer to the output data buffer */
+/* BlockLength - number of samples to process */
+/* */
+/* RETURNS: */
+/* None */
+/* */
+/* NOTES: */
+/* */
+/****************************************************************************************/
+
+void NonLinComp_D16(LVM_INT16 Gain,
+ LVM_INT16 *pDataIn,
+ LVM_INT16 *pDataOut,
+ LVM_INT32 BlockLength)
+{
+
+ LVM_INT16 Sample; /* Input samples */
+ LVM_INT32 SampleNo; /* Sample index */
+ LVM_INT16 Temp;
+
+ /*
+ * Process a block of samples
+ */
+ for(SampleNo = 0; SampleNo<BlockLength; SampleNo++)
+ {
+
+ /*
+ * Read the input
+ */
+ Sample = *pDataIn;
+ pDataIn++;
+
+ /*
+ * Apply the compander, this compresses the signal at the expense of
+ * harmonic distortion. The amount of compression is control by the
+ * gain factor
+ */
+ if ((LVM_INT32)Sample != -32768)
+ {
+ Temp = (LVM_INT16)((Sample * Sample) >> 15);
+ if(Sample >0)
+ {
+ Sample = (LVM_INT16)(Sample + ((Gain * (Sample - Temp)) >> 15));
+ }
+ else
+ {
+ Sample = (LVM_INT16)(Sample + ((Gain * (Sample + Temp)) >> 15));
+ }
+ }
+
+ /*
+ * Save the output
+ */
+ *pDataOut = Sample;
+ pDataOut++;
+
+ }
+
+}
+void NonLinComp_Float(LVM_FLOAT Gain,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT32 BlockLength)
+{
+
+ LVM_FLOAT Sample; /* Input samples */
+ LVM_INT32 SampleNo; /* Sample index */
+ LVM_FLOAT Temp;
+
+ /*
+ * Process a block of samples
+ */
+ for(SampleNo = 0; SampleNo < BlockLength; SampleNo++)
+ {
+ /*
+ * Read the input
+ */
+ Sample = *pDataIn;
+ pDataIn++;
+
+ /*
+ * Apply the compander, this compresses the signal at the expense of
+ * harmonic distortion. The amount of compression is control by the
+ * gain factor
+ */
+ if (Sample != -1.0f)
+ {
+ Temp = ((Sample * Sample));
+ if(Sample > 0)
+ {
+ Sample = (Sample + ((Gain * (Sample - Temp)) ));
+ }
+ else
+ {
+ Sample = (Sample + ((Gain * (Sample + Temp)) ));
+ }
+ }
+
+ /*
+ * Save the output
+ */
+ *pDataOut = Sample;
+ pDataOut++;
+ }
+}
diff --git a/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32C14G11_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32C14G11_TRC_WRA_01.c
deleted file mode 100644
index 6c8b2db..0000000
--- a/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32C14G11_TRC_WRA_01.c
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BIQUAD.h"
-#include "PK_2I_D32F32CssGss_TRC_WRA_01_Private.h"
-#include "LVM_Macros.h"
-
-/**************************************************************************
- ASSUMPTIONS:
- COEFS-
- pBiquadState->coefs[0] is A0,
- pBiquadState->coefs[1] is -B2,
- pBiquadState->coefs[2] is -B1, these are in Q14 format
- pBiquadState->coefs[3] is Gain, in Q11 format
-
-
- DELAYS-
- pBiquadState->pDelays[0] is x(n-1)L in Q0 format
- pBiquadState->pDelays[1] is x(n-1)R in Q0 format
- pBiquadState->pDelays[2] is x(n-2)L in Q0 format
- pBiquadState->pDelays[3] is x(n-2)R in Q0 format
- pBiquadState->pDelays[4] is y(n-1)L in Q0 format
- pBiquadState->pDelays[5] is y(n-1)R in Q0 format
- pBiquadState->pDelays[6] is y(n-2)L in Q0 format
- pBiquadState->pDelays[7] is y(n-2)R in Q0 format
-***************************************************************************/
-#ifdef BUILD_FLOAT
-void PK_2I_D32F32C14G11_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
- LVM_FLOAT *pDataIn,
- LVM_FLOAT *pDataOut,
- LVM_INT16 NrSamples)
- {
- LVM_FLOAT ynL,ynR,ynLO,ynRO,templ;
- LVM_INT16 ii;
- PFilter_State_Float pBiquadState = (PFilter_State_Float) pInstance;
-
- for (ii = NrSamples; ii != 0; ii--)
- {
-
-
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
- /* ynL= (A0 * (x(n)L - x(n-2)L ) )*/
- templ = (*pDataIn) - pBiquadState->pDelays[2];
- ynL = templ * pBiquadState->coefs[0];
-
- /* ynL+= ((-B2 * y(n-2)L )) */
- templ = pBiquadState->pDelays[6] * pBiquadState->coefs[1];
- ynL += templ;
-
- /* ynL+= ((-B1 * y(n-1)L ) ) */
- templ = pBiquadState->pDelays[4] * pBiquadState->coefs[2];
- ynL += templ;
-
- /* ynLO= ((Gain * ynL )) */
- ynLO = ynL * pBiquadState->coefs[3];
-
- /* ynLO=( ynLO + x(n)L )*/
- ynLO += (*pDataIn);
-
- /**************************************************************************
- PROCESSING OF THE RIGHT CHANNEL
- ***************************************************************************/
- /* ynR= (A0 * (x(n)R - x(n-2)R ) ) */
- templ = (*(pDataIn + 1)) - pBiquadState->pDelays[3];
- ynR = templ * pBiquadState->coefs[0];
-
- /* ynR+= ((-B2 * y(n-2)R ) ) */
- templ = pBiquadState->pDelays[7] * pBiquadState->coefs[1];
- ynR += templ;
-
- /* ynR+= ((-B1 * y(n-1)R ) ) */
- templ = pBiquadState->pDelays[5] * pBiquadState->coefs[2];
- ynR += templ;
-
- /* ynRO= ((Gain * ynR )) */
- ynRO = ynR * pBiquadState->coefs[3];
-
- /* ynRO=( ynRO + x(n)R )*/
- ynRO += (*(pDataIn+1));
-
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[7] = pBiquadState->pDelays[5]; /* y(n-2)R=y(n-1)R*/
- pBiquadState->pDelays[6] = pBiquadState->pDelays[4]; /* y(n-2)L=y(n-1)L*/
- pBiquadState->pDelays[3] = pBiquadState->pDelays[1]; /* x(n-2)R=x(n-1)R*/
- pBiquadState->pDelays[2] = pBiquadState->pDelays[0]; /* x(n-2)L=x(n-1)L*/
- pBiquadState->pDelays[5] = ynR; /* Update y(n-1)R */
- pBiquadState->pDelays[4] = ynL; /* Update y(n-1)L */
- pBiquadState->pDelays[0] = (*pDataIn); /* Update x(n-1)L */
- pDataIn++;
- pBiquadState->pDelays[1] = (*pDataIn); /* Update x(n-1)R */
- pDataIn++;
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut = ynLO; /* Write Left output*/
- pDataOut++;
- *pDataOut = ynRO; /* Write Right ouput*/
- pDataOut++;
-
- }
-
- }
-
-#ifdef SUPPORT_MC
-/**************************************************************************
-DELAYS-
-pBiquadState->pDelays[0] to
-pBiquadState->pDelays[NrChannels - 1] is x(n-1) for all NrChannels
-
-pBiquadState->pDelays[NrChannels] to
-pBiquadState->pDelays[2*NrChannels - 1] is x(n-2) for all NrChannels
-
-pBiquadState->pDelays[2*NrChannels] to
-pBiquadState->pDelays[3*NrChannels - 1] is y(n-1) for all NrChannels
-
-pBiquadState->pDelays[3*NrChannels] to
-pBiquadState->pDelays[4*NrChannels - 1] is y(n-2) for all NrChannels
-***************************************************************************/
-
-void PK_Mc_D32F32C14G11_TRC_WRA_01 (Biquad_FLOAT_Instance_t *pInstance,
- LVM_FLOAT *pDataIn,
- LVM_FLOAT *pDataOut,
- LVM_INT16 NrFrames,
- LVM_INT16 NrChannels)
- {
- LVM_FLOAT yn, ynO, temp;
- LVM_INT16 ii, jj;
- PFilter_State_Float pBiquadState = (PFilter_State_Float) pInstance;
-
- for (ii = NrFrames; ii != 0; ii--)
- {
-
- for (jj = 0; jj < NrChannels; jj++)
- {
- /**************************************************************************
- PROCESSING OF THE jj CHANNEL
- ***************************************************************************/
- /* yn= (A0 * (x(n) - x(n-2)))*/
- temp = (*pDataIn) - pBiquadState->pDelays[NrChannels + jj];
- yn = temp * pBiquadState->coefs[0];
-
- /* yn+= ((-B2 * y(n-2))) */
- temp = pBiquadState->pDelays[NrChannels*3 + jj] * pBiquadState->coefs[1];
- yn += temp;
-
- /* yn+= ((-B1 * y(n-1))) */
- temp = pBiquadState->pDelays[NrChannels*2 + jj] * pBiquadState->coefs[2];
- yn += temp;
-
- /* ynO= ((Gain * yn)) */
- ynO = yn * pBiquadState->coefs[3];
-
- /* ynO=(ynO + x(n))*/
- ynO += (*pDataIn);
-
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[NrChannels * 3 + jj] =
- pBiquadState->pDelays[NrChannels * 2 + jj]; /* y(n-2)=y(n-1)*/
- pBiquadState->pDelays[NrChannels * 1 + jj] =
- pBiquadState->pDelays[jj]; /* x(n-2)=x(n-1)*/
- pBiquadState->pDelays[NrChannels * 2 + jj] = yn; /* Update y(n-1) */
- pBiquadState->pDelays[jj] = (*pDataIn); /* Update x(n-1)*/
- pDataIn++;
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut = ynO; /* Write output*/
- pDataOut++;
- }
- }
-
- }
-#endif
-#else
-void PK_2I_D32F32C14G11_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
- LVM_INT32 *pDataIn,
- LVM_INT32 *pDataOut,
- LVM_INT16 NrSamples)
- {
- LVM_INT32 ynL,ynR,ynLO,ynRO,templ;
- LVM_INT16 ii;
- PFilter_State pBiquadState = (PFilter_State) pInstance;
-
- for (ii = NrSamples; ii != 0; ii--)
- {
-
-
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
- /* ynL= (A0 (Q14) * (x(n)L (Q0) - x(n-2)L (Q0) ) >>14) in Q0*/
- templ=(*pDataIn)-pBiquadState->pDelays[2];
- MUL32x16INTO32(templ,pBiquadState->coefs[0],ynL,14)
-
- /* ynL+= ((-B2 (Q14) * y(n-2)L (Q0) ) >>14) in Q0*/
- MUL32x16INTO32(pBiquadState->pDelays[6],pBiquadState->coefs[1],templ,14)
- ynL+=templ;
-
- /* ynL+= ((-B1 (Q14) * y(n-1)L (Q0) ) >>14) in Q0 */
- MUL32x16INTO32(pBiquadState->pDelays[4],pBiquadState->coefs[2],templ,14)
- ynL+=templ;
-
- /* ynLO= ((Gain (Q11) * ynL (Q0))>>11) in Q0*/
- MUL32x16INTO32(ynL,pBiquadState->coefs[3],ynLO,11)
-
- /* ynLO=( ynLO(Q0) + x(n)L (Q0) ) in Q0*/
- ynLO+= (*pDataIn);
-
- /**************************************************************************
- PROCESSING OF THE RIGHT CHANNEL
- ***************************************************************************/
- /* ynR= (A0 (Q14) * (x(n)R (Q0) - x(n-2)R (Q0) ) >>14) in Q0*/
- templ=(*(pDataIn+1))-pBiquadState->pDelays[3];
- MUL32x16INTO32(templ,pBiquadState->coefs[0],ynR,14)
-
- /* ynR+= ((-B2 (Q14) * y(n-2)R (Q0) ) >>14) in Q0*/
- MUL32x16INTO32(pBiquadState->pDelays[7],pBiquadState->coefs[1],templ,14)
- ynR+=templ;
-
- /* ynR+= ((-B1 (Q14) * y(n-1)R (Q0) ) >>14) in Q0 */
- MUL32x16INTO32(pBiquadState->pDelays[5],pBiquadState->coefs[2],templ,14)
- ynR+=templ;
-
- /* ynRO= ((Gain (Q11) * ynR (Q0))>>11) in Q0*/
- MUL32x16INTO32(ynR,pBiquadState->coefs[3],ynRO,11)
-
- /* ynRO=( ynRO(Q0) + x(n)R (Q0) ) in Q0*/
- ynRO+= (*(pDataIn+1));
-
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[7]=pBiquadState->pDelays[5]; /* y(n-2)R=y(n-1)R*/
- pBiquadState->pDelays[6]=pBiquadState->pDelays[4]; /* y(n-2)L=y(n-1)L*/
- pBiquadState->pDelays[3]=pBiquadState->pDelays[1]; /* x(n-2)R=x(n-1)R*/
- pBiquadState->pDelays[2]=pBiquadState->pDelays[0]; /* x(n-2)L=x(n-1)L*/
- pBiquadState->pDelays[5]=ynR; /* Update y(n-1)R in Q0*/
- pBiquadState->pDelays[4]=ynL; /* Update y(n-1)L in Q0*/
- pBiquadState->pDelays[0]=(*pDataIn); /* Update x(n-1)L in Q0*/
- pDataIn++;
- pBiquadState->pDelays[1]=(*pDataIn); /* Update x(n-1)R in Q0*/
- pDataIn++;
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut=ynLO; /* Write Left output in Q0*/
- pDataOut++;
- *pDataOut=ynRO; /* Write Right ouput in Q0*/
- pDataOut++;
-
- }
-
- }
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32C14G11_TRC_WRA_01.cpp b/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32C14G11_TRC_WRA_01.cpp
new file mode 100644
index 0000000..3f62f99
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32C14G11_TRC_WRA_01.cpp
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BIQUAD.h"
+#include "PK_2I_D32F32CssGss_TRC_WRA_01_Private.h"
+#include "LVM_Macros.h"
+
+/**************************************************************************
+ ASSUMPTIONS:
+ COEFS-
+ pBiquadState->coefs[0] is A0,
+ pBiquadState->coefs[1] is -B2,
+ pBiquadState->coefs[2] is -B1, these are in Q14 format
+ pBiquadState->coefs[3] is Gain, in Q11 format
+
+ DELAYS-
+ pBiquadState->pDelays[0] is x(n-1)L in Q0 format
+ pBiquadState->pDelays[1] is x(n-1)R in Q0 format
+ pBiquadState->pDelays[2] is x(n-2)L in Q0 format
+ pBiquadState->pDelays[3] is x(n-2)R in Q0 format
+ pBiquadState->pDelays[4] is y(n-1)L in Q0 format
+ pBiquadState->pDelays[5] is y(n-1)R in Q0 format
+ pBiquadState->pDelays[6] is y(n-2)L in Q0 format
+ pBiquadState->pDelays[7] is y(n-2)R in Q0 format
+***************************************************************************/
+void PK_2I_D32F32C14G11_TRC_WRA_01 ( Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrSamples)
+ {
+ LVM_FLOAT ynL,ynR,ynLO,ynRO,templ;
+ LVM_INT16 ii;
+ PFilter_State_Float pBiquadState = (PFilter_State_Float) pInstance;
+
+ for (ii = NrSamples; ii != 0; ii--)
+ {
+
+ /**************************************************************************
+ PROCESSING OF THE LEFT CHANNEL
+ ***************************************************************************/
+ /* ynL= (A0 * (x(n)L - x(n-2)L ) )*/
+ templ = (*pDataIn) - pBiquadState->pDelays[2];
+ ynL = templ * pBiquadState->coefs[0];
+
+ /* ynL+= ((-B2 * y(n-2)L )) */
+ templ = pBiquadState->pDelays[6] * pBiquadState->coefs[1];
+ ynL += templ;
+
+ /* ynL+= ((-B1 * y(n-1)L ) ) */
+ templ = pBiquadState->pDelays[4] * pBiquadState->coefs[2];
+ ynL += templ;
+
+ /* ynLO= ((Gain * ynL )) */
+ ynLO = ynL * pBiquadState->coefs[3];
+
+ /* ynLO=( ynLO + x(n)L )*/
+ ynLO += (*pDataIn);
+
+ /**************************************************************************
+ PROCESSING OF THE RIGHT CHANNEL
+ ***************************************************************************/
+ /* ynR= (A0 * (x(n)R - x(n-2)R ) ) */
+ templ = (*(pDataIn + 1)) - pBiquadState->pDelays[3];
+ ynR = templ * pBiquadState->coefs[0];
+
+ /* ynR+= ((-B2 * y(n-2)R ) ) */
+ templ = pBiquadState->pDelays[7] * pBiquadState->coefs[1];
+ ynR += templ;
+
+ /* ynR+= ((-B1 * y(n-1)R ) ) */
+ templ = pBiquadState->pDelays[5] * pBiquadState->coefs[2];
+ ynR += templ;
+
+ /* ynRO= ((Gain * ynR )) */
+ ynRO = ynR * pBiquadState->coefs[3];
+
+ /* ynRO=( ynRO + x(n)R )*/
+ ynRO += (*(pDataIn+1));
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[7] = pBiquadState->pDelays[5]; /* y(n-2)R=y(n-1)R*/
+ pBiquadState->pDelays[6] = pBiquadState->pDelays[4]; /* y(n-2)L=y(n-1)L*/
+ pBiquadState->pDelays[3] = pBiquadState->pDelays[1]; /* x(n-2)R=x(n-1)R*/
+ pBiquadState->pDelays[2] = pBiquadState->pDelays[0]; /* x(n-2)L=x(n-1)L*/
+ pBiquadState->pDelays[5] = ynR; /* Update y(n-1)R */
+ pBiquadState->pDelays[4] = ynL; /* Update y(n-1)L */
+ pBiquadState->pDelays[0] = (*pDataIn); /* Update x(n-1)L */
+ pDataIn++;
+ pBiquadState->pDelays[1] = (*pDataIn); /* Update x(n-1)R */
+ pDataIn++;
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+ *pDataOut = ynLO; /* Write Left output*/
+ pDataOut++;
+ *pDataOut = ynRO; /* Write Right ouput*/
+ pDataOut++;
+
+ }
+
+ }
+
+#ifdef SUPPORT_MC
+/**************************************************************************
+DELAYS-
+pBiquadState->pDelays[0] to
+pBiquadState->pDelays[NrChannels - 1] is x(n-1) for all NrChannels
+
+pBiquadState->pDelays[NrChannels] to
+pBiquadState->pDelays[2*NrChannels - 1] is x(n-2) for all NrChannels
+
+pBiquadState->pDelays[2*NrChannels] to
+pBiquadState->pDelays[3*NrChannels - 1] is y(n-1) for all NrChannels
+
+pBiquadState->pDelays[3*NrChannels] to
+pBiquadState->pDelays[4*NrChannels - 1] is y(n-2) for all NrChannels
+***************************************************************************/
+
+void PK_Mc_D32F32C14G11_TRC_WRA_01 (Biquad_FLOAT_Instance_t *pInstance,
+ LVM_FLOAT *pDataIn,
+ LVM_FLOAT *pDataOut,
+ LVM_INT16 NrFrames,
+ LVM_INT16 NrChannels)
+ {
+ LVM_FLOAT yn, ynO, temp;
+ LVM_INT16 ii, jj;
+ PFilter_State_Float pBiquadState = (PFilter_State_Float) pInstance;
+
+ for (ii = NrFrames; ii != 0; ii--)
+ {
+
+ for (jj = 0; jj < NrChannels; jj++)
+ {
+ /**************************************************************************
+ PROCESSING OF THE jj CHANNEL
+ ***************************************************************************/
+ /* yn= (A0 * (x(n) - x(n-2)))*/
+ temp = (*pDataIn) - pBiquadState->pDelays[NrChannels + jj];
+ yn = temp * pBiquadState->coefs[0];
+
+ /* yn+= ((-B2 * y(n-2))) */
+ temp = pBiquadState->pDelays[NrChannels*3 + jj] * pBiquadState->coefs[1];
+ yn += temp;
+
+ /* yn+= ((-B1 * y(n-1))) */
+ temp = pBiquadState->pDelays[NrChannels*2 + jj] * pBiquadState->coefs[2];
+ yn += temp;
+
+ /* ynO= ((Gain * yn)) */
+ ynO = yn * pBiquadState->coefs[3];
+
+ /* ynO=(ynO + x(n))*/
+ ynO += (*pDataIn);
+
+ /**************************************************************************
+ UPDATING THE DELAYS
+ ***************************************************************************/
+ pBiquadState->pDelays[NrChannels * 3 + jj] =
+ pBiquadState->pDelays[NrChannels * 2 + jj]; /* y(n-2)=y(n-1)*/
+ pBiquadState->pDelays[NrChannels * 1 + jj] =
+ pBiquadState->pDelays[jj]; /* x(n-2)=x(n-1)*/
+ pBiquadState->pDelays[NrChannels * 2 + jj] = yn; /* Update y(n-1) */
+ pBiquadState->pDelays[jj] = (*pDataIn); /* Update x(n-1)*/
+ pDataIn++;
+
+ /**************************************************************************
+ WRITING THE OUTPUT
+ ***************************************************************************/
+ *pDataOut = ynO; /* Write output*/
+ pDataOut++;
+ }
+ }
+
+ }
+#endif
diff --git a/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32C30G11_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32C30G11_TRC_WRA_01.c
deleted file mode 100644
index f705cbf..0000000
--- a/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32C30G11_TRC_WRA_01.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BIQUAD.h"
-#include "PK_2I_D32F32CllGss_TRC_WRA_01_Private.h"
-#include "LVM_Macros.h"
-
-/**************************************************************************
- ASSUMPTIONS:
- COEFS-
- pBiquadState->coefs[0] is A0,
- pBiquadState->coefs[1] is -B2,
- pBiquadState->coefs[2] is -B1, these are in Q30 format
- pBiquadState->coefs[3] is Gain, in Q11 format
-
-
- DELAYS-
- pBiquadState->pDelays[0] is x(n-1)L in Q0 format
- pBiquadState->pDelays[1] is x(n-1)R in Q0 format
- pBiquadState->pDelays[2] is x(n-2)L in Q0 format
- pBiquadState->pDelays[3] is x(n-2)R in Q0 format
- pBiquadState->pDelays[4] is y(n-1)L in Q0 format
- pBiquadState->pDelays[5] is y(n-1)R in Q0 format
- pBiquadState->pDelays[6] is y(n-2)L in Q0 format
- pBiquadState->pDelays[7] is y(n-2)R in Q0 format
-***************************************************************************/
-#ifndef BUILD_FLOAT
-void PK_2I_D32F32C30G11_TRC_WRA_01 ( Biquad_Instance_t *pInstance,
- LVM_INT32 *pDataIn,
- LVM_INT32 *pDataOut,
- LVM_INT16 NrSamples)
- {
- LVM_INT32 ynL,ynR,ynLO,ynRO,templ;
- LVM_INT16 ii;
- PFilter_State pBiquadState = (PFilter_State) pInstance;
-
- for (ii = NrSamples; ii != 0; ii--)
- {
-
-
- /**************************************************************************
- PROCESSING OF THE LEFT CHANNEL
- ***************************************************************************/
- /* ynL= (A0 (Q30) * (x(n)L (Q0) - x(n-2)L (Q0) ) >>30) in Q0*/
- templ=(*pDataIn)-pBiquadState->pDelays[2];
- MUL32x32INTO32(templ,pBiquadState->coefs[0],ynL,30)
-
- /* ynL+= ((-B2 (Q30) * y(n-2)L (Q0) ) >>30) in Q0*/
- MUL32x32INTO32(pBiquadState->pDelays[6],pBiquadState->coefs[1],templ,30)
- ynL+=templ;
-
- /* ynL+= ((-B1 (Q30) * y(n-1)L (Q0) ) >>30) in Q0 */
- MUL32x32INTO32(pBiquadState->pDelays[4],pBiquadState->coefs[2],templ,30)
- ynL+=templ;
-
- /* ynLO= ((Gain (Q11) * ynL (Q0))>>11) in Q0*/
- MUL32x16INTO32(ynL,pBiquadState->coefs[3],ynLO,11)
- /* ynLO=( ynLO(Q0) + x(n)L (Q0) ) in Q0*/
- ynLO+= (*pDataIn);
-
- /**************************************************************************
- PROCESSING OF THE RIGHT CHANNEL
- ***************************************************************************/
- /* ynR= (A0 (Q30) * (x(n)R (Q0) - x(n-2)R (Q0) ) >>30) in Q0*/
- templ=(*(pDataIn+1))-pBiquadState->pDelays[3];
- MUL32x32INTO32(templ,pBiquadState->coefs[0],ynR,30)
-
- /* ynR+= ((-B2 (Q30) * y(n-2)R (Q0) ) >>30) in Q0*/
- MUL32x32INTO32(pBiquadState->pDelays[7],pBiquadState->coefs[1],templ,30)
- ynR+=templ;
-
- /* ynR+= ((-B1 (Q30) * y(n-1)R (Q0) ) >>30) in Q0 */
- MUL32x32INTO32(pBiquadState->pDelays[5],pBiquadState->coefs[2],templ,30)
- ynR+=templ;
-
- /* ynRO= ((Gain (Q11) * ynR (Q0))>>11) in Q0*/
- MUL32x16INTO32(ynR,pBiquadState->coefs[3],ynRO,11)
-
- /* ynRO=( ynRO(Q0) + x(n)R (Q0) ) in Q0*/
- ynRO+= (*(pDataIn+1));
-
- /**************************************************************************
- UPDATING THE DELAYS
- ***************************************************************************/
- pBiquadState->pDelays[7]=pBiquadState->pDelays[5]; /* y(n-2)R=y(n-1)R*/
- pBiquadState->pDelays[6]=pBiquadState->pDelays[4]; /* y(n-2)L=y(n-1)L*/
- pBiquadState->pDelays[3]=pBiquadState->pDelays[1]; /* x(n-2)R=x(n-1)R*/
- pBiquadState->pDelays[2]=pBiquadState->pDelays[0]; /* x(n-2)L=x(n-1)L*/
- pBiquadState->pDelays[5]=ynR; /* Update y(n-1)R in Q0*/
- pBiquadState->pDelays[4]=ynL; /* Update y(n-1)L in Q0*/
- pBiquadState->pDelays[0]=(*pDataIn); /* Update x(n-1)L in Q0*/
- pDataIn++;
- pBiquadState->pDelays[1]=(*pDataIn); /* Update x(n-1)R in Q0*/
- pDataIn++;
-
- /**************************************************************************
- WRITING THE OUTPUT
- ***************************************************************************/
- *pDataOut=ynLO; /* Write Left output in Q0*/
- pDataOut++;
- *pDataOut=ynRO; /* Write Right ouput in Q0*/
- pDataOut++;
- }
-
- }
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32C30G11_TRC_WRA_01.cpp b/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32C30G11_TRC_WRA_01.cpp
new file mode 100644
index 0000000..41de1de
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32C30G11_TRC_WRA_01.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BIQUAD.h"
+#include "PK_2I_D32F32CllGss_TRC_WRA_01_Private.h"
+#include "LVM_Macros.h"
+
+/**************************************************************************
+ ASSUMPTIONS:
+ COEFS-
+ pBiquadState->coefs[0] is A0,
+ pBiquadState->coefs[1] is -B2,
+ pBiquadState->coefs[2] is -B1, these are in Q30 format
+ pBiquadState->coefs[3] is Gain, in Q11 format
+
+ DELAYS-
+ pBiquadState->pDelays[0] is x(n-1)L in Q0 format
+ pBiquadState->pDelays[1] is x(n-1)R in Q0 format
+ pBiquadState->pDelays[2] is x(n-2)L in Q0 format
+ pBiquadState->pDelays[3] is x(n-2)R in Q0 format
+ pBiquadState->pDelays[4] is y(n-1)L in Q0 format
+ pBiquadState->pDelays[5] is y(n-1)R in Q0 format
+ pBiquadState->pDelays[6] is y(n-2)L in Q0 format
+ pBiquadState->pDelays[7] is y(n-2)R in Q0 format
+***************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32CllGss_TRC_WRA_01_Init.c b/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32CllGss_TRC_WRA_01_Init.c
deleted file mode 100644
index 65475a3..0000000
--- a/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32CllGss_TRC_WRA_01_Init.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BIQUAD.h"
-#include "PK_2I_D32F32CllGss_TRC_WRA_01_Private.h"
-
-#ifndef BUILD_FLOAT
-void PK_2I_D32F32CllGss_TRC_WRA_01_Init(Biquad_Instance_t *pInstance,
- Biquad_2I_Order2_Taps_t *pTaps,
- PK_C32_Coefs_t *pCoef)
-{
- PFilter_State pBiquadState = (PFilter_State) pInstance;
- pBiquadState->pDelays =(LVM_INT32 *) pTaps;
-
- pBiquadState->coefs[0]=pCoef->A0;
-
- pBiquadState->coefs[1]=pCoef->B2;
-
- pBiquadState->coefs[2]=pCoef->B1;
-
- pBiquadState->coefs[3]=pCoef->G;
-
-}
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32CllGss_TRC_WRA_01_Init.cpp b/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32CllGss_TRC_WRA_01_Init.cpp
new file mode 100644
index 0000000..714aa52
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32CllGss_TRC_WRA_01_Init.cpp
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BIQUAD.h"
+#include "PK_2I_D32F32CllGss_TRC_WRA_01_Private.h"
+
diff --git a/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32CssGss_TRC_WRA_01_Init.c b/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32CssGss_TRC_WRA_01_Init.c
deleted file mode 100644
index a36330e..0000000
--- a/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32CssGss_TRC_WRA_01_Init.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BIQUAD.h"
-#include "PK_2I_D32F32CssGss_TRC_WRA_01_Private.h"
-#ifdef BUILD_FLOAT
-void PK_2I_D32F32CssGss_TRC_WRA_01_Init(Biquad_FLOAT_Instance_t *pInstance,
- Biquad_2I_Order2_FLOAT_Taps_t *pTaps,
- PK_FLOAT_Coefs_t *pCoef)
-{
- PFilter_State_Float pBiquadState = (PFilter_State_Float) pInstance;
- pBiquadState->pDelays = (LVM_FLOAT *) pTaps;
-
- pBiquadState->coefs[0] = pCoef->A0;
-
- pBiquadState->coefs[1] = pCoef->B2;
-
- pBiquadState->coefs[2] = pCoef->B1;
-
- pBiquadState->coefs[3] = pCoef->G;
-}
-#else
-void PK_2I_D32F32CssGss_TRC_WRA_01_Init(Biquad_Instance_t *pInstance,
- Biquad_2I_Order2_Taps_t *pTaps,
- PK_C16_Coefs_t *pCoef)
-{
- PFilter_State pBiquadState = (PFilter_State) pInstance;
- pBiquadState->pDelays =(LVM_INT32 *) pTaps;
-
- pBiquadState->coefs[0]=pCoef->A0;
-
- pBiquadState->coefs[1]=pCoef->B2;
-
- pBiquadState->coefs[2]=pCoef->B1;
-
- pBiquadState->coefs[3]=pCoef->G;
-
-}
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32CssGss_TRC_WRA_01_Init.cpp b/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32CssGss_TRC_WRA_01_Init.cpp
new file mode 100644
index 0000000..f6c05da
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32CssGss_TRC_WRA_01_Init.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BIQUAD.h"
+#include "PK_2I_D32F32CssGss_TRC_WRA_01_Private.h"
+void PK_2I_D32F32CssGss_TRC_WRA_01_Init(Biquad_FLOAT_Instance_t *pInstance,
+ Biquad_2I_Order2_FLOAT_Taps_t *pTaps,
+ PK_FLOAT_Coefs_t *pCoef)
+{
+ PFilter_State_Float pBiquadState = (PFilter_State_Float) pInstance;
+ pBiquadState->pDelays = (LVM_FLOAT *) pTaps;
+
+ pBiquadState->coefs[0] = pCoef->A0;
+
+ pBiquadState->coefs[1] = pCoef->B2;
+
+ pBiquadState->coefs[2] = pCoef->B1;
+
+ pBiquadState->coefs[3] = pCoef->G;
+}
diff --git a/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32CssGss_TRC_WRA_01_Private.h b/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32CssGss_TRC_WRA_01_Private.h
index 1e32062..cc924c4 100644
--- a/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32CssGss_TRC_WRA_01_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32CssGss_TRC_WRA_01_Private.h
@@ -18,11 +18,9 @@
#ifndef _PK_2I_D32F32CSSGSS_TRC_WRA_01_PRIVATE_H_
#define _PK_2I_D32F32CSSGSS_TRC_WRA_01_PRIVATE_H_
-
/* The internal state variables are implemented in a (for the user) hidden structure */
/* In this (private) file, the internal structure is declared fro private use. */
-#ifdef BUILD_FLOAT
typedef struct _Filter_State_Float_
{
LVM_FLOAT * pDelays; /* pointer to the delayed samples (data of 32 bits) */
@@ -30,7 +28,6 @@
}Filter_State_Float;
typedef Filter_State_Float * PFilter_State_Float ;
-#endif
typedef struct _Filter_State_
{
LVM_INT32 * pDelays; /* pointer to the delayed samples (data of 32 bits) */
diff --git a/media/libeffects/lvm/lib/Common/src/Shift_Sat_v16xv16.c b/media/libeffects/lvm/lib/Common/src/Shift_Sat_v16xv16.c
deleted file mode 100644
index 28fea65..0000000
--- a/media/libeffects/lvm/lib/Common/src/Shift_Sat_v16xv16.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**********************************************************************************
- INCLUDE FILES
-***********************************************************************************/
-
-#include "VectorArithmetic.h"
-
-/**********************************************************************************
- FUNCTION Shift_Sat_v16xv16
-***********************************************************************************/
-#ifndef BUILD_FLOAT
-void Shift_Sat_v16xv16 (const LVM_INT16 val,
- const LVM_INT16 *src,
- LVM_INT16 *dst,
- LVM_INT16 n)
-{
- LVM_INT32 temp;
- LVM_INT32 ii;
- LVM_INT16 RShift;
- if(val>0)
- {
- for (ii = n; ii != 0; ii--)
- {
- temp = (LVM_INT32)*src;
- src++;
-
- temp = temp << val;
-
- if (temp > 0x00007FFF)
- {
- *dst = 0x7FFF;
- }
- else if (temp < -0x00008000)
- {
- *dst = - 0x8000;
- }
- else
- {
- *dst = (LVM_INT16)temp;
- }
- dst++;
- }
- }
- else if(val<0)
- {
- RShift=(LVM_INT16)(-val);
-
- for (ii = n; ii != 0; ii--)
- {
- *dst = (LVM_INT16)(*src >> RShift);
- dst++;
- src++;
- }
- }
- else
- {
- if(src!=dst)
- {
- Copy_16(src,dst,n);
- }
- }
- return;
-}
-#endif
-/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/Shift_Sat_v16xv16.cpp b/media/libeffects/lvm/lib/Common/src/Shift_Sat_v16xv16.cpp
new file mode 100644
index 0000000..668a4b6
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/Shift_Sat_v16xv16.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**********************************************************************************
+ INCLUDE FILES
+***********************************************************************************/
+
+#include "VectorArithmetic.h"
+
+/**********************************************************************************
+ FUNCTION Shift_Sat_v16xv16
+***********************************************************************************/
+/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/Shift_Sat_v32xv32.c b/media/libeffects/lvm/lib/Common/src/Shift_Sat_v32xv32.c
deleted file mode 100644
index fac9de7..0000000
--- a/media/libeffects/lvm/lib/Common/src/Shift_Sat_v32xv32.c
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**********************************************************************************
- INCLUDE FILES
-***********************************************************************************/
-
-#include "VectorArithmetic.h"
-
-/**********************************************************************************
- FUNCTION Shift_Sat_v32xv32
-***********************************************************************************/
-#ifdef BUILD_FLOAT
-void Shift_Sat_Float (const LVM_INT16 val,
- const LVM_FLOAT *src,
- LVM_FLOAT *dst,
- LVM_INT16 n)
-{
- LVM_FLOAT temp;
- LVM_INT32 ii,ij;
- LVM_INT16 RShift;
-
- if(val > 0)
- {
- for (ii = n; ii != 0; ii--)
- {
- temp = (LVM_FLOAT)*src;
- src++;
- for(ij = 0; ij < val; ij++)
- {
- temp = temp * 2;
- }
-
- if(temp > 1.0)
- temp = 1.0;
- if(temp < -1.0)
- temp = -1.0;
-
- *dst = (LVM_FLOAT)temp;
- dst++;
- }
- }
- else if(val < 0)
- {
- RShift=(LVM_INT16)(-val);
-
- for (ii = n; ii != 0; ii--)
- {
- temp = (LVM_FLOAT)*src;
- src++;
- for(ij = 0; ij < RShift; ij++)
- {
- temp = temp / 2;
- }
- *dst = (LVM_FLOAT)temp;
- dst++;
- }
- }
- else
- {
- if(src != dst)
- {
- Copy_Float(src, dst, n);
- }
- }
- return;
-}
-#else
-void Shift_Sat_v32xv32 (const LVM_INT16 val,
- const LVM_INT32 *src,
- LVM_INT32 *dst,
- LVM_INT16 n)
-{
- LVM_INT32 ii;
- LVM_INT16 RShift;
-
- if(val>0)
- {
- LVM_INT32 a,b;
-
- for (ii = n; ii != 0; ii--)
- {
- a=*src;
- src++;
-
- b=(a<<val);
-
- if( (b>>val) != a ) /* if overflow occured, right shift will show difference*/
- {
- if(a<0)
- {
- b=0x80000000l;
- }
- else
- {
- b=0x7FFFFFFFl;
- }
- }
-
- *dst = b;
- dst++;
- }
- }
- else if(val<0)
- {
- RShift=(LVM_INT16)(-val);
- for (ii = n; ii != 0; ii--)
- {
- *dst = (*src >> RShift);
- dst++;
- src++;
- }
- }
- else
- {
- if(src!=dst)
- {
- Copy_16((LVM_INT16 *)src,(LVM_INT16 *)dst,(LVM_INT16)(n<<1));
- }
- }
- return;
-}
-#endif
-/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/Shift_Sat_v32xv32.cpp b/media/libeffects/lvm/lib/Common/src/Shift_Sat_v32xv32.cpp
new file mode 100644
index 0000000..97a04c1
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/Shift_Sat_v32xv32.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**********************************************************************************
+ INCLUDE FILES
+***********************************************************************************/
+
+#include "VectorArithmetic.h"
+
+/**********************************************************************************
+ FUNCTION Shift_Sat_v32xv32
+***********************************************************************************/
+void Shift_Sat_Float (const LVM_INT16 val,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 n)
+{
+ LVM_FLOAT temp;
+ LVM_INT32 ii,ij;
+ LVM_INT16 RShift;
+
+ if(val > 0)
+ {
+ for (ii = n; ii != 0; ii--)
+ {
+ temp = (LVM_FLOAT)*src;
+ src++;
+ for(ij = 0; ij < val; ij++)
+ {
+ temp = temp * 2;
+ }
+
+ if(temp > 1.0)
+ temp = 1.0;
+ if(temp < -1.0)
+ temp = -1.0;
+
+ *dst = (LVM_FLOAT)temp;
+ dst++;
+ }
+ }
+ else if(val < 0)
+ {
+ RShift=(LVM_INT16)(-val);
+
+ for (ii = n; ii != 0; ii--)
+ {
+ temp = (LVM_FLOAT)*src;
+ src++;
+ for(ij = 0; ij < RShift; ij++)
+ {
+ temp = temp / 2;
+ }
+ *dst = (LVM_FLOAT)temp;
+ dst++;
+ }
+ }
+ else
+ {
+ if(src != dst)
+ {
+ Copy_Float(src, dst, n);
+ }
+ }
+ return;
+}
+/**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/dB_to_Lin32.c b/media/libeffects/lvm/lib/Common/src/dB_to_Lin32.c
deleted file mode 100644
index 9a726f2..0000000
--- a/media/libeffects/lvm/lib/Common/src/dB_to_Lin32.c
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/************************************************************************/
-/* */
-/* %created_by: sra % (CM/S)*/
-/* %name: dB_to_Lin32.c % (CM/S)*/
-/* %version: 2 % (CM/S)*/
-/* %date_created: Wed Jun 18 11:27:46 2008 % (CM/S)*/
-/* */
-/************************************************************************/
-
-/*######################################################################################*/
-/* Include files */
-/*######################################################################################*/
-
-#include "ScalarArithmetic.h"
-#ifdef BUILD_FLOAT
-#include <math.h>
-#endif
-
-
-/****************************************************************************************
- * Name : dB_to_Lin32()
- * Input : Signed 16-bit integer
- * MSB (16) = sign bit
- * (15->05) = integer part
- * (04->01) = decimal part
- * Output : Signed 32-bit integer
- * MSB (32) = sign bit
- * (31->16) = integer part
- * (15->01) = decimal part
- * Returns : Lin value format 1.16.15
- * Description :
- * Remarks : Makes an approximation to the conversion by counting the number
- * of 6dB steps for use as shifts and then interpolates with a remainder
- * with the equation:
- *
- * Correction = (Remainder / 1.5029) - (Remainder^2 / 6)
- *
- * The two coefficients are scaled from 0x40000000 in 96 steps and calculated
- * as follows:
- *
- * FIRST_COEF = 0x80000000 / (96 * 1.5029)
- * SECOND_COEF = 0x80000000 / (96^2 * 6)
- *
- ****************************************************************************************/
-
-#define FOUR_OVER_SIX 21846 /* (4 / 6) * 2^15 */
-#define SIX_DB 96 /* 6 * 16 or 6dB in Q11.4 format */
-#define FIRST_COEF_NEG 14884305
-#define FIRST_COEF_POS 7442152 /* FIRST_COEF_NEG / 2 */
-#define SECOND_COEF 38836
-#define MAX_VALUE 1536 /* 96 * 16 */
-
-#ifdef BUILD_FLOAT
-LVM_FLOAT dB_to_LinFloat(LVM_INT16 db_fix)
-{
- LVM_FLOAT dB_Float;
- LVM_FLOAT LinFloat;
-
- dB_Float = (LVM_FLOAT)((LVM_FLOAT)db_fix / 16.0f);
- LinFloat = pow(10, dB_Float / 20.0);
-
- return LinFloat;
-}
-#else
-LVM_INT32 dB_to_Lin32(LVM_INT16 db_fix)
-{
- LVM_INT32 Lin_val_32;
- LVM_INT16 Shift;
- LVM_INT32 Remain;
-
-
- /*
- * Check sign of the input
- */
- if (db_fix<0)
- {
- if (db_fix > -MAX_VALUE)
- {
- Shift = (LVM_INT16)((((LVM_UINT32)(-db_fix) >> 4) * FOUR_OVER_SIX) >> 17); /* Number of 6dB steps in Q11.4 format */
- Remain = -db_fix - (Shift * SIX_DB);
- Remain = (0x7FFFFFFF - (Remain * FIRST_COEF_NEG)) + (Remain * Remain * SECOND_COEF);
- Lin_val_32 = (LVM_INT32)((LVM_UINT32)Remain >> (16 + Shift));
- }
- else
- {
- Lin_val_32 = 0;
- }
- }
- else
- {
- if (db_fix < MAX_VALUE)
- {
- Shift = (LVM_INT16)((((LVM_UINT32)db_fix >> 4) * FOUR_OVER_SIX) >> 17); /* Number of 6dB steps in Q11.4 format */
- Remain = db_fix - (Shift * SIX_DB);
- Remain = 0x3FFFFFFF + (Remain * FIRST_COEF_POS) + (Remain * Remain * SECOND_COEF);
- Lin_val_32 = (LVM_INT32)((LVM_UINT32)Remain >> (15 - Shift));
- }
- else
- {
- Lin_val_32 = 0x7FFFFFFF;
- }
- }
-
-
- return Lin_val_32; /* format 1.16.15 */
-}
-#endif
diff --git a/media/libeffects/lvm/lib/Common/src/dB_to_Lin32.cpp b/media/libeffects/lvm/lib/Common/src/dB_to_Lin32.cpp
new file mode 100644
index 0000000..4da2013
--- /dev/null
+++ b/media/libeffects/lvm/lib/Common/src/dB_to_Lin32.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/************************************************************************/
+/* */
+/* %created_by: sra % (CM/S)*/
+/* %name: dB_to_Lin32.c % (CM/S)*/
+/* %version: 2 % (CM/S)*/
+/* %date_created: Wed Jun 18 11:27:46 2008 % (CM/S)*/
+/* */
+/************************************************************************/
+
+/*######################################################################################*/
+/* Include files */
+/*######################################################################################*/
+
+#include "ScalarArithmetic.h"
+#include <math.h>
+
+/****************************************************************************************
+ * Name : dB_to_Lin32()
+ * Input : Signed 16-bit integer
+ * MSB (16) = sign bit
+ * (15->05) = integer part
+ * (04->01) = decimal part
+ * Output : Signed 32-bit integer
+ * MSB (32) = sign bit
+ * (31->16) = integer part
+ * (15->01) = decimal part
+ * Returns : Lin value format 1.16.15
+ * Description :
+ * Remarks : Makes an approximation to the conversion by counting the number
+ * of 6dB steps for use as shifts and then interpolates with a remainder
+ * with the equation:
+ *
+ * Correction = (Remainder / 1.5029) - (Remainder^2 / 6)
+ *
+ * The two coefficients are scaled from 0x40000000 in 96 steps and calculated
+ * as follows:
+ *
+ * FIRST_COEF = 0x80000000 / (96 * 1.5029)
+ * SECOND_COEF = 0x80000000 / (96^2 * 6)
+ *
+ ****************************************************************************************/
+
+#define FOUR_OVER_SIX 21846 /* (4 / 6) * 2^15 */
+#define SIX_DB 96 /* 6 * 16 or 6dB in Q11.4 format */
+#define FIRST_COEF_NEG 14884305
+#define FIRST_COEF_POS 7442152 /* FIRST_COEF_NEG / 2 */
+#define SECOND_COEF 38836
+#define MAX_VALUE 1536 /* 96 * 16 */
+
+LVM_FLOAT dB_to_LinFloat(LVM_INT16 db_fix)
+{
+ LVM_FLOAT dB_Float;
+ LVM_FLOAT LinFloat;
+
+ dB_Float = (LVM_FLOAT)((LVM_FLOAT)db_fix / 16.0f);
+ LinFloat = pow(10, dB_Float / 20.0);
+
+ return LinFloat;
+}
diff --git a/media/libeffects/lvm/lib/Common/src/mult3s_16x16.c b/media/libeffects/lvm/lib/Common/src/mult3s_16x16.cpp
similarity index 100%
rename from media/libeffects/lvm/lib/Common/src/mult3s_16x16.c
rename to media/libeffects/lvm/lib/Common/src/mult3s_16x16.cpp
diff --git a/media/libeffects/lvm/lib/Eq/lib/LVEQNB.h b/media/libeffects/lvm/lib/Eq/lib/LVEQNB.h
index 804f1bf..c5ddf77 100644
--- a/media/libeffects/lvm/lib/Eq/lib/LVEQNB.h
+++ b/media/libeffects/lvm/lib/Eq/lib/LVEQNB.h
@@ -68,15 +68,9 @@
/* */
/****************************************************************************************/
-
#ifndef __LVEQNB_H__
#define __LVEQNB_H__
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-
/****************************************************************************************/
/* */
/* Includes */
@@ -112,7 +106,6 @@
/* Instance handle */
typedef void *LVEQNB_Handle_t;
-
/* Operating modes */
typedef enum
{
@@ -121,7 +114,6 @@
LVEQNB_MODE_MAX = LVM_MAXINT_32
} LVEQNB_Mode_en;
-
/* Filter mode control */
typedef enum
{
@@ -130,7 +122,6 @@
LVEQNB_FILTER_DUMMY = LVM_MAXINT_32
} LVEQNB_FilterMode_en;
-
/* Memory Types */
typedef enum
{
@@ -141,7 +132,6 @@
LVEQNB_MEMORY_MAX = LVM_MAXINT_32
} LVEQNB_MemoryTypes_en;
-
/* Function return status */
typedef enum
{
@@ -152,7 +142,6 @@
LVEQNB_STATUS_MAX = LVM_MAXINT_32
} LVEQNB_ReturnStatus_en;
-
/****************************************************************************************/
/* */
/* Linked enumerated type and capability definitions */
@@ -190,7 +179,6 @@
LVEQNB_SOURCE_MAX = LVM_MAXINT_32
} LVEQNB_SourceFormat_en;
-
/*
* Supported sample rates in samples per second
*/
@@ -203,12 +191,10 @@
#define LVEQNB_CAP_FS_32000 64
#define LVEQNB_CAP_FS_44100 128
#define LVEQNB_CAP_FS_48000 256
-#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
#define LVEQNB_CAP_FS_88200 512
#define LVEQNB_CAP_FS_96000 1024
#define LVEQNB_CAP_FS_176400 2048
#define LVEQNB_CAP_FS_192000 4096
-#endif
typedef enum
{
@@ -221,16 +207,13 @@
LVEQNB_FS_32000 = 6,
LVEQNB_FS_44100 = 7,
LVEQNB_FS_48000 = 8,
-#ifdef HIGHER_FS
LVEQNB_FS_88200 = 9,
LVEQNB_FS_96000 = 10,
LVEQNB_FS_176400 = 11,
LVEQNB_FS_192000 = 12,
-#endif
LVEQNB_FS_MAX = LVM_MAXINT_32
} LVEQNB_Fs_en;
-
/****************************************************************************************/
/* */
/* Structures */
@@ -246,14 +229,12 @@
void *pBaseAddress; /* Pointer to the region base address */
} LVEQNB_MemoryRegion_t;
-
/* Memory table containing the region definitions */
typedef struct
{
LVEQNB_MemoryRegion_t Region[LVEQNB_NR_MEMORY_REGIONS]; /* One definition for each region */
} LVEQNB_MemTab_t;
-
/* Equaliser band definition */
typedef struct
{
@@ -262,7 +243,6 @@
LVM_UINT16 QFactor; /* Band quality factor */
} LVEQNB_BandDef_t;
-
/* Parameter structure */
typedef struct
{
@@ -279,7 +259,6 @@
#endif
} LVEQNB_Params_t;
-
/* Capability structure */
typedef struct
{
@@ -296,7 +275,6 @@
} LVEQNB_Capabilities_t;
-
/****************************************************************************************/
/* */
/* Function Prototypes */
@@ -339,7 +317,6 @@
LVEQNB_MemTab_t *pMemoryTable,
LVEQNB_Capabilities_t *pCapabilities);
-
/****************************************************************************************/
/* */
/* FUNCTION: LVEQNB_Init */
@@ -379,7 +356,6 @@
LVEQNB_MemTab_t *pMemoryTable,
LVEQNB_Capabilities_t *pCapabilities);
-
/****************************************************************************************/
/* */
/* FUNCTION: LVEQNB_GetParameters */
@@ -404,7 +380,6 @@
LVEQNB_ReturnStatus_en LVEQNB_GetParameters(LVEQNB_Handle_t hInstance,
LVEQNB_Params_t *pParams);
-
/****************************************************************************************/
/* */
/* FUNCTION: LVEQNB_GetCapabilities */
@@ -429,7 +404,6 @@
LVEQNB_ReturnStatus_en LVEQNB_GetCapabilities(LVEQNB_Handle_t hInstance,
LVEQNB_Capabilities_t *pCapabilities);
-
/****************************************************************************************/
/* */
/* FUNCTION: LVEQNB_Control */
@@ -455,7 +429,6 @@
LVEQNB_ReturnStatus_en LVEQNB_Control(LVEQNB_Handle_t hInstance,
LVEQNB_Params_t *pParams);
-
/****************************************************************************************/
/* */
/* FUNCTION: LVEQNB_Process */
@@ -478,23 +451,10 @@
/* NOTES: */
/* */
/****************************************************************************************/
-#ifdef BUILD_FLOAT
LVEQNB_ReturnStatus_en LVEQNB_Process(LVEQNB_Handle_t hInstance,
const LVM_FLOAT *pInData,
LVM_FLOAT *pOutData,
LVM_UINT16 NumSamples);
-#else
-LVEQNB_ReturnStatus_en LVEQNB_Process(LVEQNB_Handle_t hInstance,
- const LVM_INT16 *pInData,
- LVM_INT16 *pOutData,
- LVM_UINT16 NumSamples);
-#endif
-
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
#endif /* __LVEQNB__ */
diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_CalcCoef.c b/media/libeffects/lvm/lib/Eq/src/LVEQNB_CalcCoef.c
deleted file mode 100644
index ff52b7f..0000000
--- a/media/libeffects/lvm/lib/Eq/src/LVEQNB_CalcCoef.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/****************************************************************************************/
-/* */
-/* Includes */
-/* */
-/****************************************************************************************/
-
-#include "LVEQNB_Private.h"
-#ifdef BUILD_FLOAT
-#include <math.h>
-#endif
-
-/****************************************************************************************/
-/* */
-/* Defines */
-/* */
-/****************************************************************************************/
-
-#define PI 3.14159265358979
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVEQNB_DoublePrecCoefs */
-/* */
-/* DESCRIPTION: */
-/* Calculate double precision coefficients for a peaking filter */
-/* */
-/* PARAMETERS: */
-/* Fs Sampling frequency index */
-/* pFilterDefinition Pointer to the filter definition */
-/* pCoefficients Pointer to the coefficients */
-/* */
-/* RETURNS: */
-/* LVEQNB_SUCCESS Always succeeds */
-/* */
-/* NOTES: */
-/* 1. The equations used are as follows: */
-/* */
-/* G = 10^(GaindB/20) - 1 */
-/* t0 = 2 * Pi * Fc / Fs */
-/* D = 1 if GaindB >= 0 */
-/* D = 1 / (1 + G) if GaindB < 0 */
-/* */
-/* b2 = -0.5 * (2Q - D * t0) / (2Q + D * t0) */
-/* b1 = (0.5 - b2) * (1 - coserr(t0)) */
-/* a0 = (0.5 + b2) / 2 */
-/* */
-/* Where: */
-/* GaindB is the gain in dBs, range -15dB to +15dB */
-/* Fc is the centre frequency, DC to Fs/50 */
-/* Fs is the sample frequency, 8000 to 48000 in descrete steps */
-/* Q is the Q factor, 0.25 to 12 (represented by 25 to 1200) */
-/* */
-/* 2. The double precision coefficients are only used when fc is less than fs/85, so */
-/* the cosine of t0 is always close to 1.0. Instead of calculating the cosine */
-/* itself the difference from the value 1.0 is calculated, this can be done with */
-/* lower precision maths. */
-/* */
-/* 3. The value of the B2 coefficient is only calculated as a single precision value, */
-/* small errors in this value have a combined effect on the Q and Gain but not the */
-/* the frequency of the filter. */
-/* */
-/****************************************************************************************/
-
-
-#ifndef BUILD_FLOAT
-LVEQNB_ReturnStatus_en LVEQNB_DoublePrecCoefs(LVM_UINT16 Fs,
- LVEQNB_BandDef_t *pFilterDefinition,
- PK_C32_Coefs_t *pCoefficients)
-{
-
- extern LVM_INT16 LVEQNB_GainTable[];
- extern LVM_INT16 LVEQNB_TwoPiOnFsTable[];
- extern LVM_INT16 LVEQNB_DTable[];
- extern LVM_INT16 LVEQNB_DPCosCoef[];
-
- /*
- * Get the filter definition
- */
- LVM_INT16 Gain = pFilterDefinition->Gain;
- LVM_UINT16 Frequency = pFilterDefinition->Frequency;
- LVM_UINT16 QFactor = pFilterDefinition->QFactor;
-
- /*
- * Intermediate variables and temporary values
- */
- LVM_INT32 T0;
- LVM_INT16 D;
- LVM_INT32 A0;
- LVM_INT32 B1;
- LVM_INT32 B2;
- LVM_INT32 Dt0;
- LVM_INT32 B2_Den;
- LVM_INT32 B2_Num;
- LVM_INT32 CosErr;
- LVM_INT16 coef;
- LVM_INT32 factor;
- LVM_INT16 t0;
- LVM_INT16 i;
-
- /*
- * Calculating the intermediate values
- */
- T0 = (LVM_INT32)Frequency * LVEQNB_TwoPiOnFsTable[Fs]; /* T0 = 2 * Pi * Fc / Fs */
- if (Gain >= 0)
- {
- D = LVEQNB_DTable[15]; /* D = 1 if GaindB >= 0 */
- }
- else
- {
- D = LVEQNB_DTable[Gain+15]; /* D = 1 / (1 + G) if GaindB < 0 */
- }
-
- /*
- * Calculate the B2 coefficient
- */
- Dt0 = D * (T0 >> 10);
- B2_Den = ((LVM_INT32)QFactor << 19) + (Dt0 >> 2);
- B2_Num = (Dt0 >> 3) - ((LVM_INT32)QFactor << 18);
- B2 = (B2_Num / (B2_Den >> 16)) << 15;
-
- /*
- * Calculate the cosine error by a polynomial expansion using the equation:
- *
- * CosErr += coef(n) * t0^n For n = 0 to 4
- */
- T0 = (T0 >> 6) * 0x7f53; /* Scale to 1.0 in 16-bit for range 0 to fs/50 */
- t0 = (LVM_INT16)(T0 >> 16);
- factor = 0x7fff; /* Initialise to 1.0 for the a0 coefficient */
- CosErr = 0; /* Initialise the error to zero */
- for (i=1; i<5; i++)
- {
- coef = LVEQNB_DPCosCoef[i]; /* Get the nth coefficient */
- CosErr += (factor * coef) >> 5; /* The nth partial sum */
- factor = (factor * t0) >> 15; /* Calculate t0^n */
- }
- CosErr = CosErr << (LVEQNB_DPCosCoef[0]); /* Correct the scaling */
-
- /*
- * Calculate the B1 and A0 coefficients
- */
- B1 = (0x40000000 - B2); /* B1 = (0.5 - b2/2) */
- A0 = ((B1 >> 16) * (CosErr >> 10)) >> 6; /* Temporary storage for (0.5 - b2/2) * coserr(t0) */
- B1 -= A0; /* B1 = (0.5 - b2/2) * (1 - coserr(t0)) */
- A0 = (0x40000000 + B2) >> 1; /* A0 = (0.5 + b2) */
-
- /*
- * Write coeff into the data structure
- */
- pCoefficients->A0 = A0;
- pCoefficients->B1 = B1;
- pCoefficients->B2 = B2;
- pCoefficients->G = LVEQNB_GainTable[Gain+15];
-
- return(LVEQNB_SUCCESS);
-
-}
-#endif
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVEQNB_SinglePrecCoefs */
-/* */
-/* DESCRIPTION: */
-/* Calculate single precision coefficients for a peaking filter */
-/* */
-/* PARAMETERS: */
-/* Fs Sampling frequency index */
-/* pFilterDefinition Pointer to the filter definition */
-/* pCoefficients Pointer to the coefficients */
-/* */
-/* RETURNS: */
-/* LVEQNB_SUCCESS Always succeeds */
-/* */
-/* NOTES: */
-/* 1. The equations used are as follows: */
-/* */
-/* G = 10^(GaindB/20) - 1 */
-/* t0 = 2 * Pi * Fc / Fs */
-/* D = 1 if GaindB >= 0 */
-/* D = 1 / (1 + G) if GaindB < 0 */
-/* */
-/* b2 = -0.5 * (2Q - D * t0) / (2Q + D * t0) */
-/* b1 = (0.5 - b2) * cos(t0) */
-/* a0 = (0.5 + b2) / 2 */
-/* */
-/* Where: */
-/* GaindB is the gain in dBs, range -15dB to +15dB */
-/* Fc is the centre frequency, DC to Nyquist */
-/* Fs is the sample frequency, 8000 to 48000 in descrete steps */
-/* Q is the Q factor, 0.25 to 12 */
-/* */
-/****************************************************************************************/
-
-#ifdef BUILD_FLOAT
-LVEQNB_ReturnStatus_en LVEQNB_SinglePrecCoefs(LVM_UINT16 Fs,
- LVEQNB_BandDef_t *pFilterDefinition,
- PK_FLOAT_Coefs_t *pCoefficients)
-{
-
- extern LVM_FLOAT LVEQNB_GainTable[];
- extern LVM_FLOAT LVEQNB_TwoPiOnFsTable[];
- extern LVM_FLOAT LVEQNB_DTable[];
-
-
- /*
- * Get the filter definition
- */
- LVM_INT16 Gain = pFilterDefinition->Gain;
- LVM_UINT16 Frequency = pFilterDefinition->Frequency;
- /* As mentioned in effectbundle.h */
- LVM_FLOAT QFactor = (LVM_FLOAT)pFilterDefinition->QFactor / 100.0f;
-
-
- /*
- * Intermediate variables and temporary values
- */
- LVM_FLOAT T0;
- LVM_FLOAT D;
- LVM_FLOAT A0;
- LVM_FLOAT B1;
- LVM_FLOAT B2;
-
- /*
- * Calculating the intermediate values
- */
- T0 = Frequency * LVEQNB_TwoPiOnFsTable[Fs]; /* T0 = 2 * Pi * Fc / Fs */
- if (Gain >= 0)
- {
- D = LVEQNB_DTable[15]; /* D = 1 if GaindB >= 0 */
- }
- else
- {
- D = LVEQNB_DTable[Gain + 15]; /* D = 1 / (1 + G) if GaindB < 0 */
- }
-
- /*
- * Calculate the B2,B1,A0 coefficients
- */
- B2 = -0.5 * (2 * QFactor - D * T0) / (2 * QFactor + D * T0);
- B1 = (0.5 - B2) * cos(T0);
- A0 = (0.5 + B2) / 2.0;
-
- /*
- * Write coeff into the data structure
- */
- /* all the coefficients are multiplied with 2 to make them align with fixed point values*/
- pCoefficients->A0 = 2 * A0;
- pCoefficients->B1 = 2 * B1;
- pCoefficients->B2 = 2 * B2;
- pCoefficients->G = LVEQNB_GainTable[Gain + 15];
-
- return(LVEQNB_SUCCESS);
-}
-#else
-LVEQNB_ReturnStatus_en LVEQNB_SinglePrecCoefs(LVM_UINT16 Fs,
- LVEQNB_BandDef_t *pFilterDefinition,
- PK_C16_Coefs_t *pCoefficients)
-{
-
- extern LVM_INT16 LVEQNB_GainTable[];
- extern LVM_INT16 LVEQNB_TwoPiOnFsTable[];
- extern LVM_INT16 LVEQNB_DTable[];
- extern LVM_INT16 LVEQNB_CosCoef[];
-
-
- /*
- * Get the filter definition
- */
- LVM_INT16 Gain = pFilterDefinition->Gain;
- LVM_UINT16 Frequency = pFilterDefinition->Frequency;
- LVM_UINT16 QFactor = pFilterDefinition->QFactor;
-
-
- /*
- * Intermediate variables and temporary values
- */
- LVM_INT32 T0;
- LVM_INT16 D;
- LVM_INT32 A0;
- LVM_INT32 B1;
- LVM_INT32 B2;
- LVM_INT32 Dt0;
- LVM_INT32 B2_Den;
- LVM_INT32 B2_Num;
- LVM_INT32 COS_T0;
- LVM_INT16 coef;
- LVM_INT32 factor;
- LVM_INT16 t0;
- LVM_INT16 i;
-
- /*
- * Calculating the intermediate values
- */
- T0 = (LVM_INT32)Frequency * LVEQNB_TwoPiOnFsTable[Fs]; /* T0 = 2 * Pi * Fc / Fs */
- if (Gain >= 0)
- {
- D = LVEQNB_DTable[15]; /* D = 1 if GaindB >= 0 */
- }
- else
- {
- D = LVEQNB_DTable[Gain+15]; /* D = 1 / (1 + G) if GaindB < 0 */
- }
-
- /*
- * Calculate the B2 coefficient
- */
- Dt0 = D * (T0 >> 10);
- B2_Den = ((LVM_INT32)QFactor << 19) + (Dt0 >> 2);
- B2_Num = (Dt0 >> 3) - ((LVM_INT32)QFactor << 18);
- B2 = (B2_Num / (B2_Den >> 16)) << 15;
-
- /*
- * Calculate the cosine by a polynomial expansion using the equation:
- *
- * Cos += coef(n) * t0^n For n = 0 to 6
- */
- T0 = (T0 >> 10) * 20859; /* Scale to 1.0 in 16-bit for range 0 to fs/2 */
- t0 = (LVM_INT16)(T0 >> 16);
- factor = 0x7fff; /* Initialise to 1.0 for the a0 coefficient */
- COS_T0 = 0; /* Initialise the error to zero */
- for (i=1; i<7; i++)
- {
- coef = LVEQNB_CosCoef[i]; /* Get the nth coefficient */
- COS_T0 += (factor * coef) >> 5; /* The nth partial sum */
- factor = (factor * t0) >> 15; /* Calculate t0^n */
- }
- COS_T0 = COS_T0 << (LVEQNB_CosCoef[0]+6); /* Correct the scaling */
-
-
- B1 = ((0x40000000 - B2) >> 16) * (COS_T0 >> 16); /* B1 = (0.5 - b2/2) * cos(t0) */
- A0 = (0x40000000 + B2) >> 1; /* A0 = (0.5 + b2/2) */
-
- /*
- * Write coeff into the data structure
- */
- pCoefficients->A0 = (LVM_INT16)(A0>>16);
- pCoefficients->B1 = (LVM_INT16)(B1>>15);
- pCoefficients->B2 = (LVM_INT16)(B2>>16);
- pCoefficients->G = LVEQNB_GainTable[Gain+15];
-
-
- return(LVEQNB_SUCCESS);
-
-}
-#endif
\ No newline at end of file
diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_CalcCoef.cpp b/media/libeffects/lvm/lib/Eq/src/LVEQNB_CalcCoef.cpp
new file mode 100644
index 0000000..c3c0fad
--- /dev/null
+++ b/media/libeffects/lvm/lib/Eq/src/LVEQNB_CalcCoef.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/****************************************************************************************/
+/* */
+/* Includes */
+/* */
+/****************************************************************************************/
+
+#include "LVEQNB_Private.h"
+#include <math.h>
+
+/****************************************************************************************/
+/* */
+/* Defines */
+/* */
+/****************************************************************************************/
+
+#define PI 3.14159265358979
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVEQNB_DoublePrecCoefs */
+/* */
+/* DESCRIPTION: */
+/* Calculate double precision coefficients for a peaking filter */
+/* */
+/* PARAMETERS: */
+/* Fs Sampling frequency index */
+/* pFilterDefinition Pointer to the filter definition */
+/* pCoefficients Pointer to the coefficients */
+/* */
+/* RETURNS: */
+/* LVEQNB_SUCCESS Always succeeds */
+/* */
+/* NOTES: */
+/* 1. The equations used are as follows: */
+/* */
+/* G = 10^(GaindB/20) - 1 */
+/* t0 = 2 * Pi * Fc / Fs */
+/* D = 1 if GaindB >= 0 */
+/* D = 1 / (1 + G) if GaindB < 0 */
+/* */
+/* b2 = -0.5 * (2Q - D * t0) / (2Q + D * t0) */
+/* b1 = (0.5 - b2) * (1 - coserr(t0)) */
+/* a0 = (0.5 + b2) / 2 */
+/* */
+/* Where: */
+/* GaindB is the gain in dBs, range -15dB to +15dB */
+/* Fc is the centre frequency, DC to Fs/50 */
+/* Fs is the sample frequency, 8000 to 48000 in descrete steps */
+/* Q is the Q factor, 0.25 to 12 (represented by 25 to 1200) */
+/* */
+/* 2. The double precision coefficients are only used when fc is less than fs/85, so */
+/* the cosine of t0 is always close to 1.0. Instead of calculating the cosine */
+/* itself the difference from the value 1.0 is calculated, this can be done with */
+/* lower precision maths. */
+/* */
+/* 3. The value of the B2 coefficient is only calculated as a single precision value, */
+/* small errors in this value have a combined effect on the Q and Gain but not the */
+/* the frequency of the filter. */
+/* */
+/****************************************************************************************/
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVEQNB_SinglePrecCoefs */
+/* */
+/* DESCRIPTION: */
+/* Calculate single precision coefficients for a peaking filter */
+/* */
+/* PARAMETERS: */
+/* Fs Sampling frequency index */
+/* pFilterDefinition Pointer to the filter definition */
+/* pCoefficients Pointer to the coefficients */
+/* */
+/* RETURNS: */
+/* LVEQNB_SUCCESS Always succeeds */
+/* */
+/* NOTES: */
+/* 1. The equations used are as follows: */
+/* */
+/* G = 10^(GaindB/20) - 1 */
+/* t0 = 2 * Pi * Fc / Fs */
+/* D = 1 if GaindB >= 0 */
+/* D = 1 / (1 + G) if GaindB < 0 */
+/* */
+/* b2 = -0.5 * (2Q - D * t0) / (2Q + D * t0) */
+/* b1 = (0.5 - b2) * cos(t0) */
+/* a0 = (0.5 + b2) / 2 */
+/* */
+/* Where: */
+/* GaindB is the gain in dBs, range -15dB to +15dB */
+/* Fc is the centre frequency, DC to Nyquist */
+/* Fs is the sample frequency, 8000 to 48000 in descrete steps */
+/* Q is the Q factor, 0.25 to 12 */
+/* */
+/****************************************************************************************/
+
+LVEQNB_ReturnStatus_en LVEQNB_SinglePrecCoefs(LVM_UINT16 Fs,
+ LVEQNB_BandDef_t *pFilterDefinition,
+ PK_FLOAT_Coefs_t *pCoefficients)
+{
+
+ extern LVM_FLOAT LVEQNB_GainTable[];
+ extern LVM_FLOAT LVEQNB_TwoPiOnFsTable[];
+ extern LVM_FLOAT LVEQNB_DTable[];
+
+ /*
+ * Get the filter definition
+ */
+ LVM_INT16 Gain = pFilterDefinition->Gain;
+ LVM_UINT16 Frequency = pFilterDefinition->Frequency;
+ /* As mentioned in effectbundle.h */
+ LVM_FLOAT QFactor = (LVM_FLOAT)pFilterDefinition->QFactor / 100.0f;
+
+ /*
+ * Intermediate variables and temporary values
+ */
+ LVM_FLOAT T0;
+ LVM_FLOAT D;
+ LVM_FLOAT A0;
+ LVM_FLOAT B1;
+ LVM_FLOAT B2;
+
+ /*
+ * Calculating the intermediate values
+ */
+ T0 = Frequency * LVEQNB_TwoPiOnFsTable[Fs]; /* T0 = 2 * Pi * Fc / Fs */
+ if (Gain >= 0)
+ {
+ D = LVEQNB_DTable[15]; /* D = 1 if GaindB >= 0 */
+ }
+ else
+ {
+ D = LVEQNB_DTable[Gain + 15]; /* D = 1 / (1 + G) if GaindB < 0 */
+ }
+
+ /*
+ * Calculate the B2,B1,A0 coefficients
+ */
+ B2 = -0.5 * (2 * QFactor - D * T0) / (2 * QFactor + D * T0);
+ B1 = (0.5 - B2) * cos(T0);
+ A0 = (0.5 + B2) / 2.0;
+
+ /*
+ * Write coeff into the data structure
+ */
+ /* all the coefficients are multiplied with 2 to make them align with fixed point values*/
+ pCoefficients->A0 = 2 * A0;
+ pCoefficients->B1 = 2 * B1;
+ pCoefficients->B2 = 2 * B2;
+ pCoefficients->G = LVEQNB_GainTable[Gain + 15];
+
+ return(LVEQNB_SUCCESS);
+}
diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Coeffs.h b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Coeffs.h
index 755141e..6329181 100644
--- a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Coeffs.h
+++ b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Coeffs.h
@@ -15,17 +15,14 @@
* limitations under the License.
*/
-
#ifndef __LVEQNB_COEFFS_H__
#define __LVEQNB_COEFFS_H__
-
/************************************************************************************/
/* */
/* Gain table for (10^(Gain/20) - 1) */
/* */
/************************************************************************************/
-#ifdef BUILD_FLOAT
#define LVEQNB_Gain_Neg15_dB (-0.822172f)
#define LVEQNB_Gain_Neg14_dB (-0.800474f)
#define LVEQNB_Gain_Neg13_dB (-0.776128f)
@@ -57,47 +54,12 @@
#define LVEQNB_Gain_13_dB 3.466836f
#define LVEQNB_Gain_14_dB 4.011872f
#define LVEQNB_Gain_15_dB 4.623413f
-#else
-#define LVEQNB_GAINSHIFT 11 /* As a power of 2 */
-#define LVEQNB_Gain_Neg15_dB (-1684) /* Floating point value -0.822172 */
-#define LVEQNB_Gain_Neg14_dB (-1639) /* Floating point value -0.800474 */
-#define LVEQNB_Gain_Neg13_dB (-1590) /* Floating point value -0.776128 */
-#define LVEQNB_Gain_Neg12_dB (-1534) /* Floating point value -0.748811 */
-#define LVEQNB_Gain_Neg11_dB (-1471) /* Floating point value -0.718162 */
-#define LVEQNB_Gain_Neg10_dB (-1400) /* Floating point value -0.683772 */
-#define LVEQNB_Gain_Neg9_dB (-1321) /* Floating point value -0.645187 */
-#define LVEQNB_Gain_Neg8_dB (-1233) /* Floating point value -0.601893 */
-#define LVEQNB_Gain_Neg7_dB (-1133) /* Floating point value -0.553316 */
-#define LVEQNB_Gain_Neg6_dB (-1022) /* Floating point value -0.498813 */
-#define LVEQNB_Gain_Neg5_dB (-896) /* Floating point value -0.437659 */
-#define LVEQNB_Gain_Neg4_dB (-756) /* Floating point value -0.369043 */
-#define LVEQNB_Gain_Neg3_dB (-598) /* Floating point value -0.292054 */
-#define LVEQNB_Gain_Neg2_dB (-421) /* Floating point value -0.205672 */
-#define LVEQNB_Gain_Neg1_dB (-223) /* Floating point value -0.108749 */
-#define LVEQNB_Gain_0_dB 0 /* Floating point value 0.000000 */
-#define LVEQNB_Gain_1_dB 250 /* Floating point value 0.122018 */
-#define LVEQNB_Gain_2_dB 530 /* Floating point value 0.258925 */
-#define LVEQNB_Gain_3_dB 845 /* Floating point value 0.412538 */
-#define LVEQNB_Gain_4_dB 1198 /* Floating point value 0.584893 */
-#define LVEQNB_Gain_5_dB 1594 /* Floating point value 0.778279 */
-#define LVEQNB_Gain_6_dB 2038 /* Floating point value 0.995262 */
-#define LVEQNB_Gain_7_dB 2537 /* Floating point value 1.238721 */
-#define LVEQNB_Gain_8_dB 3096 /* Floating point value 1.511886 */
-#define LVEQNB_Gain_9_dB 3724 /* Floating point value 1.818383 */
-#define LVEQNB_Gain_10_dB 4428 /* Floating point value 2.162278 */
-#define LVEQNB_Gain_11_dB 5219 /* Floating point value 2.548134 */
-#define LVEQNB_Gain_12_dB 6105 /* Floating point value 2.981072 */
-#define LVEQNB_Gain_13_dB 7100 /* Floating point value 3.466836 */
-#define LVEQNB_Gain_14_dB 8216 /* Floating point value 4.011872 */
-#define LVEQNB_Gain_15_dB 9469 /* Floating point value 4.623413 */
-#endif
/************************************************************************************/
/* */
/* Frequency table for 2*Pi/Fs */
/* */
/************************************************************************************/
-#ifdef BUILD_FLOAT
#define LVEQNB_2PiOn_8000 0.000785f
#define LVEQNB_2PiOn_11025 0.000570f
#define LVEQNB_2PiOn_12000 0.000524f
@@ -108,32 +70,16 @@
#define LVEQNB_2PiOn_44100 0.000142f
#define LVEQNB_2PiOn_48000 0.000131f
-#ifdef HIGHER_FS
#define LVEQNB_2PiOn_88200 0.000071f
#define LVEQNB_2PiOn_96000 0.000065f
#define LVEQNB_2PiOn_176400 0.000036f
#define LVEQNB_2PiOn_192000 0.000033f
-#endif
-
-#else
-#define LVEQNB_FREQSHIFT 25 /* As a power of 2 */
-#define LVEQNB_2PiOn_8000 26354 /* Floating point value 0.000785 */
-#define LVEQNB_2PiOn_11025 19123 /* Floating point value 0.000570 */
-#define LVEQNB_2PiOn_12000 17569 /* Floating point value 0.000524 */
-#define LVEQNB_2PiOn_16000 13177 /* Floating point value 0.000393 */
-#define LVEQNB_2PiOn_22050 9561 /* Floating point value 0.000285 */
-#define LVEQNB_2PiOn_24000 8785 /* Floating point value 0.000262 */
-#define LVEQNB_2PiOn_32000 6588 /* Floating point value 0.000196 */
-#define LVEQNB_2PiOn_44100 4781 /* Floating point value 0.000142 */
-#define LVEQNB_2PiOn_48000 4392 /* Floating point value 0.000131 */
-#endif
/************************************************************************************/
/* */
/* 50D table for 50 / ( 1 + Gain ) */
/* */
/************************************************************************************/
-#ifdef BUILD_FLOAT
#define LVEQNB_100D_Neg15_dB 5.623413f
#define LVEQNB_100D_Neg14_dB 5.011872f
#define LVEQNB_100D_Neg13_dB 4.466836f
@@ -150,24 +96,5 @@
#define LVEQNB_100D_Neg2_dB 1.258925f
#define LVEQNB_100D_Neg1_dB 1.122018f
#define LVEQNB_100D_0_dB 1.000000f
-#else
-#define LVEQNB_100DSHIFT 5 /* As a power of 2 */
-#define LVEQNB_100D_Neg15_dB 17995 /* Floating point value 5.623413 */
-#define LVEQNB_100D_Neg14_dB 16038 /* Floating point value 5.011872 */
-#define LVEQNB_100D_Neg13_dB 14294 /* Floating point value 4.466836 */
-#define LVEQNB_100D_Neg12_dB 12739 /* Floating point value 3.981072 */
-#define LVEQNB_100D_Neg11_dB 11354 /* Floating point value 3.548134 */
-#define LVEQNB_100D_Neg10_dB 10119 /* Floating point value 3.162278 */
-#define LVEQNB_100D_Neg9_dB 9019 /* Floating point value 2.818383 */
-#define LVEQNB_100D_Neg8_dB 8038 /* Floating point value 2.511886 */
-#define LVEQNB_100D_Neg7_dB 7164 /* Floating point value 2.238721 */
-#define LVEQNB_100D_Neg6_dB 6385 /* Floating point value 1.995262 */
-#define LVEQNB_100D_Neg5_dB 5690 /* Floating point value 1.778279 */
-#define LVEQNB_100D_Neg4_dB 5072 /* Floating point value 1.584893 */
-#define LVEQNB_100D_Neg3_dB 4520 /* Floating point value 1.412538 */
-#define LVEQNB_100D_Neg2_dB 4029 /* Floating point value 1.258925 */
-#define LVEQNB_100D_Neg1_dB 3590 /* Floating point value 1.122018 */
-#define LVEQNB_100D_0_dB 3200 /* Floating point value 1.000000 */
-#endif
#endif
diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Control.c b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Control.c
deleted file mode 100644
index 7b0f341..0000000
--- a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Control.c
+++ /dev/null
@@ -1,552 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/****************************************************************************************/
-/* */
-/* Includes */
-/* */
-/****************************************************************************************/
-
-#include "LVEQNB.h"
-#include "LVEQNB_Private.h"
-#include "VectorArithmetic.h"
-#include "BIQUAD.h"
-
-
-/****************************************************************************************/
-/* */
-/* Defines */
-/* */
-/****************************************************************************************/
-
-#define LOW_FREQ 298 /* 32768/110 for low test frequency */
-#define HIGH_FREQ 386 /* 32768/85 for high test frequency */
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVEQNB_GetParameters */
-/* */
-/* DESCRIPTION: */
-/* Request the N-Band equaliser parameters. The current parameter set is returned via */
-/* the parameter pointer. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance handle */
-/* pParams Pointer to an empty parameter structure */
-/* */
-/* RETURNS: */
-/* LVEQNB_SUCCESS Succeeds */
-/* LVEQNB_NULLADDRESS Instance or pParams is NULL pointer */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVEQNB_Process function */
-/* */
-/****************************************************************************************/
-
-LVEQNB_ReturnStatus_en LVEQNB_GetParameters(LVEQNB_Handle_t hInstance,
- LVEQNB_Params_t *pParams)
-{
-
- LVEQNB_Instance_t *pInstance =(LVEQNB_Instance_t *)hInstance;
-
- /*
- * Check for error conditions
- */
- if((hInstance == LVM_NULL) || (pParams == LVM_NULL))
- {
- return LVEQNB_NULLADDRESS;
- }
-
- *pParams = pInstance->Params;
-
- return(LVEQNB_SUCCESS);
-}
-
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVEQNB_GetCapabilities */
-/* */
-/* DESCRIPTION: */
-/* Get the N-Band equaliser capabilities. The current capabilities are returned */
-/* via the pointer. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance handle */
-/* pCapabilities Pointer to an empty capability structure */
-/* */
-/* RETURNS: */
-/* LVEQNB_Success Succeeds */
-/* LVEQNB_NULLADDRESS hInstance or pCapabilities is NULL */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVEQNB_Process function */
-/* */
-/************************************************************************************/
-
-LVEQNB_ReturnStatus_en LVEQNB_GetCapabilities(LVEQNB_Handle_t hInstance,
- LVEQNB_Capabilities_t *pCapabilities)
-{
-
- LVEQNB_Instance_t *pInstance =(LVEQNB_Instance_t *)hInstance;
-
- if((hInstance == LVM_NULL) || (pCapabilities == LVM_NULL))
- {
- return LVEQNB_NULLADDRESS;
- }
-
- *pCapabilities = pInstance->Capabilities;
-
- return(LVEQNB_SUCCESS);
-}
-
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVEQNB_SetFilters */
-/* */
-/* DESCRIPTION: */
-/* Sets the filter type based on the definition. */
-/* */
-/* PARAMETERS: */
-/* pInstance Pointer to the instance */
-/* pParams Initialisation parameters */
-/* */
-/* RETURNS: */
-/* void Nothing */
-/* */
-/* NOTES: */
-/* 1. To select the biquad type the follow rules are applied: */
-/* Double precision if (fc <= fs/110) */
-/* Double precision if (fs/110 < fc < fs/85) & (Q>3) */
-/* Single precision otherwise */
-/* */
-/************************************************************************************/
-
-void LVEQNB_SetFilters(LVEQNB_Instance_t *pInstance,
- LVEQNB_Params_t *pParams)
-{
-#ifdef HIGHER_FS
- extern const LVM_UINT32 LVEQNB_SampleRateTab[]; /* Sample rate table */
-#else
- extern const LVM_UINT16 LVEQNB_SampleRateTab[]; /* Sample rate table */
-#endif
-
- LVM_UINT16 i; /* Filter band index */
- LVM_UINT32 fs = (LVM_UINT32)LVEQNB_SampleRateTab[(LVM_UINT16)pParams->SampleRate]; /* Sample rate */
- LVM_UINT32 fc; /* Filter centre frequency */
- LVM_INT16 QFactor; /* Filter Q factor */
-
-
- pInstance->NBands = pParams->NBands;
-
- for (i=0; i<pParams->NBands; i++)
- {
- /*
- * Get the filter settings
- */
- fc = (LVM_UINT32)pParams->pBandDefinition[i].Frequency; /* Get the band centre frequency */
- QFactor = (LVM_INT16)pParams->pBandDefinition[i].QFactor; /* Get the band Q factor */
-
-#ifdef BUILD_FLOAT
- pInstance->pBiquadType[i] = LVEQNB_SinglePrecision_Float; /* Default to single precision */
-#else
- /*
- * For each filter set the type of biquad required
- */
- pInstance->pBiquadType[i] = LVEQNB_SinglePrecision; /* Default to single precision */
-#endif
-#ifndef BUILD_FLOAT
- if ((fc << 15) <= (LOW_FREQ * fs))
- {
- /*
- * fc <= fs/110
- */
- pInstance->pBiquadType[i] = LVEQNB_DoublePrecision;
- }
- else if (((fc << 15) <= (HIGH_FREQ * fs)) && (QFactor > 300))
- {
- /*
- * (fs/110 < fc < fs/85) & (Q>3)
- */
- pInstance->pBiquadType[i] = LVEQNB_DoublePrecision;
- }
-#endif
-
- /*
- * Check for out of range frequencies
- */
- if (fc > (fs >> 1))
- {
- pInstance->pBiquadType[i] = LVEQNB_OutOfRange;
- }
-
-
- /*
- * Copy the filter definition to persistant memory
- */
- pInstance->pBandDefinitions[i] = pParams->pBandDefinition[i];
-
- }
-}
-
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVEQNB_SetCoefficients */
-/* */
-/* DESCRIPTION: */
-/* Sets the filter coefficients. This uses the type to select single or double */
-/* precision coefficients. */
-/* */
-/* PARAMETERS: */
-/* pInstance Pointer to the instance */
-/* pParams Initialisation parameters */
-/* */
-/************************************************************************************/
-
-void LVEQNB_SetCoefficients(LVEQNB_Instance_t *pInstance)
-{
-
- LVM_UINT16 i; /* Filter band index */
- LVEQNB_BiquadType_en BiquadType; /* Filter biquad type */
-
-
- /*
- * Set the coefficients for each band by the init function
- */
- for (i=0; i<pInstance->Params.NBands; i++)
- {
-
- /*
- * Check band type for correct initialisation method and recalculate the coefficients
- */
- BiquadType = pInstance->pBiquadType[i];
- switch (BiquadType)
- {
-#ifdef BUILD_FLOAT
- case LVEQNB_SinglePrecision_Float:
- {
- PK_FLOAT_Coefs_t Coefficients;
- /*
- * Calculate the single precision coefficients
- */
- LVEQNB_SinglePrecCoefs((LVM_UINT16)pInstance->Params.SampleRate,
- &pInstance->pBandDefinitions[i],
- &Coefficients);
- /*
- * Set the coefficients
- */
- PK_2I_D32F32CssGss_TRC_WRA_01_Init(&pInstance->pEQNB_FilterState_Float[i],
- &pInstance->pEQNB_Taps_Float[i],
- &Coefficients);
- break;
- }
-#else
- case LVEQNB_DoublePrecision:
- {
- PK_C32_Coefs_t Coefficients;
-
- /*
- * Calculate the double precision coefficients
- */
- LVEQNB_DoublePrecCoefs((LVM_UINT16)pInstance->Params.SampleRate,
- &pInstance->pBandDefinitions[i],
- &Coefficients);
-
- /*
- * Set the coefficients
- */
- PK_2I_D32F32CllGss_TRC_WRA_01_Init(&pInstance->pEQNB_FilterState[i],
- &pInstance->pEQNB_Taps[i],
- &Coefficients);
- break;
- }
-
- case LVEQNB_SinglePrecision:
- {
- PK_C16_Coefs_t Coefficients;
-
- /*
- * Calculate the single precision coefficients
- */
- LVEQNB_SinglePrecCoefs((LVM_UINT16)pInstance->Params.SampleRate,
- &pInstance->pBandDefinitions[i],
- &Coefficients);
-
- /*
- * Set the coefficients
- */
- PK_2I_D32F32CssGss_TRC_WRA_01_Init(&pInstance->pEQNB_FilterState[i],
- &pInstance->pEQNB_Taps[i],
- &Coefficients);
- break;
- }
-#endif
- default:
- break;
- }
- }
-
-}
-
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVEQNB_ClearFilterHistory */
-/* */
-/* DESCRIPTION: */
-/* Clears the filter data history */
-/* */
-/* PARAMETERS: */
-/* pInstance Pointer to the instance */
-/* */
-/************************************************************************************/
-#ifndef BUILD_FLOAT
-void LVEQNB_ClearFilterHistory(LVEQNB_Instance_t *pInstance)
-{
- LVM_INT16 *pTapAddress;
- LVM_INT16 NumTaps;
-
-
- pTapAddress = (LVM_INT16 *)pInstance->pEQNB_Taps;
- NumTaps = (LVM_INT16)((pInstance->Capabilities.MaxBands * sizeof(Biquad_2I_Order2_Taps_t))/sizeof(LVM_INT16));
-
- if (NumTaps != 0)
- {
- LoadConst_16(0, /* Clear the history, value 0 */
- pTapAddress, /* Destination */
- NumTaps); /* Number of words */
- }
-}
-#else
-void LVEQNB_ClearFilterHistory(LVEQNB_Instance_t *pInstance)
-{
- LVM_FLOAT *pTapAddress;
- LVM_INT16 NumTaps;
-
- pTapAddress = (LVM_FLOAT *)pInstance->pEQNB_Taps_Float;
- NumTaps = (LVM_INT16)((pInstance->Capabilities.MaxBands * \
- sizeof(Biquad_2I_Order2_FLOAT_Taps_t)) / sizeof(LVM_FLOAT));
-
- if (NumTaps != 0)
- {
- LoadConst_Float(0, /* Clear the history, value 0 */
- pTapAddress, /* Destination */
- NumTaps); /* Number of words */
- }
-}
-#endif
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVEQNB_Control */
-/* */
-/* DESCRIPTION: */
-/* Sets or changes the LifeVibes module parameters. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance handle */
-/* pParams Pointer to a parameter structure */
-/* */
-/* RETURNS: */
-/* LVEQNB_Success Always succeeds */
-/* LVEQNB_NULLADDRESS Instance or pParams is NULL pointer */
-/* LVEQNB_NULLADDRESS NULL address for the equaliser filter definitions and the */
-/* number of bands is non-zero */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVEQNB_Process function */
-/* */
-/****************************************************************************************/
-
-LVEQNB_ReturnStatus_en LVEQNB_Control(LVEQNB_Handle_t hInstance,
- LVEQNB_Params_t *pParams)
-{
-
- LVEQNB_Instance_t *pInstance = (LVEQNB_Instance_t *)hInstance;
- LVM_INT16 bChange = LVM_FALSE;
- LVM_INT16 i = 0;
- LVEQNB_Mode_en OperatingModeSave ;
-
- /*
- * Check for error conditions
- */
- if((hInstance == LVM_NULL) || (pParams == LVM_NULL))
- {
- return LVEQNB_NULLADDRESS;
- }
-
- if((pParams->NBands !=0) && (pParams->pBandDefinition==LVM_NULL))
- {
- return LVEQNB_NULLADDRESS;
- }
-
- OperatingModeSave = pInstance->Params.OperatingMode;
-
- /* Set the alpha factor of the mixer */
- if (pParams->SampleRate != pInstance->Params.SampleRate)
- {
- LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMixer.MixerStream[0],LVEQNB_BYPASS_MIXER_TC,(LVM_Fs_en)pParams->SampleRate,2);
- LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMixer.MixerStream[1],LVEQNB_BYPASS_MIXER_TC,(LVM_Fs_en)pParams->SampleRate,2);
- }
-
-
- if( (pInstance->Params.NBands != pParams->NBands ) ||
- (pInstance->Params.OperatingMode != pParams->OperatingMode ) ||
- (pInstance->Params.pBandDefinition != pParams->pBandDefinition ) ||
- (pInstance->Params.SampleRate != pParams->SampleRate ) ||
- (pInstance->Params.SourceFormat != pParams->SourceFormat ))
- {
-
- bChange = LVM_TRUE;
- }
- else
- {
- for(i = 0; i < pParams->NBands; i++)
- {
-
- if((pInstance->pBandDefinitions[i].Frequency != pParams->pBandDefinition[i].Frequency )||
- (pInstance->pBandDefinitions[i].Gain != pParams->pBandDefinition[i].Gain )||
- (pInstance->pBandDefinitions[i].QFactor != pParams->pBandDefinition[i].QFactor ))
- {
-
- bChange = LVM_TRUE;
- }
- }
- }
-
-
- // During operating mode transition, there is a race condition where the mode
- // is still LVEQNB_ON, but the effect is considered disabled in the upper layers.
- // modeChange handles this special race condition.
- const int /* bool */ modeChange = pParams->OperatingMode != OperatingModeSave
- || (OperatingModeSave == LVEQNB_ON
- && pInstance->bInOperatingModeTransition
- && LVC_Mixer_GetTarget(&pInstance->BypassMixer.MixerStream[0]) == 0);
-
- if (bChange || modeChange) {
-
- /*
- * If the sample rate has changed clear the history
- */
- if (pInstance->Params.SampleRate != pParams->SampleRate)
- {
- LVEQNB_ClearFilterHistory(pInstance); /* Clear the history */
- }
-
- /*
- * Update the instance parameters
- */
- pInstance->Params = *pParams;
-
-
- /*
- * Reset the filters except if the algo is switched off
- */
- if(pParams->OperatingMode != LVEQNB_BYPASS){
- /*
- * Reset the filters as all parameters could have changed
- */
- LVEQNB_SetFilters(pInstance, /* Instance pointer */
- pParams); /* New parameters */
-
- /*
- * Update the filters
- */
- LVEQNB_SetCoefficients(pInstance); /* Instance pointer */
- }
-
- if (modeChange) {
- if(pParams->OperatingMode == LVEQNB_ON)
- {
-#ifdef BUILD_FLOAT
- LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[0], 1.0f);
- LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[1], 0.0f);
-#else
- LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[0],LVM_MAXINT_16);
- LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[1],0);
-#endif
- pInstance->BypassMixer.MixerStream[0].CallbackSet = 1;
- pInstance->BypassMixer.MixerStream[1].CallbackSet = 1;
- }
- else
- {
- /* Stay on the ON operating mode until the transition is done */
- // This may introduce a state race condition if the effect is enabled again
- // while in transition. This is fixed in the modeChange logic.
- pInstance->Params.OperatingMode = LVEQNB_ON;
-#ifdef BUILD_FLOAT
- LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[0], 0.0f);
- LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[1], 1.0f);
-#else
- LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[0],0);
- LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[1],LVM_MAXINT_16);
-#endif
- pInstance->BypassMixer.MixerStream[0].CallbackSet = 1;
- pInstance->BypassMixer.MixerStream[1].CallbackSet = 1;
- }
- LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMixer.MixerStream[0],LVEQNB_BYPASS_MIXER_TC,(LVM_Fs_en)pParams->SampleRate,2);
- LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMixer.MixerStream[1],LVEQNB_BYPASS_MIXER_TC,(LVM_Fs_en)pParams->SampleRate,2);
- pInstance->bInOperatingModeTransition = LVM_TRUE;
- }
-
- }
- return(LVEQNB_SUCCESS);
-}
-
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVEQNB_BypassMixerCallBack */
-/* */
-/* DESCRIPTION: */
-/* CallBack function of the mixer */
-/* transition */
-/* */
-/****************************************************************************************/
-LVM_INT32 LVEQNB_BypassMixerCallBack (void* hInstance,
- void *pGeneralPurpose,
- LVM_INT16 CallbackParam)
-{
- LVEQNB_Instance_t *pInstance =(LVEQNB_Instance_t *)hInstance;
- LVM_Callback CallBack = pInstance->Capabilities.CallBack;
-
- (void) pGeneralPurpose;
-
- /*
- * Send an ALGOFF event if the ON->OFF switch transition is finished
- */
-#ifdef BUILD_FLOAT
- if((LVC_Mixer_GetTarget(&pInstance->BypassMixer.MixerStream[0]) == 0) &&
- (CallbackParam == 0)){
-#else
- if((LVC_Mixer_GetTarget(&pInstance->BypassMixer.MixerStream[0]) == 0x00000000) &&
- (CallbackParam == 0)){
-#endif
- pInstance->Params.OperatingMode = LVEQNB_BYPASS;
- if (CallBack != LVM_NULL){
- CallBack(pInstance->Capabilities.pBundleInstance, LVM_NULL, ALGORITHM_EQNB_ID|LVEQNB_EVENT_ALGOFF);
- }
- }
-
- /*
- * Exit transition state
- */
- pInstance->bInOperatingModeTransition = LVM_FALSE;
-
- return 1;
-}
diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Control.cpp b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Control.cpp
new file mode 100644
index 0000000..6bb4a7e
--- /dev/null
+++ b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Control.cpp
@@ -0,0 +1,437 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/****************************************************************************************/
+/* */
+/* Includes */
+/* */
+/****************************************************************************************/
+
+#include "LVEQNB.h"
+#include "LVEQNB_Private.h"
+#include "VectorArithmetic.h"
+#include "BIQUAD.h"
+
+/****************************************************************************************/
+/* */
+/* Defines */
+/* */
+/****************************************************************************************/
+
+#define LOW_FREQ 298 /* 32768/110 for low test frequency */
+#define HIGH_FREQ 386 /* 32768/85 for high test frequency */
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVEQNB_GetParameters */
+/* */
+/* DESCRIPTION: */
+/* Request the N-Band equaliser parameters. The current parameter set is returned via */
+/* the parameter pointer. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance handle */
+/* pParams Pointer to an empty parameter structure */
+/* */
+/* RETURNS: */
+/* LVEQNB_SUCCESS Succeeds */
+/* LVEQNB_NULLADDRESS Instance or pParams is NULL pointer */
+/* */
+/* NOTES: */
+/* 1. This function may be interrupted by the LVEQNB_Process function */
+/* */
+/****************************************************************************************/
+
+LVEQNB_ReturnStatus_en LVEQNB_GetParameters(LVEQNB_Handle_t hInstance,
+ LVEQNB_Params_t *pParams)
+{
+
+ LVEQNB_Instance_t *pInstance =(LVEQNB_Instance_t *)hInstance;
+
+ /*
+ * Check for error conditions
+ */
+ if((hInstance == LVM_NULL) || (pParams == LVM_NULL))
+ {
+ return LVEQNB_NULLADDRESS;
+ }
+
+ *pParams = pInstance->Params;
+
+ return(LVEQNB_SUCCESS);
+}
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVEQNB_GetCapabilities */
+/* */
+/* DESCRIPTION: */
+/* Get the N-Band equaliser capabilities. The current capabilities are returned */
+/* via the pointer. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance handle */
+/* pCapabilities Pointer to an empty capability structure */
+/* */
+/* RETURNS: */
+/* LVEQNB_Success Succeeds */
+/* LVEQNB_NULLADDRESS hInstance or pCapabilities is NULL */
+/* */
+/* NOTES: */
+/* 1. This function may be interrupted by the LVEQNB_Process function */
+/* */
+/************************************************************************************/
+
+LVEQNB_ReturnStatus_en LVEQNB_GetCapabilities(LVEQNB_Handle_t hInstance,
+ LVEQNB_Capabilities_t *pCapabilities)
+{
+
+ LVEQNB_Instance_t *pInstance =(LVEQNB_Instance_t *)hInstance;
+
+ if((hInstance == LVM_NULL) || (pCapabilities == LVM_NULL))
+ {
+ return LVEQNB_NULLADDRESS;
+ }
+
+ *pCapabilities = pInstance->Capabilities;
+
+ return(LVEQNB_SUCCESS);
+}
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVEQNB_SetFilters */
+/* */
+/* DESCRIPTION: */
+/* Sets the filter type based on the definition. */
+/* */
+/* PARAMETERS: */
+/* pInstance Pointer to the instance */
+/* pParams Initialisation parameters */
+/* */
+/* RETURNS: */
+/* void Nothing */
+/* */
+/* NOTES: */
+/* 1. To select the biquad type the follow rules are applied: */
+/* Double precision if (fc <= fs/110) */
+/* Double precision if (fs/110 < fc < fs/85) & (Q>3) */
+/* Single precision otherwise */
+/* */
+/************************************************************************************/
+
+void LVEQNB_SetFilters(LVEQNB_Instance_t *pInstance,
+ LVEQNB_Params_t *pParams)
+{
+ extern const LVM_UINT32 LVEQNB_SampleRateTab[]; /* Sample rate table */
+
+ LVM_UINT16 i; /* Filter band index */
+ LVM_UINT32 fs = (LVM_UINT32)LVEQNB_SampleRateTab[(LVM_UINT16)pParams->SampleRate]; /* Sample rate */
+ LVM_UINT32 fc; /* Filter centre frequency */
+ LVM_INT16 QFactor; /* Filter Q factor */
+
+ pInstance->NBands = pParams->NBands;
+
+ for (i=0; i<pParams->NBands; i++)
+ {
+ /*
+ * Get the filter settings
+ */
+ fc = (LVM_UINT32)pParams->pBandDefinition[i].Frequency; /* Get the band centre frequency */
+ QFactor = (LVM_INT16)pParams->pBandDefinition[i].QFactor; /* Get the band Q factor */
+
+ pInstance->pBiquadType[i] = LVEQNB_SinglePrecision_Float; /* Default to single precision */
+
+ /*
+ * Check for out of range frequencies
+ */
+ if (fc > (fs >> 1))
+ {
+ pInstance->pBiquadType[i] = LVEQNB_OutOfRange;
+ }
+
+ /*
+ * Copy the filter definition to persistant memory
+ */
+ pInstance->pBandDefinitions[i] = pParams->pBandDefinition[i];
+
+ }
+}
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVEQNB_SetCoefficients */
+/* */
+/* DESCRIPTION: */
+/* Sets the filter coefficients. This uses the type to select single or double */
+/* precision coefficients. */
+/* */
+/* PARAMETERS: */
+/* pInstance Pointer to the instance */
+/* pParams Initialisation parameters */
+/* */
+/************************************************************************************/
+
+void LVEQNB_SetCoefficients(LVEQNB_Instance_t *pInstance)
+{
+
+ LVM_UINT16 i; /* Filter band index */
+ LVEQNB_BiquadType_en BiquadType; /* Filter biquad type */
+
+ /*
+ * Set the coefficients for each band by the init function
+ */
+ for (i=0; i<pInstance->Params.NBands; i++)
+ {
+
+ /*
+ * Check band type for correct initialisation method and recalculate the coefficients
+ */
+ BiquadType = pInstance->pBiquadType[i];
+ switch (BiquadType)
+ {
+ case LVEQNB_SinglePrecision_Float:
+ {
+ PK_FLOAT_Coefs_t Coefficients;
+ /*
+ * Calculate the single precision coefficients
+ */
+ LVEQNB_SinglePrecCoefs((LVM_UINT16)pInstance->Params.SampleRate,
+ &pInstance->pBandDefinitions[i],
+ &Coefficients);
+ /*
+ * Set the coefficients
+ */
+ PK_2I_D32F32CssGss_TRC_WRA_01_Init(&pInstance->pEQNB_FilterState_Float[i],
+ &pInstance->pEQNB_Taps_Float[i],
+ &Coefficients);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+}
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVEQNB_ClearFilterHistory */
+/* */
+/* DESCRIPTION: */
+/* Clears the filter data history */
+/* */
+/* PARAMETERS: */
+/* pInstance Pointer to the instance */
+/* */
+/************************************************************************************/
+void LVEQNB_ClearFilterHistory(LVEQNB_Instance_t *pInstance)
+{
+ LVM_FLOAT *pTapAddress;
+ LVM_INT16 NumTaps;
+
+ pTapAddress = (LVM_FLOAT *)pInstance->pEQNB_Taps_Float;
+ NumTaps = (LVM_INT16)((pInstance->Capabilities.MaxBands * \
+ sizeof(Biquad_2I_Order2_FLOAT_Taps_t)) / sizeof(LVM_FLOAT));
+
+ if (NumTaps != 0)
+ {
+ LoadConst_Float(0, /* Clear the history, value 0 */
+ pTapAddress, /* Destination */
+ NumTaps); /* Number of words */
+ }
+}
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVEQNB_Control */
+/* */
+/* DESCRIPTION: */
+/* Sets or changes the LifeVibes module parameters. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance handle */
+/* pParams Pointer to a parameter structure */
+/* */
+/* RETURNS: */
+/* LVEQNB_Success Always succeeds */
+/* LVEQNB_NULLADDRESS Instance or pParams is NULL pointer */
+/* LVEQNB_NULLADDRESS NULL address for the equaliser filter definitions and the */
+/* number of bands is non-zero */
+/* */
+/* NOTES: */
+/* 1. This function may be interrupted by the LVEQNB_Process function */
+/* */
+/****************************************************************************************/
+
+LVEQNB_ReturnStatus_en LVEQNB_Control(LVEQNB_Handle_t hInstance,
+ LVEQNB_Params_t *pParams)
+{
+
+ LVEQNB_Instance_t *pInstance = (LVEQNB_Instance_t *)hInstance;
+ LVM_INT16 bChange = LVM_FALSE;
+ LVM_INT16 i = 0;
+ LVEQNB_Mode_en OperatingModeSave ;
+
+ /*
+ * Check for error conditions
+ */
+ if((hInstance == LVM_NULL) || (pParams == LVM_NULL))
+ {
+ return LVEQNB_NULLADDRESS;
+ }
+
+ if((pParams->NBands !=0) && (pParams->pBandDefinition==LVM_NULL))
+ {
+ return LVEQNB_NULLADDRESS;
+ }
+
+ OperatingModeSave = pInstance->Params.OperatingMode;
+
+ /* Set the alpha factor of the mixer */
+ if (pParams->SampleRate != pInstance->Params.SampleRate)
+ {
+ LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMixer.MixerStream[0],LVEQNB_BYPASS_MIXER_TC,(LVM_Fs_en)pParams->SampleRate,2);
+ LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMixer.MixerStream[1],LVEQNB_BYPASS_MIXER_TC,(LVM_Fs_en)pParams->SampleRate,2);
+ }
+
+ if( (pInstance->Params.NBands != pParams->NBands ) ||
+ (pInstance->Params.OperatingMode != pParams->OperatingMode ) ||
+ (pInstance->Params.pBandDefinition != pParams->pBandDefinition ) ||
+ (pInstance->Params.SampleRate != pParams->SampleRate ) ||
+ (pInstance->Params.SourceFormat != pParams->SourceFormat ))
+ {
+
+ bChange = LVM_TRUE;
+ }
+ else
+ {
+ for(i = 0; i < pParams->NBands; i++)
+ {
+
+ if((pInstance->pBandDefinitions[i].Frequency != pParams->pBandDefinition[i].Frequency )||
+ (pInstance->pBandDefinitions[i].Gain != pParams->pBandDefinition[i].Gain )||
+ (pInstance->pBandDefinitions[i].QFactor != pParams->pBandDefinition[i].QFactor ))
+ {
+
+ bChange = LVM_TRUE;
+ }
+ }
+ }
+
+ // During operating mode transition, there is a race condition where the mode
+ // is still LVEQNB_ON, but the effect is considered disabled in the upper layers.
+ // modeChange handles this special race condition.
+ const int /* bool */ modeChange = pParams->OperatingMode != OperatingModeSave
+ || (OperatingModeSave == LVEQNB_ON
+ && pInstance->bInOperatingModeTransition
+ && LVC_Mixer_GetTarget(&pInstance->BypassMixer.MixerStream[0]) == 0);
+
+ if (bChange || modeChange) {
+
+ /*
+ * If the sample rate has changed clear the history
+ */
+ if (pInstance->Params.SampleRate != pParams->SampleRate)
+ {
+ LVEQNB_ClearFilterHistory(pInstance); /* Clear the history */
+ }
+
+ /*
+ * Update the instance parameters
+ */
+ pInstance->Params = *pParams;
+
+ /*
+ * Reset the filters except if the algo is switched off
+ */
+ if(pParams->OperatingMode != LVEQNB_BYPASS){
+ /*
+ * Reset the filters as all parameters could have changed
+ */
+ LVEQNB_SetFilters(pInstance, /* Instance pointer */
+ pParams); /* New parameters */
+
+ /*
+ * Update the filters
+ */
+ LVEQNB_SetCoefficients(pInstance); /* Instance pointer */
+ }
+
+ if (modeChange) {
+ if(pParams->OperatingMode == LVEQNB_ON)
+ {
+ LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[0], 1.0f);
+ LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[1], 0.0f);
+ pInstance->BypassMixer.MixerStream[0].CallbackSet = 1;
+ pInstance->BypassMixer.MixerStream[1].CallbackSet = 1;
+ }
+ else
+ {
+ /* Stay on the ON operating mode until the transition is done */
+ // This may introduce a state race condition if the effect is enabled again
+ // while in transition. This is fixed in the modeChange logic.
+ pInstance->Params.OperatingMode = LVEQNB_ON;
+ LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[0], 0.0f);
+ LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[1], 1.0f);
+ pInstance->BypassMixer.MixerStream[0].CallbackSet = 1;
+ pInstance->BypassMixer.MixerStream[1].CallbackSet = 1;
+ }
+ LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMixer.MixerStream[0],LVEQNB_BYPASS_MIXER_TC,(LVM_Fs_en)pParams->SampleRate,2);
+ LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMixer.MixerStream[1],LVEQNB_BYPASS_MIXER_TC,(LVM_Fs_en)pParams->SampleRate,2);
+ pInstance->bInOperatingModeTransition = LVM_TRUE;
+ }
+
+ }
+ return(LVEQNB_SUCCESS);
+}
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVEQNB_BypassMixerCallBack */
+/* */
+/* DESCRIPTION: */
+/* CallBack function of the mixer */
+/* transition */
+/* */
+/****************************************************************************************/
+LVM_INT32 LVEQNB_BypassMixerCallBack (void* hInstance,
+ void *pGeneralPurpose,
+ LVM_INT16 CallbackParam)
+{
+ LVEQNB_Instance_t *pInstance =(LVEQNB_Instance_t *)hInstance;
+ LVM_Callback CallBack = pInstance->Capabilities.CallBack;
+
+ (void) pGeneralPurpose;
+
+ /*
+ * Send an ALGOFF event if the ON->OFF switch transition is finished
+ */
+ if((LVC_Mixer_GetTarget(&pInstance->BypassMixer.MixerStream[0]) == 0) &&
+ (CallbackParam == 0)){
+ pInstance->Params.OperatingMode = LVEQNB_BYPASS;
+ if (CallBack != LVM_NULL){
+ CallBack(pInstance->Capabilities.pBundleInstance, LVM_NULL, ALGORITHM_EQNB_ID|LVEQNB_EVENT_ALGOFF);
+ }
+ }
+
+ /*
+ * Exit transition state
+ */
+ pInstance->bInOperatingModeTransition = LVM_FALSE;
+
+ return 1;
+}
diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Init.c b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Init.c
deleted file mode 100644
index de1bbb7..0000000
--- a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Init.c
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-/****************************************************************************************/
-/* */
-/* Includes */
-/* */
-/****************************************************************************************/
-
-#include "LVEQNB.h"
-#include "LVEQNB_Private.h"
-#include "InstAlloc.h"
-#include <string.h> /* For memset */
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVEQNB_Memory */
-/* */
-/* DESCRIPTION: */
-/* This function is used for memory allocation and free. It can be called in */
-/* two ways: */
-/* */
-/* hInstance = NULL Returns the memory requirements */
-/* hInstance = Instance handle Returns the memory requirements and */
-/* allocated base addresses for the instance */
-/* */
-/* When this function is called for memory allocation (hInstance=NULL) the memory */
-/* base address pointers are NULL on return. */
-/* */
-/* When the function is called for free (hInstance = Instance Handle) the memory */
-/* table returns the allocated memory and base addresses used during initialisation. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance Handle */
-/* pMemoryTable Pointer to an empty memory definition table */
-/* pCapabilities Pointer to the instance capabilities */
-/* */
-/* RETURNS: */
-/* LVEQNB_SUCCESS Succeeded */
-/* LVEQNB_NULLADDRESS When any of pMemoryTable and pCapabilities is NULL address */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVEQNB_Process function */
-/* */
-/****************************************************************************************/
-
-LVEQNB_ReturnStatus_en LVEQNB_Memory(LVEQNB_Handle_t hInstance,
- LVEQNB_MemTab_t *pMemoryTable,
- LVEQNB_Capabilities_t *pCapabilities)
-{
-
- INST_ALLOC AllocMem;
- LVEQNB_Instance_t *pInstance = (LVEQNB_Instance_t *)hInstance;
-
-
- if((pMemoryTable == LVM_NULL)|| (pCapabilities == LVM_NULL))
- {
- return LVEQNB_NULLADDRESS;
- }
-
-
- /*
- * Fill in the memory table
- */
- if (hInstance == LVM_NULL)
- {
- /*
- * Instance memory
- */
- InstAlloc_Init(&AllocMem,
- LVM_NULL);
- InstAlloc_AddMember(&AllocMem, /* Low pass filter */
- sizeof(LVEQNB_Instance_t));
- pMemoryTable->Region[LVEQNB_MEMREGION_INSTANCE].Size = InstAlloc_GetTotal(&AllocMem);
- pMemoryTable->Region[LVEQNB_MEMREGION_INSTANCE].Alignment = LVEQNB_INSTANCE_ALIGN;
- pMemoryTable->Region[LVEQNB_MEMREGION_INSTANCE].Type = LVEQNB_PERSISTENT;
- pMemoryTable->Region[LVEQNB_MEMREGION_INSTANCE].pBaseAddress = LVM_NULL;
-
-
- /*
- * Persistant data memory
- */
- InstAlloc_Init(&AllocMem,
- LVM_NULL);
-#ifdef BUILD_FLOAT
- InstAlloc_AddMember(&AllocMem, /* Low pass filter */
- sizeof(Biquad_2I_Order2_FLOAT_Taps_t));
- InstAlloc_AddMember(&AllocMem, /* High pass filter */
- sizeof(Biquad_2I_Order2_FLOAT_Taps_t));
- /* Equaliser Biquad Taps */
- InstAlloc_AddMember(&AllocMem,
- (pCapabilities->MaxBands * sizeof(Biquad_2I_Order2_FLOAT_Taps_t)));
- /* Filter definitions */
- InstAlloc_AddMember(&AllocMem,
- (pCapabilities->MaxBands * sizeof(LVEQNB_BandDef_t)));
- /* Biquad types */
- InstAlloc_AddMember(&AllocMem,
- (pCapabilities->MaxBands * sizeof(LVEQNB_BiquadType_en)));
-#else
- InstAlloc_AddMember(&AllocMem, /* Low pass filter */
- sizeof(Biquad_2I_Order2_Taps_t));
- InstAlloc_AddMember(&AllocMem, /* High pass filter */
- sizeof(Biquad_2I_Order2_Taps_t));
- InstAlloc_AddMember(&AllocMem,
- (pCapabilities->MaxBands * sizeof(Biquad_2I_Order2_Taps_t))); /* Equaliser Biquad Taps */
- InstAlloc_AddMember(&AllocMem,
- (pCapabilities->MaxBands * sizeof(LVEQNB_BandDef_t))); /* Filter definitions */
- InstAlloc_AddMember(&AllocMem,
- (pCapabilities->MaxBands * sizeof(LVEQNB_BiquadType_en))); /* Biquad types */
-#endif
- pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_DATA].Size = InstAlloc_GetTotal(&AllocMem);
- pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_DATA].Alignment = LVEQNB_DATA_ALIGN;
- pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_DATA].Type = LVEQNB_PERSISTENT_DATA;
- pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_DATA].pBaseAddress = LVM_NULL;
-
- /*
- * Persistant coefficient memory
- */
- InstAlloc_Init(&AllocMem,
- LVM_NULL);
-#ifdef BUILD_FLOAT
- InstAlloc_AddMember(&AllocMem, /* Low pass filter */
- sizeof(Biquad_FLOAT_Instance_t));
- InstAlloc_AddMember(&AllocMem, /* High pass filter */
- sizeof(Biquad_FLOAT_Instance_t));
- /* Equaliser Biquad Instance */
- InstAlloc_AddMember(&AllocMem,
- pCapabilities->MaxBands * sizeof(Biquad_FLOAT_Instance_t));
-#else
- InstAlloc_AddMember(&AllocMem, /* Low pass filter */
- sizeof(Biquad_Instance_t));
- InstAlloc_AddMember(&AllocMem, /* High pass filter */
- sizeof(Biquad_Instance_t));
- InstAlloc_AddMember(&AllocMem,
- pCapabilities->MaxBands * sizeof(Biquad_Instance_t)); /* Equaliser Biquad Instance */
-#endif
- pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_COEF].Size = InstAlloc_GetTotal(&AllocMem);
- pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_COEF].Alignment = LVEQNB_COEF_ALIGN;
- pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_COEF].Type = LVEQNB_PERSISTENT_COEF;
- pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_COEF].pBaseAddress = LVM_NULL;
-
- /*
- * Scratch memory
- */
- InstAlloc_Init(&AllocMem,
- LVM_NULL);
-#ifdef BUILD_FLOAT
- InstAlloc_AddMember(&AllocMem, /* Low pass filter */
- LVEQNB_SCRATCHBUFFERS * sizeof(LVM_FLOAT) * \
- pCapabilities->MaxBlockSize);
-#else
- InstAlloc_AddMember(&AllocMem, /* Low pass filter */
- LVEQNB_SCRATCHBUFFERS*sizeof(LVM_INT16)*pCapabilities->MaxBlockSize);
-#endif
- pMemoryTable->Region[LVEQNB_MEMREGION_SCRATCH].Size = InstAlloc_GetTotal(&AllocMem);
- pMemoryTable->Region[LVEQNB_MEMREGION_SCRATCH].Alignment = LVEQNB_SCRATCH_ALIGN;
- pMemoryTable->Region[LVEQNB_MEMREGION_SCRATCH].Type = LVEQNB_SCRATCH;
- pMemoryTable->Region[LVEQNB_MEMREGION_SCRATCH].pBaseAddress = LVM_NULL;
- }
- else
- {
- /* Read back memory allocation table */
- *pMemoryTable = pInstance->MemoryTable;
- }
-
- return(LVEQNB_SUCCESS);
-}
-
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVEQNB_Init */
-/* */
-/* DESCRIPTION: */
-/* Create and initialisation function for the N-Band equaliser module */
-/* */
-/* This function can be used to create an algorithm instance by calling with */
-/* hInstance set to NULL. In this case the algorithm returns the new instance */
-/* handle. */
-/* */
-/* This function can be used to force a full re-initialisation of the algorithm */
-/* by calling with hInstance = Instance Handle. In this case the memory table */
-/* should be correct for the instance, this can be ensured by calling the function */
-/* DBE_Memory before calling this function. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance handle */
-/* pMemoryTable Pointer to the memory definition table */
-/* pCapabilities Pointer to the instance capabilities */
-/* */
-/* RETURNS: */
-/* LVEQNB_SUCCESS Initialisation succeeded */
-/* LVEQNB_NULLADDRESS When pCapabilities or pMemoryTableis or phInstance are NULL */
-/* LVEQNB_NULLADDRESS One or more of the memory regions has a NULL base address */
-/* pointer for a memory region with a non-zero size. */
-/* */
-/* NOTES: */
-/* 1. The instance handle is the pointer to the base address of the first memory */
-/* region. */
-/* 2. This function must not be interrupted by the LVEQNB_Process function */
-/* */
-/****************************************************************************************/
-
-LVEQNB_ReturnStatus_en LVEQNB_Init(LVEQNB_Handle_t *phInstance,
- LVEQNB_MemTab_t *pMemoryTable,
- LVEQNB_Capabilities_t *pCapabilities)
-{
-
- LVEQNB_Instance_t *pInstance;
- LVM_UINT32 MemSize;
- INST_ALLOC AllocMem;
- LVM_INT32 i;
-
- /*
- * Check for NULL pointers
- */
- if((phInstance == LVM_NULL) || (pMemoryTable == LVM_NULL) || (pCapabilities == LVM_NULL))
- {
- return LVEQNB_NULLADDRESS;
- }
-
- /*
- * Check the memory table for NULL pointers
- */
- for (i = 0; i < LVEQNB_NR_MEMORY_REGIONS; i++)
- {
- if (pMemoryTable->Region[i].Size!=0)
- {
- if (pMemoryTable->Region[i].pBaseAddress==LVM_NULL)
- {
- return(LVEQNB_NULLADDRESS);
- }
- }
- }
-
- /*
- * Set the instance handle if not already initialised
- */
-
- InstAlloc_Init(&AllocMem, pMemoryTable->Region[LVEQNB_MEMREGION_INSTANCE].pBaseAddress);
-
- if (*phInstance == LVM_NULL)
- {
- *phInstance = InstAlloc_AddMember(&AllocMem, sizeof(LVEQNB_Instance_t));
- }
- pInstance =(LVEQNB_Instance_t *)*phInstance;
-
-
-
- /*
- * Save the memory table in the instance structure
- */
- pInstance->Capabilities = *pCapabilities;
-
-
- /*
- * Save the memory table in the instance structure and
- * set the structure pointers
- */
- pInstance->MemoryTable = *pMemoryTable;
-
- /*
- * Allocate coefficient memory
- */
- InstAlloc_Init(&AllocMem,
- pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_COEF].pBaseAddress);
-
-#ifdef BUILD_FLOAT
- /* Equaliser Biquad Instance */
- pInstance->pEQNB_FilterState_Float = InstAlloc_AddMember(&AllocMem,
- pCapabilities->MaxBands * \
- sizeof(Biquad_FLOAT_Instance_t));
-#else
- pInstance->pEQNB_FilterState = InstAlloc_AddMember(&AllocMem,
- pCapabilities->MaxBands * sizeof(Biquad_Instance_t)); /* Equaliser Biquad Instance */
-#endif
-
-
-
- /*
- * Allocate data memory
- */
- InstAlloc_Init(&AllocMem,
- pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_DATA].pBaseAddress);
-
-#ifdef BUILD_FLOAT
- MemSize = (pCapabilities->MaxBands * sizeof(Biquad_2I_Order2_FLOAT_Taps_t));
- pInstance->pEQNB_Taps_Float = (Biquad_2I_Order2_FLOAT_Taps_t *)InstAlloc_AddMember(&AllocMem,
- MemSize);
-#else
- MemSize = (pCapabilities->MaxBands * sizeof(Biquad_2I_Order2_Taps_t));
- pInstance->pEQNB_Taps = (Biquad_2I_Order2_Taps_t *)InstAlloc_AddMember(&AllocMem,
- MemSize);
-#endif
- MemSize = (pCapabilities->MaxBands * sizeof(LVEQNB_BandDef_t));
- pInstance->pBandDefinitions = (LVEQNB_BandDef_t *)InstAlloc_AddMember(&AllocMem,
- MemSize);
- // clear all the bands, setting their gain to 0, otherwise when applying new params,
- // it will compare against uninitialized values
- memset(pInstance->pBandDefinitions, 0, MemSize);
- MemSize = (pCapabilities->MaxBands * sizeof(LVEQNB_BiquadType_en));
- pInstance->pBiquadType = (LVEQNB_BiquadType_en *)InstAlloc_AddMember(&AllocMem,
- MemSize);
-
-
- /*
- * Internally map, structure and allign scratch memory
- */
- InstAlloc_Init(&AllocMem,
- pMemoryTable->Region[LVEQNB_MEMREGION_SCRATCH].pBaseAddress);
-
-#ifdef BUILD_FLOAT
- pInstance->pFastTemporary = (LVM_FLOAT *)InstAlloc_AddMember(&AllocMem,
- sizeof(LVM_FLOAT));
-#else
- pInstance->pFastTemporary = (LVM_INT16 *)InstAlloc_AddMember(&AllocMem,
- sizeof(LVM_INT16));
-#endif
-
- /*
- * Update the instance parameters
- */
- pInstance->Params.NBands = 0;
- pInstance->Params.OperatingMode = LVEQNB_BYPASS;
- pInstance->Params.pBandDefinition = LVM_NULL;
- pInstance->Params.SampleRate = LVEQNB_FS_8000;
- pInstance->Params.SourceFormat = LVEQNB_STEREO;
-
- /*
- * Initialise the filters
- */
- LVEQNB_SetFilters(pInstance, /* Set the filter types */
- &pInstance->Params);
-
- LVEQNB_SetCoefficients(pInstance); /* Set the filter coefficients */
-
- LVEQNB_ClearFilterHistory(pInstance); /* Clear the filter history */
-
- /*
- * Initialise the bypass variables
- */
- pInstance->BypassMixer.MixerStream[0].CallbackSet = 0;
- pInstance->BypassMixer.MixerStream[0].CallbackParam = 0;
- pInstance->BypassMixer.MixerStream[0].pCallbackHandle = (void*)pInstance;
- pInstance->BypassMixer.MixerStream[0].pCallBack = LVEQNB_BypassMixerCallBack;
-
- LVC_Mixer_Init(&pInstance->BypassMixer.MixerStream[0],0,0);
- LVC_Mixer_SetTimeConstant(&pInstance->BypassMixer.MixerStream[0],0,LVM_FS_8000,2);
-
-
- pInstance->BypassMixer.MixerStream[1].CallbackSet = 1;
- pInstance->BypassMixer.MixerStream[1].CallbackParam = 0;
- pInstance->BypassMixer.MixerStream[1].pCallbackHandle = LVM_NULL;
- pInstance->BypassMixer.MixerStream[1].pCallBack = LVM_NULL;
-#ifdef BUILD_FLOAT
- LVC_Mixer_Init(&pInstance->BypassMixer.MixerStream[1], 0, 1.0f);
- LVC_Mixer_SetTimeConstant(&pInstance->BypassMixer.MixerStream[1], 0, LVM_FS_8000, 2);
-#else
- LVC_Mixer_Init(&pInstance->BypassMixer.MixerStream[1],0,LVM_MAXINT_16);
- LVC_Mixer_SetTimeConstant(&pInstance->BypassMixer.MixerStream[1],0,LVM_FS_8000,2);
-#endif
-
- pInstance->bInOperatingModeTransition = LVM_FALSE;
-
- return(LVEQNB_SUCCESS);
-}
-
diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Init.cpp b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Init.cpp
new file mode 100644
index 0000000..271a914
--- /dev/null
+++ b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Init.cpp
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/****************************************************************************************/
+/* */
+/* Includes */
+/* */
+/****************************************************************************************/
+
+#include "LVEQNB.h"
+#include "LVEQNB_Private.h"
+#include "InstAlloc.h"
+#include <string.h> /* For memset */
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVEQNB_Memory */
+/* */
+/* DESCRIPTION: */
+/* This function is used for memory allocation and free. It can be called in */
+/* two ways: */
+/* */
+/* hInstance = NULL Returns the memory requirements */
+/* hInstance = Instance handle Returns the memory requirements and */
+/* allocated base addresses for the instance */
+/* */
+/* When this function is called for memory allocation (hInstance=NULL) the memory */
+/* base address pointers are NULL on return. */
+/* */
+/* When the function is called for free (hInstance = Instance Handle) the memory */
+/* table returns the allocated memory and base addresses used during initialisation. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance Handle */
+/* pMemoryTable Pointer to an empty memory definition table */
+/* pCapabilities Pointer to the instance capabilities */
+/* */
+/* RETURNS: */
+/* LVEQNB_SUCCESS Succeeded */
+/* LVEQNB_NULLADDRESS When any of pMemoryTable and pCapabilities is NULL address */
+/* */
+/* NOTES: */
+/* 1. This function may be interrupted by the LVEQNB_Process function */
+/* */
+/****************************************************************************************/
+
+LVEQNB_ReturnStatus_en LVEQNB_Memory(LVEQNB_Handle_t hInstance,
+ LVEQNB_MemTab_t *pMemoryTable,
+ LVEQNB_Capabilities_t *pCapabilities)
+{
+
+ INST_ALLOC AllocMem;
+ LVEQNB_Instance_t *pInstance = (LVEQNB_Instance_t *)hInstance;
+
+ if((pMemoryTable == LVM_NULL)|| (pCapabilities == LVM_NULL))
+ {
+ return LVEQNB_NULLADDRESS;
+ }
+
+ /*
+ * Fill in the memory table
+ */
+ if (hInstance == LVM_NULL)
+ {
+ /*
+ * Instance memory
+ */
+ InstAlloc_Init(&AllocMem,
+ LVM_NULL);
+ InstAlloc_AddMember(&AllocMem, /* Low pass filter */
+ sizeof(LVEQNB_Instance_t));
+ pMemoryTable->Region[LVEQNB_MEMREGION_INSTANCE].Size = InstAlloc_GetTotal(&AllocMem);
+ pMemoryTable->Region[LVEQNB_MEMREGION_INSTANCE].Alignment = LVEQNB_INSTANCE_ALIGN;
+ pMemoryTable->Region[LVEQNB_MEMREGION_INSTANCE].Type = LVEQNB_PERSISTENT;
+ pMemoryTable->Region[LVEQNB_MEMREGION_INSTANCE].pBaseAddress = LVM_NULL;
+
+ /*
+ * Persistant data memory
+ */
+ InstAlloc_Init(&AllocMem,
+ LVM_NULL);
+ InstAlloc_AddMember(&AllocMem, /* Low pass filter */
+ sizeof(Biquad_2I_Order2_FLOAT_Taps_t));
+ InstAlloc_AddMember(&AllocMem, /* High pass filter */
+ sizeof(Biquad_2I_Order2_FLOAT_Taps_t));
+ /* Equaliser Biquad Taps */
+ InstAlloc_AddMember(&AllocMem,
+ (pCapabilities->MaxBands * sizeof(Biquad_2I_Order2_FLOAT_Taps_t)));
+ /* Filter definitions */
+ InstAlloc_AddMember(&AllocMem,
+ (pCapabilities->MaxBands * sizeof(LVEQNB_BandDef_t)));
+ /* Biquad types */
+ InstAlloc_AddMember(&AllocMem,
+ (pCapabilities->MaxBands * sizeof(LVEQNB_BiquadType_en)));
+ pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_DATA].Size = InstAlloc_GetTotal(&AllocMem);
+ pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_DATA].Alignment = LVEQNB_DATA_ALIGN;
+ pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_DATA].Type = LVEQNB_PERSISTENT_DATA;
+ pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_DATA].pBaseAddress = LVM_NULL;
+
+ /*
+ * Persistant coefficient memory
+ */
+ InstAlloc_Init(&AllocMem,
+ LVM_NULL);
+ InstAlloc_AddMember(&AllocMem, /* Low pass filter */
+ sizeof(Biquad_FLOAT_Instance_t));
+ InstAlloc_AddMember(&AllocMem, /* High pass filter */
+ sizeof(Biquad_FLOAT_Instance_t));
+ /* Equaliser Biquad Instance */
+ InstAlloc_AddMember(&AllocMem,
+ pCapabilities->MaxBands * sizeof(Biquad_FLOAT_Instance_t));
+ pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_COEF].Size = InstAlloc_GetTotal(&AllocMem);
+ pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_COEF].Alignment = LVEQNB_COEF_ALIGN;
+ pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_COEF].Type = LVEQNB_PERSISTENT_COEF;
+ pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_COEF].pBaseAddress = LVM_NULL;
+
+ /*
+ * Scratch memory
+ */
+ InstAlloc_Init(&AllocMem,
+ LVM_NULL);
+ InstAlloc_AddMember(&AllocMem, /* Low pass filter */
+ LVEQNB_SCRATCHBUFFERS * sizeof(LVM_FLOAT) * \
+ pCapabilities->MaxBlockSize);
+ pMemoryTable->Region[LVEQNB_MEMREGION_SCRATCH].Size = InstAlloc_GetTotal(&AllocMem);
+ pMemoryTable->Region[LVEQNB_MEMREGION_SCRATCH].Alignment = LVEQNB_SCRATCH_ALIGN;
+ pMemoryTable->Region[LVEQNB_MEMREGION_SCRATCH].Type = LVEQNB_SCRATCH;
+ pMemoryTable->Region[LVEQNB_MEMREGION_SCRATCH].pBaseAddress = LVM_NULL;
+ }
+ else
+ {
+ /* Read back memory allocation table */
+ *pMemoryTable = pInstance->MemoryTable;
+ }
+
+ return(LVEQNB_SUCCESS);
+}
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVEQNB_Init */
+/* */
+/* DESCRIPTION: */
+/* Create and initialisation function for the N-Band equaliser module */
+/* */
+/* This function can be used to create an algorithm instance by calling with */
+/* hInstance set to NULL. In this case the algorithm returns the new instance */
+/* handle. */
+/* */
+/* This function can be used to force a full re-initialisation of the algorithm */
+/* by calling with hInstance = Instance Handle. In this case the memory table */
+/* should be correct for the instance, this can be ensured by calling the function */
+/* DBE_Memory before calling this function. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance handle */
+/* pMemoryTable Pointer to the memory definition table */
+/* pCapabilities Pointer to the instance capabilities */
+/* */
+/* RETURNS: */
+/* LVEQNB_SUCCESS Initialisation succeeded */
+/* LVEQNB_NULLADDRESS When pCapabilities or pMemoryTableis or phInstance are NULL */
+/* LVEQNB_NULLADDRESS One or more of the memory regions has a NULL base address */
+/* pointer for a memory region with a non-zero size. */
+/* */
+/* NOTES: */
+/* 1. The instance handle is the pointer to the base address of the first memory */
+/* region. */
+/* 2. This function must not be interrupted by the LVEQNB_Process function */
+/* */
+/****************************************************************************************/
+
+LVEQNB_ReturnStatus_en LVEQNB_Init(LVEQNB_Handle_t *phInstance,
+ LVEQNB_MemTab_t *pMemoryTable,
+ LVEQNB_Capabilities_t *pCapabilities)
+{
+
+ LVEQNB_Instance_t *pInstance;
+ LVM_UINT32 MemSize;
+ INST_ALLOC AllocMem;
+ LVM_INT32 i;
+
+ /*
+ * Check for NULL pointers
+ */
+ if((phInstance == LVM_NULL) || (pMemoryTable == LVM_NULL) || (pCapabilities == LVM_NULL))
+ {
+ return LVEQNB_NULLADDRESS;
+ }
+
+ /*
+ * Check the memory table for NULL pointers
+ */
+ for (i = 0; i < LVEQNB_NR_MEMORY_REGIONS; i++)
+ {
+ if (pMemoryTable->Region[i].Size!=0)
+ {
+ if (pMemoryTable->Region[i].pBaseAddress==LVM_NULL)
+ {
+ return(LVEQNB_NULLADDRESS);
+ }
+ }
+ }
+
+ /*
+ * Set the instance handle if not already initialised
+ */
+
+ InstAlloc_Init(&AllocMem, pMemoryTable->Region[LVEQNB_MEMREGION_INSTANCE].pBaseAddress);
+
+ if (*phInstance == LVM_NULL)
+ {
+ *phInstance = InstAlloc_AddMember(&AllocMem, sizeof(LVEQNB_Instance_t));
+ }
+ pInstance =(LVEQNB_Instance_t *)*phInstance;
+
+ /*
+ * Save the memory table in the instance structure
+ */
+ pInstance->Capabilities = *pCapabilities;
+
+ /*
+ * Save the memory table in the instance structure and
+ * set the structure pointers
+ */
+ pInstance->MemoryTable = *pMemoryTable;
+
+ /*
+ * Allocate coefficient memory
+ */
+ InstAlloc_Init(&AllocMem,
+ pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_COEF].pBaseAddress);
+
+ /* Equaliser Biquad Instance */
+ pInstance->pEQNB_FilterState_Float = (Biquad_FLOAT_Instance_t *)
+ InstAlloc_AddMember(&AllocMem, pCapabilities->MaxBands * \
+ sizeof(Biquad_FLOAT_Instance_t));
+
+ /*
+ * Allocate data memory
+ */
+ InstAlloc_Init(&AllocMem,
+ pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_DATA].pBaseAddress);
+
+ MemSize = (pCapabilities->MaxBands * sizeof(Biquad_2I_Order2_FLOAT_Taps_t));
+ pInstance->pEQNB_Taps_Float = (Biquad_2I_Order2_FLOAT_Taps_t *)InstAlloc_AddMember(&AllocMem,
+ MemSize);
+ MemSize = (pCapabilities->MaxBands * sizeof(LVEQNB_BandDef_t));
+ pInstance->pBandDefinitions = (LVEQNB_BandDef_t *)InstAlloc_AddMember(&AllocMem,
+ MemSize);
+ // clear all the bands, setting their gain to 0, otherwise when applying new params,
+ // it will compare against uninitialized values
+ memset(pInstance->pBandDefinitions, 0, MemSize);
+ MemSize = (pCapabilities->MaxBands * sizeof(LVEQNB_BiquadType_en));
+ pInstance->pBiquadType = (LVEQNB_BiquadType_en *)InstAlloc_AddMember(&AllocMem,
+ MemSize);
+
+ /*
+ * Internally map, structure and allign scratch memory
+ */
+ InstAlloc_Init(&AllocMem,
+ pMemoryTable->Region[LVEQNB_MEMREGION_SCRATCH].pBaseAddress);
+
+ pInstance->pFastTemporary = (LVM_FLOAT *)InstAlloc_AddMember(&AllocMem,
+ sizeof(LVM_FLOAT));
+
+ /*
+ * Update the instance parameters
+ */
+ pInstance->Params.NBands = 0;
+ pInstance->Params.OperatingMode = LVEQNB_BYPASS;
+ pInstance->Params.pBandDefinition = LVM_NULL;
+ pInstance->Params.SampleRate = LVEQNB_FS_8000;
+ pInstance->Params.SourceFormat = LVEQNB_STEREO;
+
+ /*
+ * Initialise the filters
+ */
+ LVEQNB_SetFilters(pInstance, /* Set the filter types */
+ &pInstance->Params);
+
+ LVEQNB_SetCoefficients(pInstance); /* Set the filter coefficients */
+
+ LVEQNB_ClearFilterHistory(pInstance); /* Clear the filter history */
+
+ /*
+ * Initialise the bypass variables
+ */
+ pInstance->BypassMixer.MixerStream[0].CallbackSet = 0;
+ pInstance->BypassMixer.MixerStream[0].CallbackParam = 0;
+ pInstance->BypassMixer.MixerStream[0].pCallbackHandle = (void*)pInstance;
+ pInstance->BypassMixer.MixerStream[0].pCallBack = LVEQNB_BypassMixerCallBack;
+
+ LVC_Mixer_Init(&pInstance->BypassMixer.MixerStream[0],0,0);
+ LVC_Mixer_SetTimeConstant(&pInstance->BypassMixer.MixerStream[0],0,LVM_FS_8000,2);
+
+ pInstance->BypassMixer.MixerStream[1].CallbackSet = 1;
+ pInstance->BypassMixer.MixerStream[1].CallbackParam = 0;
+ pInstance->BypassMixer.MixerStream[1].pCallbackHandle = LVM_NULL;
+ pInstance->BypassMixer.MixerStream[1].pCallBack = LVM_NULL;
+ LVC_Mixer_Init(&pInstance->BypassMixer.MixerStream[1], 0, 1.0f);
+ LVC_Mixer_SetTimeConstant(&pInstance->BypassMixer.MixerStream[1], 0, LVM_FS_8000, 2);
+
+ pInstance->bInOperatingModeTransition = LVM_FALSE;
+
+ return(LVEQNB_SUCCESS);
+}
+
diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Private.h b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Private.h
index a9cd5fd..40facfb 100644
--- a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Private.h
+++ b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Private.h
@@ -18,11 +18,6 @@
#ifndef __LVEQNB_PRIVATE_H__
#define __LVEQNB_PRIVATE_H__
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-
/****************************************************************************************/
/* */
/* Includes */
@@ -65,24 +60,19 @@
/* Filter biquad types */
typedef enum
{
-#ifdef BUILD_FLOAT
LVEQNB_SinglePrecision_Float = -1,
-#endif
LVEQNB_SinglePrecision = 0,
LVEQNB_DoublePrecision = 1,
LVEQNB_OutOfRange = 2,
LVEQNB_BIQUADTYPE_MAX = LVM_MAXINT_32
} LVEQNB_BiquadType_en;
-
/****************************************************************************************/
/* */
/* Structures */
/* */
/****************************************************************************************/
-
-
/* Instance structure */
typedef struct
{
@@ -92,20 +82,10 @@
LVEQNB_Capabilities_t Capabilities; /* Instance capabilities */
/* Aligned memory pointers */
-#ifdef BUILD_FLOAT
LVM_FLOAT *pFastTemporary; /* Fast temporary data base address */
-#else
- LVM_INT16 *pFastTemporary; /* Fast temporary data base address */
-#endif
-#ifdef BUILD_FLOAT
Biquad_2I_Order2_FLOAT_Taps_t *pEQNB_Taps_Float; /* Equaliser Taps */
Biquad_FLOAT_Instance_t *pEQNB_FilterState_Float; /* State for each filter band */
-#else
- /* Process variables */
- Biquad_2I_Order2_Taps_t *pEQNB_Taps; /* Equaliser Taps */
- Biquad_Instance_t *pEQNB_FilterState; /* State for each filter band */
-#endif
/* Filter definitions and call back */
LVM_UINT16 NBands; /* Number of bands */
@@ -113,17 +93,12 @@
LVEQNB_BiquadType_en *pBiquadType; /* Filter biquad types */
/* Bypass variable */
-#ifdef BUILD_FLOAT
LVMixer3_2St_FLOAT_st BypassMixer;
-#else
- LVMixer3_2St_st BypassMixer; /* Bypass mixer used in transitions */
-#endif
LVM_INT16 bInOperatingModeTransition; /* Operating mode transition flag */
} LVEQNB_Instance_t;
-
/****************************************************************************************/
/* */
/* Function prototypes */
@@ -136,25 +111,11 @@
void LVEQNB_SetCoefficients(LVEQNB_Instance_t *pInstance);
void LVEQNB_ClearFilterHistory(LVEQNB_Instance_t *pInstance);
-#ifdef BUILD_FLOAT
LVEQNB_ReturnStatus_en LVEQNB_SinglePrecCoefs(LVM_UINT16 Fs,
LVEQNB_BandDef_t *pFilterDefinition,
PK_FLOAT_Coefs_t *pCoefficients);
-#else
-LVEQNB_ReturnStatus_en LVEQNB_SinglePrecCoefs(LVM_UINT16 Fs,
- LVEQNB_BandDef_t *pFilterDefinition,
- PK_C16_Coefs_t *pCoefficients);
-
-LVEQNB_ReturnStatus_en LVEQNB_DoublePrecCoefs(LVM_UINT16 Fs,
- LVEQNB_BandDef_t *pFilterDefinition,
- PK_C32_Coefs_t *pCoefficients);
-#endif
LVM_INT32 LVEQNB_BypassMixerCallBack (void* hInstance, void *pGeneralPurpose, LVM_INT16 CallbackParam);
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
#endif /* __LVEQNB_PRIVATE_H__ */
diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Process.c b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Process.c
deleted file mode 100644
index d188c0e..0000000
--- a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Process.c
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/****************************************************************************************/
-/* */
-/* Includes */
-/* */
-/****************************************************************************************/
-
-#include "LVEQNB.h"
-#include "LVEQNB_Private.h"
-#include "VectorArithmetic.h"
-#include "BIQUAD.h"
-
-#include <log/log.h>
-
-/****************************************************************************************/
-/* */
-/* Defines */
-/* */
-/****************************************************************************************/
-
-#define SHIFT 13
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVEQNB_Process */
-/* */
-/* DESCRIPTION: */
-/* Process function for the N-Band Equaliser module. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance handle */
-/* pInData Pointer to the input data */
-/* pOutData Pointer to the output data */
-/* NumSamples Number of samples in the input buffer */
-/* */
-/* RETURNS: */
-/* LVEQNB_SUCCESS Succeeded */
-/* LVEQNB_NULLADDRESS When hInstance, pInData or pOutData are NULL */
-/* LVEQNB_ALIGNMENTERROR When pInData or pOutData are not 32-bit aligned */
-/* LVEQNB_TOOMANYSAMPLES NumSamples was larger than the maximum block size */
-/* */
-/* NOTES: */
-/* */
-/****************************************************************************************/
-#ifdef BUILD_FLOAT
-LVEQNB_ReturnStatus_en LVEQNB_Process(LVEQNB_Handle_t hInstance,
- const LVM_FLOAT *pInData,
- LVM_FLOAT *pOutData,
- const LVM_UINT16 NrFrames)
-{ // updated to use samples = frames * channels.
- LVEQNB_Instance_t *pInstance = (LVEQNB_Instance_t *)hInstance;
-
-#ifdef SUPPORT_MC
- // Mono passed in as stereo
- const LVM_INT32 NrChannels = pInstance->Params.NrChannels == 1
- ? 2 : pInstance->Params.NrChannels;
-#else
- const LVM_INT32 NrChannels = 2; // FCC_2
-#endif
- const LVM_INT32 NrSamples = NrChannels * NrFrames;
-
- /* Check for NULL pointers */
- if((hInstance == LVM_NULL) || (pInData == LVM_NULL) || (pOutData == LVM_NULL))
- {
- return LVEQNB_NULLADDRESS;
- }
-
- /* Check if the input and output data buffers are 32-bit aligned */
- if ((((uintptr_t)pInData % 4) != 0) || (((uintptr_t)pOutData % 4) != 0))
- {
- return LVEQNB_ALIGNMENTERROR;
- }
-
- LVM_FLOAT * const pScratch = (LVM_FLOAT *)pInstance->pFastTemporary;
-
- /*
- * Check the number of frames is not too large
- */
- if (NrFrames > pInstance->Capabilities.MaxBlockSize)
- {
- return LVEQNB_TOOMANYSAMPLES;
- }
-
- if (pInstance->Params.OperatingMode == LVEQNB_ON)
- {
- /*
- * Copy input data in to scratch buffer
- */
- Copy_Float(pInData, /* Source */
- pScratch, /* Destination */
- (LVM_INT16)NrSamples);
-
- /*
- * For each section execte the filter unless the gain is 0dB
- */
- if (pInstance->NBands != 0)
- {
- for (LVM_UINT16 i = 0; i < pInstance->NBands; i++)
- {
- /*
- * Check if band is non-zero dB gain
- */
- if (pInstance->pBandDefinitions[i].Gain != 0)
- {
- /*
- * Get the address of the biquad instance
- */
- Biquad_FLOAT_Instance_t *pBiquad = &pInstance->pEQNB_FilterState_Float[i];
-
-
- /*
- * Select single or double precision as required
- */
- switch (pInstance->pBiquadType[i])
- {
- case LVEQNB_SinglePrecision_Float:
- {
-#ifdef SUPPORT_MC
- PK_Mc_D32F32C14G11_TRC_WRA_01(pBiquad,
- pScratch,
- pScratch,
- (LVM_INT16)NrFrames,
- (LVM_INT16)NrChannels);
-#else
- PK_2I_D32F32C14G11_TRC_WRA_01(pBiquad,
- pScratch,
- pScratch,
- (LVM_INT16)NrFrames);
-#endif
- break;
- }
- default:
- break;
- }
- }
- }
- }
-
-
- if(pInstance->bInOperatingModeTransition == LVM_TRUE){
-#ifdef SUPPORT_MC
- LVC_MixSoft_2Mc_D16C31_SAT(&pInstance->BypassMixer,
- pScratch,
- pInData,
- pScratch,
- (LVM_INT16)NrFrames,
- (LVM_INT16)NrChannels);
-#else
- LVC_MixSoft_2St_D16C31_SAT(&pInstance->BypassMixer,
- pScratch,
- pInData,
- pScratch,
- (LVM_INT16)NrSamples);
-#endif
- // duplicate with else clause(s)
- Copy_Float(pScratch, /* Source */
- pOutData, /* Destination */
- (LVM_INT16)NrSamples); /* All channel samples */
- }
- else{
- Copy_Float(pScratch, /* Source */
- pOutData, /* Destination */
- (LVM_INT16)NrSamples); /* All channel samples */
- }
- }
- else
- {
- /*
- * Mode is OFF so copy the data if necessary
- */
- if (pInData != pOutData)
- {
- Copy_Float(pInData, /* Source */
- pOutData, /* Destination */
- (LVM_INT16)NrSamples); /* All channel samples */
- }
- }
- return LVEQNB_SUCCESS;
-
-}
-#else
-LVEQNB_ReturnStatus_en LVEQNB_Process(LVEQNB_Handle_t hInstance,
- const LVM_INT16 *pInData,
- LVM_INT16 *pOutData,
- LVM_UINT16 NumSamples)
-{
-
- LVM_UINT16 i;
- Biquad_Instance_t *pBiquad;
- LVEQNB_Instance_t *pInstance = (LVEQNB_Instance_t *)hInstance;
- LVM_INT32 *pScratch;
-
-
- /* Check for NULL pointers */
- if((hInstance == LVM_NULL) || (pInData == LVM_NULL) || (pOutData == LVM_NULL))
- {
- return LVEQNB_NULLADDRESS;
- }
-
- /* Check if the input and output data buffers are 32-bit aligned */
- if ((((uintptr_t)pInData % 4) != 0) || (((uintptr_t)pOutData % 4) != 0))
- {
- return LVEQNB_ALIGNMENTERROR;
- }
-
- pScratch = (LVM_INT32 *)pInstance->pFastTemporary;
-
- /*
- * Check the number of samples is not too large
- */
- if (NumSamples > pInstance->Capabilities.MaxBlockSize)
- {
- return(LVEQNB_TOOMANYSAMPLES);
- }
-
- if (pInstance->Params.OperatingMode == LVEQNB_ON)
- {
- /*
- * Convert from 16-bit to 32-bit
- */
- Int16LShiftToInt32_16x32((LVM_INT16 *)pInData, /* Source */
- pScratch, /* Destination */
- (LVM_INT16)(2*NumSamples), /* Left and Right */
- SHIFT); /* Scaling shift */
-
- /*
- * For each section execte the filter unless the gain is 0dB
- */
- if (pInstance->NBands != 0)
- {
- for (i=0; i<pInstance->NBands; i++)
- {
- /*
- * Check if band is non-zero dB gain
- */
- if (pInstance->pBandDefinitions[i].Gain != 0)
- {
- /*
- * Get the address of the biquad instance
- */
- pBiquad = &pInstance->pEQNB_FilterState[i];
-
-
- /*
- * Select single or double precision as required
- */
- switch (pInstance->pBiquadType[i])
- {
- case LVEQNB_SinglePrecision:
- {
- PK_2I_D32F32C14G11_TRC_WRA_01(pBiquad,
- (LVM_INT32 *)pScratch,
- (LVM_INT32 *)pScratch,
- (LVM_INT16)NumSamples);
- break;
- }
-
- case LVEQNB_DoublePrecision:
- {
- PK_2I_D32F32C30G11_TRC_WRA_01(pBiquad,
- (LVM_INT32 *)pScratch,
- (LVM_INT32 *)pScratch,
- (LVM_INT16)NumSamples);
- break;
- }
- default:
- break;
- }
- }
- }
- }
-
-
- if(pInstance->bInOperatingModeTransition == LVM_TRUE){
- /*
- * Convert from 32-bit to 16- bit and saturate
- */
- Int32RShiftToInt16_Sat_32x16(pScratch, /* Source */
- (LVM_INT16 *)pScratch, /* Destination */
- (LVM_INT16)(2*NumSamples), /* Left and Right */
- SHIFT); /* Scaling shift */
-
- LVC_MixSoft_2St_D16C31_SAT(&pInstance->BypassMixer,
- (LVM_INT16 *)pScratch,
- (LVM_INT16 *)pInData,
- (LVM_INT16 *)pScratch,
- (LVM_INT16)(2*NumSamples));
-
- Copy_16((LVM_INT16*)pScratch, /* Source */
- pOutData, /* Destination */
- (LVM_INT16)(2*NumSamples)); /* Left and Right samples */
- }
- else{
-
- /*
- * Convert from 32-bit to 16- bit and saturate
- */
- Int32RShiftToInt16_Sat_32x16(pScratch, /* Source */
- pOutData, /* Destination */
- (LVM_INT16 )(2*NumSamples), /* Left and Right */
- SHIFT); /* Scaling shift */
- }
- }
- else
- {
- /*
- * Mode is OFF so copy the data if necessary
- */
- if (pInData != pOutData)
- {
- Copy_16(pInData, /* Source */
- pOutData, /* Destination */
- (LVM_INT16)(2*NumSamples)); /* Left and Right samples */
- }
- }
-
-
-
- return(LVEQNB_SUCCESS);
-
-}
-#endif
diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Process.cpp b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Process.cpp
new file mode 100644
index 0000000..65eff53
--- /dev/null
+++ b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Process.cpp
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/****************************************************************************************/
+/* */
+/* Includes */
+/* */
+/****************************************************************************************/
+
+#include "LVEQNB.h"
+#include "LVEQNB_Private.h"
+#include "VectorArithmetic.h"
+#include "BIQUAD.h"
+
+#include <log/log.h>
+
+/****************************************************************************************/
+/* */
+/* Defines */
+/* */
+/****************************************************************************************/
+
+#define SHIFT 13
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVEQNB_Process */
+/* */
+/* DESCRIPTION: */
+/* Process function for the N-Band Equaliser module. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance handle */
+/* pInData Pointer to the input data */
+/* pOutData Pointer to the output data */
+/* NumSamples Number of samples in the input buffer */
+/* */
+/* RETURNS: */
+/* LVEQNB_SUCCESS Succeeded */
+/* LVEQNB_NULLADDRESS When hInstance, pInData or pOutData are NULL */
+/* LVEQNB_ALIGNMENTERROR When pInData or pOutData are not 32-bit aligned */
+/* LVEQNB_TOOMANYSAMPLES NumSamples was larger than the maximum block size */
+/* */
+/* NOTES: */
+/* */
+/****************************************************************************************/
+LVEQNB_ReturnStatus_en LVEQNB_Process(LVEQNB_Handle_t hInstance,
+ const LVM_FLOAT *pInData,
+ LVM_FLOAT *pOutData,
+ const LVM_UINT16 NrFrames)
+{ // updated to use samples = frames * channels.
+ LVEQNB_Instance_t *pInstance = (LVEQNB_Instance_t *)hInstance;
+
+#ifdef SUPPORT_MC
+ // Mono passed in as stereo
+ const LVM_INT32 NrChannels = pInstance->Params.NrChannels == 1
+ ? 2 : pInstance->Params.NrChannels;
+#else
+ const LVM_INT32 NrChannels = 2; // FCC_2
+#endif
+ const LVM_INT32 NrSamples = NrChannels * NrFrames;
+
+ /* Check for NULL pointers */
+ if((hInstance == LVM_NULL) || (pInData == LVM_NULL) || (pOutData == LVM_NULL))
+ {
+ return LVEQNB_NULLADDRESS;
+ }
+
+ /* Check if the input and output data buffers are 32-bit aligned */
+ if ((((uintptr_t)pInData % 4) != 0) || (((uintptr_t)pOutData % 4) != 0))
+ {
+ return LVEQNB_ALIGNMENTERROR;
+ }
+
+ LVM_FLOAT * const pScratch = (LVM_FLOAT *)pInstance->pFastTemporary;
+
+ /*
+ * Check the number of frames is not too large
+ */
+ if (NrFrames > pInstance->Capabilities.MaxBlockSize)
+ {
+ return LVEQNB_TOOMANYSAMPLES;
+ }
+
+ if (pInstance->Params.OperatingMode == LVEQNB_ON)
+ {
+ /*
+ * Copy input data in to scratch buffer
+ */
+ Copy_Float(pInData, /* Source */
+ pScratch, /* Destination */
+ (LVM_INT16)NrSamples);
+
+ /*
+ * For each section execte the filter unless the gain is 0dB
+ */
+ if (pInstance->NBands != 0)
+ {
+ for (LVM_UINT16 i = 0; i < pInstance->NBands; i++)
+ {
+ /*
+ * Check if band is non-zero dB gain
+ */
+ if (pInstance->pBandDefinitions[i].Gain != 0)
+ {
+ /*
+ * Get the address of the biquad instance
+ */
+ Biquad_FLOAT_Instance_t *pBiquad = &pInstance->pEQNB_FilterState_Float[i];
+
+ /*
+ * Select single or double precision as required
+ */
+ switch (pInstance->pBiquadType[i])
+ {
+ case LVEQNB_SinglePrecision_Float:
+ {
+#ifdef SUPPORT_MC
+ PK_Mc_D32F32C14G11_TRC_WRA_01(pBiquad,
+ pScratch,
+ pScratch,
+ (LVM_INT16)NrFrames,
+ (LVM_INT16)NrChannels);
+#else
+ PK_2I_D32F32C14G11_TRC_WRA_01(pBiquad,
+ pScratch,
+ pScratch,
+ (LVM_INT16)NrFrames);
+#endif
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ if(pInstance->bInOperatingModeTransition == LVM_TRUE){
+#ifdef SUPPORT_MC
+ LVC_MixSoft_2Mc_D16C31_SAT(&pInstance->BypassMixer,
+ pScratch,
+ pInData,
+ pScratch,
+ (LVM_INT16)NrFrames,
+ (LVM_INT16)NrChannels);
+#else
+ LVC_MixSoft_2St_D16C31_SAT(&pInstance->BypassMixer,
+ pScratch,
+ pInData,
+ pScratch,
+ (LVM_INT16)NrSamples);
+#endif
+ // duplicate with else clause(s)
+ Copy_Float(pScratch, /* Source */
+ pOutData, /* Destination */
+ (LVM_INT16)NrSamples); /* All channel samples */
+ }
+ else{
+ Copy_Float(pScratch, /* Source */
+ pOutData, /* Destination */
+ (LVM_INT16)NrSamples); /* All channel samples */
+ }
+ }
+ else
+ {
+ /*
+ * Mode is OFF so copy the data if necessary
+ */
+ if (pInData != pOutData)
+ {
+ Copy_Float(pInData, /* Source */
+ pOutData, /* Destination */
+ (LVM_INT16)NrSamples); /* All channel samples */
+ }
+ }
+ return LVEQNB_SUCCESS;
+
+}
diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Tables.c b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Tables.c
deleted file mode 100644
index 453c42d..0000000
--- a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Tables.c
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-/************************************************************************************/
-/* */
-/* Includes */
-/* */
-/************************************************************************************/
-
-#include "LVEQNB.h"
-#include "LVEQNB_Coeffs.h"
-
-
-/************************************************************************************/
-/* */
-/* Sample rate table */
-/* */
-/************************************************************************************/
-
-/*
- * Sample rate table for converting between the enumerated type and the actual
- * frequency
- */
-#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
-const LVM_UINT32 LVEQNB_SampleRateTab[] = {8000, /* 8kS/s */
- 11025,
- 12000,
- 16000,
- 22050,
- 24000,
- 32000,
- 44100,
- 48000,
- 88200,
- 96000,
- 176400,
- 192000
-};
-#else
-const LVM_UINT16 LVEQNB_SampleRateTab[] = {8000, /* 8kS/s */
- 11025,
- 12000,
- 16000,
- 22050,
- 24000,
- 32000,
- 44100,
- 48000
-};
-#endif
-
-/************************************************************************************/
-/* */
-/* Coefficient calculation tables */
-/* */
-/************************************************************************************/
-
-/*
- * Table for 2 * Pi / Fs
- */
-#ifdef BUILD_FLOAT
-const LVM_FLOAT LVEQNB_TwoPiOnFsTable[] = {LVEQNB_2PiOn_8000, /* 8kS/s */
- LVEQNB_2PiOn_11025,
- LVEQNB_2PiOn_12000,
- LVEQNB_2PiOn_16000,
- LVEQNB_2PiOn_22050,
- LVEQNB_2PiOn_24000,
- LVEQNB_2PiOn_32000,
- LVEQNB_2PiOn_44100,
- LVEQNB_2PiOn_48000
-#ifdef HIGHER_FS
- ,LVEQNB_2PiOn_88200
- ,LVEQNB_2PiOn_96000
- ,LVEQNB_2PiOn_176400
- ,LVEQNB_2PiOn_192000
-#endif
- };
-#else
-const LVM_INT16 LVEQNB_TwoPiOnFsTable[] = {LVEQNB_2PiOn_8000, /* 8kS/s */
- LVEQNB_2PiOn_11025,
- LVEQNB_2PiOn_12000,
- LVEQNB_2PiOn_16000,
- LVEQNB_2PiOn_22050,
- LVEQNB_2PiOn_24000,
- LVEQNB_2PiOn_32000,
- LVEQNB_2PiOn_44100,
- LVEQNB_2PiOn_48000}; /* 48kS/s */
-#endif
-
-/*
- * Gain table
- */
-#ifdef BUILD_FLOAT
-const LVM_FLOAT LVEQNB_GainTable[] = {LVEQNB_Gain_Neg15_dB, /* -15dB gain */
- LVEQNB_Gain_Neg14_dB,
- LVEQNB_Gain_Neg13_dB,
- LVEQNB_Gain_Neg12_dB,
- LVEQNB_Gain_Neg11_dB,
- LVEQNB_Gain_Neg10_dB,
- LVEQNB_Gain_Neg9_dB,
- LVEQNB_Gain_Neg8_dB,
- LVEQNB_Gain_Neg7_dB,
- LVEQNB_Gain_Neg6_dB,
- LVEQNB_Gain_Neg5_dB,
- LVEQNB_Gain_Neg4_dB,
- LVEQNB_Gain_Neg3_dB,
- LVEQNB_Gain_Neg2_dB,
- LVEQNB_Gain_Neg1_dB,
- LVEQNB_Gain_0_dB, /* 0dB gain */
- LVEQNB_Gain_1_dB,
- LVEQNB_Gain_2_dB,
- LVEQNB_Gain_3_dB,
- LVEQNB_Gain_4_dB,
- LVEQNB_Gain_5_dB,
- LVEQNB_Gain_6_dB,
- LVEQNB_Gain_7_dB,
- LVEQNB_Gain_8_dB,
- LVEQNB_Gain_9_dB,
- LVEQNB_Gain_10_dB,
- LVEQNB_Gain_11_dB,
- LVEQNB_Gain_12_dB,
- LVEQNB_Gain_13_dB,
- LVEQNB_Gain_14_dB,
- LVEQNB_Gain_15_dB}; /* +15dB gain */
-#else
-const LVM_INT16 LVEQNB_GainTable[] = {LVEQNB_Gain_Neg15_dB, /* -15dB gain */
- LVEQNB_Gain_Neg14_dB,
- LVEQNB_Gain_Neg13_dB,
- LVEQNB_Gain_Neg12_dB,
- LVEQNB_Gain_Neg11_dB,
- LVEQNB_Gain_Neg10_dB,
- LVEQNB_Gain_Neg9_dB,
- LVEQNB_Gain_Neg8_dB,
- LVEQNB_Gain_Neg7_dB,
- LVEQNB_Gain_Neg6_dB,
- LVEQNB_Gain_Neg5_dB,
- LVEQNB_Gain_Neg4_dB,
- LVEQNB_Gain_Neg3_dB,
- LVEQNB_Gain_Neg2_dB,
- LVEQNB_Gain_Neg1_dB,
- LVEQNB_Gain_0_dB, /* 0dB gain */
- LVEQNB_Gain_1_dB,
- LVEQNB_Gain_2_dB,
- LVEQNB_Gain_3_dB,
- LVEQNB_Gain_4_dB,
- LVEQNB_Gain_5_dB,
- LVEQNB_Gain_6_dB,
- LVEQNB_Gain_7_dB,
- LVEQNB_Gain_8_dB,
- LVEQNB_Gain_9_dB,
- LVEQNB_Gain_10_dB,
- LVEQNB_Gain_11_dB,
- LVEQNB_Gain_12_dB,
- LVEQNB_Gain_13_dB,
- LVEQNB_Gain_14_dB,
- LVEQNB_Gain_15_dB}; /* +15dB gain */
-
-#endif
-/*
- * D table for 100 / (Gain + 1)
- */
-#ifdef BUILD_FLOAT
-const LVM_FLOAT LVEQNB_DTable[] = {LVEQNB_100D_Neg15_dB, /* -15dB gain */
- LVEQNB_100D_Neg14_dB,
- LVEQNB_100D_Neg13_dB,
- LVEQNB_100D_Neg12_dB,
- LVEQNB_100D_Neg11_dB,
- LVEQNB_100D_Neg10_dB,
- LVEQNB_100D_Neg9_dB,
- LVEQNB_100D_Neg8_dB,
- LVEQNB_100D_Neg7_dB,
- LVEQNB_100D_Neg6_dB,
- LVEQNB_100D_Neg5_dB,
- LVEQNB_100D_Neg4_dB,
- LVEQNB_100D_Neg3_dB,
- LVEQNB_100D_Neg2_dB,
- LVEQNB_100D_Neg1_dB,
- LVEQNB_100D_0_dB}; /* 0dB gain */
-#else
-const LVM_INT16 LVEQNB_DTable[] = {LVEQNB_100D_Neg15_dB, /* -15dB gain */
- LVEQNB_100D_Neg14_dB,
- LVEQNB_100D_Neg13_dB,
- LVEQNB_100D_Neg12_dB,
- LVEQNB_100D_Neg11_dB,
- LVEQNB_100D_Neg10_dB,
- LVEQNB_100D_Neg9_dB,
- LVEQNB_100D_Neg8_dB,
- LVEQNB_100D_Neg7_dB,
- LVEQNB_100D_Neg6_dB,
- LVEQNB_100D_Neg5_dB,
- LVEQNB_100D_Neg4_dB,
- LVEQNB_100D_Neg3_dB,
- LVEQNB_100D_Neg2_dB,
- LVEQNB_100D_Neg1_dB,
- LVEQNB_100D_0_dB}; /* 0dB gain */
-
-#endif
-/************************************************************************************/
-/* */
-/* Filter polynomial coefficients */
-/* */
-/************************************************************************************/
-
-/*
- * Coefficients for calculating the cosine with the equation:
- *
- * Cos(x) = (2^Shifts)*(a0 + a1*x + a2*x^2 + a3*x^3 + a4*x^4 + a5*x^5)
- *
- * These coefficients expect the input, x, to be in the range 0 to 32768 respresenting
- * a range of 0 to Pi. The output is in the range 32767 to -32768 representing the range
- * +1.0 to -1.0
- */
-const LVM_INT16 LVEQNB_CosCoef[] = {3, /* Shifts */
- 4096, /* a0 */
- -36, /* a1 */
- -19725, /* a2 */
- -2671, /* a3 */
- 23730, /* a4 */
- -9490}; /* a5 */
-
-/*
- * Coefficients for calculating the cosine error with the equation:
- *
- * CosErr(x) = (2^Shifts)*(a0 + a1*x + a2*x^2 + a3*x^3)
- *
- * These coefficients expect the input, x, to be in the range 0 to 32768 respresenting
- * a range of 0 to Pi/25. The output is in the range 0 to 32767 representing the range
- * 0.0 to 0.0078852986
- *
- * This is used to give a double precision cosine over the range 0 to Pi/25 using the
- * the equation:
- *
- * Cos(x) = 1.0 - CosErr(x)
- */
-const LVM_INT16 LVEQNB_DPCosCoef[] = {1, /* Shifts */
- 0, /* a0 */
- -6, /* a1 */
- 16586, /* a2 */
- -44}; /* a3 */
-
-
diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Tables.cpp b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Tables.cpp
new file mode 100644
index 0000000..0628114
--- /dev/null
+++ b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Tables.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/************************************************************************************/
+/* */
+/* Includes */
+/* */
+/************************************************************************************/
+
+#include "LVEQNB.h"
+#include "LVEQNB_Coeffs.h"
+#include "LVEQNB_Tables.h"
+
+/************************************************************************************/
+/* */
+/* Sample rate table */
+/* */
+/************************************************************************************/
+
+/*
+ * Sample rate table for converting between the enumerated type and the actual
+ * frequency
+ */
+const LVM_UINT32 LVEQNB_SampleRateTab[] = {8000, /* 8kS/s */
+ 11025,
+ 12000,
+ 16000,
+ 22050,
+ 24000,
+ 32000,
+ 44100,
+ 48000,
+ 88200,
+ 96000,
+ 176400,
+ 192000
+};
+
+/************************************************************************************/
+/* */
+/* Coefficient calculation tables */
+/* */
+/************************************************************************************/
+
+/*
+ * Table for 2 * Pi / Fs
+ */
+const LVM_FLOAT LVEQNB_TwoPiOnFsTable[] = {LVEQNB_2PiOn_8000, /* 8kS/s */
+ LVEQNB_2PiOn_11025,
+ LVEQNB_2PiOn_12000,
+ LVEQNB_2PiOn_16000,
+ LVEQNB_2PiOn_22050,
+ LVEQNB_2PiOn_24000,
+ LVEQNB_2PiOn_32000,
+ LVEQNB_2PiOn_44100,
+ LVEQNB_2PiOn_48000
+ ,LVEQNB_2PiOn_88200
+ ,LVEQNB_2PiOn_96000
+ ,LVEQNB_2PiOn_176400
+ ,LVEQNB_2PiOn_192000
+ };
+
+/*
+ * Gain table
+ */
+const LVM_FLOAT LVEQNB_GainTable[] = {LVEQNB_Gain_Neg15_dB, /* -15dB gain */
+ LVEQNB_Gain_Neg14_dB,
+ LVEQNB_Gain_Neg13_dB,
+ LVEQNB_Gain_Neg12_dB,
+ LVEQNB_Gain_Neg11_dB,
+ LVEQNB_Gain_Neg10_dB,
+ LVEQNB_Gain_Neg9_dB,
+ LVEQNB_Gain_Neg8_dB,
+ LVEQNB_Gain_Neg7_dB,
+ LVEQNB_Gain_Neg6_dB,
+ LVEQNB_Gain_Neg5_dB,
+ LVEQNB_Gain_Neg4_dB,
+ LVEQNB_Gain_Neg3_dB,
+ LVEQNB_Gain_Neg2_dB,
+ LVEQNB_Gain_Neg1_dB,
+ LVEQNB_Gain_0_dB, /* 0dB gain */
+ LVEQNB_Gain_1_dB,
+ LVEQNB_Gain_2_dB,
+ LVEQNB_Gain_3_dB,
+ LVEQNB_Gain_4_dB,
+ LVEQNB_Gain_5_dB,
+ LVEQNB_Gain_6_dB,
+ LVEQNB_Gain_7_dB,
+ LVEQNB_Gain_8_dB,
+ LVEQNB_Gain_9_dB,
+ LVEQNB_Gain_10_dB,
+ LVEQNB_Gain_11_dB,
+ LVEQNB_Gain_12_dB,
+ LVEQNB_Gain_13_dB,
+ LVEQNB_Gain_14_dB,
+ LVEQNB_Gain_15_dB}; /* +15dB gain */
+/*
+ * D table for 100 / (Gain + 1)
+ */
+const LVM_FLOAT LVEQNB_DTable[] = {LVEQNB_100D_Neg15_dB, /* -15dB gain */
+ LVEQNB_100D_Neg14_dB,
+ LVEQNB_100D_Neg13_dB,
+ LVEQNB_100D_Neg12_dB,
+ LVEQNB_100D_Neg11_dB,
+ LVEQNB_100D_Neg10_dB,
+ LVEQNB_100D_Neg9_dB,
+ LVEQNB_100D_Neg8_dB,
+ LVEQNB_100D_Neg7_dB,
+ LVEQNB_100D_Neg6_dB,
+ LVEQNB_100D_Neg5_dB,
+ LVEQNB_100D_Neg4_dB,
+ LVEQNB_100D_Neg3_dB,
+ LVEQNB_100D_Neg2_dB,
+ LVEQNB_100D_Neg1_dB,
+ LVEQNB_100D_0_dB}; /* 0dB gain */
+/************************************************************************************/
+/* */
+/* Filter polynomial coefficients */
+/* */
+/************************************************************************************/
+
+/*
+ * Coefficients for calculating the cosine with the equation:
+ *
+ * Cos(x) = (2^Shifts)*(a0 + a1*x + a2*x^2 + a3*x^3 + a4*x^4 + a5*x^5)
+ *
+ * These coefficients expect the input, x, to be in the range 0 to 32768 respresenting
+ * a range of 0 to Pi. The output is in the range 32767 to -32768 representing the range
+ * +1.0 to -1.0
+ */
+const LVM_INT16 LVEQNB_CosCoef[] = {3, /* Shifts */
+ 4096, /* a0 */
+ -36, /* a1 */
+ -19725, /* a2 */
+ -2671, /* a3 */
+ 23730, /* a4 */
+ -9490}; /* a5 */
+
+/*
+ * Coefficients for calculating the cosine error with the equation:
+ *
+ * CosErr(x) = (2^Shifts)*(a0 + a1*x + a2*x^2 + a3*x^3)
+ *
+ * These coefficients expect the input, x, to be in the range 0 to 32768 respresenting
+ * a range of 0 to Pi/25. The output is in the range 0 to 32767 representing the range
+ * 0.0 to 0.0078852986
+ *
+ * This is used to give a double precision cosine over the range 0 to Pi/25 using the
+ * the equation:
+ *
+ * Cos(x) = 1.0 - CosErr(x)
+ */
+const LVM_INT16 LVEQNB_DPCosCoef[] = {1, /* Shifts */
+ 0, /* a0 */
+ -6, /* a1 */
+ 16586, /* a2 */
+ -44}; /* a3 */
+
diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Tables.h b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Tables.h
new file mode 100644
index 0000000..a71eeb9
--- /dev/null
+++ b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Tables.h
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+#ifndef __LVEQNB_TABLES_H__
+#define __LVEQNB_TABLES_H__
+
+/************************************************************************************/
+/* */
+/* Sample rate table */
+/* */
+/************************************************************************************/
+
+/*
+ * Sample rate table for converting between the enumerated type and the actual
+ * frequency
+ */
+extern const LVM_UINT32 LVEQNB_SampleRateTab[];
+
+/************************************************************************************/
+/* */
+/* Coefficient calculation tables */
+/* */
+/************************************************************************************/
+
+/*
+ * Table for 2 * Pi / Fs
+ */
+extern const LVM_FLOAT LVEQNB_TwoPiOnFsTable[];
+
+/*
+ * Gain table
+ */
+extern const LVM_FLOAT LVEQNB_GainTable[];
+
+/*
+ * D table for 100 / (Gain + 1)
+ */
+extern const LVM_FLOAT LVEQNB_DTable[];
+
+/************************************************************************************/
+/* */
+/* Filter polynomial coefficients */
+/* */
+/************************************************************************************/
+
+/*
+ * Coefficients for calculating the cosine with the equation:
+ *
+ * Cos(x) = (2^Shifts)*(a0 + a1*x + a2*x^2 + a3*x^3 + a4*x^4 + a5*x^5)
+ *
+ * These coefficients expect the input, x, to be in the range 0 to 32768 respresenting
+ * a range of 0 to Pi. The output is in the range 32767 to -32768 representing the range
+ * +1.0 to -1.0
+ */
+extern const LVM_INT16 LVEQNB_CosCoef[];
+
+/*
+ * Coefficients for calculating the cosine error with the equation:
+ *
+ * CosErr(x) = (2^Shifts)*(a0 + a1*x + a2*x^2 + a3*x^3)
+ *
+ * These coefficients expect the input, x, to be in the range 0 to 32768 respresenting
+ * a range of 0 to Pi/25. The output is in the range 0 to 32767 representing the range
+ * 0.0 to 0.0078852986
+ *
+ * This is used to give a double precision cosine over the range 0 to Pi/25 using the
+ * the equation:
+ *
+ * Cos(x) = 1.0 - CosErr(x)
+ */
+extern const LVM_INT16 LVEQNB_DPCosCoef[];
+
+#endif /* __LVEQNB_TABLES_H__ */
diff --git a/media/libeffects/lvm/lib/Reverb/lib/LVREV.h b/media/libeffects/lvm/lib/Reverb/lib/LVREV.h
index 9c2e297..8c91ea9 100644
--- a/media/libeffects/lvm/lib/Reverb/lib/LVREV.h
+++ b/media/libeffects/lvm/lib/Reverb/lib/LVREV.h
@@ -28,11 +28,6 @@
#ifndef __LVREV_H__
#define __LVREV_H__
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-
/****************************************************************************************/
/* */
/* Includes */
@@ -40,7 +35,6 @@
/****************************************************************************************/
#include "LVM_Types.h"
-
/****************************************************************************************/
/* */
/* Definitions */
@@ -53,7 +47,6 @@
/* Memory table*/
#define LVREV_NR_MEMORY_REGIONS 4 /* Number of memory regions */
-
/****************************************************************************************/
/* */
/* Types */
@@ -62,7 +55,6 @@
/* Instance handle */
typedef void *LVREV_Handle_t;
-
/* Status return values */
typedef enum
{
@@ -73,7 +65,6 @@
LVREV_RETURNSTATUS_DUMMY = LVM_MAXENUM
} LVREV_ReturnStatus_en;
-
/* Reverb delay lines */
typedef enum
{
@@ -83,7 +74,6 @@
LVREV_DELAYLINES_DUMMY = LVM_MAXENUM
} LVREV_NumDelayLines_en;
-
/****************************************************************************************/
/* */
/* Structures */
@@ -96,7 +86,6 @@
LVM_MemoryRegion_st Region[LVREV_NR_MEMORY_REGIONS]; /* One definition for each region */
} LVREV_MemoryTable_st;
-
/* Control Parameter structure */
typedef struct
{
@@ -107,13 +96,8 @@
/* Parameters for REV */
LVM_UINT16 Level; /* Level, 0 to 100 representing percentage of reverb */
-#ifndef HIGHER_FS
- LVM_UINT16 LPF; /* Low pass filter, in Hz */
- LVM_UINT16 HPF; /* High pass filter, in Hz */
-#else
LVM_UINT32 LPF; /* Low pass filter, in Hz */
LVM_UINT32 HPF; /* High pass filter, in Hz */
-#endif
LVM_UINT16 T60; /* Decay time constant, in ms */
LVM_UINT16 Density; /* Echo density, 0 to 100 for minimum to maximum density */
@@ -122,7 +106,6 @@
} LVREV_ControlParams_st;
-
/* Instance Parameter structure */
typedef struct
{
@@ -135,7 +118,6 @@
} LVREV_InstanceParams_st;
-
/****************************************************************************************/
/* */
/* Function Prototypes */
@@ -182,7 +164,6 @@
LVREV_MemoryTable_st *pMemoryTable,
LVREV_InstanceParams_st *pInstanceParams);
-
/****************************************************************************************/
/* */
/* FUNCTION: LVREV_GetInstanceHandle */
@@ -213,7 +194,6 @@
LVREV_MemoryTable_st *pMemoryTable,
LVREV_InstanceParams_st *pInstanceParams);
-
/****************************************************************************************/
/* */
/* FUNCTION: LVXX_GetControlParameters */
@@ -237,7 +217,6 @@
LVREV_ReturnStatus_en LVREV_GetControlParameters(LVREV_Handle_t hInstance,
LVREV_ControlParams_st *pControlParams);
-
/****************************************************************************************/
/* */
/* FUNCTION: LVREV_SetControlParameters */
@@ -260,7 +239,6 @@
LVREV_ReturnStatus_en LVREV_SetControlParameters(LVREV_Handle_t hInstance,
LVREV_ControlParams_st *pNewParams);
-
/****************************************************************************************/
/* */
/* FUNCTION: LVREV_ClearAudioBuffers */
@@ -281,7 +259,6 @@
/****************************************************************************************/
LVREV_ReturnStatus_en LVREV_ClearAudioBuffers(LVREV_Handle_t hInstance);
-
/****************************************************************************************/
/* */
/* FUNCTION: LVREV_Process */
@@ -303,21 +280,10 @@
/* 1. The input and output buffers must be 32-bit aligned */
/* */
/****************************************************************************************/
-#ifdef BUILD_FLOAT
LVREV_ReturnStatus_en LVREV_Process(LVREV_Handle_t hInstance,
const LVM_FLOAT *pInData,
LVM_FLOAT *pOutData,
const LVM_UINT16 NumSamples);
-#else
-LVREV_ReturnStatus_en LVREV_Process(LVREV_Handle_t hInstance,
- const LVM_INT32 *pInData,
- LVM_INT32 *pOutData,
- const LVM_UINT16 NumSamples);
-#endif
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
#endif /* __LVREV_H__ */
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_ApplyNewSettings.c b/media/libeffects/lvm/lib/Reverb/src/LVREV_ApplyNewSettings.c
deleted file mode 100644
index e710844..0000000
--- a/media/libeffects/lvm/lib/Reverb/src/LVREV_ApplyNewSettings.c
+++ /dev/null
@@ -1,1224 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/****************************************************************************************/
-/* */
-/* Includes */
-/* */
-/****************************************************************************************/
-#include "LVREV_Private.h"
-#include "Filter.h"
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVREV_ApplyNewSettings */
-/* */
-/* DESCRIPTION: */
-/* Applies the new control parameters */
-/* */
-/* PARAMETERS: */
-/* pPrivate Pointer to the instance private parameters */
-/* */
-/* RETURNS: */
-/* LVREV_Success Succeeded */
-/* LVREV_NULLADDRESS When pPrivate is NULL */
-/* */
-/* NOTES: */
-/* */
-/****************************************************************************************/
-
-#ifndef BUILD_FLOAT
-LVREV_ReturnStatus_en LVREV_ApplyNewSettings (LVREV_Instance_st *pPrivate)
-{
-
- LVM_Mode_en OperatingMode;
- LVM_INT32 NumberOfDelayLines;
-
-
- /* Check for NULL pointer */
- if(pPrivate == LVM_NULL)
- {
- return LVREV_NULLADDRESS;
- }
-
- OperatingMode = pPrivate->NewParams.OperatingMode;
-
- if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_4)
- {
- NumberOfDelayLines = 4;
- }
- else if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_2)
- {
- NumberOfDelayLines = 2;
- }
- else
- {
- NumberOfDelayLines = 1;
- }
-
- /*
- * Update the high pass filter coefficients
- */
- if((pPrivate->NewParams.HPF != pPrivate->CurrentParams.HPF) ||
- (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
- (pPrivate->bFirstControl == LVM_TRUE))
- {
- LVM_INT32 Omega;
- FO_C32_Coefs_t Coeffs;
-
- Omega = LVM_GetOmega(pPrivate->NewParams.HPF, pPrivate->NewParams.SampleRate);
- LVM_FO_HPF(Omega, &Coeffs);
- FO_1I_D32F32Cll_TRC_WRA_01_Init( &pPrivate->pFastCoef->HPCoefs, &pPrivate->pFastData->HPTaps, &Coeffs);
- LoadConst_32(0,
- (void *)&pPrivate->pFastData->HPTaps, /* Destination Cast to void: no dereferencing in function*/
- sizeof(Biquad_1I_Order1_Taps_t)/sizeof(LVM_INT32));
- }
-
-
- /*
- * Update the low pass filter coefficients
- */
- if((pPrivate->NewParams.LPF != pPrivate->CurrentParams.LPF) ||
- (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
- (pPrivate->bFirstControl == LVM_TRUE))
- {
- LVM_INT32 Omega;
- FO_C32_Coefs_t Coeffs;
-
-
- Coeffs.A0 = 0x7FFFFFFF;
- Coeffs.A1 = 0;
- Coeffs.B1 = 0;
- if(pPrivate->NewParams.LPF <= (LVM_FsTable[pPrivate->NewParams.SampleRate] >> 1))
- {
- Omega = LVM_GetOmega(pPrivate->NewParams.LPF, pPrivate->NewParams.SampleRate);
-
- /*
- * Do not apply filter if w =2*pi*fc/fs >= 2.9
- */
- if(Omega<=LVREV_2_9_INQ29)
- {
- LVM_FO_LPF(Omega, &Coeffs);
- }
- }
- FO_1I_D32F32Cll_TRC_WRA_01_Init( &pPrivate->pFastCoef->LPCoefs, &pPrivate->pFastData->LPTaps, &Coeffs);
- LoadConst_32(0,
- (void *)&pPrivate->pFastData->LPTaps, /* Destination Cast to void: no dereferencing in function*/
- sizeof(Biquad_1I_Order1_Taps_t)/sizeof(LVM_INT32));
- }
-
-
- /*
- * Calculate the room size parameter
- */
- if( pPrivate->NewParams.RoomSize != pPrivate->CurrentParams.RoomSize)
- {
- /* Room size range is 10ms to 200ms
- * 0% -- 10ms
- * 50% -- 65ms
- * 100% -- 120ms
- */
- pPrivate->RoomSizeInms = 10 + (((pPrivate->NewParams.RoomSize*11) + 5)/10);
- }
-
-
- /*
- * Update the T delay number of samples and the all pass delay number of samples
- */
- if( (pPrivate->NewParams.RoomSize != pPrivate->CurrentParams.RoomSize) ||
- (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
- (pPrivate->bFirstControl == LVM_TRUE))
- {
-
- LVM_UINT32 Temp;
- LVM_INT32 APDelaySize;
- LVM_INT32 Fs = LVM_GetFsFromTable(pPrivate->NewParams.SampleRate);
- LVM_UINT32 DelayLengthSamples = (LVM_UINT32)(Fs * pPrivate->RoomSizeInms);
- LVM_INT16 i;
- LVM_INT16 ScaleTable[] = {LVREV_T_3_Power_minus0_on_4, LVREV_T_3_Power_minus1_on_4, LVREV_T_3_Power_minus2_on_4, LVREV_T_3_Power_minus3_on_4};
- LVM_INT16 MaxT_Delay[] = {LVREV_MAX_T0_DELAY, LVREV_MAX_T1_DELAY, LVREV_MAX_T2_DELAY, LVREV_MAX_T3_DELAY};
- LVM_INT16 MaxAP_Delay[] = {LVREV_MAX_AP0_DELAY, LVREV_MAX_AP1_DELAY, LVREV_MAX_AP2_DELAY, LVREV_MAX_AP3_DELAY};
-
-
- /*
- * For each delay line
- */
- for (i=0; i<NumberOfDelayLines; i++)
- {
- if (i != 0)
- {
- LVM_INT32 Temp1; /* to avoid QAC warning on type conversion */
- LVM_INT32 Temp2; /* to avoid QAC warning on type conversion */
-
- Temp2=(LVM_INT32)DelayLengthSamples;
- MUL32x16INTO32(Temp2, ScaleTable[i], Temp1, 15)
- Temp=(LVM_UINT32)Temp1;
- }
- else
- {
- Temp = DelayLengthSamples;
- }
- APDelaySize = Temp / 1500;
-
-
- /*
- * Set the fixed delay
- */
- Temp = (MaxT_Delay[i] - MaxAP_Delay[i]) * Fs / 48000;
- pPrivate->Delay_AP[i] = pPrivate->T[i] - Temp;
-
-
- /*
- * Set the tap selection
- */
- if (pPrivate->AB_Selection)
- {
- /* Smooth from tap A to tap B */
- pPrivate->pOffsetB[i] = &pPrivate->pDelay_T[i][pPrivate->T[i] - Temp - APDelaySize];
- pPrivate->B_DelaySize[i] = APDelaySize;
- pPrivate->Mixer_APTaps[i].Target1 = 0;
- pPrivate->Mixer_APTaps[i].Target2 = 0x7fffffff;
- }
- else
- {
- /* Smooth from tap B to tap A */
- pPrivate->pOffsetA[i] = &pPrivate->pDelay_T[i][pPrivate->T[i] - Temp - APDelaySize];
- pPrivate->A_DelaySize[i] = APDelaySize;
- pPrivate->Mixer_APTaps[i].Target2 = 0;
- pPrivate->Mixer_APTaps[i].Target1 = 0x7fffffff;
- }
-
- /*
- * Set the maximum block size to the smallest delay size
- */
- pPrivate->MaxBlkLen = Temp;
- if (pPrivate->MaxBlkLen > pPrivate->A_DelaySize[i])
- {
- pPrivate->MaxBlkLen = pPrivate->A_DelaySize[i];
- }
- if (pPrivate->MaxBlkLen > pPrivate->B_DelaySize[i])
- {
- pPrivate->MaxBlkLen = pPrivate->B_DelaySize[i];
- }
- }
- if (pPrivate->AB_Selection)
- {
- pPrivate->AB_Selection = 0;
- }
- else
- {
- pPrivate->AB_Selection = 1;
- }
-
-
- /*
- * Limit the maximum block length
- */
- pPrivate->MaxBlkLen=pPrivate->MaxBlkLen-2; /* Just as a precausion, but no problem if we remove this line */
- if(pPrivate->MaxBlkLen > pPrivate->InstanceParams.MaxBlockSize)
- {
- pPrivate->MaxBlkLen = (LVM_INT32)pPrivate->InstanceParams.MaxBlockSize;
- }
- }
-
-
- /*
- * Update the low pass filter coefficient
- */
- if( (pPrivate->NewParams.Damping != pPrivate->CurrentParams.Damping) ||
- (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
- (pPrivate->bFirstControl == LVM_TRUE))
- {
-
- LVM_INT32 Temp;
- LVM_INT32 Omega;
- FO_C32_Coefs_t Coeffs;
- LVM_INT16 i;
- LVM_INT16 Damping = (LVM_INT16)((pPrivate->NewParams.Damping * 100) + 1000);
- LVM_INT32 ScaleTable[] = {LVREV_T_3_Power_0_on_4, LVREV_T_3_Power_1_on_4, LVREV_T_3_Power_2_on_4, LVREV_T_3_Power_3_on_4};
-
-
- /*
- * For each filter
- */
- for (i=0; i<NumberOfDelayLines; i++)
- {
- if (i != 0)
- {
- MUL32x16INTO32(ScaleTable[i], Damping, Temp, 15)
- }
- else
- {
- Temp = Damping;
- }
- if(Temp <= (LVM_FsTable[pPrivate->NewParams.SampleRate] >> 1))
- {
- Omega = LVM_GetOmega((LVM_UINT16)Temp, pPrivate->NewParams.SampleRate);
- LVM_FO_LPF(Omega, &Coeffs);
- }
- else
- {
- Coeffs.A0 = 0x7FF00000;
- Coeffs.A1 = 0;
- Coeffs.B1 = 0;
- }
- FO_1I_D32F32Cll_TRC_WRA_01_Init(&pPrivate->pFastCoef->RevLPCoefs[i], &pPrivate->pFastData->RevLPTaps[i], &Coeffs);
- }
- }
-
-
- /*
- * Update All-pass filter mixer time constants
- */
- if( (pPrivate->NewParams.RoomSize != pPrivate->CurrentParams.RoomSize) ||
- (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
- (pPrivate->NewParams.Density != pPrivate->CurrentParams.Density))
- {
- LVM_INT16 i;
- LVM_INT32 Alpha = (LVM_INT32)LVM_Mixer_TimeConstant(LVREV_ALLPASS_TC, LVM_GetFsFromTable(pPrivate->NewParams.SampleRate), 1);
- LVM_INT32 AlphaTap = (LVM_INT32)LVM_Mixer_TimeConstant(LVREV_ALLPASS_TAP_TC, LVM_GetFsFromTable(pPrivate->NewParams.SampleRate), 1);
-
- for (i=0; i<4; i++)
- {
- pPrivate->Mixer_APTaps[i].Alpha1 = AlphaTap;
- pPrivate->Mixer_APTaps[i].Alpha2 = AlphaTap;
- pPrivate->Mixer_SGFeedback[i].Alpha = Alpha;
- pPrivate->Mixer_SGFeedforward[i].Alpha = Alpha;
- }
- }
-
-
- /*
- * Update the feed back gain
- */
- if( (pPrivate->NewParams.RoomSize != pPrivate->CurrentParams.RoomSize) ||
- (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
- (pPrivate->NewParams.T60 != pPrivate->CurrentParams.T60) ||
- (pPrivate->bFirstControl == LVM_TRUE))
- {
-
- LVM_INT32 G[4]; /* Feedback gain (Q7.24) */
-
- if(pPrivate->NewParams.T60 == 0)
- {
- G[3] = 0;
- G[2] = 0;
- G[1] = 0;
- G[0] = 0;
- }
- else
- {
- LVM_INT32 Temp1;
- LVM_INT32 Temp2;
- LVM_INT16 i;
- LVM_INT16 ScaleTable[] = {LVREV_T_3_Power_minus0_on_4, LVREV_T_3_Power_minus1_on_4, LVREV_T_3_Power_minus2_on_4, LVREV_T_3_Power_minus3_on_4};
-
-
- /*
- * For each delay line
- */
- for (i=0; i<NumberOfDelayLines; i++)
- {
- Temp1 = (3 * pPrivate->RoomSizeInms * ScaleTable[i]) / pPrivate->NewParams.T60;
- if(Temp1 >= (4 << 15))
- {
- G[i] = 0;
- }
- else if((Temp1 >= (2 << 15)))
- {
- Temp2 = LVM_Power10(-(Temp1 << 14));
- Temp1 = LVM_Power10(-(Temp1 << 14));
- MUL32x32INTO32(Temp1,Temp2,Temp1,24)
- }
- else
- {
- Temp1 = LVM_Power10(-(Temp1 << 15));
- }
- if (NumberOfDelayLines == 1)
- {
- G[i] = Temp1;
- }
- else
- {
- LVM_INT32 TempG;
- MUL32x16INTO32(Temp1,ONE_OVER_SQRT_TWO,TempG,15)
- G[i]=TempG;
- }
- }
- }
-
- /* Set up the feedback mixers for four delay lines */
- pPrivate->FeedbackMixer[0].Target=G[0]<<7;
- pPrivate->FeedbackMixer[1].Target=G[1]<<7;
- pPrivate->FeedbackMixer[2].Target=G[2]<<7;
- pPrivate->FeedbackMixer[3].Target=G[3]<<7;
- }
-
-
- /*
- * Calculate the gain correction
- */
- if((pPrivate->NewParams.RoomSize != pPrivate->CurrentParams.RoomSize) ||
- (pPrivate->NewParams.Level != pPrivate->CurrentParams.Level) ||
- (pPrivate->NewParams.T60 != pPrivate->CurrentParams.T60) )
- {
- LVM_INT32 Index=0;
- LVM_INT32 i=0;
- LVM_INT32 Gain=0;
- LVM_INT32 RoomSize=0;
- LVM_INT32 T60;
- LVM_INT32 Coefs[5];
-
- if(pPrivate->NewParams.RoomSize==0)
- {
- RoomSize=1;
- }
- else
- {
- RoomSize=(LVM_INT32)pPrivate->NewParams.RoomSize;
- }
-
- if(pPrivate->NewParams.T60<100)
- {
- T60 = 100 * LVREV_T60_SCALE;
- }
- else
- {
- T60 = pPrivate->NewParams.T60 * LVREV_T60_SCALE;
- }
-
- /* Find the nearest room size in table */
- for(i=0;i<24;i++)
- {
- if(RoomSize<= LVREV_GainPolyTable[i][0])
- {
- Index=i;
- break;
- }
- }
-
-
- if(RoomSize==LVREV_GainPolyTable[Index][0])
- {
- /* Take table values if the room size is in table */
- for(i=1;i<5;i++)
- {
- Coefs[i-1]=LVREV_GainPolyTable[Index][i];
- }
- Coefs[4]=0;
- Gain=LVM_Polynomial(3,Coefs,T60); /* Q.24 result */
- }
- else
- {
- /* Interpolate the gain between nearest room sizes */
-
- LVM_INT32 Gain1,Gain2;
- LVM_INT32 Tot_Dist,Dist;
-
- Tot_Dist=LVREV_GainPolyTable[Index][0]-LVREV_GainPolyTable[Index-1][0];
- Dist=RoomSize-LVREV_GainPolyTable[Index-1][0];
-
-
- /* Get gain for first */
- for(i=1;i<5;i++)
- {
- Coefs[i-1]=LVREV_GainPolyTable[Index-1][i];
- }
- Coefs[4]=0;
-
- Gain1=LVM_Polynomial(3,Coefs,T60); /* Q.24 result */
-
- /* Get gain for second */
- for(i=1;i<5;i++)
- {
- Coefs[i-1]=LVREV_GainPolyTable[Index][i];
- }
- Coefs[4]=0;
-
- Gain2=LVM_Polynomial(3,Coefs,T60); /* Q.24 result */
-
- /* Linear Interpolate the gain */
- Gain = Gain1+ (((Gain2-Gain1)*Dist)/(Tot_Dist));
- }
-
-
- /*
- * Get the inverse of gain: Q.15
- * Gain is mostly above one except few cases, take only gains above 1
- */
- if(Gain < 16777216L)
- {
- pPrivate->Gain= 32767;
- }
- else
- {
- pPrivate->Gain=(LVM_INT16)(LVM_MAXINT_32/(Gain>>8));
- }
-
-
- Index=((32767*100)/(100+pPrivate->NewParams.Level));
- pPrivate->Gain=(LVM_INT16)((pPrivate->Gain*Index)>>15);
- pPrivate->GainMixer.Target = pPrivate->Gain*Index;
- }
-
-
- /*
- * Update the all pass comb filter coefficient
- */
- if( (pPrivate->NewParams.Density != pPrivate->CurrentParams.Density) ||
- (pPrivate->bFirstControl == LVM_TRUE))
- {
- LVM_INT16 i;
- LVM_INT32 b = pPrivate->NewParams.Density * LVREV_B_8_on_1000;
-
- for (i=0;i<4; i++)
- {
- pPrivate->Mixer_SGFeedback[i].Target = b;
- pPrivate->Mixer_SGFeedforward[i].Target = b;
- }
- }
-
-
- /*
- * Update the bypass mixer time constant
- */
- if((pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
- (pPrivate->bFirstControl == LVM_TRUE))
- {
- LVM_UINT16 NumChannels = 1; /* Assume MONO format */
- LVM_INT32 Alpha;
-
- Alpha = (LVM_INT32)LVM_Mixer_TimeConstant(LVREV_FEEDBACKMIXER_TC, LVM_GetFsFromTable(pPrivate->NewParams.SampleRate), NumChannels);
- pPrivate->FeedbackMixer[0].Alpha=Alpha;
- pPrivate->FeedbackMixer[1].Alpha=Alpha;
- pPrivate->FeedbackMixer[2].Alpha=Alpha;
- pPrivate->FeedbackMixer[3].Alpha=Alpha;
-
- NumChannels = 2; /* Always stereo output */
- pPrivate->BypassMixer.Alpha1 = (LVM_INT32)LVM_Mixer_TimeConstant(LVREV_BYPASSMIXER_TC, LVM_GetFsFromTable(pPrivate->NewParams.SampleRate), NumChannels);
- pPrivate->BypassMixer.Alpha2 = pPrivate->BypassMixer.Alpha1;
- pPrivate->GainMixer.Alpha = pPrivate->BypassMixer.Alpha1;
- }
-
-
- /*
- * Update the bypass mixer targets
- */
- if( (pPrivate->NewParams.Level != pPrivate->CurrentParams.Level) &&
- (pPrivate->NewParams.OperatingMode == LVM_MODE_ON))
- {
- pPrivate->BypassMixer.Target2 = ((LVM_INT32)(pPrivate->NewParams.Level * 32767)/100)<<16;
- pPrivate->BypassMixer.Target1 = 0x00000000;
- if ((pPrivate->NewParams.Level == 0) && (pPrivate->bFirstControl == LVM_FALSE))
- {
- pPrivate->BypassMixer.CallbackSet2 = LVM_TRUE;
- }
- if (pPrivate->NewParams.Level != 0)
- {
- pPrivate->bDisableReverb = LVM_FALSE;
- }
- }
-
- if(pPrivate->NewParams.OperatingMode != pPrivate->CurrentParams.OperatingMode)
- {
- if(pPrivate->NewParams.OperatingMode == LVM_MODE_ON)
- {
- pPrivate->BypassMixer.Target2 = ((LVM_INT32)(pPrivate->NewParams.Level * 32767)/100)<<16;
- pPrivate->BypassMixer.Target1 = 0x00000000;
-
- pPrivate->BypassMixer.CallbackSet2 = LVM_FALSE;
- OperatingMode = LVM_MODE_ON;
- if (pPrivate->NewParams.Level == 0)
- {
- pPrivate->bDisableReverb = LVM_TRUE;
- }
- else
- {
- pPrivate->bDisableReverb = LVM_FALSE;
- }
- }
- else if (pPrivate->bFirstControl == LVM_FALSE)
- {
- pPrivate->BypassMixer.Target2 = 0x00000000;
- pPrivate->BypassMixer.Target1 = 0x00000000;
- pPrivate->BypassMixer.CallbackSet2 = LVM_TRUE;
- pPrivate->GainMixer.Target = 0x03FFFFFF;
- OperatingMode = LVM_MODE_ON;
- }
- else
- {
- OperatingMode = LVM_MODE_OFF;
- }
- }
-
-
- /*
- * If it is the first call to ApplyNew settings force the current to the target to begin immediate playback of the effect
- */
- if(pPrivate->bFirstControl == LVM_TRUE)
- {
- pPrivate->BypassMixer.Current1 = pPrivate->BypassMixer.Target1;
- pPrivate->BypassMixer.Current2 = pPrivate->BypassMixer.Target2;
- }
-
-
- /*
- * Copy the new parameters
- */
- pPrivate->CurrentParams = pPrivate->NewParams;
- pPrivate->CurrentParams.OperatingMode = OperatingMode;
-
-
- /*
- * Update flag
- */
- if(pPrivate->bFirstControl == LVM_TRUE)
- {
- pPrivate->bFirstControl = LVM_FALSE;
- }
-
-
- return LVREV_SUCCESS;
-}
-#else /* BUILD_FLOAT*/
-LVREV_ReturnStatus_en LVREV_ApplyNewSettings (LVREV_Instance_st *pPrivate)
-{
-
- LVM_Mode_en OperatingMode;
- LVM_INT32 NumberOfDelayLines;
-
-
- /* Check for NULL pointer */
- if(pPrivate == LVM_NULL)
- {
- return LVREV_NULLADDRESS;
- }
-
- OperatingMode = pPrivate->NewParams.OperatingMode;
-
- if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_4)
- {
- NumberOfDelayLines = 4;
- }
- else if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_2)
- {
- NumberOfDelayLines = 2;
- }
- else
- {
- NumberOfDelayLines = 1;
- }
-
- /*
- * Update the high pass filter coefficients
- */
- if((pPrivate->NewParams.HPF != pPrivate->CurrentParams.HPF) ||
- (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
- (pPrivate->bFirstControl == LVM_TRUE))
- {
- LVM_FLOAT Omega;
- FO_FLOAT_Coefs_t Coeffs;
-
- Omega = LVM_GetOmega(pPrivate->NewParams.HPF, pPrivate->NewParams.SampleRate);
- LVM_FO_HPF(Omega, &Coeffs);
- FO_1I_D32F32Cll_TRC_WRA_01_Init( &pPrivate->pFastCoef->HPCoefs,
- &pPrivate->pFastData->HPTaps, &Coeffs);
- LoadConst_Float(0,
- (void *)&pPrivate->pFastData->HPTaps, /* Destination Cast to void: \
- no dereferencing in function*/
- sizeof(Biquad_1I_Order1_FLOAT_Taps_t) / sizeof(LVM_FLOAT));
- }
-
-
- /*
- * Update the low pass filter coefficients
- */
- if((pPrivate->NewParams.LPF != pPrivate->CurrentParams.LPF) ||
- (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
- (pPrivate->bFirstControl == LVM_TRUE))
- {
- LVM_FLOAT Omega;
- FO_FLOAT_Coefs_t Coeffs;
-
- Coeffs.A0 = 1;
- Coeffs.A1 = 0;
- Coeffs.B1 = 0;
- if(pPrivate->NewParams.LPF <= (LVM_FsTable[pPrivate->NewParams.SampleRate] >> 1))
- {
- Omega = LVM_GetOmega(pPrivate->NewParams.LPF, pPrivate->NewParams.SampleRate);
-
- /*
- * Do not apply filter if w =2*pi*fc/fs >= 2.9
- */
- if(Omega <= (LVM_FLOAT)LVREV_2_9_INQ29)
- {
- LVM_FO_LPF(Omega, &Coeffs);
- }
- }
- FO_1I_D32F32Cll_TRC_WRA_01_Init( &pPrivate->pFastCoef->LPCoefs,
- &pPrivate->pFastData->LPTaps, &Coeffs);
- LoadConst_Float(0,
- (void *)&pPrivate->pFastData->LPTaps, /* Destination Cast to void: \
- no dereferencing in function*/
- sizeof(Biquad_1I_Order1_FLOAT_Taps_t) / sizeof(LVM_FLOAT));
- }
-
-
- /*
- * Calculate the room size parameter
- */
- if( pPrivate->NewParams.RoomSize != pPrivate->CurrentParams.RoomSize)
- {
- /* Room size range is 10ms to 200ms
- * 0% -- 10ms
- * 50% -- 65ms
- * 100% -- 120ms
- */
- pPrivate->RoomSizeInms = 10 + (((pPrivate->NewParams.RoomSize*11) + 5) / 10);
- }
-
-
- /*
- * Update the T delay number of samples and the all pass delay number of samples
- */
- if( (pPrivate->NewParams.RoomSize != pPrivate->CurrentParams.RoomSize) ||
- (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
- (pPrivate->bFirstControl == LVM_TRUE))
- {
-
- LVM_UINT32 Temp;
- LVM_INT32 APDelaySize;
- LVM_INT32 Fs = LVM_GetFsFromTable(pPrivate->NewParams.SampleRate);
- LVM_UINT32 DelayLengthSamples = (LVM_UINT32)(Fs * pPrivate->RoomSizeInms);
- LVM_INT16 i;
- LVM_FLOAT ScaleTable[] = {LVREV_T_3_Power_minus0_on_4, LVREV_T_3_Power_minus1_on_4, \
- LVREV_T_3_Power_minus2_on_4, LVREV_T_3_Power_minus3_on_4};
- LVM_INT16 MaxT_Delay[] = {LVREV_MAX_T0_DELAY, LVREV_MAX_T1_DELAY, \
- LVREV_MAX_T2_DELAY, LVREV_MAX_T3_DELAY};
- LVM_INT16 MaxAP_Delay[] = {LVREV_MAX_AP0_DELAY, LVREV_MAX_AP1_DELAY, \
- LVREV_MAX_AP2_DELAY, LVREV_MAX_AP3_DELAY};
-
-
- /*
- * For each delay line
- */
- for (i = 0; i < NumberOfDelayLines; i++)
- {
- if (i != 0)
- {
- LVM_FLOAT Temp1; /* to avoid QAC warning on type conversion */
-
- Temp1=(LVM_FLOAT)DelayLengthSamples;
- Temp = (LVM_UINT32)(Temp1 * ScaleTable[i]);
- }
- else
- {
- Temp = DelayLengthSamples;
- }
- APDelaySize = Temp / 1500;
-
-
- /*
- * Set the fixed delay
- */
-
-#ifdef HIGHER_FS
- Temp = (MaxT_Delay[i] - MaxAP_Delay[i]) * Fs / 192000;
-#else
- Temp = (MaxT_Delay[i] - MaxAP_Delay[i]) * Fs / 48000;
-#endif
- pPrivate->Delay_AP[i] = pPrivate->T[i] - Temp;
-
-
- /*
- * Set the tap selection
- */
- if (pPrivate->AB_Selection)
- {
- /* Smooth from tap A to tap B */
- pPrivate->pOffsetB[i] = &pPrivate->pDelay_T[i][pPrivate->T[i] - \
- Temp - APDelaySize];
- pPrivate->B_DelaySize[i] = APDelaySize;
- pPrivate->Mixer_APTaps[i].Target1 = 0;
- pPrivate->Mixer_APTaps[i].Target2 = 1.0f;
- }
- else
- {
- /* Smooth from tap B to tap A */
- pPrivate->pOffsetA[i] = &pPrivate->pDelay_T[i][pPrivate->T[i] - \
- Temp - APDelaySize];
- pPrivate->A_DelaySize[i] = APDelaySize;
- pPrivate->Mixer_APTaps[i].Target2 = 0;
- pPrivate->Mixer_APTaps[i].Target1 = 1.0f;
- }
-
- /*
- * Set the maximum block size to the smallest delay size
- */
- pPrivate->MaxBlkLen = Temp;
- if (pPrivate->MaxBlkLen > pPrivate->A_DelaySize[i])
- {
- pPrivate->MaxBlkLen = pPrivate->A_DelaySize[i];
- }
- if (pPrivate->MaxBlkLen > pPrivate->B_DelaySize[i])
- {
- pPrivate->MaxBlkLen = pPrivate->B_DelaySize[i];
- }
- }
- if (pPrivate->AB_Selection)
- {
- pPrivate->AB_Selection = 0;
- }
- else
- {
- pPrivate->AB_Selection = 1;
- }
-
-
- /*
- * Limit the maximum block length
- */
- /* Just as a precausion, but no problem if we remove this line */
- pPrivate->MaxBlkLen = pPrivate->MaxBlkLen - 2;
- if(pPrivate->MaxBlkLen > pPrivate->InstanceParams.MaxBlockSize)
- {
- pPrivate->MaxBlkLen = (LVM_INT32)pPrivate->InstanceParams.MaxBlockSize;
- }
- }
-
-
-
- /*
- * Update the low pass filter coefficient
- */
- if( (pPrivate->NewParams.Damping != pPrivate->CurrentParams.Damping) ||
- (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
- (pPrivate->bFirstControl == LVM_TRUE))
- {
-
- LVM_INT32 Temp;
- LVM_FLOAT Omega;
- FO_FLOAT_Coefs_t Coeffs;
- LVM_INT16 i;
- LVM_INT16 Damping = (LVM_INT16)((pPrivate->NewParams.Damping * 100) + 1000);
- LVM_FLOAT ScaleTable[] = {LVREV_T_3_Power_0_on_4, LVREV_T_3_Power_1_on_4,
- LVREV_T_3_Power_2_on_4, LVREV_T_3_Power_3_on_4};
-
-
- /*
- * For each filter
- */
- for (i = 0; i < NumberOfDelayLines; i++)
- {
- if (i != 0)
- {
- Temp = (LVM_INT32)(ScaleTable[i] * Damping);
- }
- else
- {
- Temp = Damping;
- }
- if(Temp <= (LVM_INT32)(LVM_FsTable[pPrivate->NewParams.SampleRate] >> 1))
- {
- Omega = LVM_GetOmega(Temp, pPrivate->NewParams.SampleRate);
- LVM_FO_LPF(Omega, &Coeffs);
- }
- else
- {
- Coeffs.A0 = 1;
- Coeffs.A1 = 0;
- Coeffs.B1 = 0;
- }
- FO_1I_D32F32Cll_TRC_WRA_01_Init(&pPrivate->pFastCoef->RevLPCoefs[i],
- &pPrivate->pFastData->RevLPTaps[i], &Coeffs);
- }
- }
-
-
- /*
- * Update All-pass filter mixer time constants
- */
- if( (pPrivate->NewParams.RoomSize != pPrivate->CurrentParams.RoomSize) ||
- (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
- (pPrivate->NewParams.Density != pPrivate->CurrentParams.Density))
- {
- LVM_INT16 i;
- LVM_FLOAT Alpha;
- LVM_FLOAT AlphaTap;
-
- Alpha = LVM_Mixer_TimeConstant(LVREV_ALLPASS_TC,
- LVM_GetFsFromTable(pPrivate->NewParams.SampleRate),
- 1);
-
- AlphaTap = LVM_Mixer_TimeConstant(LVREV_ALLPASS_TAP_TC,
- LVM_GetFsFromTable(pPrivate->NewParams.SampleRate),
- 1);
-
- for (i = 0; i < 4; i++)
- {
- pPrivate->Mixer_APTaps[i].Alpha1 = AlphaTap;
- pPrivate->Mixer_APTaps[i].Alpha2 = AlphaTap;
- pPrivate->Mixer_SGFeedback[i].Alpha = Alpha;
- pPrivate->Mixer_SGFeedforward[i].Alpha = Alpha;
- }
- }
-
-
- /*
- * Update the feed back gain
- */
- if( (pPrivate->NewParams.RoomSize != pPrivate->CurrentParams.RoomSize) ||
- (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
- (pPrivate->NewParams.T60 != pPrivate->CurrentParams.T60) ||
- (pPrivate->bFirstControl == LVM_TRUE))
- {
-
- LVM_FLOAT G[4]; /* Feedback gain (Q7.24) */
-
- if(pPrivate->NewParams.T60 == 0)
- {
- G[3] = 0;
- G[2] = 0;
- G[1] = 0;
- G[0] = 0;
- }
- else
- {
- LVM_FLOAT Temp1;
- LVM_FLOAT Temp2;
- LVM_INT16 i;
- LVM_FLOAT ScaleTable[] = {LVREV_T_3_Power_minus0_on_4, LVREV_T_3_Power_minus1_on_4,
- LVREV_T_3_Power_minus2_on_4, LVREV_T_3_Power_minus3_on_4};
-
-
- /*
- * For each delay line
- */
- for (i = 0; i < NumberOfDelayLines; i++)
- {
- Temp1 = (3 * pPrivate->RoomSizeInms * ScaleTable[i]) / pPrivate->NewParams.T60;
- if(Temp1 >= (4))
- {
- G[i] = 0;
- }
- else if((Temp1 >= (2)))
- {
- Temp2 = LVM_Power10(-(Temp1 / 2.0f));
- Temp1 = LVM_Power10(-(Temp1 / 2.0f));
- Temp1 = Temp1 * Temp2;
- }
- else
- {
- Temp1 = LVM_Power10(-(Temp1));
- }
- if (NumberOfDelayLines == 1)
- {
- G[i] = Temp1;
- }
- else
- {
- LVM_FLOAT TempG;
- TempG = Temp1 * ONE_OVER_SQRT_TWO;
- G[i]=TempG;
- }
- }
- }
-
- /* Set up the feedback mixers for four delay lines */
- pPrivate->FeedbackMixer[0].Target=G[0];
- pPrivate->FeedbackMixer[1].Target=G[1];
- pPrivate->FeedbackMixer[2].Target=G[2];
- pPrivate->FeedbackMixer[3].Target=G[3];
- }
-
-
- /*
- * Calculate the gain correction
- */
- if((pPrivate->NewParams.RoomSize != pPrivate->CurrentParams.RoomSize) ||
- (pPrivate->NewParams.Level != pPrivate->CurrentParams.Level) ||
- (pPrivate->NewParams.T60 != pPrivate->CurrentParams.T60) )
- {
- LVM_INT32 Index=0;
- LVM_FLOAT Index_FLOAT;
- LVM_INT32 i=0;
- LVM_FLOAT Gain=0;
- LVM_INT32 RoomSize=0;
- LVM_FLOAT T60;
- LVM_FLOAT Coefs[5];
-
-
- if(pPrivate->NewParams.RoomSize == 0)
- {
- RoomSize = 1;
- }
- else
- {
- RoomSize = (LVM_INT32)pPrivate->NewParams.RoomSize;
- }
-
-
- if(pPrivate->NewParams.T60 < 100)
- {
- T60 = 100 * LVREV_T60_SCALE;
- }
- else
- {
- T60 = pPrivate->NewParams.T60 * LVREV_T60_SCALE;
- }
-
- /* Find the nearest room size in table */
- for(i = 0; i < 24; i++)
- {
- if(RoomSize <= LVREV_GainPolyTable[i][0])
- {
- Index = i;
- break;
- }
- }
-
-
- if(RoomSize == LVREV_GainPolyTable[Index][0])
- {
- /* Take table values if the room size is in table */
- for(i = 1; i < 5; i++)
- {
- Coefs[i-1] = LVREV_GainPolyTable[Index][i];
- }
- Coefs[4] = 0;
- Gain = LVM_Polynomial(3, Coefs, T60); /* Q.24 result */
- }
- else
- {
- /* Interpolate the gain between nearest room sizes */
-
- LVM_FLOAT Gain1,Gain2;
- LVM_INT32 Tot_Dist,Dist;
-
- Tot_Dist = (LVM_UINT32)LVREV_GainPolyTable[Index][0] - \
- (LVM_UINT32)LVREV_GainPolyTable[Index-1][0];
- Dist = RoomSize - (LVM_UINT32)LVREV_GainPolyTable[Index - 1][0];
-
-
- /* Get gain for first */
- for(i = 1; i < 5; i++)
- {
- Coefs[i-1] = LVREV_GainPolyTable[Index-1][i];
- }
- Coefs[4] = 0;
-
- Gain1 = LVM_Polynomial(3, Coefs, T60); /* Q.24 result */
-
- /* Get gain for second */
- for(i = 1; i < 5; i++)
- {
- Coefs[i-1] = LVREV_GainPolyTable[Index][i];
- }
- Coefs[4] = 0;
-
- Gain2 = LVM_Polynomial(3, Coefs, T60); /* Q.24 result */
-
- /* Linear Interpolate the gain */
- Gain = Gain1 + (((Gain2 - Gain1) * Dist) / (Tot_Dist));
- }
-
-
- /*
- * Get the inverse of gain: Q.15
- * Gain is mostly above one except few cases, take only gains above 1
- */
- if(Gain < 1)
- {
- pPrivate->Gain = 1;
- }
- else
- {
- pPrivate->Gain = 1 / Gain;
- }
-
- Index_FLOAT = 100.0f / (LVM_FLOAT)(100 + pPrivate->NewParams.Level);
- pPrivate->Gain = pPrivate->Gain * Index_FLOAT;
- pPrivate->GainMixer.Target = (pPrivate->Gain*Index_FLOAT) / 2;
- }
-
-
- /*
- * Update the all pass comb filter coefficient
- */
- if( (pPrivate->NewParams.Density != pPrivate->CurrentParams.Density) ||
- (pPrivate->bFirstControl == LVM_TRUE))
- {
- LVM_INT16 i;
- LVM_FLOAT b = (LVM_FLOAT)pPrivate->NewParams.Density * LVREV_B_8_on_1000;
-
- for (i = 0; i < 4; i++)
- {
- pPrivate->Mixer_SGFeedback[i].Target = b;
- pPrivate->Mixer_SGFeedforward[i].Target = b;
- }
- }
-
-
- /*
- * Update the bypass mixer time constant
- */
- if((pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
- (pPrivate->bFirstControl == LVM_TRUE))
- {
- LVM_UINT16 NumChannels = 1; /* Assume MONO format */
- LVM_FLOAT Alpha;
-
- Alpha = LVM_Mixer_TimeConstant(LVREV_FEEDBACKMIXER_TC,
- LVM_GetFsFromTable(pPrivate->NewParams.SampleRate),
- NumChannels);
- pPrivate->FeedbackMixer[0].Alpha = Alpha;
- pPrivate->FeedbackMixer[1].Alpha = Alpha;
- pPrivate->FeedbackMixer[2].Alpha = Alpha;
- pPrivate->FeedbackMixer[3].Alpha = Alpha;
-
- NumChannels = 2; /* Always stereo output */
- pPrivate->BypassMixer.Alpha1 = LVM_Mixer_TimeConstant(LVREV_BYPASSMIXER_TC,
- LVM_GetFsFromTable(pPrivate->NewParams.SampleRate), NumChannels);
- pPrivate->BypassMixer.Alpha2 = pPrivate->BypassMixer.Alpha1;
- pPrivate->GainMixer.Alpha = pPrivate->BypassMixer.Alpha1;
- }
-
-
- /*
- * Update the bypass mixer targets
- */
- if( (pPrivate->NewParams.Level != pPrivate->CurrentParams.Level) &&
- (pPrivate->NewParams.OperatingMode == LVM_MODE_ON))
- {
- pPrivate->BypassMixer.Target2 = (LVM_FLOAT)(pPrivate->NewParams.Level ) / 100.0f;
- pPrivate->BypassMixer.Target1 = 0x00000000;
- if ((pPrivate->NewParams.Level == 0) && (pPrivate->bFirstControl == LVM_FALSE))
- {
- pPrivate->BypassMixer.CallbackSet2 = LVM_TRUE;
- }
- if (pPrivate->NewParams.Level != 0)
- {
- pPrivate->bDisableReverb = LVM_FALSE;
- }
- }
-
- if(pPrivate->NewParams.OperatingMode != pPrivate->CurrentParams.OperatingMode)
- {
- if(pPrivate->NewParams.OperatingMode == LVM_MODE_ON)
- {
- pPrivate->BypassMixer.Target2 = (LVM_FLOAT)(pPrivate->NewParams.Level ) / 100.0f;
- pPrivate->BypassMixer.Target1 = 0x00000000;
-
- pPrivate->BypassMixer.CallbackSet2 = LVM_FALSE;
- OperatingMode = LVM_MODE_ON;
- if (pPrivate->NewParams.Level == 0)
- {
- pPrivate->bDisableReverb = LVM_TRUE;
- }
- else
- {
- pPrivate->bDisableReverb = LVM_FALSE;
- }
- }
- else if (pPrivate->bFirstControl == LVM_FALSE)
- {
- pPrivate->BypassMixer.Target2 = 0x00000000;
- pPrivate->BypassMixer.Target1 = 0x00000000;
- pPrivate->BypassMixer.CallbackSet2 = LVM_TRUE;
- pPrivate->GainMixer.Target = 0.03125f;
- OperatingMode = LVM_MODE_ON;
- }
- else
- {
- OperatingMode = LVM_MODE_OFF;
- }
- }
-
-
- /* If it is the first call to ApplyNew settings force the current to the target \
- to begin immediate playback of the effect */
- if(pPrivate->bFirstControl == LVM_TRUE)
- {
- pPrivate->BypassMixer.Current1 = pPrivate->BypassMixer.Target1;
- pPrivate->BypassMixer.Current2 = pPrivate->BypassMixer.Target2;
- }
-
-
- /*
- * Copy the new parameters
- */
- pPrivate->CurrentParams = pPrivate->NewParams;
- pPrivate->CurrentParams.OperatingMode = OperatingMode;
-
-
- /*
- * Update flag
- */
- if(pPrivate->bFirstControl == LVM_TRUE)
- {
- pPrivate->bFirstControl = LVM_FALSE;
- }
-
-
- return LVREV_SUCCESS;
-}
-#endif /*BUILD_FLOAT*/
-/****************************************************************************************/
-/* */
-/* FUNCTION: BypassMixer_Callback */
-/* */
-/* DESCRIPTION: */
-/* Controls the On to Off operating mode transition */
-/* */
-/* PARAMETERS: */
-/* pPrivate Pointer to the instance private parameters */
-/* */
-/* RETURNS: */
-/* LVREV_Success Succeeded */
-/* LVREV_NULLADDRESS When pPrivate is NULL */
-/* */
-/* NOTES: */
-/* */
-/****************************************************************************************/
-LVM_INT32 BypassMixer_Callback (void *pCallbackData,
- void *pGeneralPurpose,
- LVM_INT16 GeneralPurpose )
-{
-
- LVREV_Instance_st *pLVREV_Private = (LVREV_Instance_st *)pCallbackData;
-
-
- /*
- * Avoid build warnings
- */
- (void)pGeneralPurpose;
- (void)GeneralPurpose;
-
-
- /*
- * Turn off
- */
- pLVREV_Private->CurrentParams.OperatingMode = LVM_MODE_OFF;
- pLVREV_Private->bDisableReverb = LVM_TRUE;
- LVREV_ClearAudioBuffers((LVREV_Handle_t)pCallbackData);
-
-
- return 0;
-}
-
-/* End of file */
-
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_ApplyNewSettings.cpp b/media/libeffects/lvm/lib/Reverb/src/LVREV_ApplyNewSettings.cpp
new file mode 100644
index 0000000..1f0d39b
--- /dev/null
+++ b/media/libeffects/lvm/lib/Reverb/src/LVREV_ApplyNewSettings.cpp
@@ -0,0 +1,633 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/****************************************************************************************/
+/* */
+/* Includes */
+/* */
+/****************************************************************************************/
+#include "LVREV_Private.h"
+#include "Filter.h"
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVREV_ApplyNewSettings */
+/* */
+/* DESCRIPTION: */
+/* Applies the new control parameters */
+/* */
+/* PARAMETERS: */
+/* pPrivate Pointer to the instance private parameters */
+/* */
+/* RETURNS: */
+/* LVREV_Success Succeeded */
+/* LVREV_NULLADDRESS When pPrivate is NULL */
+/* */
+/* NOTES: */
+/* */
+/****************************************************************************************/
+
+LVREV_ReturnStatus_en LVREV_ApplyNewSettings (LVREV_Instance_st *pPrivate)
+{
+
+ LVM_Mode_en OperatingMode;
+ LVM_INT32 NumberOfDelayLines;
+
+ /* Check for NULL pointer */
+ if(pPrivate == LVM_NULL)
+ {
+ return LVREV_NULLADDRESS;
+ }
+
+ OperatingMode = pPrivate->NewParams.OperatingMode;
+
+ if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_4)
+ {
+ NumberOfDelayLines = 4;
+ }
+ else if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_2)
+ {
+ NumberOfDelayLines = 2;
+ }
+ else
+ {
+ NumberOfDelayLines = 1;
+ }
+
+ /*
+ * Update the high pass filter coefficients
+ */
+ if((pPrivate->NewParams.HPF != pPrivate->CurrentParams.HPF) ||
+ (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
+ (pPrivate->bFirstControl == LVM_TRUE))
+ {
+ LVM_FLOAT Omega;
+ FO_FLOAT_Coefs_t Coeffs;
+
+ Omega = LVM_GetOmega(pPrivate->NewParams.HPF, pPrivate->NewParams.SampleRate);
+ LVM_FO_HPF(Omega, &Coeffs);
+ FO_1I_D32F32Cll_TRC_WRA_01_Init( &pPrivate->pFastCoef->HPCoefs,
+ &pPrivate->pFastData->HPTaps, &Coeffs);
+ LoadConst_Float(0,
+ (LVM_FLOAT *)&pPrivate->pFastData->HPTaps,
+ sizeof(Biquad_1I_Order1_FLOAT_Taps_t) / sizeof(LVM_FLOAT));
+ }
+
+ /*
+ * Update the low pass filter coefficients
+ */
+ if((pPrivate->NewParams.LPF != pPrivate->CurrentParams.LPF) ||
+ (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
+ (pPrivate->bFirstControl == LVM_TRUE))
+ {
+ LVM_FLOAT Omega;
+ FO_FLOAT_Coefs_t Coeffs;
+
+ Coeffs.A0 = 1;
+ Coeffs.A1 = 0;
+ Coeffs.B1 = 0;
+ if(pPrivate->NewParams.LPF <= (LVM_FsTable[pPrivate->NewParams.SampleRate] >> 1))
+ {
+ Omega = LVM_GetOmega(pPrivate->NewParams.LPF, pPrivate->NewParams.SampleRate);
+
+ /*
+ * Do not apply filter if w =2*pi*fc/fs >= 2.9
+ */
+ if(Omega <= (LVM_FLOAT)LVREV_2_9_INQ29)
+ {
+ LVM_FO_LPF(Omega, &Coeffs);
+ }
+ }
+ FO_1I_D32F32Cll_TRC_WRA_01_Init( &pPrivate->pFastCoef->LPCoefs,
+ &pPrivate->pFastData->LPTaps, &Coeffs);
+ LoadConst_Float(0,
+ (LVM_FLOAT *)&pPrivate->pFastData->LPTaps,
+ sizeof(Biquad_1I_Order1_FLOAT_Taps_t) / sizeof(LVM_FLOAT));
+ }
+
+ /*
+ * Calculate the room size parameter
+ */
+ if( pPrivate->NewParams.RoomSize != pPrivate->CurrentParams.RoomSize)
+ {
+ /* Room size range is 10ms to 200ms
+ * 0% -- 10ms
+ * 50% -- 65ms
+ * 100% -- 120ms
+ */
+ pPrivate->RoomSizeInms = 10 + (((pPrivate->NewParams.RoomSize*11) + 5) / 10);
+ }
+
+ /*
+ * Update the T delay number of samples and the all pass delay number of samples
+ */
+ if( (pPrivate->NewParams.RoomSize != pPrivate->CurrentParams.RoomSize) ||
+ (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
+ (pPrivate->bFirstControl == LVM_TRUE))
+ {
+
+ LVM_UINT32 Temp;
+ LVM_INT32 APDelaySize;
+ LVM_INT32 Fs = LVM_GetFsFromTable(pPrivate->NewParams.SampleRate);
+ LVM_UINT32 DelayLengthSamples = (LVM_UINT32)(Fs * pPrivate->RoomSizeInms);
+ LVM_INT16 i;
+ LVM_FLOAT ScaleTable[] = {LVREV_T_3_Power_minus0_on_4, LVREV_T_3_Power_minus1_on_4, \
+ LVREV_T_3_Power_minus2_on_4, LVREV_T_3_Power_minus3_on_4};
+ LVM_INT16 MaxT_Delay[] = {LVREV_MAX_T0_DELAY, LVREV_MAX_T1_DELAY, \
+ LVREV_MAX_T2_DELAY, LVREV_MAX_T3_DELAY};
+ LVM_INT16 MaxAP_Delay[] = {LVREV_MAX_AP0_DELAY, LVREV_MAX_AP1_DELAY, \
+ LVREV_MAX_AP2_DELAY, LVREV_MAX_AP3_DELAY};
+
+ /*
+ * For each delay line
+ */
+ for (i = 0; i < NumberOfDelayLines; i++)
+ {
+ if (i != 0)
+ {
+ LVM_FLOAT Temp1; /* to avoid QAC warning on type conversion */
+
+ Temp1=(LVM_FLOAT)DelayLengthSamples;
+ Temp = (LVM_UINT32)(Temp1 * ScaleTable[i]);
+ }
+ else
+ {
+ Temp = DelayLengthSamples;
+ }
+ APDelaySize = Temp / 1500;
+
+ /*
+ * Set the fixed delay
+ */
+
+ Temp = (MaxT_Delay[i] - MaxAP_Delay[i]) * Fs / 192000;
+ pPrivate->Delay_AP[i] = pPrivate->T[i] - Temp;
+
+ /*
+ * Set the tap selection
+ */
+ if (pPrivate->AB_Selection)
+ {
+ /* Smooth from tap A to tap B */
+ pPrivate->pOffsetB[i] = &pPrivate->pDelay_T[i][pPrivate->T[i] - \
+ Temp - APDelaySize];
+ pPrivate->B_DelaySize[i] = APDelaySize;
+ pPrivate->Mixer_APTaps[i].Target1 = 0;
+ pPrivate->Mixer_APTaps[i].Target2 = 1.0f;
+ }
+ else
+ {
+ /* Smooth from tap B to tap A */
+ pPrivate->pOffsetA[i] = &pPrivate->pDelay_T[i][pPrivate->T[i] - \
+ Temp - APDelaySize];
+ pPrivate->A_DelaySize[i] = APDelaySize;
+ pPrivate->Mixer_APTaps[i].Target2 = 0;
+ pPrivate->Mixer_APTaps[i].Target1 = 1.0f;
+ }
+
+ /*
+ * Set the maximum block size to the smallest delay size
+ */
+ pPrivate->MaxBlkLen = Temp;
+ if (pPrivate->MaxBlkLen > pPrivate->A_DelaySize[i])
+ {
+ pPrivate->MaxBlkLen = pPrivate->A_DelaySize[i];
+ }
+ if (pPrivate->MaxBlkLen > pPrivate->B_DelaySize[i])
+ {
+ pPrivate->MaxBlkLen = pPrivate->B_DelaySize[i];
+ }
+ }
+ if (pPrivate->AB_Selection)
+ {
+ pPrivate->AB_Selection = 0;
+ }
+ else
+ {
+ pPrivate->AB_Selection = 1;
+ }
+
+ /*
+ * Limit the maximum block length
+ */
+ /* Just as a precausion, but no problem if we remove this line */
+ pPrivate->MaxBlkLen = pPrivate->MaxBlkLen - 2;
+ if(pPrivate->MaxBlkLen > pPrivate->InstanceParams.MaxBlockSize)
+ {
+ pPrivate->MaxBlkLen = (LVM_INT32)pPrivate->InstanceParams.MaxBlockSize;
+ }
+ }
+
+ /*
+ * Update the low pass filter coefficient
+ */
+ if( (pPrivate->NewParams.Damping != pPrivate->CurrentParams.Damping) ||
+ (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
+ (pPrivate->bFirstControl == LVM_TRUE))
+ {
+
+ LVM_INT32 Temp;
+ LVM_FLOAT Omega;
+ FO_FLOAT_Coefs_t Coeffs;
+ LVM_INT16 i;
+ LVM_INT16 Damping = (LVM_INT16)((pPrivate->NewParams.Damping * 100) + 1000);
+ LVM_FLOAT ScaleTable[] = {LVREV_T_3_Power_0_on_4, LVREV_T_3_Power_1_on_4,
+ LVREV_T_3_Power_2_on_4, LVREV_T_3_Power_3_on_4};
+
+ /*
+ * For each filter
+ */
+ for (i = 0; i < NumberOfDelayLines; i++)
+ {
+ if (i != 0)
+ {
+ Temp = (LVM_INT32)(ScaleTable[i] * Damping);
+ }
+ else
+ {
+ Temp = Damping;
+ }
+ if(Temp <= (LVM_INT32)(LVM_FsTable[pPrivate->NewParams.SampleRate] >> 1))
+ {
+ Omega = LVM_GetOmega(Temp, pPrivate->NewParams.SampleRate);
+ LVM_FO_LPF(Omega, &Coeffs);
+ }
+ else
+ {
+ Coeffs.A0 = 1;
+ Coeffs.A1 = 0;
+ Coeffs.B1 = 0;
+ }
+ FO_1I_D32F32Cll_TRC_WRA_01_Init(&pPrivate->pFastCoef->RevLPCoefs[i],
+ &pPrivate->pFastData->RevLPTaps[i], &Coeffs);
+ }
+ }
+
+ /*
+ * Update All-pass filter mixer time constants
+ */
+ if( (pPrivate->NewParams.RoomSize != pPrivate->CurrentParams.RoomSize) ||
+ (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
+ (pPrivate->NewParams.Density != pPrivate->CurrentParams.Density))
+ {
+ LVM_INT16 i;
+ LVM_FLOAT Alpha;
+ LVM_FLOAT AlphaTap;
+
+ Alpha = LVM_Mixer_TimeConstant(LVREV_ALLPASS_TC,
+ LVM_GetFsFromTable(pPrivate->NewParams.SampleRate),
+ 1);
+
+ AlphaTap = LVM_Mixer_TimeConstant(LVREV_ALLPASS_TAP_TC,
+ LVM_GetFsFromTable(pPrivate->NewParams.SampleRate),
+ 1);
+
+ for (i = 0; i < 4; i++)
+ {
+ pPrivate->Mixer_APTaps[i].Alpha1 = AlphaTap;
+ pPrivate->Mixer_APTaps[i].Alpha2 = AlphaTap;
+ pPrivate->Mixer_SGFeedback[i].Alpha = Alpha;
+ pPrivate->Mixer_SGFeedforward[i].Alpha = Alpha;
+ }
+ }
+
+ /*
+ * Update the feed back gain
+ */
+ if( (pPrivate->NewParams.RoomSize != pPrivate->CurrentParams.RoomSize) ||
+ (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
+ (pPrivate->NewParams.T60 != pPrivate->CurrentParams.T60) ||
+ (pPrivate->bFirstControl == LVM_TRUE))
+ {
+
+ LVM_FLOAT G[4]; /* Feedback gain (Q7.24) */
+
+ if(pPrivate->NewParams.T60 == 0)
+ {
+ G[3] = 0;
+ G[2] = 0;
+ G[1] = 0;
+ G[0] = 0;
+ }
+ else
+ {
+ LVM_FLOAT Temp1;
+ LVM_FLOAT Temp2;
+ LVM_INT16 i;
+ LVM_FLOAT ScaleTable[] = {LVREV_T_3_Power_minus0_on_4, LVREV_T_3_Power_minus1_on_4,
+ LVREV_T_3_Power_minus2_on_4, LVREV_T_3_Power_minus3_on_4};
+
+ /*
+ * For each delay line
+ */
+ for (i = 0; i < NumberOfDelayLines; i++)
+ {
+ Temp1 = (3 * pPrivate->RoomSizeInms * ScaleTable[i]) / pPrivate->NewParams.T60;
+ if(Temp1 >= (4))
+ {
+ G[i] = 0;
+ }
+ else if((Temp1 >= (2)))
+ {
+ Temp2 = LVM_Power10(-(Temp1 / 2.0f));
+ Temp1 = LVM_Power10(-(Temp1 / 2.0f));
+ Temp1 = Temp1 * Temp2;
+ }
+ else
+ {
+ Temp1 = LVM_Power10(-(Temp1));
+ }
+ if (NumberOfDelayLines == 1)
+ {
+ G[i] = Temp1;
+ }
+ else
+ {
+ LVM_FLOAT TempG;
+ TempG = Temp1 * ONE_OVER_SQRT_TWO;
+ G[i]=TempG;
+ }
+ }
+ }
+
+ /* Set up the feedback mixers for four delay lines */
+ pPrivate->FeedbackMixer[0].Target=G[0];
+ pPrivate->FeedbackMixer[1].Target=G[1];
+ pPrivate->FeedbackMixer[2].Target=G[2];
+ pPrivate->FeedbackMixer[3].Target=G[3];
+ }
+
+ /*
+ * Calculate the gain correction
+ */
+ if((pPrivate->NewParams.RoomSize != pPrivate->CurrentParams.RoomSize) ||
+ (pPrivate->NewParams.Level != pPrivate->CurrentParams.Level) ||
+ (pPrivate->NewParams.T60 != pPrivate->CurrentParams.T60) )
+ {
+ LVM_INT32 Index=0;
+ LVM_FLOAT Index_FLOAT;
+ LVM_INT32 i=0;
+ LVM_FLOAT Gain=0;
+ LVM_INT32 RoomSize=0;
+ LVM_FLOAT T60;
+ LVM_FLOAT Coefs[5];
+
+ if(pPrivate->NewParams.RoomSize == 0)
+ {
+ RoomSize = 1;
+ }
+ else
+ {
+ RoomSize = (LVM_INT32)pPrivate->NewParams.RoomSize;
+ }
+
+ if(pPrivate->NewParams.T60 < 100)
+ {
+ T60 = 100 * LVREV_T60_SCALE;
+ }
+ else
+ {
+ T60 = pPrivate->NewParams.T60 * LVREV_T60_SCALE;
+ }
+
+ /* Find the nearest room size in table */
+ for(i = 0; i < 24; i++)
+ {
+ if(RoomSize <= LVREV_GainPolyTable[i][0])
+ {
+ Index = i;
+ break;
+ }
+ }
+
+ if(RoomSize == LVREV_GainPolyTable[Index][0])
+ {
+ /* Take table values if the room size is in table */
+ for(i = 1; i < 5; i++)
+ {
+ Coefs[i-1] = LVREV_GainPolyTable[Index][i];
+ }
+ Coefs[4] = 0;
+ Gain = LVM_Polynomial(3, Coefs, T60); /* Q.24 result */
+ }
+ else
+ {
+ /* Interpolate the gain between nearest room sizes */
+
+ LVM_FLOAT Gain1,Gain2;
+ LVM_INT32 Tot_Dist,Dist;
+
+ Tot_Dist = (LVM_UINT32)LVREV_GainPolyTable[Index][0] - \
+ (LVM_UINT32)LVREV_GainPolyTable[Index-1][0];
+ Dist = RoomSize - (LVM_UINT32)LVREV_GainPolyTable[Index - 1][0];
+
+ /* Get gain for first */
+ for(i = 1; i < 5; i++)
+ {
+ Coefs[i-1] = LVREV_GainPolyTable[Index-1][i];
+ }
+ Coefs[4] = 0;
+
+ Gain1 = LVM_Polynomial(3, Coefs, T60); /* Q.24 result */
+
+ /* Get gain for second */
+ for(i = 1; i < 5; i++)
+ {
+ Coefs[i-1] = LVREV_GainPolyTable[Index][i];
+ }
+ Coefs[4] = 0;
+
+ Gain2 = LVM_Polynomial(3, Coefs, T60); /* Q.24 result */
+
+ /* Linear Interpolate the gain */
+ Gain = Gain1 + (((Gain2 - Gain1) * Dist) / (Tot_Dist));
+ }
+
+ /*
+ * Get the inverse of gain: Q.15
+ * Gain is mostly above one except few cases, take only gains above 1
+ */
+ if(Gain < 1)
+ {
+ pPrivate->Gain = 1;
+ }
+ else
+ {
+ pPrivate->Gain = 1 / Gain;
+ }
+
+ Index_FLOAT = 100.0f / (LVM_FLOAT)(100 + pPrivate->NewParams.Level);
+ pPrivate->Gain = pPrivate->Gain * Index_FLOAT;
+ pPrivate->GainMixer.Target = (pPrivate->Gain*Index_FLOAT) / 2;
+ }
+
+ /*
+ * Update the all pass comb filter coefficient
+ */
+ if( (pPrivate->NewParams.Density != pPrivate->CurrentParams.Density) ||
+ (pPrivate->bFirstControl == LVM_TRUE))
+ {
+ LVM_INT16 i;
+ LVM_FLOAT b = (LVM_FLOAT)pPrivate->NewParams.Density * LVREV_B_8_on_1000;
+
+ for (i = 0; i < 4; i++)
+ {
+ pPrivate->Mixer_SGFeedback[i].Target = b;
+ pPrivate->Mixer_SGFeedforward[i].Target = b;
+ }
+ }
+
+ /*
+ * Update the bypass mixer time constant
+ */
+ if((pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
+ (pPrivate->bFirstControl == LVM_TRUE))
+ {
+ LVM_UINT16 NumChannels = 1; /* Assume MONO format */
+ LVM_FLOAT Alpha;
+
+ Alpha = LVM_Mixer_TimeConstant(LVREV_FEEDBACKMIXER_TC,
+ LVM_GetFsFromTable(pPrivate->NewParams.SampleRate),
+ NumChannels);
+ pPrivate->FeedbackMixer[0].Alpha = Alpha;
+ pPrivate->FeedbackMixer[1].Alpha = Alpha;
+ pPrivate->FeedbackMixer[2].Alpha = Alpha;
+ pPrivate->FeedbackMixer[3].Alpha = Alpha;
+
+ NumChannels = 2; /* Always stereo output */
+ pPrivate->BypassMixer.Alpha1 = LVM_Mixer_TimeConstant(LVREV_BYPASSMIXER_TC,
+ LVM_GetFsFromTable(pPrivate->NewParams.SampleRate), NumChannels);
+ pPrivate->BypassMixer.Alpha2 = pPrivate->BypassMixer.Alpha1;
+ pPrivate->GainMixer.Alpha = pPrivate->BypassMixer.Alpha1;
+ }
+
+ /*
+ * Update the bypass mixer targets
+ */
+ if( (pPrivate->NewParams.Level != pPrivate->CurrentParams.Level) &&
+ (pPrivate->NewParams.OperatingMode == LVM_MODE_ON))
+ {
+ pPrivate->BypassMixer.Target2 = (LVM_FLOAT)(pPrivate->NewParams.Level ) / 100.0f;
+ pPrivate->BypassMixer.Target1 = 0x00000000;
+ if ((pPrivate->NewParams.Level == 0) && (pPrivate->bFirstControl == LVM_FALSE))
+ {
+ pPrivate->BypassMixer.CallbackSet2 = LVM_TRUE;
+ }
+ if (pPrivate->NewParams.Level != 0)
+ {
+ pPrivate->bDisableReverb = LVM_FALSE;
+ }
+ }
+
+ if(pPrivate->NewParams.OperatingMode != pPrivate->CurrentParams.OperatingMode)
+ {
+ if(pPrivate->NewParams.OperatingMode == LVM_MODE_ON)
+ {
+ pPrivate->BypassMixer.Target2 = (LVM_FLOAT)(pPrivate->NewParams.Level ) / 100.0f;
+ pPrivate->BypassMixer.Target1 = 0x00000000;
+
+ pPrivate->BypassMixer.CallbackSet2 = LVM_FALSE;
+ OperatingMode = LVM_MODE_ON;
+ if (pPrivate->NewParams.Level == 0)
+ {
+ pPrivate->bDisableReverb = LVM_TRUE;
+ }
+ else
+ {
+ pPrivate->bDisableReverb = LVM_FALSE;
+ }
+ }
+ else if (pPrivate->bFirstControl == LVM_FALSE)
+ {
+ pPrivate->BypassMixer.Target2 = 0x00000000;
+ pPrivate->BypassMixer.Target1 = 0x00000000;
+ pPrivate->BypassMixer.CallbackSet2 = LVM_TRUE;
+ pPrivate->GainMixer.Target = 0.03125f;
+ OperatingMode = LVM_MODE_ON;
+ }
+ else
+ {
+ OperatingMode = LVM_MODE_OFF;
+ }
+ }
+
+ /* If it is the first call to ApplyNew settings force the current to the target \
+ to begin immediate playback of the effect */
+ if(pPrivate->bFirstControl == LVM_TRUE)
+ {
+ pPrivate->BypassMixer.Current1 = pPrivate->BypassMixer.Target1;
+ pPrivate->BypassMixer.Current2 = pPrivate->BypassMixer.Target2;
+ }
+
+ /*
+ * Copy the new parameters
+ */
+ pPrivate->CurrentParams = pPrivate->NewParams;
+ pPrivate->CurrentParams.OperatingMode = OperatingMode;
+
+ /*
+ * Update flag
+ */
+ if(pPrivate->bFirstControl == LVM_TRUE)
+ {
+ pPrivate->bFirstControl = LVM_FALSE;
+ }
+
+ return LVREV_SUCCESS;
+}
+/****************************************************************************************/
+/* */
+/* FUNCTION: BypassMixer_Callback */
+/* */
+/* DESCRIPTION: */
+/* Controls the On to Off operating mode transition */
+/* */
+/* PARAMETERS: */
+/* pPrivate Pointer to the instance private parameters */
+/* */
+/* RETURNS: */
+/* LVREV_Success Succeeded */
+/* LVREV_NULLADDRESS When pPrivate is NULL */
+/* */
+/* NOTES: */
+/* */
+/****************************************************************************************/
+LVM_INT32 BypassMixer_Callback (void *pCallbackData,
+ void *pGeneralPurpose,
+ LVM_INT16 GeneralPurpose )
+{
+
+ LVREV_Instance_st *pLVREV_Private = (LVREV_Instance_st *)pCallbackData;
+
+ /*
+ * Avoid build warnings
+ */
+ (void)pGeneralPurpose;
+ (void)GeneralPurpose;
+
+ /*
+ * Turn off
+ */
+ pLVREV_Private->CurrentParams.OperatingMode = LVM_MODE_OFF;
+ pLVREV_Private->bDisableReverb = LVM_TRUE;
+ LVREV_ClearAudioBuffers((LVREV_Handle_t)pCallbackData);
+
+ return 0;
+}
+
+/* End of file */
+
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_ClearAudioBuffers.c b/media/libeffects/lvm/lib/Reverb/src/LVREV_ClearAudioBuffers.c
deleted file mode 100644
index 9491016..0000000
--- a/media/libeffects/lvm/lib/Reverb/src/LVREV_ClearAudioBuffers.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/****************************************************************************************/
-/* */
-/* Includes */
-/* */
-/****************************************************************************************/
-#include "LVREV_Private.h"
-#include "VectorArithmetic.h"
-
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVREV_ClearAudioBuffers */
-/* */
-/* DESCRIPTION: */
-/* This function is used to clear the internal audio buffers of the module. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance handle */
-/* */
-/* RETURNS: */
-/* LVREV_SUCCESS Initialisation succeeded */
-/* LVREV_NULLADDRESS Instance is NULL */
-/* */
-/* NOTES: */
-/* 1. This function must not be interrupted by the LVM_Process function */
-/* */
-/****************************************************************************************/
-LVREV_ReturnStatus_en LVREV_ClearAudioBuffers(LVREV_Handle_t hInstance)
-{
-
- LVREV_Instance_st *pLVREV_Private = (LVREV_Instance_st *)hInstance;
-
-
- /*
- * Check for error conditions
- */
- /* Check for NULL pointers */
- if(hInstance == LVM_NULL)
- {
- return LVREV_NULLADDRESS;
- }
-
- /*
- * Clear all filter tap data, delay-lines and other signal related data
- */
-
-#ifdef BUILD_FLOAT
- LoadConst_Float(0,
- (void *)&pLVREV_Private->pFastData->HPTaps, /* Destination Cast to void: \
- no dereferencing in function*/
- 2);
- LoadConst_Float(0,
- (void *)&pLVREV_Private->pFastData->LPTaps, /* Destination Cast to void: \
- no dereferencing in function*/
- 2);
-#else
- LoadConst_32(0,
- (void *)&pLVREV_Private->pFastData->HPTaps, /* Destination Cast to void: no dereferencing in function*/
- 2);
- LoadConst_32(0,
- (void *)&pLVREV_Private->pFastData->LPTaps, /* Destination Cast to void: no dereferencing in function*/
- 2);
-#endif
- if((LVM_UINT16)pLVREV_Private->InstanceParams.NumDelays == LVREV_DELAYLINES_4)
- {
-#ifndef BUILD_FLOAT
- LoadConst_32(0, (LVM_INT32 *)&pLVREV_Private->pFastData->RevLPTaps[3], 2);
- LoadConst_32(0, (LVM_INT32 *)&pLVREV_Private->pFastData->RevLPTaps[2], 2);
- LoadConst_32(0, (LVM_INT32 *)&pLVREV_Private->pFastData->RevLPTaps[1], 2);
- LoadConst_32(0, (LVM_INT32 *)&pLVREV_Private->pFastData->RevLPTaps[0], 2);
-
- LoadConst_32(0,pLVREV_Private->pDelay_T[3], (LVM_INT16)LVREV_MAX_T3_DELAY);
- LoadConst_32(0,pLVREV_Private->pDelay_T[2], (LVM_INT16)LVREV_MAX_T2_DELAY);
- LoadConst_32(0,pLVREV_Private->pDelay_T[1], (LVM_INT16)LVREV_MAX_T1_DELAY);
- LoadConst_32(0,pLVREV_Private->pDelay_T[0], (LVM_INT16)LVREV_MAX_T0_DELAY);
-#else
- LoadConst_Float(0, (LVM_FLOAT *)&pLVREV_Private->pFastData->RevLPTaps[3], 2);
- LoadConst_Float(0, (LVM_FLOAT *)&pLVREV_Private->pFastData->RevLPTaps[2], 2);
- LoadConst_Float(0, (LVM_FLOAT *)&pLVREV_Private->pFastData->RevLPTaps[1], 2);
- LoadConst_Float(0, (LVM_FLOAT *)&pLVREV_Private->pFastData->RevLPTaps[0], 2);
-
- LoadConst_Float(0, pLVREV_Private->pDelay_T[3], LVREV_MAX_T3_DELAY);
- LoadConst_Float(0, pLVREV_Private->pDelay_T[2], LVREV_MAX_T2_DELAY);
- LoadConst_Float(0, pLVREV_Private->pDelay_T[1], LVREV_MAX_T1_DELAY);
- LoadConst_Float(0, pLVREV_Private->pDelay_T[0], LVREV_MAX_T0_DELAY);
-#endif
- }
-
- if((LVM_UINT16)pLVREV_Private->InstanceParams.NumDelays >= LVREV_DELAYLINES_2)
- {
-#ifndef BUILD_FLOAT
- LoadConst_32(0, (LVM_INT32 *)&pLVREV_Private->pFastData->RevLPTaps[1], 2);
- LoadConst_32(0, (LVM_INT32 *)&pLVREV_Private->pFastData->RevLPTaps[0], 2);
-
- LoadConst_32(0,pLVREV_Private->pDelay_T[1], (LVM_INT16)LVREV_MAX_T1_DELAY);
- LoadConst_32(0,pLVREV_Private->pDelay_T[0], (LVM_INT16)LVREV_MAX_T0_DELAY);
-#else
- LoadConst_Float(0, (LVM_FLOAT *)&pLVREV_Private->pFastData->RevLPTaps[1], 2);
- LoadConst_Float(0, (LVM_FLOAT *)&pLVREV_Private->pFastData->RevLPTaps[0], 2);
-
- LoadConst_Float(0, pLVREV_Private->pDelay_T[1], LVREV_MAX_T1_DELAY);
- LoadConst_Float(0, pLVREV_Private->pDelay_T[0], LVREV_MAX_T0_DELAY);
-#endif
- }
-
- if((LVM_UINT16)pLVREV_Private->InstanceParams.NumDelays >= LVREV_DELAYLINES_1)
- {
-#ifndef BUILD_FLOAT
- LoadConst_32(0, (LVM_INT32 *)&pLVREV_Private->pFastData->RevLPTaps[0], 2);
- LoadConst_32(0,pLVREV_Private->pDelay_T[0], (LVM_INT16)LVREV_MAX_T0_DELAY);
-#else
- LoadConst_Float(0, (LVM_FLOAT *)&pLVREV_Private->pFastData->RevLPTaps[0], 2);
- LoadConst_Float(0, pLVREV_Private->pDelay_T[0], LVREV_MAX_T0_DELAY);
-#endif
- }
- return LVREV_SUCCESS;
-}
-
-/* End of file */
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_ClearAudioBuffers.cpp b/media/libeffects/lvm/lib/Reverb/src/LVREV_ClearAudioBuffers.cpp
new file mode 100644
index 0000000..586539f
--- /dev/null
+++ b/media/libeffects/lvm/lib/Reverb/src/LVREV_ClearAudioBuffers.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/****************************************************************************************/
+/* */
+/* Includes */
+/* */
+/****************************************************************************************/
+#include "LVREV_Private.h"
+#include "VectorArithmetic.h"
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVREV_ClearAudioBuffers */
+/* */
+/* DESCRIPTION: */
+/* This function is used to clear the internal audio buffers of the module. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance handle */
+/* */
+/* RETURNS: */
+/* LVREV_SUCCESS Initialisation succeeded */
+/* LVREV_NULLADDRESS Instance is NULL */
+/* */
+/* NOTES: */
+/* 1. This function must not be interrupted by the LVM_Process function */
+/* */
+/****************************************************************************************/
+LVREV_ReturnStatus_en LVREV_ClearAudioBuffers(LVREV_Handle_t hInstance)
+{
+
+ LVREV_Instance_st *pLVREV_Private = (LVREV_Instance_st *)hInstance;
+
+ /*
+ * Check for error conditions
+ */
+ /* Check for NULL pointers */
+ if(hInstance == LVM_NULL)
+ {
+ return LVREV_NULLADDRESS;
+ }
+
+ /*
+ * Clear all filter tap data, delay-lines and other signal related data
+ */
+
+ LoadConst_Float(0,
+ (LVM_FLOAT *)&pLVREV_Private->pFastData->HPTaps,
+ 2);
+ LoadConst_Float(0,
+ (LVM_FLOAT *)&pLVREV_Private->pFastData->LPTaps,
+ 2);
+ if((LVM_UINT16)pLVREV_Private->InstanceParams.NumDelays == LVREV_DELAYLINES_4)
+ {
+ LoadConst_Float(0, (LVM_FLOAT *)&pLVREV_Private->pFastData->RevLPTaps[3], 2);
+ LoadConst_Float(0, (LVM_FLOAT *)&pLVREV_Private->pFastData->RevLPTaps[2], 2);
+ LoadConst_Float(0, (LVM_FLOAT *)&pLVREV_Private->pFastData->RevLPTaps[1], 2);
+ LoadConst_Float(0, (LVM_FLOAT *)&pLVREV_Private->pFastData->RevLPTaps[0], 2);
+
+ LoadConst_Float(0, pLVREV_Private->pDelay_T[3], LVREV_MAX_T3_DELAY);
+ LoadConst_Float(0, pLVREV_Private->pDelay_T[2], LVREV_MAX_T2_DELAY);
+ LoadConst_Float(0, pLVREV_Private->pDelay_T[1], LVREV_MAX_T1_DELAY);
+ LoadConst_Float(0, pLVREV_Private->pDelay_T[0], LVREV_MAX_T0_DELAY);
+ }
+
+ if((LVM_UINT16)pLVREV_Private->InstanceParams.NumDelays >= LVREV_DELAYLINES_2)
+ {
+ LoadConst_Float(0, (LVM_FLOAT *)&pLVREV_Private->pFastData->RevLPTaps[1], 2);
+ LoadConst_Float(0, (LVM_FLOAT *)&pLVREV_Private->pFastData->RevLPTaps[0], 2);
+
+ LoadConst_Float(0, pLVREV_Private->pDelay_T[1], LVREV_MAX_T1_DELAY);
+ LoadConst_Float(0, pLVREV_Private->pDelay_T[0], LVREV_MAX_T0_DELAY);
+ }
+
+ if((LVM_UINT16)pLVREV_Private->InstanceParams.NumDelays >= LVREV_DELAYLINES_1)
+ {
+ LoadConst_Float(0, (LVM_FLOAT *)&pLVREV_Private->pFastData->RevLPTaps[0], 2);
+ LoadConst_Float(0, pLVREV_Private->pDelay_T[0], LVREV_MAX_T0_DELAY);
+ }
+ return LVREV_SUCCESS;
+}
+
+/* End of file */
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_GetControlParameters.c b/media/libeffects/lvm/lib/Reverb/src/LVREV_GetControlParameters.c
deleted file mode 100644
index 7cee26d..0000000
--- a/media/libeffects/lvm/lib/Reverb/src/LVREV_GetControlParameters.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/****************************************************************************************/
-/* */
-/* Includes */
-/* */
-/****************************************************************************************/
-#include "LVREV_Private.h"
-
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVREV_GetControlParameters */
-/* */
-/* DESCRIPTION: */
-/* Request the LVREV module control parameters. The current parameter set is returned */
-/* via the parameter pointer. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance handle */
-/* pControlParams Pointer to an empty parameter structure */
-/* */
-/* RETURNS: */
-/* LVREV_Success Succeeded */
-/* LVREV_NULLADDRESS When hInstance or pControlParams is NULL */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVREV_Process function */
-/* */
-/****************************************************************************************/
-LVREV_ReturnStatus_en LVREV_GetControlParameters(LVREV_Handle_t hInstance,
- LVREV_ControlParams_st *pControlParams)
-{
-
- LVREV_Instance_st *pLVREV_Private = (LVREV_Instance_st *)hInstance;
-
-
- /*
- * Check for error conditions
- */
- if((hInstance == LVM_NULL) || (pControlParams == LVM_NULL))
- {
- return LVREV_NULLADDRESS;
- }
-
- /*
- * Return the current parameters
- */
- *pControlParams = pLVREV_Private->NewParams;
-
- return LVREV_SUCCESS;
-}
-
-/* End of file */
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_GetControlParameters.cpp b/media/libeffects/lvm/lib/Reverb/src/LVREV_GetControlParameters.cpp
new file mode 100644
index 0000000..e0b0142
--- /dev/null
+++ b/media/libeffects/lvm/lib/Reverb/src/LVREV_GetControlParameters.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/****************************************************************************************/
+/* */
+/* Includes */
+/* */
+/****************************************************************************************/
+#include "LVREV_Private.h"
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVREV_GetControlParameters */
+/* */
+/* DESCRIPTION: */
+/* Request the LVREV module control parameters. The current parameter set is returned */
+/* via the parameter pointer. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance handle */
+/* pControlParams Pointer to an empty parameter structure */
+/* */
+/* RETURNS: */
+/* LVREV_Success Succeeded */
+/* LVREV_NULLADDRESS When hInstance or pControlParams is NULL */
+/* */
+/* NOTES: */
+/* 1. This function may be interrupted by the LVREV_Process function */
+/* */
+/****************************************************************************************/
+LVREV_ReturnStatus_en LVREV_GetControlParameters(LVREV_Handle_t hInstance,
+ LVREV_ControlParams_st *pControlParams)
+{
+
+ LVREV_Instance_st *pLVREV_Private = (LVREV_Instance_st *)hInstance;
+
+ /*
+ * Check for error conditions
+ */
+ if((hInstance == LVM_NULL) || (pControlParams == LVM_NULL))
+ {
+ return LVREV_NULLADDRESS;
+ }
+
+ /*
+ * Return the current parameters
+ */
+ *pControlParams = pLVREV_Private->NewParams;
+
+ return LVREV_SUCCESS;
+}
+
+/* End of file */
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_GetInstanceHandle.c b/media/libeffects/lvm/lib/Reverb/src/LVREV_GetInstanceHandle.c
deleted file mode 100644
index 3366bcb..0000000
--- a/media/libeffects/lvm/lib/Reverb/src/LVREV_GetInstanceHandle.c
+++ /dev/null
@@ -1,417 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/****************************************************************************************/
-/* */
-/* Includes */
-/* */
-/****************************************************************************************/
-#include "LVREV_Private.h"
-#include "InstAlloc.h"
-
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVREV_GetInstanceHandle */
-/* */
-/* DESCRIPTION: */
-/* This function is used to create a LVREV module instance. It returns the created */
-/* instance handle through phInstance. All parameters are set to their default, */
-/* inactive state. */
-/* */
-/* PARAMETERS: */
-/* phInstance pointer to the instance handle */
-/* pMemoryTable Pointer to the memory definition table */
-/* pInstanceParams Pointer to the instance parameters */
-/* */
-/* RETURNS: */
-/* LVREV_SUCCESS Succeeded */
-/* LVREV_NULLADDRESS When phInstance or pMemoryTable or pInstanceParams is NULL */
-/* LVREV_NULLADDRESS When one of the memory regions has a NULL pointer */
-/* */
-/* NOTES: */
-/* */
-/****************************************************************************************/
-LVREV_ReturnStatus_en LVREV_GetInstanceHandle(LVREV_Handle_t *phInstance,
- LVREV_MemoryTable_st *pMemoryTable,
- LVREV_InstanceParams_st *pInstanceParams)
-{
-
- INST_ALLOC SlowData;
- INST_ALLOC FastData;
- INST_ALLOC FastCoef;
- INST_ALLOC Temporary;
- LVREV_Instance_st *pLVREV_Private;
- LVM_INT16 i;
- LVM_UINT16 MaxBlockSize;
-
-
- /*
- * Check for error conditions
- */
- /* Check for NULL pointers */
- if((phInstance == LVM_NULL) || (pMemoryTable == LVM_NULL) || (pInstanceParams == LVM_NULL))
- {
- return LVREV_NULLADDRESS;
- }
- /* Check the memory table for NULL pointers */
- for (i = 0; i < LVREV_NR_MEMORY_REGIONS; i++)
- {
- if (pMemoryTable->Region[i].Size!=0)
- {
- if (pMemoryTable->Region[i].pBaseAddress==LVM_NULL)
- {
- return(LVREV_NULLADDRESS);
- }
- }
- }
-
- /*
- * Check all instance parameters are in range
- */
- /* Check for a non-zero block size */
- if (pInstanceParams->MaxBlockSize == 0)
- {
- return LVREV_OUTOFRANGE;
- }
-
- /* Check for a valid number of delay lines */
- if ((pInstanceParams->NumDelays != LVREV_DELAYLINES_1)&&
- (pInstanceParams->NumDelays != LVREV_DELAYLINES_2)&&
- (pInstanceParams->NumDelays != LVREV_DELAYLINES_4))
- {
- return LVREV_OUTOFRANGE;
- }
-
- /*
- * Initialise the InstAlloc instances
- */
- InstAlloc_Init(&SlowData, pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].pBaseAddress);
- InstAlloc_Init(&FastData, pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].pBaseAddress);
- InstAlloc_Init(&FastCoef, pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].pBaseAddress);
- InstAlloc_Init(&Temporary, pMemoryTable->Region[LVM_TEMPORARY_FAST].pBaseAddress);
-
- /*
- * Zero all memory regions
- */
-#ifdef BUILD_FLOAT
- LoadConst_Float(0,
- (LVM_FLOAT *)pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].pBaseAddress,
- (LVM_INT16)((pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].Size) / \
- sizeof(LVM_FLOAT)));
- LoadConst_Float(0,
- (LVM_FLOAT *)pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].pBaseAddress,
- (LVM_INT16)((pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].Size) / \
- sizeof(LVM_FLOAT)));
- LoadConst_Float(0,
- (LVM_FLOAT *)pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].pBaseAddress,
- (LVM_INT16)((pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].Size) / \
- sizeof(LVM_FLOAT)));
- LoadConst_Float(0,
- (LVM_FLOAT *)pMemoryTable->Region[LVM_TEMPORARY_FAST].pBaseAddress,
- (LVM_INT16)((pMemoryTable->Region[LVM_TEMPORARY_FAST].Size) / \
- sizeof(LVM_FLOAT)));
-#else
- LoadConst_16(0, (LVM_INT16 *)pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].pBaseAddress, (LVM_INT16)((pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].Size)/sizeof(LVM_INT16)));
- LoadConst_16(0, (LVM_INT16 *)pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].pBaseAddress, (LVM_INT16)((pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].Size)/sizeof(LVM_INT16)));
- LoadConst_16(0, (LVM_INT16 *)pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].pBaseAddress, (LVM_INT16)((pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].Size)/sizeof(LVM_INT16)));
- LoadConst_16(0, (LVM_INT16 *)pMemoryTable->Region[LVM_TEMPORARY_FAST].pBaseAddress, (LVM_INT16)((pMemoryTable->Region[LVM_TEMPORARY_FAST].Size)/sizeof(LVM_INT16)));
-#endif
- /*
- * Set the instance handle if not already initialised
- */
- if (*phInstance == LVM_NULL)
- {
- *phInstance = InstAlloc_AddMember(&SlowData, sizeof(LVREV_Instance_st));
- }
- pLVREV_Private =(LVREV_Instance_st *)*phInstance;
- pLVREV_Private->MemoryTable = *pMemoryTable;
-
- if(pInstanceParams->NumDelays ==LVREV_DELAYLINES_4)
- {
- MaxBlockSize = LVREV_MAX_AP3_DELAY;
- }
- else if(pInstanceParams->NumDelays ==LVREV_DELAYLINES_2)
- {
- MaxBlockSize = LVREV_MAX_AP1_DELAY;
- }
- else
- {
- MaxBlockSize = LVREV_MAX_AP0_DELAY;
- }
-
- if(MaxBlockSize>pInstanceParams->MaxBlockSize)
- {
- MaxBlockSize=pInstanceParams->MaxBlockSize;
- }
-
-
- /*
- * Set the data, coefficient and temporary memory pointers
- */
- pLVREV_Private->pFastData = InstAlloc_AddMember(&FastData, sizeof(LVREV_FastData_st)); /* Fast data memory base address */
-#ifndef BUILD_FLOAT
- if(pInstanceParams->NumDelays == LVREV_DELAYLINES_4)
- {
- pLVREV_Private->pDelay_T[3] = InstAlloc_AddMember(&FastData, LVREV_MAX_T3_DELAY * sizeof(LVM_INT32));
- pLVREV_Private->pDelay_T[2] = InstAlloc_AddMember(&FastData, LVREV_MAX_T2_DELAY * sizeof(LVM_INT32));
- pLVREV_Private->pDelay_T[1] = InstAlloc_AddMember(&FastData, LVREV_MAX_T1_DELAY * sizeof(LVM_INT32));
- pLVREV_Private->pDelay_T[0] = InstAlloc_AddMember(&FastData, LVREV_MAX_T0_DELAY * sizeof(LVM_INT32));
-
- for( i = 0; i < 4; i++)
- {
- pLVREV_Private->pScratchDelayLine[i] = InstAlloc_AddMember(&Temporary, sizeof(LVM_INT32) * MaxBlockSize); /* Scratch for each delay line output */
- }
-
- LoadConst_32(0,pLVREV_Private->pDelay_T[3] ,(LVM_INT16)LVREV_MAX_T3_DELAY);
- LoadConst_32(0,pLVREV_Private->pDelay_T[2] ,(LVM_INT16)LVREV_MAX_T2_DELAY);
- LoadConst_32(0,pLVREV_Private->pDelay_T[1] ,(LVM_INT16)LVREV_MAX_T1_DELAY);
- LoadConst_32(0,pLVREV_Private->pDelay_T[0] ,(LVM_INT16)LVREV_MAX_T0_DELAY);
- }
-
- if(pInstanceParams->NumDelays == LVREV_DELAYLINES_2)
- {
- pLVREV_Private->pDelay_T[1] = InstAlloc_AddMember(&FastData, LVREV_MAX_T1_DELAY * sizeof(LVM_INT32));
- pLVREV_Private->pDelay_T[0] = InstAlloc_AddMember(&FastData, LVREV_MAX_T0_DELAY * sizeof(LVM_INT32));
-
- for( i = 0; i < 2; i++)
- {
- pLVREV_Private->pScratchDelayLine[i] = InstAlloc_AddMember(&Temporary, sizeof(LVM_INT32) * MaxBlockSize); /* Scratch for each delay line output */
- }
-
- LoadConst_32(0,pLVREV_Private->pDelay_T[1] , (LVM_INT16)LVREV_MAX_T1_DELAY);
- LoadConst_32(0,pLVREV_Private->pDelay_T[0] , (LVM_INT16)LVREV_MAX_T0_DELAY);
- }
-
- if(pInstanceParams->NumDelays == LVREV_DELAYLINES_1)
- {
- pLVREV_Private->pDelay_T[0] = InstAlloc_AddMember(&FastData, LVREV_MAX_T0_DELAY * sizeof(LVM_INT32));
-
- for( i = 0; i < 1; i++)
- {
- pLVREV_Private->pScratchDelayLine[i] = InstAlloc_AddMember(&Temporary, sizeof(LVM_INT32) * MaxBlockSize); /* Scratch for each delay line output */
- }
-
- LoadConst_32(0,pLVREV_Private->pDelay_T[0] , (LVM_INT16)LVREV_MAX_T0_DELAY);
- }
-#else
- if(pInstanceParams->NumDelays == LVREV_DELAYLINES_4)
- {
- pLVREV_Private->pDelay_T[3] = InstAlloc_AddMember(&FastData, LVREV_MAX_T3_DELAY * \
- sizeof(LVM_FLOAT));
- pLVREV_Private->pDelay_T[2] = InstAlloc_AddMember(&FastData, LVREV_MAX_T2_DELAY * \
- sizeof(LVM_FLOAT));
- pLVREV_Private->pDelay_T[1] = InstAlloc_AddMember(&FastData, LVREV_MAX_T1_DELAY * \
- sizeof(LVM_FLOAT));
- pLVREV_Private->pDelay_T[0] = InstAlloc_AddMember(&FastData, LVREV_MAX_T0_DELAY * \
- sizeof(LVM_FLOAT));
-
- for(i = 0; i < 4; i++)
- {
- /* Scratch for each delay line output */
- pLVREV_Private->pScratchDelayLine[i] = InstAlloc_AddMember(&Temporary,
- sizeof(LVM_FLOAT) * \
- MaxBlockSize);
- }
-
- LoadConst_Float(0, pLVREV_Private->pDelay_T[3], LVREV_MAX_T3_DELAY);
- LoadConst_Float(0, pLVREV_Private->pDelay_T[2], LVREV_MAX_T2_DELAY);
- LoadConst_Float(0, pLVREV_Private->pDelay_T[1], LVREV_MAX_T1_DELAY);
- LoadConst_Float(0, pLVREV_Private->pDelay_T[0], LVREV_MAX_T0_DELAY);
- }
-
- if(pInstanceParams->NumDelays == LVREV_DELAYLINES_2)
- {
- pLVREV_Private->pDelay_T[1] = InstAlloc_AddMember(&FastData, LVREV_MAX_T1_DELAY * \
- sizeof(LVM_FLOAT));
- pLVREV_Private->pDelay_T[0] = InstAlloc_AddMember(&FastData, LVREV_MAX_T0_DELAY * \
- sizeof(LVM_FLOAT));
-
- for(i = 0; i < 2; i++)
- {
- /* Scratch for each delay line output */
- pLVREV_Private->pScratchDelayLine[i] = InstAlloc_AddMember(&Temporary,
- sizeof(LVM_FLOAT) * \
- MaxBlockSize);
- }
-
- LoadConst_Float(0, pLVREV_Private->pDelay_T[1], (LVM_INT16)LVREV_MAX_T1_DELAY);
- LoadConst_Float(0, pLVREV_Private->pDelay_T[0], (LVM_INT16)LVREV_MAX_T0_DELAY);
- }
-
- if(pInstanceParams->NumDelays == LVREV_DELAYLINES_1)
- {
- pLVREV_Private->pDelay_T[0] = InstAlloc_AddMember(&FastData,
- LVREV_MAX_T0_DELAY * sizeof(LVM_FLOAT));
-
- for(i = 0; i < 1; i++)
- {
- /* Scratch for each delay line output */
- pLVREV_Private->pScratchDelayLine[i] = InstAlloc_AddMember(&Temporary,
- sizeof(LVM_FLOAT) * \
- MaxBlockSize);
- }
-
- LoadConst_Float(0, pLVREV_Private->pDelay_T[0], (LVM_INT16)LVREV_MAX_T0_DELAY);
- }
-#endif
- /* All-pass delay buffer addresses and sizes */
- pLVREV_Private->T[0] = LVREV_MAX_T0_DELAY;
- pLVREV_Private->T[1] = LVREV_MAX_T1_DELAY;
- pLVREV_Private->T[2] = LVREV_MAX_T2_DELAY;
- pLVREV_Private->T[3] = LVREV_MAX_T3_DELAY;
- pLVREV_Private->AB_Selection = 1; /* Select smoothing A to B */
-
-
- pLVREV_Private->pFastCoef = InstAlloc_AddMember(&FastCoef, sizeof(LVREV_FastCoef_st)); /* Fast coefficient memory base address */
-#ifndef BUILD_FLOAT
- pLVREV_Private->pScratch = InstAlloc_AddMember(&Temporary, sizeof(LVM_INT32) * MaxBlockSize); /* General purpose scratch */
- pLVREV_Private->pInputSave = InstAlloc_AddMember(&Temporary, 2 * sizeof(LVM_INT32) * MaxBlockSize); /* Mono->stereo input save for end mix */
- LoadConst_32(0, pLVREV_Private->pInputSave, (LVM_INT16)(MaxBlockSize*2));
-#else
- /* General purpose scratch */
- pLVREV_Private->pScratch = InstAlloc_AddMember(&Temporary, sizeof(LVM_FLOAT) * \
- MaxBlockSize);
- /* Mono->stereo input save for end mix */
- pLVREV_Private->pInputSave = InstAlloc_AddMember(&Temporary, 2 * sizeof(LVM_FLOAT) * \
- MaxBlockSize);
- LoadConst_Float(0, pLVREV_Private->pInputSave, (LVM_INT16)(MaxBlockSize * 2));
-#endif
-
- /*
- * Save the instance parameters in the instance structure
- */
- pLVREV_Private->InstanceParams = *pInstanceParams;
-
-
- /*
- * Set the parameters to invalid
- */
- pLVREV_Private->CurrentParams.SampleRate = LVM_FS_INVALID;
- pLVREV_Private->CurrentParams.OperatingMode = LVM_MODE_DUMMY;
- pLVREV_Private->CurrentParams.SourceFormat = LVM_SOURCE_DUMMY;
-
- pLVREV_Private->bControlPending = LVM_FALSE;
- pLVREV_Private->bFirstControl = LVM_TRUE;
- pLVREV_Private->bDisableReverb = LVM_FALSE;
-
-
- /*
- * Set mixer parameters
- */
- pLVREV_Private->BypassMixer.CallbackParam2 = 0;
- pLVREV_Private->BypassMixer.pCallbackHandle2 = pLVREV_Private;
- pLVREV_Private->BypassMixer.pGeneralPurpose2 = LVM_NULL;
- pLVREV_Private->BypassMixer.pCallBack2 = BypassMixer_Callback;
- pLVREV_Private->BypassMixer.CallbackSet2 = LVM_FALSE;
- pLVREV_Private->BypassMixer.Current2 = 0;
- pLVREV_Private->BypassMixer.Target2 = 0;
- pLVREV_Private->BypassMixer.CallbackParam1 = 0;
- pLVREV_Private->BypassMixer.pCallbackHandle1 = LVM_NULL;
- pLVREV_Private->BypassMixer.pGeneralPurpose1 = LVM_NULL;
- pLVREV_Private->BypassMixer.pCallBack1 = LVM_NULL;
- pLVREV_Private->BypassMixer.CallbackSet1 = LVM_FALSE;
- pLVREV_Private->BypassMixer.Current1 = 0x00000000;
- pLVREV_Private->BypassMixer.Target1 = 0x00000000;
-
- pLVREV_Private->RoomSizeInms = 100; // 100 msec
-
-
- /*
- * Set the output gain mixer parameters
- */
- pLVREV_Private->GainMixer.CallbackParam = 0;
- pLVREV_Private->GainMixer.pCallbackHandle = LVM_NULL;
- pLVREV_Private->GainMixer.pGeneralPurpose = LVM_NULL;
- pLVREV_Private->GainMixer.pCallBack = LVM_NULL;
- pLVREV_Private->GainMixer.CallbackSet = LVM_FALSE;
-#ifndef BUILD_FLOAT
- pLVREV_Private->GainMixer.Current = 0x03ffffff;
- pLVREV_Private->GainMixer.Target = 0x03ffffff;
-#else
- pLVREV_Private->GainMixer.Current = 0.03125f;//0x03ffffff;
- pLVREV_Private->GainMixer.Target = 0.03125f;//0x03ffffff;
-#endif
-
- /*
- * Set the All-Pass Filter mixers
- */
- for (i=0; i<4; i++)
- {
- pLVREV_Private->pOffsetA[i] = pLVREV_Private->pDelay_T[i];
- pLVREV_Private->pOffsetB[i] = pLVREV_Private->pDelay_T[i];
- /* Delay tap selection mixer */
- pLVREV_Private->Mixer_APTaps[i].CallbackParam2 = 0;
- pLVREV_Private->Mixer_APTaps[i].pCallbackHandle2 = LVM_NULL;
- pLVREV_Private->Mixer_APTaps[i].pGeneralPurpose2 = LVM_NULL;
- pLVREV_Private->Mixer_APTaps[i].pCallBack2 = LVM_NULL;
- pLVREV_Private->Mixer_APTaps[i].CallbackSet2 = LVM_FALSE;
- pLVREV_Private->Mixer_APTaps[i].Current2 = 0;
- pLVREV_Private->Mixer_APTaps[i].Target2 = 0;
- pLVREV_Private->Mixer_APTaps[i].CallbackParam1 = 0;
- pLVREV_Private->Mixer_APTaps[i].pCallbackHandle1 = LVM_NULL;
- pLVREV_Private->Mixer_APTaps[i].pGeneralPurpose1 = LVM_NULL;
- pLVREV_Private->Mixer_APTaps[i].pCallBack1 = LVM_NULL;
- pLVREV_Private->Mixer_APTaps[i].CallbackSet1 = LVM_FALSE;
- pLVREV_Private->Mixer_APTaps[i].Current1 = 0;
-#ifndef BUILD_FLOAT
- pLVREV_Private->Mixer_APTaps[i].Target1 = 0x7fffffff;
-#else
- pLVREV_Private->Mixer_APTaps[i].Target1 = 1;
-#endif
- /* Feedforward mixer */
- pLVREV_Private->Mixer_SGFeedforward[i].CallbackParam = 0;
- pLVREV_Private->Mixer_SGFeedforward[i].pCallbackHandle = LVM_NULL;
- pLVREV_Private->Mixer_SGFeedforward[i].pGeneralPurpose = LVM_NULL;
- pLVREV_Private->Mixer_SGFeedforward[i].pCallBack = LVM_NULL;
- pLVREV_Private->Mixer_SGFeedforward[i].CallbackSet = LVM_FALSE;
- pLVREV_Private->Mixer_SGFeedforward[i].Current = 0;
- pLVREV_Private->Mixer_SGFeedforward[i].Target = 0;
- /* Feedback mixer */
- pLVREV_Private->Mixer_SGFeedback[i].CallbackParam = 0;
- pLVREV_Private->Mixer_SGFeedback[i].pCallbackHandle = LVM_NULL;
- pLVREV_Private->Mixer_SGFeedback[i].pGeneralPurpose = LVM_NULL;
- pLVREV_Private->Mixer_SGFeedback[i].pCallBack = LVM_NULL;
- pLVREV_Private->Mixer_SGFeedback[i].CallbackSet = LVM_FALSE;
- pLVREV_Private->Mixer_SGFeedback[i].Current = 0;
- pLVREV_Private->Mixer_SGFeedback[i].Target = 0;
- /* Feedback gain mixer */
- pLVREV_Private->FeedbackMixer[i].CallbackParam = 0;
- pLVREV_Private->FeedbackMixer[i].pCallbackHandle = LVM_NULL;
- pLVREV_Private->FeedbackMixer[i].pGeneralPurpose = LVM_NULL;
- pLVREV_Private->FeedbackMixer[i].pCallBack = LVM_NULL;
- pLVREV_Private->FeedbackMixer[i].CallbackSet = LVM_FALSE;
- pLVREV_Private->FeedbackMixer[i].Current = 0;
- pLVREV_Private->FeedbackMixer[i].Target = 0;
- }
- /* Delay tap index */
- pLVREV_Private->A_DelaySize[0] = LVREV_MAX_AP0_DELAY;
- pLVREV_Private->B_DelaySize[0] = LVREV_MAX_AP0_DELAY;
- pLVREV_Private->A_DelaySize[1] = LVREV_MAX_AP1_DELAY;
- pLVREV_Private->B_DelaySize[1] = LVREV_MAX_AP1_DELAY;
- pLVREV_Private->A_DelaySize[2] = LVREV_MAX_AP2_DELAY;
- pLVREV_Private->B_DelaySize[2] = LVREV_MAX_AP2_DELAY;
- pLVREV_Private->A_DelaySize[3] = LVREV_MAX_AP3_DELAY;
- pLVREV_Private->B_DelaySize[3] = LVREV_MAX_AP3_DELAY;
-
-
- LVREV_ClearAudioBuffers(*phInstance);
-
- return LVREV_SUCCESS;
-}
-
-/* End of file */
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_GetInstanceHandle.cpp b/media/libeffects/lvm/lib/Reverb/src/LVREV_GetInstanceHandle.cpp
new file mode 100644
index 0000000..68f883a
--- /dev/null
+++ b/media/libeffects/lvm/lib/Reverb/src/LVREV_GetInstanceHandle.cpp
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/****************************************************************************************/
+/* */
+/* Includes */
+/* */
+/****************************************************************************************/
+#include "LVREV_Private.h"
+#include "InstAlloc.h"
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVREV_GetInstanceHandle */
+/* */
+/* DESCRIPTION: */
+/* This function is used to create a LVREV module instance. It returns the created */
+/* instance handle through phInstance. All parameters are set to their default, */
+/* inactive state. */
+/* */
+/* PARAMETERS: */
+/* phInstance pointer to the instance handle */
+/* pMemoryTable Pointer to the memory definition table */
+/* pInstanceParams Pointer to the instance parameters */
+/* */
+/* RETURNS: */
+/* LVREV_SUCCESS Succeeded */
+/* LVREV_NULLADDRESS When phInstance or pMemoryTable or pInstanceParams is NULL */
+/* LVREV_NULLADDRESS When one of the memory regions has a NULL pointer */
+/* */
+/* NOTES: */
+/* */
+/****************************************************************************************/
+LVREV_ReturnStatus_en LVREV_GetInstanceHandle(LVREV_Handle_t *phInstance,
+ LVREV_MemoryTable_st *pMemoryTable,
+ LVREV_InstanceParams_st *pInstanceParams)
+{
+
+ INST_ALLOC SlowData;
+ INST_ALLOC FastData;
+ INST_ALLOC FastCoef;
+ INST_ALLOC Temporary;
+ LVREV_Instance_st *pLVREV_Private;
+ LVM_INT16 i;
+ LVM_UINT16 MaxBlockSize;
+
+ /*
+ * Check for error conditions
+ */
+ /* Check for NULL pointers */
+ if((phInstance == LVM_NULL) || (pMemoryTable == LVM_NULL) || (pInstanceParams == LVM_NULL))
+ {
+ return LVREV_NULLADDRESS;
+ }
+ /* Check the memory table for NULL pointers */
+ for (i = 0; i < LVREV_NR_MEMORY_REGIONS; i++)
+ {
+ if (pMemoryTable->Region[i].Size!=0)
+ {
+ if (pMemoryTable->Region[i].pBaseAddress==LVM_NULL)
+ {
+ return(LVREV_NULLADDRESS);
+ }
+ }
+ }
+
+ /*
+ * Check all instance parameters are in range
+ */
+ /* Check for a non-zero block size */
+ if (pInstanceParams->MaxBlockSize == 0)
+ {
+ return LVREV_OUTOFRANGE;
+ }
+
+ /* Check for a valid number of delay lines */
+ if ((pInstanceParams->NumDelays != LVREV_DELAYLINES_1)&&
+ (pInstanceParams->NumDelays != LVREV_DELAYLINES_2)&&
+ (pInstanceParams->NumDelays != LVREV_DELAYLINES_4))
+ {
+ return LVREV_OUTOFRANGE;
+ }
+
+ /*
+ * Initialise the InstAlloc instances
+ */
+ InstAlloc_Init(&SlowData, pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].pBaseAddress);
+ InstAlloc_Init(&FastData, pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].pBaseAddress);
+ InstAlloc_Init(&FastCoef, pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].pBaseAddress);
+ InstAlloc_Init(&Temporary, pMemoryTable->Region[LVM_TEMPORARY_FAST].pBaseAddress);
+
+ /*
+ * Zero all memory regions
+ */
+ LoadConst_Float(0,
+ (LVM_FLOAT *)pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].pBaseAddress,
+ (LVM_INT16)((pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].Size) / \
+ sizeof(LVM_FLOAT)));
+ LoadConst_Float(0,
+ (LVM_FLOAT *)pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].pBaseAddress,
+ (LVM_INT16)((pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].Size) / \
+ sizeof(LVM_FLOAT)));
+ LoadConst_Float(0,
+ (LVM_FLOAT *)pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].pBaseAddress,
+ (LVM_INT16)((pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].Size) / \
+ sizeof(LVM_FLOAT)));
+ LoadConst_Float(0,
+ (LVM_FLOAT *)pMemoryTable->Region[LVM_TEMPORARY_FAST].pBaseAddress,
+ (LVM_INT16)((pMemoryTable->Region[LVM_TEMPORARY_FAST].Size) / \
+ sizeof(LVM_FLOAT)));
+ /*
+ * Set the instance handle if not already initialised
+ */
+ if (*phInstance == LVM_NULL)
+ {
+ *phInstance = InstAlloc_AddMember(&SlowData, sizeof(LVREV_Instance_st));
+ }
+ pLVREV_Private =(LVREV_Instance_st *)*phInstance;
+ pLVREV_Private->MemoryTable = *pMemoryTable;
+
+ if(pInstanceParams->NumDelays ==LVREV_DELAYLINES_4)
+ {
+ MaxBlockSize = LVREV_MAX_AP3_DELAY;
+ }
+ else if(pInstanceParams->NumDelays ==LVREV_DELAYLINES_2)
+ {
+ MaxBlockSize = LVREV_MAX_AP1_DELAY;
+ }
+ else
+ {
+ MaxBlockSize = LVREV_MAX_AP0_DELAY;
+ }
+
+ if(MaxBlockSize>pInstanceParams->MaxBlockSize)
+ {
+ MaxBlockSize=pInstanceParams->MaxBlockSize;
+ }
+
+ /*
+ * Set the data, coefficient and temporary memory pointers
+ */
+ /* Fast data memory base address */
+ pLVREV_Private->pFastData = (LVREV_FastData_st *)
+ InstAlloc_AddMember(&FastData, sizeof(LVREV_FastData_st));
+ if(pInstanceParams->NumDelays == LVREV_DELAYLINES_4)
+ {
+ pLVREV_Private->pDelay_T[3] =
+ (LVM_FLOAT *)InstAlloc_AddMember(&FastData, LVREV_MAX_T3_DELAY * \
+ sizeof(LVM_FLOAT));
+ pLVREV_Private->pDelay_T[2] =
+ (LVM_FLOAT *)InstAlloc_AddMember(&FastData, LVREV_MAX_T2_DELAY * \
+ sizeof(LVM_FLOAT));
+ pLVREV_Private->pDelay_T[1] =
+ (LVM_FLOAT *)InstAlloc_AddMember(&FastData, LVREV_MAX_T1_DELAY * \
+ sizeof(LVM_FLOAT));
+ pLVREV_Private->pDelay_T[0] =
+ (LVM_FLOAT *)InstAlloc_AddMember(&FastData, LVREV_MAX_T0_DELAY * \
+ sizeof(LVM_FLOAT));
+
+ for(i = 0; i < 4; i++)
+ {
+ /* Scratch for each delay line output */
+ pLVREV_Private->pScratchDelayLine[i] = (LVM_FLOAT *)InstAlloc_AddMember(&Temporary,
+ sizeof(LVM_FLOAT) * \
+ MaxBlockSize);
+ }
+
+ LoadConst_Float(0, pLVREV_Private->pDelay_T[3], LVREV_MAX_T3_DELAY);
+ LoadConst_Float(0, pLVREV_Private->pDelay_T[2], LVREV_MAX_T2_DELAY);
+ LoadConst_Float(0, pLVREV_Private->pDelay_T[1], LVREV_MAX_T1_DELAY);
+ LoadConst_Float(0, pLVREV_Private->pDelay_T[0], LVREV_MAX_T0_DELAY);
+ }
+
+ if(pInstanceParams->NumDelays == LVREV_DELAYLINES_2)
+ {
+ pLVREV_Private->pDelay_T[1] = (LVM_FLOAT *)
+ InstAlloc_AddMember(&FastData, LVREV_MAX_T1_DELAY * \
+ sizeof(LVM_FLOAT));
+ pLVREV_Private->pDelay_T[0] = (LVM_FLOAT *)
+ InstAlloc_AddMember(&FastData, LVREV_MAX_T0_DELAY * \
+ sizeof(LVM_FLOAT));
+
+ for(i = 0; i < 2; i++)
+ {
+ /* Scratch for each delay line output */
+ pLVREV_Private->pScratchDelayLine[i] = (LVM_FLOAT *)InstAlloc_AddMember(&Temporary,
+ sizeof(LVM_FLOAT) * \
+ MaxBlockSize);
+ }
+
+ LoadConst_Float(0, pLVREV_Private->pDelay_T[1], (LVM_INT16)LVREV_MAX_T1_DELAY);
+ LoadConst_Float(0, pLVREV_Private->pDelay_T[0], (LVM_INT16)LVREV_MAX_T0_DELAY);
+ }
+
+ if(pInstanceParams->NumDelays == LVREV_DELAYLINES_1)
+ {
+ pLVREV_Private->pDelay_T[0] = (LVM_FLOAT *)InstAlloc_AddMember(&FastData,
+ LVREV_MAX_T0_DELAY * sizeof(LVM_FLOAT));
+
+ for(i = 0; i < 1; i++)
+ {
+ /* Scratch for each delay line output */
+ pLVREV_Private->pScratchDelayLine[i] = (LVM_FLOAT *)InstAlloc_AddMember(&Temporary,
+ sizeof(LVM_FLOAT) * \
+ MaxBlockSize);
+ }
+
+ LoadConst_Float(0, pLVREV_Private->pDelay_T[0], (LVM_INT16)LVREV_MAX_T0_DELAY);
+ }
+ /* All-pass delay buffer addresses and sizes */
+ pLVREV_Private->T[0] = LVREV_MAX_T0_DELAY;
+ pLVREV_Private->T[1] = LVREV_MAX_T1_DELAY;
+ pLVREV_Private->T[2] = LVREV_MAX_T2_DELAY;
+ pLVREV_Private->T[3] = LVREV_MAX_T3_DELAY;
+ pLVREV_Private->AB_Selection = 1; /* Select smoothing A to B */
+
+ /* Fast coefficient memory base address */
+ pLVREV_Private->pFastCoef =
+ (LVREV_FastCoef_st *)InstAlloc_AddMember(&FastCoef, sizeof(LVREV_FastCoef_st));
+ /* General purpose scratch */
+ pLVREV_Private->pScratch =
+ (LVM_FLOAT *)InstAlloc_AddMember(&Temporary, sizeof(LVM_FLOAT) * \
+ MaxBlockSize);
+ /* Mono->stereo input save for end mix */
+ pLVREV_Private->pInputSave =
+ (LVM_FLOAT *)InstAlloc_AddMember(&Temporary, 2 * sizeof(LVM_FLOAT) * \
+ MaxBlockSize);
+ LoadConst_Float(0, pLVREV_Private->pInputSave, (LVM_INT16)(MaxBlockSize * 2));
+
+ /*
+ * Save the instance parameters in the instance structure
+ */
+ pLVREV_Private->InstanceParams = *pInstanceParams;
+
+ /*
+ * Set the parameters to invalid
+ */
+ pLVREV_Private->CurrentParams.SampleRate = LVM_FS_INVALID;
+ pLVREV_Private->CurrentParams.OperatingMode = LVM_MODE_DUMMY;
+ pLVREV_Private->CurrentParams.SourceFormat = LVM_SOURCE_DUMMY;
+
+ pLVREV_Private->bControlPending = LVM_FALSE;
+ pLVREV_Private->bFirstControl = LVM_TRUE;
+ pLVREV_Private->bDisableReverb = LVM_FALSE;
+
+ /*
+ * Set mixer parameters
+ */
+ pLVREV_Private->BypassMixer.CallbackParam2 = 0;
+ pLVREV_Private->BypassMixer.pCallbackHandle2 = pLVREV_Private;
+ pLVREV_Private->BypassMixer.pGeneralPurpose2 = LVM_NULL;
+ pLVREV_Private->BypassMixer.pCallBack2 = BypassMixer_Callback;
+ pLVREV_Private->BypassMixer.CallbackSet2 = LVM_FALSE;
+ pLVREV_Private->BypassMixer.Current2 = 0;
+ pLVREV_Private->BypassMixer.Target2 = 0;
+ pLVREV_Private->BypassMixer.CallbackParam1 = 0;
+ pLVREV_Private->BypassMixer.pCallbackHandle1 = LVM_NULL;
+ pLVREV_Private->BypassMixer.pGeneralPurpose1 = LVM_NULL;
+ pLVREV_Private->BypassMixer.pCallBack1 = LVM_NULL;
+ pLVREV_Private->BypassMixer.CallbackSet1 = LVM_FALSE;
+ pLVREV_Private->BypassMixer.Current1 = 0x00000000;
+ pLVREV_Private->BypassMixer.Target1 = 0x00000000;
+
+ pLVREV_Private->RoomSizeInms = 100; // 100 msec
+
+ /*
+ * Set the output gain mixer parameters
+ */
+ pLVREV_Private->GainMixer.CallbackParam = 0;
+ pLVREV_Private->GainMixer.pCallbackHandle = LVM_NULL;
+ pLVREV_Private->GainMixer.pGeneralPurpose = LVM_NULL;
+ pLVREV_Private->GainMixer.pCallBack = LVM_NULL;
+ pLVREV_Private->GainMixer.CallbackSet = LVM_FALSE;
+ pLVREV_Private->GainMixer.Current = 0.03125f;//0x03ffffff;
+ pLVREV_Private->GainMixer.Target = 0.03125f;//0x03ffffff;
+
+ /*
+ * Set the All-Pass Filter mixers
+ */
+ for (i=0; i<4; i++)
+ {
+ pLVREV_Private->pOffsetA[i] = pLVREV_Private->pDelay_T[i];
+ pLVREV_Private->pOffsetB[i] = pLVREV_Private->pDelay_T[i];
+ /* Delay tap selection mixer */
+ pLVREV_Private->Mixer_APTaps[i].CallbackParam2 = 0;
+ pLVREV_Private->Mixer_APTaps[i].pCallbackHandle2 = LVM_NULL;
+ pLVREV_Private->Mixer_APTaps[i].pGeneralPurpose2 = LVM_NULL;
+ pLVREV_Private->Mixer_APTaps[i].pCallBack2 = LVM_NULL;
+ pLVREV_Private->Mixer_APTaps[i].CallbackSet2 = LVM_FALSE;
+ pLVREV_Private->Mixer_APTaps[i].Current2 = 0;
+ pLVREV_Private->Mixer_APTaps[i].Target2 = 0;
+ pLVREV_Private->Mixer_APTaps[i].CallbackParam1 = 0;
+ pLVREV_Private->Mixer_APTaps[i].pCallbackHandle1 = LVM_NULL;
+ pLVREV_Private->Mixer_APTaps[i].pGeneralPurpose1 = LVM_NULL;
+ pLVREV_Private->Mixer_APTaps[i].pCallBack1 = LVM_NULL;
+ pLVREV_Private->Mixer_APTaps[i].CallbackSet1 = LVM_FALSE;
+ pLVREV_Private->Mixer_APTaps[i].Current1 = 0;
+ pLVREV_Private->Mixer_APTaps[i].Target1 = 1;
+ /* Feedforward mixer */
+ pLVREV_Private->Mixer_SGFeedforward[i].CallbackParam = 0;
+ pLVREV_Private->Mixer_SGFeedforward[i].pCallbackHandle = LVM_NULL;
+ pLVREV_Private->Mixer_SGFeedforward[i].pGeneralPurpose = LVM_NULL;
+ pLVREV_Private->Mixer_SGFeedforward[i].pCallBack = LVM_NULL;
+ pLVREV_Private->Mixer_SGFeedforward[i].CallbackSet = LVM_FALSE;
+ pLVREV_Private->Mixer_SGFeedforward[i].Current = 0;
+ pLVREV_Private->Mixer_SGFeedforward[i].Target = 0;
+ /* Feedback mixer */
+ pLVREV_Private->Mixer_SGFeedback[i].CallbackParam = 0;
+ pLVREV_Private->Mixer_SGFeedback[i].pCallbackHandle = LVM_NULL;
+ pLVREV_Private->Mixer_SGFeedback[i].pGeneralPurpose = LVM_NULL;
+ pLVREV_Private->Mixer_SGFeedback[i].pCallBack = LVM_NULL;
+ pLVREV_Private->Mixer_SGFeedback[i].CallbackSet = LVM_FALSE;
+ pLVREV_Private->Mixer_SGFeedback[i].Current = 0;
+ pLVREV_Private->Mixer_SGFeedback[i].Target = 0;
+ /* Feedback gain mixer */
+ pLVREV_Private->FeedbackMixer[i].CallbackParam = 0;
+ pLVREV_Private->FeedbackMixer[i].pCallbackHandle = LVM_NULL;
+ pLVREV_Private->FeedbackMixer[i].pGeneralPurpose = LVM_NULL;
+ pLVREV_Private->FeedbackMixer[i].pCallBack = LVM_NULL;
+ pLVREV_Private->FeedbackMixer[i].CallbackSet = LVM_FALSE;
+ pLVREV_Private->FeedbackMixer[i].Current = 0;
+ pLVREV_Private->FeedbackMixer[i].Target = 0;
+ }
+ /* Delay tap index */
+ pLVREV_Private->A_DelaySize[0] = LVREV_MAX_AP0_DELAY;
+ pLVREV_Private->B_DelaySize[0] = LVREV_MAX_AP0_DELAY;
+ pLVREV_Private->A_DelaySize[1] = LVREV_MAX_AP1_DELAY;
+ pLVREV_Private->B_DelaySize[1] = LVREV_MAX_AP1_DELAY;
+ pLVREV_Private->A_DelaySize[2] = LVREV_MAX_AP2_DELAY;
+ pLVREV_Private->B_DelaySize[2] = LVREV_MAX_AP2_DELAY;
+ pLVREV_Private->A_DelaySize[3] = LVREV_MAX_AP3_DELAY;
+ pLVREV_Private->B_DelaySize[3] = LVREV_MAX_AP3_DELAY;
+
+ LVREV_ClearAudioBuffers(*phInstance);
+
+ return LVREV_SUCCESS;
+}
+
+/* End of file */
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_GetMemoryTable.c b/media/libeffects/lvm/lib/Reverb/src/LVREV_GetMemoryTable.c
deleted file mode 100644
index f6d446b..0000000
--- a/media/libeffects/lvm/lib/Reverb/src/LVREV_GetMemoryTable.c
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/****************************************************************************************/
-/* */
-/* Includes */
-/* */
-/****************************************************************************************/
-#include "LVREV_Private.h"
-#include "InstAlloc.h"
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVREV_GetMemoryTable */
-/* */
-/* DESCRIPTION: */
-/* This function is used for memory allocation and free. It can be called in */
-/* two ways: */
-/* */
-/* hInstance = NULL Returns the memory requirements */
-/* hInstance = Instance handle Returns the memory requirements and allocated */
-/* base addresses. */
-/* */
-/* When this function is called for memory allocation (hInstance=NULL) the memory */
-/* base address pointers are NULL on return. */
-/* */
-/* When the function is called for free (hInstance = Instance Handle) the memory */
-/* table returns the allocated memory and base addresses used during initialisation. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance Handle */
-/* pMemoryTable Pointer to an empty memory table */
-/* pInstanceParams Pointer to the instance parameters */
-/* */
-/* RETURNS: */
-/* LVREV_Success Succeeded */
-/* LVREV_NULLADDRESS When pMemoryTable is NULL */
-/* LVREV_NULLADDRESS When requesting memory requirements and pInstanceParams */
-/* is NULL */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVREV_Process function */
-/* */
-/****************************************************************************************/
-LVREV_ReturnStatus_en LVREV_GetMemoryTable(LVREV_Handle_t hInstance,
- LVREV_MemoryTable_st *pMemoryTable,
- LVREV_InstanceParams_st *pInstanceParams)
-{
-
- INST_ALLOC SlowData;
- INST_ALLOC FastData;
- INST_ALLOC FastCoef;
- INST_ALLOC Temporary;
- LVM_INT16 i;
- LVM_UINT16 MaxBlockSize;
-
-
- /*
- * Check for error conditions
- */
- /* Check for NULL pointer */
- if (pMemoryTable == LVM_NULL)
- {
- return(LVREV_NULLADDRESS);
- }
-
- /*
- * Check all instance parameters are in range
- */
- if (pInstanceParams != LVM_NULL)
- {
- /*
- * Call for memory allocation, so check the parameters
- */
- /* Check for a non-zero block size */
- if (pInstanceParams->MaxBlockSize == 0)
- {
- return LVREV_OUTOFRANGE;
- }
-
- /* Check for a valid number of delay lines */
- if ((pInstanceParams->NumDelays != LVREV_DELAYLINES_1) &&
- (pInstanceParams->NumDelays != LVREV_DELAYLINES_2) &&
- (pInstanceParams->NumDelays != LVREV_DELAYLINES_4))
- {
- return LVREV_OUTOFRANGE;
- }
- }
-
- /*
- * Initialise the InstAlloc instances
- */
- InstAlloc_Init(&SlowData, (void *)LVM_NULL);
- InstAlloc_Init(&FastData, (void *)LVM_NULL);
- InstAlloc_Init(&FastCoef, (void *)LVM_NULL);
- InstAlloc_Init(&Temporary, (void *)LVM_NULL);
-
-
- /*
- * Fill in the memory table
- */
- if (hInstance == LVM_NULL)
- {
- /*
- * Check for null pointers
- */
- if (pInstanceParams == LVM_NULL)
- {
- return(LVREV_NULLADDRESS);
- }
-
-
- /*
- * Select the maximum internal block size
- */
- if(pInstanceParams->NumDelays ==LVREV_DELAYLINES_4)
- {
- MaxBlockSize = LVREV_MAX_AP3_DELAY;
- }
- else if(pInstanceParams->NumDelays ==LVREV_DELAYLINES_2)
- {
- MaxBlockSize = LVREV_MAX_AP1_DELAY;
- }
- else
- {
- MaxBlockSize = LVREV_MAX_AP0_DELAY;
- }
-
- if(MaxBlockSize>pInstanceParams->MaxBlockSize)
- {
- MaxBlockSize=pInstanceParams->MaxBlockSize;
- }
-
-
- /*
- * Slow data memory
- */
- InstAlloc_AddMember(&SlowData, sizeof(LVREV_Instance_st));
- pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].Size = InstAlloc_GetTotal(&SlowData);
- pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].Type = LVM_PERSISTENT_SLOW_DATA;
- pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].pBaseAddress = LVM_NULL;
-
-
- /*
- * Persistent fast data memory
- */
- InstAlloc_AddMember(&FastData, sizeof(LVREV_FastData_st));
- if(pInstanceParams->NumDelays == LVREV_DELAYLINES_4)
- {
-#ifndef BUILD_FLOAT
- InstAlloc_AddMember(&FastData, LVREV_MAX_T3_DELAY * sizeof(LVM_INT32));
- InstAlloc_AddMember(&FastData, LVREV_MAX_T2_DELAY * sizeof(LVM_INT32));
- InstAlloc_AddMember(&FastData, LVREV_MAX_T1_DELAY * sizeof(LVM_INT32));
- InstAlloc_AddMember(&FastData, LVREV_MAX_T0_DELAY * sizeof(LVM_INT32));
-#else
- InstAlloc_AddMember(&FastData, LVREV_MAX_T3_DELAY * sizeof(LVM_FLOAT));
- InstAlloc_AddMember(&FastData, LVREV_MAX_T2_DELAY * sizeof(LVM_FLOAT));
- InstAlloc_AddMember(&FastData, LVREV_MAX_T1_DELAY * sizeof(LVM_FLOAT));
- InstAlloc_AddMember(&FastData, LVREV_MAX_T0_DELAY * sizeof(LVM_FLOAT));
-#endif
- }
-
- if(pInstanceParams->NumDelays == LVREV_DELAYLINES_2)
- {
-#ifndef BUILD_FLOAT
- InstAlloc_AddMember(&FastData, LVREV_MAX_T1_DELAY * sizeof(LVM_INT32));
- InstAlloc_AddMember(&FastData, LVREV_MAX_T0_DELAY * sizeof(LVM_INT32));
-#else
- InstAlloc_AddMember(&FastData, LVREV_MAX_T1_DELAY * sizeof(LVM_FLOAT));
- InstAlloc_AddMember(&FastData, LVREV_MAX_T0_DELAY * sizeof(LVM_FLOAT));
-#endif
- }
-
- if(pInstanceParams->NumDelays == LVREV_DELAYLINES_1)
- {
-#ifndef BUILD_FLOAT
- InstAlloc_AddMember(&FastData, LVREV_MAX_T0_DELAY * sizeof(LVM_INT32));
-#else
- InstAlloc_AddMember(&FastData, LVREV_MAX_T0_DELAY * sizeof(LVM_FLOAT));
-#endif
- }
-
- pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].Size = InstAlloc_GetTotal(&FastData);
- pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].Type = LVM_PERSISTENT_FAST_DATA;
- pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].pBaseAddress = LVM_NULL;
-
-
- /*
- * Persistent fast coefficient memory
- */
- InstAlloc_AddMember(&FastCoef, sizeof(LVREV_FastCoef_st));
- pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].Size = InstAlloc_GetTotal(&FastCoef);
- pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].Type = LVM_PERSISTENT_FAST_COEF;
- pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].pBaseAddress = LVM_NULL;
-
-
- /*
- * Temporary fast memory
- */
-#ifndef BUILD_FLOAT
- InstAlloc_AddMember(&Temporary, sizeof(LVM_INT32) * MaxBlockSize); /* General purpose scratch memory */
- InstAlloc_AddMember(&Temporary, 2*sizeof(LVM_INT32) * MaxBlockSize); /* Mono->stereo input saved for end mix */
-#else
- /* General purpose scratch memory */
- InstAlloc_AddMember(&Temporary, sizeof(LVM_FLOAT) * MaxBlockSize);
- /* Mono->stereo input saved for end mix */
- InstAlloc_AddMember(&Temporary, 2 * sizeof(LVM_FLOAT) * MaxBlockSize);
-#endif
- if(pInstanceParams->NumDelays == LVREV_DELAYLINES_4)
- {
- for(i=0; i<4; i++)
- {
-#ifndef BUILD_FLOAT
- InstAlloc_AddMember(&Temporary, sizeof(LVM_INT32) * MaxBlockSize); /* A Scratch buffer for each delay line */
-#else
- /* A Scratch buffer for each delay line */
- InstAlloc_AddMember(&Temporary, sizeof(LVM_FLOAT) * MaxBlockSize);
-#endif
- }
- }
-
- if(pInstanceParams->NumDelays == LVREV_DELAYLINES_2)
- {
- for(i=0; i<2; i++)
- {
-#ifndef BUILD_FLOAT
- InstAlloc_AddMember(&Temporary, sizeof(LVM_INT32) * MaxBlockSize); /* A Scratch buffer for each delay line */
-#else
- /* A Scratch buffer for each delay line */
- InstAlloc_AddMember(&Temporary, sizeof(LVM_FLOAT) * MaxBlockSize);
-#endif
- }
- }
-
- if(pInstanceParams->NumDelays == LVREV_DELAYLINES_1)
- {
- for(i=0; i<1; i++)
- {
-#ifndef BUILD_FLOAT
- InstAlloc_AddMember(&Temporary, sizeof(LVM_INT32) * MaxBlockSize); /* A Scratch buffer for each delay line */
-#else
- /* A Scratch buffer for each delay line */
- InstAlloc_AddMember(&Temporary, sizeof(LVM_FLOAT) * MaxBlockSize);
-#endif
- }
- }
-
- pMemoryTable->Region[LVM_TEMPORARY_FAST].Size = InstAlloc_GetTotal(&Temporary);
- pMemoryTable->Region[LVM_TEMPORARY_FAST].Type = LVM_TEMPORARY_FAST;
- pMemoryTable->Region[LVM_TEMPORARY_FAST].pBaseAddress = LVM_NULL;
-
- }
- else
- {
- LVREV_Instance_st *pLVREV_Private = (LVREV_Instance_st *)hInstance;
-
-
- /*
- * Read back memory allocation table
- */
- *pMemoryTable = pLVREV_Private->MemoryTable;
- }
-
-
- return(LVREV_SUCCESS);
-}
-
-/* End of file */
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_GetMemoryTable.cpp b/media/libeffects/lvm/lib/Reverb/src/LVREV_GetMemoryTable.cpp
new file mode 100644
index 0000000..f59933c
--- /dev/null
+++ b/media/libeffects/lvm/lib/Reverb/src/LVREV_GetMemoryTable.cpp
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/****************************************************************************************/
+/* */
+/* Includes */
+/* */
+/****************************************************************************************/
+#include "LVREV_Private.h"
+#include "InstAlloc.h"
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVREV_GetMemoryTable */
+/* */
+/* DESCRIPTION: */
+/* This function is used for memory allocation and free. It can be called in */
+/* two ways: */
+/* */
+/* hInstance = NULL Returns the memory requirements */
+/* hInstance = Instance handle Returns the memory requirements and allocated */
+/* base addresses. */
+/* */
+/* When this function is called for memory allocation (hInstance=NULL) the memory */
+/* base address pointers are NULL on return. */
+/* */
+/* When the function is called for free (hInstance = Instance Handle) the memory */
+/* table returns the allocated memory and base addresses used during initialisation. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance Handle */
+/* pMemoryTable Pointer to an empty memory table */
+/* pInstanceParams Pointer to the instance parameters */
+/* */
+/* RETURNS: */
+/* LVREV_Success Succeeded */
+/* LVREV_NULLADDRESS When pMemoryTable is NULL */
+/* LVREV_NULLADDRESS When requesting memory requirements and pInstanceParams */
+/* is NULL */
+/* */
+/* NOTES: */
+/* 1. This function may be interrupted by the LVREV_Process function */
+/* */
+/****************************************************************************************/
+LVREV_ReturnStatus_en LVREV_GetMemoryTable(LVREV_Handle_t hInstance,
+ LVREV_MemoryTable_st *pMemoryTable,
+ LVREV_InstanceParams_st *pInstanceParams)
+{
+
+ INST_ALLOC SlowData;
+ INST_ALLOC FastData;
+ INST_ALLOC FastCoef;
+ INST_ALLOC Temporary;
+ LVM_INT16 i;
+ LVM_UINT16 MaxBlockSize;
+
+ /*
+ * Check for error conditions
+ */
+ /* Check for NULL pointer */
+ if (pMemoryTable == LVM_NULL)
+ {
+ return(LVREV_NULLADDRESS);
+ }
+
+ /*
+ * Check all instance parameters are in range
+ */
+ if (pInstanceParams != LVM_NULL)
+ {
+ /*
+ * Call for memory allocation, so check the parameters
+ */
+ /* Check for a non-zero block size */
+ if (pInstanceParams->MaxBlockSize == 0)
+ {
+ return LVREV_OUTOFRANGE;
+ }
+
+ /* Check for a valid number of delay lines */
+ if ((pInstanceParams->NumDelays != LVREV_DELAYLINES_1) &&
+ (pInstanceParams->NumDelays != LVREV_DELAYLINES_2) &&
+ (pInstanceParams->NumDelays != LVREV_DELAYLINES_4))
+ {
+ return LVREV_OUTOFRANGE;
+ }
+ }
+
+ /*
+ * Initialise the InstAlloc instances
+ */
+ InstAlloc_Init(&SlowData, (void *)LVM_NULL);
+ InstAlloc_Init(&FastData, (void *)LVM_NULL);
+ InstAlloc_Init(&FastCoef, (void *)LVM_NULL);
+ InstAlloc_Init(&Temporary, (void *)LVM_NULL);
+
+ /*
+ * Fill in the memory table
+ */
+ if (hInstance == LVM_NULL)
+ {
+ /*
+ * Check for null pointers
+ */
+ if (pInstanceParams == LVM_NULL)
+ {
+ return(LVREV_NULLADDRESS);
+ }
+
+ /*
+ * Select the maximum internal block size
+ */
+ if(pInstanceParams->NumDelays ==LVREV_DELAYLINES_4)
+ {
+ MaxBlockSize = LVREV_MAX_AP3_DELAY;
+ }
+ else if(pInstanceParams->NumDelays ==LVREV_DELAYLINES_2)
+ {
+ MaxBlockSize = LVREV_MAX_AP1_DELAY;
+ }
+ else
+ {
+ MaxBlockSize = LVREV_MAX_AP0_DELAY;
+ }
+
+ if(MaxBlockSize>pInstanceParams->MaxBlockSize)
+ {
+ MaxBlockSize=pInstanceParams->MaxBlockSize;
+ }
+
+ /*
+ * Slow data memory
+ */
+ InstAlloc_AddMember(&SlowData, sizeof(LVREV_Instance_st));
+ pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].Size = InstAlloc_GetTotal(&SlowData);
+ pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].Type = LVM_PERSISTENT_SLOW_DATA;
+ pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].pBaseAddress = LVM_NULL;
+
+ /*
+ * Persistent fast data memory
+ */
+ InstAlloc_AddMember(&FastData, sizeof(LVREV_FastData_st));
+ if(pInstanceParams->NumDelays == LVREV_DELAYLINES_4)
+ {
+ InstAlloc_AddMember(&FastData, LVREV_MAX_T3_DELAY * sizeof(LVM_FLOAT));
+ InstAlloc_AddMember(&FastData, LVREV_MAX_T2_DELAY * sizeof(LVM_FLOAT));
+ InstAlloc_AddMember(&FastData, LVREV_MAX_T1_DELAY * sizeof(LVM_FLOAT));
+ InstAlloc_AddMember(&FastData, LVREV_MAX_T0_DELAY * sizeof(LVM_FLOAT));
+ }
+
+ if(pInstanceParams->NumDelays == LVREV_DELAYLINES_2)
+ {
+ InstAlloc_AddMember(&FastData, LVREV_MAX_T1_DELAY * sizeof(LVM_FLOAT));
+ InstAlloc_AddMember(&FastData, LVREV_MAX_T0_DELAY * sizeof(LVM_FLOAT));
+ }
+
+ if(pInstanceParams->NumDelays == LVREV_DELAYLINES_1)
+ {
+ InstAlloc_AddMember(&FastData, LVREV_MAX_T0_DELAY * sizeof(LVM_FLOAT));
+ }
+
+ pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].Size = InstAlloc_GetTotal(&FastData);
+ pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].Type = LVM_PERSISTENT_FAST_DATA;
+ pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].pBaseAddress = LVM_NULL;
+
+ /*
+ * Persistent fast coefficient memory
+ */
+ InstAlloc_AddMember(&FastCoef, sizeof(LVREV_FastCoef_st));
+ pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].Size = InstAlloc_GetTotal(&FastCoef);
+ pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].Type = LVM_PERSISTENT_FAST_COEF;
+ pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].pBaseAddress = LVM_NULL;
+
+ /*
+ * Temporary fast memory
+ */
+ /* General purpose scratch memory */
+ InstAlloc_AddMember(&Temporary, sizeof(LVM_FLOAT) * MaxBlockSize);
+ /* Mono->stereo input saved for end mix */
+ InstAlloc_AddMember(&Temporary, 2 * sizeof(LVM_FLOAT) * MaxBlockSize);
+ if(pInstanceParams->NumDelays == LVREV_DELAYLINES_4)
+ {
+ for(i=0; i<4; i++)
+ {
+ /* A Scratch buffer for each delay line */
+ InstAlloc_AddMember(&Temporary, sizeof(LVM_FLOAT) * MaxBlockSize);
+ }
+ }
+
+ if(pInstanceParams->NumDelays == LVREV_DELAYLINES_2)
+ {
+ for(i=0; i<2; i++)
+ {
+ /* A Scratch buffer for each delay line */
+ InstAlloc_AddMember(&Temporary, sizeof(LVM_FLOAT) * MaxBlockSize);
+ }
+ }
+
+ if(pInstanceParams->NumDelays == LVREV_DELAYLINES_1)
+ {
+ for(i=0; i<1; i++)
+ {
+ /* A Scratch buffer for each delay line */
+ InstAlloc_AddMember(&Temporary, sizeof(LVM_FLOAT) * MaxBlockSize);
+ }
+ }
+
+ pMemoryTable->Region[LVM_TEMPORARY_FAST].Size = InstAlloc_GetTotal(&Temporary);
+ pMemoryTable->Region[LVM_TEMPORARY_FAST].Type = LVM_TEMPORARY_FAST;
+ pMemoryTable->Region[LVM_TEMPORARY_FAST].pBaseAddress = LVM_NULL;
+
+ }
+ else
+ {
+ LVREV_Instance_st *pLVREV_Private = (LVREV_Instance_st *)hInstance;
+
+ /*
+ * Read back memory allocation table
+ */
+ *pMemoryTable = pLVREV_Private->MemoryTable;
+ }
+
+ return(LVREV_SUCCESS);
+}
+
+/* End of file */
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_Private.h b/media/libeffects/lvm/lib/Reverb/src/LVREV_Private.h
index c915ac0..2c27c6e 100644
--- a/media/libeffects/lvm/lib/Reverb/src/LVREV_Private.h
+++ b/media/libeffects/lvm/lib/Reverb/src/LVREV_Private.h
@@ -18,11 +18,6 @@
#ifndef __LVREV_PRIVATE_H__
#define __LVREV_PRIVATE_H__
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
/****************************************************************************************/
/* */
/* Includes */
@@ -36,43 +31,22 @@
#include "Mixer.h"
#include "LVM_Macros.h"
-
/****************************************************************************************/
/* */
/* Defines */
/* */
/****************************************************************************************/
-#ifndef BUILD_FLOAT
-/* General */
-#define ONE_OVER_SQRT_TWO 23170 /* 1/sqrt(2) * 2^15 */
-#define LVREV_B_8_on_1000 17179869 /* 0.8 * 2^31 */
-#define LVREV_HEADROOM 8192 /* -12dB * 2^15 */
-#define LVREV_2_9_INQ29 1583769190L /* 2.9 in Q29 format */
-#define LVREV_MIN3DB 0x5A82 /* -3dB in Q15 format */
-#else
/* General */
#define ONE_OVER_SQRT_TWO 0.707107f /* 1/sqrt(2) * 2^15 */
#define LVREV_B_8_on_1000 0.008f /* 0.8 * 2^31 */
#define LVREV_HEADROOM 0.25f /* -12dB * 2^15 */
#define LVREV_2_9_INQ29 2.9f /* 2.9 in Q29 format */
#define LVREV_MIN3DB 0.7079457f /* -3dB in Q15 format */
-#endif
/* Intenal constants */
#define LVREV_LP_Poly_Order 4
#define LVREV_LP_Poly_Shift 5
-#ifndef BUILD_FLOAT
-#define LVREV_T_3_Power_0_on_4 32768
-#define LVREV_T_3_Power_1_on_4 43125
-#define LVREV_T_3_Power_2_on_4 56755
-#define LVREV_T_3_Power_3_on_4 74694
-#define LVREV_T60_SCALE 306774 /*(32767/7000)<<16 */
-#define LVREV_T_3_Power_minus0_on_4 32767 /* 3^(-0/4) * 2^15 */
-#define LVREV_T_3_Power_minus1_on_4 24898 /* 3^(-1/4) * 2^15 */
-#define LVREV_T_3_Power_minus2_on_4 18919 /* 3^(-2/4) * 2^15 */
-#define LVREV_T_3_Power_minus3_on_4 14375 /* 3^(-3/4) * 2^15 */
-#else/*BUILD_FLOAT*/
#define LVREV_T60_SCALE 0.000142f /*(1/7000) */
#define LVREV_T_3_Power_0_on_4 1.0f
@@ -83,18 +57,7 @@
#define LVREV_T_3_Power_minus1_on_4 0.759836f /* 3^(-1/4) * 2^15 */
#define LVREV_T_3_Power_minus2_on_4 0.577350f /* 3^(-2/4) * 2^15 */
#define LVREV_T_3_Power_minus3_on_4 0.438691f /* 3^(-3/4) * 2^15 */
-#endif
-#ifndef HIGHER_FS
-#define LVREV_MAX_T3_DELAY 2527 /* ((48000 * 120 * LVREV_T_3_Power_minus3_on_4) >> 15) / 1000 */
-#define LVREV_MAX_T2_DELAY 3326 /* ((48000 * 120 * LVREV_T_3_Power_minus2_on_4) >> 15) / 1000 */
-#define LVREV_MAX_T1_DELAY 4377 /* ((48000 * 120 * LVREV_T_3_Power_minus1_on_4) >> 15) / 1000 */
-#define LVREV_MAX_T0_DELAY 5760 /* ((48000 * 120 * LVREV_T_3_Power_minus0_on_4) >> 15) / 1000 */
-#define LVREV_MAX_AP3_DELAY 1685 /* ((48000 * 120 * LVREV_T_3_Power_minus3_on_4) >> 15) / 1500 */
-#define LVREV_MAX_AP2_DELAY 2218 /* ((48000 * 120 * LVREV_T_3_Power_minus2_on_4) >> 15) / 1500 */
-#define LVREV_MAX_AP1_DELAY 2918 /* ((48000 * 120 * LVREV_T_3_Power_minus1_on_4) >> 15) / 1500 */
-#define LVREV_MAX_AP0_DELAY 3840 /* ((48000 * 120 * LVREV_T_3_Power_minus0_on_4) >> 15) / 1500 */
-#else
/* ((192000 * 120 * LVREV_T_3_Power_minus3_on_4) >> 15) / 1000 */
#define LVREV_MAX_T3_DELAY 10108
/* ((192000 * 120 * LVREV_T_3_Power_minus2_on_4) >> 15) / 1000 */
@@ -111,7 +74,6 @@
#define LVREV_MAX_AP1_DELAY 11672
/* ((192000 * 120 * LVREV_T_3_Power_minus0_on_4) >> 15) / 1500 */
#define LVREV_MAX_AP0_DELAY 15360
-#endif
#define LVREV_BYPASSMIXER_TC 1000 /* Bypass mixer time constant*/
#define LVREV_ALLPASS_TC 1000 /* All-pass filter time constant */
@@ -120,11 +82,7 @@
#define LVREV_OUTPUTGAIN_SHIFT 5 /* Bits shift for output gain correction */
/* Parameter limits */
-#ifndef HIGHER_FS
-#define LVREV_NUM_FS 9 /* Number of supported sample rates */
-#else
#define LVREV_NUM_FS 13 /* Number of supported sample rates */
-#endif
#define LVREV_MAXBLKSIZE_LIMIT 64 /* Maximum block size low limit */
#define LVREV_MAX_LEVEL 100 /* Maximum level, 100% */
@@ -137,81 +95,11 @@
#define LVREV_MAX_DAMPING 100 /* Maximum damping, 100% */
#define LVREV_MAX_ROOMSIZE 100 /* Maximum room size, 100% */
-
-
/****************************************************************************************/
/* */
/* Structures */
/* */
/****************************************************************************************/
-#ifndef BUILD_FLOAT
-/* Fast data structure */
-typedef struct
-{
-
- Biquad_1I_Order1_Taps_t HPTaps; /* High pass filter taps */
- Biquad_1I_Order1_Taps_t LPTaps; /* Low pass filter taps */
- Biquad_1I_Order1_Taps_t RevLPTaps[4]; /* Reverb low pass filters taps */
-
-} LVREV_FastData_st;
-
-
-/* Fast coefficient structure */
-typedef struct
-{
-
- Biquad_Instance_t HPCoefs; /* High pass filter coefficients */
- Biquad_Instance_t LPCoefs; /* Low pass filter coefficients */
- Biquad_Instance_t RevLPCoefs[4]; /* Reverb low pass filters coefficients */
-
-} LVREV_FastCoef_st;
-
-
-/* Instance parameter structure */
-typedef struct
-{
- /* General */
- LVREV_InstanceParams_st InstanceParams; /* Initialisation time instance parameters */
- LVREV_MemoryTable_st MemoryTable; /* Memory table */
- LVREV_ControlParams_st CurrentParams; /* Parameters being used */
- LVREV_ControlParams_st NewParams; /* New parameters from the calling application */
- LVM_CHAR bControlPending; /* Flag to indicate new parameters are available */
- LVM_CHAR bFirstControl; /* Flag to indicate that the control function is called for the first time */
- LVM_CHAR bDisableReverb; /* Flag to indicate that the mix level is 0% and the reverb can be disabled */
- LVM_INT32 RoomSizeInms; /* Room size in msec */
- LVM_INT32 MaxBlkLen; /* Maximum block size for internal processing */
-
- /* Aligned memory pointers */
- LVREV_FastData_st *pFastData; /* Fast data memory base address */
- LVREV_FastCoef_st *pFastCoef; /* Fast coefficient memory base address */
- LVM_INT32 *pScratchDelayLine[4]; /* Delay line scratch memory */
- LVM_INT32 *pScratch; /* Multi ussge scratch */
- LVM_INT32 *pInputSave; /* Reverb block input save for dry/wet mixing*/
-
- /* Feedback matrix */
- Mix_1St_Cll_t FeedbackMixer[4]; /* Mixer for Pop and Click Supression caused by feedback Gain */
-
- /* All-Pass Filter */
- LVM_INT32 T[4]; /* Maximum delay size of buffer */
- LVM_INT32 *pDelay_T[4]; /* Pointer to delay buffers */
- LVM_INT32 Delay_AP[4]; /* Offset to AP delay buffer start */
- LVM_INT16 AB_Selection; /* Smooth from tap A to B when 1 otherwise B to A */
- LVM_INT32 A_DelaySize[4]; /* A delay length in samples */
- LVM_INT32 B_DelaySize[4]; /* B delay length in samples */
- LVM_INT32 *pOffsetA[4]; /* Offset for the A delay tap */
- LVM_INT32 *pOffsetB[4]; /* Offset for the B delay tap */
- Mix_2St_Cll_t Mixer_APTaps[4]; /* Smoothed AP delay mixer */
- Mix_1St_Cll_t Mixer_SGFeedback[4]; /* Smoothed SAfeedback gain */
- Mix_1St_Cll_t Mixer_SGFeedforward[4]; /* Smoothed AP feedforward gain */
-
- /* Output gain */
- Mix_2St_Cll_t BypassMixer; /* Dry/wet mixer */
- LVM_INT16 Gain; /* Gain applied to output to maintain average signal power */
- Mix_1St_Cll_t GainMixer; /* Gain smoothing */
-
-} LVREV_Instance_st;
-
-#else /* BUILD_FLOAT */
/* Fast data structure */
typedef struct
@@ -222,7 +110,6 @@
} LVREV_FastData_st;
-
/* Fast coefficient structure */
typedef struct
{
@@ -262,7 +149,6 @@
Mix_1St_Cll_FLOAT_t FeedbackMixer[4]; /* Mixer for Pop and Click Supression \
caused by feedback Gain */
-
/* All-Pass Filter */
LVM_INT32 T[4]; /* Maximum delay size of buffer */
LVM_FLOAT *pDelay_T[4]; /* Pointer to delay buffers */
@@ -285,7 +171,6 @@
} LVREV_Instance_st;
-#endif
/****************************************************************************************/
/* */
/* Function prototypes */
@@ -293,26 +178,14 @@
/****************************************************************************************/
LVREV_ReturnStatus_en LVREV_ApplyNewSettings(LVREV_Instance_st *pPrivate);
-#ifdef BUILD_FLOAT
void ReverbBlock(LVM_FLOAT *pInput,
LVM_FLOAT *pOutput,
LVREV_Instance_st *pPrivate,
LVM_UINT16 NumSamples);
-#else
-void ReverbBlock(LVM_INT32 *pInput,
- LVM_INT32 *pOutput,
- LVREV_Instance_st *pPrivate,
- LVM_UINT16 NumSamples);
-#endif
LVM_INT32 BypassMixer_Callback(void *pCallbackData,
void *pGeneralPurpose,
LVM_INT16 GeneralPurpose );
-
-#ifdef __cplusplus
-}
-#endif
-
#endif /** __LVREV_PRIVATE_H__ **/
/* End of file */
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_Process.c b/media/libeffects/lvm/lib/Reverb/src/LVREV_Process.c
deleted file mode 100644
index 1d1283e..0000000
--- a/media/libeffects/lvm/lib/Reverb/src/LVREV_Process.c
+++ /dev/null
@@ -1,825 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/****************************************************************************************/
-/* */
-/* Includes */
-/* */
-/****************************************************************************************/
-#include "LVREV_Private.h"
-#include "VectorArithmetic.h"
-
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVREV_Process */
-/* */
-/* DESCRIPTION: */
-/* Process function for the LVREV module. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance handle */
-/* pInData Pointer to the input data */
-/* pOutData Pointer to the output data */
-/* NumSamples Number of samples in the input buffer */
-/* */
-/* RETURNS: */
-/* LVREV_Success Succeeded */
-/* LVREV_INVALIDNUMSAMPLES NumSamples was larger than the maximum block size */
-/* LVREV_NULLADDRESS When one of hInstance, pInData or pOutData is NULL */
-/* */
-/* NOTES: */
-/* 1. The input and output buffers must be 32-bit aligned */
-/* */
-/****************************************************************************************/
-#ifdef BUILD_FLOAT
-LVREV_ReturnStatus_en LVREV_Process(LVREV_Handle_t hInstance,
- const LVM_FLOAT *pInData,
- LVM_FLOAT *pOutData,
- const LVM_UINT16 NumSamples)
-#else
-LVREV_ReturnStatus_en LVREV_Process(LVREV_Handle_t hInstance,
- const LVM_INT32 *pInData,
- LVM_INT32 *pOutData,
- const LVM_UINT16 NumSamples)
-#endif
-{
- LVREV_Instance_st *pLVREV_Private = (LVREV_Instance_st *)hInstance;
-#ifdef BUILD_FLOAT
- LVM_FLOAT *pInput = (LVM_FLOAT *)pInData;
- LVM_FLOAT *pOutput = pOutData;
-#else
- LVM_INT32 *pInput = (LVM_INT32 *)pInData;
- LVM_INT32 *pOutput = pOutData;
-#endif
- LVM_INT32 SamplesToProcess, RemainingSamples;
- LVM_INT32 format = 1;
-
- /*
- * Check for error conditions
- */
-
- /* Check for NULL pointers */
- if((hInstance == LVM_NULL) || (pInData == LVM_NULL) || (pOutData == LVM_NULL))
- {
- return LVREV_NULLADDRESS;
- }
-
- /*
- * Apply the new controls settings if required
- */
- if(pLVREV_Private->bControlPending == LVM_TRUE)
- {
- LVREV_ReturnStatus_en errorCode;
-
- /*
- * Clear the pending flag and update the control settings
- */
- pLVREV_Private->bControlPending = LVM_FALSE;
-
- errorCode = LVREV_ApplyNewSettings (pLVREV_Private);
-
- if(errorCode != LVREV_SUCCESS)
- {
- return errorCode;
- }
- }
-
- /*
- * Trap the case where the number of samples is zero.
- */
- if (NumSamples == 0)
- {
- return LVREV_SUCCESS;
- }
-
- /*
- * If OFF copy and reformat the data as necessary
- */
- if (pLVREV_Private->CurrentParams.OperatingMode == LVM_MODE_OFF)
- {
- if(pInput != pOutput)
- {
- /*
- * Copy the data to the output buffer, convert to stereo is required
- */
-#ifndef BUILD_FLOAT
- if(pLVREV_Private->CurrentParams.SourceFormat == LVM_MONO){
- MonoTo2I_32(pInput, pOutput, NumSamples);
- } else {
- Copy_16((LVM_INT16 *)pInput,
- (LVM_INT16 *)pOutput,
- (LVM_INT16)(NumSamples << 2)); // 32 bit data, stereo
- }
-#else
- if(pLVREV_Private->CurrentParams.SourceFormat == LVM_MONO){
- MonoTo2I_Float(pInput, pOutput, NumSamples);
- } else {
- Copy_Float(pInput,
- pOutput,
- (LVM_INT16)(NumSamples << 1)); // 32 bit data, stereo
- }
-#endif
- }
-
- return LVREV_SUCCESS;
- }
-
- RemainingSamples = (LVM_INT32)NumSamples;
-
- if (pLVREV_Private->CurrentParams.SourceFormat != LVM_MONO)
- {
- format = 2;
- }
-
- while (RemainingSamples!=0)
- {
- /*
- * Process the data
- */
-
- if(RemainingSamples > pLVREV_Private->MaxBlkLen)
- {
- SamplesToProcess = pLVREV_Private->MaxBlkLen;
- RemainingSamples = (LVM_INT16)(RemainingSamples - SamplesToProcess);
- }
- else
- {
- SamplesToProcess = RemainingSamples;
- RemainingSamples = 0;
- }
-
- ReverbBlock(pInput, pOutput, pLVREV_Private, (LVM_UINT16)SamplesToProcess);
-#ifdef BUILD_FLOAT
- pInput = (LVM_FLOAT *)(pInput + (SamplesToProcess * format));
- pOutput = (LVM_FLOAT *)(pOutput + (SamplesToProcess * 2)); // Always stereo output
-#else
- pInput = (LVM_INT32 *)(pInput +(SamplesToProcess*format));
- pOutput = (LVM_INT32 *)(pOutput+(SamplesToProcess*2));
-#endif
- }
-
- return LVREV_SUCCESS;
-}
-
-
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: ReverbBlock */
-/* */
-/* DESCRIPTION: */
-/* Process function for the LVREV module. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance handle */
-/* pInData Pointer to the input data */
-/* pOutData Pointer to the output data */
-/* NumSamples Number of samples in the input buffer */
-/* */
-/* RETURNS: */
-/* LVREV_Success Succeeded */
-/* LVREV_INVALIDNUMSAMPLES NumSamples was larger than the maximum block size */
-/* LVREV_NULLADDRESS When one of hInstance, pInData or pOutData is NULL */
-/* */
-/* NOTES: */
-/* 1. The input and output buffers must be 32-bit aligned */
-/* */
-/****************************************************************************************/
-#ifndef BUILD_FLOAT
-void ReverbBlock(LVM_INT32 *pInput, LVM_INT32 *pOutput, LVREV_Instance_st *pPrivate, LVM_UINT16 NumSamples)
-{
- LVM_INT16 j, size;
- LVM_INT32 *pDelayLine;
- LVM_INT32 *pDelayLineInput = pPrivate->pScratch;
- LVM_INT32 *pScratch = pPrivate->pScratch;
- LVM_INT32 *pIn;
- LVM_INT32 *pTemp = pPrivate->pInputSave;
- LVM_INT32 NumberOfDelayLines;
-
- /******************************************************************************
- * All calculations will go into the buffer pointed to by pTemp, this will *
- * then be mixed with the original input to create the final output. *
- * *
- * When INPLACE processing is selected this must be a temporary buffer and *
- * hence this is the worst case, so for simplicity this will ALWAYS be so *
- * *
- * The input buffer will remain untouched until the output of the mixer if *
- * INPLACE processing is selected. *
- * *
- * The temp buffer will always be NumSamples in size regardless of MONO or *
- * STEREO input. In the case of stereo input all processing is done in MONO *
- * and the final output is converted to STEREO after the mixer *
- ******************************************************************************/
-
- if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_4 )
- {
- NumberOfDelayLines = 4;
- }
- else if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_2 )
- {
- NumberOfDelayLines = 2;
- }
- else
- {
- NumberOfDelayLines = 1;
- }
-
- if(pPrivate->CurrentParams.SourceFormat == LVM_MONO)
- {
- pIn = pInput;
- }
- else
- {
- /*
- * Stereo to mono conversion
- */
-
- From2iToMono_32( pInput,
- pTemp,
- (LVM_INT16)NumSamples);
-
- pIn = pTemp;
- }
-
- Mult3s_32x16(pIn,
- (LVM_INT16)LVREV_HEADROOM,
- pTemp,
- (LVM_INT16)NumSamples);
-
- /*
- * High pass filter
- */
- FO_1I_D32F32C31_TRC_WRA_01( &pPrivate->pFastCoef->HPCoefs,
- pTemp,
- pTemp,
- (LVM_INT16)NumSamples);
- /*
- * Low pass filter
- */
- FO_1I_D32F32C31_TRC_WRA_01( &pPrivate->pFastCoef->LPCoefs,
- pTemp,
- pTemp,
- (LVM_INT16)NumSamples);
-
- /*
- * Process all delay lines
- */
-
- for(j = 0; j < NumberOfDelayLines; j++)
- {
- pDelayLine = pPrivate->pScratchDelayLine[j];
-
- /*
- * All-pass filter with pop and click suppression
- */
- /* Get the smoothed, delayed output. Put it in the output buffer */
- MixSoft_2St_D32C31_SAT(&pPrivate->Mixer_APTaps[j],
- pPrivate->pOffsetA[j],
- pPrivate->pOffsetB[j],
- pDelayLine,
- (LVM_INT16)NumSamples);
- /* Re-align the all pass filter delay buffer and copying the fixed delay data to the AP delay in the process */
- Copy_16((LVM_INT16 *)&pPrivate->pDelay_T[j][NumSamples],
- (LVM_INT16 *)pPrivate->pDelay_T[j],
- (LVM_INT16)((pPrivate->T[j]-NumSamples) << 1)); /* 32-bit data */
- /* Apply the smoothed feedback and save to fixed delay input (currently empty) */
- MixSoft_1St_D32C31_WRA(&pPrivate->Mixer_SGFeedback[j],
- pDelayLine,
- &pPrivate->pDelay_T[j][pPrivate->T[j]-NumSamples],
- (LVM_INT16)NumSamples);
- /* Sum into the AP delay line */
- Mac3s_Sat_32x16(&pPrivate->pDelay_T[j][pPrivate->T[j]-NumSamples],
- -0x7fff, /* Invert since the feedback coefficient is negative */
- &pPrivate->pDelay_T[j][pPrivate->Delay_AP[j]-NumSamples],
- (LVM_INT16)NumSamples);
- /* Apply smoothed feedforward sand save to fixed delay input (currently empty) */
- MixSoft_1St_D32C31_WRA(&pPrivate->Mixer_SGFeedforward[j],
- &pPrivate->pDelay_T[j][pPrivate->Delay_AP[j]-NumSamples],
- &pPrivate->pDelay_T[j][pPrivate->T[j]-NumSamples],
- (LVM_INT16)NumSamples);
- /* Sum into the AP output */
- Mac3s_Sat_32x16(&pPrivate->pDelay_T[j][pPrivate->T[j]-NumSamples],
- 0x7fff,
- pDelayLine,
- (LVM_INT16)NumSamples);
-
- /*
- * Feedback gain
- */
- MixSoft_1St_D32C31_WRA(&pPrivate->FeedbackMixer[j], pDelayLine, pDelayLine, NumSamples);
-
- /*
- * Low pass filter
- */
- FO_1I_D32F32C31_TRC_WRA_01( &pPrivate->pFastCoef->RevLPCoefs[j],
- pDelayLine,
- pDelayLine,
- (LVM_INT16)NumSamples);
- }
-
- /*
- * Apply rotation matrix and delay samples
- */
- for(j = 0; j < NumberOfDelayLines; j++)
- {
-
- Copy_16( (LVM_INT16*)(pTemp),
- (LVM_INT16*)(pDelayLineInput),
- (LVM_INT16)(NumSamples << 1));
-
- /*
- * Rotation matrix mix
- */
- switch(j)
- {
- case 3:
- /*
- * Add delay line 1 and 2 contribution
- */
- Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[1], -0x8000, pDelayLineInput, (LVM_INT16)NumSamples);
- Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[2], -0x8000, pDelayLineInput, (LVM_INT16)NumSamples);
-
- break;
- case 2:
-
- /*
- * Add delay line 0 and 3 contribution
- */
- Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[0], -0x8000, pDelayLineInput, (LVM_INT16)NumSamples);
- Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[3], -0x8000, pDelayLineInput, (LVM_INT16)NumSamples);
-
- break;
- case 1:
- if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_4)
- {
- /*
- * Add delay line 0 and 3 contribution
- */
- Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[0], -0x8000, pDelayLineInput, (LVM_INT16)NumSamples);
- Add2_Sat_32x32(pPrivate->pScratchDelayLine[3], pDelayLineInput, (LVM_INT16)NumSamples);
-
- }
- else
- {
- /*
- * Add delay line 0 and 1 contribution
- */
- Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[0], -0x8000, pDelayLineInput, (LVM_INT16)NumSamples);
- Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[1], -0x8000, pDelayLineInput, (LVM_INT16)NumSamples);
-
- }
- break;
- case 0:
- if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_4)
- {
- /*
- * Add delay line 1 and 2 contribution
- */
- Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[1], -0x8000, pDelayLineInput, (LVM_INT16)NumSamples);
- Add2_Sat_32x32(pPrivate->pScratchDelayLine[2], pDelayLineInput, (LVM_INT16)NumSamples);
-
- }
- else if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_2)
- {
- /*
- * Add delay line 0 and 1 contribution
- */
- Add2_Sat_32x32(pPrivate->pScratchDelayLine[0], pDelayLineInput, (LVM_INT16)NumSamples);
- Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[1], -0x8000, pDelayLineInput, (LVM_INT16)NumSamples);
-
- }
- else
- {
- /*
- * Add delay line 0 contribution
- */
-
- /* SOURCE DESTINATION*/
- Add2_Sat_32x32(pPrivate->pScratchDelayLine[0], pDelayLineInput, (LVM_INT16)NumSamples);
- }
- break;
- default:
- break;
- }
-
- /*
- * Delay samples
- */
- Copy_16((LVM_INT16 *)pDelayLineInput,
- (LVM_INT16 *)&pPrivate->pDelay_T[j][pPrivate->T[j]-NumSamples],
- (LVM_INT16)(NumSamples << 1)); /* 32-bit data */
-
- }
-
-
- /*
- * Create stereo output
- */
- switch(pPrivate->InstanceParams.NumDelays)
- {
- case LVREV_DELAYLINES_4:
- Add2_Sat_32x32(pPrivate->pScratchDelayLine[3],
- pPrivate->pScratchDelayLine[0],
- (LVM_INT16)NumSamples);
- Add2_Sat_32x32(pPrivate->pScratchDelayLine[2],
- pPrivate->pScratchDelayLine[1],
- (LVM_INT16)NumSamples);
-
-
- JoinTo2i_32x32(pPrivate->pScratchDelayLine[0],
- pPrivate->pScratchDelayLine[1],
- pTemp,
- (LVM_INT16)NumSamples);
-
-
- break;
- case LVREV_DELAYLINES_2:
-
- Copy_16( (LVM_INT16*)pPrivate->pScratchDelayLine[1],
- (LVM_INT16*)pScratch,
- (LVM_INT16)(NumSamples << 1));
-
- Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[0],
- -0x8000,
- pScratch,
- (LVM_INT16)NumSamples);
-
- Add2_Sat_32x32(pPrivate->pScratchDelayLine[1],
- pPrivate->pScratchDelayLine[0],
- (LVM_INT16)NumSamples);
-
-
- JoinTo2i_32x32(pPrivate->pScratchDelayLine[0],
- pScratch,
- pTemp,
- (LVM_INT16)NumSamples);
- break;
- case LVREV_DELAYLINES_1:
- MonoTo2I_32(pPrivate->pScratchDelayLine[0],
- pTemp,
- (LVM_INT16)NumSamples);
- break;
- default:
- break;
- }
-
-
- /*
- * Dry/wet mixer
- */
-
- size = (LVM_INT16)(NumSamples << 1);
- MixSoft_2St_D32C31_SAT(&pPrivate->BypassMixer,
- pTemp,
- pTemp,
- pOutput,
- size);
-
- /* Apply Gain*/
-
- Shift_Sat_v32xv32 (LVREV_OUTPUTGAIN_SHIFT,
- pOutput,
- pOutput,
- size);
-
- MixSoft_1St_D32C31_WRA(&pPrivate->GainMixer,
- pOutput,
- pOutput,
- size);
-
- return;
-}
-#else
-void ReverbBlock(LVM_FLOAT *pInput, LVM_FLOAT *pOutput,
- LVREV_Instance_st *pPrivate, LVM_UINT16 NumSamples)
-{
- LVM_INT16 j, size;
- LVM_FLOAT *pDelayLine;
- LVM_FLOAT *pDelayLineInput = pPrivate->pScratch;
- LVM_FLOAT *pScratch = pPrivate->pScratch;
- LVM_FLOAT *pIn;
- LVM_FLOAT *pTemp = pPrivate->pInputSave;
- LVM_INT32 NumberOfDelayLines;
-
- /******************************************************************************
- * All calculations will go into the buffer pointed to by pTemp, this will *
- * then be mixed with the original input to create the final output. *
- * *
- * When INPLACE processing is selected this must be a temporary buffer and *
- * hence this is the worst case, so for simplicity this will ALWAYS be so *
- * *
- * The input buffer will remain untouched until the output of the mixer if *
- * INPLACE processing is selected. *
- * *
- * The temp buffer will always be NumSamples in size regardless of MONO or *
- * STEREO input. In the case of stereo input all processing is done in MONO *
- * and the final output is converted to STEREO after the mixer *
- ******************************************************************************/
-
- if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_4)
- {
- NumberOfDelayLines = 4;
- }
- else if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_2)
- {
- NumberOfDelayLines = 2;
- }
- else
- {
- NumberOfDelayLines = 1;
- }
-
- if(pPrivate->CurrentParams.SourceFormat == LVM_MONO)
- {
- pIn = pInput;
- }
- else
- {
- /*
- * Stereo to mono conversion
- */
-
- From2iToMono_Float(pInput,
- pTemp,
- (LVM_INT16)NumSamples);
- pIn = pTemp;
- }
-
- Mult3s_Float(pIn,
- (LVM_FLOAT)LVREV_HEADROOM,
- pTemp,
- (LVM_INT16)NumSamples);
-
- /*
- * High pass filter
- */
- FO_1I_D32F32C31_TRC_WRA_01(&pPrivate->pFastCoef->HPCoefs,
- pTemp,
- pTemp,
- (LVM_INT16)NumSamples);
- /*
- * Low pass filter
- */
- FO_1I_D32F32C31_TRC_WRA_01(&pPrivate->pFastCoef->LPCoefs,
- pTemp,
- pTemp,
- (LVM_INT16)NumSamples);
-
- /*
- * Process all delay lines
- */
-
- for(j = 0; j < NumberOfDelayLines; j++)
- {
- pDelayLine = pPrivate->pScratchDelayLine[j];
-
- /*
- * All-pass filter with pop and click suppression
- */
- /* Get the smoothed, delayed output. Put it in the output buffer */
- MixSoft_2St_D32C31_SAT(&pPrivate->Mixer_APTaps[j],
- pPrivate->pOffsetA[j],
- pPrivate->pOffsetB[j],
- pDelayLine,
- (LVM_INT16)NumSamples);
- /* Re-align the all pass filter delay buffer and copying the fixed delay data \
- to the AP delay in the process */
- Copy_Float(&pPrivate->pDelay_T[j][NumSamples],
- pPrivate->pDelay_T[j],
- (LVM_INT16)(pPrivate->T[j] - NumSamples)); /* 32-bit data */
- /* Apply the smoothed feedback and save to fixed delay input (currently empty) */
- MixSoft_1St_D32C31_WRA(&pPrivate->Mixer_SGFeedback[j],
- pDelayLine,
- &pPrivate->pDelay_T[j][pPrivate->T[j] - NumSamples],
- (LVM_INT16)NumSamples);
- /* Sum into the AP delay line */
- Mac3s_Sat_Float(&pPrivate->pDelay_T[j][pPrivate->T[j] - NumSamples],
- -1.0f, /* Invert since the feedback coefficient is negative */
- &pPrivate->pDelay_T[j][pPrivate->Delay_AP[j] - NumSamples],
- (LVM_INT16)NumSamples);
- /* Apply smoothed feedforward sand save to fixed delay input (currently empty) */
- MixSoft_1St_D32C31_WRA(&pPrivate->Mixer_SGFeedforward[j],
- &pPrivate->pDelay_T[j][pPrivate->Delay_AP[j] - NumSamples],
- &pPrivate->pDelay_T[j][pPrivate->T[j] - NumSamples],
- (LVM_INT16)NumSamples);
- /* Sum into the AP output */
- Mac3s_Sat_Float(&pPrivate->pDelay_T[j][pPrivate->T[j] - NumSamples],
- 1.0f,
- pDelayLine,
- (LVM_INT16)NumSamples);
-
- /*
- * Feedback gain
- */
- MixSoft_1St_D32C31_WRA(&pPrivate->FeedbackMixer[j], pDelayLine, pDelayLine, NumSamples);
-
- /*
- * Low pass filter
- */
- FO_1I_D32F32C31_TRC_WRA_01(&pPrivate->pFastCoef->RevLPCoefs[j],
- pDelayLine,
- pDelayLine,
- (LVM_INT16)NumSamples);
- }
-
- /*
- * Apply rotation matrix and delay samples
- */
- for(j = 0; j < NumberOfDelayLines; j++)
- {
-
- Copy_Float(pTemp,
- pDelayLineInput,
- (LVM_INT16)(NumSamples));
- /*
- * Rotation matrix mix
- */
- switch(j)
- {
- case 3:
- /*
- * Add delay line 1 and 2 contribution
- */
- Mac3s_Sat_Float(pPrivate->pScratchDelayLine[1], -1.0f,
- pDelayLineInput, (LVM_INT16)NumSamples);
- Mac3s_Sat_Float(pPrivate->pScratchDelayLine[2], -1.0f,
- pDelayLineInput, (LVM_INT16)NumSamples);
-
- break;
- case 2:
-
- /*
- * Add delay line 0 and 3 contribution
- */
- Mac3s_Sat_Float(pPrivate->pScratchDelayLine[0], -1.0f,
- pDelayLineInput, (LVM_INT16)NumSamples);
- Mac3s_Sat_Float(pPrivate->pScratchDelayLine[3], -1.0f,
- pDelayLineInput, (LVM_INT16)NumSamples);
-
- break;
- case 1:
- if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_4)
- {
- /*
- * Add delay line 0 and 3 contribution
- */
- Mac3s_Sat_Float(pPrivate->pScratchDelayLine[0], -1.0f,
- pDelayLineInput, (LVM_INT16)NumSamples);
- Add2_Sat_Float(pPrivate->pScratchDelayLine[3], pDelayLineInput,
- (LVM_INT16)NumSamples);
-
- }
- else
- {
- /*
- * Add delay line 0 and 1 contribution
- */
- Mac3s_Sat_Float(pPrivate->pScratchDelayLine[0], -1.0f,
- pDelayLineInput, (LVM_INT16)NumSamples);
- Mac3s_Sat_Float(pPrivate->pScratchDelayLine[1], -1.0f,
- pDelayLineInput, (LVM_INT16)NumSamples);
-
- }
- break;
- case 0:
- if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_4)
- {
- /*
- * Add delay line 1 and 2 contribution
- */
- Mac3s_Sat_Float(pPrivate->pScratchDelayLine[1], -1.0f,
- pDelayLineInput, (LVM_INT16)NumSamples);
- Add2_Sat_Float(pPrivate->pScratchDelayLine[2], pDelayLineInput,
- (LVM_INT16)NumSamples);
-
- }
- else if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_2)
- {
- /*
- * Add delay line 0 and 1 contribution
- */
- Add2_Sat_Float(pPrivate->pScratchDelayLine[0], pDelayLineInput,
- (LVM_INT16)NumSamples);
- Mac3s_Sat_Float(pPrivate->pScratchDelayLine[1], -1.0f,
- pDelayLineInput, (LVM_INT16)NumSamples);
-
- }
- else
- {
- /*
- * Add delay line 0 contribution
- */
-
- /* SOURCE DESTINATION*/
- Add2_Sat_Float(pPrivate->pScratchDelayLine[0], pDelayLineInput,
- (LVM_INT16)NumSamples);
- }
- break;
- default:
- break;
- }
-
- /*
- * Delay samples
- */
- Copy_Float(pDelayLineInput,
- &pPrivate->pDelay_T[j][pPrivate->T[j] - NumSamples],
- (LVM_INT16)(NumSamples)); /* 32-bit data */
- }
-
-
- /*
- * Create stereo output
- */
- switch(pPrivate->InstanceParams.NumDelays)
- {
- case LVREV_DELAYLINES_4:
- Add2_Sat_Float(pPrivate->pScratchDelayLine[3],
- pPrivate->pScratchDelayLine[0],
- (LVM_INT16)NumSamples);
- Add2_Sat_Float(pPrivate->pScratchDelayLine[2],
- pPrivate->pScratchDelayLine[1],
- (LVM_INT16)NumSamples);
-
-
- JoinTo2i_Float(pPrivate->pScratchDelayLine[0],
- pPrivate->pScratchDelayLine[1],
- pTemp,
- (LVM_INT16)NumSamples);
-
-
- break;
- case LVREV_DELAYLINES_2:
-
- Copy_Float(pPrivate->pScratchDelayLine[1],
- pScratch,
- (LVM_INT16)(NumSamples));
-
- Mac3s_Sat_Float(pPrivate->pScratchDelayLine[0],
- -1.0f,
- pScratch,
- (LVM_INT16)NumSamples);
-
- Add2_Sat_Float(pPrivate->pScratchDelayLine[1],
- pPrivate->pScratchDelayLine[0],
- (LVM_INT16)NumSamples);
-
-
- JoinTo2i_Float(pPrivate->pScratchDelayLine[0],
- pScratch,
- pTemp,
- (LVM_INT16)NumSamples);
- break;
- case LVREV_DELAYLINES_1:
- MonoTo2I_Float(pPrivate->pScratchDelayLine[0],
- pTemp,
- (LVM_INT16)NumSamples);
- break;
- default:
- break;
- }
-
-
- /*
- * Dry/wet mixer
- */
-
- size = (LVM_INT16)(NumSamples << 1);
- MixSoft_2St_D32C31_SAT(&pPrivate->BypassMixer,
- pTemp,
- pTemp,
- pOutput,
- size);
-
- /* Apply Gain*/
-
- Shift_Sat_Float(LVREV_OUTPUTGAIN_SHIFT,
- pOutput,
- pOutput,
- size);
-
- MixSoft_1St_D32C31_WRA(&pPrivate->GainMixer,
- pOutput,
- pOutput,
- size);
-
- return;
-}
-#endif
-/* End of file */
-
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_Process.cpp b/media/libeffects/lvm/lib/Reverb/src/LVREV_Process.cpp
new file mode 100644
index 0000000..35f9ad8
--- /dev/null
+++ b/media/libeffects/lvm/lib/Reverb/src/LVREV_Process.cpp
@@ -0,0 +1,484 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/****************************************************************************************/
+/* */
+/* Includes */
+/* */
+/****************************************************************************************/
+#include "LVREV_Private.h"
+#include "VectorArithmetic.h"
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVREV_Process */
+/* */
+/* DESCRIPTION: */
+/* Process function for the LVREV module. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance handle */
+/* pInData Pointer to the input data */
+/* pOutData Pointer to the output data */
+/* NumSamples Number of samples in the input buffer */
+/* */
+/* RETURNS: */
+/* LVREV_Success Succeeded */
+/* LVREV_INVALIDNUMSAMPLES NumSamples was larger than the maximum block size */
+/* LVREV_NULLADDRESS When one of hInstance, pInData or pOutData is NULL */
+/* */
+/* NOTES: */
+/* 1. The input and output buffers must be 32-bit aligned */
+/* */
+/****************************************************************************************/
+LVREV_ReturnStatus_en LVREV_Process(LVREV_Handle_t hInstance,
+ const LVM_FLOAT *pInData,
+ LVM_FLOAT *pOutData,
+ const LVM_UINT16 NumSamples)
+{
+ LVREV_Instance_st *pLVREV_Private = (LVREV_Instance_st *)hInstance;
+ LVM_FLOAT *pInput = (LVM_FLOAT *)pInData;
+ LVM_FLOAT *pOutput = pOutData;
+ LVM_INT32 SamplesToProcess, RemainingSamples;
+ LVM_INT32 format = 1;
+
+ /*
+ * Check for error conditions
+ */
+
+ /* Check for NULL pointers */
+ if((hInstance == LVM_NULL) || (pInData == LVM_NULL) || (pOutData == LVM_NULL))
+ {
+ return LVREV_NULLADDRESS;
+ }
+
+ /*
+ * Apply the new controls settings if required
+ */
+ if(pLVREV_Private->bControlPending == LVM_TRUE)
+ {
+ LVREV_ReturnStatus_en errorCode;
+
+ /*
+ * Clear the pending flag and update the control settings
+ */
+ pLVREV_Private->bControlPending = LVM_FALSE;
+
+ errorCode = LVREV_ApplyNewSettings (pLVREV_Private);
+
+ if(errorCode != LVREV_SUCCESS)
+ {
+ return errorCode;
+ }
+ }
+
+ /*
+ * Trap the case where the number of samples is zero.
+ */
+ if (NumSamples == 0)
+ {
+ return LVREV_SUCCESS;
+ }
+
+ /*
+ * If OFF copy and reformat the data as necessary
+ */
+ if (pLVREV_Private->CurrentParams.OperatingMode == LVM_MODE_OFF)
+ {
+ if(pInput != pOutput)
+ {
+ /*
+ * Copy the data to the output buffer, convert to stereo is required
+ */
+ if(pLVREV_Private->CurrentParams.SourceFormat == LVM_MONO){
+ MonoTo2I_Float(pInput, pOutput, NumSamples);
+ } else {
+ Copy_Float(pInput,
+ pOutput,
+ (LVM_INT16)(NumSamples << 1)); // 32 bit data, stereo
+ }
+ }
+
+ return LVREV_SUCCESS;
+ }
+
+ RemainingSamples = (LVM_INT32)NumSamples;
+
+ if (pLVREV_Private->CurrentParams.SourceFormat != LVM_MONO)
+ {
+ format = 2;
+ }
+
+ while (RemainingSamples!=0)
+ {
+ /*
+ * Process the data
+ */
+
+ if(RemainingSamples > pLVREV_Private->MaxBlkLen)
+ {
+ SamplesToProcess = pLVREV_Private->MaxBlkLen;
+ RemainingSamples = (LVM_INT16)(RemainingSamples - SamplesToProcess);
+ }
+ else
+ {
+ SamplesToProcess = RemainingSamples;
+ RemainingSamples = 0;
+ }
+
+ ReverbBlock(pInput, pOutput, pLVREV_Private, (LVM_UINT16)SamplesToProcess);
+ pInput = (LVM_FLOAT *)(pInput + (SamplesToProcess * format));
+ pOutput = (LVM_FLOAT *)(pOutput + (SamplesToProcess * 2)); // Always stereo output
+ }
+
+ return LVREV_SUCCESS;
+}
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: ReverbBlock */
+/* */
+/* DESCRIPTION: */
+/* Process function for the LVREV module. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance handle */
+/* pInData Pointer to the input data */
+/* pOutData Pointer to the output data */
+/* NumSamples Number of samples in the input buffer */
+/* */
+/* RETURNS: */
+/* LVREV_Success Succeeded */
+/* LVREV_INVALIDNUMSAMPLES NumSamples was larger than the maximum block size */
+/* LVREV_NULLADDRESS When one of hInstance, pInData or pOutData is NULL */
+/* */
+/* NOTES: */
+/* 1. The input and output buffers must be 32-bit aligned */
+/* */
+/****************************************************************************************/
+void ReverbBlock(LVM_FLOAT *pInput, LVM_FLOAT *pOutput,
+ LVREV_Instance_st *pPrivate, LVM_UINT16 NumSamples)
+{
+ LVM_INT16 j, size;
+ LVM_FLOAT *pDelayLine;
+ LVM_FLOAT *pDelayLineInput = pPrivate->pScratch;
+ LVM_FLOAT *pScratch = pPrivate->pScratch;
+ LVM_FLOAT *pIn;
+ LVM_FLOAT *pTemp = pPrivate->pInputSave;
+ LVM_INT32 NumberOfDelayLines;
+
+ /******************************************************************************
+ * All calculations will go into the buffer pointed to by pTemp, this will *
+ * then be mixed with the original input to create the final output. *
+ * *
+ * When INPLACE processing is selected this must be a temporary buffer and *
+ * hence this is the worst case, so for simplicity this will ALWAYS be so *
+ * *
+ * The input buffer will remain untouched until the output of the mixer if *
+ * INPLACE processing is selected. *
+ * *
+ * The temp buffer will always be NumSamples in size regardless of MONO or *
+ * STEREO input. In the case of stereo input all processing is done in MONO *
+ * and the final output is converted to STEREO after the mixer *
+ ******************************************************************************/
+
+ if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_4)
+ {
+ NumberOfDelayLines = 4;
+ }
+ else if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_2)
+ {
+ NumberOfDelayLines = 2;
+ }
+ else
+ {
+ NumberOfDelayLines = 1;
+ }
+
+ if(pPrivate->CurrentParams.SourceFormat == LVM_MONO)
+ {
+ pIn = pInput;
+ }
+ else
+ {
+ /*
+ * Stereo to mono conversion
+ */
+
+ From2iToMono_Float(pInput,
+ pTemp,
+ (LVM_INT16)NumSamples);
+ pIn = pTemp;
+ }
+
+ Mult3s_Float(pIn,
+ (LVM_FLOAT)LVREV_HEADROOM,
+ pTemp,
+ (LVM_INT16)NumSamples);
+
+ /*
+ * High pass filter
+ */
+ FO_1I_D32F32C31_TRC_WRA_01(&pPrivate->pFastCoef->HPCoefs,
+ pTemp,
+ pTemp,
+ (LVM_INT16)NumSamples);
+ /*
+ * Low pass filter
+ */
+ FO_1I_D32F32C31_TRC_WRA_01(&pPrivate->pFastCoef->LPCoefs,
+ pTemp,
+ pTemp,
+ (LVM_INT16)NumSamples);
+
+ /*
+ * Process all delay lines
+ */
+
+ for(j = 0; j < NumberOfDelayLines; j++)
+ {
+ pDelayLine = pPrivate->pScratchDelayLine[j];
+
+ /*
+ * All-pass filter with pop and click suppression
+ */
+ /* Get the smoothed, delayed output. Put it in the output buffer */
+ MixSoft_2St_D32C31_SAT(&pPrivate->Mixer_APTaps[j],
+ pPrivate->pOffsetA[j],
+ pPrivate->pOffsetB[j],
+ pDelayLine,
+ (LVM_INT16)NumSamples);
+ /* Re-align the all pass filter delay buffer and copying the fixed delay data \
+ to the AP delay in the process */
+ Copy_Float(&pPrivate->pDelay_T[j][NumSamples],
+ pPrivate->pDelay_T[j],
+ (LVM_INT16)(pPrivate->T[j] - NumSamples)); /* 32-bit data */
+ /* Apply the smoothed feedback and save to fixed delay input (currently empty) */
+ MixSoft_1St_D32C31_WRA(&pPrivate->Mixer_SGFeedback[j],
+ pDelayLine,
+ &pPrivate->pDelay_T[j][pPrivate->T[j] - NumSamples],
+ (LVM_INT16)NumSamples);
+ /* Sum into the AP delay line */
+ Mac3s_Sat_Float(&pPrivate->pDelay_T[j][pPrivate->T[j] - NumSamples],
+ -1.0f, /* Invert since the feedback coefficient is negative */
+ &pPrivate->pDelay_T[j][pPrivate->Delay_AP[j] - NumSamples],
+ (LVM_INT16)NumSamples);
+ /* Apply smoothed feedforward sand save to fixed delay input (currently empty) */
+ MixSoft_1St_D32C31_WRA(&pPrivate->Mixer_SGFeedforward[j],
+ &pPrivate->pDelay_T[j][pPrivate->Delay_AP[j] - NumSamples],
+ &pPrivate->pDelay_T[j][pPrivate->T[j] - NumSamples],
+ (LVM_INT16)NumSamples);
+ /* Sum into the AP output */
+ Mac3s_Sat_Float(&pPrivate->pDelay_T[j][pPrivate->T[j] - NumSamples],
+ 1.0f,
+ pDelayLine,
+ (LVM_INT16)NumSamples);
+
+ /*
+ * Feedback gain
+ */
+ MixSoft_1St_D32C31_WRA(&pPrivate->FeedbackMixer[j], pDelayLine, pDelayLine, NumSamples);
+
+ /*
+ * Low pass filter
+ */
+ FO_1I_D32F32C31_TRC_WRA_01(&pPrivate->pFastCoef->RevLPCoefs[j],
+ pDelayLine,
+ pDelayLine,
+ (LVM_INT16)NumSamples);
+ }
+
+ /*
+ * Apply rotation matrix and delay samples
+ */
+ for(j = 0; j < NumberOfDelayLines; j++)
+ {
+
+ Copy_Float(pTemp,
+ pDelayLineInput,
+ (LVM_INT16)(NumSamples));
+ /*
+ * Rotation matrix mix
+ */
+ switch(j)
+ {
+ case 3:
+ /*
+ * Add delay line 1 and 2 contribution
+ */
+ Mac3s_Sat_Float(pPrivate->pScratchDelayLine[1], -1.0f,
+ pDelayLineInput, (LVM_INT16)NumSamples);
+ Mac3s_Sat_Float(pPrivate->pScratchDelayLine[2], -1.0f,
+ pDelayLineInput, (LVM_INT16)NumSamples);
+
+ break;
+ case 2:
+
+ /*
+ * Add delay line 0 and 3 contribution
+ */
+ Mac3s_Sat_Float(pPrivate->pScratchDelayLine[0], -1.0f,
+ pDelayLineInput, (LVM_INT16)NumSamples);
+ Mac3s_Sat_Float(pPrivate->pScratchDelayLine[3], -1.0f,
+ pDelayLineInput, (LVM_INT16)NumSamples);
+
+ break;
+ case 1:
+ if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_4)
+ {
+ /*
+ * Add delay line 0 and 3 contribution
+ */
+ Mac3s_Sat_Float(pPrivate->pScratchDelayLine[0], -1.0f,
+ pDelayLineInput, (LVM_INT16)NumSamples);
+ Add2_Sat_Float(pPrivate->pScratchDelayLine[3], pDelayLineInput,
+ (LVM_INT16)NumSamples);
+
+ }
+ else
+ {
+ /*
+ * Add delay line 0 and 1 contribution
+ */
+ Mac3s_Sat_Float(pPrivate->pScratchDelayLine[0], -1.0f,
+ pDelayLineInput, (LVM_INT16)NumSamples);
+ Mac3s_Sat_Float(pPrivate->pScratchDelayLine[1], -1.0f,
+ pDelayLineInput, (LVM_INT16)NumSamples);
+
+ }
+ break;
+ case 0:
+ if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_4)
+ {
+ /*
+ * Add delay line 1 and 2 contribution
+ */
+ Mac3s_Sat_Float(pPrivate->pScratchDelayLine[1], -1.0f,
+ pDelayLineInput, (LVM_INT16)NumSamples);
+ Add2_Sat_Float(pPrivate->pScratchDelayLine[2], pDelayLineInput,
+ (LVM_INT16)NumSamples);
+
+ }
+ else if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_2)
+ {
+ /*
+ * Add delay line 0 and 1 contribution
+ */
+ Add2_Sat_Float(pPrivate->pScratchDelayLine[0], pDelayLineInput,
+ (LVM_INT16)NumSamples);
+ Mac3s_Sat_Float(pPrivate->pScratchDelayLine[1], -1.0f,
+ pDelayLineInput, (LVM_INT16)NumSamples);
+
+ }
+ else
+ {
+ /*
+ * Add delay line 0 contribution
+ */
+
+ /* SOURCE DESTINATION*/
+ Add2_Sat_Float(pPrivate->pScratchDelayLine[0], pDelayLineInput,
+ (LVM_INT16)NumSamples);
+ }
+ break;
+ default:
+ break;
+ }
+
+ /*
+ * Delay samples
+ */
+ Copy_Float(pDelayLineInput,
+ &pPrivate->pDelay_T[j][pPrivate->T[j] - NumSamples],
+ (LVM_INT16)(NumSamples)); /* 32-bit data */
+ }
+
+ /*
+ * Create stereo output
+ */
+ switch(pPrivate->InstanceParams.NumDelays)
+ {
+ case LVREV_DELAYLINES_4:
+ Add2_Sat_Float(pPrivate->pScratchDelayLine[3],
+ pPrivate->pScratchDelayLine[0],
+ (LVM_INT16)NumSamples);
+ Add2_Sat_Float(pPrivate->pScratchDelayLine[2],
+ pPrivate->pScratchDelayLine[1],
+ (LVM_INT16)NumSamples);
+
+ JoinTo2i_Float(pPrivate->pScratchDelayLine[0],
+ pPrivate->pScratchDelayLine[1],
+ pTemp,
+ (LVM_INT16)NumSamples);
+
+ break;
+ case LVREV_DELAYLINES_2:
+
+ Copy_Float(pPrivate->pScratchDelayLine[1],
+ pScratch,
+ (LVM_INT16)(NumSamples));
+
+ Mac3s_Sat_Float(pPrivate->pScratchDelayLine[0],
+ -1.0f,
+ pScratch,
+ (LVM_INT16)NumSamples);
+
+ Add2_Sat_Float(pPrivate->pScratchDelayLine[1],
+ pPrivate->pScratchDelayLine[0],
+ (LVM_INT16)NumSamples);
+
+ JoinTo2i_Float(pPrivate->pScratchDelayLine[0],
+ pScratch,
+ pTemp,
+ (LVM_INT16)NumSamples);
+ break;
+ case LVREV_DELAYLINES_1:
+ MonoTo2I_Float(pPrivate->pScratchDelayLine[0],
+ pTemp,
+ (LVM_INT16)NumSamples);
+ break;
+ default:
+ break;
+ }
+
+ /*
+ * Dry/wet mixer
+ */
+
+ size = (LVM_INT16)(NumSamples << 1);
+ MixSoft_2St_D32C31_SAT(&pPrivate->BypassMixer,
+ pTemp,
+ pTemp,
+ pOutput,
+ size);
+
+ /* Apply Gain*/
+
+ Shift_Sat_Float(LVREV_OUTPUTGAIN_SHIFT,
+ pOutput,
+ pOutput,
+ size);
+
+ MixSoft_1St_D32C31_WRA(&pPrivate->GainMixer,
+ pOutput,
+ pOutput,
+ size);
+
+ return;
+}
+/* End of file */
+
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_SetControlParameters.c b/media/libeffects/lvm/lib/Reverb/src/LVREV_SetControlParameters.c
deleted file mode 100644
index dfed28e..0000000
--- a/media/libeffects/lvm/lib/Reverb/src/LVREV_SetControlParameters.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/****************************************************************************************/
-/* */
-/* Includes */
-/* */
-/****************************************************************************************/
-#include "LVREV_Private.h"
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVREV_SetControlParameters */
-/* */
-/* DESCRIPTION: */
-/* Sets or changes the LVREV module parameters. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance handle */
-/* pNewParams Pointer to a parameter structure */
-/* */
-/* RETURNS: */
-/* LVM_Success Succeeded */
-/* LVREV_NULLADDRESS When hInstance or pNewParams is NULL */
-/* LVREV_OUTOFRANGE When any of the new parameters is out of range */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVREV_Process function */
-/* */
-/****************************************************************************************/
-LVREV_ReturnStatus_en LVREV_SetControlParameters(LVREV_Handle_t hInstance,
- LVREV_ControlParams_st *pNewParams)
-{
-
- LVREV_Instance_st *pLVREV_Private = (LVREV_Instance_st *)hInstance;
-
-
- /*
- * Check for error conditions
- */
- if((hInstance == LVM_NULL) || (pNewParams == LVM_NULL))
- {
- return LVREV_NULLADDRESS;
- }
-
- /*
- * Check all new control parameters are in range
- */
- if( ((pNewParams->OperatingMode != LVM_MODE_OFF) && (pNewParams->OperatingMode != LVM_MODE_ON)) ||
- (
- (pNewParams->SampleRate != LVM_FS_8000) && (pNewParams->SampleRate != LVM_FS_11025) && (pNewParams->SampleRate != LVM_FS_12000) &&
- (pNewParams->SampleRate != LVM_FS_16000) && (pNewParams->SampleRate != LVM_FS_22050) && (pNewParams->SampleRate != LVM_FS_24000) &&
- (pNewParams->SampleRate != LVM_FS_32000) &&
- (pNewParams->SampleRate != LVM_FS_44100) &&
- (pNewParams->SampleRate != LVM_FS_48000)
-#ifdef HIGHER_FS
- && (pNewParams->SampleRate != LVM_FS_88200) && (pNewParams->SampleRate != LVM_FS_96000)
- && (pNewParams->SampleRate != LVM_FS_176400) && (pNewParams->SampleRate != LVM_FS_192000)
-#endif
- )
-#ifdef SUPPORT_MC
- || ((pNewParams->SourceFormat != LVM_STEREO) &&
- (pNewParams->SourceFormat != LVM_MONOINSTEREO) &&
- (pNewParams->SourceFormat != LVM_MONO) &&
- (pNewParams->SourceFormat != LVM_MULTICHANNEL)))
-#else
- || ((pNewParams->SourceFormat != LVM_STEREO) && (pNewParams->SourceFormat != LVM_MONOINSTEREO) && (pNewParams->SourceFormat != LVM_MONO)) )
-#endif
- {
- return (LVREV_OUTOFRANGE);
- }
-
-
- if (pNewParams->Level > LVREV_MAX_LEVEL)
- {
- return LVREV_OUTOFRANGE;
- }
-
- if ((pNewParams->LPF < LVREV_MIN_LPF_CORNER) || (pNewParams->LPF > LVREV_MAX_LPF_CORNER))
- {
- return LVREV_OUTOFRANGE;
- }
-
- if ((pNewParams->HPF < LVREV_MIN_HPF_CORNER) || (pNewParams->HPF > LVREV_MAX_HPF_CORNER))
- {
- return LVREV_OUTOFRANGE;
- }
-
- if (pNewParams->T60 > LVREV_MAX_T60)
- {
- return LVREV_OUTOFRANGE;
- }
-
- if (pNewParams->Density > LVREV_MAX_DENSITY)
- {
- return LVREV_OUTOFRANGE;
- }
-
- if (pNewParams->Damping > LVREV_MAX_DAMPING)
- {
- return LVREV_OUTOFRANGE;
- }
-
- if (pNewParams->RoomSize > LVREV_MAX_ROOMSIZE)
- {
- return LVREV_OUTOFRANGE;
- }
-
-
-
- /*
- * Copy the new parameters and set the flag to indicate they are available
- */
- pLVREV_Private->NewParams = *pNewParams;
- pLVREV_Private->bControlPending = LVM_TRUE;
-
- return LVREV_SUCCESS;
-}
-
-/* End of file */
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_SetControlParameters.cpp b/media/libeffects/lvm/lib/Reverb/src/LVREV_SetControlParameters.cpp
new file mode 100644
index 0000000..2a75559
--- /dev/null
+++ b/media/libeffects/lvm/lib/Reverb/src/LVREV_SetControlParameters.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/****************************************************************************************/
+/* */
+/* Includes */
+/* */
+/****************************************************************************************/
+#include "LVREV_Private.h"
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVREV_SetControlParameters */
+/* */
+/* DESCRIPTION: */
+/* Sets or changes the LVREV module parameters. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance handle */
+/* pNewParams Pointer to a parameter structure */
+/* */
+/* RETURNS: */
+/* LVM_Success Succeeded */
+/* LVREV_NULLADDRESS When hInstance or pNewParams is NULL */
+/* LVREV_OUTOFRANGE When any of the new parameters is out of range */
+/* */
+/* NOTES: */
+/* 1. This function may be interrupted by the LVREV_Process function */
+/* */
+/****************************************************************************************/
+LVREV_ReturnStatus_en LVREV_SetControlParameters(LVREV_Handle_t hInstance,
+ LVREV_ControlParams_st *pNewParams)
+{
+
+ LVREV_Instance_st *pLVREV_Private = (LVREV_Instance_st *)hInstance;
+
+ /*
+ * Check for error conditions
+ */
+ if((hInstance == LVM_NULL) || (pNewParams == LVM_NULL))
+ {
+ return LVREV_NULLADDRESS;
+ }
+
+ /*
+ * Check all new control parameters are in range
+ */
+ if( ((pNewParams->OperatingMode != LVM_MODE_OFF) && (pNewParams->OperatingMode != LVM_MODE_ON)) ||
+ (
+ (pNewParams->SampleRate != LVM_FS_8000) && (pNewParams->SampleRate != LVM_FS_11025) && (pNewParams->SampleRate != LVM_FS_12000) &&
+ (pNewParams->SampleRate != LVM_FS_16000) && (pNewParams->SampleRate != LVM_FS_22050) && (pNewParams->SampleRate != LVM_FS_24000) &&
+ (pNewParams->SampleRate != LVM_FS_32000) &&
+ (pNewParams->SampleRate != LVM_FS_44100) &&
+ (pNewParams->SampleRate != LVM_FS_48000)
+ && (pNewParams->SampleRate != LVM_FS_88200) && (pNewParams->SampleRate != LVM_FS_96000)
+ && (pNewParams->SampleRate != LVM_FS_176400) && (pNewParams->SampleRate != LVM_FS_192000)
+ )
+#ifdef SUPPORT_MC
+ || ((pNewParams->SourceFormat != LVM_STEREO) &&
+ (pNewParams->SourceFormat != LVM_MONOINSTEREO) &&
+ (pNewParams->SourceFormat != LVM_MONO) &&
+ (pNewParams->SourceFormat != LVM_MULTICHANNEL)))
+#else
+ || ((pNewParams->SourceFormat != LVM_STEREO) && (pNewParams->SourceFormat != LVM_MONOINSTEREO) && (pNewParams->SourceFormat != LVM_MONO)) )
+#endif
+ {
+ return (LVREV_OUTOFRANGE);
+ }
+
+ if (pNewParams->Level > LVREV_MAX_LEVEL)
+ {
+ return LVREV_OUTOFRANGE;
+ }
+
+ if ((pNewParams->LPF < LVREV_MIN_LPF_CORNER) || (pNewParams->LPF > LVREV_MAX_LPF_CORNER))
+ {
+ return LVREV_OUTOFRANGE;
+ }
+
+ if ((pNewParams->HPF < LVREV_MIN_HPF_CORNER) || (pNewParams->HPF > LVREV_MAX_HPF_CORNER))
+ {
+ return LVREV_OUTOFRANGE;
+ }
+
+ if (pNewParams->T60 > LVREV_MAX_T60)
+ {
+ return LVREV_OUTOFRANGE;
+ }
+
+ if (pNewParams->Density > LVREV_MAX_DENSITY)
+ {
+ return LVREV_OUTOFRANGE;
+ }
+
+ if (pNewParams->Damping > LVREV_MAX_DAMPING)
+ {
+ return LVREV_OUTOFRANGE;
+ }
+
+ if (pNewParams->RoomSize > LVREV_MAX_ROOMSIZE)
+ {
+ return LVREV_OUTOFRANGE;
+ }
+
+ /*
+ * Copy the new parameters and set the flag to indicate they are available
+ */
+ pLVREV_Private->NewParams = *pNewParams;
+ pLVREV_Private->bControlPending = LVM_TRUE;
+
+ return LVREV_SUCCESS;
+}
+
+/* End of file */
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_Tables.c b/media/libeffects/lvm/lib/Reverb/src/LVREV_Tables.c
deleted file mode 100644
index 1058740..0000000
--- a/media/libeffects/lvm/lib/Reverb/src/LVREV_Tables.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/****************************************************************************************/
-/* */
-/* Includes */
-/* */
-/****************************************************************************************/
-#include "LVREV.h"
-
-/****************************************************************************************/
-/* */
-/* Tables */
-/* */
-/****************************************************************************************/
-
-/* Table with supported sampling rates. The table can be indexed using LVM_Fs_en */
-#ifndef HIGHER_FS
-const LVM_UINT16 LVM_FsTable[] = {
- 8000 ,
- 11025,
- 12000,
- 16000,
- 22050,
- 24000,
- 32000,
- 44100,
- 48000
-};
-#else
-const LVM_UINT32 LVM_FsTable[] = {
- 8000 ,
- 11025,
- 12000,
- 16000,
- 22050,
- 24000,
- 32000,
- 44100,
- 48000,
- 88200,
- 96000,
- 176400,
- 192000
-};
-#endif
-/* Table with supported sampling rates. The table can be indexed using LVM_Fs_en */
-#ifndef HIGHER_FS
-LVM_UINT16 LVM_GetFsFromTable(LVM_Fs_en FsIndex){
- if (FsIndex > LVM_FS_48000)
- return 0;
-
- return (LVM_FsTable[FsIndex]);
-}
-#else
-LVM_UINT32 LVM_GetFsFromTable(LVM_Fs_en FsIndex){
- if (FsIndex > LVM_FS_192000)
- return 0;
-
- return (LVM_FsTable[FsIndex]);
-}
-#endif
-
-/* In order to maintain consistant input and out put signal strengths
- output gain/attenuation is applied. This gain depends on T60 and Rooms
- size parameters. These polynomial coefficients are calculated experimentally.
- First value in the table is room size
- second value is A0
- third value is A1
- fourth value is A2
- fifth value is A3
- sixth value is A4
-
- shift value is to be added array (to use LVM_Polynomial function)
-
- The gain is calculated using variable x=(T60*32767/7000)*32768;
-
- first values is used to get polynomial set for given room size,
- For room sizes which are not in the table, linear interpolation can be used.
-
- */
-
-/* Normalizing output including Reverb Level part (only shift up)*/
-#ifndef BUILD_FLOAT
-const LVM_INT32 LVREV_GainPolyTable[24][5]={{1,17547434,128867434,-120988896,50761228,},
- {2,18256869,172666902,-193169292,88345744,},
- {3,16591311,139250151,-149667234,66770059,},
- {4,17379977,170835131,-173579321,76278163,},
- {5,18963512,210364934,-228623519,103435022,},
- {6,17796318,135756417,-144084053,64327698,},
- {7,17454695,174593214,-187513064,85146582,},
- {8,17229257,140715570,-145790588,65361740,},
- {9,17000547,163195946,-176733969,79562130,},
- {10,16711699,142476304,-133339887,58366547,},
- {13,18108419,149223697,-161762020,74397589,},
- {15,16682043,124844884,-134284487,60082180,},
- {17,16627346,120936430,-121766674,53146421,},
- {20,17338325,125432694,-126616983,56534237,},
- {25,16489146,99218217,-94597467,40616506,},
- {30,15582373,84479043,-75365006,30952348,},
- {40,16000669,84896611,-75031127,30696306,},
- {50,15087054,71695031,-59349268,23279669,},
- {60,15830714,68672971,-58211201,23671158,},
- {70,15536061,66657972,-55901437,22560153,},
- {75,15013145,48179917,-24138354,5232074,},
- {80,15688738,50195036,-34206760,11515792,},
- {90,16003322,48323661,-35607378,13153872,},
- {100,15955223,48558201,-33706865,11715792,},
- };
-#else
-const LVM_FLOAT LVREV_GainPolyTable[24][5]={{1,1.045909f,7.681098f,-7.211500f,3.025605f,},
- {2,1.088194f,10.291749f,-11.513787f,5.265817f,},
- {3,0.988919f,8.299956f,-8.920862f,3.979806f,},
- {4,1.035927f,10.182567f,-10.346134f,4.546533f,},
- {5,1.130313f,12.538727f,-13.627023f,6.165208f,},
- {6,1.060743f,8.091713f,-8.588079f,3.834230f,},
- {7,1.040381f,10.406566f,-11.176650f,5.075132f,},
- {8,1.026944f,8.387302f,-8.689796f,3.895863f,},
- {9,1.013312f,9.727236f,-10.534165f,4.742272f,},
- {10,0.996095f,8.492249f,-7.947677f,3.478917f,},
- {13,1.079346f,8.894425f,-9.641768f,4.434442f,},
- {15,0.994327f,7.441335f,-8.003979f,3.581177f,},
- {17,0.991067f,7.208373f,-7.257859f,3.167774f,},
- {20,1.033445f,7.476371f,-7.546960f,3.369703f,},
- {25,0.982830f,5.913867f,-5.638448f,2.420932f,},
- {30,0.928782f,5.035343f,-4.492104f,1.844904f,},
- {40,0.953714f,5.060232f,-4.472204f,1.829642f,},
- {50,0.899258f,4.273357f,-3.537492f,1.387576f,},
- {60,0.943584f,4.093228f,-3.469658f,1.410911f,},
- {70,0.926021f,3.973125f,-3.331985f,1.344690f,},
- {75,0.894853f,2.871747f,-1.438758f,0.311856f,},
- {80,0.935122f,2.991857f,-2.038882f,0.686395f,},
- {90,0.953872f,2.880315f,-2.122365f,0.784032f,},
- {100,0.951005f,2.894294f,-2.009086f,0.698316f,},
-};
-#endif
-/* End of file */
-
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_Tables.cpp b/media/libeffects/lvm/lib/Reverb/src/LVREV_Tables.cpp
new file mode 100644
index 0000000..5cd623e
--- /dev/null
+++ b/media/libeffects/lvm/lib/Reverb/src/LVREV_Tables.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/****************************************************************************************/
+/* */
+/* Includes */
+/* */
+/****************************************************************************************/
+#include "LVREV.h"
+#include "LVREV_Tables.h"
+
+/****************************************************************************************/
+/* */
+/* Tables */
+/* */
+/****************************************************************************************/
+
+/* Table with supported sampling rates. The table can be indexed using LVM_Fs_en */
+const LVM_UINT32 LVM_FsTable[] = {
+ 8000 ,
+ 11025,
+ 12000,
+ 16000,
+ 22050,
+ 24000,
+ 32000,
+ 44100,
+ 48000,
+ 88200,
+ 96000,
+ 176400,
+ 192000
+};
+/* Table with supported sampling rates. The table can be indexed using LVM_Fs_en */
+LVM_UINT32 LVM_GetFsFromTable(LVM_Fs_en FsIndex){
+ if (FsIndex > LVM_FS_192000)
+ return 0;
+
+ return (LVM_FsTable[FsIndex]);
+}
+
+/* In order to maintain consistant input and out put signal strengths
+ output gain/attenuation is applied. This gain depends on T60 and Rooms
+ size parameters. These polynomial coefficients are calculated experimentally.
+ First value in the table is room size
+ second value is A0
+ third value is A1
+ fourth value is A2
+ fifth value is A3
+ sixth value is A4
+
+ shift value is to be added array (to use LVM_Polynomial function)
+
+ The gain is calculated using variable x=(T60*32767/7000)*32768;
+
+ first values is used to get polynomial set for given room size,
+ For room sizes which are not in the table, linear interpolation can be used.
+
+ */
+
+/* Normalizing output including Reverb Level part (only shift up)*/
+const LVM_FLOAT LVREV_GainPolyTable[24][5]={{1,1.045909f,7.681098f,-7.211500f,3.025605f,},
+ {2,1.088194f,10.291749f,-11.513787f,5.265817f,},
+ {3,0.988919f,8.299956f,-8.920862f,3.979806f,},
+ {4,1.035927f,10.182567f,-10.346134f,4.546533f,},
+ {5,1.130313f,12.538727f,-13.627023f,6.165208f,},
+ {6,1.060743f,8.091713f,-8.588079f,3.834230f,},
+ {7,1.040381f,10.406566f,-11.176650f,5.075132f,},
+ {8,1.026944f,8.387302f,-8.689796f,3.895863f,},
+ {9,1.013312f,9.727236f,-10.534165f,4.742272f,},
+ {10,0.996095f,8.492249f,-7.947677f,3.478917f,},
+ {13,1.079346f,8.894425f,-9.641768f,4.434442f,},
+ {15,0.994327f,7.441335f,-8.003979f,3.581177f,},
+ {17,0.991067f,7.208373f,-7.257859f,3.167774f,},
+ {20,1.033445f,7.476371f,-7.546960f,3.369703f,},
+ {25,0.982830f,5.913867f,-5.638448f,2.420932f,},
+ {30,0.928782f,5.035343f,-4.492104f,1.844904f,},
+ {40,0.953714f,5.060232f,-4.472204f,1.829642f,},
+ {50,0.899258f,4.273357f,-3.537492f,1.387576f,},
+ {60,0.943584f,4.093228f,-3.469658f,1.410911f,},
+ {70,0.926021f,3.973125f,-3.331985f,1.344690f,},
+ {75,0.894853f,2.871747f,-1.438758f,0.311856f,},
+ {80,0.935122f,2.991857f,-2.038882f,0.686395f,},
+ {90,0.953872f,2.880315f,-2.122365f,0.784032f,},
+ {100,0.951005f,2.894294f,-2.009086f,0.698316f,},
+};
+/* End of file */
+
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_Tables.h b/media/libeffects/lvm/lib/Reverb/src/LVREV_Tables.h
index 0658186..e100d8a 100644
--- a/media/libeffects/lvm/lib/Reverb/src/LVREV_Tables.h
+++ b/media/libeffects/lvm/lib/Reverb/src/LVREV_Tables.h
@@ -15,15 +15,9 @@
* limitations under the License.
*/
-
#ifndef _LVREV_TABLES_H_
#define _LVREV_TABLES_H_
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
/****************************************************************************************/
/* */
/* Includes */
@@ -37,22 +31,10 @@
/* */
/****************************************************************************************/
-#ifndef HIGHER_FS
-extern const LVM_UINT16 LVM_FsTable[];
-extern LVM_UINT16 LVM_GetFsFromTable(LVM_Fs_en FsIndex);
-#else
extern const LVM_UINT32 LVM_FsTable[];
extern LVM_UINT32 LVM_GetFsFromTable(LVM_Fs_en FsIndex);
-#endif
-#ifndef BUILD_FLOAT
-extern LVM_INT32 LVREV_GainPolyTable[24][5];
-#else
-extern LVM_FLOAT LVREV_GainPolyTable[24][5];
-#endif
-#ifdef __cplusplus
-}
-#endif
+extern const LVM_FLOAT LVREV_GainPolyTable[24][5];
#endif /** _LVREV_TABLES_H_ **/
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/lib/LVPSA.h b/media/libeffects/lvm/lib/SpectrumAnalyzer/lib/LVPSA.h
index 2038fbb..c9fa7ad 100644
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/lib/LVPSA.h
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/lib/LVPSA.h
@@ -18,14 +18,8 @@
#ifndef _LVPSA_H_
#define _LVPSA_H_
-
#include "LVM_Types.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
/****************************************************************************************/
/* */
/* CONSTANTS DEFINITIONS */
@@ -116,8 +110,6 @@
LVPSA_RETURN_DUMMY = LVM_MAXINT_32 /* Force 32 bits enum, don't use it! */
} LVPSA_RETURN;
-
-
/*********************************************************************************************************************************
FUNCTIONS PROTOTYPE
**********************************************************************************************************************************/
@@ -216,17 +208,10 @@
/* otherwise Error due to bad parameters */
/* */
/*********************************************************************************************************************************/
-#ifdef BUILD_FLOAT
LVPSA_RETURN LVPSA_Process ( pLVPSA_Handle_t hInstance,
LVM_FLOAT *pLVPSA_InputSamples,
LVM_UINT16 InputBlockSize,
LVPSA_Time AudioTime );
-#else
-LVPSA_RETURN LVPSA_Process ( pLVPSA_Handle_t hInstance,
- LVM_INT16 *pLVPSA_InputSamples,
- LVM_UINT16 InputBlockSize,
- LVPSA_Time AudioTime );
-#endif
/*********************************************************************************************************************************/
/* */
/* FUNCTION: LVPSA_GetSpectrum */
@@ -288,9 +273,4 @@
LVPSA_RETURN LVPSA_GetInitParams ( pLVPSA_Handle_t hInstance,
LVPSA_InitParams_t *pParams );
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
#endif /* _LVPSA_H */
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Control.c b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Control.c
deleted file mode 100644
index f6c4ea7..0000000
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Control.c
+++ /dev/null
@@ -1,940 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "LVPSA.h"
-#include "LVPSA_Private.h"
-#include "VectorArithmetic.h"
-
-#define LOW_FREQ 298 /* 32768/110 for low test frequency */
-#define HIGH_FREQ 386 /* 32768/85 for high test frequency */
-
-LVPSA_RETURN LVPSA_SetBPFiltersType ( LVPSA_InstancePr_t *pInst,
- LVPSA_ControlParams_t *pParams );
-
-LVPSA_RETURN LVPSA_SetQPFCoefficients( LVPSA_InstancePr_t *pInst,
- LVPSA_ControlParams_t *pParams );
-
-#ifdef BUILD_FLOAT
-LVPSA_RETURN LVPSA_BPSinglePrecCoefs( LVM_UINT16 Fs,
- LVPSA_FilterParam_t *pFilterParams,
- BP_FLOAT_Coefs_t *pCoefficients);
-
-LVPSA_RETURN LVPSA_BPDoublePrecCoefs( LVM_UINT16 Fs,
- LVPSA_FilterParam_t *pFilterParams,
- BP_FLOAT_Coefs_t *pCoefficients);
-#else
-LVPSA_RETURN LVPSA_BPSinglePrecCoefs( LVM_UINT16 Fs,
- LVPSA_FilterParam_t *pFilterParams,
- BP_C16_Coefs_t *pCoefficients);
-
-LVPSA_RETURN LVPSA_BPDoublePrecCoefs( LVM_UINT16 Fs,
- LVPSA_FilterParam_t *pFilterParams,
- BP_C32_Coefs_t *pCoefficients);
-
-LVPSA_RETURN LVPSA_BPDoublePrecCoefs( LVM_UINT16 Fs,
- LVPSA_FilterParam_t *pFilterParams,
- BP_C32_Coefs_t *pCoefficients);
-#endif
-LVPSA_RETURN LVPSA_SetBPFCoefficients( LVPSA_InstancePr_t *pInst,
- LVPSA_ControlParams_t *pParams );
-
-LVPSA_RETURN LVPSA_ClearFilterHistory( LVPSA_InstancePr_t *pInst);
-
-
-
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVPSA_Control */
-/* */
-/* DESCRIPTION: */
-/* Give some new control parameters to the module. */
-/* */
-/* PARAMETERS: */
-/* hInstance Pointer to the instance */
-/* NewParams Structure that contains the new parameters */
-/* */
-/* RETURNS: */
-/* LVPSA_OK Succeeds */
-/* otherwise Error due to bad parameters */
-/* */
-/************************************************************************************/
-LVPSA_RETURN LVPSA_Control ( pLVPSA_Handle_t hInstance,
- LVPSA_ControlParams_t *pNewParams )
-{
-
- LVPSA_InstancePr_t *pLVPSA_Inst = (LVPSA_InstancePr_t*)hInstance;
-
- if((hInstance == LVM_NULL) || (pNewParams == LVM_NULL))
- {
- return(LVPSA_ERROR_NULLADDRESS);
- }
- if(pNewParams->Fs >= LVPSA_NR_SUPPORTED_RATE)
- {
- return(LVPSA_ERROR_INVALIDPARAM);
- }
- if(pNewParams->LevelDetectionSpeed >= LVPSA_NR_SUPPORTED_SPEED)
- {
- return(LVPSA_ERROR_INVALIDPARAM);
- }
-
- pLVPSA_Inst->NewParams = *pNewParams;
- pLVPSA_Inst->bControlPending = LVM_TRUE;
-
- return(LVPSA_OK);
-}
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVPSA_GetControlParams */
-/* */
-/* DESCRIPTION: */
-/* Get the current control parameters of the module */
-/* */
-/* PARAMETERS: */
-/* hInstance Pointer to the instance */
-/* pParams Pointer to an empty control structure */
-/* RETURNS: */
-/* LVPSA_OK Succeeds */
-/* otherwise Error due to bad parameters */
-/* */
-/************************************************************************************/
-LVPSA_RETURN LVPSA_GetControlParams ( pLVPSA_Handle_t hInstance,
- LVPSA_ControlParams_t *pParams )
-{
- LVPSA_InstancePr_t *pLVPSA_Inst = (LVPSA_InstancePr_t*)hInstance;
-
- if((hInstance == LVM_NULL) || (pParams == LVM_NULL))
- {
- return(LVPSA_ERROR_NULLADDRESS);
- }
-
- pParams->Fs = pLVPSA_Inst->CurrentParams.Fs;
- pParams->LevelDetectionSpeed = pLVPSA_Inst->CurrentParams.LevelDetectionSpeed;
-
- return(LVPSA_OK);
-}
-
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVPSA_GetInitParams */
-/* */
-/* DESCRIPTION: */
-/* Get the initialization parameters of the module */
-/* */
-/* PARAMETERS: */
-/* hInstance Pointer to the instance */
-/* pParams Pointer to an empty control structure */
-/* RETURNS: */
-/* LVPSA_OK Succeeds */
-/* otherwise Error due to bad parameters */
-/* */
-/************************************************************************************/
-LVPSA_RETURN LVPSA_GetInitParams ( pLVPSA_Handle_t hInstance,
- LVPSA_InitParams_t *pParams )
-{
- LVPSA_InstancePr_t *pLVPSA_Inst = (LVPSA_InstancePr_t*)hInstance;
-
- if((hInstance == LVM_NULL) || (pParams == LVM_NULL))
- {
- return(LVPSA_ERROR_NULLADDRESS);
- }
-
- pParams->SpectralDataBufferDuration = pLVPSA_Inst->SpectralDataBufferDuration;
- pParams->MaxInputBlockSize = pLVPSA_Inst->MaxInputBlockSize;
- pParams->nBands = pLVPSA_Inst->nBands;
- pParams->pFiltersParams = pLVPSA_Inst->pFiltersParams;
-
- return(LVPSA_OK);
-}
-
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVPSA_ApplyNewSettings */
-/* */
-/* DESCRIPTION: */
-/* Reinitialize some parameters and changes filters' coefficients if */
-/* some control parameters have changed. */
-/* */
-/* PARAMETERS: */
-/* pInst Pointer to the instance */
-/* */
-/* RETURNS: */
-/* LVPSA_OK Succeeds */
-/* otherwise Error due to bad parameters */
-/* */
-/* NOTES: */
-/* */
-/************************************************************************************/
-LVPSA_RETURN LVPSA_ApplyNewSettings (LVPSA_InstancePr_t *pInst)
-{
- LVM_UINT16 ii;
- LVM_UINT16 Freq;
- LVPSA_ControlParams_t Params;
- extern LVM_INT16 LVPSA_nSamplesBufferUpdate[];
-#ifndef HIGHER_FS
- extern LVM_UINT16 LVPSA_SampleRateTab[];
-#else
- extern LVM_UINT32 LVPSA_SampleRateTab[];
-#endif
- extern LVM_UINT16 LVPSA_DownSamplingFactor[];
-
-
- if(pInst == 0)
- {
- return(LVPSA_ERROR_NULLADDRESS);
- }
-
- Params = pInst->NewParams;
-
- /* Modifies filters types and coefficients, clear the taps and
- re-initializes parameters if sample frequency has changed */
- if(Params.Fs != pInst->CurrentParams.Fs)
- {
- pInst->CurrentParams.Fs = Params.Fs;
-
- /* Initialize the center freqeuncies as a function of the sample rate */
- Freq = (LVM_UINT16) ((LVPSA_SampleRateTab[pInst->CurrentParams.Fs]>>1) / (pInst->nBands + 1));
- for(ii = pInst->nBands; ii > 0; ii--)
- {
- pInst->pFiltersParams[ii-1].CenterFrequency = (LVM_UINT16) (Freq * ii);
- }
-
- /* Count the number of relevant filters. If the center frequency of the filter is
- bigger than the nyquist frequency, then the filter is not relevant and doesn't
- need to be used */
- for(ii = pInst->nBands; ii > 0; ii--)
- {
- if(pInst->pFiltersParams[ii-1].CenterFrequency < (LVPSA_SampleRateTab[pInst->CurrentParams.Fs]>>1))
- {
- pInst->nRelevantFilters = ii;
- break;
- }
- }
- LVPSA_SetBPFiltersType(pInst, &Params);
- LVPSA_SetBPFCoefficients(pInst, &Params);
- LVPSA_SetQPFCoefficients(pInst, &Params);
- LVPSA_ClearFilterHistory(pInst);
- pInst->nSamplesBufferUpdate = (LVM_UINT16)LVPSA_nSamplesBufferUpdate[Params.Fs];
- pInst->BufferUpdateSamplesCount = 0;
- pInst->DownSamplingFactor = LVPSA_DownSamplingFactor[Params.Fs];
- pInst->DownSamplingCount = 0;
- for(ii = 0; ii < (pInst->nBands * pInst->SpectralDataBufferLength); ii++)
- {
- pInst->pSpectralDataBufferStart[ii] = 0;
- }
- for(ii = 0; ii < pInst->nBands; ii++)
- {
- pInst->pPreviousPeaks[ii] = 0;
- }
- }
- else
- {
- if(Params.LevelDetectionSpeed != pInst->CurrentParams.LevelDetectionSpeed)
- {
- LVPSA_SetQPFCoefficients(pInst, &Params);
- }
- }
-
- pInst->CurrentParams = pInst->NewParams;
-
- return (LVPSA_OK);
-}
-/************************************************************************************/
-/* */
-/* FUNCTION: LVPSA_SetBPFiltersType */
-/* */
-/* DESCRIPTION: */
-/* Sets the filter type based on the BPFilterType. */
-/* */
-/* PARAMETERS: */
-/* pInst Pointer to the instance */
-/* pParams Poniter to conrol parameters */
-/* */
-/* RETURNS: */
-/* LVPSA_OK Always succeeds */
-/* */
-/* NOTES: */
-/* 1. To select the biquad type the follow rules are applied: */
-/* Double precision if (fc <= fs/110) */
-/* Double precision if (fs/110 < fc < fs/85) & (Q>3) */
-/* Single precision otherwise */
-/* */
-/************************************************************************************/
-LVPSA_RETURN LVPSA_SetBPFiltersType ( LVPSA_InstancePr_t *pInst,
- LVPSA_ControlParams_t *pParams )
-{
-#ifndef HIGHER_FS
- extern LVM_UINT16 LVPSA_SampleRateTab[]; /* Sample rate table */
-#else
- extern LVM_UINT32 LVPSA_SampleRateTab[]; /* Sample rate table */
-#endif
- LVM_UINT16 ii; /* Filter band index */
- LVM_UINT32 fs = (LVM_UINT32)LVPSA_SampleRateTab[(LVM_UINT16)pParams->Fs]; /* Sample rate */
- LVM_UINT32 fc; /* Filter centre frequency */
- LVM_INT16 QFactor; /* Filter Q factor */
-
- for (ii = 0; ii < pInst->nRelevantFilters; ii++)
- {
- /*
- * Get the filter settings
- */
- fc = (LVM_UINT32)pInst->pFiltersParams[ii].CenterFrequency; /* Get the band centre frequency */
- QFactor =(LVM_INT16) pInst->pFiltersParams[ii].QFactor; /* Get the band Q factor */
-
-
- /*
- * For each filter set the type of biquad required
- */
- pInst->pBPFiltersPrecision[ii] = LVPSA_SimplePrecisionFilter; /* Default to single precision */
- if ((LOW_FREQ * fs) >= (fc << 15))
- {
- /*
- * fc <= fs/110
- */
- pInst->pBPFiltersPrecision[ii] = LVPSA_DoublePrecisionFilter;
- }
- else
- {
- if (((LOW_FREQ * fs) < (fc << 15)) && ((fc << 15) < (HIGH_FREQ * fs)) && (QFactor > 300))
- {
- /*
- * (fs/110 < fc < fs/85) & (Q>3)
- */
- pInst->pBPFiltersPrecision[ii] = LVPSA_DoublePrecisionFilter;
- }
- }
- }
-
- return(LVPSA_OK);
-}
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVPSA_SetBPFCoefficients */
-/* */
-/* DESCRIPTION: */
-/* Sets the band pass filter coefficients. This uses the type to select */
-/* single or double precision coefficients. */
-/* */
-/* PARAMETERS: */
-/* pInst Pointer to the instance */
-/* Params Initialisation parameters */
-/* */
-/* RETURNS: */
-/* LVPSA_OK Always succeeds */
-/* */
-/* NOTES: */
-/* */
-/************************************************************************************/
-LVPSA_RETURN LVPSA_SetBPFCoefficients( LVPSA_InstancePr_t *pInst,
- LVPSA_ControlParams_t *pParams)
-{
-
- LVM_UINT16 ii;
-
- /*
- * Set the coefficients for each band by the init function
- */
- for (ii = 0; ii < pInst->nRelevantFilters; ii++)
- {
- switch (pInst->pBPFiltersPrecision[ii])
- {
- case LVPSA_DoublePrecisionFilter:
- {
-#ifndef BUILD_FLOAT
- BP_C32_Coefs_t Coefficients;
-
- /*
- * Calculate the double precision coefficients
- */
- LVPSA_BPDoublePrecCoefs((LVM_UINT16)pParams->Fs,
- &pInst->pFiltersParams[ii],
- &Coefficients);
- /*
- * Set the coefficients
- */
- BP_1I_D16F32Cll_TRC_WRA_01_Init ( &pInst->pBP_Instances[ii],
- &pInst->pBP_Taps[ii],
- &Coefficients);
-#else
- BP_FLOAT_Coefs_t Coefficients;
- /*
- * Calculate the double precision coefficients
- */
- LVPSA_BPDoublePrecCoefs((LVM_UINT16)pParams->Fs,
- &pInst->pFiltersParams[ii],
- &Coefficients);
- /*
- * Set the coefficients
- */
- BP_1I_D16F32Cll_TRC_WRA_01_Init ( &pInst->pBP_Instances[ii],
- &pInst->pBP_Taps[ii],
- &Coefficients);
-#endif
- break;
- }
-
- case LVPSA_SimplePrecisionFilter:
- {
-#ifndef BUILD_FLOAT
- BP_C16_Coefs_t Coefficients;
-
- /*
- * Calculate the single precision coefficients
- */
- LVPSA_BPSinglePrecCoefs((LVM_UINT16)pParams->Fs,
- &pInst->pFiltersParams[ii],
- &Coefficients);
-
- /*
- * Set the coefficients
- */
- BP_1I_D16F16Css_TRC_WRA_01_Init (&pInst->pBP_Instances[ii],
- &pInst->pBP_Taps[ii],
- &Coefficients);
-#else
- BP_FLOAT_Coefs_t Coefficients;
-
- /*
- * Calculate the single precision coefficients
- */
- LVPSA_BPSinglePrecCoefs((LVM_UINT16)pParams->Fs,
- &pInst->pFiltersParams[ii],
- &Coefficients);
-
- /*
- * Set the coefficients
- */
- BP_1I_D16F16Css_TRC_WRA_01_Init (&pInst->pBP_Instances[ii],
- &pInst->pBP_Taps[ii],
- &Coefficients);
-#endif
- break;
- }
- }
- }
-
- return(LVPSA_OK);
-}
-
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVPSA_SetQPFCoefficients */
-/* */
-/* DESCRIPTION: */
-/* Sets the quasi peak filters coefficients. This uses the chosen */
-/* LevelDetectionSpeed from the control parameters. */
-/* */
-/* PARAMETERS: */
-/* pInst Pointer to the instance */
-/* Params Control parameters */
-/* */
-/* RETURNS: */
-/* LVPSA_OK Always succeeds */
-/* */
-/* NOTES: */
-/* */
-/************************************************************************************/
-LVPSA_RETURN LVPSA_SetQPFCoefficients( LVPSA_InstancePr_t *pInst,
- LVPSA_ControlParams_t *pParams )
-{
- LVM_UINT16 ii;
- LVM_Fs_en Fs = pParams->Fs;
-#ifndef BUILD_FLOAT
- QPD_C32_Coefs *pCoefficients;
- extern QPD_C32_Coefs LVPSA_QPD_Coefs[];
-
- pCoefficients = &LVPSA_QPD_Coefs[(pParams->LevelDetectionSpeed * LVPSA_NR_SUPPORTED_RATE) + Fs];
-#else
- QPD_FLOAT_Coefs *pCoefficients;
- extern QPD_FLOAT_Coefs LVPSA_QPD_Float_Coefs[];
-
- pCoefficients = &LVPSA_QPD_Float_Coefs[(pParams->LevelDetectionSpeed * \
- LVPSA_NR_SUPPORTED_RATE) + Fs];
-#endif
-
-
- for (ii = 0; ii < pInst->nRelevantFilters; ii++)
- {
-#ifndef BUILD_FLOAT
- LVPSA_QPD_Init (&pInst->pQPD_States[ii],
- &pInst->pQPD_Taps[ii],
- pCoefficients );
-#else
- LVPSA_QPD_Init_Float (&pInst->pQPD_States[ii],
- &pInst->pQPD_Taps[ii],
- pCoefficients );
-#endif
- }
-
- return(LVPSA_OK);
-
-}
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVPSA_BPSinglePrecCoefs */
-/* */
-/* DESCRIPTION: */
-/* Calculate single precision coefficients for a band pass filter */
-/* */
-/* PARAMETERS: */
-/* Fs Sampling frequency index */
-/* pFilterParams Pointer to the filter definition */
-/* pCoefficients Pointer to the coefficients */
-/* */
-/* RETURNS: */
-/* LVPSA_OK Always succeeds */
-/* */
-/* NOTES: */
-/* 1. The equations used are as follows: */
-/* */
-/* t0 = 2 * Pi * Fc / Fs */
-/* */
-/* b2 = -0.5 * (2Q - t0) / (2Q + t0) */
-/* b1 = (0.5 - b2) * cos(t0) */
-/* a0 = (0.5 + b2) / 2 */
-/* */
-/* Where: */
-/* Fc is the centre frequency, DC to Nyquist */
-/* Fs is the sample frequency, 8000 to 48000 in descrete steps */
-/* Q is the Q factor, 0.25 to 12 */
-/* */
-/* 2. This function is entirely based on the LVEQNB_SinglePrecCoefs function */
-/* of the n bands equalizer (LVEQNB */
-/* */
-/****************************************************************************************/
-#ifdef BUILD_FLOAT
-LVPSA_RETURN LVPSA_BPSinglePrecCoefs( LVM_UINT16 Fs,
- LVPSA_FilterParam_t *pFilterParams,
- BP_FLOAT_Coefs_t *pCoefficients)
-{
-
- extern LVM_FLOAT LVPSA_Float_TwoPiOnFsTable[];
- extern LVM_FLOAT LVPSA_Float_CosCoef[];
-
-
- /*
- * Intermediate variables and temporary values
- */
- LVM_FLOAT T0;
- LVM_FLOAT D;
- LVM_FLOAT A0;
- LVM_FLOAT B1;
- LVM_FLOAT B2;
- LVM_FLOAT Dt0;
- LVM_FLOAT B2_Den;
- LVM_FLOAT B2_Num;
- LVM_FLOAT COS_T0;
- LVM_FLOAT coef;
- LVM_FLOAT factor;
- LVM_FLOAT t0;
- LVM_INT16 i;
-
-
- /*
- * Get the filter definition
- */
- LVM_FLOAT Frequency = (LVM_FLOAT)(pFilterParams->CenterFrequency);
- LVM_FLOAT QFactor = ((LVM_FLOAT)(pFilterParams->QFactor)) / 100;
-
- /*
- * Calculating the intermediate values
- */
- T0 = Frequency * LVPSA_Float_TwoPiOnFsTable[Fs]; /* T0 = 2 * Pi * Fc / Fs */
- D = 3200; /* Floating point value 1.000000 (1*100*2^5) */
- /* Force D = 1 : the function was originally used for a peaking filter.
- The D parameter do not exist for a BandPass filter coefficients */
-
- /*
- * Calculate the B2 coefficient
- */
- Dt0 = T0 / 2048 ;
- B2_Den = QFactor + Dt0;
- B2_Num = Dt0 - QFactor;
- B2 = B2_Num / (2 * B2_Den);
-
- /*
- * Calculate the cosine by a polynomial expansion using the equation:
- *
- * Cos += coef(n) * t0^n For n = 0 to 6
- */
- T0 = (T0 / 2048) * 0.63658558f; /* Scale to 1.0 in 16-bit for range 0 to fs/2 */
- t0 = T0 ;
- factor = 1.0f; /* Initialise to 1.0 for the a0 coefficient */
- COS_T0 = 0.0f; /* Initialise the error to zero */
- for (i = 1; i < 7; i++)
- {
- coef = LVPSA_Float_CosCoef[i]; /* Get the nth coefficient */
- COS_T0 += (factor * coef); /* The nth partial sum */
- factor = (factor * t0) ; /* Calculate t0^n */
- }
- COS_T0 = COS_T0 * 8; /*LVPSA_CosCoef_float[0]*/ /* Correct the scaling */
-
-
- B1 = ((LVM_FLOAT)0.5 - B2) * (COS_T0); /* B1 = (0.5 - b2) * cos(t0) */
- A0 = ((LVM_FLOAT)0.5 + B2) / 2; /* A0 = (0.5 + b2) / 2 */
-
- /*
- * Write coeff into the data structure
- */
- pCoefficients->A0 = A0 * 2;
- pCoefficients->B1 = B1 * 2;
- pCoefficients->B2 = B2 * 2;
-
- return(LVPSA_OK);
-}
-#else
-LVPSA_RETURN LVPSA_BPSinglePrecCoefs( LVM_UINT16 Fs,
- LVPSA_FilterParam_t *pFilterParams,
- BP_C16_Coefs_t *pCoefficients)
-{
-
- extern LVM_INT16 LVPSA_TwoPiOnFsTable[];
- extern LVM_INT16 LVPSA_CosCoef[];
-
-
- /*
- * Intermediate variables and temporary values
- */
- LVM_INT32 T0;
- LVM_INT16 D;
- LVM_INT32 A0;
- LVM_INT32 B1;
- LVM_INT32 B2;
- LVM_INT32 Dt0;
- LVM_INT32 B2_Den;
- LVM_INT32 B2_Num;
- LVM_INT32 COS_T0;
- LVM_INT16 coef;
- LVM_INT32 factor;
- LVM_INT16 t0;
- LVM_INT16 i;
-
-
- /*
- * Get the filter definition
- */
- LVM_UINT16 Frequency = pFilterParams->CenterFrequency;
- LVM_UINT16 QFactor = pFilterParams->QFactor;
-
-
- /*
- * Calculating the intermediate values
- */
- T0 = (LVM_INT32)Frequency * LVPSA_TwoPiOnFsTable[Fs]; /* T0 = 2 * Pi * Fc / Fs */
- D = 3200; /* Floating point value 1.000000 (1*100*2^5) */
- /* Force D = 1 : the function was originally used for a peaking filter.
- The D parameter do not exist for a BandPass filter coefficients */
-
- /*
- * Calculate the B2 coefficient
- */
- Dt0 = D * (T0 >> 10);
- B2_Den = (LVM_INT32)(((LVM_UINT32)QFactor << 19) + (LVM_UINT32)(Dt0 >> 2));
- B2_Num = (LVM_INT32)((LVM_UINT32)(Dt0 >> 3) - ((LVM_UINT32)QFactor << 18));
- B2 = (B2_Num / (B2_Den >> 16)) << 15;
-
- /*
- * Calculate the cosine by a polynomial expansion using the equation:
- *
- * Cos += coef(n) * t0^n For n = 0 to 6
- */
- T0 = (T0 >> 10) * 20859; /* Scale to 1.0 in 16-bit for range 0 to fs/2 */
- t0 = (LVM_INT16)(T0 >> 16);
- factor = 0x7fff; /* Initialise to 1.0 for the a0 coefficient */
- COS_T0 = 0; /* Initialise the error to zero */
- for (i=1; i<7; i++)
- {
- coef = LVPSA_CosCoef[i]; /* Get the nth coefficient */
- COS_T0 += (factor * coef) >> 5; /* The nth partial sum */
- factor = (factor * t0) >> 15; /* Calculate t0^n */
- }
- COS_T0 = COS_T0 << (LVPSA_CosCoef[0]+6); /* Correct the scaling */
-
-
- B1 = ((0x40000000 - B2) >> 16) * (COS_T0 >> 16); /* B1 = (0.5 - b2) * cos(t0) */
- A0 = (0x40000000 + B2) >> 1; /* A0 = (0.5 + b2) / 2 */
-
- /*
- * Write coeff into the data structure
- */
- pCoefficients->A0 = (LVM_INT16)(A0>>16);
- pCoefficients->B1 = (LVM_INT16)(B1>>15);
- pCoefficients->B2 = (LVM_INT16)(B2>>16);
-
-
- return(LVPSA_OK);
-}
-#endif
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVPSA_BPDoublePrecCoefs */
-/* */
-/* DESCRIPTION: */
-/* Calculate double precision coefficients for a band pass filter */
-/* */
-/* PARAMETERS: */
-/* Fs Sampling frequency index */
-/* pFilterParams Pointer to the filter definition */
-/* pCoefficients Pointer to the coefficients */
-/* */
-/* RETURNS: */
-/* LVPSA_OK Always succeeds */
-/* */
-/* NOTES: */
-/* 1. The equations used are as follows: */
-/* */
-/* t0 = 2 * Pi * Fc / Fs */
-/* */
-/* b2 = -0.5 * (2Q - t0) / (2Q + t0) */
-/* b1 = (0.5 - b2) * (1 - coserr(t0)) */
-/* a0 = (0.5 + b2) / 2 */
-/* */
-/* Where: */
-/* Fc is the centre frequency, DC to Fs/50 */
-/* Fs is the sample frequency, 8000 to 48000 in descrete steps */
-/* Q is the Q factor, 0.25 to 12 (represented by 25 to 1200) */
-/* */
-/* 2. The double precision coefficients are only used when fc is less than fs/85, so */
-/* the cosine of t0 is always close to 1.0. Instead of calculating the cosine */
-/* itself the difference from the value 1.0 is calculated, this can be done with */
-/* lower precision maths. */
-/* */
-/* 3. The value of the B2 coefficient is only calculated as a single precision value, */
-/* small errors in this value have a combined effect on the Q and Gain but not the */
-/* the frequency of the filter. */
-/* */
-/* 4. This function is entirely based on the LVEQNB_DoublePrecCoefs function */
-/* of the n bands equalizer (LVEQNB */
-/* */
-/****************************************************************************************/
-#ifdef BUILD_FLOAT
-LVPSA_RETURN LVPSA_BPDoublePrecCoefs( LVM_UINT16 Fs,
- LVPSA_FilterParam_t *pFilterParams,
- BP_FLOAT_Coefs_t *pCoefficients)
-{
-
- extern LVM_FLOAT LVPSA_Float_TwoPiOnFsTable[];
- extern LVM_FLOAT LVPSA_Float_DPCosCoef[];
-
- /*
- * Intermediate variables and temporary values
- */
- LVM_FLOAT T0;
- LVM_FLOAT D;
- LVM_FLOAT A0;
- LVM_FLOAT B1;
- LVM_FLOAT B2;
- LVM_FLOAT Dt0;
- LVM_FLOAT B2_Den;
- LVM_FLOAT B2_Num;
- LVM_FLOAT CosErr;
- LVM_FLOAT coef;
- LVM_FLOAT factor;
- LVM_FLOAT t0;
- LVM_INT16 i;
-
- /*
- * Get the filter definition
- */
- LVM_FLOAT Frequency = (LVM_FLOAT)(pFilterParams->CenterFrequency);
- LVM_FLOAT QFactor = ((LVM_FLOAT)(pFilterParams->QFactor)) / 100;
-
-
- /*
- * Calculating the intermediate values
- */
- T0 = Frequency * LVPSA_Float_TwoPiOnFsTable[Fs]; /* T0 = 2 * Pi * Fc / Fs */
- D = 3200; /* Floating point value 1.000000 (1*100*2^5) */
- /* Force D = 1 : the function was originally used for a peaking filter.
- The D parameter do not exist for a BandPass filter coefficients */
-
- /*
- * Calculate the B2 coefficient
- */
- Dt0 = T0 / 2048 ;
- B2_Den = QFactor + Dt0;
- B2_Num = Dt0 - QFactor;
- B2 = B2_Num / (2 * B2_Den);
-
- /*
- * Calculate the cosine error by a polynomial expansion using the equation:
- *
- * CosErr += coef(n) * t0^n For n = 0 to 4
- */
- T0 = T0 * 0.994750f; /* Scale to 1.0 in 16-bit for range 0 to fs/50 */
- t0 = T0;
- factor = 1.0f; /* Initialise to 1.0 for the a0 coefficient */
- CosErr = 0.0f; /* Initialise the error to zero */
- for (i = 1; i < 5; i++)
- {
- coef = LVPSA_Float_DPCosCoef[i]; /* Get the nth coefficient */
- CosErr += factor * coef; /* The nth partial sum */
- factor = factor * t0; /* Calculate t0^n */
- }
- CosErr = CosErr * 2; /* Correct the scaling */
-
- /*
- * Calculate the B1 and A0 coefficients
- */
- B1 = ((LVM_FLOAT)0.5 - B2); /* B1 = (0.5 - b2) */
- A0 = B1 * CosErr ; /* Temporary storage for (0.5 - b2) * coserr(t0) */
- B1 -= A0; /* B1 = (0.5 - b2) * (1 - coserr(t0)) */
- A0 = ((LVM_FLOAT)0.5 + B2) / 2; /* A0 = (0.5 + b2) / 2 */
-
- /*
- * Write coeff into the data structure
- */
- pCoefficients->A0 = A0;
- pCoefficients->B1 = B1;
- pCoefficients->B2 = B2;
-
- return(LVPSA_OK);
-}
-#else
-LVPSA_RETURN LVPSA_BPDoublePrecCoefs( LVM_UINT16 Fs,
- LVPSA_FilterParam_t *pFilterParams,
- BP_C32_Coefs_t *pCoefficients)
-{
-
- extern LVM_INT16 LVPSA_TwoPiOnFsTable[];
- extern LVM_INT16 LVPSA_DPCosCoef[];
-
- /*
- * Intermediate variables and temporary values
- */
- LVM_INT32 T0;
- LVM_INT16 D;
- LVM_INT32 A0;
- LVM_INT32 B1;
- LVM_INT32 B2;
- LVM_INT32 Dt0;
- LVM_INT32 B2_Den;
- LVM_INT32 B2_Num;
- LVM_INT32 CosErr;
- LVM_INT16 coef;
- LVM_INT32 factor;
- LVM_INT16 t0;
- LVM_INT16 i;
-
- /*
- * Get the filter definition
- */
- LVM_UINT16 Frequency = pFilterParams->CenterFrequency;
- LVM_UINT16 QFactor = pFilterParams->QFactor;
-
-
- /*
- * Calculating the intermediate values
- */
- T0 = (LVM_INT32)Frequency * LVPSA_TwoPiOnFsTable[Fs]; /* T0 = 2 * Pi * Fc / Fs */
- D = 3200; /* Floating point value 1.000000 (1*100*2^5) */
- /* Force D = 1 : the function was originally used for a peaking filter.
- The D parameter do not exist for a BandPass filter coefficients */
-
- /*
- * Calculate the B2 coefficient
- */
- Dt0 = D * (T0 >> 10);
- B2_Den = (LVM_INT32)(((LVM_UINT32)QFactor << 19) + (LVM_UINT32)(Dt0 >> 2));
- B2_Num = (LVM_INT32)((LVM_UINT32)(Dt0 >> 3) - ((LVM_UINT32)QFactor << 18));
- B2 = (B2_Num / (B2_Den >> 16)) << 15;
-
- /*
- * Calculate the cosine error by a polynomial expansion using the equation:
- *
- * CosErr += coef(n) * t0^n For n = 0 to 4
- */
- T0 = (T0 >> 6) * 0x7f53; /* Scale to 1.0 in 16-bit for range 0 to fs/50 */
- t0 = (LVM_INT16)(T0 >> 16);
- factor = 0x7fff; /* Initialise to 1.0 for the a0 coefficient */
- CosErr = 0; /* Initialise the error to zero */
- for (i=1; i<5; i++)
- {
- coef = LVPSA_DPCosCoef[i]; /* Get the nth coefficient */
- CosErr += (factor * coef) >> 5; /* The nth partial sum */
- factor = (factor * t0) >> 15; /* Calculate t0^n */
- }
- CosErr = CosErr << (LVPSA_DPCosCoef[0]); /* Correct the scaling */
-
- /*
- * Calculate the B1 and A0 coefficients
- */
- B1 = (0x40000000 - B2); /* B1 = (0.5 - b2) */
- A0 = ((B1 >> 16) * (CosErr >> 10)) >> 6; /* Temporary storage for (0.5 - b2) * coserr(t0) */
- B1 -= A0; /* B1 = (0.5 - b2) * (1 - coserr(t0)) */
- A0 = (0x40000000 + B2) >> 1; /* A0 = (0.5 + b2) / 2 */
-
- /*
- * Write coeff into the data structure
- */
- pCoefficients->A0 = A0;
- pCoefficients->B1 = B1;
- pCoefficients->B2 = B2;
-
- return(LVPSA_OK);
-}
-#endif
-/************************************************************************************/
-/* */
-/* FUNCTION: LVPSA_ClearFilterHistory */
-/* */
-/* DESCRIPTION: */
-/* Clears the filters' data history */
-/* */
-/* PARAMETERS: */
-/* pInst Pointer to the instance */
-/* */
-/* RETURNS: */
-/* LVPSA_OK Always succeeds */
-/* */
-/* NOTES: */
-/* */
-/************************************************************************************/
-LVPSA_RETURN LVPSA_ClearFilterHistory(LVPSA_InstancePr_t *pInst)
-{
- LVM_INT8 *pTapAddress;
- LVM_UINT32 i;
-
- /* Band Pass filters taps */
- pTapAddress = (LVM_INT8 *)pInst->pBP_Taps;
-#ifdef BUILD_FLOAT
- for(i = 0; i < pInst->nBands * sizeof(Biquad_1I_Order2_FLOAT_Taps_t); i++)
- {
- pTapAddress[i] = 0;
- }
-#else
- for(i = 0; i < pInst->nBands * sizeof(Biquad_1I_Order2_Taps_t); i++)
- {
- pTapAddress[i] = 0;
- }
-#endif
- /* Quasi-peak filters taps */
- pTapAddress = (LVM_INT8 *)pInst->pQPD_Taps;
- for(i = 0; i < pInst->nBands * sizeof(QPD_Taps_t); i++)
- {
- pTapAddress[i] = 0;
- }
-
- return(LVPSA_OK);
-}
-
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Control.cpp b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Control.cpp
new file mode 100644
index 0000000..deafaa7
--- /dev/null
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Control.cpp
@@ -0,0 +1,681 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LVPSA.h"
+#include "LVPSA_Private.h"
+#include "VectorArithmetic.h"
+
+#define LOW_FREQ 298 /* 32768/110 for low test frequency */
+#define HIGH_FREQ 386 /* 32768/85 for high test frequency */
+
+LVPSA_RETURN LVPSA_SetBPFiltersType ( LVPSA_InstancePr_t *pInst,
+ LVPSA_ControlParams_t *pParams );
+
+LVPSA_RETURN LVPSA_SetQPFCoefficients( LVPSA_InstancePr_t *pInst,
+ LVPSA_ControlParams_t *pParams );
+
+LVPSA_RETURN LVPSA_BPSinglePrecCoefs( LVM_UINT16 Fs,
+ LVPSA_FilterParam_t *pFilterParams,
+ BP_FLOAT_Coefs_t *pCoefficients);
+
+LVPSA_RETURN LVPSA_BPDoublePrecCoefs( LVM_UINT16 Fs,
+ LVPSA_FilterParam_t *pFilterParams,
+ BP_FLOAT_Coefs_t *pCoefficients);
+LVPSA_RETURN LVPSA_SetBPFCoefficients( LVPSA_InstancePr_t *pInst,
+ LVPSA_ControlParams_t *pParams );
+
+LVPSA_RETURN LVPSA_ClearFilterHistory( LVPSA_InstancePr_t *pInst);
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVPSA_Control */
+/* */
+/* DESCRIPTION: */
+/* Give some new control parameters to the module. */
+/* */
+/* PARAMETERS: */
+/* hInstance Pointer to the instance */
+/* NewParams Structure that contains the new parameters */
+/* */
+/* RETURNS: */
+/* LVPSA_OK Succeeds */
+/* otherwise Error due to bad parameters */
+/* */
+/************************************************************************************/
+LVPSA_RETURN LVPSA_Control ( pLVPSA_Handle_t hInstance,
+ LVPSA_ControlParams_t *pNewParams )
+{
+
+ LVPSA_InstancePr_t *pLVPSA_Inst = (LVPSA_InstancePr_t*)hInstance;
+
+ if((hInstance == LVM_NULL) || (pNewParams == LVM_NULL))
+ {
+ return(LVPSA_ERROR_NULLADDRESS);
+ }
+ if(pNewParams->Fs >= LVPSA_NR_SUPPORTED_RATE)
+ {
+ return(LVPSA_ERROR_INVALIDPARAM);
+ }
+ if(pNewParams->LevelDetectionSpeed >= LVPSA_NR_SUPPORTED_SPEED)
+ {
+ return(LVPSA_ERROR_INVALIDPARAM);
+ }
+
+ pLVPSA_Inst->NewParams = *pNewParams;
+ pLVPSA_Inst->bControlPending = LVM_TRUE;
+
+ return(LVPSA_OK);
+}
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVPSA_GetControlParams */
+/* */
+/* DESCRIPTION: */
+/* Get the current control parameters of the module */
+/* */
+/* PARAMETERS: */
+/* hInstance Pointer to the instance */
+/* pParams Pointer to an empty control structure */
+/* RETURNS: */
+/* LVPSA_OK Succeeds */
+/* otherwise Error due to bad parameters */
+/* */
+/************************************************************************************/
+LVPSA_RETURN LVPSA_GetControlParams ( pLVPSA_Handle_t hInstance,
+ LVPSA_ControlParams_t *pParams )
+{
+ LVPSA_InstancePr_t *pLVPSA_Inst = (LVPSA_InstancePr_t*)hInstance;
+
+ if((hInstance == LVM_NULL) || (pParams == LVM_NULL))
+ {
+ return(LVPSA_ERROR_NULLADDRESS);
+ }
+
+ pParams->Fs = pLVPSA_Inst->CurrentParams.Fs;
+ pParams->LevelDetectionSpeed = pLVPSA_Inst->CurrentParams.LevelDetectionSpeed;
+
+ return(LVPSA_OK);
+}
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVPSA_GetInitParams */
+/* */
+/* DESCRIPTION: */
+/* Get the initialization parameters of the module */
+/* */
+/* PARAMETERS: */
+/* hInstance Pointer to the instance */
+/* pParams Pointer to an empty control structure */
+/* RETURNS: */
+/* LVPSA_OK Succeeds */
+/* otherwise Error due to bad parameters */
+/* */
+/************************************************************************************/
+LVPSA_RETURN LVPSA_GetInitParams ( pLVPSA_Handle_t hInstance,
+ LVPSA_InitParams_t *pParams )
+{
+ LVPSA_InstancePr_t *pLVPSA_Inst = (LVPSA_InstancePr_t*)hInstance;
+
+ if((hInstance == LVM_NULL) || (pParams == LVM_NULL))
+ {
+ return(LVPSA_ERROR_NULLADDRESS);
+ }
+
+ pParams->SpectralDataBufferDuration = pLVPSA_Inst->SpectralDataBufferDuration;
+ pParams->MaxInputBlockSize = pLVPSA_Inst->MaxInputBlockSize;
+ pParams->nBands = pLVPSA_Inst->nBands;
+ pParams->pFiltersParams = pLVPSA_Inst->pFiltersParams;
+
+ return(LVPSA_OK);
+}
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVPSA_ApplyNewSettings */
+/* */
+/* DESCRIPTION: */
+/* Reinitialize some parameters and changes filters' coefficients if */
+/* some control parameters have changed. */
+/* */
+/* PARAMETERS: */
+/* pInst Pointer to the instance */
+/* */
+/* RETURNS: */
+/* LVPSA_OK Succeeds */
+/* otherwise Error due to bad parameters */
+/* */
+/* NOTES: */
+/* */
+/************************************************************************************/
+LVPSA_RETURN LVPSA_ApplyNewSettings (LVPSA_InstancePr_t *pInst)
+{
+ LVM_UINT16 ii;
+ LVM_UINT16 Freq;
+ LVPSA_ControlParams_t Params;
+ extern LVM_INT16 LVPSA_nSamplesBufferUpdate[];
+ extern LVM_UINT32 LVPSA_SampleRateTab[];
+ extern LVM_UINT16 LVPSA_DownSamplingFactor[];
+
+ if(pInst == 0)
+ {
+ return(LVPSA_ERROR_NULLADDRESS);
+ }
+
+ Params = pInst->NewParams;
+
+ /* Modifies filters types and coefficients, clear the taps and
+ re-initializes parameters if sample frequency has changed */
+ if(Params.Fs != pInst->CurrentParams.Fs)
+ {
+ pInst->CurrentParams.Fs = Params.Fs;
+
+ /* Initialize the center freqeuncies as a function of the sample rate */
+ Freq = (LVM_UINT16) ((LVPSA_SampleRateTab[pInst->CurrentParams.Fs]>>1) / (pInst->nBands + 1));
+ for(ii = pInst->nBands; ii > 0; ii--)
+ {
+ pInst->pFiltersParams[ii-1].CenterFrequency = (LVM_UINT16) (Freq * ii);
+ }
+
+ /* Count the number of relevant filters. If the center frequency of the filter is
+ bigger than the nyquist frequency, then the filter is not relevant and doesn't
+ need to be used */
+ for(ii = pInst->nBands; ii > 0; ii--)
+ {
+ if(pInst->pFiltersParams[ii-1].CenterFrequency < (LVPSA_SampleRateTab[pInst->CurrentParams.Fs]>>1))
+ {
+ pInst->nRelevantFilters = ii;
+ break;
+ }
+ }
+ LVPSA_SetBPFiltersType(pInst, &Params);
+ LVPSA_SetBPFCoefficients(pInst, &Params);
+ LVPSA_SetQPFCoefficients(pInst, &Params);
+ LVPSA_ClearFilterHistory(pInst);
+ pInst->nSamplesBufferUpdate = (LVM_UINT16)LVPSA_nSamplesBufferUpdate[Params.Fs];
+ pInst->BufferUpdateSamplesCount = 0;
+ pInst->DownSamplingFactor = LVPSA_DownSamplingFactor[Params.Fs];
+ pInst->DownSamplingCount = 0;
+ for(ii = 0; ii < (pInst->nBands * pInst->SpectralDataBufferLength); ii++)
+ {
+ pInst->pSpectralDataBufferStart[ii] = 0;
+ }
+ for(ii = 0; ii < pInst->nBands; ii++)
+ {
+ pInst->pPreviousPeaks[ii] = 0;
+ }
+ }
+ else
+ {
+ if(Params.LevelDetectionSpeed != pInst->CurrentParams.LevelDetectionSpeed)
+ {
+ LVPSA_SetQPFCoefficients(pInst, &Params);
+ }
+ }
+
+ pInst->CurrentParams = pInst->NewParams;
+
+ return (LVPSA_OK);
+}
+/************************************************************************************/
+/* */
+/* FUNCTION: LVPSA_SetBPFiltersType */
+/* */
+/* DESCRIPTION: */
+/* Sets the filter type based on the BPFilterType. */
+/* */
+/* PARAMETERS: */
+/* pInst Pointer to the instance */
+/* pParams Poniter to conrol parameters */
+/* */
+/* RETURNS: */
+/* LVPSA_OK Always succeeds */
+/* */
+/* NOTES: */
+/* 1. To select the biquad type the follow rules are applied: */
+/* Double precision if (fc <= fs/110) */
+/* Double precision if (fs/110 < fc < fs/85) & (Q>3) */
+/* Single precision otherwise */
+/* */
+/************************************************************************************/
+LVPSA_RETURN LVPSA_SetBPFiltersType ( LVPSA_InstancePr_t *pInst,
+ LVPSA_ControlParams_t *pParams )
+{
+ extern LVM_UINT32 LVPSA_SampleRateTab[]; /* Sample rate table */
+ LVM_UINT16 ii; /* Filter band index */
+ LVM_UINT32 fs = (LVM_UINT32)LVPSA_SampleRateTab[(LVM_UINT16)pParams->Fs]; /* Sample rate */
+ LVM_UINT32 fc; /* Filter centre frequency */
+ LVM_INT16 QFactor; /* Filter Q factor */
+
+ for (ii = 0; ii < pInst->nRelevantFilters; ii++)
+ {
+ /*
+ * Get the filter settings
+ */
+ fc = (LVM_UINT32)pInst->pFiltersParams[ii].CenterFrequency; /* Get the band centre frequency */
+ QFactor =(LVM_INT16) pInst->pFiltersParams[ii].QFactor; /* Get the band Q factor */
+
+ /*
+ * For each filter set the type of biquad required
+ */
+ pInst->pBPFiltersPrecision[ii] = LVPSA_SimplePrecisionFilter; /* Default to single precision */
+ if ((LOW_FREQ * fs) >= (fc << 15))
+ {
+ /*
+ * fc <= fs/110
+ */
+ pInst->pBPFiltersPrecision[ii] = LVPSA_DoublePrecisionFilter;
+ }
+ else
+ {
+ if (((LOW_FREQ * fs) < (fc << 15)) && ((fc << 15) < (HIGH_FREQ * fs)) && (QFactor > 300))
+ {
+ /*
+ * (fs/110 < fc < fs/85) & (Q>3)
+ */
+ pInst->pBPFiltersPrecision[ii] = LVPSA_DoublePrecisionFilter;
+ }
+ }
+ }
+
+ return(LVPSA_OK);
+}
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVPSA_SetBPFCoefficients */
+/* */
+/* DESCRIPTION: */
+/* Sets the band pass filter coefficients. This uses the type to select */
+/* single or double precision coefficients. */
+/* */
+/* PARAMETERS: */
+/* pInst Pointer to the instance */
+/* Params Initialisation parameters */
+/* */
+/* RETURNS: */
+/* LVPSA_OK Always succeeds */
+/* */
+/* NOTES: */
+/* */
+/************************************************************************************/
+LVPSA_RETURN LVPSA_SetBPFCoefficients( LVPSA_InstancePr_t *pInst,
+ LVPSA_ControlParams_t *pParams)
+{
+
+ LVM_UINT16 ii;
+
+ /*
+ * Set the coefficients for each band by the init function
+ */
+ for (ii = 0; ii < pInst->nRelevantFilters; ii++)
+ {
+ switch (pInst->pBPFiltersPrecision[ii])
+ {
+ case LVPSA_DoublePrecisionFilter:
+ {
+ BP_FLOAT_Coefs_t Coefficients;
+ /*
+ * Calculate the double precision coefficients
+ */
+ LVPSA_BPDoublePrecCoefs((LVM_UINT16)pParams->Fs,
+ &pInst->pFiltersParams[ii],
+ &Coefficients);
+ /*
+ * Set the coefficients
+ */
+ BP_1I_D16F32Cll_TRC_WRA_01_Init ( &pInst->pBP_Instances[ii],
+ &pInst->pBP_Taps[ii],
+ &Coefficients);
+ break;
+ }
+
+ case LVPSA_SimplePrecisionFilter:
+ {
+ BP_FLOAT_Coefs_t Coefficients;
+
+ /*
+ * Calculate the single precision coefficients
+ */
+ LVPSA_BPSinglePrecCoefs((LVM_UINT16)pParams->Fs,
+ &pInst->pFiltersParams[ii],
+ &Coefficients);
+
+ /*
+ * Set the coefficients
+ */
+ BP_1I_D16F16Css_TRC_WRA_01_Init (&pInst->pBP_Instances[ii],
+ &pInst->pBP_Taps[ii],
+ &Coefficients);
+ break;
+ }
+ }
+ }
+
+ return(LVPSA_OK);
+}
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVPSA_SetQPFCoefficients */
+/* */
+/* DESCRIPTION: */
+/* Sets the quasi peak filters coefficients. This uses the chosen */
+/* LevelDetectionSpeed from the control parameters. */
+/* */
+/* PARAMETERS: */
+/* pInst Pointer to the instance */
+/* Params Control parameters */
+/* */
+/* RETURNS: */
+/* LVPSA_OK Always succeeds */
+/* */
+/* NOTES: */
+/* */
+/************************************************************************************/
+LVPSA_RETURN LVPSA_SetQPFCoefficients( LVPSA_InstancePr_t *pInst,
+ LVPSA_ControlParams_t *pParams )
+{
+ LVM_UINT16 ii;
+ LVM_Fs_en Fs = pParams->Fs;
+ QPD_FLOAT_Coefs *pCoefficients;
+ extern QPD_FLOAT_Coefs LVPSA_QPD_Float_Coefs[];
+
+ pCoefficients = &LVPSA_QPD_Float_Coefs[(pParams->LevelDetectionSpeed * \
+ LVPSA_NR_SUPPORTED_RATE) + Fs];
+
+ for (ii = 0; ii < pInst->nRelevantFilters; ii++)
+ {
+ LVPSA_QPD_Init_Float (&pInst->pQPD_States[ii],
+ &pInst->pQPD_Taps[ii],
+ pCoefficients );
+ }
+
+ return(LVPSA_OK);
+
+}
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVPSA_BPSinglePrecCoefs */
+/* */
+/* DESCRIPTION: */
+/* Calculate single precision coefficients for a band pass filter */
+/* */
+/* PARAMETERS: */
+/* Fs Sampling frequency index */
+/* pFilterParams Pointer to the filter definition */
+/* pCoefficients Pointer to the coefficients */
+/* */
+/* RETURNS: */
+/* LVPSA_OK Always succeeds */
+/* */
+/* NOTES: */
+/* 1. The equations used are as follows: */
+/* */
+/* t0 = 2 * Pi * Fc / Fs */
+/* */
+/* b2 = -0.5 * (2Q - t0) / (2Q + t0) */
+/* b1 = (0.5 - b2) * cos(t0) */
+/* a0 = (0.5 + b2) / 2 */
+/* */
+/* Where: */
+/* Fc is the centre frequency, DC to Nyquist */
+/* Fs is the sample frequency, 8000 to 48000 in descrete steps */
+/* Q is the Q factor, 0.25 to 12 */
+/* */
+/* 2. This function is entirely based on the LVEQNB_SinglePrecCoefs function */
+/* of the n bands equalizer (LVEQNB */
+/* */
+/****************************************************************************************/
+LVPSA_RETURN LVPSA_BPSinglePrecCoefs( LVM_UINT16 Fs,
+ LVPSA_FilterParam_t *pFilterParams,
+ BP_FLOAT_Coefs_t *pCoefficients)
+{
+
+ extern LVM_FLOAT LVPSA_Float_TwoPiOnFsTable[];
+ extern LVM_FLOAT LVPSA_Float_CosCoef[];
+
+ /*
+ * Intermediate variables and temporary values
+ */
+ LVM_FLOAT T0;
+ LVM_FLOAT D;
+ LVM_FLOAT A0;
+ LVM_FLOAT B1;
+ LVM_FLOAT B2;
+ LVM_FLOAT Dt0;
+ LVM_FLOAT B2_Den;
+ LVM_FLOAT B2_Num;
+ LVM_FLOAT COS_T0;
+ LVM_FLOAT coef;
+ LVM_FLOAT factor;
+ LVM_FLOAT t0;
+ LVM_INT16 i;
+
+ /*
+ * Get the filter definition
+ */
+ LVM_FLOAT Frequency = (LVM_FLOAT)(pFilterParams->CenterFrequency);
+ LVM_FLOAT QFactor = ((LVM_FLOAT)(pFilterParams->QFactor)) / 100;
+
+ /*
+ * Calculating the intermediate values
+ */
+ T0 = Frequency * LVPSA_Float_TwoPiOnFsTable[Fs]; /* T0 = 2 * Pi * Fc / Fs */
+ D = 3200; /* Floating point value 1.000000 (1*100*2^5) */
+ /* Force D = 1 : the function was originally used for a peaking filter.
+ The D parameter do not exist for a BandPass filter coefficients */
+
+ /*
+ * Calculate the B2 coefficient
+ */
+ Dt0 = T0 / 2048 ;
+ B2_Den = QFactor + Dt0;
+ B2_Num = Dt0 - QFactor;
+ B2 = B2_Num / (2 * B2_Den);
+
+ /*
+ * Calculate the cosine by a polynomial expansion using the equation:
+ *
+ * Cos += coef(n) * t0^n For n = 0 to 6
+ */
+ T0 = (T0 / 2048) * 0.63658558f; /* Scale to 1.0 in 16-bit for range 0 to fs/2 */
+ t0 = T0 ;
+ factor = 1.0f; /* Initialise to 1.0 for the a0 coefficient */
+ COS_T0 = 0.0f; /* Initialise the error to zero */
+ for (i = 1; i < 7; i++)
+ {
+ coef = LVPSA_Float_CosCoef[i]; /* Get the nth coefficient */
+ COS_T0 += (factor * coef); /* The nth partial sum */
+ factor = (factor * t0) ; /* Calculate t0^n */
+ }
+ COS_T0 = COS_T0 * 8; /*LVPSA_CosCoef_float[0]*/ /* Correct the scaling */
+
+ B1 = ((LVM_FLOAT)0.5 - B2) * (COS_T0); /* B1 = (0.5 - b2) * cos(t0) */
+ A0 = ((LVM_FLOAT)0.5 + B2) / 2; /* A0 = (0.5 + b2) / 2 */
+
+ /*
+ * Write coeff into the data structure
+ */
+ pCoefficients->A0 = A0 * 2;
+ pCoefficients->B1 = B1 * 2;
+ pCoefficients->B2 = B2 * 2;
+
+ return(LVPSA_OK);
+}
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVPSA_BPDoublePrecCoefs */
+/* */
+/* DESCRIPTION: */
+/* Calculate double precision coefficients for a band pass filter */
+/* */
+/* PARAMETERS: */
+/* Fs Sampling frequency index */
+/* pFilterParams Pointer to the filter definition */
+/* pCoefficients Pointer to the coefficients */
+/* */
+/* RETURNS: */
+/* LVPSA_OK Always succeeds */
+/* */
+/* NOTES: */
+/* 1. The equations used are as follows: */
+/* */
+/* t0 = 2 * Pi * Fc / Fs */
+/* */
+/* b2 = -0.5 * (2Q - t0) / (2Q + t0) */
+/* b1 = (0.5 - b2) * (1 - coserr(t0)) */
+/* a0 = (0.5 + b2) / 2 */
+/* */
+/* Where: */
+/* Fc is the centre frequency, DC to Fs/50 */
+/* Fs is the sample frequency, 8000 to 48000 in descrete steps */
+/* Q is the Q factor, 0.25 to 12 (represented by 25 to 1200) */
+/* */
+/* 2. The double precision coefficients are only used when fc is less than fs/85, so */
+/* the cosine of t0 is always close to 1.0. Instead of calculating the cosine */
+/* itself the difference from the value 1.0 is calculated, this can be done with */
+/* lower precision maths. */
+/* */
+/* 3. The value of the B2 coefficient is only calculated as a single precision value, */
+/* small errors in this value have a combined effect on the Q and Gain but not the */
+/* the frequency of the filter. */
+/* */
+/* 4. This function is entirely based on the LVEQNB_DoublePrecCoefs function */
+/* of the n bands equalizer (LVEQNB */
+/* */
+/****************************************************************************************/
+LVPSA_RETURN LVPSA_BPDoublePrecCoefs( LVM_UINT16 Fs,
+ LVPSA_FilterParam_t *pFilterParams,
+ BP_FLOAT_Coefs_t *pCoefficients)
+{
+
+ extern LVM_FLOAT LVPSA_Float_TwoPiOnFsTable[];
+ extern LVM_FLOAT LVPSA_Float_DPCosCoef[];
+
+ /*
+ * Intermediate variables and temporary values
+ */
+ LVM_FLOAT T0;
+ LVM_FLOAT D;
+ LVM_FLOAT A0;
+ LVM_FLOAT B1;
+ LVM_FLOAT B2;
+ LVM_FLOAT Dt0;
+ LVM_FLOAT B2_Den;
+ LVM_FLOAT B2_Num;
+ LVM_FLOAT CosErr;
+ LVM_FLOAT coef;
+ LVM_FLOAT factor;
+ LVM_FLOAT t0;
+ LVM_INT16 i;
+
+ /*
+ * Get the filter definition
+ */
+ LVM_FLOAT Frequency = (LVM_FLOAT)(pFilterParams->CenterFrequency);
+ LVM_FLOAT QFactor = ((LVM_FLOAT)(pFilterParams->QFactor)) / 100;
+
+ /*
+ * Calculating the intermediate values
+ */
+ T0 = Frequency * LVPSA_Float_TwoPiOnFsTable[Fs]; /* T0 = 2 * Pi * Fc / Fs */
+ D = 3200; /* Floating point value 1.000000 (1*100*2^5) */
+ /* Force D = 1 : the function was originally used for a peaking filter.
+ The D parameter do not exist for a BandPass filter coefficients */
+
+ /*
+ * Calculate the B2 coefficient
+ */
+ Dt0 = T0 / 2048 ;
+ B2_Den = QFactor + Dt0;
+ B2_Num = Dt0 - QFactor;
+ B2 = B2_Num / (2 * B2_Den);
+
+ /*
+ * Calculate the cosine error by a polynomial expansion using the equation:
+ *
+ * CosErr += coef(n) * t0^n For n = 0 to 4
+ */
+ T0 = T0 * 0.994750f; /* Scale to 1.0 in 16-bit for range 0 to fs/50 */
+ t0 = T0;
+ factor = 1.0f; /* Initialise to 1.0 for the a0 coefficient */
+ CosErr = 0.0f; /* Initialise the error to zero */
+ for (i = 1; i < 5; i++)
+ {
+ coef = LVPSA_Float_DPCosCoef[i]; /* Get the nth coefficient */
+ CosErr += factor * coef; /* The nth partial sum */
+ factor = factor * t0; /* Calculate t0^n */
+ }
+ CosErr = CosErr * 2; /* Correct the scaling */
+
+ /*
+ * Calculate the B1 and A0 coefficients
+ */
+ B1 = ((LVM_FLOAT)0.5 - B2); /* B1 = (0.5 - b2) */
+ A0 = B1 * CosErr ; /* Temporary storage for (0.5 - b2) * coserr(t0) */
+ B1 -= A0; /* B1 = (0.5 - b2) * (1 - coserr(t0)) */
+ A0 = ((LVM_FLOAT)0.5 + B2) / 2; /* A0 = (0.5 + b2) / 2 */
+
+ /*
+ * Write coeff into the data structure
+ */
+ pCoefficients->A0 = A0;
+ pCoefficients->B1 = B1;
+ pCoefficients->B2 = B2;
+
+ return(LVPSA_OK);
+}
+/************************************************************************************/
+/* */
+/* FUNCTION: LVPSA_ClearFilterHistory */
+/* */
+/* DESCRIPTION: */
+/* Clears the filters' data history */
+/* */
+/* PARAMETERS: */
+/* pInst Pointer to the instance */
+/* */
+/* RETURNS: */
+/* LVPSA_OK Always succeeds */
+/* */
+/* NOTES: */
+/* */
+/************************************************************************************/
+LVPSA_RETURN LVPSA_ClearFilterHistory(LVPSA_InstancePr_t *pInst)
+{
+ LVM_INT8 *pTapAddress;
+ LVM_UINT32 i;
+
+ /* Band Pass filters taps */
+ pTapAddress = (LVM_INT8 *)pInst->pBP_Taps;
+ for(i = 0; i < pInst->nBands * sizeof(Biquad_1I_Order2_FLOAT_Taps_t); i++)
+ {
+ pTapAddress[i] = 0;
+ }
+ /* Quasi-peak filters taps */
+ pTapAddress = (LVM_INT8 *)pInst->pQPD_Taps;
+ for(i = 0; i < pInst->nBands * sizeof(QPD_Taps_t); i++)
+ {
+ pTapAddress[i] = 0;
+ }
+
+ return(LVPSA_OK);
+}
+
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Init.c b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Init.c
deleted file mode 100644
index 1c26860..0000000
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Init.c
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "LVPSA.h"
-#include "LVPSA_Private.h"
-#include "InstAlloc.h"
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVPSA_Init */
-/* */
-/* DESCRIPTION: */
-/* Initialize the LVPSA module */
-/* */
-/* */
-/* PARAMETERS: */
-/* phInstance Pointer to pointer to the instance */
-/* InitParams Init parameters structure */
-/* ControlParams Control parameters structure */
-/* pMemoryTable Memory table that contains memory areas definition */
-/* */
-/* */
-/* RETURNS: */
-/* LVPSA_OK Succeeds */
-/* otherwise Error due to bad parameters */
-/* */
-/************************************************************************************/
-LVPSA_RETURN LVPSA_Init ( pLVPSA_Handle_t *phInstance,
- LVPSA_InitParams_t *pInitParams,
- LVPSA_ControlParams_t *pControlParams,
- LVPSA_MemTab_t *pMemoryTable )
-{
- LVPSA_InstancePr_t *pLVPSA_Inst;
- LVPSA_RETURN errorCode = LVPSA_OK;
- LVM_UINT32 ii;
-#ifndef BUILD_FLOAT
- extern LVM_INT16 LVPSA_GainTable[];
-#else
- extern LVM_FLOAT LVPSA_Float_GainTable[];
-#endif
- LVM_UINT32 BufferLength = 0;
-
- /* Ints_Alloc instances, needed for memory alignment management */
- INST_ALLOC Instance;
- INST_ALLOC Scratch;
- INST_ALLOC Data;
- INST_ALLOC Coef;
-
- /* Check parameters */
- if((phInstance == LVM_NULL) || (pInitParams == LVM_NULL) || (pControlParams == LVM_NULL) || (pMemoryTable == LVM_NULL))
- {
- return(LVPSA_ERROR_NULLADDRESS);
- }
- if( (pInitParams->SpectralDataBufferDuration > LVPSA_MAXBUFFERDURATION) ||
- (pInitParams->SpectralDataBufferDuration == 0) ||
- (pInitParams->MaxInputBlockSize > LVPSA_MAXINPUTBLOCKSIZE) ||
- (pInitParams->MaxInputBlockSize == 0) ||
- (pInitParams->nBands < LVPSA_NBANDSMIN) ||
- (pInitParams->nBands > LVPSA_NBANDSMAX) ||
- (pInitParams->pFiltersParams == 0))
- {
- return(LVPSA_ERROR_INVALIDPARAM);
- }
- for(ii = 0; ii < pInitParams->nBands; ii++)
- {
- if((pInitParams->pFiltersParams[ii].CenterFrequency > LVPSA_MAXCENTERFREQ) ||
- (pInitParams->pFiltersParams[ii].PostGain > LVPSA_MAXPOSTGAIN) ||
- (pInitParams->pFiltersParams[ii].PostGain < LVPSA_MINPOSTGAIN) ||
- (pInitParams->pFiltersParams[ii].QFactor < LVPSA_MINQFACTOR) ||
- (pInitParams->pFiltersParams[ii].QFactor > LVPSA_MAXQFACTOR))
- {
- return(LVPSA_ERROR_INVALIDPARAM);
- }
- }
-
-
- /*Inst_Alloc instances initialization */
- InstAlloc_Init( &Instance , pMemoryTable->Region[LVPSA_MEMREGION_INSTANCE].pBaseAddress);
- InstAlloc_Init( &Scratch , pMemoryTable->Region[LVPSA_MEMREGION_SCRATCH].pBaseAddress);
- InstAlloc_Init( &Data , pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_DATA].pBaseAddress);
- InstAlloc_Init( &Coef , pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_COEF].pBaseAddress);
-
-
- /* Set the instance handle if not already initialised */
- if (*phInstance == LVM_NULL)
- {
- *phInstance = InstAlloc_AddMember( &Instance, sizeof(LVPSA_InstancePr_t) );
- }
- pLVPSA_Inst =(LVPSA_InstancePr_t*)*phInstance;
-
-
- /* Check the memory table for NULL pointers */
- for (ii = 0; ii < LVPSA_NR_MEMORY_REGIONS; ii++)
- {
- if (pMemoryTable->Region[ii].Size!=0)
- {
- if (pMemoryTable->Region[ii].pBaseAddress==LVM_NULL)
- {
- return(LVPSA_ERROR_NULLADDRESS);
- }
- pLVPSA_Inst->MemoryTable.Region[ii] = pMemoryTable->Region[ii];
- }
- }
-
- /* Initialize module's internal parameters */
- pLVPSA_Inst->bControlPending = LVM_FALSE;
- pLVPSA_Inst->nBands = pInitParams->nBands;
- pLVPSA_Inst->MaxInputBlockSize = pInitParams->MaxInputBlockSize;
- pLVPSA_Inst->SpectralDataBufferDuration = pInitParams->SpectralDataBufferDuration;
- pLVPSA_Inst->CurrentParams.Fs = LVM_FS_DUMMY;
- pLVPSA_Inst->CurrentParams.LevelDetectionSpeed = LVPSA_SPEED_DUMMY;
-
- { /* for avoiding QAC warnings */
- LVM_INT32 SDBD=(LVM_INT32)pLVPSA_Inst->SpectralDataBufferDuration;
- LVM_INT32 IRTI=(LVM_INT32)LVPSA_InternalRefreshTimeInv;
- LVM_INT32 BL;
-
- MUL32x32INTO32(SDBD,IRTI,BL,LVPSA_InternalRefreshTimeShift)
-
- BufferLength=(LVM_UINT32)BL;
- }
-
- if((BufferLength * LVPSA_InternalRefreshTime) != pLVPSA_Inst->SpectralDataBufferDuration)
- {
- pLVPSA_Inst->SpectralDataBufferLength = BufferLength + 1;
- }
- else
- {
- pLVPSA_Inst->SpectralDataBufferLength = BufferLength;
- }
-
-
- /* Assign the pointers */
-#ifndef BUILD_FLOAT
- pLVPSA_Inst->pPostGains = InstAlloc_AddMember( &Instance, pInitParams->nBands * sizeof(LVM_UINT16) );
-#else
- pLVPSA_Inst->pPostGains = InstAlloc_AddMember( &Instance, pInitParams->nBands * \
- sizeof(LVM_FLOAT) );
-#endif
- pLVPSA_Inst->pFiltersParams = InstAlloc_AddMember( &Instance, pInitParams->nBands * sizeof(LVPSA_FilterParam_t) );
- pLVPSA_Inst->pSpectralDataBufferStart = InstAlloc_AddMember( &Instance, pInitParams->nBands * pLVPSA_Inst->SpectralDataBufferLength * sizeof(LVM_UINT8) );
- pLVPSA_Inst->pPreviousPeaks = InstAlloc_AddMember( &Instance, pInitParams->nBands * sizeof(LVM_UINT8) );
- pLVPSA_Inst->pBPFiltersPrecision = InstAlloc_AddMember( &Instance, pInitParams->nBands * sizeof(LVPSA_BPFilterPrecision_en) );
-#ifndef BUILD_FLOAT
- pLVPSA_Inst->pBP_Instances = InstAlloc_AddMember( &Coef, pInitParams->nBands * sizeof(Biquad_Instance_t) );
- pLVPSA_Inst->pQPD_States = InstAlloc_AddMember( &Coef, pInitParams->nBands * sizeof(QPD_State_t) );
-#else
- pLVPSA_Inst->pBP_Instances = InstAlloc_AddMember( &Coef, pInitParams->nBands * \
- sizeof(Biquad_FLOAT_Instance_t) );
- pLVPSA_Inst->pQPD_States = InstAlloc_AddMember( &Coef, pInitParams->nBands * \
- sizeof(QPD_FLOAT_State_t) );
-#endif
-
-#ifndef BUILD_FLOAT
- pLVPSA_Inst->pBP_Taps = InstAlloc_AddMember( &Data, pInitParams->nBands * sizeof(Biquad_1I_Order2_Taps_t) );
- pLVPSA_Inst->pQPD_Taps = InstAlloc_AddMember( &Data, pInitParams->nBands * sizeof(QPD_Taps_t) );
-
-#else
- pLVPSA_Inst->pBP_Taps = InstAlloc_AddMember( &Data,
- pInitParams->nBands * \
- sizeof(Biquad_1I_Order2_FLOAT_Taps_t));
- pLVPSA_Inst->pQPD_Taps = InstAlloc_AddMember( &Data, pInitParams->nBands * \
- sizeof(QPD_FLOAT_Taps_t) );
-#endif
-
- /* Copy filters parameters in the private instance */
- for(ii = 0; ii < pLVPSA_Inst->nBands; ii++)
- {
- pLVPSA_Inst->pFiltersParams[ii] = pInitParams->pFiltersParams[ii];
- }
-
- /* Set Post filters gains*/
- for(ii = 0; ii < pLVPSA_Inst->nBands; ii++)
- {
-#ifndef BUILD_FLOAT
- pLVPSA_Inst->pPostGains[ii] =(LVM_UINT16) LVPSA_GainTable[pInitParams->pFiltersParams[ii].PostGain + 15];
-#else
- pLVPSA_Inst->pPostGains[ii] = LVPSA_Float_GainTable[15 + \
- pInitParams->pFiltersParams[ii].PostGain];
-#endif
- }
- pLVPSA_Inst->pSpectralDataBufferWritePointer = pLVPSA_Inst->pSpectralDataBufferStart;
-
-
- /* Initialize control dependant internal parameters */
- errorCode = LVPSA_Control (*phInstance, pControlParams);
-
- if(errorCode!=0)
- {
- return errorCode;
- }
-
- errorCode = LVPSA_ApplyNewSettings (pLVPSA_Inst);
-
- if(errorCode!=0)
- {
- return errorCode;
- }
-
- return(errorCode);
-}
-
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Init.cpp b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Init.cpp
new file mode 100644
index 0000000..9fcd82f
--- /dev/null
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Init.cpp
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LVPSA.h"
+#include "LVPSA_Private.h"
+#include "InstAlloc.h"
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVPSA_Init */
+/* */
+/* DESCRIPTION: */
+/* Initialize the LVPSA module */
+/* */
+/* */
+/* PARAMETERS: */
+/* phInstance Pointer to pointer to the instance */
+/* InitParams Init parameters structure */
+/* ControlParams Control parameters structure */
+/* pMemoryTable Memory table that contains memory areas definition */
+/* */
+/* */
+/* RETURNS: */
+/* LVPSA_OK Succeeds */
+/* otherwise Error due to bad parameters */
+/* */
+/************************************************************************************/
+LVPSA_RETURN LVPSA_Init ( pLVPSA_Handle_t *phInstance,
+ LVPSA_InitParams_t *pInitParams,
+ LVPSA_ControlParams_t *pControlParams,
+ LVPSA_MemTab_t *pMemoryTable )
+{
+ LVPSA_InstancePr_t *pLVPSA_Inst;
+ LVPSA_RETURN errorCode = LVPSA_OK;
+ LVM_UINT32 ii;
+ extern LVM_FLOAT LVPSA_Float_GainTable[];
+ LVM_UINT32 BufferLength = 0;
+
+ /* Ints_Alloc instances, needed for memory alignment management */
+ INST_ALLOC Instance;
+ INST_ALLOC Scratch;
+ INST_ALLOC Data;
+ INST_ALLOC Coef;
+
+ /* Check parameters */
+ if((phInstance == LVM_NULL) || (pInitParams == LVM_NULL) || (pControlParams == LVM_NULL) || (pMemoryTable == LVM_NULL))
+ {
+ return(LVPSA_ERROR_NULLADDRESS);
+ }
+ if( (pInitParams->SpectralDataBufferDuration > LVPSA_MAXBUFFERDURATION) ||
+ (pInitParams->SpectralDataBufferDuration == 0) ||
+ (pInitParams->MaxInputBlockSize > LVPSA_MAXINPUTBLOCKSIZE) ||
+ (pInitParams->MaxInputBlockSize == 0) ||
+ (pInitParams->nBands < LVPSA_NBANDSMIN) ||
+ (pInitParams->nBands > LVPSA_NBANDSMAX) ||
+ (pInitParams->pFiltersParams == 0))
+ {
+ return(LVPSA_ERROR_INVALIDPARAM);
+ }
+ for(ii = 0; ii < pInitParams->nBands; ii++)
+ {
+ if((pInitParams->pFiltersParams[ii].CenterFrequency > LVPSA_MAXCENTERFREQ) ||
+ (pInitParams->pFiltersParams[ii].PostGain > LVPSA_MAXPOSTGAIN) ||
+ (pInitParams->pFiltersParams[ii].PostGain < LVPSA_MINPOSTGAIN) ||
+ (pInitParams->pFiltersParams[ii].QFactor < LVPSA_MINQFACTOR) ||
+ (pInitParams->pFiltersParams[ii].QFactor > LVPSA_MAXQFACTOR))
+ {
+ return(LVPSA_ERROR_INVALIDPARAM);
+ }
+ }
+
+ /*Inst_Alloc instances initialization */
+ InstAlloc_Init( &Instance , pMemoryTable->Region[LVPSA_MEMREGION_INSTANCE].pBaseAddress);
+ InstAlloc_Init( &Scratch , pMemoryTable->Region[LVPSA_MEMREGION_SCRATCH].pBaseAddress);
+ InstAlloc_Init( &Data , pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_DATA].pBaseAddress);
+ InstAlloc_Init( &Coef , pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_COEF].pBaseAddress);
+
+ /* Set the instance handle if not already initialised */
+ if (*phInstance == LVM_NULL)
+ {
+ *phInstance = InstAlloc_AddMember( &Instance, sizeof(LVPSA_InstancePr_t) );
+ }
+ pLVPSA_Inst =(LVPSA_InstancePr_t*)*phInstance;
+
+ /* Check the memory table for NULL pointers */
+ for (ii = 0; ii < LVPSA_NR_MEMORY_REGIONS; ii++)
+ {
+ if (pMemoryTable->Region[ii].Size!=0)
+ {
+ if (pMemoryTable->Region[ii].pBaseAddress==LVM_NULL)
+ {
+ return(LVPSA_ERROR_NULLADDRESS);
+ }
+ pLVPSA_Inst->MemoryTable.Region[ii] = pMemoryTable->Region[ii];
+ }
+ }
+
+ /* Initialize module's internal parameters */
+ pLVPSA_Inst->bControlPending = LVM_FALSE;
+ pLVPSA_Inst->nBands = pInitParams->nBands;
+ pLVPSA_Inst->MaxInputBlockSize = pInitParams->MaxInputBlockSize;
+ pLVPSA_Inst->SpectralDataBufferDuration = pInitParams->SpectralDataBufferDuration;
+ pLVPSA_Inst->CurrentParams.Fs = LVM_FS_DUMMY;
+ pLVPSA_Inst->CurrentParams.LevelDetectionSpeed = LVPSA_SPEED_DUMMY;
+
+ { /* for avoiding QAC warnings */
+ LVM_INT32 SDBD=(LVM_INT32)pLVPSA_Inst->SpectralDataBufferDuration;
+ LVM_INT32 IRTI=(LVM_INT32)LVPSA_InternalRefreshTimeInv;
+ LVM_INT32 BL;
+
+ MUL32x32INTO32(SDBD,IRTI,BL,LVPSA_InternalRefreshTimeShift)
+
+ BufferLength=(LVM_UINT32)BL;
+ }
+
+ if((BufferLength * LVPSA_InternalRefreshTime) != pLVPSA_Inst->SpectralDataBufferDuration)
+ {
+ pLVPSA_Inst->SpectralDataBufferLength = BufferLength + 1;
+ }
+ else
+ {
+ pLVPSA_Inst->SpectralDataBufferLength = BufferLength;
+ }
+
+ /* Assign the pointers */
+ pLVPSA_Inst->pPostGains =
+ (LVM_FLOAT *)InstAlloc_AddMember(&Instance, pInitParams->nBands * sizeof(LVM_FLOAT));
+ pLVPSA_Inst->pFiltersParams = (LVPSA_FilterParam_t *)
+ InstAlloc_AddMember(&Instance, pInitParams->nBands * sizeof(LVPSA_FilterParam_t));
+ pLVPSA_Inst->pSpectralDataBufferStart = (LVM_UINT8 *)
+ InstAlloc_AddMember(&Instance, pInitParams->nBands * \
+ pLVPSA_Inst->SpectralDataBufferLength * sizeof(LVM_UINT8));
+ pLVPSA_Inst->pPreviousPeaks = (LVM_UINT8 *)
+ InstAlloc_AddMember(&Instance, pInitParams->nBands * sizeof(LVM_UINT8));
+ pLVPSA_Inst->pBPFiltersPrecision = (LVPSA_BPFilterPrecision_en *)
+ InstAlloc_AddMember(&Instance, pInitParams->nBands * \
+ sizeof(LVPSA_BPFilterPrecision_en));
+ pLVPSA_Inst->pBP_Instances = (Biquad_FLOAT_Instance_t *)
+ InstAlloc_AddMember(&Coef, pInitParams->nBands * \
+ sizeof(Biquad_FLOAT_Instance_t));
+ pLVPSA_Inst->pQPD_States = (QPD_FLOAT_State_t *)
+ InstAlloc_AddMember(&Coef, pInitParams->nBands * \
+ sizeof(QPD_FLOAT_State_t));
+
+ pLVPSA_Inst->pBP_Taps = (Biquad_1I_Order2_FLOAT_Taps_t *)
+ InstAlloc_AddMember(&Data, pInitParams->nBands * \
+ sizeof(Biquad_1I_Order2_FLOAT_Taps_t));
+ pLVPSA_Inst->pQPD_Taps = (QPD_FLOAT_Taps_t *)
+ InstAlloc_AddMember(&Data, pInitParams->nBands * \
+ sizeof(QPD_FLOAT_Taps_t));
+
+ /* Copy filters parameters in the private instance */
+ for(ii = 0; ii < pLVPSA_Inst->nBands; ii++)
+ {
+ pLVPSA_Inst->pFiltersParams[ii] = pInitParams->pFiltersParams[ii];
+ }
+
+ /* Set Post filters gains*/
+ for(ii = 0; ii < pLVPSA_Inst->nBands; ii++)
+ {
+ pLVPSA_Inst->pPostGains[ii] = LVPSA_Float_GainTable[15 + \
+ pInitParams->pFiltersParams[ii].PostGain];
+ }
+ pLVPSA_Inst->pSpectralDataBufferWritePointer = pLVPSA_Inst->pSpectralDataBufferStart;
+
+ /* Initialize control dependant internal parameters */
+ errorCode = LVPSA_Control (*phInstance, pControlParams);
+
+ if(errorCode!=0)
+ {
+ return errorCode;
+ }
+
+ errorCode = LVPSA_ApplyNewSettings (pLVPSA_Inst);
+
+ if(errorCode!=0)
+ {
+ return errorCode;
+ }
+
+ return(errorCode);
+}
+
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Memory.c b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Memory.c
deleted file mode 100644
index 06a8f9d..0000000
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Memory.c
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "LVPSA.h"
-#include "LVPSA_Private.h"
-#include "InstAlloc.h"
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVEQNB_Memory */
-/* */
-/* DESCRIPTION: */
-/* This function is used for memory allocation and free. It can be called in */
-/* two ways: */
-/* */
-/* hInstance = NULL Returns the memory requirements */
-/* hInstance = Instance handle Returns the memory requirements and */
-/* allocated base addresses for the instance */
-/* */
-/* When this function is called for memory allocation (hInstance=NULL) the memory */
-/* base address pointers are NULL on return. */
-/* */
-/* When the function is called for free (hInstance = Instance Handle) the memory */
-/* table returns the allocated memory and base addresses used during initialisation. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance Handle */
-/* pMemoryTable Pointer to an empty memory definition table */
-/* InitParams Pointer to the instance init parameters */
-/* */
-/* RETURNS: */
-/* LVPSA_OK Succeeds */
-/* otherwise Error due to bad parameters */
-/* */
-/****************************************************************************************/
-LVPSA_RETURN LVPSA_Memory ( pLVPSA_Handle_t hInstance,
- LVPSA_MemTab_t *pMemoryTable,
- LVPSA_InitParams_t *pInitParams )
-{
- LVM_UINT32 ii;
- LVM_UINT32 BufferLength;
- INST_ALLOC Instance;
- INST_ALLOC Scratch;
- INST_ALLOC Data;
- INST_ALLOC Coef;
- LVPSA_InstancePr_t *pLVPSA_Inst = (LVPSA_InstancePr_t*)hInstance;
-
-
- InstAlloc_Init( &Instance , LVM_NULL);
- InstAlloc_Init( &Scratch , LVM_NULL);
- InstAlloc_Init( &Data , LVM_NULL);
- InstAlloc_Init( &Coef , LVM_NULL);
-
-
- if((pMemoryTable == LVM_NULL) || (pInitParams == LVM_NULL))
- {
- return(LVPSA_ERROR_NULLADDRESS);
- }
-
-
- /*
- * Fill in the memory table
- */
- if (hInstance == LVM_NULL)
- {
-
- /* Check init parameter */
- if( (pInitParams->SpectralDataBufferDuration > LVPSA_MAXBUFFERDURATION) ||
- (pInitParams->SpectralDataBufferDuration == 0) ||
- (pInitParams->MaxInputBlockSize > LVPSA_MAXINPUTBLOCKSIZE) ||
- (pInitParams->MaxInputBlockSize == 0) ||
- (pInitParams->nBands < LVPSA_NBANDSMIN) ||
- (pInitParams->nBands > LVPSA_NBANDSMAX) ||
- (pInitParams->pFiltersParams == 0))
- {
- return(LVPSA_ERROR_INVALIDPARAM);
- }
- for(ii = 0; ii < pInitParams->nBands; ii++)
- {
- if((pInitParams->pFiltersParams[ii].CenterFrequency > LVPSA_MAXCENTERFREQ) ||
- (pInitParams->pFiltersParams[ii].PostGain > LVPSA_MAXPOSTGAIN) ||
- (pInitParams->pFiltersParams[ii].PostGain < LVPSA_MINPOSTGAIN) ||
- (pInitParams->pFiltersParams[ii].QFactor < LVPSA_MINQFACTOR) ||
- (pInitParams->pFiltersParams[ii].QFactor > LVPSA_MAXQFACTOR))
- {
- return(LVPSA_ERROR_INVALIDPARAM);
- }
- }
-
- /*
- * Instance memory
- */
-
- InstAlloc_AddMember( &Instance, sizeof(LVPSA_InstancePr_t) );
-#ifdef BUILD_FLOAT
- InstAlloc_AddMember( &Instance, pInitParams->nBands * sizeof(LVM_FLOAT) );
-#else
- InstAlloc_AddMember( &Instance, pInitParams->nBands * sizeof(LVM_UINT16) );
-#endif
- InstAlloc_AddMember( &Instance, pInitParams->nBands * sizeof(LVPSA_FilterParam_t) );
-
- {
- /* for avoiding QAC warnings as MUL32x32INTO32 works on LVM_INT32 only*/
- LVM_INT32 SDBD=(LVM_INT32)pInitParams->SpectralDataBufferDuration;
- LVM_INT32 IRTI=(LVM_INT32)LVPSA_InternalRefreshTimeInv;
- LVM_INT32 BL;
-
- MUL32x32INTO32(SDBD,IRTI,BL,LVPSA_InternalRefreshTimeShift)
- BufferLength=(LVM_UINT32)BL;
- }
-
-
- if((BufferLength * LVPSA_InternalRefreshTime) != pInitParams->SpectralDataBufferDuration)
- {
- BufferLength++;
- }
- InstAlloc_AddMember( &Instance, pInitParams->nBands * BufferLength * sizeof(LVM_UINT8) );
- InstAlloc_AddMember( &Instance, pInitParams->nBands * sizeof(LVM_UINT8) );
- InstAlloc_AddMember( &Instance, pInitParams->nBands * sizeof(LVPSA_BPFilterPrecision_en) );
- pMemoryTable->Region[LVPSA_MEMREGION_INSTANCE].Size = InstAlloc_GetTotal(&Instance);
- pMemoryTable->Region[LVPSA_MEMREGION_INSTANCE].Type = LVPSA_PERSISTENT;
- pMemoryTable->Region[LVPSA_MEMREGION_INSTANCE].pBaseAddress = LVM_NULL;
-
- /*
- * Scratch memory
- */
-#ifndef BUILD_FLOAT
- InstAlloc_AddMember( &Scratch, 2 * pInitParams->MaxInputBlockSize * sizeof(LVM_INT16) );
-#else
- InstAlloc_AddMember( &Scratch, 2 * pInitParams->MaxInputBlockSize * sizeof(LVM_FLOAT) );
-#endif
- pMemoryTable->Region[LVPSA_MEMREGION_SCRATCH].Size = InstAlloc_GetTotal(&Scratch);
- pMemoryTable->Region[LVPSA_MEMREGION_SCRATCH].Type = LVPSA_SCRATCH;
- pMemoryTable->Region[LVPSA_MEMREGION_SCRATCH].pBaseAddress = LVM_NULL;
-
- /*
- * Persistent coefficients memory
- */
-#ifndef BUILD_FLOAT
- InstAlloc_AddMember( &Coef, pInitParams->nBands * sizeof(Biquad_Instance_t) );
- InstAlloc_AddMember( &Coef, pInitParams->nBands * sizeof(QPD_State_t) );
-#else
- InstAlloc_AddMember( &Coef, pInitParams->nBands * sizeof(Biquad_FLOAT_Instance_t) );
- InstAlloc_AddMember( &Coef, pInitParams->nBands * sizeof(QPD_FLOAT_State_t) );
-#endif
- pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_COEF].Size = InstAlloc_GetTotal(&Coef);
- pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_COEF].Type = LVPSA_PERSISTENT_COEF;
- pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_COEF].pBaseAddress = LVM_NULL;
-
- /*
- * Persistent data memory
- */
-#ifndef BUILD_FLOAT
- InstAlloc_AddMember( &Data, pInitParams->nBands * sizeof(Biquad_1I_Order2_Taps_t) );
- InstAlloc_AddMember( &Data, pInitParams->nBands * sizeof(QPD_Taps_t) );
-#else
- InstAlloc_AddMember( &Data, pInitParams->nBands * sizeof(Biquad_1I_Order2_FLOAT_Taps_t) );
- InstAlloc_AddMember( &Data, pInitParams->nBands * sizeof(QPD_FLOAT_Taps_t) );
-#endif
- pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_DATA].Size = InstAlloc_GetTotal(&Data);
- pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_DATA].Type = LVPSA_PERSISTENT_DATA;
- pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_DATA].pBaseAddress = LVM_NULL;
-
- }
- else
- {
- /* Read back memory allocation table */
- *pMemoryTable = pLVPSA_Inst->MemoryTable;
- }
-
- return(LVPSA_OK);
-}
-
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Memory.cpp b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Memory.cpp
new file mode 100644
index 0000000..eafcbe6
--- /dev/null
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Memory.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LVPSA.h"
+#include "LVPSA_Private.h"
+#include "InstAlloc.h"
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVEQNB_Memory */
+/* */
+/* DESCRIPTION: */
+/* This function is used for memory allocation and free. It can be called in */
+/* two ways: */
+/* */
+/* hInstance = NULL Returns the memory requirements */
+/* hInstance = Instance handle Returns the memory requirements and */
+/* allocated base addresses for the instance */
+/* */
+/* When this function is called for memory allocation (hInstance=NULL) the memory */
+/* base address pointers are NULL on return. */
+/* */
+/* When the function is called for free (hInstance = Instance Handle) the memory */
+/* table returns the allocated memory and base addresses used during initialisation. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance Handle */
+/* pMemoryTable Pointer to an empty memory definition table */
+/* InitParams Pointer to the instance init parameters */
+/* */
+/* RETURNS: */
+/* LVPSA_OK Succeeds */
+/* otherwise Error due to bad parameters */
+/* */
+/****************************************************************************************/
+LVPSA_RETURN LVPSA_Memory ( pLVPSA_Handle_t hInstance,
+ LVPSA_MemTab_t *pMemoryTable,
+ LVPSA_InitParams_t *pInitParams )
+{
+ LVM_UINT32 ii;
+ LVM_UINT32 BufferLength;
+ INST_ALLOC Instance;
+ INST_ALLOC Scratch;
+ INST_ALLOC Data;
+ INST_ALLOC Coef;
+ LVPSA_InstancePr_t *pLVPSA_Inst = (LVPSA_InstancePr_t*)hInstance;
+
+ InstAlloc_Init( &Instance , LVM_NULL);
+ InstAlloc_Init( &Scratch , LVM_NULL);
+ InstAlloc_Init( &Data , LVM_NULL);
+ InstAlloc_Init( &Coef , LVM_NULL);
+
+ if((pMemoryTable == LVM_NULL) || (pInitParams == LVM_NULL))
+ {
+ return(LVPSA_ERROR_NULLADDRESS);
+ }
+
+ /*
+ * Fill in the memory table
+ */
+ if (hInstance == LVM_NULL)
+ {
+
+ /* Check init parameter */
+ if( (pInitParams->SpectralDataBufferDuration > LVPSA_MAXBUFFERDURATION) ||
+ (pInitParams->SpectralDataBufferDuration == 0) ||
+ (pInitParams->MaxInputBlockSize > LVPSA_MAXINPUTBLOCKSIZE) ||
+ (pInitParams->MaxInputBlockSize == 0) ||
+ (pInitParams->nBands < LVPSA_NBANDSMIN) ||
+ (pInitParams->nBands > LVPSA_NBANDSMAX) ||
+ (pInitParams->pFiltersParams == 0))
+ {
+ return(LVPSA_ERROR_INVALIDPARAM);
+ }
+ for(ii = 0; ii < pInitParams->nBands; ii++)
+ {
+ if((pInitParams->pFiltersParams[ii].CenterFrequency > LVPSA_MAXCENTERFREQ) ||
+ (pInitParams->pFiltersParams[ii].PostGain > LVPSA_MAXPOSTGAIN) ||
+ (pInitParams->pFiltersParams[ii].PostGain < LVPSA_MINPOSTGAIN) ||
+ (pInitParams->pFiltersParams[ii].QFactor < LVPSA_MINQFACTOR) ||
+ (pInitParams->pFiltersParams[ii].QFactor > LVPSA_MAXQFACTOR))
+ {
+ return(LVPSA_ERROR_INVALIDPARAM);
+ }
+ }
+
+ /*
+ * Instance memory
+ */
+
+ InstAlloc_AddMember( &Instance, sizeof(LVPSA_InstancePr_t) );
+ InstAlloc_AddMember( &Instance, pInitParams->nBands * sizeof(LVM_FLOAT) );
+ InstAlloc_AddMember( &Instance, pInitParams->nBands * sizeof(LVPSA_FilterParam_t) );
+
+ {
+ /* for avoiding QAC warnings as MUL32x32INTO32 works on LVM_INT32 only*/
+ LVM_INT32 SDBD=(LVM_INT32)pInitParams->SpectralDataBufferDuration;
+ LVM_INT32 IRTI=(LVM_INT32)LVPSA_InternalRefreshTimeInv;
+ LVM_INT32 BL;
+
+ MUL32x32INTO32(SDBD,IRTI,BL,LVPSA_InternalRefreshTimeShift)
+ BufferLength=(LVM_UINT32)BL;
+ }
+
+ if((BufferLength * LVPSA_InternalRefreshTime) != pInitParams->SpectralDataBufferDuration)
+ {
+ BufferLength++;
+ }
+ InstAlloc_AddMember( &Instance, pInitParams->nBands * BufferLength * sizeof(LVM_UINT8) );
+ InstAlloc_AddMember( &Instance, pInitParams->nBands * sizeof(LVM_UINT8) );
+ InstAlloc_AddMember( &Instance, pInitParams->nBands * sizeof(LVPSA_BPFilterPrecision_en) );
+ pMemoryTable->Region[LVPSA_MEMREGION_INSTANCE].Size = InstAlloc_GetTotal(&Instance);
+ pMemoryTable->Region[LVPSA_MEMREGION_INSTANCE].Type = LVPSA_PERSISTENT;
+ pMemoryTable->Region[LVPSA_MEMREGION_INSTANCE].pBaseAddress = LVM_NULL;
+
+ /*
+ * Scratch memory
+ */
+ InstAlloc_AddMember( &Scratch, 2 * pInitParams->MaxInputBlockSize * sizeof(LVM_FLOAT) );
+ pMemoryTable->Region[LVPSA_MEMREGION_SCRATCH].Size = InstAlloc_GetTotal(&Scratch);
+ pMemoryTable->Region[LVPSA_MEMREGION_SCRATCH].Type = LVPSA_SCRATCH;
+ pMemoryTable->Region[LVPSA_MEMREGION_SCRATCH].pBaseAddress = LVM_NULL;
+
+ /*
+ * Persistent coefficients memory
+ */
+ InstAlloc_AddMember( &Coef, pInitParams->nBands * sizeof(Biquad_FLOAT_Instance_t) );
+ InstAlloc_AddMember( &Coef, pInitParams->nBands * sizeof(QPD_FLOAT_State_t) );
+ pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_COEF].Size = InstAlloc_GetTotal(&Coef);
+ pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_COEF].Type = LVPSA_PERSISTENT_COEF;
+ pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_COEF].pBaseAddress = LVM_NULL;
+
+ /*
+ * Persistent data memory
+ */
+ InstAlloc_AddMember( &Data, pInitParams->nBands * sizeof(Biquad_1I_Order2_FLOAT_Taps_t) );
+ InstAlloc_AddMember( &Data, pInitParams->nBands * sizeof(QPD_FLOAT_Taps_t) );
+ pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_DATA].Size = InstAlloc_GetTotal(&Data);
+ pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_DATA].Type = LVPSA_PERSISTENT_DATA;
+ pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_DATA].pBaseAddress = LVM_NULL;
+
+ }
+ else
+ {
+ /* Read back memory allocation table */
+ *pMemoryTable = pLVPSA_Inst->MemoryTable;
+ }
+
+ return(LVPSA_OK);
+}
+
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Private.h b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Private.h
index ee07e2e..61987b5 100644
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Private.h
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Private.h
@@ -23,12 +23,6 @@
#include "LVPSA_QPD.h"
#include "LVM_Macros.h"
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
/**********************************************************************************
CONSTANT DEFINITIONS
***********************************************************************************/
@@ -43,11 +37,7 @@
#define LVPSA_MEMREGION_PERSISTENT_COEF 1 /* Offset to persistent coefficients memory region in memory table */
#define LVPSA_MEMREGION_PERSISTENT_DATA 2 /* Offset to persistent taps memory region in memory table */
#define LVPSA_MEMREGION_SCRATCH 3 /* Offset to scratch memory region in memory table */
-#ifndef HIGHER_FS
-#define LVPSA_NR_SUPPORTED_RATE 9 /* From 8000Hz to 48000Hz*/
-#else
#define LVPSA_NR_SUPPORTED_RATE 13 /* From 8000Hz to 192000Hz*/
-#endif
#define LVPSA_NR_SUPPORTED_SPEED 3 /* LOW, MEDIUM, HIGH */
#define LVPSA_MAXBUFFERDURATION 4000 /* Maximum length in ms of the levels buffer */
@@ -77,7 +67,6 @@
#define LVPSA_InternalRefreshTimeInv 0x0666 /* 1/20ms left shifted by 15 */
#define LVPSA_InternalRefreshTimeShift 15
-
/* Precision of the filter */
typedef enum
{
@@ -96,12 +85,6 @@
LVPSA_MemTab_t MemoryTable;
LVPSA_BPFilterPrecision_en *pBPFiltersPrecision; /* Points a nBands elements array that contains the filter precision for each band */
-#ifndef BUILD_FLOAT
- Biquad_Instance_t *pBP_Instances; /* Points a nBands elements array that contains the band pass filter instance for each band */
- Biquad_1I_Order2_Taps_t *pBP_Taps; /* Points a nBands elements array that contains the band pass filter taps for each band */
- QPD_State_t *pQPD_States; /* Points a nBands elements array that contains the QPD filter instance for each band */
- QPD_Taps_t *pQPD_Taps; /* Points a nBands elements array that contains the QPD filter taps for each band */
-#else
Biquad_FLOAT_Instance_t *pBP_Instances;
/* Points a nBands elements array that contains the band pass filter taps for each band */
Biquad_1I_Order2_FLOAT_Taps_t *pBP_Taps;
@@ -109,17 +92,11 @@
QPD_FLOAT_State_t *pQPD_States;
/* Points a nBands elements array that contains the QPD filter taps for each band */
QPD_FLOAT_Taps_t *pQPD_Taps;
-#endif
-#ifndef BUILD_FLOAT
- LVM_UINT16 *pPostGains; /* Points a nBands elements array that contains the post-filter gains for each band */
-#else
/* Points a nBands elements array that contains the post-filter gains for each band */
LVM_FLOAT *pPostGains;
-#endif
LVPSA_FilterParam_t *pFiltersParams; /* Copy of the filters parameters from the input parameters */
-
LVM_UINT16 nSamplesBufferUpdate; /* Number of samples to make 20ms */
LVM_INT32 BufferUpdateSamplesCount; /* Counter used to know when to put a new value in the buffer */
LVM_UINT16 nRelevantFilters; /* Number of relevent filters depending on sampling frequency and bands center frequency */
@@ -140,8 +117,6 @@
}LVPSA_InstancePr_t, *pLVPSA_InstancePr_t;
-
-
/**********************************************************************************
FUNCTIONS PROTOTYPE
***********************************************************************************/
@@ -162,8 +137,4 @@
/************************************************************************************/
LVPSA_RETURN LVPSA_ApplyNewSettings (LVPSA_InstancePr_t *pInst);
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
#endif /* _LVPSA_PRIVATE_H */
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Process.c b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Process.c
deleted file mode 100644
index 61899fe..0000000
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Process.c
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "LVPSA.h"
-#include "LVPSA_Private.h"
-#include "LVM_Macros.h"
-#include "VectorArithmetic.h"
-
-#define LVM_MININT_32 0x80000000
-
-static LVM_INT32 mult32x32in32_shiftr(LVM_INT32 a, LVM_INT32 b, LVM_INT32 c) {
- LVM_INT64 result = ((LVM_INT64)a * b) >> c;
-
- if (result >= INT32_MAX) {
- return INT32_MAX;
- } else if (result <= INT32_MIN) {
- return INT32_MIN;
- } else {
- return (LVM_INT32)result;
- }
-}
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVPSA_Process */
-/* */
-/* DESCRIPTION: */
-/* The process applies band pass filters to the signal. Each output */
-/* feeds a quasi peak filter for level detection. */
-/* */
-/* PARAMETERS: */
-/* hInstance Pointer to the instance */
-/* pLVPSA_InputSamples Pointer to the input samples buffer */
-/* InputBlockSize Number of mono samples to process */
-/* AudioTime Playback time of the input samples */
-/* */
-/* */
-/* RETURNS: */
-/* LVPSA_OK Succeeds */
-/* otherwise Error due to bad parameters */
-/* */
-/************************************************************************************/
-#ifdef BUILD_FLOAT
-LVPSA_RETURN LVPSA_Process ( pLVPSA_Handle_t hInstance,
- LVM_FLOAT *pLVPSA_InputSamples,
- LVM_UINT16 InputBlockSize,
- LVPSA_Time AudioTime )
-
-{
- LVPSA_InstancePr_t *pLVPSA_Inst = (LVPSA_InstancePr_t*)hInstance;
- LVM_FLOAT *pScratch;
- LVM_INT16 ii;
- LVM_INT32 AudioTimeInc;
- extern LVM_UINT32 LVPSA_SampleRateInvTab[];
- LVM_UINT8 *pWrite_Save; /* Position of the write pointer
- at the beginning of the process */
-
- /******************************************************************************
- CHECK PARAMETERS
- *******************************************************************************/
- if(hInstance == LVM_NULL || pLVPSA_InputSamples == LVM_NULL)
- {
- return(LVPSA_ERROR_NULLADDRESS);
- }
- if(InputBlockSize == 0 || InputBlockSize > pLVPSA_Inst->MaxInputBlockSize)
- {
- return(LVPSA_ERROR_INVALIDPARAM);
- }
-
- pScratch = (LVM_FLOAT*)pLVPSA_Inst->MemoryTable.Region[LVPSA_MEMREGION_SCRATCH].pBaseAddress;
- pWrite_Save = pLVPSA_Inst->pSpectralDataBufferWritePointer;
-
- /******************************************************************************
- APPLY NEW SETTINGS IF NEEDED
- *******************************************************************************/
- if (pLVPSA_Inst->bControlPending == LVM_TRUE)
- {
- pLVPSA_Inst->bControlPending = 0;
- LVPSA_ApplyNewSettings( pLVPSA_Inst);
- }
-
- /******************************************************************************
- PROCESS SAMPLES
- *******************************************************************************/
- /* Put samples in range [-0.5;0.5[ for BP filters (see Biquads documentation) */
- Copy_Float(pLVPSA_InputSamples, pScratch, (LVM_INT16)InputBlockSize);
- Shift_Sat_Float(-1, pScratch, pScratch, (LVM_INT16)InputBlockSize);
-
- for (ii = 0; ii < pLVPSA_Inst->nRelevantFilters; ii++)
- {
- switch(pLVPSA_Inst->pBPFiltersPrecision[ii])
- {
- case LVPSA_SimplePrecisionFilter:
- BP_1I_D16F16C14_TRC_WRA_01 ( &pLVPSA_Inst->pBP_Instances[ii],
- pScratch,
- pScratch + InputBlockSize,
- (LVM_INT16)InputBlockSize);
- break;
-
- case LVPSA_DoublePrecisionFilter:
- BP_1I_D16F32C30_TRC_WRA_01 ( &pLVPSA_Inst->pBP_Instances[ii],
- pScratch,
- pScratch + InputBlockSize,
- (LVM_INT16)InputBlockSize);
- break;
- default:
- break;
- }
-
-
- LVPSA_QPD_Process_Float ( pLVPSA_Inst,
- pScratch + InputBlockSize,
- (LVM_INT16)InputBlockSize,
- ii);
- }
-
- /******************************************************************************
- UPDATE SpectralDataBufferAudioTime
- *******************************************************************************/
-
- if(pLVPSA_Inst->pSpectralDataBufferWritePointer != pWrite_Save)
- {
- AudioTimeInc = mult32x32in32_shiftr(
- (AudioTime + ((LVM_INT32)pLVPSA_Inst->LocalSamplesCount * 1000)),
- (LVM_INT32)LVPSA_SampleRateInvTab[pLVPSA_Inst->CurrentParams.Fs],
- LVPSA_FsInvertShift);
- pLVPSA_Inst->SpectralDataBufferAudioTime = AudioTime + AudioTimeInc;
- }
-
- return(LVPSA_OK);
-}
-#else
-LVPSA_RETURN LVPSA_Process ( pLVPSA_Handle_t hInstance,
- LVM_INT16 *pLVPSA_InputSamples,
- LVM_UINT16 InputBlockSize,
- LVPSA_Time AudioTime )
-
-{
- LVPSA_InstancePr_t *pLVPSA_Inst = (LVPSA_InstancePr_t*)hInstance;
- LVM_INT16 *pScratch;
- LVM_INT16 ii;
- LVM_INT32 AudioTimeInc;
- extern LVM_UINT32 LVPSA_SampleRateInvTab[];
- LVM_UINT8 *pWrite_Save; /* Position of the write pointer at the beginning of the process */
-
- /******************************************************************************
- CHECK PARAMETERS
- *******************************************************************************/
- if(hInstance == LVM_NULL || pLVPSA_InputSamples == LVM_NULL)
- {
- return(LVPSA_ERROR_NULLADDRESS);
- }
- if(InputBlockSize == 0 || InputBlockSize > pLVPSA_Inst->MaxInputBlockSize)
- {
- return(LVPSA_ERROR_INVALIDPARAM);
- }
-
- pScratch = (LVM_INT16*)pLVPSA_Inst->MemoryTable.Region[LVPSA_MEMREGION_SCRATCH].pBaseAddress;
- pWrite_Save = pLVPSA_Inst->pSpectralDataBufferWritePointer;
-
- /******************************************************************************
- APPLY NEW SETTINGS IF NEEDED
- *******************************************************************************/
- if (pLVPSA_Inst->bControlPending == LVM_TRUE)
- {
- pLVPSA_Inst->bControlPending = 0;
- LVPSA_ApplyNewSettings( pLVPSA_Inst);
- }
-
- /******************************************************************************
- PROCESS SAMPLES
- *******************************************************************************/
- /* Put samples in range [-0.5;0.5[ for BP filters (see Biquads documentation) */
- Copy_16( pLVPSA_InputSamples,pScratch,(LVM_INT16)InputBlockSize);
- Shift_Sat_v16xv16(-1,pScratch,pScratch,(LVM_INT16)InputBlockSize);
-
- for (ii = 0; ii < pLVPSA_Inst->nRelevantFilters; ii++)
- {
- switch(pLVPSA_Inst->pBPFiltersPrecision[ii])
- {
- case LVPSA_SimplePrecisionFilter:
- BP_1I_D16F16C14_TRC_WRA_01 ( &pLVPSA_Inst->pBP_Instances[ii],
- pScratch,
- pScratch + InputBlockSize,
- (LVM_INT16)InputBlockSize);
- break;
-
- case LVPSA_DoublePrecisionFilter:
- BP_1I_D16F32C30_TRC_WRA_01 ( &pLVPSA_Inst->pBP_Instances[ii],
- pScratch,
- pScratch + InputBlockSize,
- (LVM_INT16)InputBlockSize);
- break;
- default:
- break;
- }
-
-
- LVPSA_QPD_Process ( pLVPSA_Inst,
- pScratch + InputBlockSize,
- (LVM_INT16)InputBlockSize,
- ii);
- }
-
- /******************************************************************************
- UPDATE SpectralDataBufferAudioTime
- *******************************************************************************/
-
- if(pLVPSA_Inst->pSpectralDataBufferWritePointer != pWrite_Save)
- {
- MUL32x32INTO32((AudioTime + (LVM_INT32)((LVM_INT32)pLVPSA_Inst->LocalSamplesCount*1000)),
- (LVM_INT32)LVPSA_SampleRateInvTab[pLVPSA_Inst->CurrentParams.Fs],
- AudioTimeInc,
- LVPSA_FsInvertShift)
- pLVPSA_Inst->SpectralDataBufferAudioTime = AudioTime + AudioTimeInc;
- }
-
- return(LVPSA_OK);
-}
-#endif
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVPSA_GetSpectrum */
-/* */
-/* DESCRIPTION: */
-/* Gets the levels values at a certain point in time */
-/* */
-/* */
-/* PARAMETERS: */
-/* hInstance Pointer to the instance */
-/* GetSpectrumAudioTime Retrieve the values at this time */
-/* pCurrentValues Pointer to a buffer that will contain levels' values */
-/* pMaxValues Pointer to a buffer that will contain max levels' values */
-/* */
-/* */
-/* RETURNS: */
-/* LVPSA_OK Succeeds */
-/* otherwise Error due to bad parameters */
-/* */
-/************************************************************************************/
-LVPSA_RETURN LVPSA_GetSpectrum ( pLVPSA_Handle_t hInstance,
- LVPSA_Time GetSpectrumAudioTime,
- LVM_UINT8 *pCurrentValues,
- LVM_UINT8 *pPeakValues )
-
-{
-
- LVPSA_InstancePr_t *pLVPSA_Inst = (LVPSA_InstancePr_t*)hInstance;
- LVM_INT32 StatusDelta, ii;
- LVM_UINT8 *pRead;
-
- if(hInstance == LVM_NULL || pCurrentValues == LVM_NULL || pPeakValues == LVM_NULL)
- {
- return(LVPSA_ERROR_NULLADDRESS);
- }
-
-
- /* First find the place where to look in the status buffer */
- if(GetSpectrumAudioTime <= pLVPSA_Inst->SpectralDataBufferAudioTime)
- {
- MUL32x32INTO32((pLVPSA_Inst->SpectralDataBufferAudioTime - GetSpectrumAudioTime),LVPSA_InternalRefreshTimeInv,StatusDelta,LVPSA_InternalRefreshTimeShift);
- if((StatusDelta * LVPSA_InternalRefreshTime) != (pLVPSA_Inst->SpectralDataBufferAudioTime - GetSpectrumAudioTime))
- {
- StatusDelta += 1;
- }
- }
- else
- {
- /* This part handles the wrap around */
- MUL32x32INTO32(((pLVPSA_Inst->SpectralDataBufferAudioTime - (LVM_INT32)LVM_MININT_32) + ((LVM_INT32)LVM_MAXINT_32 - GetSpectrumAudioTime)),LVPSA_InternalRefreshTimeInv,StatusDelta,LVPSA_InternalRefreshTimeShift)
- if(((LVM_INT32)(StatusDelta * LVPSA_InternalRefreshTime)) != ((LVM_INT32)((pLVPSA_Inst->SpectralDataBufferAudioTime - (LVM_INT32)LVM_MININT_32) + ((LVM_INT32)LVM_MAXINT_32 - GetSpectrumAudioTime))))
- {
- StatusDelta += 1;
- }
- }
- /* Check whether the desired level is not too "old" (see 2.10 in LVPSA_DesignNotes.doc)*/
- if(
- ((GetSpectrumAudioTime < pLVPSA_Inst->SpectralDataBufferAudioTime)&&
- ((GetSpectrumAudioTime<0)&&(pLVPSA_Inst->SpectralDataBufferAudioTime>0))&&
- (((LVM_INT32)(-GetSpectrumAudioTime + pLVPSA_Inst->SpectralDataBufferAudioTime))>LVM_MAXINT_32))||
-
- ((GetSpectrumAudioTime > pLVPSA_Inst->SpectralDataBufferAudioTime)&&
- (((GetSpectrumAudioTime>=0)&&(pLVPSA_Inst->SpectralDataBufferAudioTime>=0))||
- ((GetSpectrumAudioTime<=0)&&(pLVPSA_Inst->SpectralDataBufferAudioTime<=0))||
- (((GetSpectrumAudioTime>=0)&&(pLVPSA_Inst->SpectralDataBufferAudioTime<=0))&&
- (((LVM_INT32)(GetSpectrumAudioTime - pLVPSA_Inst->SpectralDataBufferAudioTime))<LVM_MAXINT_32))))||
-
- (StatusDelta > (LVM_INT32)pLVPSA_Inst->SpectralDataBufferLength) ||
- (!StatusDelta))
- {
- for(ii = 0; ii < pLVPSA_Inst->nBands; ii++)
- {
- pCurrentValues[ii] = 0;
- pPeakValues[ii] = 0;
- }
- return(LVPSA_OK);
- }
- /* Set the reading pointer */
- if((LVM_INT32)(StatusDelta * pLVPSA_Inst->nBands) > (pLVPSA_Inst->pSpectralDataBufferWritePointer - pLVPSA_Inst->pSpectralDataBufferStart))
- {
- pRead = pLVPSA_Inst->pSpectralDataBufferWritePointer + (pLVPSA_Inst->SpectralDataBufferLength - (LVM_UINT32)StatusDelta) * pLVPSA_Inst->nBands;
- }
- else
- {
- pRead = pLVPSA_Inst->pSpectralDataBufferWritePointer - StatusDelta * pLVPSA_Inst->nBands;
- }
-
-
- /* Read the status buffer and fill the output buffers */
- for(ii = 0; ii < pLVPSA_Inst->nBands; ii++)
- {
- pCurrentValues[ii] = pRead[ii];
- if(pLVPSA_Inst->pPreviousPeaks[ii] <= pRead[ii])
- {
- pLVPSA_Inst->pPreviousPeaks[ii] = pRead[ii];
- }
- else if(pLVPSA_Inst->pPreviousPeaks[ii] != 0)
- {
- LVM_INT32 temp;
- /*Re-compute max values for decay */
- temp = (LVM_INT32)(LVPSA_MAXUNSIGNEDCHAR - pLVPSA_Inst->pPreviousPeaks[ii]);
- temp = ((temp * LVPSA_MAXLEVELDECAYFACTOR)>>LVPSA_MAXLEVELDECAYSHIFT);
- /* If the gain has no effect, "help" the value to increase */
- if(temp == (LVPSA_MAXUNSIGNEDCHAR - pLVPSA_Inst->pPreviousPeaks[ii]))
- {
- temp += 1;
- }
- /* Saturate */
- temp = (temp > LVPSA_MAXUNSIGNEDCHAR) ? LVPSA_MAXUNSIGNEDCHAR : temp;
- /* Store new max level */
- pLVPSA_Inst->pPreviousPeaks[ii] = (LVM_UINT8)(LVPSA_MAXUNSIGNEDCHAR - temp);
- }
-
- pPeakValues[ii] = pLVPSA_Inst->pPreviousPeaks[ii];
- }
-
- return(LVPSA_OK);
-}
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Process.cpp b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Process.cpp
new file mode 100644
index 0000000..81a88c5
--- /dev/null
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Process.cpp
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LVPSA.h"
+#include "LVPSA_Private.h"
+#include "LVM_Macros.h"
+#include "VectorArithmetic.h"
+
+#define LVM_MININT_32 0x80000000
+
+static LVM_INT32 mult32x32in32_shiftr(LVM_INT32 a, LVM_INT32 b, LVM_INT32 c) {
+ LVM_INT64 result = ((LVM_INT64)a * b) >> c;
+
+ if (result >= INT32_MAX) {
+ return INT32_MAX;
+ } else if (result <= INT32_MIN) {
+ return INT32_MIN;
+ } else {
+ return (LVM_INT32)result;
+ }
+}
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVPSA_Process */
+/* */
+/* DESCRIPTION: */
+/* The process applies band pass filters to the signal. Each output */
+/* feeds a quasi peak filter for level detection. */
+/* */
+/* PARAMETERS: */
+/* hInstance Pointer to the instance */
+/* pLVPSA_InputSamples Pointer to the input samples buffer */
+/* InputBlockSize Number of mono samples to process */
+/* AudioTime Playback time of the input samples */
+/* */
+/* */
+/* RETURNS: */
+/* LVPSA_OK Succeeds */
+/* otherwise Error due to bad parameters */
+/* */
+/************************************************************************************/
+LVPSA_RETURN LVPSA_Process ( pLVPSA_Handle_t hInstance,
+ LVM_FLOAT *pLVPSA_InputSamples,
+ LVM_UINT16 InputBlockSize,
+ LVPSA_Time AudioTime )
+
+{
+ LVPSA_InstancePr_t *pLVPSA_Inst = (LVPSA_InstancePr_t*)hInstance;
+ LVM_FLOAT *pScratch;
+ LVM_INT16 ii;
+ LVM_INT32 AudioTimeInc;
+ extern LVM_UINT32 LVPSA_SampleRateInvTab[];
+ LVM_UINT8 *pWrite_Save; /* Position of the write pointer
+ at the beginning of the process */
+
+ /******************************************************************************
+ CHECK PARAMETERS
+ *******************************************************************************/
+ if(hInstance == LVM_NULL || pLVPSA_InputSamples == LVM_NULL)
+ {
+ return(LVPSA_ERROR_NULLADDRESS);
+ }
+ if(InputBlockSize == 0 || InputBlockSize > pLVPSA_Inst->MaxInputBlockSize)
+ {
+ return(LVPSA_ERROR_INVALIDPARAM);
+ }
+
+ pScratch = (LVM_FLOAT*)pLVPSA_Inst->MemoryTable.Region[LVPSA_MEMREGION_SCRATCH].pBaseAddress;
+ pWrite_Save = pLVPSA_Inst->pSpectralDataBufferWritePointer;
+
+ /******************************************************************************
+ APPLY NEW SETTINGS IF NEEDED
+ *******************************************************************************/
+ if (pLVPSA_Inst->bControlPending == LVM_TRUE)
+ {
+ pLVPSA_Inst->bControlPending = 0;
+ LVPSA_ApplyNewSettings( pLVPSA_Inst);
+ }
+
+ /******************************************************************************
+ PROCESS SAMPLES
+ *******************************************************************************/
+ /* Put samples in range [-0.5;0.5[ for BP filters (see Biquads documentation) */
+ Copy_Float(pLVPSA_InputSamples, pScratch, (LVM_INT16)InputBlockSize);
+ Shift_Sat_Float(-1, pScratch, pScratch, (LVM_INT16)InputBlockSize);
+
+ for (ii = 0; ii < pLVPSA_Inst->nRelevantFilters; ii++)
+ {
+ switch(pLVPSA_Inst->pBPFiltersPrecision[ii])
+ {
+ case LVPSA_SimplePrecisionFilter:
+ BP_1I_D16F16C14_TRC_WRA_01 ( &pLVPSA_Inst->pBP_Instances[ii],
+ pScratch,
+ pScratch + InputBlockSize,
+ (LVM_INT16)InputBlockSize);
+ break;
+
+ case LVPSA_DoublePrecisionFilter:
+ BP_1I_D16F32C30_TRC_WRA_01 ( &pLVPSA_Inst->pBP_Instances[ii],
+ pScratch,
+ pScratch + InputBlockSize,
+ (LVM_INT16)InputBlockSize);
+ break;
+ default:
+ break;
+ }
+
+ LVPSA_QPD_Process_Float ( pLVPSA_Inst,
+ pScratch + InputBlockSize,
+ (LVM_INT16)InputBlockSize,
+ ii);
+ }
+
+ /******************************************************************************
+ UPDATE SpectralDataBufferAudioTime
+ *******************************************************************************/
+
+ if(pLVPSA_Inst->pSpectralDataBufferWritePointer != pWrite_Save)
+ {
+ AudioTimeInc = mult32x32in32_shiftr(
+ (AudioTime + ((LVM_INT32)pLVPSA_Inst->LocalSamplesCount * 1000)),
+ (LVM_INT32)LVPSA_SampleRateInvTab[pLVPSA_Inst->CurrentParams.Fs],
+ LVPSA_FsInvertShift);
+ pLVPSA_Inst->SpectralDataBufferAudioTime = AudioTime + AudioTimeInc;
+ }
+
+ return(LVPSA_OK);
+}
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVPSA_GetSpectrum */
+/* */
+/* DESCRIPTION: */
+/* Gets the levels values at a certain point in time */
+/* */
+/* */
+/* PARAMETERS: */
+/* hInstance Pointer to the instance */
+/* GetSpectrumAudioTime Retrieve the values at this time */
+/* pCurrentValues Pointer to a buffer that will contain levels' values */
+/* pMaxValues Pointer to a buffer that will contain max levels' values */
+/* */
+/* */
+/* RETURNS: */
+/* LVPSA_OK Succeeds */
+/* otherwise Error due to bad parameters */
+/* */
+/************************************************************************************/
+LVPSA_RETURN LVPSA_GetSpectrum ( pLVPSA_Handle_t hInstance,
+ LVPSA_Time GetSpectrumAudioTime,
+ LVM_UINT8 *pCurrentValues,
+ LVM_UINT8 *pPeakValues )
+
+{
+
+ LVPSA_InstancePr_t *pLVPSA_Inst = (LVPSA_InstancePr_t*)hInstance;
+ LVM_INT32 StatusDelta, ii;
+ LVM_UINT8 *pRead;
+
+ if(hInstance == LVM_NULL || pCurrentValues == LVM_NULL || pPeakValues == LVM_NULL)
+ {
+ return(LVPSA_ERROR_NULLADDRESS);
+ }
+
+ /* First find the place where to look in the status buffer */
+ if(GetSpectrumAudioTime <= pLVPSA_Inst->SpectralDataBufferAudioTime)
+ {
+ MUL32x32INTO32((pLVPSA_Inst->SpectralDataBufferAudioTime - GetSpectrumAudioTime),LVPSA_InternalRefreshTimeInv,StatusDelta,LVPSA_InternalRefreshTimeShift);
+ if((StatusDelta * LVPSA_InternalRefreshTime) != (pLVPSA_Inst->SpectralDataBufferAudioTime - GetSpectrumAudioTime))
+ {
+ StatusDelta += 1;
+ }
+ }
+ else
+ {
+ /* This part handles the wrap around */
+ MUL32x32INTO32(((pLVPSA_Inst->SpectralDataBufferAudioTime - (LVM_INT32)LVM_MININT_32) + ((LVM_INT32)LVM_MAXINT_32 - GetSpectrumAudioTime)),LVPSA_InternalRefreshTimeInv,StatusDelta,LVPSA_InternalRefreshTimeShift)
+ if(((LVM_INT32)(StatusDelta * LVPSA_InternalRefreshTime)) != ((LVM_INT32)((pLVPSA_Inst->SpectralDataBufferAudioTime - (LVM_INT32)LVM_MININT_32) + ((LVM_INT32)LVM_MAXINT_32 - GetSpectrumAudioTime))))
+ {
+ StatusDelta += 1;
+ }
+ }
+ /* Check whether the desired level is not too "old" (see 2.10 in LVPSA_DesignNotes.doc)*/
+ if(
+ ((GetSpectrumAudioTime < pLVPSA_Inst->SpectralDataBufferAudioTime)&&
+ ((GetSpectrumAudioTime<0)&&(pLVPSA_Inst->SpectralDataBufferAudioTime>0))&&
+ (((LVM_INT32)(-GetSpectrumAudioTime + pLVPSA_Inst->SpectralDataBufferAudioTime))>LVM_MAXINT_32))||
+
+ ((GetSpectrumAudioTime > pLVPSA_Inst->SpectralDataBufferAudioTime)&&
+ (((GetSpectrumAudioTime>=0)&&(pLVPSA_Inst->SpectralDataBufferAudioTime>=0))||
+ ((GetSpectrumAudioTime<=0)&&(pLVPSA_Inst->SpectralDataBufferAudioTime<=0))||
+ (((GetSpectrumAudioTime>=0)&&(pLVPSA_Inst->SpectralDataBufferAudioTime<=0))&&
+ (((LVM_INT32)(GetSpectrumAudioTime - pLVPSA_Inst->SpectralDataBufferAudioTime))<LVM_MAXINT_32))))||
+
+ (StatusDelta > (LVM_INT32)pLVPSA_Inst->SpectralDataBufferLength) ||
+ (!StatusDelta))
+ {
+ for(ii = 0; ii < pLVPSA_Inst->nBands; ii++)
+ {
+ pCurrentValues[ii] = 0;
+ pPeakValues[ii] = 0;
+ }
+ return(LVPSA_OK);
+ }
+ /* Set the reading pointer */
+ if((LVM_INT32)(StatusDelta * pLVPSA_Inst->nBands) > (pLVPSA_Inst->pSpectralDataBufferWritePointer - pLVPSA_Inst->pSpectralDataBufferStart))
+ {
+ pRead = pLVPSA_Inst->pSpectralDataBufferWritePointer + (pLVPSA_Inst->SpectralDataBufferLength - (LVM_UINT32)StatusDelta) * pLVPSA_Inst->nBands;
+ }
+ else
+ {
+ pRead = pLVPSA_Inst->pSpectralDataBufferWritePointer - StatusDelta * pLVPSA_Inst->nBands;
+ }
+
+ /* Read the status buffer and fill the output buffers */
+ for(ii = 0; ii < pLVPSA_Inst->nBands; ii++)
+ {
+ pCurrentValues[ii] = pRead[ii];
+ if(pLVPSA_Inst->pPreviousPeaks[ii] <= pRead[ii])
+ {
+ pLVPSA_Inst->pPreviousPeaks[ii] = pRead[ii];
+ }
+ else if(pLVPSA_Inst->pPreviousPeaks[ii] != 0)
+ {
+ LVM_INT32 temp;
+ /*Re-compute max values for decay */
+ temp = (LVM_INT32)(LVPSA_MAXUNSIGNEDCHAR - pLVPSA_Inst->pPreviousPeaks[ii]);
+ temp = ((temp * LVPSA_MAXLEVELDECAYFACTOR)>>LVPSA_MAXLEVELDECAYSHIFT);
+ /* If the gain has no effect, "help" the value to increase */
+ if(temp == (LVPSA_MAXUNSIGNEDCHAR - pLVPSA_Inst->pPreviousPeaks[ii]))
+ {
+ temp += 1;
+ }
+ /* Saturate */
+ temp = (temp > LVPSA_MAXUNSIGNEDCHAR) ? LVPSA_MAXUNSIGNEDCHAR : temp;
+ /* Store new max level */
+ pLVPSA_Inst->pPreviousPeaks[ii] = (LVM_UINT8)(LVPSA_MAXUNSIGNEDCHAR - temp);
+ }
+
+ pPeakValues[ii] = pLVPSA_Inst->pPreviousPeaks[ii];
+ }
+
+ return(LVPSA_OK);
+}
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_QPD.h b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_QPD.h
index 99d844b..609a485 100644
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_QPD.h
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_QPD.h
@@ -20,25 +20,18 @@
#include "LVM_Types.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
typedef struct
{
LVM_INT32 *pDelay; /* pointer to the delayed samples (data of 32 bits) */
LVM_INT32 Coefs[2]; /* pointer to the filter coefficients */
}QPD_State_t, *pQPD_State_t;
-#ifdef BUILD_FLOAT
typedef struct
{
/* pointer to the delayed samples (data of 32 bits) */
LVM_FLOAT *pDelay;
LVM_FLOAT Coefs[2]; /* pointer to the filter coefficients */
}QPD_FLOAT_State_t, *pQPD_FLOAT_State_t;
-#endif
typedef struct
{
@@ -47,15 +40,12 @@
} QPD_C32_Coefs, *PQPD_C32_Coefs;
-#ifdef BUILD_FLOAT
typedef struct
{
LVM_FLOAT KP; /*should store a0*/
LVM_FLOAT KM; /*should store b2*/
} QPD_FLOAT_Coefs, *PQPD_FLOAT_Coefs;
-#endif
-
typedef struct
{
@@ -63,14 +53,12 @@
} QPD_Taps_t, *pQPD_Taps_t;
-#ifdef BUILD_FLOAT
typedef struct
{
LVM_FLOAT Storage[1];
} QPD_FLOAT_Taps_t, *pQPD_FLOAT_Taps_t;
-#endif
/************************************************************************************/
/* */
/* FUNCTION: LVPSA_QPD_Process */
@@ -89,12 +77,10 @@
LVM_INT16 numSamples,
LVM_INT16 BandIndex);
-#ifdef BUILD_FLOAT
void LVPSA_QPD_Process_Float ( void *hInstance,
LVM_FLOAT *pInSamps,
LVM_INT16 numSamples,
LVM_INT16 BandIndex);
-#endif
/************************************************************************************/
/* */
/* FUNCTION: LVPSA_QPD_Init */
@@ -113,15 +99,10 @@
void LVPSA_QPD_Init ( QPD_State_t *pInstance,
QPD_Taps_t *pTaps,
QPD_C32_Coefs *pCoef );
-#ifdef BUILD_FLOAT
void LVPSA_QPD_Init_Float ( QPD_FLOAT_State_t *pInstance,
QPD_FLOAT_Taps_t *pTaps,
QPD_FLOAT_Coefs *pCoef );
-#endif
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
#endif
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_QPD_Init.c b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_QPD_Init.c
deleted file mode 100644
index 2cc32ab..0000000
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_QPD_Init.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "LVPSA_QPD.h"
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVPSA_QPD_Init */
-/* */
-/* DESCRIPTION: */
-/* Initialize a quasi peak filter instance. */
-/* */
-/* PARAMETERS: */
-/* pQPD_State Pointer to the filter state */
-/* pTaps Pointer to the filter's taps */
-/* pCoef Pointer to the filter's coefficients */
-/* */
-/* RETURNS: void */
-/* */
-/************************************************************************************/
-void LVPSA_QPD_Init ( pQPD_State_t pQPD_State,
- QPD_Taps_t *pTaps,
- QPD_C32_Coefs *pCoef )
-{
- pQPD_State->pDelay = pTaps->Storage;
- pQPD_State->Coefs[0] = pCoef->KP;
- pQPD_State->Coefs[1] = pCoef->KM;
-}
-
-#ifdef BUILD_FLOAT
-void LVPSA_QPD_Init_Float ( pQPD_FLOAT_State_t pQPD_State,
- QPD_FLOAT_Taps_t *pTaps,
- QPD_FLOAT_Coefs *pCoef )
-{
- pQPD_State->pDelay = pTaps->Storage;
- pQPD_State->Coefs[0] = ((LVM_FLOAT)pCoef->KP);
- pQPD_State->Coefs[1] = ((LVM_FLOAT)pCoef->KM);
-}
-#endif
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_QPD_Init.cpp b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_QPD_Init.cpp
new file mode 100644
index 0000000..2dbf694
--- /dev/null
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_QPD_Init.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LVPSA_QPD.h"
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVPSA_QPD_Init */
+/* */
+/* DESCRIPTION: */
+/* Initialize a quasi peak filter instance. */
+/* */
+/* PARAMETERS: */
+/* pQPD_State Pointer to the filter state */
+/* pTaps Pointer to the filter's taps */
+/* pCoef Pointer to the filter's coefficients */
+/* */
+/* RETURNS: void */
+/* */
+/************************************************************************************/
+void LVPSA_QPD_Init ( pQPD_State_t pQPD_State,
+ QPD_Taps_t *pTaps,
+ QPD_C32_Coefs *pCoef )
+{
+ pQPD_State->pDelay = pTaps->Storage;
+ pQPD_State->Coefs[0] = pCoef->KP;
+ pQPD_State->Coefs[1] = pCoef->KM;
+}
+
+void LVPSA_QPD_Init_Float ( pQPD_FLOAT_State_t pQPD_State,
+ QPD_FLOAT_Taps_t *pTaps,
+ QPD_FLOAT_Coefs *pCoef )
+{
+ pQPD_State->pDelay = pTaps->Storage;
+ pQPD_State->Coefs[0] = ((LVM_FLOAT)pCoef->KP);
+ pQPD_State->Coefs[1] = ((LVM_FLOAT)pCoef->KM);
+}
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_QPD_Process.c b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_QPD_Process.c
deleted file mode 100644
index e233172..0000000
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_QPD_Process.c
+++ /dev/null
@@ -1,360 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "LVPSA_QPD.h"
-#include "LVPSA_Private.h"
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVPSA_QPD_WritePeak */
-/* */
-/* DESCRIPTION: */
-/* Write a level value in the buffer in the corresponding band. */
-/* */
-/* PARAMETERS: */
-/* pInst Pointer to the LVPSA instance */
-/* ppWrite Pointer to pointer to the buffer */
-/* CallNumber Number of the band the value should be written in */
-/* Value Value to write in the buffer */
-/* */
-/* RETURNS: void */
-/* */
-/************************************************************************************/
-void LVPSA_QPD_WritePeak( pLVPSA_InstancePr_t pLVPSA_Inst,
- LVM_UINT8 **ppWrite,
- LVM_INT16 BandIndex,
- LVM_INT16 Value );
-
-#ifdef BUILD_FLOAT
-void LVPSA_QPD_WritePeak_Float( pLVPSA_InstancePr_t pLVPSA_Inst,
- LVM_UINT8 **ppWrite,
- LVM_INT16 BandIndex,
- LVM_FLOAT Value );
-#endif
-/************************************************************************************/
-/* */
-/* FUNCTION: LVPSA_QPD_Process */
-/* */
-/* DESCRIPTION: */
-/* Apply downsampling, post gain, quasi peak filtering and write the levels values */
-/* in the buffer every 20 ms. */
-/* */
-/* PARAMETERS: */
-/* */
-/* RETURNS: void */
-/* */
-/************************************************************************************/
-#ifndef BUILD_FLOAT
-void LVPSA_QPD_Process ( void *hInstance,
- LVM_INT16 *pInSamps,
- LVM_INT16 numSamples,
- LVM_INT16 BandIndex)
-{
-
- /******************************************************************************
- PARAMETERS
- *******************************************************************************/
- LVPSA_InstancePr_t *pLVPSA_Inst = (LVPSA_InstancePr_t*)hInstance;
- QPD_State_t *pQPDState = (QPD_State_t*)&pLVPSA_Inst->pQPD_States[BandIndex];
-
- /* Pointer to taps */
- LVM_INT32* pDelay = pQPDState->pDelay;
-
- /* Parameters needed during quasi peak calculations */
- LVM_INT32 X0;
- LVM_INT32 temp,temp2;
- LVM_INT32 accu;
- LVM_INT16 Xg0;
- LVM_INT16 D0;
- LVM_INT16 V0 = (LVM_INT16)(*pDelay);
-
- /* Filter's coef */
- LVM_INT32 Kp = pQPDState->Coefs[0];
- LVM_INT32 Km = pQPDState->Coefs[1];
-
- LVM_INT16 ii = numSamples;
-
- LVM_UINT8 *pWrite = pLVPSA_Inst->pSpectralDataBufferWritePointer;
- LVM_INT32 BufferUpdateSamplesCount = pLVPSA_Inst->BufferUpdateSamplesCount;
- LVM_UINT16 DownSamplingFactor = pLVPSA_Inst->DownSamplingFactor;
-
- /******************************************************************************
- INITIALIZATION
- *******************************************************************************/
- /* Correct the pointer to take the first down sampled signal sample */
- pInSamps += pLVPSA_Inst->DownSamplingCount;
- /* Correct also the number of samples */
- ii = (LVM_INT16)(ii - (LVM_INT16)pLVPSA_Inst->DownSamplingCount);
-
- while (ii > 0)
- {
- /* Apply post gain */
- X0 = ((*pInSamps) * pLVPSA_Inst->pPostGains[BandIndex]) >> (LVPSA_GAINSHIFT-1); /* - 1 to compensate scaling in process function*/
- pInSamps = pInSamps + DownSamplingFactor;
-
- /* Saturate and take absolute value */
- if(X0 < 0)
- X0 = -X0;
- if (X0 > 0x7FFF)
- Xg0 = 0x7FFF;
- else
- Xg0 = (LVM_INT16)(X0);
-
-
- /* Quasi peak filter calculation */
- D0 = (LVM_INT16)(Xg0 - V0);
-
- temp2 = (LVM_INT32)D0;
- MUL32x32INTO32(temp2,Kp,accu,31);
-
- D0 = (LVM_INT16)(D0>>1);
- if (D0 < 0){
- D0 = (LVM_INT16)(-D0);
- }
-
- temp2 = (LVM_INT32)D0;
- MUL32x32INTO32((LVM_INT32)D0,Km,temp,31);
- accu +=temp + Xg0;
-
- if (accu > 0x7FFF)
- accu = 0x7FFF;
- else if(accu < 0)
- accu = 0x0000;
-
- V0 = (LVM_INT16)accu;
-
- if(((pLVPSA_Inst->nSamplesBufferUpdate - BufferUpdateSamplesCount) < DownSamplingFactor))
- {
- LVPSA_QPD_WritePeak( pLVPSA_Inst,
- &pWrite,
- BandIndex,
- V0);
- BufferUpdateSamplesCount -= pLVPSA_Inst->nSamplesBufferUpdate;
- pLVPSA_Inst->LocalSamplesCount = (LVM_UINT16)(numSamples - ii);
- }
- BufferUpdateSamplesCount+=DownSamplingFactor;
-
- ii = (LVM_INT16)(ii-DownSamplingFactor);
-
- }
-
- /* Store last taps in memory */
- *pDelay = (LVM_INT32)(V0);
-
- /* If this is the last call to the function after last band processing,
- update the parameters. */
- if(BandIndex == (pLVPSA_Inst->nRelevantFilters-1))
- {
- pLVPSA_Inst->pSpectralDataBufferWritePointer = pWrite;
- /* Adjustment for 11025Hz input, 220,5 is normally
- the exact number of samples for 20ms.*/
- if((pLVPSA_Inst->pSpectralDataBufferWritePointer != pWrite)&&(pLVPSA_Inst->CurrentParams.Fs == LVM_FS_11025))
- {
- if(pLVPSA_Inst->nSamplesBufferUpdate == 220)
- {
- pLVPSA_Inst->nSamplesBufferUpdate = 221;
- }
- else
- {
- pLVPSA_Inst->nSamplesBufferUpdate = 220;
- }
- }
- pLVPSA_Inst->pSpectralDataBufferWritePointer = pWrite;
- pLVPSA_Inst->BufferUpdateSamplesCount = BufferUpdateSamplesCount;
- pLVPSA_Inst->DownSamplingCount = (LVM_UINT16)(-ii);
- }
-}
-#else
-void LVPSA_QPD_Process_Float ( void *hInstance,
- LVM_FLOAT *pInSamps,
- LVM_INT16 numSamples,
- LVM_INT16 BandIndex)
-{
-
- /******************************************************************************
- PARAMETERS
- *******************************************************************************/
- LVPSA_InstancePr_t *pLVPSA_Inst = (LVPSA_InstancePr_t*)hInstance;
- QPD_FLOAT_State_t *pQPDState = (QPD_FLOAT_State_t*)&pLVPSA_Inst->pQPD_States[BandIndex];
-
- /* Pointer to taps */
- LVM_FLOAT* pDelay = pQPDState->pDelay;
-
- /* Parameters needed during quasi peak calculations */
- LVM_FLOAT X0;
- LVM_FLOAT temp,temp2;
- LVM_FLOAT accu;
- LVM_FLOAT Xg0;
- LVM_FLOAT D0;
- LVM_FLOAT V0 = (LVM_FLOAT)(*pDelay);
-
- /* Filter's coef */
- LVM_FLOAT Kp = ((LVM_FLOAT)(pQPDState->Coefs[0]));
- LVM_FLOAT Km = ((LVM_FLOAT)(pQPDState->Coefs[1]));
-
- LVM_INT16 ii = numSamples;
-
- LVM_UINT8 *pWrite = pLVPSA_Inst->pSpectralDataBufferWritePointer;
- LVM_INT32 BufferUpdateSamplesCount = pLVPSA_Inst->BufferUpdateSamplesCount;
- LVM_UINT16 DownSamplingFactor = pLVPSA_Inst->DownSamplingFactor;
-
- /******************************************************************************
- INITIALIZATION
- *******************************************************************************/
- /* Correct the pointer to take the first down sampled signal sample */
- pInSamps += pLVPSA_Inst->DownSamplingCount;
- /* Correct also the number of samples */
- ii = (LVM_INT16)(ii - (LVM_INT16)pLVPSA_Inst->DownSamplingCount);
-
- while (ii > 0)
- {
- /* Apply post gain */
- /* - 1 to compensate scaling in process function*/
- X0 = (*pInSamps) * pLVPSA_Inst->pPostGains[BandIndex];
- pInSamps = pInSamps + DownSamplingFactor;
-
- /* Saturate and take absolute value */
- if(X0 < 0.0f)
- X0 = -X0;
- if (X0 > 1.0f)
- Xg0 = 1.0f;
- else
- Xg0 =X0;
-
-
- /* Quasi peak filter calculation */
- D0 = Xg0 - V0;
-
- temp2 = D0;
-
- accu = temp2 * Kp;
- D0 = D0 / 2.0f;
- if (D0 < 0.0f){
- D0 = -D0;
- }
-
- temp2 = D0;
-
- temp = D0 * Km;
- accu += temp + Xg0;
-
- if (accu > 1.0f)
- accu = 1.0f;
- else if(accu < 0.0f)
- accu = 0.0f;
-
- V0 = accu;
-
- if(((pLVPSA_Inst->nSamplesBufferUpdate - BufferUpdateSamplesCount) < DownSamplingFactor))
- {
- LVPSA_QPD_WritePeak_Float( pLVPSA_Inst,
- &pWrite,
- BandIndex,
- V0);
-
- BufferUpdateSamplesCount -= pLVPSA_Inst->nSamplesBufferUpdate;
- pLVPSA_Inst->LocalSamplesCount = (LVM_UINT16)(numSamples - ii);
- }
- BufferUpdateSamplesCount += DownSamplingFactor;
-
- ii = (LVM_INT16)(ii - DownSamplingFactor);
-
- }
-
- /* Store last taps in memory */
- *pDelay = V0;
-
- /* If this is the last call to the function after last band processing,
- update the parameters. */
- if(BandIndex == (pLVPSA_Inst->nRelevantFilters - 1))
- {
- pLVPSA_Inst->pSpectralDataBufferWritePointer = pWrite;
- /* Adjustment for 11025Hz input, 220,5 is normally
- the exact number of samples for 20ms.*/
- if((pLVPSA_Inst->pSpectralDataBufferWritePointer != pWrite)&&
- (pLVPSA_Inst->CurrentParams.Fs == LVM_FS_11025))
- {
- if(pLVPSA_Inst->nSamplesBufferUpdate == 220)
- {
- pLVPSA_Inst->nSamplesBufferUpdate = 221;
- }
- else
- {
- pLVPSA_Inst->nSamplesBufferUpdate = 220;
- }
- }
- pLVPSA_Inst->pSpectralDataBufferWritePointer = pWrite;
- pLVPSA_Inst->BufferUpdateSamplesCount = BufferUpdateSamplesCount;
- pLVPSA_Inst->DownSamplingCount = (LVM_UINT16)(-ii);
- }
-}
-#endif
-/************************************************************************************/
-/* */
-/* FUNCTION: LVPSA_QPD_WritePeak */
-/* */
-/* DESCRIPTION: */
-/* Write a level value in the spectrum data buffer in the corresponding band. */
-/* */
-/* PARAMETERS: */
-/* pLVPSA_Inst Pointer to the LVPSA instance */
-/* ppWrite Pointer to pointer to the buffer */
-/* CallNumber Number of the band the value should be written in */
-/* Value Value to write in the spectrum data buffer */
-/* */
-/* RETURNS: void */
-/* */
-/************************************************************************************/
-void LVPSA_QPD_WritePeak( pLVPSA_InstancePr_t pLVPSA_Inst,
- LVM_UINT8 **ppWrite,
- LVM_INT16 BandIndex,
- LVM_INT16 Value )
-{
- LVM_UINT8 *pWrite = *ppWrite;
-
-
- /* Write the value and update the write pointer */
- *(pWrite + BandIndex) = (LVM_UINT8)(Value>>7);
- pWrite += pLVPSA_Inst->nBands;
- if (pWrite == (pLVPSA_Inst->pSpectralDataBufferStart + pLVPSA_Inst->nBands * pLVPSA_Inst->SpectralDataBufferLength))
- {
- pWrite = pLVPSA_Inst->pSpectralDataBufferStart;
- }
-
- *ppWrite = pWrite;
-
-}
-#ifdef BUILD_FLOAT
-void LVPSA_QPD_WritePeak_Float( pLVPSA_InstancePr_t pLVPSA_Inst,
- LVM_UINT8 **ppWrite,
- LVM_INT16 BandIndex,
- LVM_FLOAT Value )
-{
- LVM_UINT8 *pWrite = *ppWrite;
-
- /* Write the value and update the write pointer */
- *(pWrite + BandIndex) = (LVM_UINT8)(Value * 256);
- pWrite += pLVPSA_Inst->nBands;
- if (pWrite == (pLVPSA_Inst->pSpectralDataBufferStart + pLVPSA_Inst->nBands * \
- pLVPSA_Inst->SpectralDataBufferLength))
- {
- pWrite = pLVPSA_Inst->pSpectralDataBufferStart;
- }
-
- *ppWrite = pWrite;
-}
-#endif
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_QPD_Process.cpp b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_QPD_Process.cpp
new file mode 100644
index 0000000..8805420
--- /dev/null
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_QPD_Process.cpp
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LVPSA_QPD.h"
+#include "LVPSA_Private.h"
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVPSA_QPD_WritePeak */
+/* */
+/* DESCRIPTION: */
+/* Write a level value in the buffer in the corresponding band. */
+/* */
+/* PARAMETERS: */
+/* pInst Pointer to the LVPSA instance */
+/* ppWrite Pointer to pointer to the buffer */
+/* CallNumber Number of the band the value should be written in */
+/* Value Value to write in the buffer */
+/* */
+/* RETURNS: void */
+/* */
+/************************************************************************************/
+void LVPSA_QPD_WritePeak( pLVPSA_InstancePr_t pLVPSA_Inst,
+ LVM_UINT8 **ppWrite,
+ LVM_INT16 BandIndex,
+ LVM_INT16 Value );
+
+void LVPSA_QPD_WritePeak_Float( pLVPSA_InstancePr_t pLVPSA_Inst,
+ LVM_UINT8 **ppWrite,
+ LVM_INT16 BandIndex,
+ LVM_FLOAT Value );
+/************************************************************************************/
+/* */
+/* FUNCTION: LVPSA_QPD_Process */
+/* */
+/* DESCRIPTION: */
+/* Apply downsampling, post gain, quasi peak filtering and write the levels values */
+/* in the buffer every 20 ms. */
+/* */
+/* PARAMETERS: */
+/* */
+/* RETURNS: void */
+/* */
+/************************************************************************************/
+void LVPSA_QPD_Process_Float ( void *hInstance,
+ LVM_FLOAT *pInSamps,
+ LVM_INT16 numSamples,
+ LVM_INT16 BandIndex)
+{
+
+ /******************************************************************************
+ PARAMETERS
+ *******************************************************************************/
+ LVPSA_InstancePr_t *pLVPSA_Inst = (LVPSA_InstancePr_t*)hInstance;
+ QPD_FLOAT_State_t *pQPDState = (QPD_FLOAT_State_t*)&pLVPSA_Inst->pQPD_States[BandIndex];
+
+ /* Pointer to taps */
+ LVM_FLOAT* pDelay = pQPDState->pDelay;
+
+ /* Parameters needed during quasi peak calculations */
+ LVM_FLOAT X0;
+ LVM_FLOAT temp,temp2;
+ LVM_FLOAT accu;
+ LVM_FLOAT Xg0;
+ LVM_FLOAT D0;
+ LVM_FLOAT V0 = (LVM_FLOAT)(*pDelay);
+
+ /* Filter's coef */
+ LVM_FLOAT Kp = ((LVM_FLOAT)(pQPDState->Coefs[0]));
+ LVM_FLOAT Km = ((LVM_FLOAT)(pQPDState->Coefs[1]));
+
+ LVM_INT16 ii = numSamples;
+
+ LVM_UINT8 *pWrite = pLVPSA_Inst->pSpectralDataBufferWritePointer;
+ LVM_INT32 BufferUpdateSamplesCount = pLVPSA_Inst->BufferUpdateSamplesCount;
+ LVM_UINT16 DownSamplingFactor = pLVPSA_Inst->DownSamplingFactor;
+
+ /******************************************************************************
+ INITIALIZATION
+ *******************************************************************************/
+ /* Correct the pointer to take the first down sampled signal sample */
+ pInSamps += pLVPSA_Inst->DownSamplingCount;
+ /* Correct also the number of samples */
+ ii = (LVM_INT16)(ii - (LVM_INT16)pLVPSA_Inst->DownSamplingCount);
+
+ while (ii > 0)
+ {
+ /* Apply post gain */
+ /* - 1 to compensate scaling in process function*/
+ X0 = (*pInSamps) * pLVPSA_Inst->pPostGains[BandIndex];
+ pInSamps = pInSamps + DownSamplingFactor;
+
+ /* Saturate and take absolute value */
+ if(X0 < 0.0f)
+ X0 = -X0;
+ if (X0 > 1.0f)
+ Xg0 = 1.0f;
+ else
+ Xg0 =X0;
+
+ /* Quasi peak filter calculation */
+ D0 = Xg0 - V0;
+
+ temp2 = D0;
+
+ accu = temp2 * Kp;
+ D0 = D0 / 2.0f;
+ if (D0 < 0.0f){
+ D0 = -D0;
+ }
+
+ temp2 = D0;
+
+ temp = D0 * Km;
+ accu += temp + Xg0;
+
+ if (accu > 1.0f)
+ accu = 1.0f;
+ else if(accu < 0.0f)
+ accu = 0.0f;
+
+ V0 = accu;
+
+ if(((pLVPSA_Inst->nSamplesBufferUpdate - BufferUpdateSamplesCount) < DownSamplingFactor))
+ {
+ LVPSA_QPD_WritePeak_Float( pLVPSA_Inst,
+ &pWrite,
+ BandIndex,
+ V0);
+
+ BufferUpdateSamplesCount -= pLVPSA_Inst->nSamplesBufferUpdate;
+ pLVPSA_Inst->LocalSamplesCount = (LVM_UINT16)(numSamples - ii);
+ }
+ BufferUpdateSamplesCount += DownSamplingFactor;
+
+ ii = (LVM_INT16)(ii - DownSamplingFactor);
+
+ }
+
+ /* Store last taps in memory */
+ *pDelay = V0;
+
+ /* If this is the last call to the function after last band processing,
+ update the parameters. */
+ if(BandIndex == (pLVPSA_Inst->nRelevantFilters - 1))
+ {
+ pLVPSA_Inst->pSpectralDataBufferWritePointer = pWrite;
+ /* Adjustment for 11025Hz input, 220,5 is normally
+ the exact number of samples for 20ms.*/
+ if((pLVPSA_Inst->pSpectralDataBufferWritePointer != pWrite)&&
+ (pLVPSA_Inst->CurrentParams.Fs == LVM_FS_11025))
+ {
+ if(pLVPSA_Inst->nSamplesBufferUpdate == 220)
+ {
+ pLVPSA_Inst->nSamplesBufferUpdate = 221;
+ }
+ else
+ {
+ pLVPSA_Inst->nSamplesBufferUpdate = 220;
+ }
+ }
+ pLVPSA_Inst->pSpectralDataBufferWritePointer = pWrite;
+ pLVPSA_Inst->BufferUpdateSamplesCount = BufferUpdateSamplesCount;
+ pLVPSA_Inst->DownSamplingCount = (LVM_UINT16)(-ii);
+ }
+}
+/************************************************************************************/
+/* */
+/* FUNCTION: LVPSA_QPD_WritePeak */
+/* */
+/* DESCRIPTION: */
+/* Write a level value in the spectrum data buffer in the corresponding band. */
+/* */
+/* PARAMETERS: */
+/* pLVPSA_Inst Pointer to the LVPSA instance */
+/* ppWrite Pointer to pointer to the buffer */
+/* CallNumber Number of the band the value should be written in */
+/* Value Value to write in the spectrum data buffer */
+/* */
+/* RETURNS: void */
+/* */
+/************************************************************************************/
+void LVPSA_QPD_WritePeak( pLVPSA_InstancePr_t pLVPSA_Inst,
+ LVM_UINT8 **ppWrite,
+ LVM_INT16 BandIndex,
+ LVM_INT16 Value )
+{
+ LVM_UINT8 *pWrite = *ppWrite;
+
+ /* Write the value and update the write pointer */
+ *(pWrite + BandIndex) = (LVM_UINT8)(Value>>7);
+ pWrite += pLVPSA_Inst->nBands;
+ if (pWrite == (pLVPSA_Inst->pSpectralDataBufferStart + pLVPSA_Inst->nBands * pLVPSA_Inst->SpectralDataBufferLength))
+ {
+ pWrite = pLVPSA_Inst->pSpectralDataBufferStart;
+ }
+
+ *ppWrite = pWrite;
+
+}
+void LVPSA_QPD_WritePeak_Float( pLVPSA_InstancePr_t pLVPSA_Inst,
+ LVM_UINT8 **ppWrite,
+ LVM_INT16 BandIndex,
+ LVM_FLOAT Value )
+{
+ LVM_UINT8 *pWrite = *ppWrite;
+
+ /* Write the value and update the write pointer */
+ *(pWrite + BandIndex) = (LVM_UINT8)(Value * 256);
+ pWrite += pLVPSA_Inst->nBands;
+ if (pWrite == (pLVPSA_Inst->pSpectralDataBufferStart + pLVPSA_Inst->nBands * \
+ pLVPSA_Inst->SpectralDataBufferLength))
+ {
+ pWrite = pLVPSA_Inst->pSpectralDataBufferStart;
+ }
+
+ *ppWrite = pWrite;
+}
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Tables.c b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Tables.c
deleted file mode 100644
index f8af496..0000000
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Tables.c
+++ /dev/null
@@ -1,408 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-/************************************************************************************/
-/* */
-/* Includes */
-/* */
-/************************************************************************************/
-
-#include "LVPSA.h"
-#include "LVPSA_QPD.h"
-/************************************************************************************/
-/* */
-/* Sample rate table */
-/* */
-/************************************************************************************/
-
-/*
- * Sample rate table for converting between the enumerated type and the actual
- * frequency
- */
-#ifndef HIGHER_FS
-const LVM_UINT16 LVPSA_SampleRateTab[] = { 8000, /* 8kS/s */
- 11025,
- 12000,
- 16000,
- 22050,
- 24000,
- 32000,
- 44100,
- 48000}; /* 48kS/s */
-#else
-const LVM_UINT32 LVPSA_SampleRateTab[] = { 8000, /* 8kS/s */
- 11025,
- 12000,
- 16000,
- 22050,
- 24000,
- 32000,
- 44100,
- 48000,
- 88200,
- 96000,
- 176400,
- 192000}; /* 192kS/s */
-#endif
-
-/************************************************************************************/
-/* */
-/* Sample rate inverse table */
-/* */
-/************************************************************************************/
-
-/*
- * Sample rate table for converting between the enumerated type and the actual
- * frequency
- */
-const LVM_UINT32 LVPSA_SampleRateInvTab[] = { 268435, /* 8kS/s */
- 194783,
- 178957,
- 134218,
- 97391,
- 89478,
- 67109,
- 48696,
- 44739
-#ifdef HIGHER_FS
- ,24348
- ,22369
- ,12174
- ,11185 /* 192kS/s */
-#endif
- };
-
-
-
-/************************************************************************************/
-/* */
-/* Number of samples in 20ms */
-/* */
-/************************************************************************************/
-
-/*
- * Table for converting between the enumerated type and the number of samples
- * during 20ms
- */
-const LVM_UINT16 LVPSA_nSamplesBufferUpdate[] = { 160, /* 8kS/s */
- 220,
- 240,
- 320,
- 441,
- 480,
- 640,
- 882,
- 960
-#ifdef HIGHER_FS
- ,1764
- ,1920
- ,3528
- ,3840 /* 192kS/s */
-#endif
- };
-/************************************************************************************/
-/* */
-/* Down sampling factors */
-/* */
-/************************************************************************************/
-
-/*
- * Table for converting between the enumerated type and the down sampling factor
- */
-const LVM_UINT16 LVPSA_DownSamplingFactor[] = { 5, /* 8000 S/s */
- 7, /* 11025 S/s */
- 8, /* 12000 S/s */
- 10, /* 16000 S/s */
- 15, /* 22050 S/s */
- 16, /* 24000 S/s */
- 21, /* 32000 S/s */
- 30, /* 44100 S/s */
- 32 /* 48000 S/s */
-#ifdef HIGHER_FS
- ,60 /* 88200 S/s */
- ,64 /* 96000 S/s */
- ,120 /* 176400 S/s */
- ,128 /*192000 S/s */
-#endif
- };
-
-
-/************************************************************************************/
-/* */
-/* Coefficient calculation tables */
-/* */
-/************************************************************************************/
-
-/*
- * Table for 2 * Pi / Fs
- */
-const LVM_INT16 LVPSA_TwoPiOnFsTable[] = { 26354, /* 8kS/s */
- 19123,
- 17569,
- 13177,
- 9561,
- 8785,
- 6588,
- 4781,
- 4392
-#ifdef HIGHER_FS
- ,2390
- ,2196
- ,1195
- ,1098 /* 192kS/s */
-#endif
- };
-
-#ifdef BUILD_FLOAT
-const LVM_FLOAT LVPSA_Float_TwoPiOnFsTable[] = { 0.8042847f, /* 8kS/s */
- 0.5836054f,
- 0.5361796f,
- 0.4021423f,
- 0.2917874f,
- 0.2681051f,
- 0.2010559f,
- 0.1459089f,
- 0.1340372f
-#ifdef HIGHER_FS
- ,0.0729476f
- ,0.0670186f
- ,0.0364738f
- ,0.0335093f /* 192kS/s */
-#endif
- };
-
-#endif
-/*
- * Gain table
- */
-const LVM_INT16 LVPSA_GainTable[] = { 364, /* -15dB gain */
- 408,
- 458,
- 514,
- 577,
- 647,
- 726,
- 815,
- 914,
- 1026,
- 1151,
- 1292,
- 1449,
- 1626,
- 1825,
- 2048, /* 0dB gain */
- 2297,
- 2578,
- 2892,
- 3245,
- 3641,
- 4096,
- 4584,
- 5144,
- 5772,
- 6476,
- 7266,
- 8153,
- 9148,
- 10264,
- 11576}; /* +15dB gain */
-
-#ifdef BUILD_FLOAT
-const LVM_FLOAT LVPSA_Float_GainTable[]={ 0.177734375f, /* -15dB gain */
- 0.199218750f,
- 0.223632812f,
- 0.250976562f,
- 0.281738281f,
- 0.315917968f,
- 0.354492187f,
- 0.397949218f,
- 0.446289062f,
- 0.500976562f,
- 0.562011718f,
- 0.630859375f,
- 0.707519531f,
- 0.793945312f,
- 0.891113281f,
- 1.000000000f, /* 0dB gain */
- 1.121582031f,
- 1.258789062f,
- 1.412109375f,
- 1.584472656f,
- 1.777832031f,
- 2.000000000f,
- 2.238281250f,
- 2.511718750f,
- 2.818359375f,
- 3.162109375f,
- 3.547851562f,
- 3.980957031f,
- 4.466796875f,
- 5.011718750f,
- 5.652343750f}; /* +15dB gain */
-#endif
-/************************************************************************************/
-/* */
-/* Cosone polynomial coefficients */
-/* */
-/************************************************************************************/
-
-/*
- * Coefficients for calculating the cosine with the equation:
- *
- * Cos(x) = (2^Shifts)*(a0 + a1*x + a2*x^2 + a3*x^3 + a4*x^4 + a5*x^5)
- *
- * These coefficients expect the input, x, to be in the range 0 to 32768 respresenting
- * a range of 0 to Pi. The output is in the range 32767 to -32768 representing the range
- * +1.0 to -1.0
- */
-const LVM_INT16 LVPSA_CosCoef[] = { 3, /* Shifts */
- 4096, /* a0 */
- -36, /* a1 */
- -19725, /* a2 */
- -2671, /* a3 */
- 23730, /* a4 */
- -9490}; /* a5 */
-#ifdef BUILD_FLOAT
-const LVM_FLOAT LVPSA_Float_CosCoef[] = { 3, /* Shifts */
- 0.1250038f, /* a0 */
- -0.0010986f, /* a1 */
- -0.6019775f, /* a2 */
- -0.0815149f, /* a3 */
- 0.7242042f, /* a4 */
- -0.2896206f}; /* a5 */
-#endif
-/*
- * Coefficients for calculating the cosine error with the equation:
- *
- * CosErr(x) = (2^Shifts)*(a0 + a1*x + a2*x^2 + a3*x^3)
- *
- * These coefficients expect the input, x, to be in the range 0 to 32768 respresenting
- * a range of 0 to Pi/25. The output is in the range 0 to 32767 representing the range
- * 0.0 to 0.0078852986
- *
- * This is used to give a double precision cosine over the range 0 to Pi/25 using the
- * the equation:
- *
- * Cos(x) = 1.0 - CosErr(x)
- */
-const LVM_INT16 LVPSA_DPCosCoef[] = { 1, /* Shifts */
- 0, /* a0 */
- -6, /* a1 */
- 16586, /* a2 */
- -44}; /* a3 */
-#ifdef BUILD_FLOAT
-const LVM_FLOAT LVPSA_Float_DPCosCoef[] = {1.0f, /* Shifts */
- 0.0f, /* a0 */
- -0.00008311f, /* a1 */
- 0.50617999f, /* a2 */
- -0.00134281f}; /* a3 */
-#endif
-/************************************************************************************/
-/* */
-/* Quasi peak filter coefficients table */
-/* */
-/************************************************************************************/
-const QPD_C32_Coefs LVPSA_QPD_Coefs[] = {
-
- {0x80CEFD2B,0x00CB9B17}, /* 8kS/s */ /* LVPSA_SPEED_LOW */
- {0x80D242E7,0x00CED11D},
- {0x80DCBAF5,0x00D91679},
- {0x80CEFD2B,0x00CB9B17},
- {0x80E13739,0x00DD7CD3},
- {0x80DCBAF5,0x00D91679},
- {0x80D94BAF,0x00D5B7E7},
- {0x80E13739,0x00DD7CD3},
- {0x80DCBAF5,0x00D91679}, /* 48kS/s */
-
- {0x8587513D,0x055C22CF}, /* 8kS/s */ /* LVPSA_SPEED_MEDIUM */
- {0x859D2967,0x0570F007},
- {0x85E2EFAC,0x05B34D79},
- {0x8587513D,0x055C22CF},
- {0x8600C7B9,0x05CFA6CF},
- {0x85E2EFAC,0x05B34D79},
- {0x85CC1018,0x059D8F69},
- {0x8600C7B9,0x05CFA6CF},//{0x8600C7B9,0x05CFA6CF},
- {0x85E2EFAC,0x05B34D79}, /* 48kS/s */
-
- {0xA115EA7A,0x1CDB3F5C}, /* 8kS/s */ /* LVPSA_SPEED_HIGH */
- {0xA18475F0,0x1D2C83A2},
- {0xA2E1E950,0x1E2A532E},
- {0xA115EA7A,0x1CDB3F5C},
- {0xA375B2C6,0x1E943BBC},
- {0xA2E1E950,0x1E2A532E},
- {0xA26FF6BD,0x1DD81530},
- {0xA375B2C6,0x1E943BBC},
- {0xA2E1E950,0x1E2A532E}}; /* 48kS/s */
-
-#ifdef BUILD_FLOAT
-const QPD_FLOAT_Coefs LVPSA_QPD_Float_Coefs[] = {
-
- /* 8kS/s */ /* LVPSA_SPEED_LOW */
- {-0.9936831989325583f,0.0062135565094650f},
- {-0.9935833332128823f,0.0063115493394434f},
- {-0.9932638457976282f,0.0066249934025109f},
- {-0.9936831989325583f,0.0062135565094650f},
- {-0.9931269618682563f,0.0067592649720609f},
- {-0.9932638457976282f,0.0066249934025109f},
- {-0.9933686633594334f,0.0065221670083702f},
- {-0.9931269618682563f,0.0067592649720609f},
- /* 48kS/s */
- {-0.9932638457976282f,0.0066249934025109f},
-#ifdef HIGHER_FS
- {-0.9931269618682563f,0.0067592649720609f},
- {-0.9932638457976282f,0.0066249934025109f},
- {-0.9931269618682563f,0.0067592649720609f},
- {-0.9932638457976282f,0.0066249934025109f},
-#endif
- /* 8kS/s */ /* LVPSA_SPEED_MEDIUM */
- {-0.9568079425953329f,0.0418742666952312f},
- {-0.9561413046903908f,0.0425090822391212f},
- {-0.9540119562298059f,0.0445343819446862f},
- {-0.9568079425953329f,0.0418742666952312f},
- {-0.9531011912040412f,0.0453995238058269f},
- {-0.9540119562298059f,0.0445343819446862f},
- {-0.9547099955379963f,0.0438708555884659f},
- //{0x8600C7B9,0x05CFA6CF},
- {-0.9531011912040412f,0.0453995238058269f},
- /* 48kS/s */
- {-0.9540119562298059f,0.0445343819446862f},
-#ifdef HIGHER_FS
- {-0.9531011912040412f,0.0453995238058269f},
- {-0.9540119562298059f,0.0445343819446862f},
- {-0.9531011912040412f,0.0453995238058269f},
- {-0.9540119562298059f,0.0445343819446862f},
-#endif
- /* 8kS/s */ /* LVPSA_SPEED_HIGH */
- {-0.7415186790749431f,0.2254409026354551f},
- {-0.7381451204419136f,0.2279209652915597f},
- {-0.7274807319045067f,0.2356666540727019f},
- {-0.7415186790749431f,0.2254409026354551f},
- {-0.7229706319049001f,0.2388987224549055f},
- {-0.7274807319045067f,0.2356666540727019f},
- {-0.7309581353329122f,0.2331568226218224f},
- {-0.7229706319049001f,0.2388987224549055f},
- /* 48kS/s */
- {-0.7274807319045067f,0.2356666540727019f}
-#ifdef HIGHER_FS
- ,{-0.7229706319049001f,0.2388987224549055f}
- ,{-0.7274807319045067f,0.2356666540727019f}
- ,{-0.7229706319049001f,0.2388987224549055f}
- ,{-0.7274807319045067f,0.2356666540727019f}
-#endif
- };
-#endif
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Tables.cpp b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Tables.cpp
new file mode 100644
index 0000000..9f0aa02
--- /dev/null
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Tables.cpp
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/************************************************************************************/
+/* */
+/* Includes */
+/* */
+/************************************************************************************/
+
+#include "LVPSA.h"
+#include "LVPSA_QPD.h"
+#include "LVPSA_Tables.h"
+/************************************************************************************/
+/* */
+/* Sample rate table */
+/* */
+/************************************************************************************/
+
+/*
+ * Sample rate table for converting between the enumerated type and the actual
+ * frequency
+ */
+const LVM_UINT32 LVPSA_SampleRateTab[] = { 8000, /* 8kS/s */
+ 11025,
+ 12000,
+ 16000,
+ 22050,
+ 24000,
+ 32000,
+ 44100,
+ 48000,
+ 88200,
+ 96000,
+ 176400,
+ 192000}; /* 192kS/s */
+
+/************************************************************************************/
+/* */
+/* Sample rate inverse table */
+/* */
+/************************************************************************************/
+
+/*
+ * Sample rate table for converting between the enumerated type and the actual
+ * frequency
+ */
+const LVM_UINT32 LVPSA_SampleRateInvTab[] = { 268435, /* 8kS/s */
+ 194783,
+ 178957,
+ 134218,
+ 97391,
+ 89478,
+ 67109,
+ 48696,
+ 44739
+ ,24348
+ ,22369
+ ,12174
+ ,11185 /* 192kS/s */
+ };
+
+/************************************************************************************/
+/* */
+/* Number of samples in 20ms */
+/* */
+/************************************************************************************/
+
+/*
+ * Table for converting between the enumerated type and the number of samples
+ * during 20ms
+ */
+const LVM_UINT16 LVPSA_nSamplesBufferUpdate[] = { 160, /* 8kS/s */
+ 220,
+ 240,
+ 320,
+ 441,
+ 480,
+ 640,
+ 882,
+ 960
+ ,1764
+ ,1920
+ ,3528
+ ,3840 /* 192kS/s */
+ };
+/************************************************************************************/
+/* */
+/* Down sampling factors */
+/* */
+/************************************************************************************/
+
+/*
+ * Table for converting between the enumerated type and the down sampling factor
+ */
+const LVM_UINT16 LVPSA_DownSamplingFactor[] = { 5, /* 8000 S/s */
+ 7, /* 11025 S/s */
+ 8, /* 12000 S/s */
+ 10, /* 16000 S/s */
+ 15, /* 22050 S/s */
+ 16, /* 24000 S/s */
+ 21, /* 32000 S/s */
+ 30, /* 44100 S/s */
+ 32 /* 48000 S/s */
+ ,60 /* 88200 S/s */
+ ,64 /* 96000 S/s */
+ ,120 /* 176400 S/s */
+ ,128 /*192000 S/s */
+ };
+
+/************************************************************************************/
+/* */
+/* Coefficient calculation tables */
+/* */
+/************************************************************************************/
+
+/*
+ * Table for 2 * Pi / Fs
+ */
+const LVM_INT16 LVPSA_TwoPiOnFsTable[] = { 26354, /* 8kS/s */
+ 19123,
+ 17569,
+ 13177,
+ 9561,
+ 8785,
+ 6588,
+ 4781,
+ 4392
+ ,2390
+ ,2196
+ ,1195
+ ,1098 /* 192kS/s */
+ };
+
+const LVM_FLOAT LVPSA_Float_TwoPiOnFsTable[] = { 0.8042847f, /* 8kS/s */
+ 0.5836054f,
+ 0.5361796f,
+ 0.4021423f,
+ 0.2917874f,
+ 0.2681051f,
+ 0.2010559f,
+ 0.1459089f,
+ 0.1340372f
+ ,0.0729476f
+ ,0.0670186f
+ ,0.0364738f
+ ,0.0335093f /* 192kS/s */
+ };
+
+/*
+ * Gain table
+ */
+const LVM_INT16 LVPSA_GainTable[] = { 364, /* -15dB gain */
+ 408,
+ 458,
+ 514,
+ 577,
+ 647,
+ 726,
+ 815,
+ 914,
+ 1026,
+ 1151,
+ 1292,
+ 1449,
+ 1626,
+ 1825,
+ 2048, /* 0dB gain */
+ 2297,
+ 2578,
+ 2892,
+ 3245,
+ 3641,
+ 4096,
+ 4584,
+ 5144,
+ 5772,
+ 6476,
+ 7266,
+ 8153,
+ 9148,
+ 10264,
+ 11576}; /* +15dB gain */
+
+const LVM_FLOAT LVPSA_Float_GainTable[]={ 0.177734375f, /* -15dB gain */
+ 0.199218750f,
+ 0.223632812f,
+ 0.250976562f,
+ 0.281738281f,
+ 0.315917968f,
+ 0.354492187f,
+ 0.397949218f,
+ 0.446289062f,
+ 0.500976562f,
+ 0.562011718f,
+ 0.630859375f,
+ 0.707519531f,
+ 0.793945312f,
+ 0.891113281f,
+ 1.000000000f, /* 0dB gain */
+ 1.121582031f,
+ 1.258789062f,
+ 1.412109375f,
+ 1.584472656f,
+ 1.777832031f,
+ 2.000000000f,
+ 2.238281250f,
+ 2.511718750f,
+ 2.818359375f,
+ 3.162109375f,
+ 3.547851562f,
+ 3.980957031f,
+ 4.466796875f,
+ 5.011718750f,
+ 5.652343750f}; /* +15dB gain */
+/************************************************************************************/
+/* */
+/* Cosone polynomial coefficients */
+/* */
+/************************************************************************************/
+
+/*
+ * Coefficients for calculating the cosine with the equation:
+ *
+ * Cos(x) = (2^Shifts)*(a0 + a1*x + a2*x^2 + a3*x^3 + a4*x^4 + a5*x^5)
+ *
+ * These coefficients expect the input, x, to be in the range 0 to 32768 respresenting
+ * a range of 0 to Pi. The output is in the range 32767 to -32768 representing the range
+ * +1.0 to -1.0
+ */
+const LVM_INT16 LVPSA_CosCoef[] = { 3, /* Shifts */
+ 4096, /* a0 */
+ -36, /* a1 */
+ -19725, /* a2 */
+ -2671, /* a3 */
+ 23730, /* a4 */
+ -9490}; /* a5 */
+const LVM_FLOAT LVPSA_Float_CosCoef[] = { 3, /* Shifts */
+ 0.1250038f, /* a0 */
+ -0.0010986f, /* a1 */
+ -0.6019775f, /* a2 */
+ -0.0815149f, /* a3 */
+ 0.7242042f, /* a4 */
+ -0.2896206f}; /* a5 */
+/*
+ * Coefficients for calculating the cosine error with the equation:
+ *
+ * CosErr(x) = (2^Shifts)*(a0 + a1*x + a2*x^2 + a3*x^3)
+ *
+ * These coefficients expect the input, x, to be in the range 0 to 32768 respresenting
+ * a range of 0 to Pi/25. The output is in the range 0 to 32767 representing the range
+ * 0.0 to 0.0078852986
+ *
+ * This is used to give a double precision cosine over the range 0 to Pi/25 using the
+ * the equation:
+ *
+ * Cos(x) = 1.0 - CosErr(x)
+ */
+const LVM_INT16 LVPSA_DPCosCoef[] = { 1, /* Shifts */
+ 0, /* a0 */
+ -6, /* a1 */
+ 16586, /* a2 */
+ -44}; /* a3 */
+const LVM_FLOAT LVPSA_Float_DPCosCoef[] = {1.0f, /* Shifts */
+ 0.0f, /* a0 */
+ -0.00008311f, /* a1 */
+ 0.50617999f, /* a2 */
+ -0.00134281f}; /* a3 */
+/************************************************************************************/
+/* */
+/* Quasi peak filter coefficients table */
+/* */
+/************************************************************************************/
+const QPD_C32_Coefs LVPSA_QPD_Coefs[] = {
+ /* 8kS/s */ /* LVPSA_SPEED_LOW */
+ {(LVM_INT32)0x80CEFD2B,0x00CB9B17},
+ {(LVM_INT32)0x80D242E7,0x00CED11D},
+ {(LVM_INT32)0x80DCBAF5,0x00D91679},
+ {(LVM_INT32)0x80CEFD2B,0x00CB9B17},
+ {(LVM_INT32)0x80E13739,0x00DD7CD3},
+ {(LVM_INT32)0x80DCBAF5,0x00D91679},
+ {(LVM_INT32)0x80D94BAF,0x00D5B7E7},
+ {(LVM_INT32)0x80E13739,0x00DD7CD3},
+ {(LVM_INT32)0x80DCBAF5,0x00D91679}, /* 48kS/s */
+
+ /* 8kS/s */ /* LVPSA_SPEED_MEDIUM */
+ {(LVM_INT32)0x8587513D,0x055C22CF},
+ {(LVM_INT32)0x859D2967,0x0570F007},
+ {(LVM_INT32)0x85E2EFAC,0x05B34D79},
+ {(LVM_INT32)0x8587513D,0x055C22CF},
+ {(LVM_INT32)0x8600C7B9,0x05CFA6CF},
+ {(LVM_INT32)0x85E2EFAC,0x05B34D79},
+ {(LVM_INT32)0x85CC1018,0x059D8F69},
+ {(LVM_INT32)0x8600C7B9,0x05CFA6CF},
+ {(LVM_INT32)0x85E2EFAC,0x05B34D79}, /* 48kS/s */
+
+ /* 8kS/s */ /* LVPSA_SPEED_HIGH */
+ {(LVM_INT32)0xA115EA7A,0x1CDB3F5C},
+ {(LVM_INT32)0xA18475F0,0x1D2C83A2},
+ {(LVM_INT32)0xA2E1E950,0x1E2A532E},
+ {(LVM_INT32)0xA115EA7A,0x1CDB3F5C},
+ {(LVM_INT32)0xA375B2C6,0x1E943BBC},
+ {(LVM_INT32)0xA2E1E950,0x1E2A532E},
+ {(LVM_INT32)0xA26FF6BD,0x1DD81530},
+ {(LVM_INT32)0xA375B2C6,0x1E943BBC},
+ {(LVM_INT32)0xA2E1E950,0x1E2A532E}}; /* 48kS/s */
+
+const QPD_FLOAT_Coefs LVPSA_QPD_Float_Coefs[] = {
+
+ /* 8kS/s */ /* LVPSA_SPEED_LOW */
+ {-0.9936831989325583f,0.0062135565094650f},
+ {-0.9935833332128823f,0.0063115493394434f},
+ {-0.9932638457976282f,0.0066249934025109f},
+ {-0.9936831989325583f,0.0062135565094650f},
+ {-0.9931269618682563f,0.0067592649720609f},
+ {-0.9932638457976282f,0.0066249934025109f},
+ {-0.9933686633594334f,0.0065221670083702f},
+ {-0.9931269618682563f,0.0067592649720609f},
+ /* 48kS/s */
+ {-0.9932638457976282f,0.0066249934025109f},
+ {-0.9931269618682563f,0.0067592649720609f},
+ {-0.9932638457976282f,0.0066249934025109f},
+ {-0.9931269618682563f,0.0067592649720609f},
+ {-0.9932638457976282f,0.0066249934025109f},
+ /* 8kS/s */ /* LVPSA_SPEED_MEDIUM */
+ {-0.9568079425953329f,0.0418742666952312f},
+ {-0.9561413046903908f,0.0425090822391212f},
+ {-0.9540119562298059f,0.0445343819446862f},
+ {-0.9568079425953329f,0.0418742666952312f},
+ {-0.9531011912040412f,0.0453995238058269f},
+ {-0.9540119562298059f,0.0445343819446862f},
+ {-0.9547099955379963f,0.0438708555884659f},
+ //{0x8600C7B9,0x05CFA6CF},
+ {-0.9531011912040412f,0.0453995238058269f},
+ /* 48kS/s */
+ {-0.9540119562298059f,0.0445343819446862f},
+ {-0.9531011912040412f,0.0453995238058269f},
+ {-0.9540119562298059f,0.0445343819446862f},
+ {-0.9531011912040412f,0.0453995238058269f},
+ {-0.9540119562298059f,0.0445343819446862f},
+ /* 8kS/s */ /* LVPSA_SPEED_HIGH */
+ {-0.7415186790749431f,0.2254409026354551f},
+ {-0.7381451204419136f,0.2279209652915597f},
+ {-0.7274807319045067f,0.2356666540727019f},
+ {-0.7415186790749431f,0.2254409026354551f},
+ {-0.7229706319049001f,0.2388987224549055f},
+ {-0.7274807319045067f,0.2356666540727019f},
+ {-0.7309581353329122f,0.2331568226218224f},
+ {-0.7229706319049001f,0.2388987224549055f},
+ /* 48kS/s */
+ {-0.7274807319045067f,0.2356666540727019f}
+ ,{-0.7229706319049001f,0.2388987224549055f}
+ ,{-0.7274807319045067f,0.2356666540727019f}
+ ,{-0.7229706319049001f,0.2388987224549055f}
+ ,{-0.7274807319045067f,0.2356666540727019f}
+ };
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Tables.h b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Tables.h
new file mode 100644
index 0000000..65872fe
--- /dev/null
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Tables.h
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ */
+
+#ifndef __LVPSA_TABLES_H__
+#define __LVPSA_TABLES_H__
+
+/************************************************************************************/
+/* */
+/* Sample rate table */
+/* */
+/************************************************************************************/
+
+/*
+ * Sample rate table for converting between the enumerated type and the actual
+ * frequency
+ */
+extern const LVM_UINT32 LVPSA_SampleRateTab[];
+
+/************************************************************************************/
+/* */
+/* Sample rate inverse table */
+/* */
+/************************************************************************************/
+
+/*
+ * Sample rate table for converting between the enumerated type and the actual
+ * frequency
+ */
+extern const LVM_UINT32 LVPSA_SampleRateInvTab[];
+
+/************************************************************************************/
+/* */
+/* Number of samples in 20ms */
+/* */
+/************************************************************************************/
+
+/*
+ * Table for converting between the enumerated type and the number of samples
+ * during 20ms
+ */
+extern const LVM_UINT16 LVPSA_nSamplesBufferUpdate[];
+
+/************************************************************************************/
+/* */
+/* Down sampling factors */
+/* */
+/************************************************************************************/
+
+/*
+ * Table for converting between the enumerated type and the down sampling factor
+ */
+extern const LVM_UINT16 LVPSA_DownSamplingFactor[];
+
+/************************************************************************************/
+/* */
+/* Coefficient calculation tables */
+/* */
+/************************************************************************************/
+
+/*
+ * Table for 2 * Pi / Fs
+ */
+extern const LVM_INT16 LVPSA_TwoPiOnFsTable[];
+extern const LVM_FLOAT LVPSA_Float_TwoPiOnFsTable[];
+
+/*
+ * Gain table
+ */
+extern const LVM_INT16 LVPSA_GainTable[];
+extern const LVM_FLOAT LVPSA_Float_GainTable[];
+
+/************************************************************************************/
+/* */
+/* Cosone polynomial coefficients */
+/* */
+/************************************************************************************/
+
+/*
+ * Coefficients for calculating the cosine with the equation:
+ *
+ * Cos(x) = (2^Shifts)*(a0 + a1*x + a2*x^2 + a3*x^3 + a4*x^4 + a5*x^5)
+ *
+ * These coefficients expect the input, x, to be in the range 0 to 32768 respresenting
+ * a range of 0 to Pi. The output is in the range 32767 to -32768 representing the range
+ * +1.0 to -1.0
+ */
+extern const LVM_INT16 LVPSA_CosCoef[];
+extern const LVM_FLOAT LVPSA_Float_CosCoef[];
+
+/*
+ * Coefficients for calculating the cosine error with the equation:
+ *
+ * CosErr(x) = (2^Shifts)*(a0 + a1*x + a2*x^2 + a3*x^3)
+ *
+ * These coefficients expect the input, x, to be in the range 0 to 32768 respresenting
+ * a range of 0 to Pi/25. The output is in the range 0 to 32767 representing the range
+ * 0.0 to 0.0078852986
+ *
+ * This is used to give a double precision cosine over the range 0 to Pi/25 using the
+ * the equation:
+ *
+ * Cos(x) = 1.0 - CosErr(x)
+ */
+extern const LVM_INT16 LVPSA_DPCosCoef[];
+extern const LVM_FLOAT LVPSA_Float_DPCosCoef[];
+
+/************************************************************************************/
+/* */
+/* Quasi peak filter coefficients table */
+/* */
+/************************************************************************************/
+extern const QPD_C32_Coefs LVPSA_QPD_Coefs[];
+extern const QPD_FLOAT_Coefs LVPSA_QPD_Float_Coefs[];
+
+#endif /* __LVPSA_TABLES_H__ */
diff --git a/media/libeffects/lvm/lib/StereoWidening/lib/LVCS.h b/media/libeffects/lvm/lib/StereoWidening/lib/LVCS.h
index e507a7c..0adfd1b 100644
--- a/media/libeffects/lvm/lib/StereoWidening/lib/LVCS.h
+++ b/media/libeffects/lvm/lib/StereoWidening/lib/LVCS.h
@@ -56,11 +56,6 @@
#ifndef LVCS_H
#define LVCS_H
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-
/****************************************************************************************/
/* */
/* Includes */
@@ -70,7 +65,6 @@
#include "LVM_Types.h"
#include "LVM_Common.h"
-
/****************************************************************************************/
/* */
/* Definitions */
@@ -93,7 +87,6 @@
#define LVCS_EVENT_NONE 0x0000 /* Not a valid event */
#define LVCS_EVENT_ALGOFF 0x0001 /* CS has completed switch off */
-
/****************************************************************************************/
/* */
/* Types */
@@ -103,7 +96,6 @@
/* Instance handle */
typedef void *LVCS_Handle_t;
-
/* Operating modes */
typedef enum
{
@@ -112,7 +104,6 @@
LVCS_MAX = LVM_MAXENUM
} LVCS_Modes_en;
-
/* Memory Types */
typedef enum
{
@@ -123,7 +114,6 @@
LVCS_MEMORYTYPE_MAX = LVM_MAXENUM
} LVCS_MemoryTypes_en;
-
/* Function return status */
typedef enum
{
@@ -135,7 +125,6 @@
LVCS_STATUSMAX = LVM_MAXENUM
} LVCS_ReturnStatus_en;
-
/*
* Source data formats
*/
@@ -146,7 +135,6 @@
LVCS_SOURCEMAX = LVM_MAXENUM
} LVCS_SourceFormat_en;
-
/*
* Supported output devices
*/
@@ -172,7 +160,6 @@
void *pTable8;
} LVCS_CSMS_Coef_Tables_t;
-
/****************************************************************************************/
/* */
/* Structures */
@@ -187,14 +174,12 @@
void *pBaseAddress; /* Pointer to the region base address */
} LVCS_MemoryRegion_t;
-
/* Memory table containing the region definitions */
typedef struct
{
LVCS_MemoryRegion_t Region[LVCS_NR_MEMORY_REGIONS]; /* One definition for each region */
} LVCS_MemTab_t;
-
/* Concert Sound parameter structure */
typedef struct
{
@@ -210,7 +195,6 @@
#endif
} LVCS_Params_t;
-
/* Concert Sound Capability structure */
typedef struct
{
@@ -223,7 +207,6 @@
} LVCS_Capabilities_t;
-
/****************************************************************************************/
/* */
/* Function Prototypes */
@@ -270,7 +253,6 @@
LVCS_MemTab_t *pMemoryTable,
LVCS_Capabilities_t *pCapabilities);
-
/****************************************************************************************/
/* */
/* FUNCTION: LVCS_Init */
@@ -308,7 +290,6 @@
LVCS_MemTab_t *pMemoryTable,
LVCS_Capabilities_t *pCapabilities);
-
/****************************************************************************************/
/* */
/* FUNCTION: LVCS_GetParameters */
@@ -332,7 +313,6 @@
LVCS_ReturnStatus_en LVCS_GetParameters(LVCS_Handle_t hInstance,
LVCS_Params_t *pParams);
-
/****************************************************************************************/
/* */
/* FUNCTION: LVCS_Control */
@@ -355,7 +335,6 @@
LVCS_ReturnStatus_en LVCS_Control(LVCS_Handle_t hInstance,
LVCS_Params_t *pParams);
-
/****************************************************************************************/
/* */
/* FUNCTION: LVCS_Process */
@@ -377,20 +356,9 @@
/* NOTES: */
/* */
/****************************************************************************************/
-#ifdef BUILD_FLOAT
LVCS_ReturnStatus_en LVCS_Process(LVCS_Handle_t hInstance,
const LVM_FLOAT *pInData,
LVM_FLOAT *pOutData,
LVM_UINT16 NumSamples);
-#else
-LVCS_ReturnStatus_en LVCS_Process(LVCS_Handle_t hInstance,
- const LVM_INT16 *pInData,
- LVM_INT16 *pOutData,
- LVM_UINT16 NumSamples);
-#endif
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
#endif /* LVCS_H */
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_BypassMix.c b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_BypassMix.c
deleted file mode 100644
index 29e3c9e..0000000
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_BypassMix.c
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/************************************************************************************/
-/* */
-/* Includes */
-/* */
-/************************************************************************************/
-
-#include "LVCS.h"
-#include "LVCS_Private.h"
-#include "LVCS_BypassMix.h"
-#include "VectorArithmetic.h"
-#include "LVCS_Tables.h"
-
-/****************************************************************************************/
-/* */
-/* Function Prototypes */
-/* */
-/****************************************************************************************/
-LVM_INT32 LVCS_MixerCallback( LVCS_Handle_t hInstance,
- void *pGeneralPurpose,
- LVM_INT16 CallbackParam);
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVCS_BypassMixInit */
-/* */
-/* DESCRIPTION: */
-/* Initialises the bypass mixer module */
-/* */
-/* The overall gain of the processed path is set by the gains in the individual */
-/* processing blocks and by the effect level gain. */
-/* */
-/* The unprocessed path must have matching gain for the processed path to ensure */
-/* as they are mixed together the correct effect is achieved, this is the value */
-/* UnprocLoss. */
-/* */
-/* The overall gain is corrected by a combination of a shift with saturation and a */
-/* linear scaler, loss. The loss ensures the sum in the mixer does not saturate */
-/* and also corrects for any excess gain in the shift. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance Handle */
-/* pParams Initialisation parameters */
-/* */
-/* RETURNS: */
-/* LVCS_Success Always succeeds */
-/* */
-/* NOTES: */
-/* */
-/************************************************************************************/
-
-LVCS_ReturnStatus_en LVCS_BypassMixInit(LVCS_Handle_t hInstance,
- LVCS_Params_t *pParams)
-{
-
- LVM_UINT16 Offset;
-#ifndef BUILD_FLOAT
- LVM_UINT32 Gain;
- LVM_INT32 Current;
-#else
- LVM_FLOAT Gain;
- LVM_FLOAT Current;
-#endif
- LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
- LVCS_BypassMix_t *pConfig = (LVCS_BypassMix_t *)&pInstance->BypassMix;
- const Gain_t *pOutputGainTable;
-
-
-
- /*
- * Set the transition gain
- */
- if ((pParams->OperatingMode == LVCS_ON) &&
- (pInstance->bTimerDone == LVM_TRUE)
- && (pInstance->MSTarget1 != 0x7FFF) /* this indicates an off->on transtion */
- )
- {
-#ifndef BUILD_FLOAT
- pInstance->TransitionGain = pParams->EffectLevel;
-#else
- pInstance->TransitionGain = ((LVM_FLOAT)pParams->EffectLevel / 32767);
-#endif
- }
- else
- {
- /* Select no effect level */
- pInstance->TransitionGain = 0;
- }
-
- /*
- * Calculate the output gain table offset
- */
- Offset = (LVM_UINT16)(pParams->SpeakerType + (pParams->SourceFormat*(1+LVCS_EX_HEADPHONES)));
- pOutputGainTable = (Gain_t*)&LVCS_OutputGainTable[0];
-
- /*
- * Setup the mixer gain for the processed path
- */
-#ifndef BUILD_FLOAT
- Gain = (LVM_UINT32)(pOutputGainTable[Offset].Loss * pInstance->TransitionGain);
-#else
- Gain = (LVM_FLOAT)(pOutputGainTable[Offset].Loss * pInstance->TransitionGain);
-#endif
-
- pConfig->Mixer_Instance.MixerStream[0].CallbackParam = 0;
- pConfig->Mixer_Instance.MixerStream[0].pCallbackHandle = LVM_NULL;
- pConfig->Mixer_Instance.MixerStream[0].pCallBack = LVM_NULL;
- pConfig->Mixer_Instance.MixerStream[0].CallbackSet=1;
-
-#ifndef BUILD_FLOAT
- Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[0]);
- LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[0],(LVM_INT32)(Gain >> 15),Current);
- LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
-#else
- Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[0]);
- LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[0], (LVM_FLOAT)(Gain), Current);
- LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],
- LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
-#endif
-
- /*
- * Setup the mixer gain for the unprocessed path
- */
-#ifndef BUILD_FLOAT
- Gain = (LVM_UINT32)(pOutputGainTable[Offset].Loss * (0x7FFF - pInstance->TransitionGain));
- Gain = (LVM_UINT32)pOutputGainTable[Offset].UnprocLoss * (Gain >> 15);
- Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[1]);
- LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[1],(LVM_INT32)(Gain >> 15),Current);
- LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
-#else
- Gain = (LVM_FLOAT)(pOutputGainTable[Offset].Loss * (1.0 - \
- (LVM_FLOAT)pInstance->TransitionGain));
- Gain = (LVM_FLOAT)pOutputGainTable[Offset].UnprocLoss * Gain;
- Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[1]);
- LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[1], (LVM_FLOAT)(Gain), Current);
- LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],
- LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
-#endif
- pConfig->Mixer_Instance.MixerStream[1].CallbackParam = 0;
- pConfig->Mixer_Instance.MixerStream[1].pCallbackHandle = hInstance;
- pConfig->Mixer_Instance.MixerStream[1].CallbackSet=1;
- pConfig->Mixer_Instance.MixerStream[1].pCallBack = LVCS_MixerCallback;
-
- /*
- * Setup the output gain shift
- */
- pConfig->Output_Shift = pOutputGainTable[Offset].Shift;
-
-
- /*
- * Correct gain for the effect level
- */
- {
-#ifndef BUILD_FLOAT
- LVM_INT16 GainCorrect;
- LVM_INT32 Gain1;
- LVM_INT32 Gain2;
-
- Gain1 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[0]);
- Gain2 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[1]);
- /*
- * Calculate the gain correction
- */
- if (pInstance->Params.CompressorMode == LVM_MODE_ON)
- {
- GainCorrect = (LVM_INT16)( pInstance->VolCorrect.GainMin
- - (((LVM_INT32)pInstance->VolCorrect.GainMin * (LVM_INT32)pInstance->TransitionGain) >> 15)
- + (((LVM_INT32)pInstance->VolCorrect.GainFull * (LVM_INT32)pInstance->TransitionGain) >> 15) );
-
- /*
- * Apply the gain correction and shift, note the result is in Q3.13 format
- */
- Gain1 = (Gain1 * GainCorrect) << 4;
- Gain2 = (Gain2 * GainCorrect) << 4;
- }
- else
- {
- Gain1 = Gain1 << 16;
- Gain2 = Gain2 << 16;
- }
-
-
-
- /*
- * Set the gain values
- */
- pConfig->Output_Shift = pConfig->Output_Shift;
- LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[0],Gain1>>16);
- LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
- LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[1],Gain2>>16);
- LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
-#else
- LVM_FLOAT GainCorrect;
- LVM_FLOAT Gain1;
- LVM_FLOAT Gain2;
-
- Gain1 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[0]);
- Gain2 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[1]);
- /*
- * Calculate the gain correction
- */
- if (pInstance->Params.CompressorMode == LVM_MODE_ON)
- {
- GainCorrect = (LVM_FLOAT)( pInstance->VolCorrect.GainMin
- - (((LVM_FLOAT)pInstance->VolCorrect.GainMin * \
- ((LVM_FLOAT)pInstance->TransitionGain)))
- + (((LVM_FLOAT)pInstance->VolCorrect.GainFull * \
- ((LVM_FLOAT)pInstance->TransitionGain))));
-
- /*
- * Apply the gain correction
- */
- Gain1 = (Gain1 * GainCorrect);
- Gain2 = (Gain2 * GainCorrect);
-
- }
-
- /*
- * Set the gain values
- */
- pConfig->Output_Shift = pConfig->Output_Shift;
- LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[0],Gain1);
- LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],
- LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
- LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[1],Gain2);
- LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],
- LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
-#endif
- }
-
- return(LVCS_SUCCESS);
-
-}
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVCS_BypassMixer */
-/* */
-/* DESCRIPTION: */
-/* Apply Bypass Mix. */
-/* */
-/* This mixes the processed and unprocessed data streams together to correct the */
-/* overall system gain and allow progressive control of the Concert Sound effect. */
-/* */
-/* When the bypass mixer is enabled the output is the processed signal only and */
-/* without gain correction. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance Handle */
-/* pProcessed Pointer to the processed data */
-/* pUnprocessed Pointer to the unprocessed data */
-/* pOutData Pointer to the output data */
-/* NumSamples Number of samples to process */
-/* */
-/* RETURNS: */
-/* LVCS_Success Always succeeds */
-/* */
-/* NOTES: */
-/* */
-/************************************************************************************/
-
-LVCS_ReturnStatus_en LVCS_BypassMixer(LVCS_Handle_t hInstance,
-#ifndef BUILD_FLOAT
- const LVM_INT16 *pProcessed,
- const LVM_INT16 *pUnprocessed,
- LVM_INT16 *pOutData,
-#else
- const LVM_FLOAT *pProcessed,
- const LVM_FLOAT *pUnprocessed,
- LVM_FLOAT *pOutData,
-#endif
- LVM_UINT16 NumSamples)
-{
-
- LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
- LVCS_BypassMix_t *pConfig = (LVCS_BypassMix_t *)&pInstance->BypassMix;
-
- /*
- * Check if the bypass mixer is enabled
- */
- if ((pInstance->Params.OperatingMode & LVCS_BYPASSMIXSWITCH) != 0)
- {
- /*
- * Apply the bypass mix
- */
-#ifndef BUILD_FLOAT
- LVC_MixSoft_2St_D16C31_SAT(&pConfig->Mixer_Instance,
- pProcessed,
- (LVM_INT16 *) pUnprocessed,
- pOutData,
- (LVM_INT16)(2*NumSamples));
-
- /*
- * Apply output gain correction shift
- */
- Shift_Sat_v16xv16 ((LVM_INT16)pConfig->Output_Shift,
- (LVM_INT16*)pOutData,
- (LVM_INT16*)pOutData,
- (LVM_INT16)(2*NumSamples)); /* Left and right*/
-#else
- LVC_MixSoft_2St_D16C31_SAT(&pConfig->Mixer_Instance,
- pProcessed,
- (LVM_FLOAT *) pUnprocessed,
- pOutData,
- (LVM_INT16)(2 * NumSamples));
- /*
- * Apply output gain correction shift
- */
- Shift_Sat_Float((LVM_INT16)pConfig->Output_Shift,
- (LVM_FLOAT*)pOutData,
- (LVM_FLOAT*)pOutData,
- (LVM_INT16)(2 * NumSamples)); /* Left and right*/
-#endif
- }
-
- return(LVCS_SUCCESS);
-}
-
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVCS_MixerCallback */
-/* */
-/************************************************************************************/
-LVM_INT32 LVCS_MixerCallback(LVCS_Handle_t hInstance,
- void *pGeneralPurpose,
- LVM_INT16 CallbackParam)
-{
- LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
-
- (void)pGeneralPurpose;
-
- /*
- * Off transition has completed in Headphone mode
- */
- if ((pInstance->OutputDevice == LVCS_HEADPHONE) &&
- (pInstance->bInOperatingModeTransition) &&
- (pInstance->MSTarget0 == 0x0000)&& /* this indicates an on->off transition */
- (CallbackParam == 0))
- {
- /* Set operating mode to OFF */
- pInstance->Params.OperatingMode = LVCS_OFF;
-
- /* Exit transition state */
- pInstance->bInOperatingModeTransition = LVM_FALSE;
-
- /* Signal to the bundle */
- if((*pInstance->Capabilities.CallBack) != LVM_NULL){
- (*pInstance->Capabilities.CallBack)(pInstance->Capabilities.pBundleInstance,
- LVM_NULL,
- (ALGORITHM_CS_ID | LVCS_EVENT_ALGOFF));
- }
- }
-
-
- if ((pInstance->OutputDevice == LVCS_HEADPHONE) &&
- (pInstance->MSTarget0 == 1) &&
- (pInstance->bTimerDone == LVM_TRUE)){
-
- /* Exit transition state */
- pInstance->bInOperatingModeTransition = LVM_FALSE;
- }
-
- return 1;
-}
-
-
-
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_BypassMix.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_BypassMix.cpp
new file mode 100644
index 0000000..ba152c0
--- /dev/null
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_BypassMix.cpp
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/************************************************************************************/
+/* */
+/* Includes */
+/* */
+/************************************************************************************/
+
+#include "LVCS.h"
+#include "LVCS_Private.h"
+#include "LVCS_BypassMix.h"
+#include "VectorArithmetic.h"
+#include "LVCS_Tables.h"
+
+/****************************************************************************************/
+/* */
+/* Function Prototypes */
+/* */
+/****************************************************************************************/
+LVM_INT32 LVCS_MixerCallback( LVCS_Handle_t hInstance,
+ void *pGeneralPurpose,
+ LVM_INT16 CallbackParam);
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVCS_BypassMixInit */
+/* */
+/* DESCRIPTION: */
+/* Initialises the bypass mixer module */
+/* */
+/* The overall gain of the processed path is set by the gains in the individual */
+/* processing blocks and by the effect level gain. */
+/* */
+/* The unprocessed path must have matching gain for the processed path to ensure */
+/* as they are mixed together the correct effect is achieved, this is the value */
+/* UnprocLoss. */
+/* */
+/* The overall gain is corrected by a combination of a shift with saturation and a */
+/* linear scaler, loss. The loss ensures the sum in the mixer does not saturate */
+/* and also corrects for any excess gain in the shift. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance Handle */
+/* pParams Initialisation parameters */
+/* */
+/* RETURNS: */
+/* LVCS_Success Always succeeds */
+/* */
+/* NOTES: */
+/* */
+/************************************************************************************/
+
+LVCS_ReturnStatus_en LVCS_BypassMixInit(LVCS_Handle_t hInstance,
+ LVCS_Params_t *pParams)
+{
+
+ LVM_UINT16 Offset;
+ LVM_FLOAT Gain;
+ LVM_FLOAT Current;
+ LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
+ LVCS_BypassMix_t *pConfig = (LVCS_BypassMix_t *)&pInstance->BypassMix;
+ const Gain_t *pOutputGainTable;
+
+ /*
+ * Set the transition gain
+ */
+ if ((pParams->OperatingMode == LVCS_ON) &&
+ (pInstance->bTimerDone == LVM_TRUE)
+ && (pInstance->MSTarget1 != 0x7FFF) /* this indicates an off->on transtion */
+ )
+ {
+ pInstance->TransitionGain = ((LVM_FLOAT)pParams->EffectLevel / 32767);
+ }
+ else
+ {
+ /* Select no effect level */
+ pInstance->TransitionGain = 0;
+ }
+
+ /*
+ * Calculate the output gain table offset
+ */
+ Offset = (LVM_UINT16)(pParams->SpeakerType + (pParams->SourceFormat*(1+LVCS_EX_HEADPHONES)));
+ pOutputGainTable = (Gain_t*)&LVCS_OutputGainTable[0];
+
+ /*
+ * Setup the mixer gain for the processed path
+ */
+ Gain = (LVM_FLOAT)(pOutputGainTable[Offset].Loss * pInstance->TransitionGain);
+
+ pConfig->Mixer_Instance.MixerStream[0].CallbackParam = 0;
+ pConfig->Mixer_Instance.MixerStream[0].pCallbackHandle = LVM_NULL;
+ pConfig->Mixer_Instance.MixerStream[0].pCallBack = LVM_NULL;
+ pConfig->Mixer_Instance.MixerStream[0].CallbackSet=1;
+
+ Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[0]);
+ LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[0], (LVM_FLOAT)(Gain), Current);
+ LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],
+ LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
+
+ /*
+ * Setup the mixer gain for the unprocessed path
+ */
+ Gain = (LVM_FLOAT)(pOutputGainTable[Offset].Loss * (1.0 - \
+ (LVM_FLOAT)pInstance->TransitionGain));
+ Gain = (LVM_FLOAT)pOutputGainTable[Offset].UnprocLoss * Gain;
+ Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[1]);
+ LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[1], (LVM_FLOAT)(Gain), Current);
+ LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],
+ LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
+ pConfig->Mixer_Instance.MixerStream[1].CallbackParam = 0;
+ pConfig->Mixer_Instance.MixerStream[1].pCallbackHandle = hInstance;
+ pConfig->Mixer_Instance.MixerStream[1].CallbackSet=1;
+ pConfig->Mixer_Instance.MixerStream[1].pCallBack = LVCS_MixerCallback;
+
+ /*
+ * Setup the output gain shift
+ */
+ pConfig->Output_Shift = pOutputGainTable[Offset].Shift;
+
+ /*
+ * Correct gain for the effect level
+ */
+ {
+ LVM_FLOAT GainCorrect;
+ LVM_FLOAT Gain1;
+ LVM_FLOAT Gain2;
+
+ Gain1 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[0]);
+ Gain2 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[1]);
+ /*
+ * Calculate the gain correction
+ */
+ if (pInstance->Params.CompressorMode == LVM_MODE_ON)
+ {
+ GainCorrect = (LVM_FLOAT)( pInstance->VolCorrect.GainMin
+ - (((LVM_FLOAT)pInstance->VolCorrect.GainMin * \
+ ((LVM_FLOAT)pInstance->TransitionGain)))
+ + (((LVM_FLOAT)pInstance->VolCorrect.GainFull * \
+ ((LVM_FLOAT)pInstance->TransitionGain))));
+
+ /*
+ * Apply the gain correction
+ */
+ Gain1 = (Gain1 * GainCorrect);
+ Gain2 = (Gain2 * GainCorrect);
+
+ }
+
+ /*
+ * Set the gain values
+ */
+ pConfig->Output_Shift = pConfig->Output_Shift;
+ LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[0],Gain1);
+ LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],
+ LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
+ LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[1],Gain2);
+ LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],
+ LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
+ }
+
+ return(LVCS_SUCCESS);
+
+}
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVCS_BypassMixer */
+/* */
+/* DESCRIPTION: */
+/* Apply Bypass Mix. */
+/* */
+/* This mixes the processed and unprocessed data streams together to correct the */
+/* overall system gain and allow progressive control of the Concert Sound effect. */
+/* */
+/* When the bypass mixer is enabled the output is the processed signal only and */
+/* without gain correction. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance Handle */
+/* pProcessed Pointer to the processed data */
+/* pUnprocessed Pointer to the unprocessed data */
+/* pOutData Pointer to the output data */
+/* NumSamples Number of samples to process */
+/* */
+/* RETURNS: */
+/* LVCS_Success Always succeeds */
+/* */
+/* NOTES: */
+/* */
+/************************************************************************************/
+
+LVCS_ReturnStatus_en LVCS_BypassMixer(LVCS_Handle_t hInstance,
+ const LVM_FLOAT *pProcessed,
+ const LVM_FLOAT *pUnprocessed,
+ LVM_FLOAT *pOutData,
+ LVM_UINT16 NumSamples)
+{
+
+ LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
+ LVCS_BypassMix_t *pConfig = (LVCS_BypassMix_t *)&pInstance->BypassMix;
+
+ /*
+ * Check if the bypass mixer is enabled
+ */
+ if ((pInstance->Params.OperatingMode & LVCS_BYPASSMIXSWITCH) != 0)
+ {
+ /*
+ * Apply the bypass mix
+ */
+ LVC_MixSoft_2St_D16C31_SAT(&pConfig->Mixer_Instance,
+ pProcessed,
+ (LVM_FLOAT *) pUnprocessed,
+ pOutData,
+ (LVM_INT16)(2 * NumSamples));
+ /*
+ * Apply output gain correction shift
+ */
+ Shift_Sat_Float((LVM_INT16)pConfig->Output_Shift,
+ (LVM_FLOAT*)pOutData,
+ (LVM_FLOAT*)pOutData,
+ (LVM_INT16)(2 * NumSamples)); /* Left and right*/
+ }
+
+ return(LVCS_SUCCESS);
+}
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVCS_MixerCallback */
+/* */
+/************************************************************************************/
+LVM_INT32 LVCS_MixerCallback(LVCS_Handle_t hInstance,
+ void *pGeneralPurpose,
+ LVM_INT16 CallbackParam)
+{
+ LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
+
+ (void)pGeneralPurpose;
+
+ /*
+ * Off transition has completed in Headphone mode
+ */
+ if ((pInstance->OutputDevice == LVCS_HEADPHONE) &&
+ (pInstance->bInOperatingModeTransition) &&
+ (pInstance->MSTarget0 == 0x0000)&& /* this indicates an on->off transition */
+ (CallbackParam == 0))
+ {
+ /* Set operating mode to OFF */
+ pInstance->Params.OperatingMode = LVCS_OFF;
+
+ /* Exit transition state */
+ pInstance->bInOperatingModeTransition = LVM_FALSE;
+
+ /* Signal to the bundle */
+ if((*pInstance->Capabilities.CallBack) != LVM_NULL){
+ (*pInstance->Capabilities.CallBack)(pInstance->Capabilities.pBundleInstance,
+ LVM_NULL,
+ (ALGORITHM_CS_ID | LVCS_EVENT_ALGOFF));
+ }
+ }
+
+ if ((pInstance->OutputDevice == LVCS_HEADPHONE) &&
+ (pInstance->MSTarget0 == 1) &&
+ (pInstance->bTimerDone == LVM_TRUE)){
+
+ /* Exit transition state */
+ pInstance->bInOperatingModeTransition = LVM_FALSE;
+ }
+
+ return 1;
+}
+
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_BypassMix.h b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_BypassMix.h
index f69ba38..fcd8ee3 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_BypassMix.h
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_BypassMix.h
@@ -18,11 +18,6 @@
#ifndef __LVCS_BYPASSMIX_H__
#define __LVCS_BYPASSMIX_H__
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-
/************************************************************************************/
/* */
/* Includes */
@@ -31,7 +26,6 @@
#include "LVC_Mixer.h"
-
/************************************************************************************/
/* */
/* Structures */
@@ -42,25 +36,11 @@
typedef struct
{
/* Mixer settings */
-#ifdef BUILD_FLOAT
LVMixer3_2St_FLOAT_st Mixer_Instance; /* Mixer instance */
-#else
- LVMixer3_2St_st Mixer_Instance; /* Mixer instance */
-#endif
LVM_UINT16 Output_Shift; /* Correcting gain output shift */
} LVCS_BypassMix_t;
-#ifndef BUILD_FLOAT
-/* Output gain type */
-typedef struct
-{
- /* Output gain settings, Gain = (Loss/32768) * 2^Shift */
- LVM_UINT16 Shift; /* Left shifts required */
- LVM_UINT16 Loss; /* Loss required */
- LVM_UINT16 UnprocLoss; /* Unprocessed path loss */
-} Gain_t;
-#else
typedef struct
{
/* Output gain settings, Gain = (Loss/32768) * 2^Shift */
@@ -68,7 +48,6 @@
LVM_FLOAT Loss; /* Loss required */
LVM_FLOAT UnprocLoss; /* Unprocessed path loss */
} Gain_t;
-#endif
/************************************************************************************/
/* */
/* Function prototypes */
@@ -78,21 +57,10 @@
LVCS_ReturnStatus_en LVCS_BypassMixInit(LVCS_Handle_t hInstance,
LVCS_Params_t *pParams);
-#ifndef BUILD_FLOAT
-LVCS_ReturnStatus_en LVCS_BypassMixer(LVCS_Handle_t hInstance,
- const LVM_INT16 *pProcessed,
- const LVM_INT16 *unProcessed,
- LVM_INT16 *pOutData,
- LVM_UINT16 NumSamples);
-#else
LVCS_ReturnStatus_en LVCS_BypassMixer(LVCS_Handle_t hInstance,
const LVM_FLOAT *pProcessed,
const LVM_FLOAT *unProcessed,
LVM_FLOAT *pOutData,
LVM_UINT16 NumSamples);
-#endif
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
#endif /* BYPASSMIX_H */
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Control.c b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Control.c
deleted file mode 100644
index 3bf6ec6..0000000
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Control.c
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/************************************************************************************/
-/* */
-/* Includes */
-/* */
-/************************************************************************************/
-
-#include "LVCS.h"
-#include "LVCS_Private.h"
-#include "LVCS_Tables.h"
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVCS_GetParameters */
-/* */
-/* DESCRIPTION: */
-/* Request the Concert Sound parameters. The current parameter set is returned */
-/* via the parameter pointer. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance handle */
-/* pParams Pointer to an empty parameter structure */
-/* */
-/* RETURNS: */
-/* LVCS_Success Always succeeds */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVCS_Process function */
-/* */
-/************************************************************************************/
-
-LVCS_ReturnStatus_en LVCS_GetParameters(LVCS_Handle_t hInstance,
- LVCS_Params_t *pParams)
-{
-
- LVCS_Instance_t *pInstance =(LVCS_Instance_t *)hInstance;
-
- *pParams = pInstance->Params;
-
- return(LVCS_SUCCESS);
-}
-
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVCS_Control */
-/* */
-/* DESCRIPTION: */
-/* Sets or changes the Concert Sound parameters. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance handle */
-/* pParams Pointer to a parameter structure */
-/* */
-/* RETURNS: */
-/* LVCS_Success Succeeded */
-/* */
-/* NOTES: */
-/* 1. This function must not be interrupted by the LVCS_Process function */
-/* */
-/************************************************************************************/
-
-LVCS_ReturnStatus_en LVCS_Control(LVCS_Handle_t hInstance,
- LVCS_Params_t *pParams)
-{
- LVM_INT16 Offset;
- LVCS_Instance_t *pInstance =(LVCS_Instance_t *)hInstance;
- LVCS_ReturnStatus_en err;
- LVCS_Modes_en OperatingModeSave = pInstance->Params.OperatingMode;
-
- if (pParams->SampleRate != pInstance->Params.SampleRate)
- {
- pInstance->TimerParams.SamplingRate = LVCS_SampleRateTable[pParams->SampleRate];
- }
-
- /*
- * If the reverb level has changed
- */
- if(pInstance->Params.ReverbLevel != pParams->ReverbLevel)
- {
- err=LVCS_ReverbGeneratorInit(hInstance,pParams);
- }
-
- /*
- * If the sample rate or speaker has changed then perform a full re-initialisation
- */
- if ((pInstance->Params.SampleRate != pParams->SampleRate) ||
- (pInstance->Params.SpeakerType != pParams->SpeakerType))
- {
- const LVCS_VolCorrect_t *pLVCS_VolCorrectTable;
-
- /*
- * Output device
- */
- pInstance->OutputDevice = LVCS_HEADPHONE;
-
- /*
- * Get the volume correction parameters
- */
- /* Use internal coefficient table */
- pLVCS_VolCorrectTable = (LVCS_VolCorrect_t*)&LVCS_VolCorrectTable[0];
- Offset = (LVM_INT16)(pParams->SpeakerType + pParams->SourceFormat*(1+LVCS_EX_HEADPHONES));
-
- pInstance->VolCorrect = pLVCS_VolCorrectTable[Offset];
-
- pInstance->CompressGain = pInstance->VolCorrect.CompMin;
-#ifdef BUILD_FLOAT
- LVC_Mixer_Init(&pInstance->BypassMix.Mixer_Instance.MixerStream[0], 0, 0);
-#else
- LVC_Mixer_Init(&pInstance->BypassMix.Mixer_Instance.MixerStream[0],0,0);
-#endif
- {
-#ifndef BUILD_FLOAT
- LVM_UINT32 Gain;
- const Gain_t *pOutputGainTable = (Gain_t*)&LVCS_OutputGainTable[0];
- Gain = (LVM_UINT32)(pOutputGainTable[Offset].Loss * LVM_MAXINT_16);
- Gain = (LVM_UINT32)pOutputGainTable[Offset].UnprocLoss * (Gain >> 15);
- Gain=Gain>>15;
- /*
- * Apply the gain correction and shift, note the result is in Q3.13 format
- */
- Gain = (Gain * pInstance->VolCorrect.GainMin) >>12;
-
- LVC_Mixer_Init(&pInstance->BypassMix.Mixer_Instance.MixerStream[1],0,Gain);
- LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMix.Mixer_Instance.MixerStream[0],
- LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
- LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMix.Mixer_Instance.MixerStream[1],
- LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
-#else
- LVM_FLOAT Gain;
- const Gain_t *pOutputGainTable = (Gain_t*)&LVCS_OutputGainTable[0];
- Gain = (LVM_FLOAT)(pOutputGainTable[Offset].Loss);
- Gain = (LVM_FLOAT)pOutputGainTable[Offset].UnprocLoss * (Gain);
-
- /*
- * Apply the gain correction
- */
- Gain = (Gain * pInstance->VolCorrect.GainMin);
-
- LVC_Mixer_Init(&pInstance->BypassMix.Mixer_Instance.MixerStream[1], 0, Gain);
- LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMix.Mixer_Instance.MixerStream[0],
- LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
- LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMix.Mixer_Instance.MixerStream[1],
- LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
-#endif
- }
-
-
- err=LVCS_SEnhancerInit(hInstance,
- pParams);
-
- err=LVCS_ReverbGeneratorInit(hInstance,
- pParams);
-
- err=LVCS_EqualiserInit(hInstance,
- pParams);
-
- err=LVCS_BypassMixInit(hInstance,
- pParams);
-
- }
-
-
- /*
- * Check if the effect level or source format has changed
- */
- else if ((pInstance->Params.EffectLevel != pParams->EffectLevel) ||
- (pInstance->Params.SourceFormat != pParams->SourceFormat))
- {
- const LVCS_VolCorrect_t *pLVCS_VolCorrectTable;
-
- /*
- * Get the volume correction parameters
- */
- /* Use internal coefficient table */
- pLVCS_VolCorrectTable = (LVCS_VolCorrect_t*)&LVCS_VolCorrectTable[0];
- Offset = (LVM_INT16)(pParams->SpeakerType + pParams->SourceFormat*(1+LVCS_EX_HEADPHONES));
-
- pInstance->VolCorrect = pLVCS_VolCorrectTable[Offset];
-
- /* Update the effect level and alpha-mixer gains */
- err=LVCS_BypassMixInit(hInstance,
- pParams);
-
- if(err != LVCS_SUCCESS)
- {
- return err;
- }
- }
- else
- {
- pInstance->Params = *pParams;
- }
-
- /*
- * Update the instance parameters
- */
- pInstance->Params = *pParams;
-
- /* Stay on the current operating mode until the transition is done */
- if((pParams->OperatingMode != OperatingModeSave) ||
- (pInstance->bInOperatingModeTransition == LVM_TRUE)){
-
- /* Set the reverb delay timeout */
- if(pInstance->bInOperatingModeTransition != LVM_TRUE){
- pInstance->bTimerDone = LVM_FALSE;
- pInstance->TimerParams.TimeInMs =
- (LVM_INT16)(((pInstance->Reverberation.DelaySize << 2)
- /pInstance->TimerParams.SamplingRate) + 1);
- LVM_Timer_Init ( &pInstance->TimerInstance,
- &pInstance->TimerParams);
- }
-
- /* Update the effect level and alpha-mixer gains */
- err=LVCS_BypassMixInit(hInstance,
- pParams);
-
- /* Change transition bypass mixer settings if needed depending on transition type */
- if(pParams->OperatingMode != LVCS_OFF){
- pInstance->MSTarget0=LVM_MAXINT_16;
- pInstance->MSTarget1=0;
- }
- else
- {
- pInstance->Params.OperatingMode = OperatingModeSave;
- pInstance->MSTarget1=LVM_MAXINT_16;
- pInstance->MSTarget0=0;
- }
-
-
- /* Set transition flag */
- pInstance->bInOperatingModeTransition = LVM_TRUE;
- }
-
- return(LVCS_SUCCESS);
-}
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVCS_TimerCallBack */
-/* */
-/* DESCRIPTION: */
-/* CallBack function of the Timer. */
-/* */
-/****************************************************************************************/
-void LVCS_TimerCallBack (void* hInstance, void* pCallBackParams, LVM_INT32 CallbackParam)
-{
- LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
-
- /* Avoid warnings because pCallBackParams and CallbackParam are not used*/
- if((pCallBackParams != LVM_NULL) || (CallbackParam != 0)){
- pCallBackParams = hInstance;
- CallbackParam = 0;
- return;
- }
-
- pInstance->bTimerDone = LVM_TRUE;
-
-
- return;
-}
-
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Control.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Control.cpp
new file mode 100644
index 0000000..50db03d
--- /dev/null
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Control.cpp
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/************************************************************************************/
+/* */
+/* Includes */
+/* */
+/************************************************************************************/
+
+#include "LVCS.h"
+#include "LVCS_Private.h"
+#include "LVCS_Tables.h"
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVCS_GetParameters */
+/* */
+/* DESCRIPTION: */
+/* Request the Concert Sound parameters. The current parameter set is returned */
+/* via the parameter pointer. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance handle */
+/* pParams Pointer to an empty parameter structure */
+/* */
+/* RETURNS: */
+/* LVCS_Success Always succeeds */
+/* */
+/* NOTES: */
+/* 1. This function may be interrupted by the LVCS_Process function */
+/* */
+/************************************************************************************/
+
+LVCS_ReturnStatus_en LVCS_GetParameters(LVCS_Handle_t hInstance,
+ LVCS_Params_t *pParams)
+{
+
+ LVCS_Instance_t *pInstance =(LVCS_Instance_t *)hInstance;
+
+ *pParams = pInstance->Params;
+
+ return(LVCS_SUCCESS);
+}
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVCS_Control */
+/* */
+/* DESCRIPTION: */
+/* Sets or changes the Concert Sound parameters. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance handle */
+/* pParams Pointer to a parameter structure */
+/* */
+/* RETURNS: */
+/* LVCS_Success Succeeded */
+/* */
+/* NOTES: */
+/* 1. This function must not be interrupted by the LVCS_Process function */
+/* */
+/************************************************************************************/
+
+LVCS_ReturnStatus_en LVCS_Control(LVCS_Handle_t hInstance,
+ LVCS_Params_t *pParams)
+{
+ LVM_INT16 Offset;
+ LVCS_Instance_t *pInstance =(LVCS_Instance_t *)hInstance;
+ LVCS_ReturnStatus_en err;
+ LVCS_Modes_en OperatingModeSave = pInstance->Params.OperatingMode;
+
+ if (pParams->SampleRate != pInstance->Params.SampleRate)
+ {
+ pInstance->TimerParams.SamplingRate = LVCS_SampleRateTable[pParams->SampleRate];
+ }
+
+ /*
+ * If the reverb level has changed
+ */
+ if(pInstance->Params.ReverbLevel != pParams->ReverbLevel)
+ {
+ err=LVCS_ReverbGeneratorInit(hInstance,pParams);
+ }
+
+ /*
+ * If the sample rate or speaker has changed then perform a full re-initialisation
+ */
+ if ((pInstance->Params.SampleRate != pParams->SampleRate) ||
+ (pInstance->Params.SpeakerType != pParams->SpeakerType))
+ {
+ const LVCS_VolCorrect_t *pLVCS_VolCorrectTable;
+
+ /*
+ * Output device
+ */
+ pInstance->OutputDevice = LVCS_HEADPHONE;
+
+ /*
+ * Get the volume correction parameters
+ */
+ /* Use internal coefficient table */
+ pLVCS_VolCorrectTable = (LVCS_VolCorrect_t*)&LVCS_VolCorrectTable[0];
+ Offset = (LVM_INT16)(pParams->SpeakerType + pParams->SourceFormat*(1+LVCS_EX_HEADPHONES));
+
+ pInstance->VolCorrect = pLVCS_VolCorrectTable[Offset];
+
+ pInstance->CompressGain = pInstance->VolCorrect.CompMin;
+ LVC_Mixer_Init(&pInstance->BypassMix.Mixer_Instance.MixerStream[0], 0, 0);
+ {
+ LVM_FLOAT Gain;
+ const Gain_t *pOutputGainTable = (Gain_t*)&LVCS_OutputGainTable[0];
+ Gain = (LVM_FLOAT)(pOutputGainTable[Offset].Loss);
+ Gain = (LVM_FLOAT)pOutputGainTable[Offset].UnprocLoss * (Gain);
+
+ /*
+ * Apply the gain correction
+ */
+ Gain = (Gain * pInstance->VolCorrect.GainMin);
+
+ LVC_Mixer_Init(&pInstance->BypassMix.Mixer_Instance.MixerStream[1], 0, Gain);
+ LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMix.Mixer_Instance.MixerStream[0],
+ LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
+ LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMix.Mixer_Instance.MixerStream[1],
+ LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
+ }
+
+ err=LVCS_SEnhancerInit(hInstance,
+ pParams);
+
+ err=LVCS_ReverbGeneratorInit(hInstance,
+ pParams);
+
+ err=LVCS_EqualiserInit(hInstance,
+ pParams);
+
+ err=LVCS_BypassMixInit(hInstance,
+ pParams);
+
+ }
+
+ /*
+ * Check if the effect level or source format has changed
+ */
+ else if ((pInstance->Params.EffectLevel != pParams->EffectLevel) ||
+ (pInstance->Params.SourceFormat != pParams->SourceFormat))
+ {
+ const LVCS_VolCorrect_t *pLVCS_VolCorrectTable;
+
+ /*
+ * Get the volume correction parameters
+ */
+ /* Use internal coefficient table */
+ pLVCS_VolCorrectTable = (LVCS_VolCorrect_t*)&LVCS_VolCorrectTable[0];
+ Offset = (LVM_INT16)(pParams->SpeakerType + pParams->SourceFormat*(1+LVCS_EX_HEADPHONES));
+
+ pInstance->VolCorrect = pLVCS_VolCorrectTable[Offset];
+
+ /* Update the effect level and alpha-mixer gains */
+ err=LVCS_BypassMixInit(hInstance,
+ pParams);
+
+ if(err != LVCS_SUCCESS)
+ {
+ return err;
+ }
+ }
+ else
+ {
+ pInstance->Params = *pParams;
+ }
+
+ /*
+ * Update the instance parameters
+ */
+ pInstance->Params = *pParams;
+
+ /* Stay on the current operating mode until the transition is done */
+ if((pParams->OperatingMode != OperatingModeSave) ||
+ (pInstance->bInOperatingModeTransition == LVM_TRUE)){
+
+ /* Set the reverb delay timeout */
+ if(pInstance->bInOperatingModeTransition != LVM_TRUE){
+ pInstance->bTimerDone = LVM_FALSE;
+ pInstance->TimerParams.TimeInMs =
+ (LVM_INT16)(((pInstance->Reverberation.DelaySize << 2)
+ /pInstance->TimerParams.SamplingRate) + 1);
+ LVM_Timer_Init ( &pInstance->TimerInstance,
+ &pInstance->TimerParams);
+ }
+
+ /* Update the effect level and alpha-mixer gains */
+ err=LVCS_BypassMixInit(hInstance,
+ pParams);
+
+ /* Change transition bypass mixer settings if needed depending on transition type */
+ if(pParams->OperatingMode != LVCS_OFF){
+ pInstance->MSTarget0=LVM_MAXINT_16;
+ pInstance->MSTarget1=0;
+ }
+ else
+ {
+ pInstance->Params.OperatingMode = OperatingModeSave;
+ pInstance->MSTarget1=LVM_MAXINT_16;
+ pInstance->MSTarget0=0;
+ }
+
+ /* Set transition flag */
+ pInstance->bInOperatingModeTransition = LVM_TRUE;
+ }
+
+ return(LVCS_SUCCESS);
+}
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVCS_TimerCallBack */
+/* */
+/* DESCRIPTION: */
+/* CallBack function of the Timer. */
+/* */
+/****************************************************************************************/
+void LVCS_TimerCallBack (void* hInstance, void* pCallBackParams, LVM_INT32 CallbackParam)
+{
+ LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
+
+ /* Avoid warnings because pCallBackParams and CallbackParam are not used*/
+ if((pCallBackParams != LVM_NULL) || (CallbackParam != 0)){
+ pCallBackParams = hInstance;
+ CallbackParam = 0;
+ return;
+ }
+
+ pInstance->bTimerDone = LVM_TRUE;
+
+ return;
+}
+
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.c b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.c
deleted file mode 100644
index ec5312e..0000000
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/************************************************************************************/
-/* */
-/* Includes */
-/* */
-/************************************************************************************/
-
-#include "LVCS.h"
-#include "LVCS_Private.h"
-#include "LVCS_Equaliser.h"
-#include "BIQUAD.h"
-#include "VectorArithmetic.h"
-#include "LVCS_Tables.h"
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVCS_EqualiserInit */
-/* */
-/* DESCRIPTION: */
-/* Initialises the equaliser module */
-/* */
-/* The function selects the coefficients for the filters and clears the data */
-/* history. It is also used for re-initialisation when one of the system control */
-/* parameters changes but will only change the coefficients and clear the history */
-/* if the sample rate or speaker type has changed. */
-/* */
-/* To avoid excessive testing during the sample processing the biquad type is */
-/* set as a callback function in the init routine. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance Handle */
-/* pParams Initialisation parameters */
-/* */
-/* RETURNS: */
-/* LVCS_Success Always succeeds */
-/* */
-/* NOTES: */
-/* */
-/************************************************************************************/
-#ifdef BUILD_FLOAT
-LVCS_ReturnStatus_en LVCS_EqualiserInit(LVCS_Handle_t hInstance,
- LVCS_Params_t *pParams)
-{
-
- LVM_UINT16 Offset;
- LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
- LVCS_Equaliser_t *pConfig = (LVCS_Equaliser_t *)&pInstance->Equaliser;
- LVCS_Data_t *pData;
- LVCS_Coefficient_t *pCoefficients;
- BQ_FLOAT_Coefs_t Coeffs;
- const BiquadA012B12CoefsSP_t *pEqualiserCoefTable;
-
- pData = (LVCS_Data_t *) \
- pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress;
-
- pCoefficients = (LVCS_Coefficient_t *) \
- pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
- /*
- * If the sample rate changes re-initialise the filters
- */
- if ((pInstance->Params.SampleRate != pParams->SampleRate) ||
- (pInstance->Params.SpeakerType != pParams->SpeakerType))
- {
- /*
- * Setup the filter coefficients and clear the history
- */
- Offset = (LVM_UINT16)(pParams->SampleRate + (pParams->SpeakerType * (1 + LVM_FS_48000)));
- pEqualiserCoefTable = (BiquadA012B12CoefsSP_t*)&LVCS_EqualiserCoefTable[0];
-
- /* Left and right filters */
- /* Convert incoming coefficients to the required format/ordering */
- Coeffs.A0 = (LVM_FLOAT) pEqualiserCoefTable[Offset].A0;
- Coeffs.A1 = (LVM_FLOAT) pEqualiserCoefTable[Offset].A1;
- Coeffs.A2 = (LVM_FLOAT) pEqualiserCoefTable[Offset].A2;
- Coeffs.B1 = (LVM_FLOAT)-pEqualiserCoefTable[Offset].B1;
- Coeffs.B2 = (LVM_FLOAT)-pEqualiserCoefTable[Offset].B2;
-
- LoadConst_Float((LVM_INT16)0, /* Value */
- (void *)&pData->EqualiserBiquadTaps, /* Destination Cast to void:\
- no dereferencing in function*/
- /* Number of words */
- (LVM_UINT16)(sizeof(pData->EqualiserBiquadTaps) / sizeof(LVM_FLOAT)));
-
- BQ_2I_D16F32Css_TRC_WRA_01_Init(&pCoefficients->EqualiserBiquadInstance,
- &pData->EqualiserBiquadTaps,
- &Coeffs);
-
- /* Callbacks */
- switch(pEqualiserCoefTable[Offset].Scale)
- {
- case 13:
- pConfig->pBiquadCallBack = BQ_2I_D16F32C13_TRC_WRA_01;
- break;
- case 14:
- pConfig->pBiquadCallBack = BQ_2I_D16F32C14_TRC_WRA_01;
- break;
- case 15:
- pConfig->pBiquadCallBack = BQ_2I_D16F32C15_TRC_WRA_01;
- break;
- }
- }
-
- return(LVCS_SUCCESS);
-}
-#else
-LVCS_ReturnStatus_en LVCS_EqualiserInit(LVCS_Handle_t hInstance,
- LVCS_Params_t *pParams)
-{
-
- LVM_UINT16 Offset;
- LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
- LVCS_Equaliser_t *pConfig = (LVCS_Equaliser_t *)&pInstance->Equaliser;
- LVCS_Data_t *pData = (LVCS_Data_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress;
- LVCS_Coefficient_t *pCoefficients = (LVCS_Coefficient_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
- BQ_C16_Coefs_t Coeffs;
- const BiquadA012B12CoefsSP_t *pEqualiserCoefTable;
-
- /*
- * If the sample rate changes re-initialise the filters
- */
- if ((pInstance->Params.SampleRate != pParams->SampleRate) ||
- (pInstance->Params.SpeakerType != pParams->SpeakerType))
- {
- /*
- * Setup the filter coefficients and clear the history
- */
- Offset = (LVM_UINT16)(pParams->SampleRate + (pParams->SpeakerType * (1+LVM_FS_48000)));
- pEqualiserCoefTable = (BiquadA012B12CoefsSP_t*)&LVCS_EqualiserCoefTable[0];
-
- /* Left and right filters */
- /* Convert incoming coefficients to the required format/ordering */
- Coeffs.A0 = (LVM_INT16) pEqualiserCoefTable[Offset].A0;
- Coeffs.A1 = (LVM_INT16) pEqualiserCoefTable[Offset].A1;
- Coeffs.A2 = (LVM_INT16) pEqualiserCoefTable[Offset].A2;
- Coeffs.B1 = (LVM_INT16)-pEqualiserCoefTable[Offset].B1;
- Coeffs.B2 = (LVM_INT16)-pEqualiserCoefTable[Offset].B2;
-
- LoadConst_16((LVM_INT16)0, /* Value */
- (void *)&pData->EqualiserBiquadTaps, /* Destination Cast to void:\
- no dereferencing in function*/
- (LVM_UINT16)(sizeof(pData->EqualiserBiquadTaps)/sizeof(LVM_INT16))); /* Number of words */
-
- BQ_2I_D16F32Css_TRC_WRA_01_Init(&pCoefficients->EqualiserBiquadInstance,
- &pData->EqualiserBiquadTaps,
- &Coeffs);
-
- /* Callbacks */
- switch(pEqualiserCoefTable[Offset].Scale)
- {
- case 13:
- pConfig->pBiquadCallBack = BQ_2I_D16F32C13_TRC_WRA_01;
- break;
- case 14:
- pConfig->pBiquadCallBack = BQ_2I_D16F32C14_TRC_WRA_01;
- break;
- case 15:
- pConfig->pBiquadCallBack = BQ_2I_D16F32C15_TRC_WRA_01;
- break;
- }
- }
-
- return(LVCS_SUCCESS);
-}
-#endif
-/************************************************************************************/
-/* */
-/* FUNCTION: LVCS_Equaliser */
-/* */
-/* DESCRIPTION: */
-/* Apply the equaliser filter. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance Handle */
-/* pInputOutput Pointer to the input/output buffer */
-/* NumSamples The number of samples to process */
-/* */
-/* RETURNS: */
-/* LVCS_Success Always succeeds */
-/* */
-/* NOTES: */
-/* 1. Always processes in place. */
-/* */
-/************************************************************************************/
-#ifdef BUILD_FLOAT
-LVCS_ReturnStatus_en LVCS_Equaliser(LVCS_Handle_t hInstance,
- LVM_FLOAT *pInputOutput,
- LVM_UINT16 NumSamples)
-{
-
- LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
- LVCS_Equaliser_t *pConfig = (LVCS_Equaliser_t *)&pInstance->Equaliser;
- LVCS_Coefficient_t *pCoefficients;
-
-
- pCoefficients = (LVCS_Coefficient_t *) \
- pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
-
-
- /*
- * Check if the equaliser is required
- */
- if ((pInstance->Params.OperatingMode & LVCS_EQUALISERSWITCH) != 0)
- {
- /* Apply filter to the left and right channels */
- (pConfig->pBiquadCallBack)((Biquad_FLOAT_Instance_t*) \
- &pCoefficients->EqualiserBiquadInstance,
- (LVM_FLOAT *)pInputOutput,
- (LVM_FLOAT *)pInputOutput,
- (LVM_INT16)NumSamples);
- }
-
- return(LVCS_SUCCESS);
-}
-#else
-LVCS_ReturnStatus_en LVCS_Equaliser(LVCS_Handle_t hInstance,
- LVM_INT16 *pInputOutput,
- LVM_UINT16 NumSamples)
-{
-
- LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
- LVCS_Equaliser_t *pConfig = (LVCS_Equaliser_t *)&pInstance->Equaliser;
- LVCS_Coefficient_t *pCoefficients = (LVCS_Coefficient_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
-
-
- /*
- * Check if the equaliser is required
- */
- if ((pInstance->Params.OperatingMode & LVCS_EQUALISERSWITCH) != 0)
- {
- /* Apply filter to the left and right channels */
- (pConfig->pBiquadCallBack)((Biquad_Instance_t*)&pCoefficients->EqualiserBiquadInstance,
- (LVM_INT16 *)pInputOutput,
- (LVM_INT16 *)pInputOutput,
- (LVM_INT16)NumSamples);
- }
-
- return(LVCS_SUCCESS);
-}
-#endif
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.cpp
new file mode 100644
index 0000000..431b7e3
--- /dev/null
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.cpp
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/************************************************************************************/
+/* */
+/* Includes */
+/* */
+/************************************************************************************/
+
+#include "LVCS.h"
+#include "LVCS_Private.h"
+#include "LVCS_Equaliser.h"
+#include "BIQUAD.h"
+#include "VectorArithmetic.h"
+#include "LVCS_Tables.h"
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVCS_EqualiserInit */
+/* */
+/* DESCRIPTION: */
+/* Initialises the equaliser module */
+/* */
+/* The function selects the coefficients for the filters and clears the data */
+/* history. It is also used for re-initialisation when one of the system control */
+/* parameters changes but will only change the coefficients and clear the history */
+/* if the sample rate or speaker type has changed. */
+/* */
+/* To avoid excessive testing during the sample processing the biquad type is */
+/* set as a callback function in the init routine. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance Handle */
+/* pParams Initialisation parameters */
+/* */
+/* RETURNS: */
+/* LVCS_Success Always succeeds */
+/* */
+/* NOTES: */
+/* */
+/************************************************************************************/
+LVCS_ReturnStatus_en LVCS_EqualiserInit(LVCS_Handle_t hInstance,
+ LVCS_Params_t *pParams)
+{
+
+ LVM_UINT16 Offset;
+ LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
+ LVCS_Equaliser_t *pConfig = (LVCS_Equaliser_t *)&pInstance->Equaliser;
+ LVCS_Data_t *pData;
+ LVCS_Coefficient_t *pCoefficients;
+ BQ_FLOAT_Coefs_t Coeffs;
+ const BiquadA012B12CoefsSP_t *pEqualiserCoefTable;
+
+ pData = (LVCS_Data_t *) \
+ pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress;
+
+ pCoefficients = (LVCS_Coefficient_t *) \
+ pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
+ /*
+ * If the sample rate changes re-initialise the filters
+ */
+ if ((pInstance->Params.SampleRate != pParams->SampleRate) ||
+ (pInstance->Params.SpeakerType != pParams->SpeakerType))
+ {
+ /*
+ * Setup the filter coefficients and clear the history
+ */
+ Offset = (LVM_UINT16)(pParams->SampleRate + (pParams->SpeakerType * (1 + LVM_FS_48000)));
+ pEqualiserCoefTable = (BiquadA012B12CoefsSP_t*)&LVCS_EqualiserCoefTable[0];
+
+ /* Left and right filters */
+ /* Convert incoming coefficients to the required format/ordering */
+ Coeffs.A0 = (LVM_FLOAT) pEqualiserCoefTable[Offset].A0;
+ Coeffs.A1 = (LVM_FLOAT) pEqualiserCoefTable[Offset].A1;
+ Coeffs.A2 = (LVM_FLOAT) pEqualiserCoefTable[Offset].A2;
+ Coeffs.B1 = (LVM_FLOAT)-pEqualiserCoefTable[Offset].B1;
+ Coeffs.B2 = (LVM_FLOAT)-pEqualiserCoefTable[Offset].B2;
+
+ LoadConst_Float((LVM_INT16)0, /* Value */
+ (LVM_FLOAT *)&pData->EqualiserBiquadTaps, /* Destination */
+ /* Number of words */
+ (LVM_UINT16)(sizeof(pData->EqualiserBiquadTaps) / sizeof(LVM_FLOAT)));
+
+ BQ_2I_D16F32Css_TRC_WRA_01_Init(&pCoefficients->EqualiserBiquadInstance,
+ &pData->EqualiserBiquadTaps,
+ &Coeffs);
+
+ /* Callbacks */
+ switch(pEqualiserCoefTable[Offset].Scale)
+ {
+ case 13:
+ pConfig->pBiquadCallBack = BQ_2I_D16F32C13_TRC_WRA_01;
+ break;
+ case 14:
+ pConfig->pBiquadCallBack = BQ_2I_D16F32C14_TRC_WRA_01;
+ break;
+ case 15:
+ pConfig->pBiquadCallBack = BQ_2I_D16F32C15_TRC_WRA_01;
+ break;
+ }
+ }
+
+ return(LVCS_SUCCESS);
+}
+/************************************************************************************/
+/* */
+/* FUNCTION: LVCS_Equaliser */
+/* */
+/* DESCRIPTION: */
+/* Apply the equaliser filter. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance Handle */
+/* pInputOutput Pointer to the input/output buffer */
+/* NumSamples The number of samples to process */
+/* */
+/* RETURNS: */
+/* LVCS_Success Always succeeds */
+/* */
+/* NOTES: */
+/* 1. Always processes in place. */
+/* */
+/************************************************************************************/
+LVCS_ReturnStatus_en LVCS_Equaliser(LVCS_Handle_t hInstance,
+ LVM_FLOAT *pInputOutput,
+ LVM_UINT16 NumSamples)
+{
+
+ LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
+ LVCS_Equaliser_t *pConfig = (LVCS_Equaliser_t *)&pInstance->Equaliser;
+ LVCS_Coefficient_t *pCoefficients;
+
+ pCoefficients = (LVCS_Coefficient_t *) \
+ pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
+
+ /*
+ * Check if the equaliser is required
+ */
+ if ((pInstance->Params.OperatingMode & LVCS_EQUALISERSWITCH) != 0)
+ {
+ /* Apply filter to the left and right channels */
+ (pConfig->pBiquadCallBack)((Biquad_FLOAT_Instance_t*) \
+ &pCoefficients->EqualiserBiquadInstance,
+ (LVM_FLOAT *)pInputOutput,
+ (LVM_FLOAT *)pInputOutput,
+ (LVM_INT16)NumSamples);
+ }
+
+ return(LVCS_SUCCESS);
+}
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.h b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.h
index 0e756e7..918d931 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.h
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.h
@@ -18,11 +18,6 @@
#ifndef __LVCS_EQUALISER_H__
#define __LVCS_EQUALISER_H__
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-
/************************************************************************************/
/* */
/* Structures */
@@ -32,14 +27,9 @@
/* Equaliser structure */
typedef struct
{
-#ifndef BUILD_FLOAT
- void (*pBiquadCallBack) (Biquad_Instance_t*, LVM_INT16*, LVM_INT16*, LVM_INT16);
-#else
void (*pBiquadCallBack) (Biquad_FLOAT_Instance_t*, LVM_FLOAT*, LVM_FLOAT*, LVM_INT16);
-#endif
} LVCS_Equaliser_t;
-
/************************************************************************************/
/* */
/* Function prototypes */
@@ -48,17 +38,8 @@
LVCS_ReturnStatus_en LVCS_EqualiserInit(LVCS_Handle_t hInstance,
LVCS_Params_t *pParams);
-#ifndef BUILD_FLOAT
-LVCS_ReturnStatus_en LVCS_Equaliser(LVCS_Handle_t hInstance,
- LVM_INT16 *pInputOutput,
- LVM_UINT16 NumSamples);
-#else
LVCS_ReturnStatus_en LVCS_Equaliser(LVCS_Handle_t hInstance,
LVM_FLOAT *pInputOutput,
LVM_UINT16 NumSamples);
-#endif
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
#endif /* EQUALISER_H */
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Headphone_Coeffs.h b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Headphone_Coeffs.h
index ba05577..c7ee232 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Headphone_Coeffs.h
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Headphone_Coeffs.h
@@ -18,13 +18,11 @@
#ifndef __LVCS_HEADPHONE_COEFFS_H__
#define __LVCS_HEADPHONE_COEFFS_H__
-
/************************************************************************************/
/* */
/* The Stereo Enhancer */
/* */
/************************************************************************************/
-#ifdef BUILD_FLOAT
/* Stereo Enhancer coefficients for 8000 Hz sample rate, scaled with 0.161258 */
#define CS_MIDDLE_8000_A0 0.227720
#define CS_MIDDLE_8000_A1 (-0.215125)
@@ -151,7 +149,6 @@
#define CS_SIDE_48000_B2 0.630405
#define CS_SIDE_48000_SCALE 14
-#ifdef HIGHER_FS
/* Coefficients for 88200Hz sample rate.
* The filter coefficients are obtained by carrying out
* state-space analysis using the coefficients available
@@ -222,7 +219,6 @@
#define CS_SIDE_192000_B1 (-1.891380f)
#define CS_SIDE_192000_B2 0.8923460f
#define CS_SIDE_192000_SCALE 14
-#endif
/************************************************************************************/
/* */
@@ -286,7 +282,6 @@
#define CS_REVERB_22050_B2 (-0.290990)
#define CS_REVERB_22050_SCALE 15
-
/* Reverb coefficients for 24000Hz sample rate, scaled with 1.038030 */
#define CS_REVERB_24000_A0 0.479565
#define CS_REVERB_24000_A1 0.000000
@@ -319,7 +314,6 @@
#define CS_REVERB_48000_B2 0.303347
#define CS_REVERB_48000_SCALE 14
-#ifdef HIGHER_FS
/* Reverb coefficients for 88200Hz sample rate, scaled with 0.8 */
/* Band pass filter with fc1=500 and fc2=8000 */
#define CS_REVERB_88200_A0 0.171901f
@@ -354,9 +348,6 @@
#define CS_REVERB_192000_B2 0.7804076
#define CS_REVERB_192000_SCALE 14
-#endif
-
-
/* Reverb Gain Settings */
#define LVCS_HEADPHONE_DELAYGAIN 0.800000 /* Algorithm delay path gain */
#define LVCS_HEADPHONE_OUTPUTGAIN 1.000000 /* Algorithm output gain */
@@ -505,8 +496,6 @@
#define CSEX_EQUALISER_48000_B2 (-0.347332)
#define CSEX_EQUALISER_48000_SCALE 13
-
-#ifdef HIGHER_FS
/* Equaliser coefficients for 88200Hz sample rate.
* The filter coefficients are obtained by carrying out
* state-space analysis using the coefficients available
@@ -567,8 +556,6 @@
#define CSEX_EQUALISER_192000_B1 (-1.31074)
#define CSEX_EQUALISER_192000_B2 0.31312
#define CSEX_EQUALISER_192000_SCALE 13
-#endif
-
#define LVCS_HEADPHONE_SHIFT 2 /* Output Shift */
#define LVCS_HEADPHONE_SHIFTLOSS 0.8477735 /* Output Shift loss */
@@ -576,376 +563,5 @@
#define LVCS_EX_HEADPHONE_SHIFT 3 /* EX Output Shift */
#define LVCS_EX_HEADPHONE_SHIFTLOSS 0.569225 /* EX Output Shift loss */
#define LVCS_EX_HEADPHONE_GAIN 0.07794425 /* EX Unprocessed path gain */
-#else
-/* Stereo Enhancer coefficients for 8000 Hz sample rate, scaled with 0.161258 */
-#define CS_MIDDLE_8000_A0 7462 /* Floating point value 0.227720 */
-#define CS_MIDDLE_8000_A1 (-7049) /* Floating point value -0.215125 */
-#define CS_MIDDLE_8000_A2 0 /* Floating point value 0.000000 */
-#define CS_MIDDLE_8000_B1 (-30209) /* Floating point value -0.921899 */
-#define CS_MIDDLE_8000_B2 0 /* Floating point value 0.000000 */
-#define CS_MIDDLE_8000_SCALE 15
-#define CS_SIDE_8000_A0 20036 /* Floating point value 0.611441 */
-#define CS_SIDE_8000_A1 (-12463) /* Floating point value -0.380344 */
-#define CS_SIDE_8000_A2 (-7573) /* Floating point value -0.231097 */
-#define CS_SIDE_8000_B1 (-20397) /* Floating point value -0.622470 */
-#define CS_SIDE_8000_B2 (-4285) /* Floating point value -0.130759 */
-#define CS_SIDE_8000_SCALE 15
-
-/* Stereo Enhancer coefficients for 11025Hz sample rate, scaled with 0.162943 */
-#define CS_MIDDLE_11025_A0 7564 /* Floating point value 0.230838 */
-#define CS_MIDDLE_11025_A1 (-7260) /* Floating point value -0.221559 */
-#define CS_MIDDLE_11025_A2 0 /* Floating point value 0.000000 */
-#define CS_MIDDLE_11025_B1 (-30902) /* Floating point value -0.943056 */
-#define CS_MIDDLE_11025_B2 0 /* Floating point value 0.000000 */
-#define CS_MIDDLE_11025_SCALE 15
-#define CS_SIDE_11025_A0 18264 /* Floating point value 0.557372 */
-#define CS_SIDE_11025_A1 (-12828) /* Floating point value -0.391490 */
-#define CS_SIDE_11025_A2 (-5436) /* Floating point value -0.165881 */
-#define CS_SIDE_11025_B1 (-28856) /* Floating point value -0.880608 */
-#define CS_SIDE_11025_B2 1062 /* Floating point value 0.032397 */
-#define CS_SIDE_11025_SCALE 15
-
-/* Stereo Enhancer coefficients for 12000Hz sample rate, scaled with 0.162191 */
-#define CS_MIDDLE_12000_A0 7534 /* Floating point value 0.229932 */
-#define CS_MIDDLE_12000_A1 (-7256) /* Floating point value -0.221436 */
-#define CS_MIDDLE_12000_A2 0 /* Floating point value 0.000000 */
-#define CS_MIDDLE_12000_B1 (-31051) /* Floating point value -0.947616 */
-#define CS_MIDDLE_12000_B2 0 /* Floating point value 0.000000 */
-#define CS_MIDDLE_12000_SCALE 15
-#define CS_SIDE_12000_A0 18298 /* Floating point value 0.558398 */
-#define CS_SIDE_12000_A1 (-12852) /* Floating point value -0.392211 */
-#define CS_SIDE_12000_A2 (-5446) /* Floating point value -0.166187 */
-#define CS_SIDE_12000_B1 (-29247) /* Floating point value -0.892550 */
-#define CS_SIDE_12000_B2 1077 /* Floating point value 0.032856 */
-#define CS_SIDE_12000_SCALE 15
-
-/* Stereo Enhancer coefficients for 16000Hz sample rate, scaled with 0.162371 */
-#define CS_MIDDLE_16000_A0 7558 /* Floating point value 0.230638 */
-#define CS_MIDDLE_16000_A1 (-7348) /* Floating point value -0.224232 */
-#define CS_MIDDLE_16000_A2 0 /* Floating point value 0.000000 */
-#define CS_MIDDLE_16000_B1 (-31475) /* Floating point value -0.960550 */
-#define CS_MIDDLE_16000_B2 0 /* Floating point value 0.000000 */
-#define CS_MIDDLE_16000_SCALE 15
-#define CS_SIDE_16000_A0 8187 /* Floating point value 0.499695 */
-#define CS_SIDE_16000_A1 (-5825) /* Floating point value -0.355543 */
-#define CS_SIDE_16000_A2 (-2362) /* Floating point value -0.144152 */
-#define CS_SIDE_16000_B1 (-17216) /* Floating point value -1.050788 */
-#define CS_SIDE_16000_B2 2361 /* Floating point value 0.144104 */
-#define CS_SIDE_16000_SCALE 14
-
-/* Stereo Enhancer coefficients for 22050Hz sample rate, scaled with 0.160781 */
-#define CS_MIDDLE_22050_A0 7496 /* Floating point value 0.228749 */
-#define CS_MIDDLE_22050_A1 (-7344) /* Floating point value -0.224128 */
-#define CS_MIDDLE_22050_A2 0 /* Floating point value 0.000000 */
-#define CS_MIDDLE_22050_B1 (-31826) /* Floating point value -0.971262 */
-#define CS_MIDDLE_22050_B2 0 /* Floating point value 0.000000 */
-#define CS_MIDDLE_22050_SCALE 15
-#define CS_SIDE_22050_A0 7211 /* Floating point value 0.440112 */
-#define CS_SIDE_22050_A1 (-4278) /* Floating point value -0.261096 */
-#define CS_SIDE_22050_A2 (-2933) /* Floating point value -0.179016 */
-#define CS_SIDE_22050_B1 (-18297) /* Floating point value -1.116786 */
-#define CS_SIDE_22050_B2 2990 /* Floating point value 0.182507 */
-#define CS_SIDE_22050_SCALE 14
-
-/* Stereo Enhancer coefficients for 24000Hz sample rate, scaled with 0.161882 */
-#define CS_MIDDLE_24000_A0 7550 /* Floating point value 0.230395 */
-#define CS_MIDDLE_24000_A1 (-7409) /* Floating point value -0.226117 */
-#define CS_MIDDLE_24000_A2 0 /* Floating point value 0.000000 */
-#define CS_MIDDLE_24000_B1 (-31902) /* Floating point value -0.973573 */
-#define CS_MIDDLE_24000_B2 0 /* Floating point value 0.000000 */
-#define CS_MIDDLE_24000_SCALE 15
-#define CS_SIDE_24000_A0 6796 /* Floating point value 0.414770 */
-#define CS_SIDE_24000_A1 (-4705) /* Floating point value -0.287182 */
-#define CS_SIDE_24000_A2 (-2090) /* Floating point value -0.127588 */
-#define CS_SIDE_24000_B1 (-20147) /* Floating point value -1.229648 */
-#define CS_SIDE_24000_B2 4623 /* Floating point value 0.282177 */
-#define CS_SIDE_24000_SCALE 14
-
-/* Stereo Enhancer coefficients for 32000Hz sample rate, scaled with 0.160322 */
-#define CS_MIDDLE_32000_A0 7484 /* Floating point value 0.228400 */
-#define CS_MIDDLE_32000_A1 (-7380) /* Floating point value -0.225214 */
-#define CS_MIDDLE_32000_A2 0 /* Floating point value 0.000000 */
-#define CS_MIDDLE_32000_B1 (-32117) /* Floating point value -0.980126 */
-#define CS_MIDDLE_32000_B2 0 /* Floating point value 0.000000 */
-#define CS_MIDDLE_32000_SCALE 15
-#define CS_SIDE_32000_A0 5973 /* Floating point value 0.364579 */
-#define CS_SIDE_32000_A1 (-3397) /* Floating point value -0.207355 */
-#define CS_SIDE_32000_A2 (-2576) /* Floating point value -0.157224 */
-#define CS_SIDE_32000_B1 (-20877) /* Floating point value -1.274231 */
-#define CS_SIDE_32000_B2 5120 /* Floating point value 0.312495 */
-#define CS_SIDE_32000_SCALE 14
-
-/* Stereo Enhancer coefficients for 44100Hz sample rate, scaled with 0.163834 */
-#define CS_MIDDLE_44100_A0 7654 /* Floating point value 0.233593 */
-#define CS_MIDDLE_44100_A1 (-7577) /* Floating point value -0.231225 */
-#define CS_MIDDLE_44100_A2 0 /* Floating point value 0.000000 */
-#define CS_MIDDLE_44100_B1 (-32294) /* Floating point value -0.985545 */
-#define CS_MIDDLE_44100_B2 0 /* Floating point value 0.000000 */
-#define CS_MIDDLE_44100_SCALE 15
-#define CS_SIDE_44100_A0 4662 /* Floating point value 0.284573 */
-#define CS_SIDE_44100_A1 (-4242) /* Floating point value -0.258910 */
-#define CS_SIDE_44100_A2 (-420) /* Floating point value -0.025662 */
-#define CS_SIDE_44100_B1 (-25760) /* Floating point value -1.572248 */
-#define CS_SIDE_44100_B2 9640 /* Floating point value 0.588399 */
-#define CS_SIDE_44100_SCALE 14
-
-/* Stereo Enhancer coefficients for 48000Hz sample rate, scaled with 0.164402 */
-#define CS_MIDDLE_48000_A0 7682 /* Floating point value 0.234445 */
-#define CS_MIDDLE_48000_A1 (-7611) /* Floating point value -0.232261 */
-#define CS_MIDDLE_48000_A2 0 /* Floating point value 0.000000 */
-#define CS_MIDDLE_48000_B1 (-32333) /* Floating point value -0.986713 */
-#define CS_MIDDLE_48000_B2 0 /* Floating point value 0.000000 */
-#define CS_MIDDLE_48000_SCALE 15
-#define CS_SIDE_48000_A0 4466 /* Floating point value 0.272606 */
-#define CS_SIDE_48000_A1 (-4374) /* Floating point value -0.266952 */
-#define CS_SIDE_48000_A2 (-93) /* Floating point value -0.005654 */
-#define CS_SIDE_48000_B1 (-26495) /* Floating point value -1.617141 */
-#define CS_SIDE_48000_B2 10329 /* Floating point value 0.630405 */
-#define CS_SIDE_48000_SCALE 14
-
-
-/************************************************************************************/
-/* */
-/* The Reverb Unit */
-/* */
-/************************************************************************************/
-
-/* Reverb delay settings in samples */
-#define LVCS_STEREODELAY_CS_8KHZ 93 /* Sample rate 8kS/s */
-#define LVCS_STEREODELAY_CS_11KHZ 128 /* Sample rate 11kS/s */
-#define LVCS_STEREODELAY_CS_12KHZ 139 /* Sample rate 12kS/s */
-#define LVCS_STEREODELAY_CS_16KHZ 186 /* Sample rate 16kS/s */
-#define LVCS_STEREODELAY_CS_22KHZ 256 /* Sample rate 22kS/s */
-#define LVCS_STEREODELAY_CS_24KHZ 279 /* Sample rate 24kS/s */
-#define LVCS_STEREODELAY_CS_32KHZ 372 /* Sample rate 32kS/s */
-#define LVCS_STEREODELAY_CS_44KHZ 512 /* Sample rate 44kS/s */
-#define LVCS_STEREODELAY_CS_48KHZ 512 /* Sample rate 48kS/s */
-
-/* Reverb coefficients for 8000 Hz sample rate, scaled with 1.038030 */
-#define CS_REVERB_8000_A0 21865 /* Floating point value 0.667271 */
-#define CS_REVERB_8000_A1 (-21865) /* Floating point value -0.667271 */
-#define CS_REVERB_8000_A2 0 /* Floating point value 0.000000 */
-#define CS_REVERB_8000_B1 (-21895) /* Floating point value -0.668179 */
-#define CS_REVERB_8000_B2 0 /* Floating point value 0.000000 */
-#define CS_REVERB_8000_SCALE 15
-
-/* Reverb coefficients for 11025Hz sample rate, scaled with 1.038030 */
-#define CS_REVERB_11025_A0 22926 /* Floating point value 0.699638 */
-#define CS_REVERB_11025_A1 (-22926) /* Floating point value -0.699638 */
-#define CS_REVERB_11025_A2 0 /* Floating point value 0.000000 */
-#define CS_REVERB_11025_B1 (-24546) /* Floating point value -0.749096 */
-#define CS_REVERB_11025_B2 0 /* Floating point value 0.000000 */
-#define CS_REVERB_11025_SCALE 15
-
-/* Reverb coefficients for 12000Hz sample rate, scaled with 1.038030 */
-#define CS_REVERB_12000_A0 23165 /* Floating point value 0.706931 */
-#define CS_REVERB_12000_A1 (-23165) /* Floating point value -0.706931 */
-#define CS_REVERB_12000_A2 0 /* Floating point value 0.000000 */
-#define CS_REVERB_12000_B1 (-25144) /* Floating point value -0.767327 */
-#define CS_REVERB_12000_B2 0 /* Floating point value 0.000000 */
-#define CS_REVERB_12000_SCALE 15
-
-/* Reverb coefficients for 16000Hz sample rate, scaled with 1.038030 */
-#define CS_REVERB_16000_A0 23864 /* Floating point value 0.728272 */
-#define CS_REVERB_16000_A1 (-23864) /* Floating point value -0.728272 */
-#define CS_REVERB_16000_A2 0 /* Floating point value 0.000000 */
-#define CS_REVERB_16000_B1 (-26892) /* Floating point value -0.820679 */
-#define CS_REVERB_16000_B2 0 /* Floating point value 0.000000 */
-#define CS_REVERB_16000_SCALE 15
-
-/* Reverb coefficients for 22050Hz sample rate, scaled with 1.038030 */
-#define CS_REVERB_22050_A0 16921 /* Floating point value 0.516396 */
-#define CS_REVERB_22050_A1 0 /* Floating point value 0.000000 */
-#define CS_REVERB_22050_A2 (-16921) /* Floating point value -0.516396 */
-#define CS_REVERB_22050_B1 (-16991) /* Floating point value -0.518512 */
-#define CS_REVERB_22050_B2 (-9535) /* Floating point value -0.290990 */
-#define CS_REVERB_22050_SCALE 15
-
-/* Reverb coefficients for 24000Hz sample rate, scaled with 1.038030 */
-#define CS_REVERB_24000_A0 15714 /* Floating point value 0.479565 */
-#define CS_REVERB_24000_A1 0 /* Floating point value 0.000000 */
-#define CS_REVERB_24000_A2 (-15714) /* Floating point value -0.479565 */
-#define CS_REVERB_24000_B1 (-20898) /* Floating point value -0.637745 */
-#define CS_REVERB_24000_B2 (-6518) /* Floating point value -0.198912 */
-#define CS_REVERB_24000_SCALE 15
-
-/* Reverb coefficients for 32000Hz sample rate, scaled with 1.038030 */
-#define CS_REVERB_32000_A0 12463 /* Floating point value 0.380349 */
-#define CS_REVERB_32000_A1 0 /* Floating point value 0.000000 */
-#define CS_REVERB_32000_A2 (-12463) /* Floating point value -0.380349 */
-#define CS_REVERB_32000_B1 (-31158) /* Floating point value -0.950873 */
-#define CS_REVERB_32000_B2 1610 /* Floating point value 0.049127 */
-#define CS_REVERB_32000_SCALE 15
-
-/* Reverb coefficients for 44100Hz sample rate, scaled with 1.038030 */
-#define CS_REVERB_44100_A0 4872 /* Floating point value 0.297389 */
-#define CS_REVERB_44100_A1 0 /* Floating point value 0.000000 */
-#define CS_REVERB_44100_A2 (-4872) /* Floating point value -0.297389 */
-#define CS_REVERB_44100_B1 (-19668) /* Floating point value -1.200423 */
-#define CS_REVERB_44100_B2 4203 /* Floating point value 0.256529 */
-#define CS_REVERB_44100_SCALE 14
-
-/* Reverb coefficients for 48000Hz sample rate, scaled with 1.038030 */
-#define CS_REVERB_48000_A0 4566 /* Floating point value 0.278661 */
-#define CS_REVERB_48000_A1 0 /* Floating point value 0.000000 */
-#define CS_REVERB_48000_A2 (-4566) /* Floating point value -0.278661 */
-#define CS_REVERB_48000_B1 (-20562) /* Floating point value -1.254993 */
-#define CS_REVERB_48000_B2 4970 /* Floating point value 0.303347 */
-#define CS_REVERB_48000_SCALE 14
-
-/* Reverb Gain Settings */
-#define LVCS_HEADPHONE_DELAYGAIN 0.800000 /* Algorithm delay path gain */
-#define LVCS_HEADPHONE_OUTPUTGAIN 1.000000 /* Algorithm output gain */
-#define LVCS_HEADPHONE_PROCGAIN 18403 /* Processed path gain */
-#define LVCS_HEADPHONE_UNPROCGAIN 18403 /* Unprocessed path gain */
-#define LVCS_HEADPHONE_GAINCORRECT 1.009343 /* Delay mixer gain correction */
-
-
-/************************************************************************************/
-/* */
-/* The Equaliser */
-/* */
-/************************************************************************************/
-
-/* Equaliser coefficients for 8000 Hz sample rate, CS scaled with 1.038497 and CSEX scaled with 0.775480 */
-#define CS_EQUALISER_8000_A0 20698 /* Floating point value 1.263312 */
-#define CS_EQUALISER_8000_A1 (-9859) /* Floating point value -0.601748 */
-#define CS_EQUALISER_8000_A2 (-4599) /* Floating point value -0.280681 */
-#define CS_EQUALISER_8000_B1 (-7797) /* Floating point value -0.475865 */
-#define CS_EQUALISER_8000_B2 (-6687) /* Floating point value -0.408154 */
-#define CS_EQUALISER_8000_SCALE 14
-#define CSEX_EQUALISER_8000_A0 30912 /* Floating point value 0.943357 */
-#define CSEX_EQUALISER_8000_A1 (-14724) /* Floating point value -0.449345 */
-#define CSEX_EQUALISER_8000_A2 (-6868) /* Floating point value -0.209594 */
-#define CSEX_EQUALISER_8000_B1 (-15593) /* Floating point value -0.475865 */
-#define CSEX_EQUALISER_8000_B2 (-13374) /* Floating point value -0.408154 */
-#define CSEX_EQUALISER_8000_SCALE 15
-
-/* Equaliser coefficients for 11025Hz sample rate, CS scaled with 1.027761 and CSEX scaled with 0.767463 */
-#define CS_EQUALISER_11025_A0 18041 /* Floating point value 1.101145 */
-#define CS_EQUALISER_11025_A1 2278 /* Floating point value 0.139020 */
-#define CS_EQUALISER_11025_A2 (-14163) /* Floating point value -0.864423 */
-#define CS_EQUALISER_11025_B1 402 /* Floating point value 0.024541 */
-#define CS_EQUALISER_11025_B2 (-14892) /* Floating point value -0.908930 */
-#define CS_EQUALISER_11025_SCALE 14
-#define CSEX_EQUALISER_11025_A0 31983 /* Floating point value 0.976058 */
-#define CSEX_EQUALISER_11025_A1 (-22784) /* Floating point value -0.695326 */
-#define CSEX_EQUALISER_11025_A2 (-2976) /* Floating point value -0.090809 */
-#define CSEX_EQUALISER_11025_B1 (-20008) /* Floating point value -0.610594 */
-#define CSEX_EQUALISER_11025_B2 (-10196) /* Floating point value -0.311149 */
-#define CSEX_EQUALISER_11025_SCALE 15
-
-/* Equaliser coefficients for 12000Hz sample rate, CS scaled with 1.032521 and CSEX scaled with 0.771017 */
-#define CS_EQUALISER_12000_A0 20917 /* Floating point value 1.276661 */
-#define CS_EQUALISER_12000_A1 (-16671) /* Floating point value -1.017519 */
-#define CS_EQUALISER_12000_A2 (-723) /* Floating point value -0.044128 */
-#define CS_EQUALISER_12000_B1 (-11954) /* Floating point value -0.729616 */
-#define CS_EQUALISER_12000_B2 (-3351) /* Floating point value -0.204532 */
-#define CS_EQUALISER_12000_SCALE 14
-#define CSEX_EQUALISER_12000_A0 16500 /* Floating point value 1.007095 */
-#define CSEX_EQUALISER_12000_A1 (-14285) /* Floating point value -0.871912 */
-#define CSEX_EQUALISER_12000_A2 381 /* Floating point value 0.023232 */
-#define CSEX_EQUALISER_12000_B1 (-12220) /* Floating point value -0.745857 */
-#define CSEX_EQUALISER_12000_B2 (-3099) /* Floating point value -0.189171 */
-#define CSEX_EQUALISER_12000_SCALE 14
-
-/* Equaliser coefficients for 16000Hz sample rate, CS scaled with 1.031378 and CSEX scaled with 0.770164 */
-#define CS_EQUALISER_16000_A0 20998 /* Floating point value 1.281629 */
-#define CS_EQUALISER_16000_A1 (-17627) /* Floating point value -1.075872 */
-#define CS_EQUALISER_16000_A2 (-678) /* Floating point value -0.041365 */
-#define CS_EQUALISER_16000_B1 (-11882) /* Floating point value -0.725239 */
-#define CS_EQUALISER_16000_B2 (-3676) /* Floating point value -0.224358 */
-#define CS_EQUALISER_16000_SCALE 14
-#define CSEX_EQUALISER_16000_A0 17713 /* Floating point value 1.081091 */
-#define CSEX_EQUALISER_16000_A1 (-14208) /* Floating point value -0.867183 */
-#define CSEX_EQUALISER_16000_A2 (-1151) /* Floating point value -0.070247 */
-#define CSEX_EQUALISER_16000_B1 (-8440) /* Floating point value -0.515121 */
-#define CSEX_EQUALISER_16000_B2 (-6978) /* Floating point value -0.425893 */
-#define CSEX_EQUALISER_16000_SCALE 14
-
-/* Equaliser coefficients for 22050Hz sample rate, CS scaled with 1.041576 and CSEX scaled with 0.777779 */
-#define CS_EQUALISER_22050_A0 22751 /* Floating point value 1.388605 */
-#define CS_EQUALISER_22050_A1 (-21394) /* Floating point value -1.305799 */
-#define CS_EQUALISER_22050_A2 654 /* Floating point value 0.039922 */
-#define CS_EQUALISER_22050_B1 (-11788) /* Floating point value -0.719494 */
-#define CS_EQUALISER_22050_B2 (-3985) /* Floating point value -0.243245 */
-#define CS_EQUALISER_22050_SCALE 14
-#define CSEX_EQUALISER_22050_A0 20855 /* Floating point value 1.272910 */
-#define CSEX_EQUALISER_22050_A1 (-21971) /* Floating point value -1.341014 */
-#define CSEX_EQUALISER_22050_A2 2744 /* Floating point value 0.167462 */
-#define CSEX_EQUALISER_22050_B1 (-10063) /* Floating point value -0.614219 */
-#define CSEX_EQUALISER_22050_B2 (-5659) /* Floating point value -0.345384 */
-#define CSEX_EQUALISER_22050_SCALE 14
-
-/* Equaliser coefficients for 24000Hz sample rate, CS scaled with 1.034495 and CSEX scaled with 0.772491 */
-#define CS_EQUALISER_24000_A0 23099 /* Floating point value 1.409832 */
-#define CS_EQUALISER_24000_A1 (-23863) /* Floating point value -1.456506 */
-#define CS_EQUALISER_24000_A2 2481 /* Floating point value 0.151410 */
-#define CS_EQUALISER_24000_B1 (-13176) /* Floating point value -0.804201 */
-#define CS_EQUALISER_24000_B2 (-2683) /* Floating point value -0.163783 */
-#define CS_EQUALISER_24000_SCALE 14
-#define CSEX_EQUALISER_24000_A0 21286 /* Floating point value 1.299198 */
-#define CSEX_EQUALISER_24000_A1 (-23797) /* Floating point value -1.452447 */
-#define CSEX_EQUALISER_24000_A2 3940 /* Floating point value 0.240489 */
-#define CSEX_EQUALISER_24000_B1 (-10966) /* Floating point value -0.669303 */
-#define CSEX_EQUALISER_24000_B2 (-4833) /* Floating point value -0.294984 */
-#define CSEX_EQUALISER_24000_SCALE 14
-
-/* Equaliser coefficients for 32000Hz sample rate, CS scaled with 1.044559 and CSEX scaled with 0.780006 */
-#define CS_EQUALISER_32000_A0 25575 /* Floating point value 1.560988 */
-#define CS_EQUALISER_32000_A1 (-30765) /* Floating point value -1.877724 */
-#define CS_EQUALISER_32000_A2 6386 /* Floating point value 0.389741 */
-#define CS_EQUALISER_32000_B1 (-14867) /* Floating point value -0.907410 */
-#define CS_EQUALISER_32000_B2 (-1155) /* Floating point value -0.070489 */
-#define CS_EQUALISER_32000_SCALE 14
-#define CSEX_EQUALISER_32000_A0 14623 /* Floating point value 1.785049 */
-#define CSEX_EQUALISER_32000_A1 (-18297) /* Floating point value -2.233497 */
-#define CSEX_EQUALISER_32000_A2 4313 /* Floating point value 0.526431 */
-#define CSEX_EQUALISER_32000_B1 (-3653) /* Floating point value -0.445939 */
-#define CSEX_EQUALISER_32000_B2 (-4280) /* Floating point value -0.522446 */
-#define CSEX_EQUALISER_32000_SCALE 13
-
-/* Equaliser coefficients for 44100Hz sample rate, CS scaled with 1.022170 and CSEX scaled with 0.763288 */
-#define CS_EQUALISER_44100_A0 13304 /* Floating point value 1.623993 */
-#define CS_EQUALISER_44100_A1 (-18602) /* Floating point value -2.270743 */
-#define CS_EQUALISER_44100_A2 5643 /* Floating point value 0.688829 */
-#define CS_EQUALISER_44100_B1 (-9152) /* Floating point value -1.117190 */
-#define CS_EQUALISER_44100_B2 1067 /* Floating point value 0.130208 */
-#define CS_EQUALISER_44100_SCALE 13
-#define CSEX_EQUALISER_44100_A0 16616 /* Floating point value 2.028315 */
-#define CSEX_EQUALISER_44100_A1 (-23613) /* Floating point value -2.882459 */
-#define CSEX_EQUALISER_44100_A2 7410 /* Floating point value 0.904535 */
-#define CSEX_EQUALISER_44100_B1 (-4860) /* Floating point value -0.593308 */
-#define CSEX_EQUALISER_44100_B2 (-3161) /* Floating point value -0.385816 */
-#define CSEX_EQUALISER_44100_SCALE 13
-
-/* Equaliser coefficients for 48000Hz sample rate, CS scaled with 1.018635 and CSEX scaled with 0.760648 */
-#define CS_EQUALISER_48000_A0 13445 /* Floating point value 1.641177 */
-#define CS_EQUALISER_48000_A1 (-19372) /* Floating point value -2.364687 */
-#define CS_EQUALISER_48000_A2 6225 /* Floating point value 0.759910 */
-#define CS_EQUALISER_48000_B1 (-9558) /* Floating point value -1.166774 */
-#define CS_EQUALISER_48000_B2 1459 /* Floating point value 0.178074 */
-#define CS_EQUALISER_48000_SCALE 13
-#define CSEX_EQUALISER_48000_A0 17200 /* Floating point value 2.099655 */
-#define CSEX_EQUALISER_48000_A1 (-25110) /* Floating point value -3.065220 */
-#define CSEX_EQUALISER_48000_A2 8277 /* Floating point value 1.010417 */
-#define CSEX_EQUALISER_48000_B1 (-5194) /* Floating point value -0.634021 */
-#define CSEX_EQUALISER_48000_B2 (-2845) /* Floating point value -0.347332 */
-#define CSEX_EQUALISER_48000_SCALE 13
-
-
-/************************************************************************************/
-/* */
-/* The Output Gain Correction */
-/* */
-/************************************************************************************/
-
-#define LVCS_HEADPHONE_SHIFT 2 /* Output Shift */
-#define LVCS_HEADPHONE_SHIFTLOSS 27779 /* Output Shift loss */
-#define LVCS_HEADPHONE_GAIN 6840 /* Unprocessed path gain */
-#define LVCS_EX_HEADPHONE_SHIFT 3 /* EX Output Shift */
-#define LVCS_EX_HEADPHONE_SHIFTLOSS 18600 /* EX Output Shift loss */
-#define LVCS_EX_HEADPHONE_GAIN 5108 /* EX Unprocessed path gain */
-#endif
#endif
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Init.c b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Init.c
deleted file mode 100644
index d4c7627..0000000
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Init.c
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/************************************************************************************/
-/* */
-/* Includes */
-/* */
-/************************************************************************************/
-
-#include "LVCS.h"
-#include "LVCS_Private.h"
-#include "LVCS_Tables.h"
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVCS_Memory */
-/* */
-/* DESCRIPTION: */
-/* This function is used for memory allocation and free. It can be called in */
-/* two ways: */
-/* */
-/* hInstance = NULL Returns the memory requirements */
-/* hInstance = Instance handle Returns the memory requirements and */
-/* allocated base addresses for the instance */
-/* */
-/* When this function is called for memory allocation (hInstance=NULL) it is */
-/* passed the default capabilities. */
-/* */
-/* When called for memory allocation the memory base address pointers are NULL on */
-/* return. */
-/* */
-/* When the function is called for free (hInstance = Instance Handle) the */
-/* capabilities are ignored and the memory table returns the allocated memory and */
-/* base addresses used during initialisation. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance Handle */
-/* pMemoryTable Pointer to an empty memory definition table */
-/* pCapabilities Pointer to the default capabilites */
-/* */
-/* RETURNS: */
-/* LVCS_Success Succeeded */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVCS_Process function */
-/* */
-/****************************************************************************************/
-
-LVCS_ReturnStatus_en LVCS_Memory(LVCS_Handle_t hInstance,
- LVCS_MemTab_t *pMemoryTable,
- LVCS_Capabilities_t *pCapabilities)
-{
-
- LVM_UINT32 ScratchSize;
- LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
-
-
- /*
- * Fill in the memory table
- */
- if (hInstance == LVM_NULL)
- {
- /*
- * Instance memory
- */
- pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_SLOW_DATA].Size = (LVM_UINT32)sizeof(LVCS_Instance_t);
- pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_SLOW_DATA].Type = LVCS_PERSISTENT;
- pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_SLOW_DATA].pBaseAddress = LVM_NULL;
-
- /*
- * Data memory
- */
- pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].Size = (LVM_UINT32)sizeof(LVCS_Data_t);
- pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].Type = LVCS_DATA;
- pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress = LVM_NULL;
-
- /*
- * Coefficient memory
- */
- pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].Size = (LVM_UINT32)sizeof(LVCS_Coefficient_t);
- pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].Type = LVCS_COEFFICIENT;
- pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress = LVM_NULL;
-
- /*
- * Scratch memory
- */
-#ifdef BUILD_FLOAT
- /* Inplace processing */
- ScratchSize = (LVM_UINT32) \
- (LVCS_SCRATCHBUFFERS * sizeof(LVM_FLOAT) * pCapabilities->MaxBlockSize);
-#else
- ScratchSize = (LVM_UINT32)(LVCS_SCRATCHBUFFERS*sizeof(LVM_INT16)*pCapabilities->MaxBlockSize); /* Inplace processing */
-#endif
- pMemoryTable->Region[LVCS_MEMREGION_TEMPORARY_FAST].Size = ScratchSize;
- pMemoryTable->Region[LVCS_MEMREGION_TEMPORARY_FAST].Type = LVCS_SCRATCH;
- pMemoryTable->Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress = LVM_NULL;
- }
- else
- {
- /* Read back memory allocation table */
- *pMemoryTable = pInstance->MemoryTable;
- }
-
- return(LVCS_SUCCESS);
-}
-
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVCS_Init */
-/* */
-/* DESCRIPTION: */
-/* Create and initialisation function for the Concert Sound module */
-/* */
-/* This function can be used to create an algorithm instance by calling with */
-/* hInstance set to LVM_NULL. In this case the algorithm returns the new instance */
-/* handle. */
-/* */
-/* This function can be used to force a full re-initialisation of the algorithm */
-/* by calling with hInstance = Instance Handle. In this case the memory table */
-/* should be correct for the instance, this can be ensured by calling the function */
-/* LVCS_Memory before calling this function. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance handle */
-/* pMemoryTable Pointer to the memory definition table */
-/* pCapabilities Pointer to the capabilities structure */
-/* */
-/* RETURNS: */
-/* LVCS_Success Initialisation succeeded */
-/* */
-/* NOTES: */
-/* 1. The instance handle is the pointer to the base address of the first memory */
-/* region. */
-/* 2. This function must not be interrupted by the LVCS_Process function */
-/* 3. This function must be called with the same capabilities as used for the */
-/* call to the memory function */
-/* */
-/************************************************************************************/
-
-LVCS_ReturnStatus_en LVCS_Init(LVCS_Handle_t *phInstance,
- LVCS_MemTab_t *pMemoryTable,
- LVCS_Capabilities_t *pCapabilities)
-{
-
- LVCS_Instance_t *pInstance;
- LVCS_VolCorrect_t *pLVCS_VolCorrectTable;
-
-
- /*
- * Set the instance handle if not already initialised
- */
- if (*phInstance == LVM_NULL)
- {
- *phInstance = (LVCS_Handle_t)pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_SLOW_DATA].pBaseAddress;
- }
- pInstance =(LVCS_Instance_t *)*phInstance;
-
-
- /*
- * Save the capabilities in the instance structure
- */
- pInstance->Capabilities = *pCapabilities;
-
- /*
- * Save the memory table in the instance structure
- */
- pInstance->MemoryTable = *pMemoryTable;
-
-
- /*
- * Set all initial parameters to invalid to force a full initialisation
- */
- pInstance->Params.OperatingMode = LVCS_OFF;
- pInstance->Params.SpeakerType = LVCS_SPEAKERTYPE_MAX;
- pInstance->OutputDevice = LVCS_HEADPHONE;
- pInstance->Params.SourceFormat = LVCS_SOURCEMAX;
- pInstance->Params.CompressorMode = LVM_MODE_OFF;
- pInstance->Params.SampleRate = LVM_FS_INVALID;
- pInstance->Params.EffectLevel = 0;
- pInstance->Params.ReverbLevel = (LVM_UINT16)0x8000;
- pLVCS_VolCorrectTable = (LVCS_VolCorrect_t*)&LVCS_VolCorrectTable[0];
- pInstance->VolCorrect = pLVCS_VolCorrectTable[0];
- pInstance->TransitionGain = 0;
-
- /* These current and target values are intialized again in LVCS_Control.c */
- LVC_Mixer_Init(&pInstance->BypassMix.Mixer_Instance.MixerStream[0],0,0);
- /* These current and target values are intialized again in LVCS_Control.c */
- LVC_Mixer_Init(&pInstance->BypassMix.Mixer_Instance.MixerStream[1],0,0);
-
- /*
- * Initialise the bypass variables
- */
- pInstance->MSTarget0=0;
- pInstance->MSTarget1=0;
- pInstance->bInOperatingModeTransition = LVM_FALSE;
- pInstance->bTimerDone = LVM_FALSE;
- pInstance->TimerParams.CallBackParam = 0;
- pInstance->TimerParams.pCallBack = LVCS_TimerCallBack;
- pInstance->TimerParams.pCallbackInstance = pInstance;
- pInstance->TimerParams.pCallBackParams = LVM_NULL;
-
- return(LVCS_SUCCESS);
-}
-
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Init.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Init.cpp
new file mode 100644
index 0000000..630ecf7
--- /dev/null
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Init.cpp
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/************************************************************************************/
+/* */
+/* Includes */
+/* */
+/************************************************************************************/
+
+#include "LVCS.h"
+#include "LVCS_Private.h"
+#include "LVCS_Tables.h"
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVCS_Memory */
+/* */
+/* DESCRIPTION: */
+/* This function is used for memory allocation and free. It can be called in */
+/* two ways: */
+/* */
+/* hInstance = NULL Returns the memory requirements */
+/* hInstance = Instance handle Returns the memory requirements and */
+/* allocated base addresses for the instance */
+/* */
+/* When this function is called for memory allocation (hInstance=NULL) it is */
+/* passed the default capabilities. */
+/* */
+/* When called for memory allocation the memory base address pointers are NULL on */
+/* return. */
+/* */
+/* When the function is called for free (hInstance = Instance Handle) the */
+/* capabilities are ignored and the memory table returns the allocated memory and */
+/* base addresses used during initialisation. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance Handle */
+/* pMemoryTable Pointer to an empty memory definition table */
+/* pCapabilities Pointer to the default capabilites */
+/* */
+/* RETURNS: */
+/* LVCS_Success Succeeded */
+/* */
+/* NOTES: */
+/* 1. This function may be interrupted by the LVCS_Process function */
+/* */
+/****************************************************************************************/
+
+LVCS_ReturnStatus_en LVCS_Memory(LVCS_Handle_t hInstance,
+ LVCS_MemTab_t *pMemoryTable,
+ LVCS_Capabilities_t *pCapabilities)
+{
+
+ LVM_UINT32 ScratchSize;
+ LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
+
+ /*
+ * Fill in the memory table
+ */
+ if (hInstance == LVM_NULL)
+ {
+ /*
+ * Instance memory
+ */
+ pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_SLOW_DATA].Size = (LVM_UINT32)sizeof(LVCS_Instance_t);
+ pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_SLOW_DATA].Type = LVCS_PERSISTENT;
+ pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_SLOW_DATA].pBaseAddress = LVM_NULL;
+
+ /*
+ * Data memory
+ */
+ pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].Size = (LVM_UINT32)sizeof(LVCS_Data_t);
+ pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].Type = LVCS_DATA;
+ pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress = LVM_NULL;
+
+ /*
+ * Coefficient memory
+ */
+ pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].Size = (LVM_UINT32)sizeof(LVCS_Coefficient_t);
+ pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].Type = LVCS_COEFFICIENT;
+ pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress = LVM_NULL;
+
+ /*
+ * Scratch memory
+ */
+ /* Inplace processing */
+ ScratchSize = (LVM_UINT32) \
+ (LVCS_SCRATCHBUFFERS * sizeof(LVM_FLOAT) * pCapabilities->MaxBlockSize);
+ pMemoryTable->Region[LVCS_MEMREGION_TEMPORARY_FAST].Size = ScratchSize;
+ pMemoryTable->Region[LVCS_MEMREGION_TEMPORARY_FAST].Type = LVCS_SCRATCH;
+ pMemoryTable->Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress = LVM_NULL;
+ }
+ else
+ {
+ /* Read back memory allocation table */
+ *pMemoryTable = pInstance->MemoryTable;
+ }
+
+ return(LVCS_SUCCESS);
+}
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVCS_Init */
+/* */
+/* DESCRIPTION: */
+/* Create and initialisation function for the Concert Sound module */
+/* */
+/* This function can be used to create an algorithm instance by calling with */
+/* hInstance set to LVM_NULL. In this case the algorithm returns the new instance */
+/* handle. */
+/* */
+/* This function can be used to force a full re-initialisation of the algorithm */
+/* by calling with hInstance = Instance Handle. In this case the memory table */
+/* should be correct for the instance, this can be ensured by calling the function */
+/* LVCS_Memory before calling this function. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance handle */
+/* pMemoryTable Pointer to the memory definition table */
+/* pCapabilities Pointer to the capabilities structure */
+/* */
+/* RETURNS: */
+/* LVCS_Success Initialisation succeeded */
+/* */
+/* NOTES: */
+/* 1. The instance handle is the pointer to the base address of the first memory */
+/* region. */
+/* 2. This function must not be interrupted by the LVCS_Process function */
+/* 3. This function must be called with the same capabilities as used for the */
+/* call to the memory function */
+/* */
+/************************************************************************************/
+
+LVCS_ReturnStatus_en LVCS_Init(LVCS_Handle_t *phInstance,
+ LVCS_MemTab_t *pMemoryTable,
+ LVCS_Capabilities_t *pCapabilities)
+{
+
+ LVCS_Instance_t *pInstance;
+ LVCS_VolCorrect_t *pLVCS_VolCorrectTable;
+
+ /*
+ * Set the instance handle if not already initialised
+ */
+ if (*phInstance == LVM_NULL)
+ {
+ *phInstance = (LVCS_Handle_t)pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_SLOW_DATA].pBaseAddress;
+ }
+ pInstance =(LVCS_Instance_t *)*phInstance;
+
+ /*
+ * Save the capabilities in the instance structure
+ */
+ pInstance->Capabilities = *pCapabilities;
+
+ /*
+ * Save the memory table in the instance structure
+ */
+ pInstance->MemoryTable = *pMemoryTable;
+
+ /*
+ * Set all initial parameters to invalid to force a full initialisation
+ */
+ pInstance->Params.OperatingMode = LVCS_OFF;
+ pInstance->Params.SpeakerType = LVCS_SPEAKERTYPE_MAX;
+ pInstance->OutputDevice = LVCS_HEADPHONE;
+ pInstance->Params.SourceFormat = LVCS_SOURCEMAX;
+ pInstance->Params.CompressorMode = LVM_MODE_OFF;
+ pInstance->Params.SampleRate = LVM_FS_INVALID;
+ pInstance->Params.EffectLevel = 0;
+ pInstance->Params.ReverbLevel = (LVM_UINT16)0x8000;
+ pLVCS_VolCorrectTable = (LVCS_VolCorrect_t*)&LVCS_VolCorrectTable[0];
+ pInstance->VolCorrect = pLVCS_VolCorrectTable[0];
+ pInstance->TransitionGain = 0;
+
+ /* These current and target values are intialized again in LVCS_Control.c */
+ LVC_Mixer_Init(&pInstance->BypassMix.Mixer_Instance.MixerStream[0],0,0);
+ /* These current and target values are intialized again in LVCS_Control.c */
+ LVC_Mixer_Init(&pInstance->BypassMix.Mixer_Instance.MixerStream[1],0,0);
+
+ /*
+ * Initialise the bypass variables
+ */
+ pInstance->MSTarget0=0;
+ pInstance->MSTarget1=0;
+ pInstance->bInOperatingModeTransition = LVM_FALSE;
+ pInstance->bTimerDone = LVM_FALSE;
+ pInstance->TimerParams.CallBackParam = 0;
+ pInstance->TimerParams.pCallBack = LVCS_TimerCallBack;
+ pInstance->TimerParams.pCallbackInstance = pInstance;
+ pInstance->TimerParams.pCallBackParams = LVM_NULL;
+
+ return(LVCS_SUCCESS);
+}
+
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Private.h b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Private.h
index ab8ccd1..154ea55 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Private.h
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Private.h
@@ -27,11 +27,6 @@
#ifndef __LVCS_PRIVATE_H__
#define __LVCS_PRIVATE_H__
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-
/************************************************************************************/
/* */
/* Includes */
@@ -45,7 +40,6 @@
#include "LVCS_BypassMix.h" /* Bypass Mixer module definitions */
#include "LVM_Timer.h"
-
/************************************************************************************/
/* */
/* Defines */
@@ -60,7 +54,11 @@
#define LVCS_COMPGAINFRAME 64 /* Compressor gain update interval */
/* Memory */
+#ifdef SUPPORT_MC
+#define LVCS_SCRATCHBUFFERS 8 /* Number of buffers required for inplace processing */
+#else
#define LVCS_SCRATCHBUFFERS 6 /* Number of buffers required for inplace processing */
+#endif
#ifdef SUPPORT_MC
/*
* The Concert Surround module applies processing only on the first two
@@ -79,7 +77,6 @@
#define LVCS_NR_OF_FS 9
#define LVCS_NR_OF_CHAN_CFG 2
-
/************************************************************************************/
/* */
/* Types */
@@ -94,7 +91,6 @@
LVCS_DEVICE_MAX = LVM_MAXENUM
} LVCS_OutputDevice_en;
-
/************************************************************************************/
/* */
/* Structures */
@@ -104,17 +100,10 @@
/* Volume correction structure */
typedef struct
{
-#ifdef BUILD_FLOAT
LVM_FLOAT CompFull; /* Post CS compression 100% effect */
LVM_FLOAT CompMin; /* Post CS compression 0% effect */
LVM_FLOAT GainFull; /* CS gain correct 100% effect */
LVM_FLOAT GainMin; /* CS gain correct 0% effect */
-#else
- LVM_INT16 CompFull; /* Post CS compression 100% effect */
- LVM_INT16 CompMin; /* Post CS compression 0% effect */
- LVM_INT16 GainFull; /* CS gain correct 100% effect */
- LVM_INT16 GainMin; /* CS gain correct 0% effect */
-#endif
} LVCS_VolCorrect_t;
/* Instance structure */
@@ -128,13 +117,8 @@
/* Private parameters */
LVCS_OutputDevice_en OutputDevice; /* Selected output device type */
LVCS_VolCorrect_t VolCorrect; /* Volume correction settings */
-#ifndef BUILD_FLOAT
- LVM_INT16 TransitionGain; /* Transition gain */
- LVM_INT16 CompressGain; /* Last used compressor gain*/
-#else
LVM_FLOAT TransitionGain; /* Transition gain */
LVM_FLOAT CompressGain; /* Last used compressor gain*/
-#endif
/* Sub-block configurations */
LVCS_StereoEnhancer_t StereoEnhancer; /* Stereo enhancer configuration */
@@ -155,44 +139,24 @@
/* Coefficient Structure */
typedef struct
{
-#ifdef BUILD_FLOAT
Biquad_FLOAT_Instance_t EqualiserBiquadInstance;
Biquad_FLOAT_Instance_t ReverbBiquadInstance;
Biquad_FLOAT_Instance_t SEBiquadInstanceMid;
Biquad_FLOAT_Instance_t SEBiquadInstanceSide;
-#else
- Biquad_Instance_t EqualiserBiquadInstance;
- Biquad_Instance_t ReverbBiquadInstance;
- Biquad_Instance_t SEBiquadInstanceMid;
- Biquad_Instance_t SEBiquadInstanceSide;
-#endif
} LVCS_Coefficient_t;
/* Data Structure */
typedef struct
{
-#ifdef BUILD_FLOAT
Biquad_2I_Order2_FLOAT_Taps_t EqualiserBiquadTaps;
Biquad_2I_Order2_FLOAT_Taps_t ReverbBiquadTaps;
Biquad_1I_Order1_FLOAT_Taps_t SEBiquadTapsMid;
Biquad_1I_Order2_FLOAT_Taps_t SEBiquadTapsSide;
-#else
- Biquad_2I_Order2_Taps_t EqualiserBiquadTaps;
- Biquad_2I_Order2_Taps_t ReverbBiquadTaps;
- Biquad_1I_Order1_Taps_t SEBiquadTapsMid;
- Biquad_1I_Order2_Taps_t SEBiquadTapsSide;
-#endif
} LVCS_Data_t;
void LVCS_TimerCallBack ( void* hInstance,
void* pCallBackParams,
LVM_INT32 CallbackParam);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
#endif /* PRIVATE_H */
-
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Process.c b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Process.c
deleted file mode 100644
index ef1d9eb..0000000
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Process.c
+++ /dev/null
@@ -1,622 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-/************************************************************************************/
-/* */
-/* Includes */
-/* */
-/************************************************************************************/
-
-#include "LVCS.h"
-#include "LVCS_Private.h"
-#include "VectorArithmetic.h"
-#include "CompLim.h"
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVCS_Process_CS */
-/* */
-/* DESCRIPTION: */
-/* Process function for the Concert Sound module based on the following block */
-/* diagram: */
-/* _________ ________ _____ _______ ___ ______ */
-/* | | | | | | | | | | | | */
-/* ----->| Stereo |->| Reverb |->| Equ |->| Alpha |-->| + |-| Gain |----> */
-/* | | Enhance | |________| |_____| |_______| |___| |______| */
-/* | |_________| | */
-/* | ___________ | */
-/* | | | | */
-/* |------------------------------->| 1 - Alpha |-----| */
-/* |___________| */
-/* */
-/* The Stereo Enhancer, Reverb and Equaliser blocks are each configured to have */
-/* their gain to give a near peak to peak output (-0.1dBFS) with a worst case */
-/* input signal. The gains of these blocks are re-combined in the Alpha mixer and */
-/* the gain block folloing the sum. */
-/* */
-/* The processing uses the output buffer for data storage after each processing */
-/* block. When processing is inplace a copy of the input signal is made in scratch */
-/* memory for the 1-Alpha path. */
-/* */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance handle */
-/* pInData Pointer to the input data */
-/* pOutData Pointer to the output data */
-/* NumSamples Number of samples in the input buffer */
-/* */
-/* RETURNS: */
-/* LVCS_Success Succeeded */
-/* */
-/* NOTES: */
-/* */
-/************************************************************************************/
-#ifdef BUILD_FLOAT
-LVCS_ReturnStatus_en LVCS_Process_CS(LVCS_Handle_t hInstance,
- const LVM_FLOAT *pInData,
- LVM_FLOAT *pOutData,
- LVM_UINT16 NumSamples)
-{
- const LVM_FLOAT *pInput;
- LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
- LVM_FLOAT *pScratch;
- LVCS_ReturnStatus_en err;
-#ifdef SUPPORT_MC
- LVM_FLOAT *pStIn;
- LVM_INT32 channels = pInstance->Params.NrChannels;
-#define NrFrames NumSamples // alias for clarity
-
- /*In case of mono processing, stereo input is created from mono
- *and stored in pInData before applying any of the effects.
- *However we do not update the value pInstance->Params.NrChannels
- *at this point.
- *So to treat the pInData as stereo we are setting channels to 2
- */
- if (channels == 1)
- {
- channels = 2;
- }
-#endif
-
- pScratch = (LVM_FLOAT *) \
- pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
-
- /*
- * Check if the processing is inplace
- */
-#ifdef SUPPORT_MC
- /*
- * The pInput buffer holds the first 2 (Left, Right) channels information.
- * Hence the memory required by this buffer is 2 * NumFrames.
- * The Concert Surround module carries out processing only on L, R.
- */
- pInput = pScratch + (2 * NrFrames);
- pStIn = pScratch + (LVCS_SCRATCHBUFFERS * NrFrames);
- /* The first two channel data is extracted from the input data and
- * copied into pInput buffer
- */
- Copy_Float_Mc_Stereo((LVM_FLOAT *)pInData,
- (LVM_FLOAT *)pInput,
- NrFrames,
- channels);
- Copy_Float((LVM_FLOAT *)pInput,
- (LVM_FLOAT *)pStIn,
- (LVM_INT16)(2 * NrFrames));
-#else
- if (pInData == pOutData)
- {
- /* Processing inplace */
- pInput = pScratch + (2 * NumSamples);
- Copy_Float((LVM_FLOAT *)pInData, /* Source */
- (LVM_FLOAT *)pInput, /* Destination */
- (LVM_INT16)(2 * NumSamples)); /* Left and right */
- }
- else
- {
- /* Processing outplace */
- pInput = pInData;
- }
-#endif
- /*
- * Call the stereo enhancer
- */
-#ifdef SUPPORT_MC
- err = LVCS_StereoEnhancer(hInstance, /* Instance handle */
- pStIn, /* Pointer to the input data */
- pOutData, /* Pointer to the output data */
- NrFrames); /* Number of frames to process */
-#else
- err = LVCS_StereoEnhancer(hInstance, /* Instance handle */
- pInData, /* Pointer to the input data */
- pOutData, /* Pointer to the output data */
- NumSamples); /* Number of samples to process */
-#endif
-
- /*
- * Call the reverb generator
- */
- err = LVCS_ReverbGenerator(hInstance, /* Instance handle */
- pOutData, /* Pointer to the input data */
- pOutData, /* Pointer to the output data */
- NumSamples); /* Number of samples to process */
-
- /*
- * Call the equaliser
- */
- err = LVCS_Equaliser(hInstance, /* Instance handle */
- pOutData, /* Pointer to the input data */
- NumSamples); /* Number of samples to process */
-
- /*
- * Call the bypass mixer
- */
- err = LVCS_BypassMixer(hInstance, /* Instance handle */
- pOutData, /* Pointer to the processed data */
- pInput, /* Pointer to the input (unprocessed) data */
- pOutData, /* Pointer to the output data */
- NumSamples); /* Number of samples to process */
-
- if(err != LVCS_SUCCESS)
- {
- return err;
- }
-
- return(LVCS_SUCCESS);
-}
-#else
-LVCS_ReturnStatus_en LVCS_Process_CS(LVCS_Handle_t hInstance,
- const LVM_INT16 *pInData,
- LVM_INT16 *pOutData,
- LVM_UINT16 NumSamples)
-{
- const LVM_INT16 *pInput;
- LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
- LVM_INT16 *pScratch = (LVM_INT16 *)pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
- LVCS_ReturnStatus_en err;
-
- /*
- * Check if the processing is inplace
- */
- if (pInData == pOutData)
- {
- /* Processing inplace */
- pInput = pScratch + (2*NumSamples);
- Copy_16((LVM_INT16 *)pInData, /* Source */
- (LVM_INT16 *)pInput, /* Destination */
- (LVM_INT16)(2*NumSamples)); /* Left and right */
- }
- else
- {
- /* Processing outplace */
- pInput = pInData;
- }
-
- /*
- * Call the stereo enhancer
- */
- err=LVCS_StereoEnhancer(hInstance, /* Instance handle */
- pInData, /* Pointer to the input data */
- pOutData, /* Pointer to the output data */
- NumSamples); /* Number of samples to process */
-
- /*
- * Call the reverb generator
- */
- err=LVCS_ReverbGenerator(hInstance, /* Instance handle */
- pOutData, /* Pointer to the input data */
- pOutData, /* Pointer to the output data */
- NumSamples); /* Number of samples to process */
-
- /*
- * Call the equaliser
- */
- err=LVCS_Equaliser(hInstance, /* Instance handle */
- pOutData, /* Pointer to the input data */
- NumSamples); /* Number of samples to process */
-
- /*
- * Call the bypass mixer
- */
- err=LVCS_BypassMixer(hInstance, /* Instance handle */
- pOutData, /* Pointer to the processed data */
- pInput, /* Pointer to the input (unprocessed) data */
- pOutData, /* Pointer to the output data */
- NumSamples); /* Number of samples to process */
-
- if(err !=LVCS_SUCCESS)
- {
- return err;
- }
-
- return(LVCS_SUCCESS);
-}
-#endif
-/************************************************************************************/
-/* */
-/* FUNCTION: LVCS_Process */
-/* */
-/* DESCRIPTION: */
-/* Process function for the Concert Sound module. The implementation supports two */
-/* variants of the algorithm, one for headphones and one for mobile speakers. */
-/* */
-/* Data can be processed in two formats, stereo or mono-in-stereo. Data in mono */
-/* format is not supported, the calling routine must convert the mono stream to */
-/* mono-in-stereo. */
-/* */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance handle */
-/* pInData Pointer to the input data */
-/* pOutData Pointer to the output data */
-/* NumSamples Number of samples in the input buffer */
-/* */
-/* RETURNS: */
-/* LVCS_Success Succeeded */
-/* LVCS_TooManySamples NumSamples was larger than the maximum block size */
-/* */
-/* NOTES: */
-/* */
-/************************************************************************************/
-#ifdef BUILD_FLOAT
-LVCS_ReturnStatus_en LVCS_Process(LVCS_Handle_t hInstance,
- const LVM_FLOAT *pInData,
- LVM_FLOAT *pOutData,
- LVM_UINT16 NumSamples)
-{
-
- LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
- LVCS_ReturnStatus_en err;
-#ifdef SUPPORT_MC
- /*Extract number of Channels info*/
- LVM_INT32 channels = pInstance->Params.NrChannels;
-#define NrFrames NumSamples // alias for clarity
- if (channels == 1)
- {
- channels = 2;
- }
-#endif
- /*
- * Check the number of samples is not too large
- */
- if (NumSamples > pInstance->Capabilities.MaxBlockSize)
- {
- return(LVCS_TOOMANYSAMPLES);
- }
-
- /*
- * Check if the algorithm is enabled
- */
- if (pInstance->Params.OperatingMode != LVCS_OFF)
- {
- /*
- * Call CS process function
- */
- err = LVCS_Process_CS(hInstance,
- pInData,
- pOutData,
- NumSamples);
-
-
- /*
- * Compress to reduce expansion effect of Concert Sound and correct volume
- * differences for difference settings. Not applied in test modes
- */
- if ((pInstance->Params.OperatingMode == LVCS_ON)&& \
- (pInstance->Params.CompressorMode == LVM_MODE_ON))
- {
- LVM_FLOAT Gain = pInstance->VolCorrect.CompMin;
- LVM_FLOAT Current1;
-
- Current1 = LVC_Mixer_GetCurrent(&pInstance->BypassMix.Mixer_Instance.MixerStream[0]);
- Gain = (LVM_FLOAT)( pInstance->VolCorrect.CompMin
- - (((LVM_FLOAT)pInstance->VolCorrect.CompMin * (Current1)))
- + (((LVM_FLOAT)pInstance->VolCorrect.CompFull * (Current1))));
-
- if(NumSamples < LVCS_COMPGAINFRAME)
- {
- NonLinComp_Float(Gain, /* Compressor gain setting */
- pOutData,
- pOutData,
- (LVM_INT32)(2 * NumSamples));
- }
- else
- {
- LVM_FLOAT GainStep;
- LVM_FLOAT FinalGain;
- LVM_INT16 SampleToProcess = NumSamples;
- LVM_FLOAT *pOutPtr;
-
- /* Large changes in Gain can cause clicks in output
- Split data into small blocks and use interpolated gain values */
-
- GainStep = (LVM_FLOAT)(((Gain-pInstance->CompressGain) * \
- LVCS_COMPGAINFRAME) / NumSamples);
-
- if((GainStep == 0) && (pInstance->CompressGain < Gain))
- {
- GainStep = 1;
- }
- else
- {
- if((GainStep == 0) && (pInstance->CompressGain > Gain))
- {
- GainStep = -1;
- }
- }
-
- FinalGain = Gain;
- Gain = pInstance->CompressGain;
- pOutPtr = pOutData;
-
- while(SampleToProcess > 0)
- {
- Gain = (LVM_FLOAT)(Gain + GainStep);
- if((GainStep > 0) && (FinalGain <= Gain))
- {
- Gain = FinalGain;
- GainStep = 0;
- }
-
- if((GainStep < 0) && (FinalGain > Gain))
- {
- Gain = FinalGain;
- GainStep = 0;
- }
-
- if(SampleToProcess > LVCS_COMPGAINFRAME)
- {
- NonLinComp_Float(Gain, /* Compressor gain setting */
- pOutPtr,
- pOutPtr,
- (LVM_INT32)(2 * LVCS_COMPGAINFRAME));
- pOutPtr += (2 * LVCS_COMPGAINFRAME);
- SampleToProcess = (LVM_INT16)(SampleToProcess - LVCS_COMPGAINFRAME);
- }
- else
- {
- NonLinComp_Float(Gain, /* Compressor gain setting */
- pOutPtr,
- pOutPtr,
- (LVM_INT32)(2 * SampleToProcess));
- SampleToProcess = 0;
- }
-
- }
- }
-
- /* Store gain value*/
- pInstance->CompressGain = Gain;
- }
-
-
- if(pInstance->bInOperatingModeTransition == LVM_TRUE){
-
- /*
- * Re-init bypass mix when timer has completed
- */
- if ((pInstance->bTimerDone == LVM_TRUE) &&
- (pInstance->BypassMix.Mixer_Instance.MixerStream[1].CallbackSet == 0))
- {
- err = LVCS_BypassMixInit(hInstance,
- &pInstance->Params);
-
- if(err != LVCS_SUCCESS)
- {
- return err;
- }
-
- }
- else{
- LVM_Timer ( &pInstance->TimerInstance,
- (LVM_INT16)NumSamples);
- }
- }
-#ifdef SUPPORT_MC
- Copy_Float_Stereo_Mc(pInData,
- pOutData,
- NrFrames,
- channels);
-#endif
- }
- else
- {
- if (pInData != pOutData)
- {
-#ifdef SUPPORT_MC
- /*
- * The algorithm is disabled so just copy the data
- */
- Copy_Float((LVM_FLOAT *)pInData, /* Source */
- (LVM_FLOAT *)pOutData, /* Destination */
- (LVM_INT16)(channels * NrFrames)); /* All Channels*/
-#else
- /*
- * The algorithm is disabled so just copy the data
- */
- Copy_Float((LVM_FLOAT *)pInData, /* Source */
- (LVM_FLOAT *)pOutData, /* Destination */
- (LVM_INT16)(2 * NumSamples)); /* Left and right */
-#endif
- }
- }
-
-
- return(LVCS_SUCCESS);
-}
-#else
-LVCS_ReturnStatus_en LVCS_Process(LVCS_Handle_t hInstance,
- const LVM_INT16 *pInData,
- LVM_INT16 *pOutData,
- LVM_UINT16 NumSamples)
-{
-
- LVCS_Instance_t *pInstance =(LVCS_Instance_t *)hInstance;
- LVCS_ReturnStatus_en err;
-
- /*
- * Check the number of samples is not too large
- */
- if (NumSamples > pInstance->Capabilities.MaxBlockSize)
- {
- return(LVCS_TOOMANYSAMPLES);
- }
-
- /*
- * Check if the algorithm is enabled
- */
- if (pInstance->Params.OperatingMode != LVCS_OFF)
- {
- /*
- * Call CS process function
- */
- err=LVCS_Process_CS(hInstance,
- pInData,
- pOutData,
- NumSamples);
-
- /*
- * Compress to reduce expansion effect of Concert Sound and correct volume
- * differences for difference settings. Not applied in test modes
- */
- if ((pInstance->Params.OperatingMode == LVCS_ON)&&(pInstance->Params.CompressorMode == LVM_MODE_ON))
- {
- LVM_INT16 Gain = pInstance->VolCorrect.CompMin;
- LVM_INT32 Current1;
-
- Current1 = LVC_Mixer_GetCurrent(&pInstance->BypassMix.Mixer_Instance.MixerStream[0]);
- Gain = (LVM_INT16)( pInstance->VolCorrect.CompMin
- - (((LVM_INT32)pInstance->VolCorrect.CompMin * (Current1)) >> 15)
- + (((LVM_INT32)pInstance->VolCorrect.CompFull * (Current1)) >> 15) );
-
- if(NumSamples < LVCS_COMPGAINFRAME)
- {
- NonLinComp_D16(Gain, /* Compressor gain setting */
- pOutData,
- pOutData,
- (LVM_INT32)(2*NumSamples));
- }
- else
- {
- LVM_INT16 GainStep;
- LVM_INT16 FinalGain;
- LVM_INT16 SampleToProcess = NumSamples;
- LVM_INT16 *pOutPtr;
-
- /* Large changes in Gain can cause clicks in output
- Split data into small blocks and use interpolated gain values */
-
- GainStep = (LVM_INT16)(((Gain-pInstance->CompressGain) * LVCS_COMPGAINFRAME)/NumSamples);
-
- if((GainStep ==0)&&(pInstance->CompressGain < Gain))
- {
- GainStep=1;
- }
- else
- {
- if((GainStep ==0)&&(pInstance->CompressGain > Gain))
- {
- GainStep=-1;
- }
- }
-
- FinalGain = Gain;
- Gain = pInstance->CompressGain;
- pOutPtr = pOutData;
-
- while(SampleToProcess > 0)
- {
- Gain = (LVM_INT16)(Gain + GainStep);
- if((GainStep > 0)&& (FinalGain <= Gain))
- {
- Gain = FinalGain;
- GainStep =0;
- }
-
- if((GainStep < 0)&& (FinalGain > Gain))
- {
- Gain = FinalGain;
- GainStep =0;
- }
-
- if(SampleToProcess > LVCS_COMPGAINFRAME)
- {
- NonLinComp_D16(Gain, /* Compressor gain setting */
- pOutPtr,
- pOutPtr,
- (LVM_INT32)(2*LVCS_COMPGAINFRAME));
- pOutPtr +=(2*LVCS_COMPGAINFRAME);
- SampleToProcess = (LVM_INT16)(SampleToProcess-LVCS_COMPGAINFRAME);
- }
- else
- {
- NonLinComp_D16(Gain, /* Compressor gain setting */
- pOutPtr,
- pOutPtr,
- (LVM_INT32)(2*SampleToProcess));
-
- SampleToProcess = 0;
- }
-
- }
- }
-
- /* Store gain value*/
- pInstance->CompressGain = Gain;
- }
-
-
- if(pInstance->bInOperatingModeTransition == LVM_TRUE){
-
- /*
- * Re-init bypass mix when timer has completed
- */
- if ((pInstance->bTimerDone == LVM_TRUE) &&
- (pInstance->BypassMix.Mixer_Instance.MixerStream[1].CallbackSet == 0))
- {
- err=LVCS_BypassMixInit(hInstance,
- &pInstance->Params);
-
- if(err != LVCS_SUCCESS)
- {
- return err;
- }
-
- }
- else{
- LVM_Timer ( &pInstance->TimerInstance,
- (LVM_INT16)NumSamples);
- }
- }
- }
- else
- {
- if (pInData != pOutData)
- {
- /*
- * The algorithm is disabled so just copy the data
- */
- Copy_16((LVM_INT16 *)pInData, /* Source */
- (LVM_INT16 *)pOutData, /* Destination */
- (LVM_INT16)(2*NumSamples)); /* Left and right */
- }
- }
-
-
- return(LVCS_SUCCESS);
-}
-#endif
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Process.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Process.cpp
new file mode 100644
index 0000000..8e09be2
--- /dev/null
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Process.cpp
@@ -0,0 +1,430 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/************************************************************************************/
+/* */
+/* Includes */
+/* */
+/************************************************************************************/
+
+#include "LVCS.h"
+#include "LVCS_Private.h"
+#include "VectorArithmetic.h"
+#include "CompLim.h"
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVCS_Process_CS */
+/* */
+/* DESCRIPTION: */
+/* Process function for the Concert Sound module based on the following block */
+/* diagram: */
+/* _________ ________ _____ _______ ___ ______ */
+/* | | | | | | | | | | | | */
+/* ----->| Stereo |->| Reverb |->| Equ |->| Alpha |-->| + |-| Gain |----> */
+/* | | Enhance | |________| |_____| |_______| |___| |______| */
+/* | |_________| | */
+/* | ___________ | */
+/* | | | | */
+/* |------------------------------->| 1 - Alpha |-----| */
+/* |___________| */
+/* */
+/* The Stereo Enhancer, Reverb and Equaliser blocks are each configured to have */
+/* their gain to give a near peak to peak output (-0.1dBFS) with a worst case */
+/* input signal. The gains of these blocks are re-combined in the Alpha mixer and */
+/* the gain block folloing the sum. */
+/* */
+/* The processing uses the output buffer for data storage after each processing */
+/* block. When processing is inplace a copy of the input signal is made in scratch */
+/* memory for the 1-Alpha path. */
+/* */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance handle */
+/* pInData Pointer to the input data */
+/* pOutData Pointer to the output data */
+/* NumSamples Number of samples in the input buffer */
+/* */
+/* RETURNS: */
+/* LVCS_Success Succeeded */
+/* */
+/* NOTES: */
+/* */
+/************************************************************************************/
+LVCS_ReturnStatus_en LVCS_Process_CS(LVCS_Handle_t hInstance,
+ const LVM_FLOAT *pInData,
+ LVM_FLOAT *pOutData,
+ LVM_UINT16 NumSamples)
+{
+ const LVM_FLOAT *pInput;
+ LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
+ LVM_FLOAT *pScratch;
+ LVCS_ReturnStatus_en err;
+#ifdef SUPPORT_MC
+ LVM_FLOAT *pStIn;
+ LVM_INT32 channels = pInstance->Params.NrChannels;
+#define NrFrames NumSamples // alias for clarity
+
+ /*In case of mono processing, stereo input is created from mono
+ *and stored in pInData before applying any of the effects.
+ *However we do not update the value pInstance->Params.NrChannels
+ *at this point.
+ *So to treat the pInData as stereo we are setting channels to 2
+ */
+ if (channels == 1)
+ {
+ channels = 2;
+ }
+#endif
+
+ pScratch = (LVM_FLOAT *) \
+ pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
+
+ /*
+ * Check if the processing is inplace
+ */
+#ifdef SUPPORT_MC
+ /*
+ * The pInput buffer holds the first 2 (Left, Right) channels information.
+ * Hence the memory required by this buffer is 2 * NumFrames.
+ * The Concert Surround module carries out processing only on L, R.
+ */
+ pInput = pScratch + (2 * NrFrames);
+ pStIn = pScratch + ((LVCS_SCRATCHBUFFERS - 2) * NrFrames);
+ /* The first two channel data is extracted from the input data and
+ * copied into pInput buffer
+ */
+ Copy_Float_Mc_Stereo((LVM_FLOAT *)pInData,
+ (LVM_FLOAT *)pInput,
+ NrFrames,
+ channels);
+ Copy_Float((LVM_FLOAT *)pInput,
+ (LVM_FLOAT *)pStIn,
+ (LVM_INT16)(2 * NrFrames));
+#else
+ if (pInData == pOutData)
+ {
+ /* Processing inplace */
+ pInput = pScratch + (2 * NumSamples);
+ Copy_Float((LVM_FLOAT *)pInData, /* Source */
+ (LVM_FLOAT *)pInput, /* Destination */
+ (LVM_INT16)(2 * NumSamples)); /* Left and right */
+ }
+ else
+ {
+ /* Processing outplace */
+ pInput = pInData;
+ }
+#endif
+ /*
+ * Call the stereo enhancer
+ */
+#ifdef SUPPORT_MC
+ err = LVCS_StereoEnhancer(hInstance, /* Instance handle */
+ pStIn, /* Pointer to the input data */
+ pOutData, /* Pointer to the output data */
+ NrFrames); /* Number of frames to process */
+#else
+ err = LVCS_StereoEnhancer(hInstance, /* Instance handle */
+ pInData, /* Pointer to the input data */
+ pOutData, /* Pointer to the output data */
+ NumSamples); /* Number of samples to process */
+#endif
+
+ /*
+ * Call the reverb generator
+ */
+ err = LVCS_ReverbGenerator(hInstance, /* Instance handle */
+ pOutData, /* Pointer to the input data */
+ pOutData, /* Pointer to the output data */
+ NumSamples); /* Number of samples to process */
+
+ /*
+ * Call the equaliser
+ */
+ err = LVCS_Equaliser(hInstance, /* Instance handle */
+ pOutData, /* Pointer to the input data */
+ NumSamples); /* Number of samples to process */
+
+ /*
+ * Call the bypass mixer
+ */
+ err = LVCS_BypassMixer(hInstance, /* Instance handle */
+ pOutData, /* Pointer to the processed data */
+ pInput, /* Pointer to the input (unprocessed) data */
+ pOutData, /* Pointer to the output data */
+ NumSamples); /* Number of samples to process */
+
+ if(err != LVCS_SUCCESS)
+ {
+ return err;
+ }
+
+ return(LVCS_SUCCESS);
+}
+/************************************************************************************/
+/* */
+/* FUNCTION: LVCS_Process */
+/* */
+/* DESCRIPTION: */
+/* Process function for the Concert Sound module. The implementation supports two */
+/* variants of the algorithm, one for headphones and one for mobile speakers. */
+/* */
+/* Data can be processed in two formats, stereo or mono-in-stereo. Data in mono */
+/* format is not supported, the calling routine must convert the mono stream to */
+/* mono-in-stereo. */
+/* */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance handle */
+/* pInData Pointer to the input data */
+/* pOutData Pointer to the output data */
+/* NumSamples Number of samples in the input buffer */
+/* */
+/* RETURNS: */
+/* LVCS_Success Succeeded */
+/* LVCS_TooManySamples NumSamples was larger than the maximum block size */
+/* */
+/* NOTES: */
+/* */
+/************************************************************************************/
+LVCS_ReturnStatus_en LVCS_Process(LVCS_Handle_t hInstance,
+ const LVM_FLOAT *pInData,
+ LVM_FLOAT *pOutData,
+ LVM_UINT16 NumSamples)
+{
+
+ LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
+ LVCS_ReturnStatus_en err;
+#ifdef SUPPORT_MC
+ /*Extract number of Channels info*/
+ LVM_INT32 channels = pInstance->Params.NrChannels;
+#define NrFrames NumSamples // alias for clarity
+ if (channels == 1)
+ {
+ channels = 2;
+ }
+#endif
+ /*
+ * Check the number of samples is not too large
+ */
+ if (NumSamples > pInstance->Capabilities.MaxBlockSize)
+ {
+ return(LVCS_TOOMANYSAMPLES);
+ }
+
+ /*
+ * Check if the algorithm is enabled
+ */
+ if (pInstance->Params.OperatingMode != LVCS_OFF)
+ {
+#ifdef SUPPORT_MC
+ LVM_FLOAT *pStereoOut;
+ /*
+ * LVCS_Process_CS uses output buffer to store intermediate outputs of StereoEnhancer,
+ * Equalizer, ReverbGenerator and BypassMixer.
+ * So, to avoid i/o data overlapping, when i/o buffers are common, use scratch buffer
+ * to store intermediate outputs.
+ */
+ if (pOutData == pInData)
+ {
+ /*
+ * Scratch memory is used in 4 chunks of (2 * NrFrames) size.
+ * First chunk of memory is used by LVCS_StereoEnhancer and LVCS_ReverbGenerator,
+ * second and fourth are used as input buffers by pInput and pStIn in LVCS_Process_CS.
+ * Hence, pStereoOut is pointed to use unused third portion of scratch memory.
+ */
+ pStereoOut = (LVM_FLOAT *) \
+ pInstance->MemoryTable. \
+ Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress +
+ ((LVCS_SCRATCHBUFFERS - 4) * NrFrames);
+ }
+ else
+ {
+ pStereoOut = pOutData;
+ }
+
+ /*
+ * Call CS process function
+ */
+ err = LVCS_Process_CS(hInstance,
+ pInData,
+ pStereoOut,
+ NrFrames);
+#else
+ err = LVCS_Process_CS(hInstance,
+ pInData,
+ pOutData,
+ NumSamples);
+#endif
+
+ /*
+ * Compress to reduce expansion effect of Concert Sound and correct volume
+ * differences for difference settings. Not applied in test modes
+ */
+ if ((pInstance->Params.OperatingMode == LVCS_ON)&& \
+ (pInstance->Params.CompressorMode == LVM_MODE_ON))
+ {
+ LVM_FLOAT Gain = pInstance->VolCorrect.CompMin;
+ LVM_FLOAT Current1;
+
+ Current1 = LVC_Mixer_GetCurrent(&pInstance->BypassMix.Mixer_Instance.MixerStream[0]);
+ Gain = (LVM_FLOAT)( pInstance->VolCorrect.CompMin
+ - (((LVM_FLOAT)pInstance->VolCorrect.CompMin * (Current1)))
+ + (((LVM_FLOAT)pInstance->VolCorrect.CompFull * (Current1))));
+
+ if(NumSamples < LVCS_COMPGAINFRAME)
+ {
+#ifdef SUPPORT_MC
+ NonLinComp_Float(Gain, /* Compressor gain setting */
+ pStereoOut,
+ pStereoOut,
+ (LVM_INT32)(2 * NrFrames));
+#else
+ NonLinComp_Float(Gain, /* Compressor gain setting */
+ pOutData,
+ pOutData,
+ (LVM_INT32)(2 * NumSamples));
+#endif
+ }
+ else
+ {
+ LVM_FLOAT GainStep;
+ LVM_FLOAT FinalGain;
+ LVM_INT16 SampleToProcess = NumSamples;
+ LVM_FLOAT *pOutPtr;
+
+ /* Large changes in Gain can cause clicks in output
+ Split data into small blocks and use interpolated gain values */
+
+ GainStep = (LVM_FLOAT)(((Gain-pInstance->CompressGain) * \
+ LVCS_COMPGAINFRAME) / NumSamples);
+
+ if((GainStep == 0) && (pInstance->CompressGain < Gain))
+ {
+ GainStep = 1;
+ }
+ else
+ {
+ if((GainStep == 0) && (pInstance->CompressGain > Gain))
+ {
+ GainStep = -1;
+ }
+ }
+
+ FinalGain = Gain;
+ Gain = pInstance->CompressGain;
+#ifdef SUPPORT_MC
+ pOutPtr = pStereoOut;
+#else
+ pOutPtr = pOutData;
+#endif
+
+ while(SampleToProcess > 0)
+ {
+ Gain = (LVM_FLOAT)(Gain + GainStep);
+ if((GainStep > 0) && (FinalGain <= Gain))
+ {
+ Gain = FinalGain;
+ GainStep = 0;
+ }
+
+ if((GainStep < 0) && (FinalGain > Gain))
+ {
+ Gain = FinalGain;
+ GainStep = 0;
+ }
+
+ if(SampleToProcess > LVCS_COMPGAINFRAME)
+ {
+ NonLinComp_Float(Gain, /* Compressor gain setting */
+ pOutPtr,
+ pOutPtr,
+ (LVM_INT32)(2 * LVCS_COMPGAINFRAME));
+ pOutPtr += (2 * LVCS_COMPGAINFRAME);
+ SampleToProcess = (LVM_INT16)(SampleToProcess - LVCS_COMPGAINFRAME);
+ }
+ else
+ {
+ NonLinComp_Float(Gain, /* Compressor gain setting */
+ pOutPtr,
+ pOutPtr,
+ (LVM_INT32)(2 * SampleToProcess));
+ SampleToProcess = 0;
+ }
+
+ }
+ }
+
+ /* Store gain value*/
+ pInstance->CompressGain = Gain;
+ }
+
+ if(pInstance->bInOperatingModeTransition == LVM_TRUE){
+
+ /*
+ * Re-init bypass mix when timer has completed
+ */
+ if ((pInstance->bTimerDone == LVM_TRUE) &&
+ (pInstance->BypassMix.Mixer_Instance.MixerStream[1].CallbackSet == 0))
+ {
+ err = LVCS_BypassMixInit(hInstance,
+ &pInstance->Params);
+
+ if(err != LVCS_SUCCESS)
+ {
+ return err;
+ }
+
+ }
+ else{
+ LVM_Timer ( &pInstance->TimerInstance,
+ (LVM_INT16)NumSamples);
+ }
+ }
+#ifdef SUPPORT_MC
+ Copy_Float_Stereo_Mc(pInData,
+ pStereoOut,
+ pOutData,
+ NrFrames,
+ channels);
+#endif
+ }
+ else
+ {
+ if (pInData != pOutData)
+ {
+#ifdef SUPPORT_MC
+ /*
+ * The algorithm is disabled so just copy the data
+ */
+ Copy_Float((LVM_FLOAT *)pInData, /* Source */
+ (LVM_FLOAT *)pOutData, /* Destination */
+ (LVM_INT16)(channels * NrFrames)); /* All Channels*/
+#else
+ /*
+ * The algorithm is disabled so just copy the data
+ */
+ Copy_Float((LVM_FLOAT *)pInData, /* Source */
+ (LVM_FLOAT *)pOutData, /* Destination */
+ (LVM_INT16)(2 * NumSamples)); /* Left and right */
+#endif
+ }
+ }
+
+ return(LVCS_SUCCESS);
+}
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.c b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.c
deleted file mode 100644
index 1085101..0000000
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.c
+++ /dev/null
@@ -1,435 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/************************************************************************************/
-/* */
-/* Includes */
-/* */
-/************************************************************************************/
-
-#include "LVCS.h"
-#include "LVCS_Private.h"
-#include "LVCS_ReverbGenerator.h"
-#include "LVC_Mixer.h"
-#include "VectorArithmetic.h"
-#include "BIQUAD.h"
-#include "LVCS_Tables.h"
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVCS_ReverbGeneratorInit */
-/* */
-/* DESCRIPTION: */
-/* Initialises the reverb module. The delay buffer size is configured for the */
-/* sample rate and the speaker type. */
-/* */
-/* The routine may also be called for re-initialisation, i.e. when one of the */
-/* control parameters has changed. In this case the delay and filters are only */
-/* re-initialised if one of the following two conditions is met: */
-/* - the sample rate has changed */
-/* - the speaker type changes to/from the mobile speaker */
-/* */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance Handle */
-/* pParams Pointer to the inialisation parameters */
-/* */
-/* RETURNS: */
-/* LVCS_Success Always succeeds */
-/* */
-/* NOTES: */
-/* 1. In the delay settings 'Samples' is the number of samples to the end of the */
-/* buffer. */
-/* 2. The numerator coefficients of the filter are negated to cause an inversion. */
-/* */
-/************************************************************************************/
-#ifdef BUILD_FLOAT
-LVCS_ReturnStatus_en LVCS_ReverbGeneratorInit(LVCS_Handle_t hInstance,
- LVCS_Params_t *pParams)
-{
-
- LVM_UINT16 Delay;
- LVM_UINT16 Offset;
- LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
- LVCS_ReverbGenerator_t *pConfig = (LVCS_ReverbGenerator_t *)&pInstance->Reverberation;
- LVCS_Data_t *pData;
- LVCS_Coefficient_t *pCoefficients;
- BQ_FLOAT_Coefs_t Coeffs;
- const BiquadA012B12CoefsSP_t *pReverbCoefTable;
-
-
- pData = (LVCS_Data_t *) \
- pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress;
-
- pCoefficients = (LVCS_Coefficient_t *) \
- pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
-
- /*
- * Initialise the delay and filters if:
- * - the sample rate has changed
- * - the speaker type has changed to or from the mobile speaker
- */
- if(pInstance->Params.SampleRate != pParams->SampleRate ) /* Sample rate change test */
-
- {
- /*
- * Setup the delay
- */
- Delay = (LVM_UINT16)LVCS_StereoDelayCS[(LVM_UINT16)pParams->SampleRate];
-
-
- pConfig->DelaySize = (LVM_INT16)(2 * Delay);
- pConfig->DelayOffset = 0;
- LoadConst_Float(0, /* Value */
- (LVM_FLOAT *)&pConfig->StereoSamples[0], /* Destination */
- /* Number of words */
- (LVM_UINT16)(sizeof(pConfig->StereoSamples) / sizeof(LVM_FLOAT)));
- /*
- * Setup the filters
- */
- Offset = (LVM_UINT16)pParams->SampleRate;
- pReverbCoefTable = (BiquadA012B12CoefsSP_t*)&LVCS_ReverbCoefTable[0];
-
- /* Convert incoming coefficients to the required format/ordering */
- Coeffs.A0 = (LVM_FLOAT)pReverbCoefTable[Offset].A0;
- Coeffs.A1 = (LVM_FLOAT)pReverbCoefTable[Offset].A1;
- Coeffs.A2 = (LVM_FLOAT)pReverbCoefTable[Offset].A2;
- Coeffs.B1 = (LVM_FLOAT)-pReverbCoefTable[Offset].B1;
- Coeffs.B2 = (LVM_FLOAT)-pReverbCoefTable[Offset].B2;
-
- LoadConst_Float(0, /* Value */
- (void *)&pData->ReverbBiquadTaps, /* Destination Cast to void:
- no dereferencing in function*/
- /* Number of words */
- (LVM_UINT16)(sizeof(pData->ReverbBiquadTaps) / sizeof(LVM_FLOAT)));
-
- BQ_2I_D16F16Css_TRC_WRA_01_Init(&pCoefficients->ReverbBiquadInstance,
- &pData->ReverbBiquadTaps,
- &Coeffs);
-
- /* Callbacks */
- switch(pReverbCoefTable[Offset].Scale)
- {
- case 14:
- pConfig->pBiquadCallBack = BQ_2I_D16F16C14_TRC_WRA_01;
- break;
- case 15:
- pConfig->pBiquadCallBack = BQ_2I_D16F16C15_TRC_WRA_01;
- break;
- }
-
-
- /*
- * Setup the mixer
- */
- pConfig->ProcGain = (LVM_UINT16)(HEADPHONEGAINPROC);
- pConfig->UnprocGain = (LVM_UINT16)(HEADPHONEGAINUNPROC);
- }
-
- if(pInstance->Params.ReverbLevel != pParams->ReverbLevel)
- {
- LVM_INT32 ReverbPercentage = 83886; // 1 Percent Reverb i.e 1/100 in Q 23 format
- ReverbPercentage *= pParams->ReverbLevel; // Actual Reverb Level in Q 23 format
- pConfig->ReverbLevel = ((LVM_FLOAT)(ReverbPercentage>>8)) / 32767.0f;
- }
- return(LVCS_SUCCESS);
-}
-#else
-LVCS_ReturnStatus_en LVCS_ReverbGeneratorInit(LVCS_Handle_t hInstance,
- LVCS_Params_t *pParams)
-{
-
- LVM_UINT16 Delay;
- LVM_UINT16 Offset;
- LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
- LVCS_ReverbGenerator_t *pConfig = (LVCS_ReverbGenerator_t *)&pInstance->Reverberation;
- LVCS_Data_t *pData = (LVCS_Data_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress;
- LVCS_Coefficient_t *pCoefficients = (LVCS_Coefficient_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
- BQ_C16_Coefs_t Coeffs;
- const BiquadA012B12CoefsSP_t *pReverbCoefTable;
-
- /*
- * Initialise the delay and filters if:
- * - the sample rate has changed
- * - the speaker type has changed to or from the mobile speaker
- */
- if(pInstance->Params.SampleRate != pParams->SampleRate ) /* Sample rate change test */
-
- {
- /*
- * Setup the delay
- */
- Delay = (LVM_UINT16)LVCS_StereoDelayCS[(LVM_UINT16)pParams->SampleRate];
-
-
- pConfig->DelaySize = (LVM_INT16)(2 * Delay);
- pConfig->DelayOffset = 0;
- LoadConst_16(0, /* Value */
- (LVM_INT16 *)&pConfig->StereoSamples[0], /* Destination */
- (LVM_UINT16)(sizeof(pConfig->StereoSamples)/sizeof(LVM_INT16))); /* Number of words */
-
- /*
- * Setup the filters
- */
- Offset = (LVM_UINT16)pParams->SampleRate;
- pReverbCoefTable = (BiquadA012B12CoefsSP_t*)&LVCS_ReverbCoefTable[0];
-
- /* Convert incoming coefficients to the required format/ordering */
- Coeffs.A0 = (LVM_INT16)pReverbCoefTable[Offset].A0;
- Coeffs.A1 = (LVM_INT16)pReverbCoefTable[Offset].A1;
- Coeffs.A2 = (LVM_INT16)pReverbCoefTable[Offset].A2;
- Coeffs.B1 = (LVM_INT16)-pReverbCoefTable[Offset].B1;
- Coeffs.B2 = (LVM_INT16)-pReverbCoefTable[Offset].B2;
-
- LoadConst_16(0, /* Value */
- (void *)&pData->ReverbBiquadTaps, /* Destination Cast to void: no dereferencing in function*/
- (LVM_UINT16)(sizeof(pData->ReverbBiquadTaps)/sizeof(LVM_INT16))); /* Number of words */
-
- BQ_2I_D16F16Css_TRC_WRA_01_Init(&pCoefficients->ReverbBiquadInstance,
- &pData->ReverbBiquadTaps,
- &Coeffs);
-
- /* Callbacks */
- switch(pReverbCoefTable[Offset].Scale)
- {
- case 14:
- pConfig->pBiquadCallBack = BQ_2I_D16F16C14_TRC_WRA_01;
- break;
- case 15:
- pConfig->pBiquadCallBack = BQ_2I_D16F16C15_TRC_WRA_01;
- break;
- }
-
-
- /*
- * Setup the mixer
- */
- pConfig->ProcGain = (LVM_UINT16)(HEADPHONEGAINPROC);
- pConfig->UnprocGain = (LVM_UINT16)(HEADPHONEGAINUNPROC);
- }
-
- if(pInstance->Params.ReverbLevel != pParams->ReverbLevel)
- {
- LVM_INT32 ReverbPercentage=83886; // 1 Percent Reverb i.e 1/100 in Q 23 format
- ReverbPercentage*=pParams->ReverbLevel; // Actual Reverb Level in Q 23 format
- pConfig->ReverbLevel=(LVM_INT16)(ReverbPercentage>>8); // Reverb Level in Q 15 format
- }
-
- return(LVCS_SUCCESS);
-}
-#endif
-/************************************************************************************/
-/* */
-/* FUNCTION: LVCS_Reverb */
-/* */
-/* DESCRIPTION: */
-/* Create reverb using the block of input samples based on the following block */
-/* diagram: */
-/* ________ ________ */
-/* | | | | */
-/* _____ _______ | |----------->| | ______ ___ */
-/* | | | | | Stereo | | L & R | | | | | */
-/* -->| LPF |-->| Delay |-->| to | ____ | to |-->| Gain |-->| + |--> */
-/* | |_____| |_______| | L & R | | | | Stereo | |______| |___| */
-/* | | |-->| -1 |-->| | | */
-/* | |________| |____| |________| | */
-/* | | */
-/* |-----------------------------------------------------------------------| */
-/* */
-/* The input buffer is broken in to sub-blocks of the size of the delay or less. */
-/* This allows the delay buffer to be treated as a circular buffer but processed */
-/* as a linear buffer. */
-/* */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance Handle */
-/* pInData Pointer to the input buffer */
-/* pOutData Pointer to the output buffer */
-/* NumSamples Number of samples to process */
-/* */
-/* RETURNS: */
-/* LVCS_Success Always succeeds */
-/* */
-/* NOTES: */
-/* 1. Process in blocks of samples the size of the delay where possible, if not */
-/* the number of samples left over */
-/* 2. The Gain is combined with the LPF and incorporated in to the coefficients */
-/* */
-/************************************************************************************/
-#ifdef BUILD_FLOAT
-LVCS_ReturnStatus_en LVCS_ReverbGenerator(LVCS_Handle_t hInstance,
- const LVM_FLOAT *pInData,
- LVM_FLOAT *pOutData,
- LVM_UINT16 NumSamples)
-{
-
- LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
- LVCS_ReverbGenerator_t *pConfig = (LVCS_ReverbGenerator_t *)&pInstance->Reverberation;
- LVCS_Coefficient_t *pCoefficients;
- LVM_FLOAT *pScratch;
-
- pCoefficients = (LVCS_Coefficient_t *)\
- pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
-
- pScratch = (LVM_FLOAT *)\
- pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
-
- /*
- * Copy the data to the output in outplace processing
- */
- if (pInData != pOutData)
- {
- /*
- * Reverb not required so just copy the data
- */
- Copy_Float((LVM_FLOAT *)pInData, /* Source */
- (LVM_FLOAT *)pOutData, /* Destination */
- (LVM_INT16)(2 * NumSamples)); /* Left and right */
- }
-
-
- /*
- * Check if the reverb is required
- */
- /* Disable when CS4MS in stereo mode */
- if (((pInstance->Params.SpeakerType == LVCS_HEADPHONE) || \
- (pInstance->Params.SpeakerType == LVCS_EX_HEADPHONES) ||
- (pInstance->Params.SourceFormat != LVCS_STEREO)) &&
- /* For validation testing */
- ((pInstance->Params.OperatingMode & LVCS_REVERBSWITCH) !=0))
- {
- /********************************************************************************/
- /* */
- /* Copy the input data to scratch memory and filter it */
- /* */
- /********************************************************************************/
-
- /*
- * Copy the input data to the scratch memory
- */
- Copy_Float((LVM_FLOAT *)pInData, /* Source */
- (LVM_FLOAT *)pScratch, /* Destination */
- (LVM_INT16)(2 * NumSamples)); /* Left and right */
-
- /*
- * Filter the data
- */
- (pConfig->pBiquadCallBack)((Biquad_FLOAT_Instance_t*)&pCoefficients->ReverbBiquadInstance,
- (LVM_FLOAT *)pScratch,
- (LVM_FLOAT *)pScratch,
- (LVM_INT16)NumSamples);
-
- Mult3s_Float( (LVM_FLOAT *)pScratch,
- pConfig->ReverbLevel,
- (LVM_FLOAT *)pScratch,
- (LVM_INT16)(2 * NumSamples));
-
-
- /*
- * Apply the delay mix
- */
- DelayMix_Float((LVM_FLOAT *)pScratch,
- &pConfig->StereoSamples[0],
- pConfig->DelaySize,
- pOutData,
- &pConfig->DelayOffset,
- (LVM_INT16)NumSamples);
-
-
- }
-
- return(LVCS_SUCCESS);
-}
-#else
-LVCS_ReturnStatus_en LVCS_ReverbGenerator(LVCS_Handle_t hInstance,
- const LVM_INT16 *pInData,
- LVM_INT16 *pOutData,
- LVM_UINT16 NumSamples)
-{
-
- LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
- LVCS_ReverbGenerator_t *pConfig = (LVCS_ReverbGenerator_t *)&pInstance->Reverberation;
- LVCS_Coefficient_t *pCoefficients = (LVCS_Coefficient_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
- LVM_INT16 *pScratch = (LVM_INT16 *)pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
-
-
- /*
- * Copy the data to the output in outplace processing
- */
- if (pInData != pOutData)
- {
- /*
- * Reverb not required so just copy the data
- */
- Copy_16((LVM_INT16 *)pInData, /* Source */
- (LVM_INT16 *)pOutData, /* Destination */
- (LVM_INT16)(2*NumSamples)); /* Left and right */
- }
-
-
- /*
- * Check if the reverb is required
- */
- if (((pInstance->Params.SpeakerType == LVCS_HEADPHONE) || /* Disable when CS4MS in stereo mode */
- (pInstance->Params.SpeakerType == LVCS_EX_HEADPHONES) ||
- (pInstance->Params.SourceFormat != LVCS_STEREO)) &&
- ((pInstance->Params.OperatingMode & LVCS_REVERBSWITCH) !=0)) /* For validation testing */
- {
- /********************************************************************************/
- /* */
- /* Copy the input data to scratch memory and filter it */
- /* */
- /********************************************************************************/
-
- /*
- * Copy the input data to the scratch memory
- */
- Copy_16((LVM_INT16 *)pInData, /* Source */
- (LVM_INT16 *)pScratch, /* Destination */
- (LVM_INT16)(2*NumSamples)); /* Left and right */
-
-
- /*
- * Filter the data
- */
- (pConfig->pBiquadCallBack)((Biquad_Instance_t*)&pCoefficients->ReverbBiquadInstance,
- (LVM_INT16 *)pScratch,
- (LVM_INT16 *)pScratch,
- (LVM_INT16)NumSamples);
-
- Mult3s_16x16( (LVM_INT16 *)pScratch,
- pConfig->ReverbLevel,
- (LVM_INT16 *)pScratch,
- (LVM_INT16)(2*NumSamples));
-
-
- /*
- * Apply the delay mix
- */
- DelayMix_16x16((LVM_INT16 *)pScratch,
- &pConfig->StereoSamples[0],
- pConfig->DelaySize,
- pOutData,
- &pConfig->DelayOffset,
- (LVM_INT16)NumSamples);
-
-
- }
-
- return(LVCS_SUCCESS);
-}
-#endif
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.cpp
new file mode 100644
index 0000000..d0e6e09
--- /dev/null
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.cpp
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/************************************************************************************/
+/* */
+/* Includes */
+/* */
+/************************************************************************************/
+
+#include "LVCS.h"
+#include "LVCS_Private.h"
+#include "LVCS_ReverbGenerator.h"
+#include "LVC_Mixer.h"
+#include "VectorArithmetic.h"
+#include "BIQUAD.h"
+#include "LVCS_Tables.h"
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVCS_ReverbGeneratorInit */
+/* */
+/* DESCRIPTION: */
+/* Initialises the reverb module. The delay buffer size is configured for the */
+/* sample rate and the speaker type. */
+/* */
+/* The routine may also be called for re-initialisation, i.e. when one of the */
+/* control parameters has changed. In this case the delay and filters are only */
+/* re-initialised if one of the following two conditions is met: */
+/* - the sample rate has changed */
+/* - the speaker type changes to/from the mobile speaker */
+/* */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance Handle */
+/* pParams Pointer to the inialisation parameters */
+/* */
+/* RETURNS: */
+/* LVCS_Success Always succeeds */
+/* */
+/* NOTES: */
+/* 1. In the delay settings 'Samples' is the number of samples to the end of the */
+/* buffer. */
+/* 2. The numerator coefficients of the filter are negated to cause an inversion. */
+/* */
+/************************************************************************************/
+LVCS_ReturnStatus_en LVCS_ReverbGeneratorInit(LVCS_Handle_t hInstance,
+ LVCS_Params_t *pParams)
+{
+
+ LVM_UINT16 Delay;
+ LVM_UINT16 Offset;
+ LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
+ LVCS_ReverbGenerator_t *pConfig = (LVCS_ReverbGenerator_t *)&pInstance->Reverberation;
+ LVCS_Data_t *pData;
+ LVCS_Coefficient_t *pCoefficients;
+ BQ_FLOAT_Coefs_t Coeffs;
+ const BiquadA012B12CoefsSP_t *pReverbCoefTable;
+
+ pData = (LVCS_Data_t *) \
+ pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress;
+
+ pCoefficients = (LVCS_Coefficient_t *) \
+ pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
+
+ /*
+ * Initialise the delay and filters if:
+ * - the sample rate has changed
+ * - the speaker type has changed to or from the mobile speaker
+ */
+ if(pInstance->Params.SampleRate != pParams->SampleRate ) /* Sample rate change test */
+
+ {
+ /*
+ * Setup the delay
+ */
+ Delay = (LVM_UINT16)LVCS_StereoDelayCS[(LVM_UINT16)pParams->SampleRate];
+
+ pConfig->DelaySize = (LVM_INT16)(2 * Delay);
+ pConfig->DelayOffset = 0;
+ LoadConst_Float(0, /* Value */
+ (LVM_FLOAT *)&pConfig->StereoSamples[0], /* Destination */
+ /* Number of words */
+ (LVM_UINT16)(sizeof(pConfig->StereoSamples) / sizeof(LVM_FLOAT)));
+ /*
+ * Setup the filters
+ */
+ Offset = (LVM_UINT16)pParams->SampleRate;
+ pReverbCoefTable = (BiquadA012B12CoefsSP_t*)&LVCS_ReverbCoefTable[0];
+
+ /* Convert incoming coefficients to the required format/ordering */
+ Coeffs.A0 = (LVM_FLOAT)pReverbCoefTable[Offset].A0;
+ Coeffs.A1 = (LVM_FLOAT)pReverbCoefTable[Offset].A1;
+ Coeffs.A2 = (LVM_FLOAT)pReverbCoefTable[Offset].A2;
+ Coeffs.B1 = (LVM_FLOAT)-pReverbCoefTable[Offset].B1;
+ Coeffs.B2 = (LVM_FLOAT)-pReverbCoefTable[Offset].B2;
+
+ LoadConst_Float(0, /* Value */
+ (LVM_FLOAT *)&pData->ReverbBiquadTaps, /* Destination */
+ /* Number of words */
+ (LVM_UINT16)(sizeof(pData->ReverbBiquadTaps) / sizeof(LVM_FLOAT)));
+
+ BQ_2I_D16F16Css_TRC_WRA_01_Init(&pCoefficients->ReverbBiquadInstance,
+ &pData->ReverbBiquadTaps,
+ &Coeffs);
+
+ /* Callbacks */
+ switch(pReverbCoefTable[Offset].Scale)
+ {
+ case 14:
+ pConfig->pBiquadCallBack = BQ_2I_D16F16C14_TRC_WRA_01;
+ break;
+ case 15:
+ pConfig->pBiquadCallBack = BQ_2I_D16F16C15_TRC_WRA_01;
+ break;
+ }
+
+ /*
+ * Setup the mixer
+ */
+ pConfig->ProcGain = (LVM_UINT16)(HEADPHONEGAINPROC);
+ pConfig->UnprocGain = (LVM_UINT16)(HEADPHONEGAINUNPROC);
+ }
+
+ if(pInstance->Params.ReverbLevel != pParams->ReverbLevel)
+ {
+ LVM_INT32 ReverbPercentage = 83886; // 1 Percent Reverb i.e 1/100 in Q 23 format
+ ReverbPercentage *= pParams->ReverbLevel; // Actual Reverb Level in Q 23 format
+ pConfig->ReverbLevel = ((LVM_FLOAT)(ReverbPercentage>>8)) / 32767.0f;
+ }
+ return(LVCS_SUCCESS);
+}
+/************************************************************************************/
+/* */
+/* FUNCTION: LVCS_Reverb */
+/* */
+/* DESCRIPTION: */
+/* Create reverb using the block of input samples based on the following block */
+/* diagram: */
+/* ________ ________ */
+/* | | | | */
+/* _____ _______ | |----------->| | ______ ___ */
+/* | | | | | Stereo | | L & R | | | | | */
+/* -->| LPF |-->| Delay |-->| to | ____ | to |-->| Gain |-->| + |--> */
+/* | |_____| |_______| | L & R | | | | Stereo | |______| |___| */
+/* | | |-->| -1 |-->| | | */
+/* | |________| |____| |________| | */
+/* | | */
+/* |-----------------------------------------------------------------------| */
+/* */
+/* The input buffer is broken in to sub-blocks of the size of the delay or less. */
+/* This allows the delay buffer to be treated as a circular buffer but processed */
+/* as a linear buffer. */
+/* */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance Handle */
+/* pInData Pointer to the input buffer */
+/* pOutData Pointer to the output buffer */
+/* NumSamples Number of samples to process */
+/* */
+/* RETURNS: */
+/* LVCS_Success Always succeeds */
+/* */
+/* NOTES: */
+/* 1. Process in blocks of samples the size of the delay where possible, if not */
+/* the number of samples left over */
+/* 2. The Gain is combined with the LPF and incorporated in to the coefficients */
+/* */
+/************************************************************************************/
+LVCS_ReturnStatus_en LVCS_ReverbGenerator(LVCS_Handle_t hInstance,
+ const LVM_FLOAT *pInData,
+ LVM_FLOAT *pOutData,
+ LVM_UINT16 NumSamples)
+{
+
+ LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
+ LVCS_ReverbGenerator_t *pConfig = (LVCS_ReverbGenerator_t *)&pInstance->Reverberation;
+ LVCS_Coefficient_t *pCoefficients;
+ LVM_FLOAT *pScratch;
+
+ pCoefficients = (LVCS_Coefficient_t *)\
+ pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
+
+ pScratch = (LVM_FLOAT *)\
+ pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
+
+ /*
+ * Copy the data to the output in outplace processing
+ */
+ if (pInData != pOutData)
+ {
+ /*
+ * Reverb not required so just copy the data
+ */
+ Copy_Float((LVM_FLOAT *)pInData, /* Source */
+ (LVM_FLOAT *)pOutData, /* Destination */
+ (LVM_INT16)(2 * NumSamples)); /* Left and right */
+ }
+
+ /*
+ * Check if the reverb is required
+ */
+ /* Disable when CS4MS in stereo mode */
+ if ((((LVCS_OutputDevice_en)pInstance->Params.SpeakerType == LVCS_HEADPHONE) || \
+ (pInstance->Params.SpeakerType == LVCS_EX_HEADPHONES) ||
+ (pInstance->Params.SourceFormat != LVCS_STEREO)) &&
+ /* For validation testing */
+ ((pInstance->Params.OperatingMode & LVCS_REVERBSWITCH) !=0))
+ {
+ /********************************************************************************/
+ /* */
+ /* Copy the input data to scratch memory and filter it */
+ /* */
+ /********************************************************************************/
+
+ /*
+ * Copy the input data to the scratch memory
+ */
+ Copy_Float((LVM_FLOAT *)pInData, /* Source */
+ (LVM_FLOAT *)pScratch, /* Destination */
+ (LVM_INT16)(2 * NumSamples)); /* Left and right */
+
+ /*
+ * Filter the data
+ */
+ (pConfig->pBiquadCallBack)((Biquad_FLOAT_Instance_t*)&pCoefficients->ReverbBiquadInstance,
+ (LVM_FLOAT *)pScratch,
+ (LVM_FLOAT *)pScratch,
+ (LVM_INT16)NumSamples);
+
+ Mult3s_Float( (LVM_FLOAT *)pScratch,
+ pConfig->ReverbLevel,
+ (LVM_FLOAT *)pScratch,
+ (LVM_INT16)(2 * NumSamples));
+
+ /*
+ * Apply the delay mix
+ */
+ DelayMix_Float((LVM_FLOAT *)pScratch,
+ &pConfig->StereoSamples[0],
+ pConfig->DelaySize,
+ pOutData,
+ &pConfig->DelayOffset,
+ (LVM_INT16)NumSamples);
+
+ }
+
+ return(LVCS_SUCCESS);
+}
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.h b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.h
index f94d4e4..1bc4338 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.h
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.h
@@ -18,11 +18,6 @@
#ifndef __LVCS_REVERBGENERATOR_H__
#define __LVCS_REVERBGENERATOR_H__
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-
/************************************************************************************/
/* */
/* Includes */
@@ -31,7 +26,6 @@
#include "LVC_Mixer.h"
-
/************************************************************************************/
/* */
/* Defines */
@@ -41,14 +35,12 @@
#define HEADPHONEGAINPROC LVCS_HEADPHONE_PROCGAIN
#define HEADPHONEGAINUNPROC LVCS_HEADPHONE_UNPROCGAIN
-
/************************************************************************************/
/* */
/* Structures */
/* */
/************************************************************************************/
-
/* Reverberation module structure */
typedef struct
{
@@ -58,23 +50,14 @@
LVM_INT16 DelayOffset;
LVM_INT16 ProcGain;
LVM_INT16 UnprocGain;
-#ifndef BUILD_FLOAT
- LVM_INT16 StereoSamples[2*LVCS_STEREODELAY_CS_48KHZ];
- /* Reverb Level */
- LVM_INT16 ReverbLevel;
- /* Filter */
- void (*pBiquadCallBack) (Biquad_Instance_t*, LVM_INT16*, LVM_INT16*, LVM_INT16);
-#else
LVM_FLOAT StereoSamples[2 * LVCS_STEREODELAY_CS_MAX_VAL];
/* Reverb Level */
LVM_FLOAT ReverbLevel;
/* Filter */
void (*pBiquadCallBack) (Biquad_FLOAT_Instance_t*,
LVM_FLOAT*, LVM_FLOAT*, LVM_INT16);
-#endif
} LVCS_ReverbGenerator_t;
-
/************************************************************************************/
/* */
/* Function prototypes */
@@ -83,19 +66,9 @@
LVCS_ReturnStatus_en LVCS_ReverbGeneratorInit(LVCS_Handle_t hInstance,
LVCS_Params_t *pParams);
-#ifdef BUILD_FLOAT
LVCS_ReturnStatus_en LVCS_ReverbGenerator(LVCS_Handle_t hInstance,
const LVM_FLOAT *pInput,
LVM_FLOAT *pOutput,
LVM_UINT16 NumSamples);
-#else
-LVCS_ReturnStatus_en LVCS_ReverbGenerator(LVCS_Handle_t hInstance,
- const LVM_INT16 *pInput,
- LVM_INT16 *pOutput,
- LVM_UINT16 NumSamples);
-#endif
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
#endif /* REVERB_H */
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.c b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.c
deleted file mode 100644
index 2992c35..0000000
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.c
+++ /dev/null
@@ -1,436 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/************************************************************************************/
-/* */
-/* Includes */
-/* */
-/************************************************************************************/
-
-#include "LVCS.h"
-#include "LVCS_Private.h"
-#include "LVCS_StereoEnhancer.h"
-#include "VectorArithmetic.h"
-#include "LVCS_Tables.h"
-
-/************************************************************************************/
-/* */
-/* FUNCTION: LVCS_StereoEnhanceInit */
-/* */
-/* DESCRIPTION: */
-/* Initialises the stereo enhancement module based on the sample rate. */
-/* */
-/* The function selects the coefficients for the filters and clears the data */
-/* history. It is also used for re-initialisation when one of the system control */
-/* parameters changes but will only change the coefficients and clear the history */
-/* if the sample rate or speaker type has changed. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance Handle */
-/* pParams Initialisation parameters */
-/* */
-/* RETURNS: */
-/* LVCS_Success Always succeeds */
-/* */
-/* NOTES: */
-/* */
-/************************************************************************************/
-#ifdef BUILD_FLOAT
-LVCS_ReturnStatus_en LVCS_SEnhancerInit(LVCS_Handle_t hInstance,
- LVCS_Params_t *pParams)
-{
-
- LVM_UINT16 Offset;
- LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
- LVCS_StereoEnhancer_t *pConfig = (LVCS_StereoEnhancer_t *)&pInstance->StereoEnhancer;
- LVCS_Data_t *pData;
- LVCS_Coefficient_t *pCoefficient;
- FO_FLOAT_Coefs_t CoeffsMid;
- BQ_FLOAT_Coefs_t CoeffsSide;
- const BiquadA012B12CoefsSP_t *pSESideCoefs;
-
-
- pData = (LVCS_Data_t *) \
- pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress;
-
- pCoefficient = (LVCS_Coefficient_t *) \
- pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
-
- /*
- * If the sample rate or speaker type has changed update the filters
- */
- if ((pInstance->Params.SampleRate != pParams->SampleRate) ||
- (pInstance->Params.SpeakerType != pParams->SpeakerType))
- {
- /*
- * Set the filter coefficients based on the sample rate
- */
- /* Mid filter */
- Offset = (LVM_UINT16)pParams->SampleRate;
-
- /* Convert incoming coefficients to the required format/ordering */
- CoeffsMid.A0 = (LVM_FLOAT) LVCS_SEMidCoefTable[Offset].A0;
- CoeffsMid.A1 = (LVM_FLOAT) LVCS_SEMidCoefTable[Offset].A1;
- CoeffsMid.B1 = (LVM_FLOAT)-LVCS_SEMidCoefTable[Offset].B1;
-
- /* Clear the taps */
- LoadConst_Float(0, /* Value */
- (void *)&pData->SEBiquadTapsMid, /* Destination Cast to void:\
- no dereferencing in function*/
- /* Number of words */
- (LVM_UINT16)(sizeof(pData->SEBiquadTapsMid) / sizeof(LVM_FLOAT)));
-
- FO_1I_D16F16Css_TRC_WRA_01_Init(&pCoefficient->SEBiquadInstanceMid,
- &pData->SEBiquadTapsMid,
- &CoeffsMid);
-
- /* Callbacks */
- if(LVCS_SEMidCoefTable[Offset].Scale == 15)
- {
- pConfig->pBiquadCallBack_Mid = FO_1I_D16F16C15_TRC_WRA_01;
- }
-
- Offset = (LVM_UINT16)(pParams->SampleRate);
- pSESideCoefs = (BiquadA012B12CoefsSP_t*)&LVCS_SESideCoefTable[0];
-
- /* Side filter */
- /* Convert incoming coefficients to the required format/ordering */
- CoeffsSide.A0 = (LVM_FLOAT) pSESideCoefs[Offset].A0;
- CoeffsSide.A1 = (LVM_FLOAT) pSESideCoefs[Offset].A1;
- CoeffsSide.A2 = (LVM_FLOAT) pSESideCoefs[Offset].A2;
- CoeffsSide.B1 = (LVM_FLOAT)-pSESideCoefs[Offset].B1;
- CoeffsSide.B2 = (LVM_FLOAT)-pSESideCoefs[Offset].B2;
-
- /* Clear the taps */
- LoadConst_Float(0, /* Value */
- (void *)&pData->SEBiquadTapsSide, /* Destination Cast to void:\
- no dereferencing in function*/
- /* Number of words */
- (LVM_UINT16)(sizeof(pData->SEBiquadTapsSide) / sizeof(LVM_FLOAT)));
- /* Callbacks */
- switch(pSESideCoefs[Offset].Scale)
- {
- case 14:
- BQ_1I_D16F32Css_TRC_WRA_01_Init(&pCoefficient->SEBiquadInstanceSide,
- &pData->SEBiquadTapsSide,
- &CoeffsSide);
-
- pConfig->pBiquadCallBack_Side = BQ_1I_D16F32C14_TRC_WRA_01;
- break;
- case 15:
- BQ_1I_D16F16Css_TRC_WRA_01_Init(&pCoefficient->SEBiquadInstanceSide,
- &pData->SEBiquadTapsSide,
- &CoeffsSide);
-
- pConfig->pBiquadCallBack_Side = BQ_1I_D16F16C15_TRC_WRA_01;
- break;
- }
-
- }
-
-
- return(LVCS_SUCCESS);
-}
-#else
-LVCS_ReturnStatus_en LVCS_SEnhancerInit(LVCS_Handle_t hInstance,
- LVCS_Params_t *pParams)
-{
-
- LVM_UINT16 Offset;
- LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
- LVCS_StereoEnhancer_t *pConfig = (LVCS_StereoEnhancer_t *)&pInstance->StereoEnhancer;
- LVCS_Data_t *pData = (LVCS_Data_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress;
- LVCS_Coefficient_t *pCoefficient = (LVCS_Coefficient_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
- FO_C16_Coefs_t CoeffsMid;
- BQ_C16_Coefs_t CoeffsSide;
- const BiquadA012B12CoefsSP_t *pSESideCoefs;
-
- /*
- * If the sample rate or speaker type has changed update the filters
- */
- if ((pInstance->Params.SampleRate != pParams->SampleRate) ||
- (pInstance->Params.SpeakerType != pParams->SpeakerType))
- {
- /*
- * Set the filter coefficients based on the sample rate
- */
- /* Mid filter */
- Offset = (LVM_UINT16)pParams->SampleRate;
-
- /* Convert incoming coefficients to the required format/ordering */
- CoeffsMid.A0 = (LVM_INT16) LVCS_SEMidCoefTable[Offset].A0;
- CoeffsMid.A1 = (LVM_INT16) LVCS_SEMidCoefTable[Offset].A1;
- CoeffsMid.B1 = (LVM_INT16)-LVCS_SEMidCoefTable[Offset].B1;
-
- /* Clear the taps */
- LoadConst_16(0, /* Value */
- (void *)&pData->SEBiquadTapsMid, /* Destination Cast to void:\
- no dereferencing in function*/
- (LVM_UINT16)(sizeof(pData->SEBiquadTapsMid)/sizeof(LVM_UINT16))); /* Number of words */
-
- FO_1I_D16F16Css_TRC_WRA_01_Init(&pCoefficient->SEBiquadInstanceMid,
- &pData->SEBiquadTapsMid,
- &CoeffsMid);
-
- /* Callbacks */
- if(LVCS_SEMidCoefTable[Offset].Scale==15)
- {
- pConfig->pBiquadCallBack_Mid = FO_1I_D16F16C15_TRC_WRA_01;
- }
-
- Offset = (LVM_UINT16)(pParams->SampleRate);
- pSESideCoefs = (BiquadA012B12CoefsSP_t*)&LVCS_SESideCoefTable[0];
-
- /* Side filter */
- /* Convert incoming coefficients to the required format/ordering */
- CoeffsSide.A0 = (LVM_INT16) pSESideCoefs[Offset].A0;
- CoeffsSide.A1 = (LVM_INT16) pSESideCoefs[Offset].A1;
- CoeffsSide.A2 = (LVM_INT16) pSESideCoefs[Offset].A2;
- CoeffsSide.B1 = (LVM_INT16)-pSESideCoefs[Offset].B1;
- CoeffsSide.B2 = (LVM_INT16)-pSESideCoefs[Offset].B2;
-
- /* Clear the taps */
- LoadConst_16(0, /* Value */
- (void *)&pData->SEBiquadTapsSide, /* Destination Cast to void:\
- no dereferencing in function*/
- (LVM_UINT16)(sizeof(pData->SEBiquadTapsSide)/sizeof(LVM_UINT16))); /* Number of words */
-
-
- /* Callbacks */
- switch(pSESideCoefs[Offset].Scale)
- {
- case 14:
- BQ_1I_D16F32Css_TRC_WRA_01_Init(&pCoefficient->SEBiquadInstanceSide,
- &pData->SEBiquadTapsSide,
- &CoeffsSide);
-
- pConfig->pBiquadCallBack_Side = BQ_1I_D16F32C14_TRC_WRA_01;
- break;
- case 15:
- BQ_1I_D16F16Css_TRC_WRA_01_Init(&pCoefficient->SEBiquadInstanceSide,
- &pData->SEBiquadTapsSide,
- &CoeffsSide);
-
- pConfig->pBiquadCallBack_Side = BQ_1I_D16F16C15_TRC_WRA_01;
- break;
- }
-
- }
-
-
- return(LVCS_SUCCESS);
-}
-#endif
-/************************************************************************************/
-/* */
-/* FUNCTION: LVCS_StereoEnhance */
-/* */
-/* DESCRIPTION: */
-/* Enhance the stereo image in the input samples based on the following block */
-/* diagram: */
-/* */
-/* ________ */
-/* ________ | | ________ */
-/* | | Middle | Treble | | | */
-/* | |---------->| Boost |-------->| | */
-/* | Stereo | |________| | M & S | */
-/* -->| to | ________ | to |--> */
-/* | M & S | Side | | | Stereo | */
-/* | |---------->| Side |-------->| | */
-/* |________| | Boost | |________| */
-/* |________| */
-/* */
-/* */
-/* If the input signal is a mono signal there will be no side signal and hence */
-/* the side filter will not be run. In mobile speaker mode the middle filter is */
-/* not required and the Trebble boost filter is replaced by a simple gain block. */
-/* */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance Handle */
-/* pInData Pointer to the input data */
-/* pOutData Pointer to the output data */
-/* NumSamples Number of samples to process */
-/* */
-/* RETURNS: */
-/* LVCS_Success Always succeeds */
-/* */
-/* NOTES: */
-/* 1. The side filter is not used in Mobile Speaker mode */
-/* */
-/************************************************************************************/
-#ifdef BUILD_FLOAT
-LVCS_ReturnStatus_en LVCS_StereoEnhancer(LVCS_Handle_t hInstance,
- const LVM_FLOAT *pInData,
- LVM_FLOAT *pOutData,
- LVM_UINT16 NumSamples)
-{
-
- LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
- LVCS_StereoEnhancer_t *pConfig = (LVCS_StereoEnhancer_t *)&pInstance->StereoEnhancer;
- LVCS_Coefficient_t *pCoefficient;
- LVM_FLOAT *pScratch;
-
- pCoefficient = (LVCS_Coefficient_t *) \
- pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
-
- pScratch = (LVM_FLOAT *) \
- pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
- /*
- * Check if the Stereo Enhancer is enabled
- */
- if ((pInstance->Params.OperatingMode & LVCS_STEREOENHANCESWITCH) != 0)
- {
- /*
- * Convert from stereo to middle and side
- */
- From2iToMS_Float(pInData,
- pScratch,
- pScratch + NumSamples,
- (LVM_INT16)NumSamples);
-
- /*
- * Apply filter to the middle signal
- */
- if (pInstance->OutputDevice == LVCS_HEADPHONE)
- {
- (pConfig->pBiquadCallBack_Mid)((Biquad_FLOAT_Instance_t*)\
- &pCoefficient->SEBiquadInstanceMid,
- (LVM_FLOAT *)pScratch,
- (LVM_FLOAT *)pScratch,
- (LVM_INT16)NumSamples);
- }
- else
- {
- Mult3s_Float(pScratch, /* Source */
- (LVM_FLOAT)pConfig->MidGain, /* Gain */
- pScratch, /* Destination */
- (LVM_INT16)NumSamples); /* Number of samples */
- }
-
- /*
- * Apply the filter the side signal only in stereo mode for headphones
- * and in all modes for mobile speakers
- */
- if (pInstance->Params.SourceFormat == LVCS_STEREO)
- {
- (pConfig->pBiquadCallBack_Side)((Biquad_FLOAT_Instance_t*) \
- &pCoefficient->SEBiquadInstanceSide,
- (LVM_FLOAT *)(pScratch + NumSamples),
- (LVM_FLOAT *)(pScratch + NumSamples),
- (LVM_INT16)NumSamples);
- }
-
- /*
- * Convert from middle and side to stereo
- */
- MSTo2i_Sat_Float(pScratch,
- pScratch + NumSamples,
- pOutData,
- (LVM_INT16)NumSamples);
-
- }
- else
- {
- /*
- * The stereo enhancer is disabled so just copy the data
- */
- Copy_Float((LVM_FLOAT *)pInData, /* Source */
- (LVM_FLOAT *)pOutData, /* Destination */
- (LVM_INT16)(2 * NumSamples)); /* Left and right */
- }
-
- return(LVCS_SUCCESS);
-}
-#else
-LVCS_ReturnStatus_en LVCS_StereoEnhancer(LVCS_Handle_t hInstance,
- const LVM_INT16 *pInData,
- LVM_INT16 *pOutData,
- LVM_UINT16 NumSamples)
-{
-
- LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
- LVCS_StereoEnhancer_t *pConfig = (LVCS_StereoEnhancer_t *)&pInstance->StereoEnhancer;
- LVCS_Coefficient_t *pCoefficient = (LVCS_Coefficient_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
- LVM_INT16 *pScratch = (LVM_INT16 *)pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
-
- /*
- * Check if the Stereo Enhancer is enabled
- */
- if ((pInstance->Params.OperatingMode & LVCS_STEREOENHANCESWITCH) != 0)
- {
- /*
- * Convert from stereo to middle and side
- */
- From2iToMS_16x16(pInData,
- pScratch,
- pScratch+NumSamples,
- (LVM_INT16)NumSamples);
-
- /*
- * Apply filter to the middle signal
- */
- if (pInstance->OutputDevice == LVCS_HEADPHONE)
- {
- (pConfig->pBiquadCallBack_Mid)((Biquad_Instance_t*)&pCoefficient->SEBiquadInstanceMid,
- (LVM_INT16 *)pScratch,
- (LVM_INT16 *)pScratch,
- (LVM_INT16)NumSamples);
- }
- else
- {
- Mult3s_16x16(pScratch, /* Source */
- (LVM_INT16)pConfig->MidGain, /* Gain */
- pScratch, /* Destination */
- (LVM_INT16)NumSamples); /* Number of samples */
- }
-
- /*
- * Apply the filter the side signal only in stereo mode for headphones
- * and in all modes for mobile speakers
- */
- if (pInstance->Params.SourceFormat == LVCS_STEREO)
- {
- (pConfig->pBiquadCallBack_Side)((Biquad_Instance_t*)&pCoefficient->SEBiquadInstanceSide,
- (LVM_INT16 *)(pScratch + NumSamples),
- (LVM_INT16 *)(pScratch + NumSamples),
- (LVM_INT16)NumSamples);
- }
-
- /*
- * Convert from middle and side to stereo
- */
- MSTo2i_Sat_16x16(pScratch,
- pScratch+NumSamples,
- pOutData,
- (LVM_INT16)NumSamples);
-
- }
- else
- {
- /*
- * The stereo enhancer is disabled so just copy the data
- */
- Copy_16((LVM_INT16 *)pInData, /* Source */
- (LVM_INT16 *)pOutData, /* Destination */
- (LVM_INT16)(2*NumSamples)); /* Left and right */
-
- }
-
- return(LVCS_SUCCESS);
-}
-#endif
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.cpp
new file mode 100644
index 0000000..7fd8444
--- /dev/null
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.cpp
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/************************************************************************************/
+/* */
+/* Includes */
+/* */
+/************************************************************************************/
+
+#include "LVCS.h"
+#include "LVCS_Private.h"
+#include "LVCS_StereoEnhancer.h"
+#include "VectorArithmetic.h"
+#include "LVCS_Tables.h"
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVCS_StereoEnhanceInit */
+/* */
+/* DESCRIPTION: */
+/* Initialises the stereo enhancement module based on the sample rate. */
+/* */
+/* The function selects the coefficients for the filters and clears the data */
+/* history. It is also used for re-initialisation when one of the system control */
+/* parameters changes but will only change the coefficients and clear the history */
+/* if the sample rate or speaker type has changed. */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance Handle */
+/* pParams Initialisation parameters */
+/* */
+/* RETURNS: */
+/* LVCS_Success Always succeeds */
+/* */
+/* NOTES: */
+/* */
+/************************************************************************************/
+LVCS_ReturnStatus_en LVCS_SEnhancerInit(LVCS_Handle_t hInstance,
+ LVCS_Params_t *pParams)
+{
+
+ LVM_UINT16 Offset;
+ LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
+ LVCS_StereoEnhancer_t *pConfig = (LVCS_StereoEnhancer_t *)&pInstance->StereoEnhancer;
+ LVCS_Data_t *pData;
+ LVCS_Coefficient_t *pCoefficient;
+ FO_FLOAT_Coefs_t CoeffsMid;
+ BQ_FLOAT_Coefs_t CoeffsSide;
+ const BiquadA012B12CoefsSP_t *pSESideCoefs;
+
+ pData = (LVCS_Data_t *) \
+ pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress;
+
+ pCoefficient = (LVCS_Coefficient_t *) \
+ pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
+
+ /*
+ * If the sample rate or speaker type has changed update the filters
+ */
+ if ((pInstance->Params.SampleRate != pParams->SampleRate) ||
+ (pInstance->Params.SpeakerType != pParams->SpeakerType))
+ {
+ /*
+ * Set the filter coefficients based on the sample rate
+ */
+ /* Mid filter */
+ Offset = (LVM_UINT16)pParams->SampleRate;
+
+ /* Convert incoming coefficients to the required format/ordering */
+ CoeffsMid.A0 = (LVM_FLOAT) LVCS_SEMidCoefTable[Offset].A0;
+ CoeffsMid.A1 = (LVM_FLOAT) LVCS_SEMidCoefTable[Offset].A1;
+ CoeffsMid.B1 = (LVM_FLOAT)-LVCS_SEMidCoefTable[Offset].B1;
+
+ /* Clear the taps */
+ LoadConst_Float(0, /* Value */
+ (LVM_FLOAT *)&pData->SEBiquadTapsMid, /* Destination */
+ /* Number of words */
+ (LVM_UINT16)(sizeof(pData->SEBiquadTapsMid) / sizeof(LVM_FLOAT)));
+
+ FO_1I_D16F16Css_TRC_WRA_01_Init(&pCoefficient->SEBiquadInstanceMid,
+ &pData->SEBiquadTapsMid,
+ &CoeffsMid);
+
+ /* Callbacks */
+ if(LVCS_SEMidCoefTable[Offset].Scale == 15)
+ {
+ pConfig->pBiquadCallBack_Mid = FO_1I_D16F16C15_TRC_WRA_01;
+ }
+
+ Offset = (LVM_UINT16)(pParams->SampleRate);
+ pSESideCoefs = (BiquadA012B12CoefsSP_t*)&LVCS_SESideCoefTable[0];
+
+ /* Side filter */
+ /* Convert incoming coefficients to the required format/ordering */
+ CoeffsSide.A0 = (LVM_FLOAT) pSESideCoefs[Offset].A0;
+ CoeffsSide.A1 = (LVM_FLOAT) pSESideCoefs[Offset].A1;
+ CoeffsSide.A2 = (LVM_FLOAT) pSESideCoefs[Offset].A2;
+ CoeffsSide.B1 = (LVM_FLOAT)-pSESideCoefs[Offset].B1;
+ CoeffsSide.B2 = (LVM_FLOAT)-pSESideCoefs[Offset].B2;
+
+ /* Clear the taps */
+ LoadConst_Float(0, /* Value */
+ (LVM_FLOAT *)&pData->SEBiquadTapsSide, /* Destination */
+ /* Number of words */
+ (LVM_UINT16)(sizeof(pData->SEBiquadTapsSide) / sizeof(LVM_FLOAT)));
+ /* Callbacks */
+ switch(pSESideCoefs[Offset].Scale)
+ {
+ case 14:
+ BQ_1I_D16F32Css_TRC_WRA_01_Init(&pCoefficient->SEBiquadInstanceSide,
+ &pData->SEBiquadTapsSide,
+ &CoeffsSide);
+
+ pConfig->pBiquadCallBack_Side = BQ_1I_D16F32C14_TRC_WRA_01;
+ break;
+ case 15:
+ BQ_1I_D16F16Css_TRC_WRA_01_Init(&pCoefficient->SEBiquadInstanceSide,
+ &pData->SEBiquadTapsSide,
+ &CoeffsSide);
+
+ pConfig->pBiquadCallBack_Side = BQ_1I_D16F16C15_TRC_WRA_01;
+ break;
+ }
+
+ }
+
+ return(LVCS_SUCCESS);
+}
+/************************************************************************************/
+/* */
+/* FUNCTION: LVCS_StereoEnhance */
+/* */
+/* DESCRIPTION: */
+/* Enhance the stereo image in the input samples based on the following block */
+/* diagram: */
+/* */
+/* ________ */
+/* ________ | | ________ */
+/* | | Middle | Treble | | | */
+/* | |---------->| Boost |-------->| | */
+/* | Stereo | |________| | M & S | */
+/* -->| to | ________ | to |--> */
+/* | M & S | Side | | | Stereo | */
+/* | |---------->| Side |-------->| | */
+/* |________| | Boost | |________| */
+/* |________| */
+/* */
+/* */
+/* If the input signal is a mono signal there will be no side signal and hence */
+/* the side filter will not be run. In mobile speaker mode the middle filter is */
+/* not required and the Trebble boost filter is replaced by a simple gain block. */
+/* */
+/* */
+/* PARAMETERS: */
+/* hInstance Instance Handle */
+/* pInData Pointer to the input data */
+/* pOutData Pointer to the output data */
+/* NumSamples Number of samples to process */
+/* */
+/* RETURNS: */
+/* LVCS_Success Always succeeds */
+/* */
+/* NOTES: */
+/* 1. The side filter is not used in Mobile Speaker mode */
+/* */
+/************************************************************************************/
+LVCS_ReturnStatus_en LVCS_StereoEnhancer(LVCS_Handle_t hInstance,
+ const LVM_FLOAT *pInData,
+ LVM_FLOAT *pOutData,
+ LVM_UINT16 NumSamples)
+{
+
+ LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
+ LVCS_StereoEnhancer_t *pConfig = (LVCS_StereoEnhancer_t *)&pInstance->StereoEnhancer;
+ LVCS_Coefficient_t *pCoefficient;
+ LVM_FLOAT *pScratch;
+
+ pCoefficient = (LVCS_Coefficient_t *) \
+ pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
+
+ pScratch = (LVM_FLOAT *) \
+ pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
+ /*
+ * Check if the Stereo Enhancer is enabled
+ */
+ if ((pInstance->Params.OperatingMode & LVCS_STEREOENHANCESWITCH) != 0)
+ {
+ /*
+ * Convert from stereo to middle and side
+ */
+ From2iToMS_Float(pInData,
+ pScratch,
+ pScratch + NumSamples,
+ (LVM_INT16)NumSamples);
+
+ /*
+ * Apply filter to the middle signal
+ */
+ if (pInstance->OutputDevice == LVCS_HEADPHONE)
+ {
+ (pConfig->pBiquadCallBack_Mid)((Biquad_FLOAT_Instance_t*)\
+ &pCoefficient->SEBiquadInstanceMid,
+ (LVM_FLOAT *)pScratch,
+ (LVM_FLOAT *)pScratch,
+ (LVM_INT16)NumSamples);
+ }
+ else
+ {
+ Mult3s_Float(pScratch, /* Source */
+ (LVM_FLOAT)pConfig->MidGain, /* Gain */
+ pScratch, /* Destination */
+ (LVM_INT16)NumSamples); /* Number of samples */
+ }
+
+ /*
+ * Apply the filter the side signal only in stereo mode for headphones
+ * and in all modes for mobile speakers
+ */
+ if (pInstance->Params.SourceFormat == LVCS_STEREO)
+ {
+ (pConfig->pBiquadCallBack_Side)((Biquad_FLOAT_Instance_t*) \
+ &pCoefficient->SEBiquadInstanceSide,
+ (LVM_FLOAT *)(pScratch + NumSamples),
+ (LVM_FLOAT *)(pScratch + NumSamples),
+ (LVM_INT16)NumSamples);
+ }
+
+ /*
+ * Convert from middle and side to stereo
+ */
+ MSTo2i_Sat_Float(pScratch,
+ pScratch + NumSamples,
+ pOutData,
+ (LVM_INT16)NumSamples);
+
+ }
+ else
+ {
+ /*
+ * The stereo enhancer is disabled so just copy the data
+ */
+ Copy_Float((LVM_FLOAT *)pInData, /* Source */
+ (LVM_FLOAT *)pOutData, /* Destination */
+ (LVM_INT16)(2 * NumSamples)); /* Left and right */
+ }
+
+ return(LVCS_SUCCESS);
+}
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.h b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.h
index 4125f24..12a5982 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.h
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.h
@@ -18,11 +18,6 @@
#ifndef __LVCS_STEREOENHANCER_H__
#define __LVCS_STEREOENHANCER_H__
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-
/************************************************************************************/
/* */
/* Includes */
@@ -33,7 +28,6 @@
#include "LVCS_Headphone_Coeffs.h" /* Headphone coefficients */
#include "BIQUAD.h"
-
/************************************************************************************/
/* */
/* Structures */
@@ -44,17 +38,6 @@
typedef struct
{
-#ifndef BUILD_FLOAT
- /*
- * Middle filter
- */
- void (*pBiquadCallBack_Mid)(Biquad_Instance_t*, LVM_INT16*, LVM_INT16*, LVM_INT16);
- /*
- * Side filter
- */
- void (*pBiquadCallBack_Side)(Biquad_Instance_t*, LVM_INT16*, LVM_INT16*, LVM_INT16);
- LVM_UINT16 MidGain; /* Middle gain in mobile speaker mode */
-#else
/*
* Middle filter
*/
@@ -67,10 +50,8 @@
void (*pBiquadCallBack_Side)(Biquad_FLOAT_Instance_t*,
LVM_FLOAT*, LVM_FLOAT*, LVM_INT16);
LVM_FLOAT MidGain; /* Middle gain in mobile speaker mode */
-#endif
} LVCS_StereoEnhancer_t;
-
/************************************************************************************/
/* */
/* Function prototypes */
@@ -80,19 +61,9 @@
LVCS_ReturnStatus_en LVCS_SEnhancerInit(LVCS_Handle_t hInstance,
LVCS_Params_t *pParams);
-#ifndef BUILD_FLOAT
-LVCS_ReturnStatus_en LVCS_StereoEnhancer(LVCS_Handle_t hInstance,
- const LVM_INT16 *pInData,
- LVM_INT16 *pOutData,
- LVM_UINT16 NumSamples);
-#else
LVCS_ReturnStatus_en LVCS_StereoEnhancer(LVCS_Handle_t hInstance,
const LVM_FLOAT *pInData,
LVM_FLOAT *pOutData,
LVM_UINT16 NumSamples);
-#endif
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
#endif /* STEREOENHANCE_H */
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Tables.c b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Tables.c
deleted file mode 100644
index a1fb48f..0000000
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Tables.c
+++ /dev/null
@@ -1,638 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-/************************************************************************************/
-/* */
-/* Includes */
-/* */
-/************************************************************************************/
-
-#include "LVCS_Private.h"
-#include "Filters.h" /* Filter definitions */
-#include "BIQUAD.h" /* Biquad definitions */
-#include "LVCS_Headphone_Coeffs.h" /* Headphone coefficients */
-
-
-/************************************************************************************/
-/* */
-/* Stereo Enhancer coefficient constant tables */
-/* */
-/************************************************************************************/
-
-/* Coefficient table for the middle filter */
-const BiquadA01B1CoefsSP_t LVCS_SEMidCoefTable[] = {
- {CS_MIDDLE_8000_A0, /* 8kS/s coefficients */
- CS_MIDDLE_8000_A1,
- CS_MIDDLE_8000_B1,
- (LVM_UINT16 )CS_MIDDLE_8000_SCALE},
- {CS_MIDDLE_11025_A0, /* 11kS/s coefficients */
- CS_MIDDLE_11025_A1,
- CS_MIDDLE_11025_B1,
- (LVM_UINT16 )CS_MIDDLE_11025_SCALE},
- {CS_MIDDLE_12000_A0, /* 12kS/s coefficients */
- CS_MIDDLE_12000_A1,
- CS_MIDDLE_12000_B1,
- (LVM_UINT16 )CS_MIDDLE_12000_SCALE},
- {CS_MIDDLE_16000_A0, /* 16kS/s coefficients */
- CS_MIDDLE_16000_A1,
- CS_MIDDLE_16000_B1,
- (LVM_UINT16 )CS_MIDDLE_16000_SCALE},
- {CS_MIDDLE_22050_A0, /* 22kS/s coefficients */
- CS_MIDDLE_22050_A1,
- CS_MIDDLE_22050_B1,
- (LVM_UINT16 )CS_MIDDLE_22050_SCALE},
- {CS_MIDDLE_24000_A0, /* 24kS/s coefficients */
- CS_MIDDLE_24000_A1,
- CS_MIDDLE_24000_B1,
- (LVM_UINT16 )CS_MIDDLE_24000_SCALE},
- {CS_MIDDLE_32000_A0, /* 32kS/s coefficients */
- CS_MIDDLE_32000_A1,
- CS_MIDDLE_32000_B1,
- (LVM_UINT16 )CS_MIDDLE_32000_SCALE},
- {CS_MIDDLE_44100_A0, /* 44kS/s coefficients */
- CS_MIDDLE_44100_A1,
- CS_MIDDLE_44100_B1,
- (LVM_UINT16 )CS_MIDDLE_44100_SCALE},
- {CS_MIDDLE_48000_A0, /* 48kS/s coefficients */
- CS_MIDDLE_48000_A1,
- CS_MIDDLE_48000_B1,
- (LVM_UINT16 )CS_MIDDLE_48000_SCALE}
-#ifdef HIGHER_FS
- ,
- {CS_MIDDLE_88200_A0, /* 88kS/s coefficients */
- CS_MIDDLE_88200_A1,
- CS_MIDDLE_88200_B1,
- (LVM_UINT16)CS_MIDDLE_88200_SCALE},
- {CS_MIDDLE_96000_A0, /* 96kS/s coefficients */
- CS_MIDDLE_96000_A1,
- CS_MIDDLE_96000_B1,
- (LVM_UINT16 )CS_MIDDLE_96000_SCALE},
- {CS_MIDDLE_176400_A0, /* 176kS/s coefficients */
- CS_MIDDLE_176400_A1,
- CS_MIDDLE_176400_B1,
- (LVM_UINT16)CS_MIDDLE_176400_SCALE},
- {CS_MIDDLE_192000_A0, /* 192kS/s coefficients */
- CS_MIDDLE_192000_A1,
- CS_MIDDLE_192000_B1,
- (LVM_UINT16 )CS_MIDDLE_192000_SCALE}
-#endif
- };
-
-/* Coefficient table for the side filter */
-const BiquadA012B12CoefsSP_t LVCS_SESideCoefTable[] = {
- /* Headphone Side coefficients */
- {CS_SIDE_8000_A0, /* 8kS/s coefficients */
- CS_SIDE_8000_A1,
- CS_SIDE_8000_A2,
- CS_SIDE_8000_B1,
- CS_SIDE_8000_B2,
- (LVM_UINT16 )CS_SIDE_8000_SCALE},
- {CS_SIDE_11025_A0, /* 11kS/s coefficients */
- CS_SIDE_11025_A1,
- CS_SIDE_11025_A2,
- CS_SIDE_11025_B1,
- CS_SIDE_11025_B2,
- (LVM_UINT16 )CS_SIDE_11025_SCALE},
- {CS_SIDE_12000_A0, /* 12kS/s coefficients */
- CS_SIDE_12000_A1,
- CS_SIDE_12000_A2,
- CS_SIDE_12000_B1,
- CS_SIDE_12000_B2,
- (LVM_UINT16 )CS_SIDE_12000_SCALE},
- {CS_SIDE_16000_A0, /* 16kS/s coefficients */
- CS_SIDE_16000_A1,
- CS_SIDE_16000_A2,
- CS_SIDE_16000_B1,
- CS_SIDE_16000_B2,
- (LVM_UINT16 )CS_SIDE_16000_SCALE},
- {CS_SIDE_22050_A0, /* 22kS/s coefficients */
- CS_SIDE_22050_A1,
- CS_SIDE_22050_A2,
- CS_SIDE_22050_B1,
- CS_SIDE_22050_B2,
- (LVM_UINT16 )CS_SIDE_22050_SCALE},
- {CS_SIDE_24000_A0, /* 24kS/s coefficients */
- CS_SIDE_24000_A1,
- CS_SIDE_24000_A2,
- CS_SIDE_24000_B1,
- CS_SIDE_24000_B2,
- (LVM_UINT16 )CS_SIDE_24000_SCALE},
- {CS_SIDE_32000_A0, /* 32kS/s coefficients */
- CS_SIDE_32000_A1,
- CS_SIDE_32000_A2,
- CS_SIDE_32000_B1,
- CS_SIDE_32000_B2,
- (LVM_UINT16 )CS_SIDE_32000_SCALE},
- {CS_SIDE_44100_A0, /* 44kS/s coefficients */
- CS_SIDE_44100_A1,
- CS_SIDE_44100_A2,
- CS_SIDE_44100_B1,
- CS_SIDE_44100_B2,
- (LVM_UINT16 )CS_SIDE_44100_SCALE},
- {CS_SIDE_48000_A0, /* 48kS/s coefficients */
- CS_SIDE_48000_A1,
- CS_SIDE_48000_A2,
- CS_SIDE_48000_B1,
- CS_SIDE_48000_B2,
- (LVM_UINT16 )CS_SIDE_48000_SCALE}
-#ifdef HIGHER_FS
- ,
- {CS_SIDE_88200_A0, /* 88kS/s coefficients */
- CS_SIDE_88200_A1,
- CS_SIDE_88200_A2,
- CS_SIDE_88200_B1,
- CS_SIDE_88200_B2,
- (LVM_UINT16)CS_SIDE_88200_SCALE},
- {CS_SIDE_96000_A0, /* 96kS/s coefficients */
- CS_SIDE_96000_A1,
- CS_SIDE_96000_A2,
- CS_SIDE_96000_B1,
- CS_SIDE_96000_B2,
- (LVM_UINT16 )CS_SIDE_96000_SCALE},
- {CS_SIDE_176400_A0, /*176kS/s coefficients */
- CS_SIDE_176400_A1,
- CS_SIDE_176400_A2,
- CS_SIDE_176400_B1,
- CS_SIDE_176400_B2,
- (LVM_UINT16)CS_SIDE_176400_SCALE},
- {CS_SIDE_192000_A0, /* 192kS/s coefficients */
- CS_SIDE_192000_A1,
- CS_SIDE_192000_A2,
- CS_SIDE_192000_B1,
- CS_SIDE_192000_B2,
- (LVM_UINT16 )CS_SIDE_192000_SCALE}
-#endif
-};
-
-
-/************************************************************************************/
-/* */
-/* Equaliser coefficient constant tables */
-/* */
-/************************************************************************************/
-
-const BiquadA012B12CoefsSP_t LVCS_EqualiserCoefTable[] = {
- /* Headphone coefficients */
- {CS_EQUALISER_8000_A0, /* 8kS/s coefficients */
- CS_EQUALISER_8000_A1,
- CS_EQUALISER_8000_A2,
- CS_EQUALISER_8000_B1,
- CS_EQUALISER_8000_B2,
- (LVM_UINT16 )CS_EQUALISER_8000_SCALE},
- {CS_EQUALISER_11025_A0, /* 11kS/s coefficients */
- CS_EQUALISER_11025_A1,
- CS_EQUALISER_11025_A2,
- CS_EQUALISER_11025_B1,
- CS_EQUALISER_11025_B2,
- (LVM_UINT16 )CS_EQUALISER_11025_SCALE},
- {CS_EQUALISER_12000_A0, /* 12kS/s coefficients */
- CS_EQUALISER_12000_A1,
- CS_EQUALISER_12000_A2,
- CS_EQUALISER_12000_B1,
- CS_EQUALISER_12000_B2,
- (LVM_UINT16 )CS_EQUALISER_12000_SCALE},
- {CS_EQUALISER_16000_A0, /* 16kS/s coefficients */
- CS_EQUALISER_16000_A1,
- CS_EQUALISER_16000_A2,
- CS_EQUALISER_16000_B1,
- CS_EQUALISER_16000_B2,
- (LVM_UINT16 )CS_EQUALISER_16000_SCALE},
- {CS_EQUALISER_22050_A0, /* 22kS/s coefficients */
- CS_EQUALISER_22050_A1,
- CS_EQUALISER_22050_A2,
- CS_EQUALISER_22050_B1,
- CS_EQUALISER_22050_B2,
- (LVM_UINT16 )CS_EQUALISER_22050_SCALE},
- {CS_EQUALISER_24000_A0, /* 24kS/s coefficients */
- CS_EQUALISER_24000_A1,
- CS_EQUALISER_24000_A2,
- CS_EQUALISER_24000_B1,
- CS_EQUALISER_24000_B2,
- (LVM_UINT16 )CS_EQUALISER_24000_SCALE},
- {CS_EQUALISER_32000_A0, /* 32kS/s coefficients */
- CS_EQUALISER_32000_A1,
- CS_EQUALISER_32000_A2,
- CS_EQUALISER_32000_B1,
- CS_EQUALISER_32000_B2,
- (LVM_UINT16 )CS_EQUALISER_32000_SCALE},
- {CS_EQUALISER_44100_A0, /* 44kS/s coefficients */
- CS_EQUALISER_44100_A1,
- CS_EQUALISER_44100_A2,
- CS_EQUALISER_44100_B1,
- CS_EQUALISER_44100_B2,
- (LVM_UINT16 )CS_EQUALISER_44100_SCALE},
- {CS_EQUALISER_48000_A0, /* 48kS/s coefficients */
- CS_EQUALISER_48000_A1,
- CS_EQUALISER_48000_A2,
- CS_EQUALISER_48000_B1,
- CS_EQUALISER_48000_B2,
- (LVM_UINT16 )CS_EQUALISER_48000_SCALE},
-#ifdef HIGHER_FS
- {CS_EQUALISER_88200_A0, /* 88kS/s coeffieients */
- CS_EQUALISER_88200_A1,
- CS_EQUALISER_88200_A2,
- CS_EQUALISER_88200_B1,
- CS_EQUALISER_88200_B2,
- (LVM_UINT16)CS_EQUALISER_88200_SCALE},
- {CS_EQUALISER_96000_A0, /* 96kS/s coefficients */
- CS_EQUALISER_96000_A1,
- CS_EQUALISER_96000_A2,
- CS_EQUALISER_96000_B1,
- CS_EQUALISER_96000_B2,
- (LVM_UINT16 )CS_EQUALISER_96000_SCALE},
- {CS_EQUALISER_176400_A0, /* 176kS/s coefficients */
- CS_EQUALISER_176400_A1,
- CS_EQUALISER_176400_A2,
- CS_EQUALISER_176400_B1,
- CS_EQUALISER_176400_B2,
- (LVM_UINT16)CS_EQUALISER_176400_SCALE},
- {CS_EQUALISER_192000_A0, /* 192kS/s coefficients */
- CS_EQUALISER_192000_A1,
- CS_EQUALISER_192000_A2,
- CS_EQUALISER_192000_B1,
- CS_EQUALISER_192000_B2,
- (LVM_UINT16 )CS_EQUALISER_192000_SCALE},
-#endif
-
- /* Concert Sound EX Headphone coefficients */
- {CSEX_EQUALISER_8000_A0, /* 8kS/s coefficients */
- CSEX_EQUALISER_8000_A1,
- CSEX_EQUALISER_8000_A2,
- CSEX_EQUALISER_8000_B1,
- CSEX_EQUALISER_8000_B2,
- (LVM_UINT16 )CSEX_EQUALISER_8000_SCALE},
- {CSEX_EQUALISER_11025_A0, /* 11kS/s coefficients */
- CSEX_EQUALISER_11025_A1,
- CSEX_EQUALISER_11025_A2,
- CSEX_EQUALISER_11025_B1,
- CSEX_EQUALISER_11025_B2,
- (LVM_UINT16 )CSEX_EQUALISER_11025_SCALE},
- {CSEX_EQUALISER_12000_A0, /* 12kS/s coefficients */
- CSEX_EQUALISER_12000_A1,
- CSEX_EQUALISER_12000_A2,
- CSEX_EQUALISER_12000_B1,
- CSEX_EQUALISER_12000_B2,
- (LVM_UINT16 )CSEX_EQUALISER_12000_SCALE},
- {CSEX_EQUALISER_16000_A0, /* 16kS/s coefficients */
- CSEX_EQUALISER_16000_A1,
- CSEX_EQUALISER_16000_A2,
- CSEX_EQUALISER_16000_B1,
- CSEX_EQUALISER_16000_B2,
- (LVM_UINT16 )CSEX_EQUALISER_16000_SCALE},
- {CSEX_EQUALISER_22050_A0, /* 22kS/s coefficients */
- CSEX_EQUALISER_22050_A1,
- CSEX_EQUALISER_22050_A2,
- CSEX_EQUALISER_22050_B1,
- CSEX_EQUALISER_22050_B2,
- (LVM_UINT16 )CSEX_EQUALISER_22050_SCALE},
- {CSEX_EQUALISER_24000_A0, /* 24kS/s coefficients */
- CSEX_EQUALISER_24000_A1,
- CSEX_EQUALISER_24000_A2,
- CSEX_EQUALISER_24000_B1,
- CSEX_EQUALISER_24000_B2,
- (LVM_UINT16 )CSEX_EQUALISER_24000_SCALE},
- {CSEX_EQUALISER_32000_A0, /* 32kS/s coefficients */
- CSEX_EQUALISER_32000_A1,
- CSEX_EQUALISER_32000_A2,
- CSEX_EQUALISER_32000_B1,
- CSEX_EQUALISER_32000_B2,
- (LVM_UINT16 )CSEX_EQUALISER_32000_SCALE},
- {CSEX_EQUALISER_44100_A0, /* 44kS/s coefficients */
- CSEX_EQUALISER_44100_A1,
- CSEX_EQUALISER_44100_A2,
- CSEX_EQUALISER_44100_B1,
- CSEX_EQUALISER_44100_B2,
- (LVM_UINT16 )CSEX_EQUALISER_44100_SCALE},
- {CSEX_EQUALISER_48000_A0, /* 48kS/s coefficients */
- CSEX_EQUALISER_48000_A1,
- CSEX_EQUALISER_48000_A2,
- CSEX_EQUALISER_48000_B1,
- CSEX_EQUALISER_48000_B2,
- (LVM_UINT16 )CSEX_EQUALISER_48000_SCALE}
-#ifdef HIGHER_FS
- ,
- {CSEX_EQUALISER_88200_A0, /* 88kS/s coefficients */
- CSEX_EQUALISER_88200_A1,
- CSEX_EQUALISER_88200_A2,
- CSEX_EQUALISER_88200_B1,
- CSEX_EQUALISER_88200_B2,
- (LVM_UINT16)CSEX_EQUALISER_88200_SCALE},
- {CSEX_EQUALISER_96000_A0, /* 96kS/s coefficients */
- CSEX_EQUALISER_96000_A1,
- CSEX_EQUALISER_96000_A2,
- CSEX_EQUALISER_96000_B1,
- CSEX_EQUALISER_96000_B2,
- (LVM_UINT16 )CSEX_EQUALISER_96000_SCALE},
- {CSEX_EQUALISER_176400_A0, /* 176kS/s coefficients */
- CSEX_EQUALISER_176400_A1,
- CSEX_EQUALISER_176400_A2,
- CSEX_EQUALISER_176400_B1,
- CSEX_EQUALISER_176400_B2,
- (LVM_UINT16)CSEX_EQUALISER_176400_SCALE},
- {CSEX_EQUALISER_192000_A0, /* 192kS/s coefficients */
- CSEX_EQUALISER_192000_A1,
- CSEX_EQUALISER_192000_A2,
- CSEX_EQUALISER_192000_B1,
- CSEX_EQUALISER_192000_B2,
- (LVM_UINT16 )CSEX_EQUALISER_192000_SCALE}
-#endif
-};
-
-
-/************************************************************************************/
-/* */
-/* Reverb delay constant tables */
-/* */
-/************************************************************************************/
-
-/* Stereo delay table for Concert Sound */
-const LVM_UINT16 LVCS_StereoDelayCS[] = {
- LVCS_STEREODELAY_CS_8KHZ,
- LVCS_STEREODELAY_CS_11KHZ,
- LVCS_STEREODELAY_CS_12KHZ,
- LVCS_STEREODELAY_CS_16KHZ,
- LVCS_STEREODELAY_CS_22KHZ,
- LVCS_STEREODELAY_CS_24KHZ,
- LVCS_STEREODELAY_CS_32KHZ,
- LVCS_STEREODELAY_CS_44KHZ,
- LVCS_STEREODELAY_CS_48KHZ,
- LVCS_STEREODELAY_CS_88KHZ,
- LVCS_STEREODELAY_CS_96KHZ,
- LVCS_STEREODELAY_CS_176KHZ,
- LVCS_STEREODELAY_CS_192KHZ,
-};
-
-/************************************************************************************/
-/* */
-/* Reverb coefficients constant table */
-/* */
-/************************************************************************************/
-
-const BiquadA012B12CoefsSP_t LVCS_ReverbCoefTable[] = {
- /* Headphone coefficients */
- {CS_REVERB_8000_A0, /* 8kS/s coefficients */
- CS_REVERB_8000_A1,
- CS_REVERB_8000_A2,
- CS_REVERB_8000_B1,
- CS_REVERB_8000_B2,
- (LVM_UINT16 )CS_REVERB_8000_SCALE},
- {CS_REVERB_11025_A0, /* 11kS/s coefficients */
- CS_REVERB_11025_A1,
- CS_REVERB_11025_A2,
- CS_REVERB_11025_B1,
- CS_REVERB_11025_B2,
- (LVM_UINT16 )CS_REVERB_11025_SCALE},
- {CS_REVERB_12000_A0, /* 12kS/s coefficients */
- CS_REVERB_12000_A1,
- CS_REVERB_12000_A2,
- CS_REVERB_12000_B1,
- CS_REVERB_12000_B2,
- (LVM_UINT16 )CS_REVERB_12000_SCALE},
- {CS_REVERB_16000_A0, /* 16kS/s coefficients */
- CS_REVERB_16000_A1,
- CS_REVERB_16000_A2,
- CS_REVERB_16000_B1,
- CS_REVERB_16000_B2,
- (LVM_UINT16 )CS_REVERB_16000_SCALE},
- {CS_REVERB_22050_A0, /* 22kS/s coefficients */
- CS_REVERB_22050_A1,
- CS_REVERB_22050_A2,
- CS_REVERB_22050_B1,
- CS_REVERB_22050_B2,
- (LVM_UINT16 )CS_REVERB_22050_SCALE},
- {CS_REVERB_24000_A0, /* 24kS/s coefficients */
- CS_REVERB_24000_A1,
- CS_REVERB_24000_A2,
- CS_REVERB_24000_B1,
- CS_REVERB_24000_B2,
- (LVM_UINT16 )CS_REVERB_24000_SCALE},
- {CS_REVERB_32000_A0, /* 32kS/s coefficients */
- CS_REVERB_32000_A1,
- CS_REVERB_32000_A2,
- CS_REVERB_32000_B1,
- CS_REVERB_32000_B2,
- (LVM_UINT16 )CS_REVERB_32000_SCALE},
- {CS_REVERB_44100_A0, /* 44kS/s coefficients */
- CS_REVERB_44100_A1,
- CS_REVERB_44100_A2,
- CS_REVERB_44100_B1,
- CS_REVERB_44100_B2,
- (LVM_UINT16 )CS_REVERB_44100_SCALE},
- {CS_REVERB_48000_A0, /* 48kS/s coefficients */
- CS_REVERB_48000_A1,
- CS_REVERB_48000_A2,
- CS_REVERB_48000_B1,
- CS_REVERB_48000_B2,
- (LVM_UINT16 )CS_REVERB_48000_SCALE}
-#ifdef HIGHER_FS
- ,
- {CS_REVERB_88200_A0, /* 88kS/s coefficients */
- CS_REVERB_88200_A1,
- CS_REVERB_88200_A2,
- CS_REVERB_88200_B1,
- CS_REVERB_88200_B2,
- (LVM_UINT16)CS_REVERB_88200_SCALE},
- {CS_REVERB_96000_A0, /* 96kS/s coefficients */
- CS_REVERB_96000_A1,
- CS_REVERB_96000_A2,
- CS_REVERB_96000_B1,
- CS_REVERB_96000_B2,
- (LVM_UINT16 )CS_REVERB_96000_SCALE},
- {CS_REVERB_176400_A0, /* 176kS/s coefficients */
- CS_REVERB_176400_A1,
- CS_REVERB_176400_A2,
- CS_REVERB_176400_B1,
- CS_REVERB_176400_B2,
- (LVM_UINT16)CS_REVERB_176400_SCALE},
- {CS_REVERB_192000_A0, /* 192kS/s coefficients */
- CS_REVERB_192000_A1,
- CS_REVERB_192000_A2,
- CS_REVERB_192000_B1,
- CS_REVERB_192000_B2,
- (LVM_UINT16 )CS_REVERB_192000_SCALE}
-#endif
-};
-
-
-/************************************************************************************/
-/* */
-/* Bypass mixer constant tables */
-/* */
-/************************************************************************************/
-
-const Gain_t LVCS_OutputGainTable[] = {
- {LVCS_HEADPHONE_SHIFT, /* Headphone, stereo mode */
- LVCS_HEADPHONE_SHIFTLOSS,
- LVCS_HEADPHONE_GAIN},
- {LVCS_EX_HEADPHONE_SHIFT, /* EX Headphone, stereo mode */
- LVCS_EX_HEADPHONE_SHIFTLOSS,
- LVCS_EX_HEADPHONE_GAIN},
- {LVCS_HEADPHONE_SHIFT, /* Headphone, mono mode */
- LVCS_HEADPHONE_SHIFTLOSS,
- LVCS_HEADPHONE_GAIN},
- {LVCS_EX_HEADPHONE_SHIFT, /* EX Headphone, mono mode */
- LVCS_EX_HEADPHONE_SHIFTLOSS,
- LVCS_EX_HEADPHONE_GAIN}
-};
-
-
-/************************************************************************************/
-/* */
-/* Volume correction table */
-/* */
-/* Coefficient order: */
-/* Compression 100% effect */
-/* Compression 0% effect */
-/* Gain 100% effect */
-/* Gain 0% effect */
-/* */
-/* The Compression gain is represented by a Q1.15 number to give a range of 0dB */
-/* to +6dB, E.g.: */
-/* 0 is 0dB compression (no effect) */
-/* 5461 is 1dB compression gain */
-/* 10923 is 2dB compression gain */
-/* 32767 is 6dB compression gain */
-/* */
-/* The Gain is represented as a Q3.13 number to give a range of +8 to -infinity */
-/* E.g.: */
-/* 0 is -infinity */
-/* 32767 is +18dB (x8) gain */
-/* 4096 is 0dB gain */
-/* 1024 is -12dB gain */
-/* */
-/************************************************************************************/
-const LVCS_VolCorrect_t LVCS_VolCorrectTable[] = {
-#ifdef BUILD_FLOAT
- {0.433362f, /* Headphone, stereo mode */
- 0.000000f,
- 1.000024f,
- 1.412640f},
- {0.433362f, /* EX Headphone, stereo mode */
- 0.000000f,
- 1.000024f,
- 1.412640f},
- {1.000000f, /* Headphone, mono mode */
- 0.000000f,
- 1.000024f,
- 1.412640f},
- {1.000000f, /* EX Headphone, mono mode */
- 0.000000f,
- 1.000024f,
- 1.412640f}
-#else
- {14200, /* Headphone, stereo mode */
- 0,
- 4096,
- 5786},
- {14200, /* EX Headphone, stereo mode */
- 0,
- 4096,
- 5786},
- {32767, /* Headphone, mono mode */
- 0,
- 4096,
- 5786},
- {32767, /* EX Headphone, mono mode */
- 0,
- 4096,
- 5786}
-#endif
-};
-
-/************************************************************************************/
-/* */
-/* Mixer time constants, 100ms */
-/* */
-/************************************************************************************/
-
-#define LVCS_VOL_TC_Fs8000 32580 /* Floating point value 0.994262695 */
-#define LVCS_VOL_TC_Fs11025 32632 /* Floating point value 0.995849609 */
-#define LVCS_VOL_TC_Fs12000 32643 /* Floating point value 0.996185303 */
-#define LVCS_VOL_TC_Fs16000 32674 /* Floating point value 0.997131348 */
-#define LVCS_VOL_TC_Fs22050 32700 /* Floating point value 0.997924805 */
-#define LVCS_VOL_TC_Fs24000 32705 /* Floating point value 0.998077393 */
-#define LVCS_VOL_TC_Fs32000 32721 /* Floating point value 0.998565674 */
-#define LVCS_VOL_TC_Fs44100 32734 /* Floating point value 0.998962402 */
-#define LVCS_VOL_TC_Fs48000 32737 /* Floating point value 0.999053955 */
-#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
-#define LVCS_VOL_TC_Fs88200 32751 /* Floating point value 0.999481066 */
-#define LVCS_VOL_TC_Fs96000 32751 /* Floating point value 0.999511703 */ /* Todo @ need to re check this value*/
-#define LVCS_VOL_TC_Fs176400 32759 /* Floating point value 0.999740499 */
-#define LVCS_VOL_TC_Fs192000 32763 /* Floating point value 0.999877925 */ /* Todo @ need to re check this value*/
-#endif
-
-#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
-const LVM_INT16 LVCS_VolumeTCTable[13] = {LVCS_VOL_TC_Fs8000,
- LVCS_VOL_TC_Fs11025,
- LVCS_VOL_TC_Fs12000,
- LVCS_VOL_TC_Fs16000,
- LVCS_VOL_TC_Fs22050,
- LVCS_VOL_TC_Fs24000,
- LVCS_VOL_TC_Fs32000,
- LVCS_VOL_TC_Fs44100,
- LVCS_VOL_TC_Fs48000,
- LVCS_VOL_TC_Fs88200,
- LVCS_VOL_TC_Fs96000,
- LVCS_VOL_TC_Fs176400,
- LVCS_VOL_TC_Fs192000
-};
-#else
-const LVM_INT16 LVCS_VolumeTCTable[9] = {LVCS_VOL_TC_Fs8000,
- LVCS_VOL_TC_Fs11025,
- LVCS_VOL_TC_Fs12000,
- LVCS_VOL_TC_Fs16000,
- LVCS_VOL_TC_Fs22050,
- LVCS_VOL_TC_Fs24000,
- LVCS_VOL_TC_Fs32000,
- LVCS_VOL_TC_Fs44100,
- LVCS_VOL_TC_Fs48000
-};
-#endif
-
-/************************************************************************************/
-/* */
-/* Sample rate table */
-/* */
-/************************************************************************************/
-#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
-const LVM_INT32 LVCS_SampleRateTable[13] = {8000,
- 11025,
- 12000,
- 16000,
- 22050,
- 24000,
- 32000,
- 44100,
- 48000,
- 88200,
- 96000,
- 176400,
- 192000
-};
-#else
-const LVM_INT16 LVCS_SampleRateTable[9] = {8000,
- 11025,
- 12000,
- 16000,
- 22050,
- 24000,
- 32000,
- 44100,
- 48000
-};
-#endif
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Tables.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Tables.cpp
new file mode 100644
index 0000000..d79db61
--- /dev/null
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Tables.cpp
@@ -0,0 +1,576 @@
+/*
+ * Copyright (C) 2004-2010 NXP Software
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/************************************************************************************/
+/* */
+/* Includes */
+/* */
+/************************************************************************************/
+
+#include "LVCS_Private.h"
+#include "LVCS_Tables.h"
+#include "Filters.h" /* Filter definitions */
+#include "BIQUAD.h" /* Biquad definitions */
+#include "LVCS_Headphone_Coeffs.h" /* Headphone coefficients */
+
+/************************************************************************************/
+/* */
+/* Stereo Enhancer coefficient constant tables */
+/* */
+/************************************************************************************/
+
+/* Coefficient table for the middle filter */
+const BiquadA01B1CoefsSP_t LVCS_SEMidCoefTable[] = {
+ {CS_MIDDLE_8000_A0, /* 8kS/s coefficients */
+ CS_MIDDLE_8000_A1,
+ CS_MIDDLE_8000_B1,
+ (LVM_UINT16 )CS_MIDDLE_8000_SCALE},
+ {CS_MIDDLE_11025_A0, /* 11kS/s coefficients */
+ CS_MIDDLE_11025_A1,
+ CS_MIDDLE_11025_B1,
+ (LVM_UINT16 )CS_MIDDLE_11025_SCALE},
+ {CS_MIDDLE_12000_A0, /* 12kS/s coefficients */
+ CS_MIDDLE_12000_A1,
+ CS_MIDDLE_12000_B1,
+ (LVM_UINT16 )CS_MIDDLE_12000_SCALE},
+ {CS_MIDDLE_16000_A0, /* 16kS/s coefficients */
+ CS_MIDDLE_16000_A1,
+ CS_MIDDLE_16000_B1,
+ (LVM_UINT16 )CS_MIDDLE_16000_SCALE},
+ {CS_MIDDLE_22050_A0, /* 22kS/s coefficients */
+ CS_MIDDLE_22050_A1,
+ CS_MIDDLE_22050_B1,
+ (LVM_UINT16 )CS_MIDDLE_22050_SCALE},
+ {CS_MIDDLE_24000_A0, /* 24kS/s coefficients */
+ CS_MIDDLE_24000_A1,
+ CS_MIDDLE_24000_B1,
+ (LVM_UINT16 )CS_MIDDLE_24000_SCALE},
+ {CS_MIDDLE_32000_A0, /* 32kS/s coefficients */
+ CS_MIDDLE_32000_A1,
+ CS_MIDDLE_32000_B1,
+ (LVM_UINT16 )CS_MIDDLE_32000_SCALE},
+ {CS_MIDDLE_44100_A0, /* 44kS/s coefficients */
+ CS_MIDDLE_44100_A1,
+ CS_MIDDLE_44100_B1,
+ (LVM_UINT16 )CS_MIDDLE_44100_SCALE},
+ {CS_MIDDLE_48000_A0, /* 48kS/s coefficients */
+ CS_MIDDLE_48000_A1,
+ CS_MIDDLE_48000_B1,
+ (LVM_UINT16 )CS_MIDDLE_48000_SCALE}
+ ,
+ {CS_MIDDLE_88200_A0, /* 88kS/s coefficients */
+ CS_MIDDLE_88200_A1,
+ CS_MIDDLE_88200_B1,
+ (LVM_UINT16)CS_MIDDLE_88200_SCALE},
+ {CS_MIDDLE_96000_A0, /* 96kS/s coefficients */
+ CS_MIDDLE_96000_A1,
+ CS_MIDDLE_96000_B1,
+ (LVM_UINT16 )CS_MIDDLE_96000_SCALE},
+ {CS_MIDDLE_176400_A0, /* 176kS/s coefficients */
+ CS_MIDDLE_176400_A1,
+ CS_MIDDLE_176400_B1,
+ (LVM_UINT16)CS_MIDDLE_176400_SCALE},
+ {CS_MIDDLE_192000_A0, /* 192kS/s coefficients */
+ CS_MIDDLE_192000_A1,
+ CS_MIDDLE_192000_B1,
+ (LVM_UINT16 )CS_MIDDLE_192000_SCALE}
+ };
+
+/* Coefficient table for the side filter */
+const BiquadA012B12CoefsSP_t LVCS_SESideCoefTable[] = {
+ /* Headphone Side coefficients */
+ {CS_SIDE_8000_A0, /* 8kS/s coefficients */
+ CS_SIDE_8000_A1,
+ CS_SIDE_8000_A2,
+ CS_SIDE_8000_B1,
+ CS_SIDE_8000_B2,
+ (LVM_UINT16 )CS_SIDE_8000_SCALE},
+ {CS_SIDE_11025_A0, /* 11kS/s coefficients */
+ CS_SIDE_11025_A1,
+ CS_SIDE_11025_A2,
+ CS_SIDE_11025_B1,
+ CS_SIDE_11025_B2,
+ (LVM_UINT16 )CS_SIDE_11025_SCALE},
+ {CS_SIDE_12000_A0, /* 12kS/s coefficients */
+ CS_SIDE_12000_A1,
+ CS_SIDE_12000_A2,
+ CS_SIDE_12000_B1,
+ CS_SIDE_12000_B2,
+ (LVM_UINT16 )CS_SIDE_12000_SCALE},
+ {CS_SIDE_16000_A0, /* 16kS/s coefficients */
+ CS_SIDE_16000_A1,
+ CS_SIDE_16000_A2,
+ CS_SIDE_16000_B1,
+ CS_SIDE_16000_B2,
+ (LVM_UINT16 )CS_SIDE_16000_SCALE},
+ {CS_SIDE_22050_A0, /* 22kS/s coefficients */
+ CS_SIDE_22050_A1,
+ CS_SIDE_22050_A2,
+ CS_SIDE_22050_B1,
+ CS_SIDE_22050_B2,
+ (LVM_UINT16 )CS_SIDE_22050_SCALE},
+ {CS_SIDE_24000_A0, /* 24kS/s coefficients */
+ CS_SIDE_24000_A1,
+ CS_SIDE_24000_A2,
+ CS_SIDE_24000_B1,
+ CS_SIDE_24000_B2,
+ (LVM_UINT16 )CS_SIDE_24000_SCALE},
+ {CS_SIDE_32000_A0, /* 32kS/s coefficients */
+ CS_SIDE_32000_A1,
+ CS_SIDE_32000_A2,
+ CS_SIDE_32000_B1,
+ CS_SIDE_32000_B2,
+ (LVM_UINT16 )CS_SIDE_32000_SCALE},
+ {CS_SIDE_44100_A0, /* 44kS/s coefficients */
+ CS_SIDE_44100_A1,
+ CS_SIDE_44100_A2,
+ CS_SIDE_44100_B1,
+ CS_SIDE_44100_B2,
+ (LVM_UINT16 )CS_SIDE_44100_SCALE},
+ {CS_SIDE_48000_A0, /* 48kS/s coefficients */
+ CS_SIDE_48000_A1,
+ CS_SIDE_48000_A2,
+ CS_SIDE_48000_B1,
+ CS_SIDE_48000_B2,
+ (LVM_UINT16 )CS_SIDE_48000_SCALE}
+ ,
+ {CS_SIDE_88200_A0, /* 88kS/s coefficients */
+ CS_SIDE_88200_A1,
+ CS_SIDE_88200_A2,
+ CS_SIDE_88200_B1,
+ CS_SIDE_88200_B2,
+ (LVM_UINT16)CS_SIDE_88200_SCALE},
+ {CS_SIDE_96000_A0, /* 96kS/s coefficients */
+ CS_SIDE_96000_A1,
+ CS_SIDE_96000_A2,
+ CS_SIDE_96000_B1,
+ CS_SIDE_96000_B2,
+ (LVM_UINT16 )CS_SIDE_96000_SCALE},
+ {CS_SIDE_176400_A0, /*176kS/s coefficients */
+ CS_SIDE_176400_A1,
+ CS_SIDE_176400_A2,
+ CS_SIDE_176400_B1,
+ CS_SIDE_176400_B2,
+ (LVM_UINT16)CS_SIDE_176400_SCALE},
+ {CS_SIDE_192000_A0, /* 192kS/s coefficients */
+ CS_SIDE_192000_A1,
+ CS_SIDE_192000_A2,
+ CS_SIDE_192000_B1,
+ CS_SIDE_192000_B2,
+ (LVM_UINT16 )CS_SIDE_192000_SCALE}
+};
+
+/************************************************************************************/
+/* */
+/* Equaliser coefficient constant tables */
+/* */
+/************************************************************************************/
+
+const BiquadA012B12CoefsSP_t LVCS_EqualiserCoefTable[] = {
+ /* Headphone coefficients */
+ {CS_EQUALISER_8000_A0, /* 8kS/s coefficients */
+ CS_EQUALISER_8000_A1,
+ CS_EQUALISER_8000_A2,
+ CS_EQUALISER_8000_B1,
+ CS_EQUALISER_8000_B2,
+ (LVM_UINT16 )CS_EQUALISER_8000_SCALE},
+ {CS_EQUALISER_11025_A0, /* 11kS/s coefficients */
+ CS_EQUALISER_11025_A1,
+ CS_EQUALISER_11025_A2,
+ CS_EQUALISER_11025_B1,
+ CS_EQUALISER_11025_B2,
+ (LVM_UINT16 )CS_EQUALISER_11025_SCALE},
+ {CS_EQUALISER_12000_A0, /* 12kS/s coefficients */
+ CS_EQUALISER_12000_A1,
+ CS_EQUALISER_12000_A2,
+ CS_EQUALISER_12000_B1,
+ CS_EQUALISER_12000_B2,
+ (LVM_UINT16 )CS_EQUALISER_12000_SCALE},
+ {CS_EQUALISER_16000_A0, /* 16kS/s coefficients */
+ CS_EQUALISER_16000_A1,
+ CS_EQUALISER_16000_A2,
+ CS_EQUALISER_16000_B1,
+ CS_EQUALISER_16000_B2,
+ (LVM_UINT16 )CS_EQUALISER_16000_SCALE},
+ {CS_EQUALISER_22050_A0, /* 22kS/s coefficients */
+ CS_EQUALISER_22050_A1,
+ CS_EQUALISER_22050_A2,
+ CS_EQUALISER_22050_B1,
+ CS_EQUALISER_22050_B2,
+ (LVM_UINT16 )CS_EQUALISER_22050_SCALE},
+ {CS_EQUALISER_24000_A0, /* 24kS/s coefficients */
+ CS_EQUALISER_24000_A1,
+ CS_EQUALISER_24000_A2,
+ CS_EQUALISER_24000_B1,
+ CS_EQUALISER_24000_B2,
+ (LVM_UINT16 )CS_EQUALISER_24000_SCALE},
+ {CS_EQUALISER_32000_A0, /* 32kS/s coefficients */
+ CS_EQUALISER_32000_A1,
+ CS_EQUALISER_32000_A2,
+ CS_EQUALISER_32000_B1,
+ CS_EQUALISER_32000_B2,
+ (LVM_UINT16 )CS_EQUALISER_32000_SCALE},
+ {CS_EQUALISER_44100_A0, /* 44kS/s coefficients */
+ CS_EQUALISER_44100_A1,
+ CS_EQUALISER_44100_A2,
+ CS_EQUALISER_44100_B1,
+ CS_EQUALISER_44100_B2,
+ (LVM_UINT16 )CS_EQUALISER_44100_SCALE},
+ {CS_EQUALISER_48000_A0, /* 48kS/s coefficients */
+ CS_EQUALISER_48000_A1,
+ CS_EQUALISER_48000_A2,
+ CS_EQUALISER_48000_B1,
+ CS_EQUALISER_48000_B2,
+ (LVM_UINT16 )CS_EQUALISER_48000_SCALE},
+ {CS_EQUALISER_88200_A0, /* 88kS/s coeffieients */
+ CS_EQUALISER_88200_A1,
+ CS_EQUALISER_88200_A2,
+ CS_EQUALISER_88200_B1,
+ CS_EQUALISER_88200_B2,
+ (LVM_UINT16)CS_EQUALISER_88200_SCALE},
+ {CS_EQUALISER_96000_A0, /* 96kS/s coefficients */
+ CS_EQUALISER_96000_A1,
+ CS_EQUALISER_96000_A2,
+ CS_EQUALISER_96000_B1,
+ CS_EQUALISER_96000_B2,
+ (LVM_UINT16 )CS_EQUALISER_96000_SCALE},
+ {CS_EQUALISER_176400_A0, /* 176kS/s coefficients */
+ CS_EQUALISER_176400_A1,
+ CS_EQUALISER_176400_A2,
+ CS_EQUALISER_176400_B1,
+ CS_EQUALISER_176400_B2,
+ (LVM_UINT16)CS_EQUALISER_176400_SCALE},
+ {CS_EQUALISER_192000_A0, /* 192kS/s coefficients */
+ CS_EQUALISER_192000_A1,
+ CS_EQUALISER_192000_A2,
+ CS_EQUALISER_192000_B1,
+ CS_EQUALISER_192000_B2,
+ (LVM_UINT16 )CS_EQUALISER_192000_SCALE},
+
+ /* Concert Sound EX Headphone coefficients */
+ {CSEX_EQUALISER_8000_A0, /* 8kS/s coefficients */
+ CSEX_EQUALISER_8000_A1,
+ CSEX_EQUALISER_8000_A2,
+ CSEX_EQUALISER_8000_B1,
+ CSEX_EQUALISER_8000_B2,
+ (LVM_UINT16 )CSEX_EQUALISER_8000_SCALE},
+ {CSEX_EQUALISER_11025_A0, /* 11kS/s coefficients */
+ CSEX_EQUALISER_11025_A1,
+ CSEX_EQUALISER_11025_A2,
+ CSEX_EQUALISER_11025_B1,
+ CSEX_EQUALISER_11025_B2,
+ (LVM_UINT16 )CSEX_EQUALISER_11025_SCALE},
+ {CSEX_EQUALISER_12000_A0, /* 12kS/s coefficients */
+ CSEX_EQUALISER_12000_A1,
+ CSEX_EQUALISER_12000_A2,
+ CSEX_EQUALISER_12000_B1,
+ CSEX_EQUALISER_12000_B2,
+ (LVM_UINT16 )CSEX_EQUALISER_12000_SCALE},
+ {CSEX_EQUALISER_16000_A0, /* 16kS/s coefficients */
+ CSEX_EQUALISER_16000_A1,
+ CSEX_EQUALISER_16000_A2,
+ CSEX_EQUALISER_16000_B1,
+ CSEX_EQUALISER_16000_B2,
+ (LVM_UINT16 )CSEX_EQUALISER_16000_SCALE},
+ {CSEX_EQUALISER_22050_A0, /* 22kS/s coefficients */
+ CSEX_EQUALISER_22050_A1,
+ CSEX_EQUALISER_22050_A2,
+ CSEX_EQUALISER_22050_B1,
+ CSEX_EQUALISER_22050_B2,
+ (LVM_UINT16 )CSEX_EQUALISER_22050_SCALE},
+ {CSEX_EQUALISER_24000_A0, /* 24kS/s coefficients */
+ CSEX_EQUALISER_24000_A1,
+ CSEX_EQUALISER_24000_A2,
+ CSEX_EQUALISER_24000_B1,
+ CSEX_EQUALISER_24000_B2,
+ (LVM_UINT16 )CSEX_EQUALISER_24000_SCALE},
+ {CSEX_EQUALISER_32000_A0, /* 32kS/s coefficients */
+ CSEX_EQUALISER_32000_A1,
+ CSEX_EQUALISER_32000_A2,
+ CSEX_EQUALISER_32000_B1,
+ CSEX_EQUALISER_32000_B2,
+ (LVM_UINT16 )CSEX_EQUALISER_32000_SCALE},
+ {CSEX_EQUALISER_44100_A0, /* 44kS/s coefficients */
+ CSEX_EQUALISER_44100_A1,
+ CSEX_EQUALISER_44100_A2,
+ CSEX_EQUALISER_44100_B1,
+ CSEX_EQUALISER_44100_B2,
+ (LVM_UINT16 )CSEX_EQUALISER_44100_SCALE},
+ {CSEX_EQUALISER_48000_A0, /* 48kS/s coefficients */
+ CSEX_EQUALISER_48000_A1,
+ CSEX_EQUALISER_48000_A2,
+ CSEX_EQUALISER_48000_B1,
+ CSEX_EQUALISER_48000_B2,
+ (LVM_UINT16 )CSEX_EQUALISER_48000_SCALE}
+ ,
+ {CSEX_EQUALISER_88200_A0, /* 88kS/s coefficients */
+ CSEX_EQUALISER_88200_A1,
+ CSEX_EQUALISER_88200_A2,
+ CSEX_EQUALISER_88200_B1,
+ CSEX_EQUALISER_88200_B2,
+ (LVM_UINT16)CSEX_EQUALISER_88200_SCALE},
+ {CSEX_EQUALISER_96000_A0, /* 96kS/s coefficients */
+ CSEX_EQUALISER_96000_A1,
+ CSEX_EQUALISER_96000_A2,
+ CSEX_EQUALISER_96000_B1,
+ CSEX_EQUALISER_96000_B2,
+ (LVM_UINT16 )CSEX_EQUALISER_96000_SCALE},
+ {CSEX_EQUALISER_176400_A0, /* 176kS/s coefficients */
+ CSEX_EQUALISER_176400_A1,
+ CSEX_EQUALISER_176400_A2,
+ CSEX_EQUALISER_176400_B1,
+ CSEX_EQUALISER_176400_B2,
+ (LVM_UINT16)CSEX_EQUALISER_176400_SCALE},
+ {CSEX_EQUALISER_192000_A0, /* 192kS/s coefficients */
+ CSEX_EQUALISER_192000_A1,
+ CSEX_EQUALISER_192000_A2,
+ CSEX_EQUALISER_192000_B1,
+ CSEX_EQUALISER_192000_B2,
+ (LVM_UINT16 )CSEX_EQUALISER_192000_SCALE}
+};
+
+/************************************************************************************/
+/* */
+/* Reverb delay constant tables */
+/* */
+/************************************************************************************/
+
+/* Stereo delay table for Concert Sound */
+const LVM_UINT16 LVCS_StereoDelayCS[] = {
+ LVCS_STEREODELAY_CS_8KHZ,
+ LVCS_STEREODELAY_CS_11KHZ,
+ LVCS_STEREODELAY_CS_12KHZ,
+ LVCS_STEREODELAY_CS_16KHZ,
+ LVCS_STEREODELAY_CS_22KHZ,
+ LVCS_STEREODELAY_CS_24KHZ,
+ LVCS_STEREODELAY_CS_32KHZ,
+ LVCS_STEREODELAY_CS_44KHZ,
+ LVCS_STEREODELAY_CS_48KHZ,
+ LVCS_STEREODELAY_CS_88KHZ,
+ LVCS_STEREODELAY_CS_96KHZ,
+ LVCS_STEREODELAY_CS_176KHZ,
+ LVCS_STEREODELAY_CS_192KHZ,
+};
+
+/************************************************************************************/
+/* */
+/* Reverb coefficients constant table */
+/* */
+/************************************************************************************/
+
+const BiquadA012B12CoefsSP_t LVCS_ReverbCoefTable[] = {
+ /* Headphone coefficients */
+ {CS_REVERB_8000_A0, /* 8kS/s coefficients */
+ CS_REVERB_8000_A1,
+ CS_REVERB_8000_A2,
+ CS_REVERB_8000_B1,
+ CS_REVERB_8000_B2,
+ (LVM_UINT16 )CS_REVERB_8000_SCALE},
+ {CS_REVERB_11025_A0, /* 11kS/s coefficients */
+ CS_REVERB_11025_A1,
+ CS_REVERB_11025_A2,
+ CS_REVERB_11025_B1,
+ CS_REVERB_11025_B2,
+ (LVM_UINT16 )CS_REVERB_11025_SCALE},
+ {CS_REVERB_12000_A0, /* 12kS/s coefficients */
+ CS_REVERB_12000_A1,
+ CS_REVERB_12000_A2,
+ CS_REVERB_12000_B1,
+ CS_REVERB_12000_B2,
+ (LVM_UINT16 )CS_REVERB_12000_SCALE},
+ {CS_REVERB_16000_A0, /* 16kS/s coefficients */
+ CS_REVERB_16000_A1,
+ CS_REVERB_16000_A2,
+ CS_REVERB_16000_B1,
+ CS_REVERB_16000_B2,
+ (LVM_UINT16 )CS_REVERB_16000_SCALE},
+ {CS_REVERB_22050_A0, /* 22kS/s coefficients */
+ CS_REVERB_22050_A1,
+ CS_REVERB_22050_A2,
+ CS_REVERB_22050_B1,
+ CS_REVERB_22050_B2,
+ (LVM_UINT16 )CS_REVERB_22050_SCALE},
+ {CS_REVERB_24000_A0, /* 24kS/s coefficients */
+ CS_REVERB_24000_A1,
+ CS_REVERB_24000_A2,
+ CS_REVERB_24000_B1,
+ CS_REVERB_24000_B2,
+ (LVM_UINT16 )CS_REVERB_24000_SCALE},
+ {CS_REVERB_32000_A0, /* 32kS/s coefficients */
+ CS_REVERB_32000_A1,
+ CS_REVERB_32000_A2,
+ CS_REVERB_32000_B1,
+ CS_REVERB_32000_B2,
+ (LVM_UINT16 )CS_REVERB_32000_SCALE},
+ {CS_REVERB_44100_A0, /* 44kS/s coefficients */
+ CS_REVERB_44100_A1,
+ CS_REVERB_44100_A2,
+ CS_REVERB_44100_B1,
+ CS_REVERB_44100_B2,
+ (LVM_UINT16 )CS_REVERB_44100_SCALE},
+ {CS_REVERB_48000_A0, /* 48kS/s coefficients */
+ CS_REVERB_48000_A1,
+ CS_REVERB_48000_A2,
+ CS_REVERB_48000_B1,
+ CS_REVERB_48000_B2,
+ (LVM_UINT16 )CS_REVERB_48000_SCALE}
+ ,
+ {CS_REVERB_88200_A0, /* 88kS/s coefficients */
+ CS_REVERB_88200_A1,
+ CS_REVERB_88200_A2,
+ CS_REVERB_88200_B1,
+ CS_REVERB_88200_B2,
+ (LVM_UINT16)CS_REVERB_88200_SCALE},
+ {CS_REVERB_96000_A0, /* 96kS/s coefficients */
+ CS_REVERB_96000_A1,
+ CS_REVERB_96000_A2,
+ CS_REVERB_96000_B1,
+ CS_REVERB_96000_B2,
+ (LVM_UINT16 )CS_REVERB_96000_SCALE},
+ {CS_REVERB_176400_A0, /* 176kS/s coefficients */
+ CS_REVERB_176400_A1,
+ CS_REVERB_176400_A2,
+ CS_REVERB_176400_B1,
+ CS_REVERB_176400_B2,
+ (LVM_UINT16)CS_REVERB_176400_SCALE},
+ {CS_REVERB_192000_A0, /* 192kS/s coefficients */
+ CS_REVERB_192000_A1,
+ CS_REVERB_192000_A2,
+ CS_REVERB_192000_B1,
+ CS_REVERB_192000_B2,
+ (LVM_UINT16 )CS_REVERB_192000_SCALE}
+};
+
+/************************************************************************************/
+/* */
+/* Bypass mixer constant tables */
+/* */
+/************************************************************************************/
+
+const Gain_t LVCS_OutputGainTable[] = {
+ {LVCS_HEADPHONE_SHIFT, /* Headphone, stereo mode */
+ LVCS_HEADPHONE_SHIFTLOSS,
+ LVCS_HEADPHONE_GAIN},
+ {LVCS_EX_HEADPHONE_SHIFT, /* EX Headphone, stereo mode */
+ LVCS_EX_HEADPHONE_SHIFTLOSS,
+ LVCS_EX_HEADPHONE_GAIN},
+ {LVCS_HEADPHONE_SHIFT, /* Headphone, mono mode */
+ LVCS_HEADPHONE_SHIFTLOSS,
+ LVCS_HEADPHONE_GAIN},
+ {LVCS_EX_HEADPHONE_SHIFT, /* EX Headphone, mono mode */
+ LVCS_EX_HEADPHONE_SHIFTLOSS,
+ LVCS_EX_HEADPHONE_GAIN}
+};
+
+/************************************************************************************/
+/* */
+/* Volume correction table */
+/* */
+/* Coefficient order: */
+/* Compression 100% effect */
+/* Compression 0% effect */
+/* Gain 100% effect */
+/* Gain 0% effect */
+/* */
+/* The Compression gain is represented by a Q1.15 number to give a range of 0dB */
+/* to +6dB, E.g.: */
+/* 0 is 0dB compression (no effect) */
+/* 5461 is 1dB compression gain */
+/* 10923 is 2dB compression gain */
+/* 32767 is 6dB compression gain */
+/* */
+/* The Gain is represented as a Q3.13 number to give a range of +8 to -infinity */
+/* E.g.: */
+/* 0 is -infinity */
+/* 32767 is +18dB (x8) gain */
+/* 4096 is 0dB gain */
+/* 1024 is -12dB gain */
+/* */
+/************************************************************************************/
+const LVCS_VolCorrect_t LVCS_VolCorrectTable[] = {
+ {0.433362f, /* Headphone, stereo mode */
+ 0.000000f,
+ 1.000024f,
+ 1.412640f},
+ {0.433362f, /* EX Headphone, stereo mode */
+ 0.000000f,
+ 1.000024f,
+ 1.412640f},
+ {1.000000f, /* Headphone, mono mode */
+ 0.000000f,
+ 1.000024f,
+ 1.412640f},
+ {1.000000f, /* EX Headphone, mono mode */
+ 0.000000f,
+ 1.000024f,
+ 1.412640f}
+};
+
+/************************************************************************************/
+/* */
+/* Mixer time constants, 100ms */
+/* */
+/************************************************************************************/
+
+#define LVCS_VOL_TC_Fs8000 32580 /* Floating point value 0.994262695 */
+#define LVCS_VOL_TC_Fs11025 32632 /* Floating point value 0.995849609 */
+#define LVCS_VOL_TC_Fs12000 32643 /* Floating point value 0.996185303 */
+#define LVCS_VOL_TC_Fs16000 32674 /* Floating point value 0.997131348 */
+#define LVCS_VOL_TC_Fs22050 32700 /* Floating point value 0.997924805 */
+#define LVCS_VOL_TC_Fs24000 32705 /* Floating point value 0.998077393 */
+#define LVCS_VOL_TC_Fs32000 32721 /* Floating point value 0.998565674 */
+#define LVCS_VOL_TC_Fs44100 32734 /* Floating point value 0.998962402 */
+#define LVCS_VOL_TC_Fs48000 32737 /* Floating point value 0.999053955 */
+#define LVCS_VOL_TC_Fs88200 32751 /* Floating point value 0.999481066 */
+#define LVCS_VOL_TC_Fs96000 32751 /* Floating point value 0.999511703 */ /* Todo @ need to re check this value*/
+#define LVCS_VOL_TC_Fs176400 32759 /* Floating point value 0.999740499 */
+#define LVCS_VOL_TC_Fs192000 32763 /* Floating point value 0.999877925 */ /* Todo @ need to re check this value*/
+
+const LVM_INT16 LVCS_VolumeTCTable[13] = {LVCS_VOL_TC_Fs8000,
+ LVCS_VOL_TC_Fs11025,
+ LVCS_VOL_TC_Fs12000,
+ LVCS_VOL_TC_Fs16000,
+ LVCS_VOL_TC_Fs22050,
+ LVCS_VOL_TC_Fs24000,
+ LVCS_VOL_TC_Fs32000,
+ LVCS_VOL_TC_Fs44100,
+ LVCS_VOL_TC_Fs48000,
+ LVCS_VOL_TC_Fs88200,
+ LVCS_VOL_TC_Fs96000,
+ LVCS_VOL_TC_Fs176400,
+ LVCS_VOL_TC_Fs192000
+};
+
+/************************************************************************************/
+/* */
+/* Sample rate table */
+/* */
+/************************************************************************************/
+const LVM_INT32 LVCS_SampleRateTable[13] = {8000,
+ 11025,
+ 12000,
+ 16000,
+ 22050,
+ 24000,
+ 32000,
+ 44100,
+ 48000,
+ 88200,
+ 96000,
+ 176400,
+ 192000
+};
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Tables.h b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Tables.h
index 3f6c4c8..5490699 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Tables.h
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Tables.h
@@ -18,10 +18,6 @@
#ifndef __LVCS_TABLES_H__
#define __LVCS_TABLES_H__
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
/************************************************************************************/
/* */
/* Includes */
@@ -104,15 +100,13 @@
extern const LVCS_VolCorrect_t LVCS_VolCorrectTable[];
extern const LVM_INT16 LVCS_VolumeTCTable[];
-
/************************************************************************************/
/* */
/* Sample rates */
/* */
/************************************************************************************/
-extern LVM_INT32 LVCS_SampleRateTable[];
-
+extern const LVM_INT32 LVCS_SampleRateTable[];
/*Speaker coeffient tables*/
extern LVM_UINT16 LVCS_MS_Small_SEMiddleGainTable[];
@@ -142,11 +136,5 @@
extern LVCS_VolCorrect_t LVCS_MS_Large_VolCorrectTable[];
extern LVM_UINT16 LVCS_MS_Large_ReverbGainTable[];
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
#endif /* __LVCS_TABLES_H__ */
diff --git a/media/libeffects/lvm/tests/Android.bp b/media/libeffects/lvm/tests/Android.bp
index 003ce9e..674c246 100644
--- a/media/libeffects/lvm/tests/Android.bp
+++ b/media/libeffects/lvm/tests/Android.bp
@@ -35,8 +35,6 @@
srcs: ["lvmtest.cpp"],
cflags: [
- "-DBUILD_FLOAT",
- "-DHIGHER_FS",
"-DSUPPORT_MC",
"-Wall",
diff --git a/media/libeffects/lvm/tests/lvmtest.cpp b/media/libeffects/lvm/tests/lvmtest.cpp
index 5b58dd1..a4ace6c 100644
--- a/media/libeffects/lvm/tests/lvmtest.cpp
+++ b/media/libeffects/lvm/tests/lvmtest.cpp
@@ -482,10 +482,6 @@
pContext->pBundledContext->SamplesToExitCountVirt = 0;
pContext->pBundledContext->SamplesToExitCountBb = 0;
pContext->pBundledContext->SamplesToExitCountEq = 0;
-#if defined(BUILD_FLOAT) && !defined(NATIVE_FLOAT_BUFFER)
- pContext->pBundledContext->pInputBuffer = NULL;
- pContext->pBundledContext->pOutputBuffer = NULL;
-#endif
for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
pContext->pBundledContext->bandGaindB[i] = EQNB_5BandSoftPresets[i];
}
diff --git a/media/libeffects/lvm/wrapper/Android.bp b/media/libeffects/lvm/wrapper/Android.bp
index 16fa126..afc4220 100644
--- a/media/libeffects/lvm/wrapper/Android.bp
+++ b/media/libeffects/lvm/wrapper/Android.bp
@@ -1,6 +1,3 @@
-// The wrapper -DBUILD_FLOAT needs to match
-// the lvm library -DBUILD_FLOAT.
-
// music bundle wrapper
cc_library_shared {
name: "libbundlewrapper",
@@ -14,10 +11,8 @@
vendor: true,
srcs: ["Bundle/EffectBundle.cpp"],
- cflags: [
+ cppflags: [
"-fvisibility=hidden",
- "-DBUILD_FLOAT",
- "-DHIGHER_FS",
"-DSUPPORT_MC",
"-Wall",
@@ -56,10 +51,8 @@
vendor: true,
srcs: ["Reverb/EffectReverb.cpp"],
- cflags: [
+ cppflags: [
"-fvisibility=hidden",
- "-DBUILD_FLOAT",
- "-DHIGHER_FS",
"-Wall",
"-Werror",
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 10dda19..6fca0e7 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -81,7 +81,6 @@
} \
}
-
// NXP SW BassBoost UUID
const effect_descriptor_t gBassBoostDescriptor = {
{0x0634f220, 0xddd4, 0x11db, 0xa0fc, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b }},
@@ -258,26 +257,6 @@
pContext->pBundledContext->firstVolume = LVM_TRUE;
pContext->pBundledContext->volume = 0;
- #ifdef LVM_PCM
- char fileName[256];
- snprintf(fileName, 256, "/data/tmp/bundle_%p_pcm_in.pcm", pContext->pBundledContext);
- pContext->pBundledContext->PcmInPtr = fopen(fileName, "w");
- if (pContext->pBundledContext->PcmInPtr == NULL) {
- ALOGV("cannot open %s", fileName);
- ret = -EINVAL;
- goto exit;
- }
-
- snprintf(fileName, 256, "/data/tmp/bundle_%p_pcm_out.pcm", pContext->pBundledContext);
- pContext->pBundledContext->PcmOutPtr = fopen(fileName, "w");
- if (pContext->pBundledContext->PcmOutPtr == NULL) {
- ALOGV("cannot open %s", fileName);
- fclose(pContext->pBundledContext->PcmInPtr);
- pContext->pBundledContext->PcmInPtr = NULL;
- ret = -EINVAL;
- goto exit;
- }
- #endif
/* Saved strength is used to return the exact strength that was used in the set to the get
* because we map the original strength range of 0:1000 to 1:15, and this will avoid
@@ -295,10 +274,6 @@
pContext->pBundledContext->SamplesToExitCountVirt = 0;
pContext->pBundledContext->SamplesToExitCountBb = 0;
pContext->pBundledContext->SamplesToExitCountEq = 0;
-#if defined(BUILD_FLOAT) && !defined(NATIVE_FLOAT_BUFFER)
- pContext->pBundledContext->pInputBuffer = NULL;
- pContext->pBundledContext->pOutputBuffer = NULL;
-#endif
for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
pContext->pBundledContext->bandGaindB[i] = EQNB_5BandSoftPresets[i];
}
@@ -443,17 +418,6 @@
(pSessionContext->bEqualizerInstantiated ==LVM_FALSE) &&
(pSessionContext->bVirtualizerInstantiated==LVM_FALSE))
{
-#ifdef LVM_PCM
- if (pContext->pBundledContext->PcmInPtr != NULL) {
- fclose(pContext->pBundledContext->PcmInPtr);
- pContext->pBundledContext->PcmInPtr = NULL;
- }
- if (pContext->pBundledContext->PcmOutPtr != NULL) {
- fclose(pContext->pBundledContext->PcmOutPtr);
- pContext->pBundledContext->PcmOutPtr = NULL;
- }
-#endif
-
// Clear the SessionIndex
for(int i=0; i<LVM_MAX_SESSIONS; i++){
@@ -474,10 +438,6 @@
if (pContext->pBundledContext->workBuffer != NULL) {
free(pContext->pBundledContext->workBuffer);
}
-#if defined(BUILD_FLOAT) && !defined(NATIVE_FLOAT_BUFFER)
- free(pContext->pBundledContext->pInputBuffer);
- free(pContext->pBundledContext->pOutputBuffer);
-#endif
delete pContext->pBundledContext;
pContext->pBundledContext = LVM_NULL;
}
@@ -759,7 +719,6 @@
// pOut: pointer to updated stereo 16 bit output data
//
//----------------------------------------------------------------------------
-#ifdef BUILD_FLOAT
int LvmBundle_process(effect_buffer_t *pIn,
effect_buffer_t *pOut,
int frameCount,
@@ -769,30 +728,6 @@
effect_buffer_t *pOutTmp;
const LVM_INT32 NrChannels =
audio_channel_count_from_out_mask(pContext->config.inputCfg.channels);
-#ifndef NATIVE_FLOAT_BUFFER
- if (pContext->pBundledContext->pInputBuffer == nullptr ||
- pContext->pBundledContext->frameCount < frameCount) {
- free(pContext->pBundledContext->pInputBuffer);
- pContext->pBundledContext->pInputBuffer =
- (LVM_FLOAT *)calloc(frameCount, sizeof(LVM_FLOAT) * NrChannels);
- }
-
- if (pContext->pBundledContext->pOutputBuffer == nullptr ||
- pContext->pBundledContext->frameCount < frameCount) {
- free(pContext->pBundledContext->pOutputBuffer);
- pContext->pBundledContext->pOutputBuffer =
- (LVM_FLOAT *)calloc(frameCount, sizeof(LVM_FLOAT) * NrChannels);
- }
-
- if (pContext->pBundledContext->pInputBuffer == nullptr ||
- pContext->pBundledContext->pOutputBuffer == nullptr) {
- ALOGE("LVM_ERROR : LvmBundle_process memory allocation for float buffer's failed");
- return -EINVAL;
- }
-
- LVM_FLOAT * const pInputBuff = pContext->pBundledContext->pInputBuffer;
- LVM_FLOAT * const pOutputBuff = pContext->pBundledContext->pOutputBuffer;
-#endif
if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_WRITE){
pOutTmp = pOut;
@@ -814,123 +749,25 @@
return -EINVAL;
}
-#ifdef LVM_PCM
- fwrite(pIn,
- frameCount * sizeof(effect_buffer_t) * NrChannels,
- 1,
- pContext->pBundledContext->PcmInPtr);
- fflush(pContext->pBundledContext->PcmInPtr);
-#endif
-#ifndef NATIVE_FLOAT_BUFFER
- /* Converting input data from fixed point to float point */
- memcpy_to_float_from_i16(pInputBuff, pIn, frameCount * NrChannels);
-
- /* Process the samples */
- LvmStatus = LVM_Process(pContext->pBundledContext->hInstance, /* Instance handle */
- pInputBuff, /* Input buffer */
- pOutputBuff, /* Output buffer */
- (LVM_UINT16)frameCount, /* Number of samples to read */
- 0); /* Audio Time */
-
- /* Converting output data from float point to fixed point */
- memcpy_to_i16_from_float(pOutTmp, pOutputBuff, frameCount * NrChannels);
-
-#else
/* Process the samples */
LvmStatus = LVM_Process(pContext->pBundledContext->hInstance, /* Instance handle */
pIn, /* Input buffer */
pOutTmp, /* Output buffer */
(LVM_UINT16)frameCount, /* Number of samples to read */
0); /* Audio Time */
-#endif
LVM_ERROR_CHECK(LvmStatus, "LVM_Process", "LvmBundle_process")
if(LvmStatus != LVM_SUCCESS) return -EINVAL;
-#ifdef LVM_PCM
- fwrite(pOutTmp,
- frameCount * sizeof(effect_buffer_t) * NrChannels,
- 1,
- pContext->pBundledContext->PcmOutPtr);
- fflush(pContext->pBundledContext->PcmOutPtr);
-#endif
if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
for (int i = 0; i < frameCount * NrChannels; i++) {
-#ifndef NATIVE_FLOAT_BUFFER
- pOut[i] = clamp16((LVM_INT32)pOut[i] + (LVM_INT32)pOutTmp[i]);
-#else
pOut[i] = pOut[i] + pOutTmp[i];
-#endif
}
}
return 0;
} /* end LvmBundle_process */
-#else // BUILD_FLOAT
-
-int LvmBundle_process(LVM_INT16 *pIn,
- LVM_INT16 *pOut,
- int frameCount,
- EffectContext *pContext) {
-
- LVM_ReturnStatus_en LvmStatus = LVM_SUCCESS; /* Function call status */
- LVM_INT16 *pOutTmp;
-
- if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_WRITE){
- pOutTmp = pOut;
- } else if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
- if (pContext->pBundledContext->frameCount != frameCount) {
- if (pContext->pBundledContext->workBuffer != NULL) {
- free(pContext->pBundledContext->workBuffer);
- }
- pContext->pBundledContext->workBuffer =
- (effect_buffer_t *)calloc(frameCount, sizeof(effect_buffer_t) * FCC_2);
- if (pContext->pBundledContext->workBuffer == NULL) {
- return -ENOMEM;
- }
- pContext->pBundledContext->frameCount = frameCount;
- }
- pOutTmp = pContext->pBundledContext->workBuffer;
- } else {
- ALOGV("LVM_ERROR : LvmBundle_process invalid access mode");
- return -EINVAL;
- }
-
-#ifdef LVM_PCM
- fwrite(pIn, frameCount * sizeof(*pIn) * FCC_2,
- 1 /* nmemb */, pContext->pBundledContext->PcmInPtr);
- fflush(pContext->pBundledContext->PcmInPtr);
-#endif
-
- //ALOGV("Calling LVM_Process");
-
- /* Process the samples */
- LvmStatus = LVM_Process(pContext->pBundledContext->hInstance, /* Instance handle */
- pIn, /* Input buffer */
- pOutTmp, /* Output buffer */
- (LVM_UINT16)frameCount, /* Number of samples to read */
- 0); /* Audio Time */
-
- LVM_ERROR_CHECK(LvmStatus, "LVM_Process", "LvmBundle_process")
- if(LvmStatus != LVM_SUCCESS) return -EINVAL;
-
-#ifdef LVM_PCM
- fwrite(pOutTmp, frameCount * sizeof(*pOutTmp) * FCC_2,
- 1 /* nmemb */, pContext->pBundledContext->PcmOutPtr);
- fflush(pContext->pBundledContext->PcmOutPtr);
-#endif
-
- if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
- for (int i=0; i<frameCount*2; i++){
- pOut[i] = clamp16((LVM_INT32)pOut[i] + (LVM_INT32)pOutTmp[i]);
- }
- }
- return 0;
-} /* end LvmBundle_process */
-
-#endif // BUILD_FLOAT
-
//----------------------------------------------------------------------------
// EqualizerUpdateActiveParams()
//----------------------------------------------------------------------------
@@ -953,7 +790,6 @@
//ALOGV("\tEqualizerUpdateActiveParams just Got -> %d\n",
// ActiveParams.pEQNB_BandDefinition[band].Gain);
-
for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
ActiveParams.pEQNB_BandDefinition[i].Frequency = EQNB_5BandPresetsFrequencies[i];
ActiveParams.pEQNB_BandDefinition[i].QFactor = EQNB_5BandPresetsQFactors[i];
@@ -1290,7 +1126,6 @@
SampleRate = LVM_FS_48000;
pContext->pBundledContext->SamplesPerSecond = 48000 * NrChannels;
break;
-#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
case 88200:
SampleRate = LVM_FS_88200;
pContext->pBundledContext->SamplesPerSecond = 88200 * NrChannels;
@@ -1307,7 +1142,6 @@
SampleRate = LVM_FS_192000;
pContext->pBundledContext->SamplesPerSecond = 192000 * NrChannels;
break;
-#endif
default:
ALOGV("\tEffect_setConfig invalid sampling rate %d", pConfig->inputCfg.samplingRate);
return -EINVAL;
@@ -2051,8 +1885,6 @@
LVM_ReturnStatus_en LvmStatus=LVM_SUCCESS; /* Function call status */
LVM_INT16 Balance = 0;
-
-
pContext->pBundledContext->positionSaved = position;
Balance = VolumeConvertStereoPosition(pContext->pBundledContext->positionSaved);
@@ -2097,7 +1929,6 @@
return 0;
} /* end VolumeSetStereoPosition */
-
//----------------------------------------------------------------------------
// VolumeGetStereoPosition()
//----------------------------------------------------------------------------
@@ -2710,7 +2541,7 @@
name[*pValueSize - 1] = 0;
*pValueSize = strlen(name) + 1;
ALOGVV("%s EQ_PARAM_GET_PRESET_NAME preset %d, name %s len %d",
- __func__, preset, gEqualizerPresets[preset].name, *pValueSize);
+ __func__, preset, name, *pValueSize);
} break;
@@ -2970,7 +2801,6 @@
return status;
} /* end Volume_getParameter */
-
//----------------------------------------------------------------------------
// Volume_setParameter()
//----------------------------------------------------------------------------
@@ -3422,17 +3252,10 @@
pContext->pBundledContext->NumberEffectsCalled = 0;
/* Process all the available frames, block processing is
handled internalLY by the LVM bundle */
-#ifdef NATIVE_FLOAT_BUFFER
processStatus = android::LvmBundle_process(inBuffer->f32,
outBuffer->f32,
outBuffer->frameCount,
pContext);
-#else
- processStatus = android::LvmBundle_process(inBuffer->s16,
- outBuffer->s16,
- outBuffer->frameCount,
- pContext);
-#endif
if (processStatus != 0){
ALOGV("\tLVM_ERROR : LvmBundle_process returned error %d", processStatus);
if (status == 0) {
@@ -3447,11 +3270,7 @@
if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
for (size_t i = 0; i < outBuffer->frameCount * NrChannels; ++i) {
-#ifdef NATIVE_FLOAT_BUFFER
outBuffer->f32[i] += inBuffer->f32[i];
-#else
- outBuffer->s16[i] = clamp16((LVM_INT32)outBuffer->s16[i] + inBuffer->s16[i]);
-#endif
}
} else if (outBuffer->raw != inBuffer->raw) {
memcpy(outBuffer->raw,
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
index e4aacd0..524e103 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
@@ -23,10 +23,6 @@
#include <LVM.h>
#include <limits.h>
-#if __cplusplus
-extern "C" {
-#endif
-
#define FIVEBAND_NUMBANDS 5
#define MAX_NUM_BANDS 5
#define MAX_CALL_SIZE 256
@@ -37,7 +33,6 @@
#define EQUALIZER_CUP_LOAD_ARM9E 220 // Expressed in 0.1 MIPS
#define VOLUME_CUP_LOAD_ARM9E 0 // Expressed in 0.1 MIPS
#define BUNDLE_MEM_USAGE 25 // Expressed in kB
-//#define LVM_PCM
#ifndef OPENSL_ES_H_
static const effect_uuid_t SL_IID_VOLUME_ = { 0x09e8ede0, 0xddde, 0x11db, 0xb4f6,
@@ -99,14 +94,6 @@
int frameCount;
int32_t bandGaindB[FIVEBAND_NUMBANDS];
int volume;
- #ifdef LVM_PCM
- FILE *PcmInPtr;
- FILE *PcmOutPtr;
- #endif
-#if defined(BUILD_FLOAT) && !defined(NATIVE_FLOAT_BUFFER)
- LVM_FLOAT *pInputBuffer;
- LVM_FLOAT *pOutputBuffer;
-#endif
#ifdef SUPPORT_MC
LVM_INT32 ChMask;
#endif
@@ -137,7 +124,6 @@
BundledEffectContext *pBundledContext;
};
-
/* enumerated parameter settings for Volume effect */
typedef enum
{
@@ -228,9 +214,4 @@
static const float LimitLevel_virtualizerContribution = 1.9;
-#if __cplusplus
-} // extern "C"
-#endif
-
-
#endif /*ANDROID_EFFECTBUNDLE_H_*/
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index 602f607..1cb81a6 100644
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -79,7 +79,6 @@
{-400, -200, 1300, 900, 0, 2, 0, 10, 1000, 750},
};
-
// NXP SW auxiliary environmental reverb
const effect_descriptor_t gAuxEnvReverbDescriptor = {
{ 0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac, { 0x4e, 0x23, 0x4d, 0x06, 0x83, 0x9e } },
@@ -136,11 +135,7 @@
&gInsertPresetReverbDescriptor
};
-#ifdef BUILD_FLOAT
typedef float process_buffer_t; // process in float
-#else
-typedef int32_t process_buffer_t; // process in Q4_27
-#endif // BUILD_FLOAT
struct ReverbContext{
const struct effect_interface_s *itfe;
@@ -154,10 +149,6 @@
int16_t SavedDiffusion;
int16_t SavedDensity;
bool bEnabled;
- #ifdef LVM_PCM
- FILE *PcmInPtr;
- FILE *PcmOutPtr;
- #endif
LVM_Fs_en SampleRate;
process_buffer_t *InFrames;
process_buffer_t *OutFrames;
@@ -183,11 +174,7 @@
#define REVERB_DEFAULT_PRESET REVERB_PRESET_NONE
-#ifdef BUILD_FLOAT
#define REVERB_SEND_LEVEL 0.75f // 0.75 in 4.12 format
-#else
-#define REVERB_SEND_LEVEL (0x0C00) // 0.75 in 4.12 format
-#endif
#define REVERB_UNIT_VOLUME (0x1000) // 1.0 in 4.12 format
//--- local function prototypes
@@ -269,18 +256,6 @@
*pHandle = (effect_handle_t)pContext;
-#ifdef LVM_PCM
- pContext->PcmInPtr = NULL;
- pContext->PcmOutPtr = NULL;
-
- pContext->PcmInPtr = fopen("/data/tmp/reverb_pcm_in.pcm", "w");
- pContext->PcmOutPtr = fopen("/data/tmp/reverb_pcm_out.pcm", "w");
-
- if((pContext->PcmInPtr == NULL)||
- (pContext->PcmOutPtr == NULL)){
- return -EINVAL;
- }
-#endif
int channels = audio_channel_count_from_out_mask(pContext->config.inputCfg.channels);
@@ -304,10 +279,6 @@
return -EINVAL;
}
- #ifdef LVM_PCM
- fclose(pContext->PcmInPtr);
- fclose(pContext->PcmOutPtr);
- #endif
free(pContext->InFrames);
free(pContext->OutFrames);
pContext->bufferSizeIn = 0;
@@ -378,7 +349,6 @@
return -EINVAL;
}
-#ifdef BUILD_FLOAT
size_t inSize = frameCount * sizeof(process_buffer_t) * channels;
size_t outSize = frameCount * sizeof(process_buffer_t) * FCC_2;
if (pContext->InFrames == NULL ||
@@ -394,10 +364,6 @@
pContext->OutFrames = (process_buffer_t *)calloc(1, pContext->bufferSizeOut);
}
-#ifndef NATIVE_FLOAT_BUFFER
- effect_buffer_t * const OutFrames16 = (effect_buffer_t *)pContext->OutFrames;
-#endif
-#endif
// Check for NULL pointers
if ((pContext->InFrames == NULL) || (pContext->OutFrames == NULL)) {
@@ -405,47 +371,20 @@
return -EINVAL;
}
-#ifdef LVM_PCM
- fwrite(pIn, frameCount * sizeof(*pIn) * channels, 1 /* nmemb */, pContext->PcmInPtr);
- fflush(pContext->PcmInPtr);
-#endif
if (pContext->preset && pContext->nextPreset != pContext->curPreset) {
Reverb_LoadPreset(pContext);
}
if (pContext->auxiliary) {
-#ifdef BUILD_FLOAT
-#ifdef NATIVE_FLOAT_BUFFER
static_assert(std::is_same<decltype(*pIn), decltype(*pContext->InFrames)>::value,
"pIn and InFrames must be same type");
memcpy(pContext->InFrames, pIn, frameCount * channels * sizeof(*pIn));
-#else
- memcpy_to_float_from_i16(
- pContext->InFrames, pIn, frameCount * channels);
-#endif
-#else //no BUILD_FLOAT
- for (int i = 0; i < frameCount * channels; i++) {
- pContext->InFrames[i] = (process_buffer_t)pIn[i]<<8;
- }
-#endif
} else {
// insert reverb input is always stereo
for (int i = 0; i < frameCount; i++) {
-#ifdef BUILD_FLOAT
-#ifdef NATIVE_FLOAT_BUFFER
pContext->InFrames[2 * i] = (process_buffer_t)pIn[2 * i] * REVERB_SEND_LEVEL;
pContext->InFrames[2 * i + 1] = (process_buffer_t)pIn[2 * i + 1] * REVERB_SEND_LEVEL;
-#else
- pContext->InFrames[2 * i] =
- (process_buffer_t)pIn[2 * i] * REVERB_SEND_LEVEL / 32768.0f;
- pContext->InFrames[2 * i + 1] =
- (process_buffer_t)pIn[2 * i + 1] * REVERB_SEND_LEVEL / 32768.0f;
-#endif
-#else
- pContext->InFrames[2*i] = (pIn[2*i] * REVERB_SEND_LEVEL) >> 4; // <<8 + >>12
- pContext->InFrames[2*i+1] = (pIn[2*i+1] * REVERB_SEND_LEVEL) >> 4; // <<8 + >>12
-#endif
}
}
@@ -471,43 +410,16 @@
// Convert to 16 bits
if (pContext->auxiliary) {
-#ifdef BUILD_FLOAT
// nothing to do here
-#ifndef NATIVE_FLOAT_BUFFER
- // pContext->OutFrames and OutFrames16 point to the same buffer
- // make sure the float to int conversion happens in the right order.
- memcpy_to_i16_from_float(OutFrames16, pContext->OutFrames,
- (size_t)frameCount * FCC_2);
-#endif
-#else
- memcpy_to_i16_from_q4_27(OutFrames16, pContext->OutFrames, (size_t)frameCount * FCC_2);
-#endif
} else {
-#ifdef BUILD_FLOAT
-#ifdef NATIVE_FLOAT_BUFFER
for (int i = 0; i < frameCount * FCC_2; i++) { // always stereo here
// Mix with dry input
pContext->OutFrames[i] += pIn[i];
}
-#else
- for (int i = 0; i < frameCount * FCC_2; i++) { // always stereo here
- // pOutputBuff and OutFrames16 point to the same buffer
- // make sure the float to int conversion happens in the right order.
- pContext->OutFrames[i] += (process_buffer_t)pIn[i] / 32768.0f;
- }
- memcpy_to_i16_from_float(OutFrames16, pContext->OutFrames,
- (size_t)frameCount * FCC_2);
-#endif
-#else
- for (int i=0; i < frameCount * FCC_2; i++) { // always stereo here
- OutFrames16[i] = clamp16((pContext->OutFrames[i]>>8) + (process_buffer_t)pIn[i]);
- }
-#endif
// apply volume with ramp if needed
if ((pContext->leftVolume != pContext->prevLeftVolume ||
pContext->rightVolume != pContext->prevRightVolume) &&
pContext->volumeMode == REVERB_VOLUME_RAMP) {
-#if defined (BUILD_FLOAT) && defined (NATIVE_FLOAT_BUFFER)
// FIXME: still using int16 volumes.
// For reference: REVERB_UNIT_VOLUME (0x1000) // 1.0 in 4.12 format
float vl = (float)pContext->prevLeftVolume / 4096;
@@ -522,37 +434,14 @@
vl += incl;
vr += incr;
}
-#else
- LVM_INT32 vl = (LVM_INT32)pContext->prevLeftVolume << 16;
- LVM_INT32 incl = (((LVM_INT32)pContext->leftVolume << 16) - vl) / frameCount;
- LVM_INT32 vr = (LVM_INT32)pContext->prevRightVolume << 16;
- LVM_INT32 incr = (((LVM_INT32)pContext->rightVolume << 16) - vr) / frameCount;
-
- for (int i = 0; i < frameCount; i++) {
- OutFrames16[FCC_2 * i] =
- clamp16((LVM_INT32)((vl >> 16) * OutFrames16[2*i]) >> 12);
- OutFrames16[FCC_2 * i + 1] =
- clamp16((LVM_INT32)((vr >> 16) * OutFrames16[2*i+1]) >> 12);
-
- vl += incl;
- vr += incr;
- }
-#endif
pContext->prevLeftVolume = pContext->leftVolume;
pContext->prevRightVolume = pContext->rightVolume;
} else if (pContext->volumeMode != REVERB_VOLUME_OFF) {
if (pContext->leftVolume != REVERB_UNIT_VOLUME ||
pContext->rightVolume != REVERB_UNIT_VOLUME) {
for (int i = 0; i < frameCount; i++) {
-#if defined(BUILD_FLOAT) && defined(NATIVE_FLOAT_BUFFER)
pContext->OutFrames[FCC_2 * i] *= ((float)pContext->leftVolume / 4096);
pContext->OutFrames[FCC_2 * i + 1] *= ((float)pContext->rightVolume / 4096);
-#else
- OutFrames16[FCC_2 * i] =
- clamp16((LVM_INT32)(pContext->leftVolume * OutFrames16[2*i]) >> 12);
- OutFrames16[FCC_2 * i + 1] =
- clamp16((LVM_INT32)(pContext->rightVolume * OutFrames16[2*i+1]) >> 12);
-#endif
}
}
pContext->prevLeftVolume = pContext->leftVolume;
@@ -561,21 +450,12 @@
}
}
-#ifdef LVM_PCM
- fwrite(pContext->OutFrames, frameCount * sizeof(*pContext->OutFrames) * FCC_2,
- 1 /* nmemb */, pContext->PcmOutPtr);
- fflush(pContext->PcmOutPtr);
-#endif
// Accumulate if required
if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
//ALOGV("\tBuffer access is ACCUMULATE");
for (int i = 0; i < frameCount * FCC_2; i++) { // always stereo here
-#ifndef NATIVE_FLOAT_BUFFER
- pOut[i] = clamp16((int32_t)pOut[i] + (int32_t)OutFrames16[i]);
-#else
pOut[i] += pContext->OutFrames[i];
-#endif
}
}else{
//ALOGV("\tBuffer access is WRITE");
@@ -654,7 +534,6 @@
//ALOGV("\tReverb_setConfig calling memcpy");
pContext->config = *pConfig;
-
switch (pConfig->inputCfg.samplingRate) {
case 8000:
SampleRate = LVM_FS_8000;
@@ -674,7 +553,6 @@
case 48000:
SampleRate = LVM_FS_48000;
break;
-#if defined(BUILD_FLOAT) && defined(HIGHER_FS)
case 88200:
SampleRate = LVM_FS_88200;
break;
@@ -687,7 +565,6 @@
case 192000:
SampleRate = LVM_FS_192000;
break;
-#endif
default:
ALOGV("\rReverb_setConfig invalid sampling rate %d", pConfig->inputCfg.samplingRate);
return -EINVAL;
@@ -1509,7 +1386,6 @@
//ALOGV("\tReverbGetDensity Succesfully returned from LVM_GetControlParameters\n");
//ALOGV("\tReverbGetDensity() just Got -> %d\n", ActiveParams.RoomSize);
-
Temp = (LVM_INT16)(((pContext->SavedDensity * 99) / 1000) + 1);
if(Temp != ActiveParams.RoomSize){
@@ -1557,7 +1433,6 @@
return 0;
}
-
//----------------------------------------------------------------------------
// Reverb_getParameter()
//----------------------------------------------------------------------------
@@ -1903,7 +1778,6 @@
return status;
} /* end Reverb_setParameter */
-
/**
* returns the size in bytes of the value of each environmental reverb parameter
*/
@@ -1951,17 +1825,10 @@
}
//ALOGV("\tReverb_process() Calling process with %d frames", outBuffer->frameCount);
/* Process all the available frames, block processing is handled internalLY by the LVM bundle */
-#if defined (BUILD_FLOAT) && defined (NATIVE_FLOAT_BUFFER)
status = process( inBuffer->f32,
outBuffer->f32,
outBuffer->frameCount,
pContext);
-#else
- status = process( inBuffer->s16,
- outBuffer->s16,
- outBuffer->frameCount,
- pContext);
-#endif
if (pContext->bEnabled == LVM_FALSE) {
if (pContext->SamplesToExitCount > 0) {
@@ -1986,7 +1853,6 @@
LVREV_ControlParams_st ActiveParams; /* Current control Parameters */
LVREV_ReturnStatus_en LvmStatus=LVREV_SUCCESS; /* Function call status */
-
if (pContext == NULL){
ALOGV("\tLVM_ERROR : Reverb_command ERROR pContext == NULL");
return -EINVAL;
@@ -2161,7 +2027,6 @@
return -EINVAL;
}
-
if (pReplyData != NULL) { // we have volume control
pContext->leftVolume = (LVM_INT16)((*(uint32_t *)pCmdData + (1 << 11)) >> 12);
pContext->rightVolume = (LVM_INT16)((*((uint32_t *)pCmdData + 1) + (1 << 11)) >> 12);
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.h b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.h
index 8165f5a..96223a8 100644
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.h
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.h
@@ -20,10 +20,6 @@
#include <audio_effects/effect_environmentalreverb.h>
#include <audio_effects/effect_presetreverb.h>
-#if __cplusplus
-extern "C" {
-#endif
-
#define MAX_NUM_BANDS 5
#define MAX_CALL_SIZE 256
#define LVREV_MAX_T60 7000
@@ -31,16 +27,11 @@
#define LVREV_MAX_FRAME_SIZE 2560
#define LVREV_CUP_LOAD_ARM9E 470 // Expressed in 0.1 MIPS
#define LVREV_MEM_USAGE (71+(LVREV_MAX_FRAME_SIZE>>7)) // Expressed in kB
-//#define LVM_PCM
typedef struct _LPFPair_t
{
int16_t Room_HF;
int16_t LPF;
} LPFPair_t;
-#if __cplusplus
-} // extern "C"
-#endif
-
#endif /*ANDROID_EFFECTREVERB_H_*/
diff --git a/media/libheif/HeifDecoderImpl.cpp b/media/libheif/HeifDecoderImpl.cpp
index a977300..273d91c 100644
--- a/media/libheif/HeifDecoderImpl.cpp
+++ b/media/libheif/HeifDecoderImpl.cpp
@@ -21,16 +21,17 @@
#include <stdio.h>
+#include <android/IDataSource.h>
#include <binder/IMemory.h>
#include <binder/MemoryDealer.h>
#include <drm/drm_framework_common.h>
-#include <media/IDataSource.h>
#include <media/mediametadataretriever.h>
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/stagefright/foundation/ADebug.h>
#include <private/media/VideoFrame.h>
#include <utils/Log.h>
#include <utils/RefBase.h>
+#include <vector>
HeifDecoder* createHeifDecoder() {
return new android::HeifDecoderImpl();
@@ -38,6 +39,22 @@
namespace android {
+void initFrameInfo(HeifFrameInfo *info, const VideoFrame *videoFrame) {
+ info->mWidth = videoFrame->mWidth;
+ info->mHeight = videoFrame->mHeight;
+ info->mRotationAngle = videoFrame->mRotationAngle;
+ info->mBytesPerPixel = videoFrame->mBytesPerPixel;
+ info->mDurationUs = videoFrame->mDurationUs;
+ if (videoFrame->mIccSize > 0) {
+ info->mIccData.assign(
+ videoFrame->getFlattenedIccData(),
+ videoFrame->getFlattenedIccData() + videoFrame->mIccSize);
+ } else {
+ // clear old Icc data if there is no Icc data.
+ info->mIccData.clear();
+ }
+}
+
/*
* HeifDataSource
*
@@ -66,9 +83,6 @@
void close() {}
uint32_t getFlags() override { return 0; }
String8 toString() override { return String8("HeifDataSource"); }
- sp<DecryptHandle> DrmInitialization(const char*) override {
- return nullptr;
- }
private:
enum {
@@ -156,7 +170,7 @@
// copy from cache if the request falls entirely in cache
if (offset + size <= mCachedOffset + mCachedSize) {
- memcpy(mMemory->pointer(), mCache.get() + offset - mCachedOffset, size);
+ memcpy(mMemory->unsecurePointer(), mCache.get() + offset - mCachedOffset, size);
return size;
}
@@ -254,7 +268,7 @@
if (bytesAvailable < (int64_t)size) {
size = bytesAvailable;
}
- memcpy(mMemory->pointer(), mCache.get() + offset - mCachedOffset, size);
+ memcpy(mMemory->unsecurePointer(), mCache.get() + offset - mCachedOffset, size);
return size;
}
@@ -293,11 +307,11 @@
// it's not, default to HAL_PIXEL_FORMAT_RGB_565.
mOutputColor(HAL_PIXEL_FORMAT_RGB_565),
mCurScanline(0),
- mWidth(0),
- mHeight(0),
+ mTotalScanline(0),
mFrameDecoded(false),
mHasImage(false),
mHasVideo(false),
+ mSequenceLength(0),
mAvailableLines(0),
mNumSlices(1),
mSliceHeight(0),
@@ -320,6 +334,13 @@
}
mDataSource = dataSource;
+ return reinit(frameInfo);
+}
+
+bool HeifDecoderImpl::reinit(HeifFrameInfo* frameInfo) {
+ mFrameDecoded = false;
+ mFrameMemory.clear();
+
mRetriever = new MediaMetadataRetriever();
status_t err = mRetriever->setDataSource(mDataSource, "image/heif");
if (err != OK) {
@@ -336,48 +357,103 @@
mHasImage = hasImage && !strcasecmp(hasImage, "yes");
mHasVideo = hasVideo && !strcasecmp(hasVideo, "yes");
- sp<IMemory> sharedMem;
+
+ HeifFrameInfo* defaultInfo = nullptr;
if (mHasImage) {
// image index < 0 to retrieve primary image
- sharedMem = mRetriever->getImageAtIndex(
+ sp<IMemory> sharedMem = mRetriever->getImageAtIndex(
-1, mOutputColor, true /*metaOnly*/);
- } else if (mHasVideo) {
- sharedMem = mRetriever->getFrameAtTime(0,
- MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC,
- mOutputColor, true /*metaOnly*/);
+
+ if (sharedMem == nullptr || sharedMem->unsecurePointer() == nullptr) {
+ ALOGE("init: videoFrame is a nullptr");
+ return false;
+ }
+
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
+ VideoFrame* videoFrame = static_cast<VideoFrame*>(sharedMem->unsecurePointer());
+
+ ALOGV("Image dimension %dx%d, display %dx%d, angle %d, iccSize %d",
+ videoFrame->mWidth,
+ videoFrame->mHeight,
+ videoFrame->mDisplayWidth,
+ videoFrame->mDisplayHeight,
+ videoFrame->mRotationAngle,
+ videoFrame->mIccSize);
+
+ initFrameInfo(&mImageInfo, videoFrame);
+
+ if (videoFrame->mTileHeight >= 512) {
+ // Try decoding in slices only if the image has tiles and is big enough.
+ mSliceHeight = videoFrame->mTileHeight;
+ ALOGV("mSliceHeight %u", mSliceHeight);
+ }
+
+ defaultInfo = &mImageInfo;
}
- if (sharedMem == nullptr || sharedMem->pointer() == nullptr) {
- ALOGE("getFrameAtTime: videoFrame is a nullptr");
+ if (mHasVideo) {
+ sp<IMemory> sharedMem = mRetriever->getFrameAtTime(0,
+ MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC,
+ mOutputColor, true /*metaOnly*/);
+
+ if (sharedMem == nullptr || sharedMem->unsecurePointer() == nullptr) {
+ ALOGE("init: videoFrame is a nullptr");
+ return false;
+ }
+
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
+ VideoFrame* videoFrame = static_cast<VideoFrame*>(
+ sharedMem->unsecurePointer());
+
+ ALOGV("Sequence dimension %dx%d, display %dx%d, angle %d, iccSize %d",
+ videoFrame->mWidth,
+ videoFrame->mHeight,
+ videoFrame->mDisplayWidth,
+ videoFrame->mDisplayHeight,
+ videoFrame->mRotationAngle,
+ videoFrame->mIccSize);
+
+ initFrameInfo(&mSequenceInfo, videoFrame);
+
+ mSequenceLength = atoi(mRetriever->extractMetadata(METADATA_KEY_VIDEO_FRAME_COUNT));
+
+ if (defaultInfo == nullptr) {
+ defaultInfo = &mSequenceInfo;
+ }
+ }
+
+ if (defaultInfo == nullptr) {
+ ALOGD("No valid image or sequence available");
return false;
}
- VideoFrame* videoFrame = static_cast<VideoFrame*>(sharedMem->pointer());
-
- ALOGV("Meta dimension %dx%d, display %dx%d, angle %d, iccSize %d",
- videoFrame->mWidth,
- videoFrame->mHeight,
- videoFrame->mDisplayWidth,
- videoFrame->mDisplayHeight,
- videoFrame->mRotationAngle,
- videoFrame->mIccSize);
-
if (frameInfo != nullptr) {
- frameInfo->set(
- videoFrame->mWidth,
- videoFrame->mHeight,
- videoFrame->mRotationAngle,
- videoFrame->mBytesPerPixel,
- videoFrame->mIccSize,
- videoFrame->getFlattenedIccData());
+ *frameInfo = *defaultInfo;
}
- mWidth = videoFrame->mWidth;
- mHeight = videoFrame->mHeight;
- if (mHasImage && videoFrame->mTileHeight >= 512 && mWidth >= 3000 && mHeight >= 2000 ) {
- // Try decoding in slices only if the image has tiles and is big enough.
- mSliceHeight = videoFrame->mTileHeight;
- mNumSlices = (videoFrame->mHeight + mSliceHeight - 1) / mSliceHeight;
- ALOGV("mSliceHeight %u, mNumSlices %zu", mSliceHeight, mNumSlices);
+
+ // default total scanline, this might change if decodeSequence() is used
+ mTotalScanline = defaultInfo->mHeight;
+
+ return true;
+}
+
+bool HeifDecoderImpl::getSequenceInfo(
+ HeifFrameInfo* frameInfo, size_t *frameCount) {
+ ALOGV("%s", __FUNCTION__);
+ if (!mHasVideo) {
+ return false;
+ }
+ if (frameInfo != nullptr) {
+ *frameInfo = mSequenceInfo;
+ }
+ if (frameCount != nullptr) {
+ *frameCount = mSequenceLength;
}
return true;
}
@@ -388,27 +464,35 @@
}
bool HeifDecoderImpl::setOutputColor(HeifColorFormat heifColor) {
+ if (heifColor == mOutputColor) {
+ return true;
+ }
+
switch(heifColor) {
case kHeifColorFormat_RGB565:
{
mOutputColor = HAL_PIXEL_FORMAT_RGB_565;
- return true;
+ break;
}
case kHeifColorFormat_RGBA_8888:
{
mOutputColor = HAL_PIXEL_FORMAT_RGBA_8888;
- return true;
+ break;
}
case kHeifColorFormat_BGRA_8888:
{
mOutputColor = HAL_PIXEL_FORMAT_BGRA_8888;
- return true;
+ break;
}
default:
- break;
+ ALOGE("Unsupported output color format %d", heifColor);
+ return false;
}
- ALOGE("Unsupported output color format %d", heifColor);
- return false;
+
+ if (mFrameDecoded) {
+ return reinit(nullptr);
+ }
+ return true;
}
bool HeifDecoderImpl::decodeAsync() {
@@ -416,15 +500,15 @@
ALOGV("decodeAsync(): decoding slice %zu", i);
size_t top = i * mSliceHeight;
size_t bottom = (i + 1) * mSliceHeight;
- if (bottom > mHeight) {
- bottom = mHeight;
+ if (bottom > mImageInfo.mHeight) {
+ bottom = mImageInfo.mHeight;
}
sp<IMemory> frameMemory = mRetriever->getImageRectAtIndex(
- -1, mOutputColor, 0, top, mWidth, bottom);
+ -1, mOutputColor, 0, top, mImageInfo.mWidth, bottom);
{
Mutex::Autolock autolock(mLock);
- if (frameMemory == nullptr || frameMemory->pointer() == nullptr) {
+ if (frameMemory == nullptr || frameMemory->unsecurePointer() == nullptr) {
mAsyncDecodeDone = true;
mScanlineReady.signal();
break;
@@ -437,7 +521,8 @@
}
// Aggressive clear to avoid holding on to resources
mRetriever.clear();
- mDataSource.clear();
+
+ // Hold on to mDataSource in case the client wants to redecode.
return false;
}
@@ -452,42 +537,48 @@
// See if we want to decode in slices to allow client to start
// scanline processing in parallel with decode. If this fails
// we fallback to decoding the full frame.
- if (mHasImage && mNumSlices > 1) {
- // get first slice and metadata
- sp<IMemory> frameMemory = mRetriever->getImageRectAtIndex(
- -1, mOutputColor, 0, 0, mWidth, mSliceHeight);
-
- if (frameMemory == nullptr || frameMemory->pointer() == nullptr) {
- ALOGE("decode: metadata is a nullptr");
- return false;
+ if (mHasImage) {
+ if (mSliceHeight >= 512 &&
+ mImageInfo.mWidth >= 3000 &&
+ mImageInfo.mHeight >= 2000 ) {
+ // Try decoding in slices only if the image has tiles and is big enough.
+ mNumSlices = (mImageInfo.mHeight + mSliceHeight - 1) / mSliceHeight;
+ ALOGV("mSliceHeight %u, mNumSlices %zu", mSliceHeight, mNumSlices);
}
- VideoFrame* videoFrame = static_cast<VideoFrame*>(frameMemory->pointer());
+ if (mNumSlices > 1) {
+ // get first slice and metadata
+ sp<IMemory> frameMemory = mRetriever->getImageRectAtIndex(
+ -1, mOutputColor, 0, 0, mImageInfo.mWidth, mSliceHeight);
- if (frameInfo != nullptr) {
- frameInfo->set(
- videoFrame->mWidth,
- videoFrame->mHeight,
- videoFrame->mRotationAngle,
- videoFrame->mBytesPerPixel,
- videoFrame->mIccSize,
- videoFrame->getFlattenedIccData());
+ if (frameMemory == nullptr || frameMemory->unsecurePointer() == nullptr) {
+ ALOGE("decode: metadata is a nullptr");
+ return false;
+ }
+
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
+ VideoFrame* videoFrame = static_cast<VideoFrame*>(frameMemory->unsecurePointer());
+
+ if (frameInfo != nullptr) {
+ initFrameInfo(frameInfo, videoFrame);
+ }
+ mFrameMemory = frameMemory;
+ mAvailableLines = mSliceHeight;
+ mThread = new DecodeThread(this);
+ if (mThread->run("HeifDecode", ANDROID_PRIORITY_FOREGROUND) == OK) {
+ mFrameDecoded = true;
+ return true;
+ }
+ // Fallback to decode without slicing
+ mThread.clear();
+ mNumSlices = 1;
+ mSliceHeight = 0;
+ mAvailableLines = 0;
+ mFrameMemory.clear();
}
-
- mFrameMemory = frameMemory;
- mAvailableLines = mSliceHeight;
- mThread = new DecodeThread(this);
- if (mThread->run("HeifDecode", ANDROID_PRIORITY_FOREGROUND) == OK) {
- mFrameDecoded = true;
- return true;
- }
-
- // Fallback to decode without slicing
- mThread.clear();
- mNumSlices = 1;
- mSliceHeight = 0;
- mAvailableLines = 0;
- mFrameMemory.clear();
}
if (mHasImage) {
@@ -498,12 +589,16 @@
MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC, mOutputColor);
}
- if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) {
+ if (mFrameMemory == nullptr || mFrameMemory->unsecurePointer() == nullptr) {
ALOGE("decode: videoFrame is a nullptr");
return false;
}
- VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->pointer());
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
+ VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->unsecurePointer());
if (videoFrame->mSize == 0 ||
mFrameMemory->size() < videoFrame->getFlattenedSize()) {
ALOGE("decode: videoFrame size is invalid");
@@ -520,34 +615,82 @@
videoFrame->mSize);
if (frameInfo != nullptr) {
- frameInfo->set(
- videoFrame->mWidth,
- videoFrame->mHeight,
- videoFrame->mRotationAngle,
- videoFrame->mBytesPerPixel,
- videoFrame->mIccSize,
- videoFrame->getFlattenedIccData());
+ initFrameInfo(frameInfo, videoFrame);
+
}
mFrameDecoded = true;
// Aggressively clear to avoid holding on to resources
mRetriever.clear();
- mDataSource.clear();
+
+ // Hold on to mDataSource in case the client wants to redecode.
+ return true;
+}
+
+bool HeifDecoderImpl::decodeSequence(int frameIndex, HeifFrameInfo* frameInfo) {
+ ALOGV("%s: frame index %d", __FUNCTION__, frameIndex);
+ if (!mHasVideo) {
+ return false;
+ }
+
+ if (frameIndex < 0 || frameIndex >= mSequenceLength) {
+ ALOGE("invalid frame index: %d, total frames %zu", frameIndex, mSequenceLength);
+ return false;
+ }
+
+ mCurScanline = 0;
+
+ // set total scanline to sequence height now
+ mTotalScanline = mSequenceInfo.mHeight;
+
+ mFrameMemory = mRetriever->getFrameAtIndex(frameIndex, mOutputColor);
+ if (mFrameMemory == nullptr || mFrameMemory->unsecurePointer() == nullptr) {
+ ALOGE("decode: videoFrame is a nullptr");
+ return false;
+ }
+
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
+ VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->unsecurePointer());
+ if (videoFrame->mSize == 0 ||
+ mFrameMemory->size() < videoFrame->getFlattenedSize()) {
+ ALOGE("decode: videoFrame size is invalid");
+ return false;
+ }
+
+ ALOGV("Decoded dimension %dx%d, display %dx%d, angle %d, rowbytes %d, size %d",
+ videoFrame->mWidth,
+ videoFrame->mHeight,
+ videoFrame->mDisplayWidth,
+ videoFrame->mDisplayHeight,
+ videoFrame->mRotationAngle,
+ videoFrame->mRowBytes,
+ videoFrame->mSize);
+
+ if (frameInfo != nullptr) {
+ initFrameInfo(frameInfo, videoFrame);
+ }
return true;
}
bool HeifDecoderImpl::getScanlineInner(uint8_t* dst) {
- if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) {
+ if (mFrameMemory == nullptr || mFrameMemory->unsecurePointer() == nullptr) {
return false;
}
- VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->pointer());
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
+ VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->unsecurePointer());
uint8_t* src = videoFrame->getFlattenedData() + videoFrame->mRowBytes * mCurScanline++;
memcpy(dst, src, videoFrame->mBytesPerPixel * videoFrame->mWidth);
return true;
}
bool HeifDecoderImpl::getScanline(uint8_t* dst) {
- if (mCurScanline >= mHeight) {
+ if (mCurScanline >= mTotalScanline) {
ALOGE("no more scanline available");
return false;
}
@@ -567,8 +710,8 @@
size_t HeifDecoderImpl::skipScanlines(size_t count) {
uint32_t oldScanline = mCurScanline;
mCurScanline += count;
- if (mCurScanline > mHeight) {
- mCurScanline = mHeight;
+ if (mCurScanline > mTotalScanline) {
+ mCurScanline = mTotalScanline;
}
return (mCurScanline > oldScanline) ? (mCurScanline - oldScanline) : 0;
}
diff --git a/media/libheif/HeifDecoderImpl.h b/media/libheif/HeifDecoderImpl.h
index 528ee3b..2b9c710 100644
--- a/media/libheif/HeifDecoderImpl.h
+++ b/media/libheif/HeifDecoderImpl.h
@@ -40,12 +40,16 @@
bool init(HeifStream* stream, HeifFrameInfo* frameInfo) override;
+ bool getSequenceInfo(HeifFrameInfo* frameInfo, size_t *frameCount) override;
+
bool getEncodedColor(HeifEncodedColor* outColor) const override;
bool setOutputColor(HeifColorFormat heifColor) override;
bool decode(HeifFrameInfo* frameInfo) override;
+ bool decodeSequence(int frameIndex, HeifFrameInfo* frameInfo) override;
+
bool getScanline(uint8_t* dst) override;
size_t skipScanlines(size_t count) override;
@@ -56,13 +60,15 @@
sp<IDataSource> mDataSource;
sp<MediaMetadataRetriever> mRetriever;
sp<IMemory> mFrameMemory;
+ HeifFrameInfo mImageInfo;
+ HeifFrameInfo mSequenceInfo;
android_pixel_format_t mOutputColor;
size_t mCurScanline;
- uint32_t mWidth;
- uint32_t mHeight;
+ size_t mTotalScanline;
bool mFrameDecoded;
bool mHasImage;
bool mHasVideo;
+ size_t mSequenceLength;
// Slice decoding only
Mutex mLock;
@@ -75,6 +81,7 @@
bool decodeAsync();
bool getScanlineInner(uint8_t* dst);
+ bool reinit(HeifFrameInfo* frameInfo);
};
} // namespace android
diff --git a/media/libheif/include/HeifDecoderAPI.h b/media/libheif/include/HeifDecoderAPI.h
index aa10f33..9073672 100644
--- a/media/libheif/include/HeifDecoderAPI.h
+++ b/media/libheif/include/HeifDecoderAPI.h
@@ -17,7 +17,7 @@
#ifndef _HEIF_DECODER_API_
#define _HEIF_DECODER_API_
-#include <memory>
+#include <vector>
/*
* The output color pixel format of heif decoder.
@@ -40,41 +40,13 @@
/*
* Represents a color converted (RGB-based) video frame
*/
-struct HeifFrameInfo
-{
- HeifFrameInfo() :
- mWidth(0), mHeight(0), mRotationAngle(0), mBytesPerPixel(0),
- mIccSize(0), mIccData(nullptr) {}
-
- // update the frame info, will make a copy of |iccData| internally
- void set(uint32_t width, uint32_t height, int32_t rotation, uint32_t bpp,
- uint32_t iccSize, uint8_t* iccData) {
- mWidth = width;
- mHeight = height;
- mRotationAngle = rotation;
- mBytesPerPixel = bpp;
-
- if (mIccData != nullptr) {
- mIccData.reset(nullptr);
- }
- mIccSize = iccSize;
- if (iccSize > 0) {
- mIccData.reset(new uint8_t[iccSize]);
- if (mIccData.get() != nullptr) {
- memcpy(mIccData.get(), iccData, iccSize);
- } else {
- mIccSize = 0;
- }
- }
- }
-
- // Intentional public access modifiers:
+struct HeifFrameInfo {
uint32_t mWidth;
uint32_t mHeight;
int32_t mRotationAngle; // Rotation angle, clockwise, should be multiple of 90
uint32_t mBytesPerPixel; // Number of bytes for one pixel
- uint32_t mIccSize; // Number of bytes in mIccData
- std::unique_ptr<uint8_t[]> mIccData; // Actual ICC data, memory is owned by this structure
+ int64_t mDurationUs; // Duration of the frame in us
+ std::vector<uint8_t> mIccData; // ICC data array
};
/*
@@ -113,8 +85,8 @@
virtual size_t getLength() const = 0;
private:
- HeifStream(const HeifFrameInfo&) = delete;
- HeifStream& operator=(const HeifFrameInfo&) = delete;
+ HeifStream(const HeifStream&) = delete;
+ HeifStream& operator=(const HeifStream&) = delete;
};
/*
@@ -146,6 +118,14 @@
virtual bool init(HeifStream* stream, HeifFrameInfo* frameInfo) = 0;
/*
+ * Returns true if the stream contains an image sequence and false otherwise.
+ * |frameInfo| will be filled with information of pictures in the sequence
+ * and |frameCount| the length of the sequence upon success and unmodified
+ * upon failure.
+ */
+ virtual bool getSequenceInfo(HeifFrameInfo* frameInfo, size_t *frameCount) = 0;
+
+ /*
* Decode the picture internally, returning whether it succeeded. |frameInfo|
* will be filled with information of the primary picture upon success and
* unmodified upon failure.
@@ -156,6 +136,20 @@
virtual bool decode(HeifFrameInfo* frameInfo) = 0;
/*
+ * Decode the picture from the image sequence at index |frameIndex|.
+ * |frameInfo| will be filled with information of the decoded picture upon
+ * success and unmodified upon failure.
+ *
+ * |frameIndex| is the 0-based index of the video frame to retrieve. The frame
+ * index must be that of a valid frame. The total number of frames available for
+ * retrieval was reported via getSequenceInfo().
+ *
+ * After this succeeded, getScanline can be called to read the scanlines
+ * that were decoded.
+ */
+ virtual bool decodeSequence(int frameIndex, HeifFrameInfo* frameInfo) = 0;
+
+ /*
* Read the next scanline (in top-down order), returns true upon success
* and false otherwise.
*/
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 1d33590..867187d 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -1,15 +1,8 @@
-cc_defaults {
- name: "libmedia_defaults",
- include_dirs: [
- "bionic/libc/private",
- ],
-}
-
cc_library_headers {
name: "libmedia_headers",
vendor_available: true,
export_include_dirs: ["include"],
- header_libs:[
+ header_libs: [
"libbase_headers",
"libgui_headers",
"libstagefright_headers",
@@ -22,29 +15,33 @@
],
}
-cc_library {
- name: "libmedia_helper",
- vendor_available: true,
- vndk: {
- enabled: true,
- },
- double_loadable: true,
- srcs: ["AudioParameter.cpp", "TypeConverter.cpp"],
- cflags: [
- "-Werror",
- "-Wno-error=deprecated-declarations",
- "-Wall",
+filegroup {
+ name: "libmedia_omx_aidl",
+ srcs: [
+ "aidl/android/IOMXBufferSource.aidl",
],
- shared_libs: ["libutils", "liblog"],
- header_libs: [
- "libmedia_headers",
- "libaudioclient_headers",
- "libaudio_system_headers",
+ path: "aidl",
+}
+
+filegroup {
+ name: "mediaextractorservice_aidl",
+ srcs: [
+ "aidl/android/IMediaExtractorService.aidl",
],
- export_header_lib_headers: [
- "libmedia_headers",
+ path: "aidl",
+}
+
+aidl_interface {
+ name: "resourcemanager_aidl_interface",
+ local_include_dir: "aidl",
+ srcs: [
+ "aidl/android/media/IResourceManagerClient.aidl",
+ "aidl/android/media/IResourceManagerService.aidl",
+ "aidl/android/media/MediaResourceType.aidl",
+ "aidl/android/media/MediaResourceSubType.aidl",
+ "aidl/android/media/MediaResourceParcel.aidl",
+ "aidl/android/media/MediaResourcePolicyParcel.aidl",
],
- clang: true,
}
cc_library_shared {
@@ -56,15 +53,11 @@
double_loadable: true,
srcs: [
- "aidl/android/IGraphicBufferSource.aidl",
- "aidl/android/IOMXBufferSource.aidl",
+ ":libmedia_omx_aidl",
- "IMediaCodecList.cpp",
"IOMX.cpp",
"MediaCodecBuffer.cpp",
- "MediaCodecInfo.cpp",
"OMXBuffer.cpp",
- "omx/1.0/WGraphicBufferSource.cpp",
"omx/1.0/WOmxBufferSource.cpp",
"omx/1.0/WOmxNode.cpp",
"omx/1.0/WOmxObserver.cpp",
@@ -74,7 +67,7 @@
local_include_dirs: ["aidl"],
export_aidl_headers: true,
},
-
+
local_include_dirs: [
"include",
],
@@ -85,7 +78,6 @@
"libbinder",
"libcutils",
"libhidlbase",
- "libhidltransport",
"liblog",
"libstagefright_foundation",
"libui",
@@ -129,7 +121,6 @@
},
}
-
cc_library_shared {
name: "libmedia_omx_client",
@@ -146,7 +137,6 @@
"libcutils",
"libgui",
"libhidlbase",
- "libhidltransport",
"liblog",
"libmedia_omx",
"libstagefright_foundation",
@@ -200,6 +190,7 @@
],
header_libs: [
+ "libmedia_headers",
"media_ndk_headers",
],
@@ -218,19 +209,60 @@
},
}
+cc_library_shared {
+ name: "libmedia_codeclist",
+
+ srcs: [
+ "IMediaCodecList.cpp",
+ "MediaCodecInfo.cpp",
+ ],
+
+ local_include_dirs: [
+ "include",
+ ],
+
+ shared_libs: [
+ "android.hardware.media.omx@1.0",
+ "libbinder",
+ "liblog",
+ "libstagefright_foundation",
+ "libutils",
+ ],
+
+ include_dirs: [
+ "system/libhidl/transport/token/1.0/utils/include",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wno-error=deprecated-declarations",
+ "-Wall",
+ ],
+
+ sanitize: {
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ cfi: true,
+ },
+}
+
cc_library {
name: "libmedia",
- defaults: [ "libmedia_defaults" ],
-
srcs: [
+ ":mediaextractorservice_aidl",
"IDataSource.cpp",
"BufferingSettings.cpp",
"mediaplayer.cpp",
"IMediaHTTPConnection.cpp",
"IMediaHTTPService.cpp",
"IMediaExtractor.cpp",
- "IMediaExtractorService.cpp",
"IMediaPlayerService.cpp",
"IMediaPlayerClient.cpp",
"IMediaRecorderClient.cpp",
@@ -239,16 +271,12 @@
"IMediaSource.cpp",
"IRemoteDisplay.cpp",
"IRemoteDisplayClient.cpp",
- "IResourceManagerClient.cpp",
- "IResourceManagerService.cpp",
"IStreamSource.cpp",
"MediaUtils.cpp",
"Metadata.cpp",
"mediarecorder.cpp",
"IMediaMetadataRetriever.cpp",
"mediametadataretriever.cpp",
- "MidiDeviceInfo.cpp",
- "JetPlayer.cpp",
"MediaScanner.cpp",
"MediaScannerClient.cpp",
"CharacterEncodingDetector.cpp",
@@ -256,7 +284,6 @@
"MediaProfiles.cpp",
"MediaResource.cpp",
"MediaResourcePolicy.cpp",
- "Visualizer.cpp",
"StringArray.cpp",
"NdkMediaFormatPriv.cpp",
"NdkMediaErrorPriv.cpp",
@@ -268,6 +295,7 @@
},
header_libs: [
+ "bionic_libc_platform_headers",
"libstagefright_headers",
"media_ndk_headers",
],
@@ -284,6 +312,7 @@
"libprocessgroup",
"libutils",
"libbinder",
+ "libbinder_ndk",
"libsonivox",
"libandroidicu",
"libexpat",
@@ -291,8 +320,8 @@
"libstagefright_foundation",
"libgui",
"libdl",
- "libaudioutils",
"libaudioclient",
+ "libmedia_codeclist",
"libmedia_omx",
],
@@ -305,8 +334,12 @@
],
static_libs: [
- "libc_malloc_debug_backtrace", // for memory heap analysis
- "libmedia_midiiowrapper",
+ "libc_malloc_debug_backtrace", // for memory heap analysis
+ "resourcemanager_aidl_interface-ndk_platform",
+ ],
+
+ export_static_lib_headers: [
+ "resourcemanager_aidl_interface-ndk_platform",
],
export_include_dirs: [
@@ -329,66 +362,3 @@
cfi: true,
},
}
-
-cc_library_static {
- name: "libmedia_player2_util",
-
- defaults: [ "libmedia_defaults" ],
-
- srcs: [
- "AudioParameter.cpp",
- "BufferingSettings.cpp",
- "DataSourceDesc.cpp",
- "MediaCodecBuffer.cpp",
- "Metadata.cpp",
- "NdkWrapper.cpp",
- ],
-
- shared_libs: [
- "libbinder",
- "libcutils",
- "liblog",
- "libmediandk",
- "libnativewindow",
- "libmediandk_utils",
- "libstagefright_foundation",
- "libui",
- "libutils",
- ],
-
- export_shared_lib_headers: [
- "libbinder",
- "libmediandk",
- ],
-
- header_libs: [
- "media_plugin_headers",
- ],
-
- include_dirs: [
- "frameworks/av/media/ndk",
- ],
-
- static_libs: [
- "libstagefright_rtsp",
- "libstagefright_timedtext",
- ],
-
- export_include_dirs: [
- "include",
- ],
-
- cflags: [
- "-Werror",
- "-Wno-error=deprecated-declarations",
- "-Wall",
- ],
-
- sanitize: {
- misc_undefined: [
- "unsigned-integer-overflow",
- "signed-integer-overflow",
- ],
- cfi: true,
- },
-}
diff --git a/media/libmedia/AudioParameter.cpp b/media/libmedia/AudioParameter.cpp
deleted file mode 100644
index 1c95e27..0000000
--- a/media/libmedia/AudioParameter.cpp
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright (C) 2006-2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "AudioParameter"
-//#define LOG_NDEBUG 0
-
-#include <utils/Log.h>
-
-#include <media/AudioParameter.h>
-#include <system/audio.h>
-
-namespace android {
-
-// static
-const char * const AudioParameter::keyRouting = AUDIO_PARAMETER_STREAM_ROUTING;
-const char * const AudioParameter::keySamplingRate = AUDIO_PARAMETER_STREAM_SAMPLING_RATE;
-const char * const AudioParameter::keyFormat = AUDIO_PARAMETER_STREAM_FORMAT;
-const char * const AudioParameter::keyChannels = AUDIO_PARAMETER_STREAM_CHANNELS;
-const char * const AudioParameter::keyFrameCount = AUDIO_PARAMETER_STREAM_FRAME_COUNT;
-const char * const AudioParameter::keyInputSource = AUDIO_PARAMETER_STREAM_INPUT_SOURCE;
-const char * const AudioParameter::keyScreenState = AUDIO_PARAMETER_KEY_SCREEN_STATE;
-const char * const AudioParameter::keyBtNrec = AUDIO_PARAMETER_KEY_BT_NREC;
-const char * const AudioParameter::keyHwAvSync = AUDIO_PARAMETER_HW_AV_SYNC;
-const char * const AudioParameter::keyPresentationId = AUDIO_PARAMETER_STREAM_PRESENTATION_ID;
-const char * const AudioParameter::keyProgramId = AUDIO_PARAMETER_STREAM_PROGRAM_ID;
-const char * const AudioParameter::keyAudioLanguagePreferred =
- AUDIO_PARAMETER_KEY_AUDIO_LANGUAGE_PREFERRED;
-const char * const AudioParameter::keyMonoOutput = AUDIO_PARAMETER_MONO_OUTPUT;
-const char * const AudioParameter::keyStreamHwAvSync = AUDIO_PARAMETER_STREAM_HW_AV_SYNC;
-const char * const AudioParameter::keyStreamConnect = AUDIO_PARAMETER_DEVICE_CONNECT;
-const char * const AudioParameter::keyStreamDisconnect = AUDIO_PARAMETER_DEVICE_DISCONNECT;
-const char * const AudioParameter::keyStreamSupportedFormats = AUDIO_PARAMETER_STREAM_SUP_FORMATS;
-const char * const AudioParameter::keyStreamSupportedChannels = AUDIO_PARAMETER_STREAM_SUP_CHANNELS;
-const char * const AudioParameter::keyStreamSupportedSamplingRates =
- AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES;
-const char * const AudioParameter::valueOn = AUDIO_PARAMETER_VALUE_ON;
-const char * const AudioParameter::valueOff = AUDIO_PARAMETER_VALUE_OFF;
-const char * const AudioParameter::valueListSeparator = AUDIO_PARAMETER_VALUE_LIST_SEPARATOR;
-const char * const AudioParameter::keyReconfigA2dp = AUDIO_PARAMETER_RECONFIG_A2DP;
-const char * const AudioParameter::keyReconfigA2dpSupported = AUDIO_PARAMETER_A2DP_RECONFIG_SUPPORTED;
-
-AudioParameter::AudioParameter(const String8& keyValuePairs)
-{
- char *str = new char[keyValuePairs.length()+1];
- mKeyValuePairs = keyValuePairs;
- char *last;
-
- strcpy(str, keyValuePairs.string());
- char *pair = strtok_r(str, ";", &last);
- while (pair != NULL) {
- if (strlen(pair) != 0) {
- size_t eqIdx = strcspn(pair, "=");
- String8 key = String8(pair, eqIdx);
- String8 value;
- if (eqIdx == strlen(pair)) {
- value = String8("");
- } else {
- value = String8(pair + eqIdx + 1);
- }
- if (mParameters.indexOfKey(key) < 0) {
- mParameters.add(key, value);
- } else {
- mParameters.replaceValueFor(key, value);
- }
- } else {
- ALOGV("AudioParameter() cstor empty key value pair");
- }
- pair = strtok_r(NULL, ";", &last);
- }
-
- delete[] str;
-}
-
-AudioParameter::~AudioParameter()
-{
- mParameters.clear();
-}
-
-String8 AudioParameter::toStringImpl(bool useValues) const
-{
- String8 str = String8("");
-
- size_t size = mParameters.size();
- for (size_t i = 0; i < size; i++) {
- str += mParameters.keyAt(i);
- if (useValues) {
- str += "=";
- str += mParameters.valueAt(i);
- }
- if (i < (size - 1)) str += ";";
- }
- return str;
-}
-
-status_t AudioParameter::add(const String8& key, const String8& value)
-{
- if (mParameters.indexOfKey(key) < 0) {
- mParameters.add(key, value);
- return NO_ERROR;
- } else {
- mParameters.replaceValueFor(key, value);
- return ALREADY_EXISTS;
- }
-}
-
-status_t AudioParameter::addKey(const String8& key)
-{
- return add(key, String8());
-}
-
-status_t AudioParameter::addInt(const String8& key, const int value)
-{
- char str[12];
- if (snprintf(str, 12, "%d", value) > 0) {
- String8 str8 = String8(str);
- return add(key, str8);
- } else {
- return BAD_VALUE;
- }
-}
-
-status_t AudioParameter::addFloat(const String8& key, const float value)
-{
- char str[23];
- if (snprintf(str, 23, "%.10f", value) > 0) {
- String8 str8 = String8(str);
- return add(key, str8);
- } else {
- return BAD_VALUE;
- }
-}
-
-status_t AudioParameter::remove(const String8& key)
-{
- if (mParameters.indexOfKey(key) >= 0) {
- mParameters.removeItem(key);
- return NO_ERROR;
- } else {
- return BAD_VALUE;
- }
-}
-
-status_t AudioParameter::get(const String8& key, String8& value) const
-{
- if (mParameters.indexOfKey(key) >= 0) {
- value = mParameters.valueFor(key);
- return NO_ERROR;
- } else {
- return BAD_VALUE;
- }
-}
-
-status_t AudioParameter::getInt(const String8& key, int& value) const
-{
- String8 str8;
- status_t result = get(key, str8);
- value = 0;
- if (result == NO_ERROR) {
- int val;
- if (sscanf(str8.string(), "%d", &val) == 1) {
- value = val;
- } else {
- result = INVALID_OPERATION;
- }
- }
- return result;
-}
-
-status_t AudioParameter::getFloat(const String8& key, float& value) const
-{
- String8 str8;
- status_t result = get(key, str8);
- value = 0;
- if (result == NO_ERROR) {
- float val;
- if (sscanf(str8.string(), "%f", &val) == 1) {
- value = val;
- } else {
- result = INVALID_OPERATION;
- }
- }
- return result;
-}
-
-status_t AudioParameter::getAt(size_t index, String8& key) const
-{
- if (mParameters.size() > index) {
- key = mParameters.keyAt(index);
- return NO_ERROR;
- } else {
- return BAD_VALUE;
- }
-}
-
-status_t AudioParameter::getAt(size_t index, String8& key, String8& value) const
-{
- if (mParameters.size() > index) {
- key = mParameters.keyAt(index);
- value = mParameters.valueAt(index);
- return NO_ERROR;
- } else {
- return BAD_VALUE;
- }
-}
-
-} // namespace android
diff --git a/media/libmedia/DataSourceDesc.cpp b/media/libmedia/DataSourceDesc.cpp
deleted file mode 100644
index b7ccbce..0000000
--- a/media/libmedia/DataSourceDesc.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "DataSourceDesc"
-
-#include <media/DataSource.h>
-#include <media/DataSourceDesc.h>
-#include <media/MediaHTTPService.h>
-
-namespace android {
-
-static const int64_t kLongMax = 0x7ffffffffffffffL;
-
-DataSourceDesc::DataSourceDesc()
- : mType(TYPE_NONE),
- mFDOffset(0),
- mFDLength(kLongMax),
- mId(0),
- mStartPositionMs(0),
- mEndPositionMs(0) {
-}
-
-} // namespace android
diff --git a/media/libmedia/IDataSource.cpp b/media/libmedia/IDataSource.cpp
index 31c85af..e96a113 100644
--- a/media/libmedia/IDataSource.cpp
+++ b/media/libmedia/IDataSource.cpp
@@ -19,11 +19,9 @@
#include <utils/Log.h>
#include <utils/Timers.h>
-#include <media/IDataSource.h>
-
+#include <android/IDataSource.h>
#include <binder/IMemory.h>
#include <binder/Parcel.h>
-#include <drm/drm_framework_common.h>
#include <media/stagefright/foundation/ADebug.h>
namespace android {
@@ -35,7 +33,6 @@
CLOSE,
GET_FLAGS,
TO_STRING,
- DRM_INITIALIZATION,
};
struct BpDataSource : public BpInterface<IDataSource> {
@@ -95,47 +92,6 @@
remote()->transact(TO_STRING, data, &reply);
return reply.readString8();
}
-
- virtual sp<DecryptHandle> DrmInitialization(const char *mime) {
- Parcel data, reply;
- data.writeInterfaceToken(IDataSource::getInterfaceDescriptor());
- if (mime == NULL) {
- data.writeInt32(0);
- } else {
- data.writeInt32(1);
- data.writeCString(mime);
- }
- remote()->transact(DRM_INITIALIZATION, data, &reply);
- sp<DecryptHandle> handle;
- if (reply.dataAvail() != 0) {
- handle = new DecryptHandle();
- handle->decryptId = reply.readInt32();
- handle->mimeType = reply.readString8();
- handle->decryptApiType = reply.readInt32();
- handle->status = reply.readInt32();
-
- const int bufferLength = data.readInt32();
- if (bufferLength != -1) {
- handle->decryptInfo = new DecryptInfo();
- handle->decryptInfo->decryptBufferLength = bufferLength;
- }
-
- size_t size = data.readInt32();
- for (size_t i = 0; i < size; ++i) {
- DrmCopyControl key = (DrmCopyControl)data.readInt32();
- int value = data.readInt32();
- handle->copyControlVector.add(key, value);
- }
-
- size = data.readInt32();
- for (size_t i = 0; i < size; ++i) {
- String8 key = data.readString8();
- String8 value = data.readString8();
- handle->extendedData.add(key, value);
- }
- }
- return handle;
- }
};
IMPLEMENT_META_INTERFACE(DataSource, "android.media.IDataSource");
@@ -178,42 +134,6 @@
reply->writeString8(toString());
return NO_ERROR;
} break;
- case DRM_INITIALIZATION: {
- CHECK_INTERFACE(IDataSource, data, reply);
- const char *mime = NULL;
- const int32_t flag = data.readInt32();
- if (flag != 0) {
- mime = data.readCString();
- }
- sp<DecryptHandle> handle = DrmInitialization(mime);
- if (handle != NULL) {
- reply->writeInt32(handle->decryptId);
- reply->writeString8(handle->mimeType);
- reply->writeInt32(handle->decryptApiType);
- reply->writeInt32(handle->status);
-
- if (handle->decryptInfo != NULL) {
- reply->writeInt32(handle->decryptInfo->decryptBufferLength);
- } else {
- reply->writeInt32(-1);
- }
-
- size_t size = handle->copyControlVector.size();
- reply->writeInt32(size);
- for (size_t i = 0; i < size; ++i) {
- reply->writeInt32(handle->copyControlVector.keyAt(i));
- reply->writeInt32(handle->copyControlVector.valueAt(i));
- }
-
- size = handle->extendedData.size();
- reply->writeInt32(size);
- for (size_t i = 0; i < size; ++i) {
- reply->writeString8(handle->extendedData.keyAt(i));
- reply->writeString8(handle->extendedData.valueAt(i));
- }
- }
- return NO_ERROR;
- } break;
default:
return BBinder::onTransact(code, data, reply, flags);
diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
index fb6d3a2..39caf53 100644
--- a/media/libmedia/IMediaExtractor.cpp
+++ b/media/libmedia/IMediaExtractor.cpp
@@ -25,7 +25,7 @@
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
#include <binder/PermissionCache.h>
-#include <media/IMediaExtractor.h>
+#include <android/IMediaExtractor.h>
#include <media/stagefright/MetaData.h>
namespace android {
@@ -107,8 +107,15 @@
}
virtual uint32_t flags() const {
- ALOGV("flags NOT IMPLEMENTED");
- return 0;
+ ALOGV("flags");
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
+ status_t ret = remote()->transact(FLAGS, data, &reply);
+ int flgs = 0;
+ if (ret == NO_ERROR) {
+ flgs = reply.readUint32();
+ }
+ return flgs;
}
virtual status_t setMediaCas(const HInterfaceToken &casToken) {
@@ -125,9 +132,15 @@
return reply.readInt32();
}
- virtual const char * name() {
- ALOGV("name NOT IMPLEMENTED");
- return NULL;
+ virtual String8 name() {
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
+ status_t ret = remote()->transact(NAME, data, &reply);
+ String8 nm;
+ if (ret == NO_ERROR) {
+ nm = reply.readString8();
+ }
+ return nm;
}
};
@@ -192,6 +205,12 @@
status_t ret = getMetrics(reply);
return ret;
}
+ case FLAGS: {
+ ALOGV("flags");
+ CHECK_INTERFACE(IMediaExtractor, data, reply);
+ reply->writeUint32(this->flags());
+ return NO_ERROR;
+ }
case SETMEDIACAS: {
ALOGV("setMediaCas");
CHECK_INTERFACE(IMediaExtractor, data, reply);
@@ -206,6 +225,13 @@
reply->writeInt32(setMediaCas(casToken));
return OK;
}
+ case NAME: {
+ ALOGV("name");
+ CHECK_INTERFACE(IMediaExtractor, data, reply);
+ String8 nm = name();
+ reply->writeString8(nm);
+ return NO_ERROR;
+ }
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/media/libmedia/IMediaExtractorService.cpp b/media/libmedia/IMediaExtractorService.cpp
deleted file mode 100644
index 243b09d..0000000
--- a/media/libmedia/IMediaExtractorService.cpp
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#define LOG_TAG "IMediaExtractorService"
-//#define LOG_NDEBUG 0
-
-#include <utils/Log.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <binder/Parcel.h>
-#include <media/IMediaExtractorService.h>
-
-namespace android {
-
-enum {
- MAKE_EXTRACTOR = IBinder::FIRST_CALL_TRANSACTION,
- MAKE_IDATA_SOURCE_FD,
- GET_SUPPORTED_TYPES,
-};
-
-class BpMediaExtractorService : public BpInterface<IMediaExtractorService>
-{
-public:
- explicit BpMediaExtractorService(const sp<IBinder>& impl)
- : BpInterface<IMediaExtractorService>(impl)
- {
- }
-
- virtual sp<IMediaExtractor> makeExtractor(const sp<IDataSource> &source, const char *mime) {
- Parcel data, reply;
- data.writeInterfaceToken(IMediaExtractorService::getInterfaceDescriptor());
- data.writeStrongBinder(IInterface::asBinder(source));
- if (mime != NULL) {
- data.writeCString(mime);
- }
- status_t ret = remote()->transact(MAKE_EXTRACTOR, data, &reply);
- if (ret == NO_ERROR) {
- return interface_cast<IMediaExtractor>(reply.readStrongBinder());
- }
- return NULL;
- }
-
- virtual sp<IDataSource> makeIDataSource(int fd, int64_t offset, int64_t length)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IMediaExtractorService::getInterfaceDescriptor());
- data.writeFileDescriptor(fd);
- data.writeInt64(offset);
- data.writeInt64(length);
- status_t ret = remote()->transact(MAKE_IDATA_SOURCE_FD, data, &reply);
- ALOGV("fd:%d offset:%lld length:%lld ret:%d",
- fd, (long long)offset, (long long)length, ret);
- if (ret == NO_ERROR) {
- return interface_cast<IDataSource>(reply.readStrongBinder());
- }
- return nullptr;
- }
-
- virtual std::unordered_set<std::string> getSupportedTypes() {
- std::unordered_set<std::string> supportedTypes;
- Parcel data, reply;
- data.writeInterfaceToken(IMediaExtractorService::getInterfaceDescriptor());
- status_t ret = remote()->transact(GET_SUPPORTED_TYPES, data, &reply);
- if (ret == NO_ERROR) {
- // process reply
- while(true) {
- const char *ext = reply.readCString();
- if (!ext) {
- break;
- }
- supportedTypes.insert(std::string(ext));
- }
- }
- return supportedTypes;
- }
-};
-
-IMPLEMENT_META_INTERFACE(MediaExtractorService, "android.media.IMediaExtractorService");
-
-// ----------------------------------------------------------------------
-
-status_t BnMediaExtractorService::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch (code) {
-
- case MAKE_EXTRACTOR: {
- CHECK_INTERFACE(IMediaExtractorService, data, reply);
- sp<IBinder> b;
- status_t ret = data.readStrongBinder(&b);
- if (ret != NO_ERROR || b == NULL) {
- ALOGE("Error reading source from parcel");
- return ret;
- }
- // If we make an extractor through Binder, enabled shared memory
- // for MediaBuffers for this process.
- MediaBuffer::useSharedMemory();
- sp<IDataSource> source = interface_cast<IDataSource>(b);
- const char *mime = data.readCString();
- sp<IMediaExtractor> ex = makeExtractor(source, mime);
- reply->writeStrongBinder(IInterface::asBinder(ex));
- return NO_ERROR;
- }
-
- case MAKE_IDATA_SOURCE_FD: {
- CHECK_INTERFACE(IMediaExtractorService, data, reply);
- const int fd = dup(data.readFileDescriptor()); // -1 fd checked in makeIDataSource
- const int64_t offset = data.readInt64();
- const int64_t length = data.readInt64();
- ALOGV("fd %d offset%lld length:%lld", fd, (long long)offset, (long long)length);
- sp<IDataSource> source = makeIDataSource(fd, offset, length);
- reply->writeStrongBinder(IInterface::asBinder(source));
- // The FileSource closes the descriptor, so if it is not created
- // we need to close the descriptor explicitly.
- if (source.get() == nullptr && fd != -1) {
- close(fd);
- }
- return NO_ERROR;
- }
-
- case GET_SUPPORTED_TYPES:
- {
- CHECK_INTERFACE(IMediaExtractorService, data, reply);
- std::unordered_set<std::string> supportedTypes = getSupportedTypes();
- for (auto it = supportedTypes.begin(); it != supportedTypes.end(); ++it) {
- reply->writeCString((*it).c_str());
- }
- return NO_ERROR;
- }
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-// ----------------------------------------------------------------------------
-
-} // namespace android
diff --git a/media/libmedia/IMediaHTTPConnection.cpp b/media/libmedia/IMediaHTTPConnection.cpp
index 1bb8d67..8cbb4c2 100644
--- a/media/libmedia/IMediaHTTPConnection.cpp
+++ b/media/libmedia/IMediaHTTPConnection.cpp
@@ -128,12 +128,12 @@
ALOGE("readAt got a NULL buffer");
return UNKNOWN_ERROR;
}
- if (mMemory->pointer() == NULL) {
- ALOGE("readAt got a NULL mMemory->pointer()");
+ if (mMemory->unsecurePointer() == NULL) {
+ ALOGE("readAt got a NULL mMemory->unsecurePointer()");
return UNKNOWN_ERROR;
}
- memcpy(buffer, mMemory->pointer(), len);
+ memcpy(buffer, mMemory->unsecurePointer(), len);
return len;
}
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index f9fa86e..8a3b84e 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -19,8 +19,8 @@
#include <stdint.h>
#include <sys/types.h>
+#include <android/IDataSource.h>
#include <binder/Parcel.h>
-#include <media/IDataSource.h>
#include <media/IMediaHTTPService.h>
#include <media/IMediaMetadataRetriever.h>
#include <processgroup/sched_policy.h>
@@ -109,7 +109,7 @@
data.writeInt32(0);
} else {
// serialize the headers
- data.writeInt64(headers->size());
+ data.writeInt32(headers->size());
for (size_t i = 0; i < headers->size(); ++i) {
data.writeString8(headers->keyAt(i));
data.writeString8(headers->valueAt(i));
@@ -213,15 +213,14 @@
return interface_cast<IMemory>(reply.readStrongBinder());
}
- status_t getFrameAtIndex(std::vector<sp<IMemory> > *frames,
- int frameIndex, int numFrames, int colorFormat, bool metaOnly)
+ sp<IMemory> getFrameAtIndex(
+ int index, int colorFormat, bool metaOnly)
{
- ALOGV("getFrameAtIndex: frameIndex(%d), numFrames(%d), colorFormat(%d) metaOnly(%d)",
- frameIndex, numFrames, colorFormat, metaOnly);
+ ALOGV("getFrameAtIndex: index(%d), colorFormat(%d) metaOnly(%d)",
+ index, colorFormat, metaOnly);
Parcel data, reply;
data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
- data.writeInt32(frameIndex);
- data.writeInt32(numFrames);
+ data.writeInt32(index);
data.writeInt32(colorFormat);
data.writeInt32(metaOnly);
#ifndef DISABLE_GROUP_SCHEDULE_HACK
@@ -230,16 +229,9 @@
remote()->transact(GET_FRAME_AT_INDEX, data, &reply);
status_t ret = reply.readInt32();
if (ret != NO_ERROR) {
- return ret;
+ return NULL;
}
- int retNumFrames = reply.readInt32();
- if (retNumFrames < numFrames) {
- numFrames = retNumFrames;
- }
- for (int i = 0; i < numFrames; i++) {
- frames->push_back(interface_cast<IMemory>(reply.readStrongBinder()));
- }
- return OK;
+ return interface_cast<IMemory>(reply.readStrongBinder());
}
sp<IMemory> extractAlbumArt()
@@ -318,11 +310,22 @@
}
KeyedVector<String8, String8> headers;
- size_t numHeaders = (size_t) data.readInt64();
+ size_t numHeaders = (size_t) data.readInt32();
for (size_t i = 0; i < numHeaders; ++i) {
- String8 key = data.readString8();
- String8 value = data.readString8();
- headers.add(key, value);
+ String8 key;
+ String8 value;
+ status_t status;
+ status = data.readString8(&key);
+ if (status != OK) {
+ return status;
+ }
+ status = data.readString8(&value);
+ if (status != OK) {
+ return status;
+ }
+ if (headers.add(key, value) < 0) {
+ return UNKNOWN_ERROR;
+ }
}
reply->writeInt32(
@@ -431,24 +434,20 @@
case GET_FRAME_AT_INDEX: {
CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
- int frameIndex = data.readInt32();
- int numFrames = data.readInt32();
+ int index = data.readInt32();
int colorFormat = data.readInt32();
bool metaOnly = (data.readInt32() != 0);
- ALOGV("getFrameAtIndex: frameIndex(%d), numFrames(%d), colorFormat(%d), metaOnly(%d)",
- frameIndex, numFrames, colorFormat, metaOnly);
+ ALOGV("getFrameAtIndex: index(%d), colorFormat(%d), metaOnly(%d)",
+ index, colorFormat, metaOnly);
#ifndef DISABLE_GROUP_SCHEDULE_HACK
setSchedPolicy(data);
#endif
- std::vector<sp<IMemory> > frames;
- status_t err = getFrameAtIndex(
- &frames, frameIndex, numFrames, colorFormat, metaOnly);
- reply->writeInt32(err);
- if (OK == err) {
- reply->writeInt32(frames.size());
- for (size_t i = 0; i < frames.size(); i++) {
- reply->writeStrongBinder(IInterface::asBinder(frames[i]));
- }
+ sp<IMemory> frame = getFrameAtIndex(index, colorFormat, metaOnly);
+ if (frame != nullptr) { // Don't send NULL across the binder interface
+ reply->writeInt32(NO_ERROR);
+ reply->writeStrongBinder(IInterface::asBinder(frame));
+ } else {
+ reply->writeInt32(UNKNOWN_ERROR);
}
#ifndef DISABLE_GROUP_SCHEDULE_HACK
restoreSchedPolicy();
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index ea06665..20bc23d 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -19,18 +19,15 @@
#include <stdint.h>
#include <sys/types.h>
+#include <android/IDataSource.h>
#include <binder/Parcel.h>
-
+#include <gui/IGraphicBufferProducer.h>
#include <media/AudioResamplerPublic.h>
#include <media/AVSyncSettings.h>
#include <media/BufferingSettings.h>
-
-#include <media/IDataSource.h>
#include <media/IMediaHTTPService.h>
#include <media/IMediaPlayer.h>
#include <media/IStreamSource.h>
-
-#include <gui/IGraphicBufferProducer.h>
#include <utils/String8.h>
namespace android {
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
index a354ce1..ac86f72 100644
--- a/media/libmedia/IMediaRecorder.cpp
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -67,7 +67,9 @@
GET_ACTIVE_MICROPHONES,
GET_PORT_ID,
SET_PREFERRED_MICROPHONE_DIRECTION,
- SET_PREFERRED_MICROPHONE_FIELD_DIMENSION
+ SET_PREFERRED_MICROPHONE_FIELD_DIMENSION,
+ SET_PRIVACY_SENSITIVE,
+ GET_PRIVACY_SENSITIVE
};
class BpMediaRecorder: public BpInterface<IMediaRecorder>
@@ -151,6 +153,36 @@
return reply.readInt32();
}
+ status_t setPrivacySensitive(bool privacySensitive)
+ {
+ ALOGV("%s(%s)", __func__, privacySensitive ? "true" : "false");
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ data.writeInt32(privacySensitive ? 1 : 0);
+ status_t status = remote()->transact(SET_PRIVACY_SENSITIVE, data, &reply);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ return reply.readInt32();
+ }
+
+ status_t isPrivacySensitive(bool *privacySensitive) const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ *privacySensitive = false;
+ status_t status = remote()->transact(GET_PRIVACY_SENSITIVE, data, &reply);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ status = reply.readInt32();
+ if (status == NO_ERROR) {
+ *privacySensitive = reply.readInt32() == 1;
+ }
+ ALOGV("%s status %d enabled: %s", __func__, status, *privacySensitive ? "true" : "false");
+ return status;
+ }
+
status_t setOutputFormat(int of)
{
ALOGV("setOutputFormat(%d)", of);
@@ -537,6 +569,24 @@
reply->writeInt32(setAudioSource(as));
return NO_ERROR;
} break;
+ case SET_PRIVACY_SENSITIVE: {
+ ALOGV("SET_PRIVACY_SENSITIVE");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ bool privacySensitive = data.readInt32() == 1;
+ reply->writeInt32(setPrivacySensitive(privacySensitive));
+ return NO_ERROR;
+ } break;
+ case GET_PRIVACY_SENSITIVE: {
+ ALOGV("GET_PRIVACY_SENSITIVE");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ bool privacySensitive = false;
+ status_t status = isPrivacySensitive(&privacySensitive);
+ reply->writeInt32(status);
+ if (status == NO_ERROR) {
+ reply->writeInt32(privacySensitive ? 1 : 0);
+ }
+ return NO_ERROR;
+ } break;
case SET_OUTPUT_FORMAT: {
ALOGV("SET_OUTPUT_FORMAT");
CHECK_INTERFACE(IMediaRecorder, data, reply);
diff --git a/media/libmedia/IMediaSource.cpp b/media/libmedia/IMediaSource.cpp
index 50826c5..b18571f 100644
--- a/media/libmedia/IMediaSource.cpp
+++ b/media/libmedia/IMediaSource.cpp
@@ -26,7 +26,7 @@
#include <media/IMediaSource.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
namespace android {
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index bc0c2cd..959a3d7 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -29,7 +29,6 @@
#include <utils/NativeHandle.h>
#include <media/omx/1.0/WOmxNode.h>
-#include <android/IGraphicBufferSource.h>
#include <android/IOMXBufferSource.h>
namespace android {
diff --git a/media/libmedia/IResourceManagerClient.cpp b/media/libmedia/IResourceManagerClient.cpp
deleted file mode 100644
index 1fea479..0000000
--- a/media/libmedia/IResourceManagerClient.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
-**
-** Copyright 2015, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <utils/RefBase.h>
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-
-#include <media/IResourceManagerClient.h>
-
-namespace android {
-
-enum {
- RECLAIM_RESOURCE = IBinder::FIRST_CALL_TRANSACTION,
- GET_NAME,
-};
-
-class BpResourceManagerClient: public BpInterface<IResourceManagerClient>
-{
-public:
- explicit BpResourceManagerClient(const sp<IBinder> &impl)
- : BpInterface<IResourceManagerClient>(impl)
- {
- }
-
- virtual bool reclaimResource() {
- Parcel data, reply;
- data.writeInterfaceToken(IResourceManagerClient::getInterfaceDescriptor());
-
- bool ret = false;
- status_t status = remote()->transact(RECLAIM_RESOURCE, data, &reply);
- if (status == NO_ERROR) {
- ret = (bool)reply.readInt32();
- }
- return ret;
- }
-
- virtual String8 getName() {
- Parcel data, reply;
- data.writeInterfaceToken(IResourceManagerClient::getInterfaceDescriptor());
-
- String8 ret;
- status_t status = remote()->transact(GET_NAME, data, &reply);
- if (status == NO_ERROR) {
- ret = reply.readString8();
- }
- return ret;
- }
-
-};
-
-IMPLEMENT_META_INTERFACE(ResourceManagerClient, "android.media.IResourceManagerClient");
-
-// ----------------------------------------------------------------------
-
-status_t BnResourceManagerClient::onTransact(
- uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags)
-{
- switch (code) {
- case RECLAIM_RESOURCE: {
- CHECK_INTERFACE(IResourceManagerClient, data, reply);
- bool ret = reclaimResource();
- reply->writeInt32(ret);
- return NO_ERROR;
- } break;
- case GET_NAME: {
- CHECK_INTERFACE(IResourceManagerClient, data, reply);
- String8 ret = getName();
- reply->writeString8(ret);
- return NO_ERROR;
- } break;
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-}; // namespace android
diff --git a/media/libmedia/IResourceManagerService.cpp b/media/libmedia/IResourceManagerService.cpp
deleted file mode 100644
index f8a0a14..0000000
--- a/media/libmedia/IResourceManagerService.cpp
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
-**
-** Copyright 2015, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "IResourceManagerService"
-#include <utils/Log.h>
-
-#include <media/IResourceManagerService.h>
-
-#include <binder/Parcel.h>
-
-#include <stdint.h>
-#include <sys/types.h>
-
-namespace android {
-
-enum {
- CONFIG = IBinder::FIRST_CALL_TRANSACTION,
- ADD_RESOURCE,
- REMOVE_RESOURCE,
- REMOVE_CLIENT,
- RECLAIM_RESOURCE,
-};
-
-template <typename T>
-static void writeToParcel(Parcel *data, const Vector<T> &items) {
- size_t size = items.size();
- // truncates size, but should be okay for this usecase
- data->writeUint32(static_cast<uint32_t>(size));
- for (size_t i = 0; i < size; i++) {
- items[i].writeToParcel(data);
- }
-}
-
-template <typename T>
-static void readFromParcel(const Parcel &data, Vector<T> *items) {
- size_t size = (size_t)data.readUint32();
- for (size_t i = 0; i < size && data.dataAvail() > 0; i++) {
- T item;
- item.readFromParcel(data);
- items->add(item);
- }
-}
-
-class BpResourceManagerService : public BpInterface<IResourceManagerService>
-{
-public:
- explicit BpResourceManagerService(const sp<IBinder> &impl)
- : BpInterface<IResourceManagerService>(impl)
- {
- }
-
- virtual void config(const Vector<MediaResourcePolicy> &policies) {
- Parcel data, reply;
- data.writeInterfaceToken(IResourceManagerService::getInterfaceDescriptor());
- writeToParcel(&data, policies);
- remote()->transact(CONFIG, data, &reply);
- }
-
- virtual void addResource(
- int pid,
- int uid,
- int64_t clientId,
- const sp<IResourceManagerClient> client,
- const Vector<MediaResource> &resources) {
- Parcel data, reply;
- data.writeInterfaceToken(IResourceManagerService::getInterfaceDescriptor());
- data.writeInt32(pid);
- data.writeInt32(uid);
- data.writeInt64(clientId);
- data.writeStrongBinder(IInterface::asBinder(client));
- writeToParcel(&data, resources);
-
- remote()->transact(ADD_RESOURCE, data, &reply);
- }
-
- virtual void removeResource(int pid, int64_t clientId, const Vector<MediaResource> &resources) {
- Parcel data, reply;
- data.writeInterfaceToken(IResourceManagerService::getInterfaceDescriptor());
- data.writeInt32(pid);
- data.writeInt64(clientId);
- writeToParcel(&data, resources);
-
- remote()->transact(REMOVE_RESOURCE, data, &reply);
- }
-
- virtual void removeClient(int pid, int64_t clientId) {
- Parcel data, reply;
- data.writeInterfaceToken(IResourceManagerService::getInterfaceDescriptor());
- data.writeInt32(pid);
- data.writeInt64(clientId);
-
- remote()->transact(REMOVE_CLIENT, data, &reply);
- }
-
- virtual bool reclaimResource(int callingPid, const Vector<MediaResource> &resources) {
- Parcel data, reply;
- data.writeInterfaceToken(IResourceManagerService::getInterfaceDescriptor());
- data.writeInt32(callingPid);
- writeToParcel(&data, resources);
-
- bool ret = false;
- status_t status = remote()->transact(RECLAIM_RESOURCE, data, &reply);
- if (status == NO_ERROR) {
- ret = (bool)reply.readInt32();
- }
- return ret;
- }
-};
-
-IMPLEMENT_META_INTERFACE(ResourceManagerService, "android.media.IResourceManagerService");
-
-// ----------------------------------------------------------------------
-
-
-status_t BnResourceManagerService::onTransact(
- uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags)
-{
- switch (code) {
- case CONFIG: {
- CHECK_INTERFACE(IResourceManagerService, data, reply);
- Vector<MediaResourcePolicy> policies;
- readFromParcel(data, &policies);
- config(policies);
- return NO_ERROR;
- } break;
-
- case ADD_RESOURCE: {
- CHECK_INTERFACE(IResourceManagerService, data, reply);
- int pid = data.readInt32();
- int uid = data.readInt32();
- int64_t clientId = data.readInt64();
- sp<IResourceManagerClient> client(
- interface_cast<IResourceManagerClient>(data.readStrongBinder()));
- if (client == NULL) {
- return NO_ERROR;
- }
- Vector<MediaResource> resources;
- readFromParcel(data, &resources);
- addResource(pid, uid, clientId, client, resources);
- return NO_ERROR;
- } break;
-
- case REMOVE_RESOURCE: {
- CHECK_INTERFACE(IResourceManagerService, data, reply);
- int pid = data.readInt32();
- int64_t clientId = data.readInt64();
- Vector<MediaResource> resources;
- readFromParcel(data, &resources);
- removeResource(pid, clientId, resources);
- return NO_ERROR;
- } break;
-
- case REMOVE_CLIENT: {
- CHECK_INTERFACE(IResourceManagerService, data, reply);
- int pid = data.readInt32();
- int64_t clientId = data.readInt64();
- removeClient(pid, clientId);
- return NO_ERROR;
- } break;
-
- case RECLAIM_RESOURCE: {
- CHECK_INTERFACE(IResourceManagerService, data, reply);
- int callingPid = data.readInt32();
- Vector<MediaResource> resources;
- readFromParcel(data, &resources);
- bool ret = reclaimResource(callingPid, resources);
- reply->writeInt32(ret);
- return NO_ERROR;
- } break;
-
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp
deleted file mode 100644
index 0d3c1ba..0000000
--- a/media/libmedia/JetPlayer.cpp
+++ /dev/null
@@ -1,471 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "JetPlayer-C"
-
-#include <utils/Log.h>
-#include <media/JetPlayer.h>
-
-
-namespace android
-{
-
-static const int MIX_NUM_BUFFERS = 4;
-static const S_EAS_LIB_CONFIG* pLibConfig = NULL;
-
-//-------------------------------------------------------------------------------------------------
-JetPlayer::JetPlayer(void *javaJetPlayer, int maxTracks, int trackBufferSize) :
- mEventCallback(NULL),
- mJavaJetPlayerRef(javaJetPlayer),
- mTid(-1),
- mRender(false),
- mPaused(false),
- mMaxTracks(maxTracks),
- mEasData(NULL),
- mIoWrapper(NULL),
- mTrackBufferSize(trackBufferSize)
-{
- ALOGV("JetPlayer constructor");
- mPreviousJetStatus.currentUserID = -1;
- mPreviousJetStatus.segmentRepeatCount = -1;
- mPreviousJetStatus.numQueuedSegments = -1;
- mPreviousJetStatus.paused = true;
-}
-
-//-------------------------------------------------------------------------------------------------
-JetPlayer::~JetPlayer()
-{
- ALOGV("~JetPlayer");
- release();
-}
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::init()
-{
- //Mutex::Autolock lock(&mMutex);
-
- EAS_RESULT result;
-
- // retrieve the EAS library settings
- if (pLibConfig == NULL)
- pLibConfig = EAS_Config();
- if (pLibConfig == NULL) {
- ALOGE("JetPlayer::init(): EAS library configuration could not be retrieved, aborting.");
- return EAS_FAILURE;
- }
-
- // init the EAS library
- result = EAS_Init(&mEasData);
- if (result != EAS_SUCCESS) {
- ALOGE("JetPlayer::init(): Error initializing Sonivox EAS library, aborting.");
- mState = EAS_STATE_ERROR;
- return result;
- }
- // init the JET library with the default app event controller range
- result = JET_Init(mEasData, NULL, sizeof(S_JET_CONFIG));
- if (result != EAS_SUCCESS) {
- ALOGE("JetPlayer::init(): Error initializing JET library, aborting.");
- mState = EAS_STATE_ERROR;
- return result;
- }
-
- // create the output AudioTrack
- mAudioTrack = new AudioTrack();
- status_t status = mAudioTrack->set(AUDIO_STREAM_MUSIC, //TODO parameterize this
- pLibConfig->sampleRate,
- AUDIO_FORMAT_PCM_16_BIT,
- audio_channel_out_mask_from_count(pLibConfig->numChannels),
- (size_t) mTrackBufferSize,
- AUDIO_OUTPUT_FLAG_NONE);
- if (status != OK) {
- ALOGE("JetPlayer::init(): Error initializing JET library; AudioTrack error %d", status);
- mAudioTrack.clear();
- mState = EAS_STATE_ERROR;
- return EAS_FAILURE;
- }
-
- // create render and playback thread
- {
- Mutex::Autolock l(mMutex);
- ALOGV("JetPlayer::init(): trying to start render thread");
- mThread = new JetPlayerThread(this);
- mThread->run("jetRenderThread", ANDROID_PRIORITY_AUDIO);
- mCondition.wait(mMutex);
- }
- if (mTid > 0) {
- // render thread started, we're ready
- ALOGV("JetPlayer::init(): render thread(%d) successfully started.", mTid);
- mState = EAS_STATE_READY;
- } else {
- ALOGE("JetPlayer::init(): failed to start render thread.");
- mState = EAS_STATE_ERROR;
- return EAS_FAILURE;
- }
-
- return EAS_SUCCESS;
-}
-
-void JetPlayer::setEventCallback(jetevent_callback eventCallback)
-{
- Mutex::Autolock l(mMutex);
- mEventCallback = eventCallback;
-}
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::release()
-{
- ALOGV("JetPlayer::release()");
- Mutex::Autolock lock(mMutex);
- mPaused = true;
- mRender = false;
- if (mEasData) {
- JET_Pause(mEasData);
- JET_CloseFile(mEasData);
- JET_Shutdown(mEasData);
- EAS_Shutdown(mEasData);
- }
- delete mIoWrapper;
- mIoWrapper = NULL;
- if (mAudioTrack != 0) {
- mAudioTrack->stop();
- mAudioTrack->flush();
- mAudioTrack.clear();
- }
- if (mAudioBuffer) {
- delete mAudioBuffer;
- mAudioBuffer = NULL;
- }
- mEasData = NULL;
-
- return EAS_SUCCESS;
-}
-
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::render() {
- EAS_RESULT result = EAS_FAILURE;
- EAS_I32 count;
- int temp;
- bool audioStarted = false;
-
- ALOGV("JetPlayer::render(): entering");
-
- // allocate render buffer
- mAudioBuffer =
- new EAS_PCM[pLibConfig->mixBufferSize * pLibConfig->numChannels * MIX_NUM_BUFFERS];
-
- // signal main thread that we started
- {
- Mutex::Autolock l(mMutex);
- mTid = gettid();
- ALOGV("JetPlayer::render(): render thread(%d) signal", mTid);
- mCondition.signal();
- }
-
- while (1) {
-
- mMutex.lock(); // [[[[[[[[ LOCK ---------------------------------------
-
- if (mEasData == NULL) {
- mMutex.unlock();
- ALOGV("JetPlayer::render(): NULL EAS data, exiting render.");
- goto threadExit;
- }
-
- // nothing to render, wait for client thread to wake us up
- while (!mRender)
- {
- ALOGV("JetPlayer::render(): signal wait");
- if (audioStarted) {
- mAudioTrack->pause();
- // we have to restart the playback once we start rendering again
- audioStarted = false;
- }
- mCondition.wait(mMutex);
- ALOGV("JetPlayer::render(): signal rx'd");
- }
-
- // render midi data into the input buffer
- int num_output = 0;
- EAS_PCM* p = mAudioBuffer;
- for (int i = 0; i < MIX_NUM_BUFFERS; i++) {
- result = EAS_Render(mEasData, p, pLibConfig->mixBufferSize, &count);
- if (result != EAS_SUCCESS) {
- ALOGE("JetPlayer::render(): EAS_Render returned error %ld", result);
- }
- p += count * pLibConfig->numChannels;
- num_output += count * pLibConfig->numChannels * sizeof(EAS_PCM);
-
- // send events that were generated (if any) to the event callback
- fireEventsFromJetQueue();
- }
-
- // update playback state
- //ALOGV("JetPlayer::render(): updating state");
- JET_Status(mEasData, &mJetStatus);
- fireUpdateOnStatusChange();
- mPaused = mJetStatus.paused;
-
- mMutex.unlock(); // UNLOCK ]]]]]]]] -----------------------------------
-
- // check audio output track
- if (mAudioTrack == NULL) {
- ALOGE("JetPlayer::render(): output AudioTrack was not created");
- goto threadExit;
- }
-
- // Write data to the audio hardware
- //ALOGV("JetPlayer::render(): writing to audio output");
- if ((temp = mAudioTrack->write(mAudioBuffer, num_output)) < 0) {
- ALOGE("JetPlayer::render(): Error in writing:%d",temp);
- return temp;
- }
-
- // start audio output if necessary
- if (!audioStarted) {
- ALOGV("JetPlayer::render(): starting audio playback");
- mAudioTrack->start();
- audioStarted = true;
- }
-
- }//while (1)
-
-threadExit:
- if (mAudioTrack != NULL) {
- mAudioTrack->stop();
- mAudioTrack->flush();
- }
- delete [] mAudioBuffer;
- mAudioBuffer = NULL;
- mMutex.lock();
- mTid = -1;
- mCondition.signal();
- mMutex.unlock();
- return result;
-}
-
-
-//-------------------------------------------------------------------------------------------------
-// fire up an update if any of the status fields has changed
-// precondition: mMutex locked
-void JetPlayer::fireUpdateOnStatusChange()
-{
- if ( (mJetStatus.currentUserID != mPreviousJetStatus.currentUserID)
- ||(mJetStatus.segmentRepeatCount != mPreviousJetStatus.segmentRepeatCount) ) {
- if (mEventCallback) {
- mEventCallback(
- JetPlayer::JET_USERID_UPDATE,
- mJetStatus.currentUserID,
- mJetStatus.segmentRepeatCount,
- mJavaJetPlayerRef);
- }
- mPreviousJetStatus.currentUserID = mJetStatus.currentUserID;
- mPreviousJetStatus.segmentRepeatCount = mJetStatus.segmentRepeatCount;
- }
-
- if (mJetStatus.numQueuedSegments != mPreviousJetStatus.numQueuedSegments) {
- if (mEventCallback) {
- mEventCallback(
- JetPlayer::JET_NUMQUEUEDSEGMENT_UPDATE,
- mJetStatus.numQueuedSegments,
- -1,
- mJavaJetPlayerRef);
- }
- mPreviousJetStatus.numQueuedSegments = mJetStatus.numQueuedSegments;
- }
-
- if (mJetStatus.paused != mPreviousJetStatus.paused) {
- if (mEventCallback) {
- mEventCallback(JetPlayer::JET_PAUSE_UPDATE,
- mJetStatus.paused,
- -1,
- mJavaJetPlayerRef);
- }
- mPreviousJetStatus.paused = mJetStatus.paused;
- }
-
-}
-
-
-//-------------------------------------------------------------------------------------------------
-// fire up all the JET events in the JET engine queue (until the queue is empty)
-// precondition: mMutex locked
-void JetPlayer::fireEventsFromJetQueue()
-{
- if (!mEventCallback) {
- // no callback, just empty the event queue
- while (JET_GetEvent(mEasData, NULL, NULL)) { }
- return;
- }
-
- EAS_U32 rawEvent;
- while (JET_GetEvent(mEasData, &rawEvent, NULL)) {
- mEventCallback(
- JetPlayer::JET_EVENT,
- rawEvent,
- -1,
- mJavaJetPlayerRef);
- }
-}
-
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::loadFromFile(const char* path)
-{
- ALOGV("JetPlayer::loadFromFile(): path=%s", path);
-
- Mutex::Autolock lock(mMutex);
-
- delete mIoWrapper;
- mIoWrapper = new MidiIoWrapper(path);
-
- EAS_RESULT result = JET_OpenFile(mEasData, mIoWrapper->getLocator());
- if (result != EAS_SUCCESS)
- mState = EAS_STATE_ERROR;
- else
- mState = EAS_STATE_OPEN;
- return( result );
-}
-
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::loadFromFD(const int fd, const long long offset, const long long length)
-{
- ALOGV("JetPlayer::loadFromFD(): fd=%d offset=%lld length=%lld", fd, offset, length);
-
- Mutex::Autolock lock(mMutex);
-
- delete mIoWrapper;
- mIoWrapper = new MidiIoWrapper(fd, offset, length);
-
- EAS_RESULT result = JET_OpenFile(mEasData, mIoWrapper->getLocator());
- if (result != EAS_SUCCESS)
- mState = EAS_STATE_ERROR;
- else
- mState = EAS_STATE_OPEN;
- return( result );
-}
-
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::closeFile()
-{
- Mutex::Autolock lock(mMutex);
- return JET_CloseFile(mEasData);
-}
-
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::play()
-{
- ALOGV("JetPlayer::play(): entering");
- Mutex::Autolock lock(mMutex);
-
- EAS_RESULT result = JET_Play(mEasData);
-
- mPaused = false;
- mRender = true;
-
- JET_Status(mEasData, &mJetStatus);
- this->dumpJetStatus(&mJetStatus);
-
- fireUpdateOnStatusChange();
-
- // wake up render thread
- ALOGV("JetPlayer::play(): wakeup render thread");
- mCondition.signal();
-
- return result;
-}
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::pause()
-{
- Mutex::Autolock lock(mMutex);
- mPaused = true;
- EAS_RESULT result = JET_Pause(mEasData);
-
- mRender = false;
-
- JET_Status(mEasData, &mJetStatus);
- this->dumpJetStatus(&mJetStatus);
- fireUpdateOnStatusChange();
-
-
- return result;
-}
-
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::queueSegment(int segmentNum, int libNum, int repeatCount, int transpose,
- EAS_U32 muteFlags, EAS_U8 userID)
-{
- ALOGV("JetPlayer::queueSegment segmentNum=%d, libNum=%d, repeatCount=%d, transpose=%d",
- segmentNum, libNum, repeatCount, transpose);
- Mutex::Autolock lock(mMutex);
- return JET_QueueSegment(mEasData, segmentNum, libNum, repeatCount, transpose, muteFlags,
- userID);
-}
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::setMuteFlags(EAS_U32 muteFlags, bool sync)
-{
- Mutex::Autolock lock(mMutex);
- return JET_SetMuteFlags(mEasData, muteFlags, sync);
-}
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::setMuteFlag(int trackNum, bool muteFlag, bool sync)
-{
- Mutex::Autolock lock(mMutex);
- return JET_SetMuteFlag(mEasData, trackNum, muteFlag, sync);
-}
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::triggerClip(int clipId)
-{
- ALOGV("JetPlayer::triggerClip clipId=%d", clipId);
- Mutex::Autolock lock(mMutex);
- return JET_TriggerClip(mEasData, clipId);
-}
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::clearQueue()
-{
- ALOGV("JetPlayer::clearQueue");
- Mutex::Autolock lock(mMutex);
- return JET_Clear_Queue(mEasData);
-}
-
-//-------------------------------------------------------------------------------------------------
-void JetPlayer::dump()
-{
-}
-
-void JetPlayer::dumpJetStatus(S_JET_STATUS* pJetStatus)
-{
- if (pJetStatus!=NULL)
- ALOGV(">> current JET player status: userID=%d segmentRepeatCount=%d numQueuedSegments=%d "
- "paused=%d",
- pJetStatus->currentUserID, pJetStatus->segmentRepeatCount,
- pJetStatus->numQueuedSegments, pJetStatus->paused);
- else
- ALOGE(">> JET player status is NULL");
-}
-
-
-} // end namespace android
diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp
index 98c5497..637322f 100644
--- a/media/libmedia/MediaProfiles.cpp
+++ b/media/libmedia/MediaProfiles.cpp
@@ -29,9 +29,55 @@
#include <OMX_Video.h>
#include <sys/stat.h>
+#include <array>
+#include <string>
+#include <vector>
+
namespace android {
-constexpr char const * const MediaProfiles::xmlFiles[];
+namespace /* unnamed */ {
+
+// Returns a list of possible paths for the media_profiles XML file.
+std::array<char const*, 5> const& getXmlPaths() {
+ static std::array<std::string const, 5> const paths =
+ []() -> decltype(paths) {
+ // Directories for XML file that will be searched (in this order).
+ constexpr std::array<char const*, 4> searchDirs = {
+ "product/etc/",
+ "odm/etc/",
+ "vendor/etc/",
+ "system/etc/",
+ };
+
+ // The file name may contain a variant if the vendor property
+ // ro.vendor.media_profiles_xml_variant is set.
+ char variant[PROPERTY_VALUE_MAX];
+ property_get("ro.media.xml_variant.profiles",
+ variant,
+ "_V1_0");
+
+ std::string fileName =
+ std::string("media_profiles") + variant + ".xml";
+
+ return { searchDirs[0] + fileName,
+ searchDirs[1] + fileName,
+ searchDirs[2] + fileName,
+ searchDirs[3] + fileName,
+ "system/etc/media_profiles_V1_0.xml" // System fallback
+ };
+ }();
+ static std::array<char const*, 5> const cPaths = {
+ paths[0].data(),
+ paths[1].data(),
+ paths[2].data(),
+ paths[3].data(),
+ paths[4].data()
+ };
+ return cPaths;
+}
+
+} // unnamed namespace
+
Mutex MediaProfiles::sLock;
bool MediaProfiles::sIsInitialized = false;
MediaProfiles *MediaProfiles::sInstance = NULL;
@@ -48,7 +94,7 @@
{"amrwb", AUDIO_ENCODER_AMR_WB},
{"aac", AUDIO_ENCODER_AAC},
{"heaac", AUDIO_ENCODER_HE_AAC},
- {"aaceld", AUDIO_ENCODER_AAC_ELD},
+ {"aaceld", AUDIO_ENCODER_AAC_ELD},
{"opus", AUDIO_ENCODER_OPUS}
};
@@ -610,7 +656,7 @@
char value[PROPERTY_VALUE_MAX];
if (property_get("media.settings.xml", value, NULL) <= 0) {
const char* xmlFile = nullptr;
- for (auto const& f : xmlFiles) {
+ for (auto const& f : getXmlPaths()) {
if (checkXmlFile(f)) {
xmlFile = f;
break;
diff --git a/media/libmedia/MediaResource.cpp b/media/libmedia/MediaResource.cpp
index e636a50..0936a99 100644
--- a/media/libmedia/MediaResource.cpp
+++ b/media/libmedia/MediaResource.cpp
@@ -19,47 +19,73 @@
#include <utils/Log.h>
#include <media/MediaResource.h>
+#include <vector>
+
namespace android {
-MediaResource::MediaResource()
- : mType(kUnspecified),
- mSubType(kUnspecifiedSubType),
- mValue(0) {}
-
-MediaResource::MediaResource(Type type, uint64_t value)
- : mType(type),
- mSubType(kUnspecifiedSubType),
- mValue(value) {}
-
-MediaResource::MediaResource(Type type, SubType subType, uint64_t value)
- : mType(type),
- mSubType(subType),
- mValue(value) {}
-
-void MediaResource::readFromParcel(const Parcel &parcel) {
- mType = static_cast<Type>(parcel.readInt32());
- mSubType = static_cast<SubType>(parcel.readInt32());
- mValue = parcel.readUint64();
+MediaResource::MediaResource(Type type, int64_t value) {
+ this->type = type;
+ this->subType = SubType::kUnspecifiedSubType;
+ this->value = value;
}
-void MediaResource::writeToParcel(Parcel *parcel) const {
- parcel->writeInt32(static_cast<int32_t>(mType));
- parcel->writeInt32(static_cast<int32_t>(mSubType));
- parcel->writeUint64(mValue);
+MediaResource::MediaResource(Type type, SubType subType, int64_t value) {
+ this->type = type;
+ this->subType = subType;
+ this->value = value;
}
-String8 MediaResource::toString() const {
+MediaResource::MediaResource(Type type, const std::vector<int8_t> &id, int64_t value) {
+ this->type = type;
+ this->subType = SubType::kUnspecifiedSubType;
+ this->id = id;
+ this->value = value;
+}
+
+//static
+MediaResource MediaResource::CodecResource(bool secure, bool video) {
+ return MediaResource(
+ secure ? Type::kSecureCodec : Type::kNonSecureCodec,
+ video ? SubType::kVideoCodec : SubType::kAudioCodec,
+ 1);
+}
+
+//static
+MediaResource MediaResource::GraphicMemoryResource(int64_t value) {
+ return MediaResource(Type::kGraphicMemory, value);
+}
+
+//static
+MediaResource MediaResource::CpuBoostResource() {
+ return MediaResource(Type::kCpuBoost, 1);
+}
+
+//static
+MediaResource MediaResource::VideoBatteryResource() {
+ return MediaResource(Type::kBattery, SubType::kVideoCodec, 1);
+}
+
+//static
+MediaResource MediaResource::DrmSessionResource(const std::vector<int8_t> &id, int64_t value) {
+ return MediaResource(Type::kDrmSession, id, value);
+}
+
+static String8 bytesToHexString(const std::vector<int8_t> &bytes) {
String8 str;
- str.appendFormat("%s/%s:%llu", asString(mType), asString(mSubType), (unsigned long long)mValue);
+ for (auto &b : bytes) {
+ str.appendFormat("%02x", b);
+ }
return str;
}
-bool MediaResource::operator==(const MediaResource &other) const {
- return (other.mType == mType) && (other.mSubType == mSubType) && (other.mValue == mValue);
-}
+String8 toString(const MediaResourceParcel& resource) {
+ String8 str;
-bool MediaResource::operator!=(const MediaResource &other) const {
- return !(*this == other);
+ str.appendFormat("%s/%s:[%s]:%lld",
+ asString(resource.type), asString(resource.subType),
+ bytesToHexString(resource.id).c_str(),
+ (long long)resource.value);
+ return str;
}
}; // namespace android
diff --git a/media/libmedia/MediaResourcePolicy.cpp b/media/libmedia/MediaResourcePolicy.cpp
index 5210825..afa971d 100644
--- a/media/libmedia/MediaResourcePolicy.cpp
+++ b/media/libmedia/MediaResourcePolicy.cpp
@@ -16,33 +16,32 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "MediaResourcePolicy"
-#include <utils/Log.h>
+
+#include <aidl/android/media/IResourceManagerService.h>
#include <media/MediaResourcePolicy.h>
+#include <utils/Log.h>
namespace android {
-const char kPolicySupportsMultipleSecureCodecs[] = "supports-multiple-secure-codecs";
-const char kPolicySupportsSecureWithNonSecureCodec[] = "supports-secure-with-non-secure-codec";
-
-MediaResourcePolicy::MediaResourcePolicy() {}
-
-MediaResourcePolicy::MediaResourcePolicy(String8 type, String8 value)
- : mType(type),
- mValue(value) {}
-
-void MediaResourcePolicy::readFromParcel(const Parcel &parcel) {
- mType = parcel.readString8();
- mValue = parcel.readString8();
+using aidl::android::media::IResourceManagerService;
+//static
+const char* MediaResourcePolicy::kPolicySupportsMultipleSecureCodecs() {
+ return IResourceManagerService::kPolicySupportsMultipleSecureCodecs;
+}
+//static
+const char* MediaResourcePolicy::kPolicySupportsSecureWithNonSecureCodec() {
+ return IResourceManagerService::kPolicySupportsSecureWithNonSecureCodec;
}
-void MediaResourcePolicy::writeToParcel(Parcel *parcel) const {
- parcel->writeString8(mType);
- parcel->writeString8(mValue);
+MediaResourcePolicy::MediaResourcePolicy(
+ const std::string& type, const std::string& value) {
+ this->type = type;
+ this->value = value;
}
-String8 MediaResourcePolicy::toString() const {
+String8 toString(const MediaResourcePolicyParcel &policy) {
String8 str;
- str.appendFormat("%s:%s", mType.string(), mValue.string());
+ str.appendFormat("%s:%s", policy.type.c_str(), policy.value.c_str());
return str;
}
diff --git a/media/libmedia/MediaUtils.cpp b/media/libmedia/MediaUtils.cpp
index 31972fa..2efb30e 100644
--- a/media/libmedia/MediaUtils.cpp
+++ b/media/libmedia/MediaUtils.cpp
@@ -22,7 +22,7 @@
#include <sys/resource.h>
#include <unistd.h>
-#include <bionic_malloc.h>
+#include <bionic/malloc.h>
#include "MediaUtils.h"
diff --git a/media/libmedia/MidiDeviceInfo.cpp b/media/libmedia/MidiDeviceInfo.cpp
deleted file mode 100644
index 7588e00..0000000
--- a/media/libmedia/MidiDeviceInfo.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "MidiDeviceInfo"
-
-#include <media/MidiDeviceInfo.h>
-
-#include <binder/Parcel.h>
-#include <log/log.h>
-#include <utils/Errors.h>
-#include <utils/String16.h>
-
-namespace android {
-namespace media {
-namespace midi {
-
-// The constant values need to be kept in sync with MidiDeviceInfo.java.
-// static
-const char* const MidiDeviceInfo::PROPERTY_NAME = "name";
-const char* const MidiDeviceInfo::PROPERTY_MANUFACTURER = "manufacturer";
-const char* const MidiDeviceInfo::PROPERTY_PRODUCT = "product";
-const char* const MidiDeviceInfo::PROPERTY_VERSION = "version";
-const char* const MidiDeviceInfo::PROPERTY_SERIAL_NUMBER = "serial_number";
-const char* const MidiDeviceInfo::PROPERTY_ALSA_CARD = "alsa_card";
-const char* const MidiDeviceInfo::PROPERTY_ALSA_DEVICE = "alsa_device";
-
-String16 MidiDeviceInfo::getProperty(const char* propertyName) {
- String16 value;
- if (mProperties.getString(String16(propertyName), &value)) {
- return value;
- } else {
- return String16();
- }
-}
-
-#define RETURN_IF_FAILED(calledOnce) \
- { \
- status_t returnStatus = calledOnce; \
- if (returnStatus) { \
- ALOGE("Failed at %s:%d (%s)", __FILE__, __LINE__, __func__); \
- return returnStatus; \
- } \
- }
-
-status_t MidiDeviceInfo::writeToParcel(Parcel* parcel) const {
- // Needs to be kept in sync with code in MidiDeviceInfo.java
- RETURN_IF_FAILED(parcel->writeInt32(mType));
- RETURN_IF_FAILED(parcel->writeInt32(mId));
- RETURN_IF_FAILED(parcel->writeInt32((int32_t)mInputPortNames.size()));
- RETURN_IF_FAILED(parcel->writeInt32((int32_t)mOutputPortNames.size()));
- RETURN_IF_FAILED(writeStringVector(parcel, mInputPortNames));
- RETURN_IF_FAILED(writeStringVector(parcel, mOutputPortNames));
- RETURN_IF_FAILED(parcel->writeInt32(mIsPrivate ? 1 : 0));
- RETURN_IF_FAILED(mProperties.writeToParcel(parcel));
- // This corresponds to "extra" properties written by Java code
- RETURN_IF_FAILED(mProperties.writeToParcel(parcel));
- return OK;
-}
-
-status_t MidiDeviceInfo::readFromParcel(const Parcel* parcel) {
- // Needs to be kept in sync with code in MidiDeviceInfo.java
- RETURN_IF_FAILED(parcel->readInt32(&mType));
- RETURN_IF_FAILED(parcel->readInt32(&mId));
- int32_t inputPortCount;
- RETURN_IF_FAILED(parcel->readInt32(&inputPortCount));
- int32_t outputPortCount;
- RETURN_IF_FAILED(parcel->readInt32(&outputPortCount));
- RETURN_IF_FAILED(readStringVector(parcel, &mInputPortNames, inputPortCount));
- RETURN_IF_FAILED(readStringVector(parcel, &mOutputPortNames, outputPortCount));
- int32_t isPrivate;
- RETURN_IF_FAILED(parcel->readInt32(&isPrivate));
- mIsPrivate = isPrivate == 1;
- RETURN_IF_FAILED(mProperties.readFromParcel(parcel));
- // Ignore "extra" properties as they may contain Java Parcelables
- return OK;
-}
-
-status_t MidiDeviceInfo::readStringVector(
- const Parcel* parcel, Vector<String16> *vectorPtr, size_t defaultLength) {
- std::unique_ptr<std::vector<std::unique_ptr<String16>>> v;
- status_t result = parcel->readString16Vector(&v);
- if (result != OK) return result;
- vectorPtr->clear();
- if (v.get() != nullptr) {
- for (const auto& iter : *v) {
- if (iter.get() != nullptr) {
- vectorPtr->push_back(*iter);
- } else {
- vectorPtr->push_back(String16());
- }
- }
- } else {
- vectorPtr->resize(defaultLength);
- }
- return OK;
-}
-
-status_t MidiDeviceInfo::writeStringVector(Parcel* parcel, const Vector<String16>& vector) const {
- std::vector<String16> v;
- for (size_t i = 0; i < vector.size(); ++i) {
- v.push_back(vector[i]);
- }
- return parcel->writeString16Vector(v);
-}
-
-// Vector does not define operator==
-static inline bool areVectorsEqual(const Vector<String16>& lhs, const Vector<String16>& rhs) {
- if (lhs.size() != rhs.size()) return false;
- for (size_t i = 0; i < lhs.size(); ++i) {
- if (lhs[i] != rhs[i]) return false;
- }
- return true;
-}
-
-bool operator==(const MidiDeviceInfo& lhs, const MidiDeviceInfo& rhs) {
- return (lhs.mType == rhs.mType && lhs.mId == rhs.mId &&
- areVectorsEqual(lhs.mInputPortNames, rhs.mInputPortNames) &&
- areVectorsEqual(lhs.mOutputPortNames, rhs.mOutputPortNames) &&
- lhs.mProperties == rhs.mProperties &&
- lhs.mIsPrivate == rhs.mIsPrivate);
-}
-
-} // namespace midi
-} // namespace media
-} // namespace android
diff --git a/media/libmedia/MidiIoWrapper.cpp b/media/libmedia/MidiIoWrapper.cpp
index d8ef9cf..e71ea2c 100644
--- a/media/libmedia/MidiIoWrapper.cpp
+++ b/media/libmedia/MidiIoWrapper.cpp
@@ -17,7 +17,6 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "MidiIoWrapper"
#include <utils/Log.h>
-#include <utils/RefBase.h>
#include <sys/stat.h>
#include <fcntl.h>
@@ -50,7 +49,7 @@
mDataSource = nullptr;
}
-class DataSourceUnwrapper : public DataSourceBase {
+class MidiIoWrapper::DataSourceUnwrapper {
public:
explicit DataSourceUnwrapper(CDataSource *csource) {
diff --git a/media/libmedia/NdkWrapper.cpp b/media/libmedia/NdkWrapper.cpp
deleted file mode 100644
index c150407..0000000
--- a/media/libmedia/NdkWrapper.cpp
+++ /dev/null
@@ -1,1290 +0,0 @@
-/*
- * Copyright 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NdkWrapper"
-
-#include <media/NdkWrapper.h>
-
-#include <android/native_window.h>
-#include <log/log.h>
-#include <media/NdkMediaCodec.h>
-#include <media/NdkMediaCrypto.h>
-#include <media/NdkMediaDrm.h>
-#include <media/NdkMediaFormat.h>
-#include <media/NdkMediaExtractor.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <utils/Errors.h>
-
-#include "NdkMediaDataSourceCallbacksPriv.h"
-
-namespace android {
-
-static const size_t kAESBlockSize = 16; // AES_BLOCK_SIZE
-
-static const char *AMediaFormatKeyGroupInt32[] = {
- AMEDIAFORMAT_KEY_AAC_DRC_ATTENUATION_FACTOR,
- AMEDIAFORMAT_KEY_AAC_DRC_BOOST_FACTOR,
- AMEDIAFORMAT_KEY_AAC_DRC_HEAVY_COMPRESSION,
- AMEDIAFORMAT_KEY_AAC_DRC_TARGET_REFERENCE_LEVEL,
- AMEDIAFORMAT_KEY_AAC_ENCODED_TARGET_LEVEL,
- AMEDIAFORMAT_KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT,
- AMEDIAFORMAT_KEY_AAC_PROFILE,
- AMEDIAFORMAT_KEY_AAC_SBR_MODE,
- AMEDIAFORMAT_KEY_AUDIO_SESSION_ID,
- AMEDIAFORMAT_KEY_BITRATE_MODE,
- AMEDIAFORMAT_KEY_BIT_RATE,
- AMEDIAFORMAT_KEY_CAPTURE_RATE,
- AMEDIAFORMAT_KEY_CHANNEL_COUNT,
- AMEDIAFORMAT_KEY_CHANNEL_MASK,
- AMEDIAFORMAT_KEY_COLOR_FORMAT,
- AMEDIAFORMAT_KEY_COLOR_RANGE,
- AMEDIAFORMAT_KEY_COLOR_STANDARD,
- AMEDIAFORMAT_KEY_COLOR_TRANSFER,
- AMEDIAFORMAT_KEY_COMPLEXITY,
- AMEDIAFORMAT_KEY_CREATE_INPUT_SURFACE_SUSPENDED,
- AMEDIAFORMAT_KEY_CRYPTO_DEFAULT_IV_SIZE,
- AMEDIAFORMAT_KEY_CRYPTO_ENCRYPTED_BYTE_BLOCK,
- AMEDIAFORMAT_KEY_CRYPTO_MODE,
- AMEDIAFORMAT_KEY_CRYPTO_SKIP_BYTE_BLOCK,
- AMEDIAFORMAT_KEY_FLAC_COMPRESSION_LEVEL,
- AMEDIAFORMAT_KEY_GRID_COLUMNS,
- AMEDIAFORMAT_KEY_GRID_ROWS,
- AMEDIAFORMAT_KEY_HAPTIC_CHANNEL_COUNT,
- AMEDIAFORMAT_KEY_HEIGHT,
- AMEDIAFORMAT_KEY_INTRA_REFRESH_PERIOD,
- AMEDIAFORMAT_KEY_IS_ADTS,
- AMEDIAFORMAT_KEY_IS_AUTOSELECT,
- AMEDIAFORMAT_KEY_IS_DEFAULT,
- AMEDIAFORMAT_KEY_IS_FORCED_SUBTITLE,
- AMEDIAFORMAT_KEY_LATENCY,
- AMEDIAFORMAT_KEY_LEVEL,
- AMEDIAFORMAT_KEY_MAX_HEIGHT,
- AMEDIAFORMAT_KEY_MAX_INPUT_SIZE,
- AMEDIAFORMAT_KEY_MAX_WIDTH,
- AMEDIAFORMAT_KEY_PCM_ENCODING,
- AMEDIAFORMAT_KEY_PRIORITY,
- AMEDIAFORMAT_KEY_PROFILE,
- AMEDIAFORMAT_KEY_PUSH_BLANK_BUFFERS_ON_STOP,
- AMEDIAFORMAT_KEY_ROTATION,
- AMEDIAFORMAT_KEY_SAMPLE_RATE,
- AMEDIAFORMAT_KEY_SLICE_HEIGHT,
- AMEDIAFORMAT_KEY_STRIDE,
- AMEDIAFORMAT_KEY_TRACK_ID,
- AMEDIAFORMAT_KEY_WIDTH,
- AMEDIAFORMAT_KEY_DISPLAY_HEIGHT,
- AMEDIAFORMAT_KEY_DISPLAY_WIDTH,
- AMEDIAFORMAT_KEY_TEMPORAL_LAYER_ID,
- AMEDIAFORMAT_KEY_TILE_HEIGHT,
- AMEDIAFORMAT_KEY_TILE_WIDTH,
- AMEDIAFORMAT_KEY_TRACK_INDEX,
-};
-
-static const char *AMediaFormatKeyGroupInt64[] = {
- AMEDIAFORMAT_KEY_DURATION,
- AMEDIAFORMAT_KEY_MAX_PTS_GAP_TO_ENCODER,
- AMEDIAFORMAT_KEY_REPEAT_PREVIOUS_FRAME_AFTER,
- AMEDIAFORMAT_KEY_TIME_US,
-};
-
-static const char *AMediaFormatKeyGroupString[] = {
- AMEDIAFORMAT_KEY_LANGUAGE,
- AMEDIAFORMAT_KEY_MIME,
- AMEDIAFORMAT_KEY_TEMPORAL_LAYERING,
-};
-
-static const char *AMediaFormatKeyGroupBuffer[] = {
- AMEDIAFORMAT_KEY_CRYPTO_IV,
- AMEDIAFORMAT_KEY_CRYPTO_KEY,
- AMEDIAFORMAT_KEY_HDR_STATIC_INFO,
- AMEDIAFORMAT_KEY_SEI,
- AMEDIAFORMAT_KEY_MPEG_USER_DATA,
-};
-
-static const char *AMediaFormatKeyGroupCsd[] = {
- AMEDIAFORMAT_KEY_CSD_0,
- AMEDIAFORMAT_KEY_CSD_1,
- AMEDIAFORMAT_KEY_CSD_2,
-};
-
-static const char *AMediaFormatKeyGroupRect[] = {
- AMEDIAFORMAT_KEY_DISPLAY_CROP,
-};
-
-static const char *AMediaFormatKeyGroupFloatInt32[] = {
- AMEDIAFORMAT_KEY_FRAME_RATE,
- AMEDIAFORMAT_KEY_I_FRAME_INTERVAL,
- AMEDIAFORMAT_KEY_MAX_FPS_TO_ENCODER,
- AMEDIAFORMAT_KEY_OPERATING_RATE,
-};
-
-static status_t translateErrorCode(media_status_t err) {
- if (err == AMEDIA_OK) {
- return OK;
- } else if (err == AMEDIA_ERROR_END_OF_STREAM) {
- return ERROR_END_OF_STREAM;
- } else if (err == AMEDIA_ERROR_IO) {
- return ERROR_IO;
- } else if (err == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
- return -EAGAIN;
- }
-
- ALOGE("ndk error code: %d", err);
- return UNKNOWN_ERROR;
-}
-
-static int32_t translateActionCode(int32_t actionCode) {
- if (AMediaCodecActionCode_isTransient(actionCode)) {
- return ACTION_CODE_TRANSIENT;
- } else if (AMediaCodecActionCode_isRecoverable(actionCode)) {
- return ACTION_CODE_RECOVERABLE;
- }
- return ACTION_CODE_FATAL;
-}
-
-static CryptoPlugin::Mode translateToCryptoPluginMode(cryptoinfo_mode_t mode) {
- CryptoPlugin::Mode ret = CryptoPlugin::kMode_Unencrypted;
- switch (mode) {
- case AMEDIACODECRYPTOINFO_MODE_AES_CTR: {
- ret = CryptoPlugin::kMode_AES_CTR;
- break;
- }
-
- case AMEDIACODECRYPTOINFO_MODE_AES_WV: {
- ret = CryptoPlugin::kMode_AES_WV;
- break;
- }
-
- case AMEDIACODECRYPTOINFO_MODE_AES_CBC: {
- ret = CryptoPlugin::kMode_AES_CBC;
- break;
- }
-
- default:
- break;
- }
-
- return ret;
-}
-
-static cryptoinfo_mode_t translateToCryptoInfoMode(CryptoPlugin::Mode mode) {
- cryptoinfo_mode_t ret = AMEDIACODECRYPTOINFO_MODE_CLEAR;
- switch (mode) {
- case CryptoPlugin::kMode_AES_CTR: {
- ret = AMEDIACODECRYPTOINFO_MODE_AES_CTR;
- break;
- }
-
- case CryptoPlugin::kMode_AES_WV: {
- ret = AMEDIACODECRYPTOINFO_MODE_AES_WV;
- break;
- }
-
- case CryptoPlugin::kMode_AES_CBC: {
- ret = AMEDIACODECRYPTOINFO_MODE_AES_CBC;
- break;
- }
-
- default:
- break;
- }
-
- return ret;
-}
-
-//////////// AMediaFormatWrapper
-// static
-sp<AMediaFormatWrapper> AMediaFormatWrapper::Create(const sp<AMessage> &message) {
- sp<AMediaFormatWrapper> aMediaFormat = new AMediaFormatWrapper();
-
- for (size_t i = 0; i < message->countEntries(); ++i) {
- AMessage::Type valueType;
- const char *key = message->getEntryNameAt(i, &valueType);
-
- switch (valueType) {
- case AMessage::kTypeInt32: {
- int32_t val;
- if (!message->findInt32(key, &val)) {
- ALOGE("AMediaFormatWrapper::Create: error at item %zu", i);
- continue;
- }
- aMediaFormat->setInt32(key, val);
- break;
- }
-
- case AMessage::kTypeInt64: {
- int64_t val;
- if (!message->findInt64(key, &val)) {
- ALOGE("AMediaFormatWrapper::Create: error at item %zu", i);
- continue;
- }
- aMediaFormat->setInt64(key, val);
- break;
- }
-
- case AMessage::kTypeFloat: {
- float val;
- if (!message->findFloat(key, &val)) {
- ALOGE("AMediaFormatWrapper::Create: error at item %zu", i);
- continue;
- }
- aMediaFormat->setFloat(key, val);
- break;
- }
-
- case AMessage::kTypeDouble: {
- double val;
- if (!message->findDouble(key, &val)) {
- ALOGE("AMediaFormatWrapper::Create: error at item %zu", i);
- continue;
- }
- aMediaFormat->setDouble(key, val);
- break;
- }
-
- case AMessage::kTypeSize: {
- size_t val;
- if (!message->findSize(key, &val)) {
- ALOGE("AMediaFormatWrapper::Create: error at item %zu", i);
- continue;
- }
- aMediaFormat->setSize(key, val);
- break;
- }
-
- case AMessage::kTypeRect: {
- int32_t left, top, right, bottom;
- if (!message->findRect(key, &left, &top, &right, &bottom)) {
- ALOGE("AMediaFormatWrapper::Create: error at item %zu", i);
- continue;
- }
- aMediaFormat->setRect(key, left, top, right, bottom);
- break;
- }
-
- case AMessage::kTypeString: {
- AString val;
- if (!message->findString(key, &val)) {
- ALOGE("AMediaFormatWrapper::Create: error at item %zu", i);
- continue;
- }
- aMediaFormat->setString(key, val);
- break;
- }
-
- case AMessage::kTypeBuffer: {
- sp<ABuffer> val;
- if (!message->findBuffer(key, &val)) {
- ALOGE("AMediaFormatWrapper::Create: error at item %zu", i);
- continue;
- }
- aMediaFormat->setBuffer(key, val->data(), val->size());
- break;
- }
-
- default: {
- break;
- }
- }
- }
-
- return aMediaFormat;
-}
-
-AMediaFormatWrapper::AMediaFormatWrapper() {
- mAMediaFormat = AMediaFormat_new();
-}
-
-AMediaFormatWrapper::AMediaFormatWrapper(AMediaFormat *aMediaFormat)
- : mAMediaFormat(aMediaFormat) {
-}
-
-AMediaFormatWrapper::~AMediaFormatWrapper() {
- release();
-}
-
-status_t AMediaFormatWrapper::release() {
- if (mAMediaFormat != NULL) {
- media_status_t err = AMediaFormat_delete(mAMediaFormat);
- mAMediaFormat = NULL;
- return translateErrorCode(err);
- }
- return OK;
-}
-
-AMediaFormat *AMediaFormatWrapper::getAMediaFormat() const {
- return mAMediaFormat;
-}
-
-sp<AMessage> AMediaFormatWrapper::toAMessage() const {
- sp<AMessage> msg;
- writeToAMessage(msg);
- return msg;
-}
-
-void AMediaFormatWrapper::writeToAMessage(sp<AMessage> &msg) const {
- if (mAMediaFormat == NULL) {
- msg = NULL;
- }
-
- if (msg == NULL) {
- msg = new AMessage;
- }
- for (auto& key : AMediaFormatKeyGroupInt32) {
- int32_t val;
- if (getInt32(key, &val)) {
- msg->setInt32(key, val);
- }
- }
- for (auto& key : AMediaFormatKeyGroupInt64) {
- int64_t val;
- if (getInt64(key, &val)) {
- msg->setInt64(key, val);
- }
- }
- for (auto& key : AMediaFormatKeyGroupString) {
- AString val;
- if (getString(key, &val)) {
- msg->setString(key, val);
- }
- }
- for (auto& key : AMediaFormatKeyGroupBuffer) {
- void *data;
- size_t size;
- if (getBuffer(key, &data, &size)) {
- sp<ABuffer> buffer = ABuffer::CreateAsCopy(data, size);
- msg->setBuffer(key, buffer);
- }
- }
- for (auto& key : AMediaFormatKeyGroupCsd) {
- void *data;
- size_t size;
- if (getBuffer(key, &data, &size)) {
- sp<ABuffer> buffer = ABuffer::CreateAsCopy(data, size);
- buffer->meta()->setInt32(AMEDIAFORMAT_KEY_CSD, 1);
- buffer->meta()->setInt64(AMEDIAFORMAT_KEY_TIME_US, 0);
- msg->setBuffer(key, buffer);
- }
- }
- for (auto& key : AMediaFormatKeyGroupRect) {
- int32_t left, top, right, bottom;
- if (getRect(key, &left, &top, &right, &bottom)) {
- msg->setRect(key, left, top, right, bottom);
- }
- }
- for (auto& key : AMediaFormatKeyGroupFloatInt32) {
- float valFloat;
- if (getFloat(key, &valFloat)) {
- msg->setFloat(key, valFloat);
- } else {
- int32_t valInt32;
- if (getInt32(key, &valInt32)) {
- msg->setFloat(key, (float)valInt32);
- }
- }
- }
-}
-
-const char* AMediaFormatWrapper::toString() const {
- if (mAMediaFormat == NULL) {
- return NULL;
- }
- return AMediaFormat_toString(mAMediaFormat);
-}
-
-bool AMediaFormatWrapper::getInt32(const char *name, int32_t *out) const {
- if (mAMediaFormat == NULL) {
- return false;
- }
- return AMediaFormat_getInt32(mAMediaFormat, name, out);
-}
-
-bool AMediaFormatWrapper::getInt64(const char *name, int64_t *out) const {
- if (mAMediaFormat == NULL) {
- return false;
- }
- return AMediaFormat_getInt64(mAMediaFormat, name, out);
-}
-
-bool AMediaFormatWrapper::getFloat(const char *name, float *out) const {
- if (mAMediaFormat == NULL) {
- return false;
- }
- return AMediaFormat_getFloat(mAMediaFormat, name, out);
-}
-
-bool AMediaFormatWrapper::getDouble(const char *name, double *out) const {
- if (mAMediaFormat == NULL) {
- return false;
- }
- return AMediaFormat_getDouble(mAMediaFormat, name, out);
-}
-
-bool AMediaFormatWrapper::getSize(const char *name, size_t *out) const {
- if (mAMediaFormat == NULL) {
- return false;
- }
- return AMediaFormat_getSize(mAMediaFormat, name, out);
-}
-
-bool AMediaFormatWrapper::getRect(
- const char *name, int32_t *left, int32_t *top, int32_t *right, int32_t *bottom) const {
- if (mAMediaFormat == NULL) {
- return false;
- }
- return AMediaFormat_getRect(mAMediaFormat, name, left, top, right, bottom);
-}
-
-bool AMediaFormatWrapper::getBuffer(const char *name, void** data, size_t *outSize) const {
- if (mAMediaFormat == NULL) {
- return false;
- }
- return AMediaFormat_getBuffer(mAMediaFormat, name, data, outSize);
-}
-
-bool AMediaFormatWrapper::getString(const char *name, AString *out) const {
- if (mAMediaFormat == NULL) {
- return false;
- }
- const char *outChar = NULL;
- bool ret = AMediaFormat_getString(mAMediaFormat, name, &outChar);
- if (ret) {
- *out = AString(outChar);
- }
- return ret;
-}
-
-void AMediaFormatWrapper::setInt32(const char* name, int32_t value) {
- if (mAMediaFormat != NULL) {
- AMediaFormat_setInt32(mAMediaFormat, name, value);
- }
-}
-
-void AMediaFormatWrapper::setInt64(const char* name, int64_t value) {
- if (mAMediaFormat != NULL) {
- AMediaFormat_setInt64(mAMediaFormat, name, value);
- }
-}
-
-void AMediaFormatWrapper::setFloat(const char* name, float value) {
- if (mAMediaFormat != NULL) {
- AMediaFormat_setFloat(mAMediaFormat, name, value);
- }
-}
-
-void AMediaFormatWrapper::setDouble(const char* name, double value) {
- if (mAMediaFormat != NULL) {
- AMediaFormat_setDouble(mAMediaFormat, name, value);
- }
-}
-
-void AMediaFormatWrapper::setSize(const char* name, size_t value) {
- if (mAMediaFormat != NULL) {
- AMediaFormat_setSize(mAMediaFormat, name, value);
- }
-}
-
-void AMediaFormatWrapper::setRect(
- const char* name, int32_t left, int32_t top, int32_t right, int32_t bottom) {
- if (mAMediaFormat != NULL) {
- AMediaFormat_setRect(mAMediaFormat, name, left, top, right, bottom);
- }
-}
-
-void AMediaFormatWrapper::setString(const char* name, const AString &value) {
- if (mAMediaFormat != NULL) {
- AMediaFormat_setString(mAMediaFormat, name, value.c_str());
- }
-}
-
-void AMediaFormatWrapper::setBuffer(const char* name, void* data, size_t size) {
- if (mAMediaFormat != NULL) {
- AMediaFormat_setBuffer(mAMediaFormat, name, data, size);
- }
-}
-
-
-//////////// ANativeWindowWrapper
-ANativeWindowWrapper::ANativeWindowWrapper(ANativeWindow *aNativeWindow)
- : mANativeWindow(aNativeWindow) {
- if (aNativeWindow != NULL) {
- ANativeWindow_acquire(aNativeWindow);
- }
-}
-
-ANativeWindowWrapper::~ANativeWindowWrapper() {
- release();
-}
-
-status_t ANativeWindowWrapper::release() {
- if (mANativeWindow != NULL) {
- ANativeWindow_release(mANativeWindow);
- mANativeWindow = NULL;
- }
- return OK;
-}
-
-ANativeWindow *ANativeWindowWrapper::getANativeWindow() const {
- return mANativeWindow;
-}
-
-
-//////////// AMediaDrmWrapper
-AMediaDrmWrapper::AMediaDrmWrapper(const uint8_t uuid[16]) {
- mAMediaDrm = AMediaDrm_createByUUID(uuid);
-}
-
-AMediaDrmWrapper::AMediaDrmWrapper(AMediaDrm *aMediaDrm)
- : mAMediaDrm(aMediaDrm) {
-}
-
-AMediaDrmWrapper::~AMediaDrmWrapper() {
- release();
-}
-
-status_t AMediaDrmWrapper::release() {
- if (mAMediaDrm != NULL) {
- AMediaDrm_release(mAMediaDrm);
- mAMediaDrm = NULL;
- }
- return OK;
-}
-
-AMediaDrm *AMediaDrmWrapper::getAMediaDrm() const {
- return mAMediaDrm;
-}
-
-// static
-bool AMediaDrmWrapper::isCryptoSchemeSupported(
- const uint8_t uuid[16],
- const char *mimeType) {
- return AMediaDrm_isCryptoSchemeSupported(uuid, mimeType);
-}
-
-
-//////////// AMediaCryptoWrapper
-AMediaCryptoWrapper::AMediaCryptoWrapper(
- const uint8_t uuid[16], const void *initData, size_t initDataSize) {
- mAMediaCrypto = AMediaCrypto_new(uuid, initData, initDataSize);
-}
-
-AMediaCryptoWrapper::AMediaCryptoWrapper(AMediaCrypto *aMediaCrypto)
- : mAMediaCrypto(aMediaCrypto) {
-}
-
-AMediaCryptoWrapper::~AMediaCryptoWrapper() {
- release();
-}
-
-status_t AMediaCryptoWrapper::release() {
- if (mAMediaCrypto != NULL) {
- AMediaCrypto_delete(mAMediaCrypto);
- mAMediaCrypto = NULL;
- }
- return OK;
-}
-
-AMediaCrypto *AMediaCryptoWrapper::getAMediaCrypto() const {
- return mAMediaCrypto;
-}
-
-bool AMediaCryptoWrapper::isCryptoSchemeSupported(const uint8_t uuid[16]) {
- if (mAMediaCrypto == NULL) {
- return false;
- }
- return AMediaCrypto_isCryptoSchemeSupported(uuid);
-}
-
-bool AMediaCryptoWrapper::requiresSecureDecoderComponent(const char *mime) {
- if (mAMediaCrypto == NULL) {
- return false;
- }
- return AMediaCrypto_requiresSecureDecoderComponent(mime);
-}
-
-
-//////////// AMediaCodecCryptoInfoWrapper
-// static
-sp<AMediaCodecCryptoInfoWrapper> AMediaCodecCryptoInfoWrapper::Create(MetaDataBase &meta) {
-
- uint32_t type;
- const void *crypteddata;
- size_t cryptedsize;
-
- if (!meta.findData(kKeyEncryptedSizes, &type, &crypteddata, &cryptedsize)) {
- return NULL;
- }
-
- int numSubSamples = cryptedsize / sizeof(size_t);
-
- if (numSubSamples <= 0) {
- ALOGE("Create: INVALID numSubSamples: %d", numSubSamples);
- return NULL;
- }
-
- const void *cleardata;
- size_t clearsize;
- if (meta.findData(kKeyPlainSizes, &type, &cleardata, &clearsize)) {
- if (clearsize != cryptedsize) {
- // The two must be of the same length.
- ALOGE("Create: mismatch cryptedsize: %zu != clearsize: %zu", cryptedsize, clearsize);
- return NULL;
- }
- }
-
- const void *key;
- size_t keysize;
- if (meta.findData(kKeyCryptoKey, &type, &key, &keysize)) {
- if (keysize != kAESBlockSize) {
- // Keys must be 16 bytes in length.
- ALOGE("Create: Keys must be %zu bytes in length: %zu", kAESBlockSize, keysize);
- return NULL;
- }
- }
-
- const void *iv;
- size_t ivsize;
- if (meta.findData(kKeyCryptoIV, &type, &iv, &ivsize)) {
- if (ivsize != kAESBlockSize) {
- // IVs must be 16 bytes in length.
- ALOGE("Create: IV must be %zu bytes in length: %zu", kAESBlockSize, ivsize);
- return NULL;
- }
- }
-
- int32_t mode;
- if (!meta.findInt32(kKeyCryptoMode, &mode)) {
- mode = CryptoPlugin::kMode_AES_CTR;
- }
-
- return new AMediaCodecCryptoInfoWrapper(
- numSubSamples,
- (uint8_t*) key,
- (uint8_t*) iv,
- (CryptoPlugin::Mode)mode,
- (size_t*) cleardata,
- (size_t*) crypteddata);
-}
-
-AMediaCodecCryptoInfoWrapper::AMediaCodecCryptoInfoWrapper(
- int numsubsamples,
- uint8_t key[16],
- uint8_t iv[16],
- CryptoPlugin::Mode mode,
- size_t *clearbytes,
- size_t *encryptedbytes) {
- mAMediaCodecCryptoInfo =
- AMediaCodecCryptoInfo_new(numsubsamples,
- key,
- iv,
- translateToCryptoInfoMode(mode),
- clearbytes,
- encryptedbytes);
-}
-
-AMediaCodecCryptoInfoWrapper::AMediaCodecCryptoInfoWrapper(
- AMediaCodecCryptoInfo *aMediaCodecCryptoInfo)
- : mAMediaCodecCryptoInfo(aMediaCodecCryptoInfo) {
-}
-
-AMediaCodecCryptoInfoWrapper::~AMediaCodecCryptoInfoWrapper() {
- release();
-}
-
-status_t AMediaCodecCryptoInfoWrapper::release() {
- if (mAMediaCodecCryptoInfo != NULL) {
- media_status_t err = AMediaCodecCryptoInfo_delete(mAMediaCodecCryptoInfo);
- mAMediaCodecCryptoInfo = NULL;
- return translateErrorCode(err);
- }
- return OK;
-}
-
-AMediaCodecCryptoInfo *AMediaCodecCryptoInfoWrapper::getAMediaCodecCryptoInfo() const {
- return mAMediaCodecCryptoInfo;
-}
-
-void AMediaCodecCryptoInfoWrapper::setPattern(CryptoPlugin::Pattern *pattern) {
- if (mAMediaCodecCryptoInfo == NULL || pattern == NULL) {
- return;
- }
- cryptoinfo_pattern_t ndkPattern = {(int32_t)pattern->mEncryptBlocks,
- (int32_t)pattern->mSkipBlocks };
- return AMediaCodecCryptoInfo_setPattern(mAMediaCodecCryptoInfo, &ndkPattern);
-}
-
-size_t AMediaCodecCryptoInfoWrapper::getNumSubSamples() {
- if (mAMediaCodecCryptoInfo == NULL) {
- return 0;
- }
- return AMediaCodecCryptoInfo_getNumSubSamples(mAMediaCodecCryptoInfo);
-}
-
-status_t AMediaCodecCryptoInfoWrapper::getKey(uint8_t *dst) {
- if (mAMediaCodecCryptoInfo == NULL) {
- return DEAD_OBJECT;
- }
- if (dst == NULL) {
- return BAD_VALUE;
- }
- return translateErrorCode(
- AMediaCodecCryptoInfo_getKey(mAMediaCodecCryptoInfo, dst));
-}
-
-status_t AMediaCodecCryptoInfoWrapper::getIV(uint8_t *dst) {
- if (mAMediaCodecCryptoInfo == NULL) {
- return DEAD_OBJECT;
- }
- if (dst == NULL) {
- return BAD_VALUE;
- }
- return translateErrorCode(
- AMediaCodecCryptoInfo_getIV(mAMediaCodecCryptoInfo, dst));
-}
-
-CryptoPlugin::Mode AMediaCodecCryptoInfoWrapper::getMode() {
- if (mAMediaCodecCryptoInfo == NULL) {
- return CryptoPlugin::kMode_Unencrypted;
- }
- return translateToCryptoPluginMode(
- AMediaCodecCryptoInfo_getMode(mAMediaCodecCryptoInfo));
-}
-
-status_t AMediaCodecCryptoInfoWrapper::getClearBytes(size_t *dst) {
- if (mAMediaCodecCryptoInfo == NULL) {
- return DEAD_OBJECT;
- }
- if (dst == NULL) {
- return BAD_VALUE;
- }
- return translateErrorCode(
- AMediaCodecCryptoInfo_getClearBytes(mAMediaCodecCryptoInfo, dst));
-}
-
-status_t AMediaCodecCryptoInfoWrapper::getEncryptedBytes(size_t *dst) {
- if (mAMediaCodecCryptoInfo == NULL) {
- return DEAD_OBJECT;
- }
- if (dst == NULL) {
- return BAD_VALUE;
- }
- return translateErrorCode(
- AMediaCodecCryptoInfo_getEncryptedBytes(mAMediaCodecCryptoInfo, dst));
-}
-
-
-//////////// AMediaCodecWrapper
-// static
-sp<AMediaCodecWrapper> AMediaCodecWrapper::CreateCodecByName(const AString &name) {
- AMediaCodec *aMediaCodec = AMediaCodec_createCodecByName(name.c_str());
- return new AMediaCodecWrapper(aMediaCodec);
-}
-
-// static
-sp<AMediaCodecWrapper> AMediaCodecWrapper::CreateDecoderByType(const AString &mimeType) {
- AMediaCodec *aMediaCodec = AMediaCodec_createDecoderByType(mimeType.c_str());
- return new AMediaCodecWrapper(aMediaCodec);
-}
-
-// static
-void AMediaCodecWrapper::OnInputAvailableCB(
- AMediaCodec * /* aMediaCodec */,
- void *userdata,
- int32_t index) {
- ALOGV("OnInputAvailableCB: index(%d)", index);
- sp<AMessage> msg = sp<AMessage>((AMessage *)userdata)->dup();
- msg->setInt32("callbackID", CB_INPUT_AVAILABLE);
- msg->setInt32("index", index);
- msg->post();
-}
-
-// static
-void AMediaCodecWrapper::OnOutputAvailableCB(
- AMediaCodec * /* aMediaCodec */,
- void *userdata,
- int32_t index,
- AMediaCodecBufferInfo *bufferInfo) {
- ALOGV("OnOutputAvailableCB: index(%d), (%d, %d, %lld, 0x%x)",
- index, bufferInfo->offset, bufferInfo->size,
- (long long)bufferInfo->presentationTimeUs, bufferInfo->flags);
- sp<AMessage> msg = sp<AMessage>((AMessage *)userdata)->dup();
- msg->setInt32("callbackID", CB_OUTPUT_AVAILABLE);
- msg->setInt32("index", index);
- msg->setSize("offset", (size_t)(bufferInfo->offset));
- msg->setSize("size", (size_t)(bufferInfo->size));
- msg->setInt64("timeUs", bufferInfo->presentationTimeUs);
- msg->setInt32("flags", (int32_t)(bufferInfo->flags));
- msg->post();
-}
-
-// static
-void AMediaCodecWrapper::OnFormatChangedCB(
- AMediaCodec * /* aMediaCodec */,
- void *userdata,
- AMediaFormat *format) {
- sp<AMediaFormatWrapper> formatWrapper = new AMediaFormatWrapper(format);
- sp<AMessage> outputFormat = formatWrapper->toAMessage();
- ALOGV("OnFormatChangedCB: format(%s)", outputFormat->debugString().c_str());
-
- sp<AMessage> msg = sp<AMessage>((AMessage *)userdata)->dup();
- msg->setInt32("callbackID", CB_OUTPUT_FORMAT_CHANGED);
- msg->setMessage("format", outputFormat);
- msg->post();
-}
-
-// static
-void AMediaCodecWrapper::OnErrorCB(
- AMediaCodec * /* aMediaCodec */,
- void *userdata,
- media_status_t err,
- int32_t actionCode,
- const char *detail) {
- ALOGV("OnErrorCB: err(%d), actionCode(%d), detail(%s)", err, actionCode, detail);
- sp<AMessage> msg = sp<AMessage>((AMessage *)userdata)->dup();
- msg->setInt32("callbackID", CB_ERROR);
- msg->setInt32("err", translateErrorCode(err));
- msg->setInt32("actionCode", translateActionCode(actionCode));
- msg->setString("detail", detail);
- msg->post();
-}
-
-AMediaCodecWrapper::AMediaCodecWrapper(AMediaCodec *aMediaCodec)
- : mAMediaCodec(aMediaCodec) {
-}
-
-AMediaCodecWrapper::~AMediaCodecWrapper() {
- release();
-}
-
-status_t AMediaCodecWrapper::release() {
- if (mAMediaCodec != NULL) {
- AMediaCodecOnAsyncNotifyCallback aCB = {};
- AMediaCodec_setAsyncNotifyCallback(mAMediaCodec, aCB, NULL);
- mCallback = NULL;
-
- media_status_t err = AMediaCodec_delete(mAMediaCodec);
- mAMediaCodec = NULL;
- return translateErrorCode(err);
- }
- return OK;
-}
-
-AMediaCodec *AMediaCodecWrapper::getAMediaCodec() const {
- return mAMediaCodec;
-}
-
-status_t AMediaCodecWrapper::getName(AString *outComponentName) const {
- if (mAMediaCodec == NULL) {
- return DEAD_OBJECT;
- }
- char *name = NULL;
- media_status_t err = AMediaCodec_getName(mAMediaCodec, &name);
- if (err != AMEDIA_OK) {
- return translateErrorCode(err);
- }
-
- *outComponentName = AString(name);
- AMediaCodec_releaseName(mAMediaCodec, name);
- return OK;
-}
-
-status_t AMediaCodecWrapper::configure(
- const sp<AMediaFormatWrapper> &format,
- const sp<ANativeWindowWrapper> &nww,
- const sp<AMediaCryptoWrapper> &crypto,
- uint32_t flags) {
- if (mAMediaCodec == NULL) {
- return DEAD_OBJECT;
- }
-
- media_status_t err = AMediaCodec_configure(
- mAMediaCodec,
- format->getAMediaFormat(),
- (nww == NULL ? NULL : nww->getANativeWindow()),
- crypto == NULL ? NULL : crypto->getAMediaCrypto(),
- flags);
-
- return translateErrorCode(err);
-}
-
-status_t AMediaCodecWrapper::setCallback(const sp<AMessage> &callback) {
- if (mAMediaCodec == NULL) {
- return DEAD_OBJECT;
- }
-
- mCallback = callback;
-
- AMediaCodecOnAsyncNotifyCallback aCB = {
- OnInputAvailableCB,
- OnOutputAvailableCB,
- OnFormatChangedCB,
- OnErrorCB
- };
-
- return translateErrorCode(
- AMediaCodec_setAsyncNotifyCallback(mAMediaCodec, aCB, callback.get()));
-}
-
-status_t AMediaCodecWrapper::releaseCrypto() {
- if (mAMediaCodec == NULL) {
- return DEAD_OBJECT;
- }
- return translateErrorCode(AMediaCodec_releaseCrypto(mAMediaCodec));
-}
-
-status_t AMediaCodecWrapper::start() {
- if (mAMediaCodec == NULL) {
- return DEAD_OBJECT;
- }
- return translateErrorCode(AMediaCodec_start(mAMediaCodec));
-}
-
-status_t AMediaCodecWrapper::stop() {
- if (mAMediaCodec == NULL) {
- return DEAD_OBJECT;
- }
- return translateErrorCode(AMediaCodec_stop(mAMediaCodec));
-}
-
-status_t AMediaCodecWrapper::flush() {
- if (mAMediaCodec == NULL) {
- return DEAD_OBJECT;
- }
- return translateErrorCode(AMediaCodec_flush(mAMediaCodec));
-}
-
-uint8_t* AMediaCodecWrapper::getInputBuffer(size_t idx, size_t *out_size) {
- if (mAMediaCodec == NULL) {
- return NULL;
- }
- return AMediaCodec_getInputBuffer(mAMediaCodec, idx, out_size);
-}
-
-uint8_t* AMediaCodecWrapper::getOutputBuffer(size_t idx, size_t *out_size) {
- if (mAMediaCodec == NULL) {
- return NULL;
- }
- return AMediaCodec_getOutputBuffer(mAMediaCodec, idx, out_size);
-}
-
-status_t AMediaCodecWrapper::queueInputBuffer(
- size_t idx,
- size_t offset,
- size_t size,
- uint64_t time,
- uint32_t flags) {
- if (mAMediaCodec == NULL) {
- return DEAD_OBJECT;
- }
- return translateErrorCode(
- AMediaCodec_queueInputBuffer(mAMediaCodec, idx, offset, size, time, flags));
-}
-
-status_t AMediaCodecWrapper::queueSecureInputBuffer(
- size_t idx,
- size_t offset,
- sp<AMediaCodecCryptoInfoWrapper> &codecCryptoInfo,
- uint64_t time,
- uint32_t flags) {
- if (mAMediaCodec == NULL) {
- return DEAD_OBJECT;
- }
- return translateErrorCode(
- AMediaCodec_queueSecureInputBuffer(
- mAMediaCodec,
- idx,
- offset,
- codecCryptoInfo->getAMediaCodecCryptoInfo(),
- time,
- flags));
-}
-
-sp<AMediaFormatWrapper> AMediaCodecWrapper::getOutputFormat() {
- if (mAMediaCodec == NULL) {
- return NULL;
- }
- return new AMediaFormatWrapper(AMediaCodec_getOutputFormat(mAMediaCodec));
-}
-
-sp<AMediaFormatWrapper> AMediaCodecWrapper::getInputFormat() {
- if (mAMediaCodec == NULL) {
- return NULL;
- }
- return new AMediaFormatWrapper(AMediaCodec_getInputFormat(mAMediaCodec));
-}
-
-status_t AMediaCodecWrapper::releaseOutputBuffer(size_t idx, bool render) {
- if (mAMediaCodec == NULL) {
- return DEAD_OBJECT;
- }
- return translateErrorCode(
- AMediaCodec_releaseOutputBuffer(mAMediaCodec, idx, render));
-}
-
-status_t AMediaCodecWrapper::setOutputSurface(const sp<ANativeWindowWrapper> &nww) {
- if (mAMediaCodec == NULL) {
- return DEAD_OBJECT;
- }
- return translateErrorCode(
- AMediaCodec_setOutputSurface(mAMediaCodec,
- (nww == NULL ? NULL : nww->getANativeWindow())));
-}
-
-status_t AMediaCodecWrapper::releaseOutputBufferAtTime(size_t idx, int64_t timestampNs) {
- if (mAMediaCodec == NULL) {
- return DEAD_OBJECT;
- }
- return translateErrorCode(
- AMediaCodec_releaseOutputBufferAtTime(mAMediaCodec, idx, timestampNs));
-}
-
-status_t AMediaCodecWrapper::setParameters(const sp<AMediaFormatWrapper> ¶ms) {
- if (mAMediaCodec == NULL) {
- return DEAD_OBJECT;
- }
- return translateErrorCode(
- AMediaCodec_setParameters(mAMediaCodec, params->getAMediaFormat()));
-}
-
-//////////// AMediaExtractorWrapper
-
-AMediaExtractorWrapper::AMediaExtractorWrapper(AMediaExtractor *aMediaExtractor)
- : mAMediaExtractor(aMediaExtractor) {
-}
-
-AMediaExtractorWrapper::~AMediaExtractorWrapper() {
- release();
-}
-
-status_t AMediaExtractorWrapper::release() {
- if (mAMediaExtractor != NULL) {
- media_status_t err = AMediaExtractor_delete(mAMediaExtractor);
- mAMediaExtractor = NULL;
- return translateErrorCode(err);
- }
- return OK;
-}
-
-AMediaExtractor *AMediaExtractorWrapper::getAMediaExtractor() const {
- return mAMediaExtractor;
-}
-
-status_t AMediaExtractorWrapper::setDataSource(int fd, off64_t offset, off64_t length) {
- if (mAMediaExtractor == NULL) {
- return DEAD_OBJECT;
- }
- return translateErrorCode(AMediaExtractor_setDataSourceFd(
- mAMediaExtractor, fd, offset, length));
-}
-
-status_t AMediaExtractorWrapper::setDataSource(const char *location) {
- if (mAMediaExtractor == NULL) {
- return DEAD_OBJECT;
- }
- return translateErrorCode(AMediaExtractor_setDataSource(mAMediaExtractor, location));
-}
-
-status_t AMediaExtractorWrapper::setDataSource(AMediaDataSource *source) {
- if (mAMediaExtractor == NULL) {
- return DEAD_OBJECT;
- }
- return translateErrorCode(AMediaExtractor_setDataSourceCustom(mAMediaExtractor, source));
-}
-
-size_t AMediaExtractorWrapper::getTrackCount() {
- if (mAMediaExtractor == NULL) {
- return 0;
- }
- return AMediaExtractor_getTrackCount(mAMediaExtractor);
-}
-
-sp<AMediaFormatWrapper> AMediaExtractorWrapper::getFormat() {
- if (mAMediaExtractor == NULL) {
- return NULL;
- }
- return new AMediaFormatWrapper(AMediaExtractor_getFileFormat(mAMediaExtractor));
-}
-
-sp<AMediaFormatWrapper> AMediaExtractorWrapper::getTrackFormat(size_t idx) {
- if (mAMediaExtractor == NULL) {
- return NULL;
- }
- return new AMediaFormatWrapper(AMediaExtractor_getTrackFormat(mAMediaExtractor, idx));
-}
-
-status_t AMediaExtractorWrapper::selectTrack(size_t idx) {
- if (mAMediaExtractor == NULL) {
- return DEAD_OBJECT;
- }
- return translateErrorCode(AMediaExtractor_selectTrack(mAMediaExtractor, idx));
-}
-
-status_t AMediaExtractorWrapper::unselectTrack(size_t idx) {
- if (mAMediaExtractor == NULL) {
- return DEAD_OBJECT;
- }
- return translateErrorCode(AMediaExtractor_unselectTrack(mAMediaExtractor, idx));
-}
-
-status_t AMediaExtractorWrapper::selectSingleTrack(size_t idx) {
- if (mAMediaExtractor == NULL) {
- return DEAD_OBJECT;
- }
- for (size_t i = 0; i < AMediaExtractor_getTrackCount(mAMediaExtractor); ++i) {
- if (i == idx) {
- media_status_t err = AMediaExtractor_selectTrack(mAMediaExtractor, i);
- if (err != AMEDIA_OK) {
- return translateErrorCode(err);
- }
- } else {
- media_status_t err = AMediaExtractor_unselectTrack(mAMediaExtractor, i);
- if (err != AMEDIA_OK) {
- return translateErrorCode(err);
- }
- }
- }
- return OK;
-}
-
-ssize_t AMediaExtractorWrapper::readSampleData(const sp<ABuffer> &buffer) {
- if (mAMediaExtractor == NULL) {
- return -1;
- }
- return AMediaExtractor_readSampleData(mAMediaExtractor, buffer->data(), buffer->capacity());
-}
-
-ssize_t AMediaExtractorWrapper::getSampleSize() {
- if (mAMediaExtractor == NULL) {
- return 0;
- }
- return AMediaExtractor_getSampleSize(mAMediaExtractor);
-}
-
-uint32_t AMediaExtractorWrapper::getSampleFlags() {
- if (mAMediaExtractor == NULL) {
- return 0;
- }
- return AMediaExtractor_getSampleFlags(mAMediaExtractor);
-}
-
-int AMediaExtractorWrapper::getSampleTrackIndex() {
- if (mAMediaExtractor == NULL) {
- return -1;
- }
- return AMediaExtractor_getSampleTrackIndex(mAMediaExtractor);
-}
-
-int64_t AMediaExtractorWrapper::getSampleTime() {
- if (mAMediaExtractor == NULL) {
- return -1;
- }
- return AMediaExtractor_getSampleTime(mAMediaExtractor);
-}
-
-status_t AMediaExtractorWrapper::getSampleFormat(sp<AMediaFormatWrapper> &formatWrapper) {
- if (mAMediaExtractor == NULL) {
- return DEAD_OBJECT;
- }
- AMediaFormat *format = AMediaFormat_new();
- formatWrapper = new AMediaFormatWrapper(format);
- return translateErrorCode(AMediaExtractor_getSampleFormat(mAMediaExtractor, format));
-}
-
-int64_t AMediaExtractorWrapper::getCachedDuration() {
- if (mAMediaExtractor == NULL) {
- return -1;
- }
- return AMediaExtractor_getCachedDuration(mAMediaExtractor);
-}
-
-bool AMediaExtractorWrapper::advance() {
- if (mAMediaExtractor == NULL) {
- return false;
- }
- return AMediaExtractor_advance(mAMediaExtractor);
-}
-
-status_t AMediaExtractorWrapper::seekTo(int64_t seekPosUs, MediaSource::ReadOptions::SeekMode mode) {
- if (mAMediaExtractor == NULL) {
- return DEAD_OBJECT;
- }
-
- SeekMode aMode;
- switch (mode) {
- case MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC: {
- aMode = AMEDIAEXTRACTOR_SEEK_PREVIOUS_SYNC;
- break;
- }
- case MediaSource::ReadOptions::SEEK_NEXT_SYNC: {
- aMode = AMEDIAEXTRACTOR_SEEK_NEXT_SYNC;
- break;
- }
- default: {
- aMode = AMEDIAEXTRACTOR_SEEK_CLOSEST_SYNC;
- break;
- }
- }
- return AMediaExtractor_seekTo(mAMediaExtractor, seekPosUs, aMode);
-}
-
-PsshInfo* AMediaExtractorWrapper::getPsshInfo() {
- if (mAMediaExtractor == NULL) {
- return NULL;
- }
- return AMediaExtractor_getPsshInfo(mAMediaExtractor);
-}
-
-sp<AMediaCodecCryptoInfoWrapper> AMediaExtractorWrapper::getSampleCryptoInfo() {
- if (mAMediaExtractor == NULL) {
- return NULL;
- }
- AMediaCodecCryptoInfo *cryptoInfo = AMediaExtractor_getSampleCryptoInfo(mAMediaExtractor);
- if (cryptoInfo == NULL) {
- return NULL;
- }
- return new AMediaCodecCryptoInfoWrapper(cryptoInfo);
-}
-
-AMediaDataSourceWrapper::AMediaDataSourceWrapper(const sp<DataSource> &dataSource)
- : mDataSource(dataSource),
- mAMediaDataSource(convertDataSourceToAMediaDataSource(dataSource)) {
-}
-
-AMediaDataSourceWrapper::AMediaDataSourceWrapper(AMediaDataSource *aDataSource)
- : mDataSource(NULL),
- mAMediaDataSource(aDataSource) {
-}
-
-AMediaDataSourceWrapper::~AMediaDataSourceWrapper() {
- if (mAMediaDataSource == NULL) {
- return;
- }
- AMediaDataSource_close(mAMediaDataSource);
- AMediaDataSource_delete(mAMediaDataSource);
- mAMediaDataSource = NULL;
-}
-
-AMediaDataSource* AMediaDataSourceWrapper::getAMediaDataSource() {
- return mAMediaDataSource;
-}
-
-void AMediaDataSourceWrapper::close() {
- AMediaDataSource_close(mAMediaDataSource);
-}
-
-} // namespace android
diff --git a/media/libmedia/TypeConverter.cpp b/media/libmedia/TypeConverter.cpp
deleted file mode 100644
index 5be78d1..0000000
--- a/media/libmedia/TypeConverter.cpp
+++ /dev/null
@@ -1,484 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <media/TypeConverter.h>
-
-namespace android {
-
-#define MAKE_STRING_FROM_ENUM(string) { #string, string }
-#define TERMINATOR { .literal = nullptr }
-
-template <>
-const OutputDeviceConverter::Table OutputDeviceConverter::mTable[] = {
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_NONE),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_EARPIECE),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_SPEAKER),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_SPEAKER_SAFE),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADSET),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADPHONE),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_SCO),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_ALL_SCO),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_ALL_A2DP),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_AUX_DIGITAL),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_HDMI),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_USB_ACCESSORY),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_USB_DEVICE),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_ALL_USB),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_REMOTE_SUBMIX),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_TELEPHONY_TX),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_LINE),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_HDMI_ARC),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_SPDIF),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_FM),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_AUX_LINE),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_IP),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BUS),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_PROXY),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_USB_HEADSET),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_HEARING_AID),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_ECHO_CANCELLER),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_DEFAULT),
- // STUB must be after DEFAULT, so the latter is picked up by toString first.
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_STUB),
- TERMINATOR
-};
-
-template <>
-const InputDeviceConverter::Table InputDeviceConverter::mTable[] = {
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_NONE),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_COMMUNICATION),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_AMBIENT),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BUILTIN_MIC),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_ALL_SCO),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_WIRED_HEADSET),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_AUX_DIGITAL),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_HDMI),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_HDMI_ARC),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_TELEPHONY_RX),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_VOICE_CALL),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BACK_MIC),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_REMOTE_SUBMIX),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_USB_ACCESSORY),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_USB_DEVICE),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_ALL_USB),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_FM_TUNER),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_TV_TUNER),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_LINE),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_SPDIF),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_A2DP),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_LOOPBACK),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_IP),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BUS),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_PROXY),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_USB_HEADSET),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_BLE),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_ECHO_REFERENCE),
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_DEFAULT),
- // STUB must be after DEFAULT, so the latter is picked up by toString first.
- MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_STUB),
- TERMINATOR
-};
-
-
-template <>
-const OutputFlagConverter::Table OutputFlagConverter::mTable[] = {
- MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_NONE),
- MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_DIRECT),
- MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_PRIMARY),
- MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_FAST),
- MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_DEEP_BUFFER),
- MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD),
- MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_NON_BLOCKING),
- MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_HW_AV_SYNC),
- MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_TTS),
- MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_RAW),
- MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_SYNC),
- MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO),
- MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_DIRECT_PCM),
- MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ),
- MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_VOIP_RX),
- MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_INCALL_MUSIC),
- TERMINATOR
-};
-
-
-template <>
-const InputFlagConverter::Table InputFlagConverter::mTable[] = {
- MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_NONE),
- MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_FAST),
- MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_HW_HOTWORD),
- MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_RAW),
- MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_SYNC),
- MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_MMAP_NOIRQ),
- MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_VOIP_TX),
- MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_HW_AV_SYNC),
- MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_DIRECT),
- TERMINATOR
-};
-
-
-template <>
-const FormatConverter::Table FormatConverter::mTable[] = {
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_PCM_16_BIT),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_PCM_8_BIT),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_PCM_32_BIT),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_PCM_8_24_BIT),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_PCM_FLOAT),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_PCM_24_BIT_PACKED),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_MP3),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AMR_NB),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AMR_WB),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_MAIN),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_LC),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_SSR),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_LTP),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_HE_V1),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_SCALABLE),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ERLC),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_LD),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_HE_V2),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ELD),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_XHE),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ADTS_MAIN),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ADTS_LC),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ADTS_SSR),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ADTS_LTP),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ADTS_HE_V1),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ADTS_SCALABLE),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ADTS_ERLC),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ADTS_LD),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ADTS_HE_V2),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ADTS_ELD),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ADTS_XHE),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_VORBIS),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_HE_AAC_V1),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_HE_AAC_V2),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_OPUS),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AC3),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_E_AC3),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_DTS),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_DTS_HD),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_IEC61937),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_DOLBY_TRUEHD),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_EVRC),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_EVRCB),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_EVRCWB),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_EVRCNW),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ADIF),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_WMA),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_WMA_PRO),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AMR_WB_PLUS),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_MP2),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_QCELP),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_DSD),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_FLAC),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_ALAC),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_APE),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ADTS),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_SBC),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_APTX),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_APTX_HD),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AC4),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_LDAC),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_MAT),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_E_AC3_JOC),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_MAT_1_0),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_MAT_2_0),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_MAT_2_1),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_LATM),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_LATM_LC),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_LATM_HE_V1),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_LATM_HE_V2),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_CELT),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_APTX_ADAPTIVE),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_LHDC),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_LHDC_LL),
- MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_APTX_TWSP),
- TERMINATOR
-};
-
-
-template <>
-const OutputChannelConverter::Table OutputChannelConverter::mTable[] = {
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_MONO),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_STEREO),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_2POINT1),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_2POINT0POINT2),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_2POINT1POINT2),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_TRI),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_TRI_BACK),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_3POINT1),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_3POINT0POINT2),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_3POINT1POINT2),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_QUAD),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_QUAD_BACK),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_QUAD_SIDE),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_SURROUND),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_PENTA),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_5POINT1),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_5POINT1_BACK),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_5POINT1_SIDE),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_5POINT1POINT2),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_5POINT1POINT4),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_6POINT1),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_7POINT1POINT2),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_7POINT1POINT4),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_HAPTIC_A),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_MONO_HAPTIC_A),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_STEREO_HAPTIC_A),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_HAPTIC_AB),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_MONO_HAPTIC_AB),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_STEREO_HAPTIC_AB),
- TERMINATOR
-};
-
-
-template <>
-const InputChannelConverter::Table InputChannelConverter::mTable[] = {
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_MONO),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_STEREO),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_FRONT_BACK),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_6),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_2POINT0POINT2),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_2POINT1POINT2),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_3POINT0POINT2),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_3POINT1POINT2),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_5POINT1),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO),
- MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_VOICE_CALL_MONO),
- TERMINATOR
-};
-
-template <>
-const ChannelIndexConverter::Table ChannelIndexConverter::mTable[] = {
- {"AUDIO_CHANNEL_INDEX_MASK_1", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_1)},
- {"AUDIO_CHANNEL_INDEX_MASK_2", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_2)},
- {"AUDIO_CHANNEL_INDEX_MASK_3", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_3)},
- {"AUDIO_CHANNEL_INDEX_MASK_4", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_4)},
- {"AUDIO_CHANNEL_INDEX_MASK_5", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_5)},
- {"AUDIO_CHANNEL_INDEX_MASK_6", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_6)},
- {"AUDIO_CHANNEL_INDEX_MASK_7", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_7)},
- {"AUDIO_CHANNEL_INDEX_MASK_8", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_8)},
- TERMINATOR
-};
-
-
-template <>
-const GainModeConverter::Table GainModeConverter::mTable[] = {
- MAKE_STRING_FROM_ENUM(AUDIO_GAIN_MODE_JOINT),
- MAKE_STRING_FROM_ENUM(AUDIO_GAIN_MODE_CHANNELS),
- MAKE_STRING_FROM_ENUM(AUDIO_GAIN_MODE_RAMP),
- TERMINATOR
-};
-
-
-template <>
-const StreamTypeConverter::Table StreamTypeConverter::mTable[] = {
- MAKE_STRING_FROM_ENUM(AUDIO_STREAM_DEFAULT),
- MAKE_STRING_FROM_ENUM(AUDIO_STREAM_VOICE_CALL),
- MAKE_STRING_FROM_ENUM(AUDIO_STREAM_SYSTEM),
- MAKE_STRING_FROM_ENUM(AUDIO_STREAM_RING),
- MAKE_STRING_FROM_ENUM(AUDIO_STREAM_MUSIC),
- MAKE_STRING_FROM_ENUM(AUDIO_STREAM_ALARM),
- MAKE_STRING_FROM_ENUM(AUDIO_STREAM_NOTIFICATION),
- MAKE_STRING_FROM_ENUM(AUDIO_STREAM_BLUETOOTH_SCO ),
- MAKE_STRING_FROM_ENUM(AUDIO_STREAM_ENFORCED_AUDIBLE),
- MAKE_STRING_FROM_ENUM(AUDIO_STREAM_DTMF),
- MAKE_STRING_FROM_ENUM(AUDIO_STREAM_TTS),
- MAKE_STRING_FROM_ENUM(AUDIO_STREAM_ACCESSIBILITY),
- MAKE_STRING_FROM_ENUM(AUDIO_STREAM_REROUTING),
- MAKE_STRING_FROM_ENUM(AUDIO_STREAM_PATCH),
- TERMINATOR
-};
-
-template<>
-const AudioModeConverter::Table AudioModeConverter::mTable[] = {
- MAKE_STRING_FROM_ENUM(AUDIO_MODE_INVALID),
- MAKE_STRING_FROM_ENUM(AUDIO_MODE_CURRENT),
- MAKE_STRING_FROM_ENUM(AUDIO_MODE_NORMAL),
- MAKE_STRING_FROM_ENUM(AUDIO_MODE_RINGTONE),
- MAKE_STRING_FROM_ENUM(AUDIO_MODE_IN_CALL),
- MAKE_STRING_FROM_ENUM(AUDIO_MODE_IN_COMMUNICATION),
- TERMINATOR
-};
-
-template<>
-const AudioContentTypeConverter::Table AudioContentTypeConverter::mTable[] = {
- MAKE_STRING_FROM_ENUM(AUDIO_CONTENT_TYPE_UNKNOWN),
- MAKE_STRING_FROM_ENUM(AUDIO_CONTENT_TYPE_SPEECH),
- MAKE_STRING_FROM_ENUM(AUDIO_CONTENT_TYPE_MUSIC),
- MAKE_STRING_FROM_ENUM(AUDIO_CONTENT_TYPE_MOVIE),
- MAKE_STRING_FROM_ENUM(AUDIO_CONTENT_TYPE_SONIFICATION),
- TERMINATOR
-};
-
-template <>
-const UsageTypeConverter::Table UsageTypeConverter::mTable[] = {
- MAKE_STRING_FROM_ENUM(AUDIO_USAGE_UNKNOWN),
- MAKE_STRING_FROM_ENUM(AUDIO_USAGE_MEDIA),
- MAKE_STRING_FROM_ENUM(AUDIO_USAGE_VOICE_COMMUNICATION),
- MAKE_STRING_FROM_ENUM(AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING),
- MAKE_STRING_FROM_ENUM(AUDIO_USAGE_ALARM),
- MAKE_STRING_FROM_ENUM(AUDIO_USAGE_NOTIFICATION),
- MAKE_STRING_FROM_ENUM(AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE),
- MAKE_STRING_FROM_ENUM(AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST),
- MAKE_STRING_FROM_ENUM(AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT),
- MAKE_STRING_FROM_ENUM(AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED),
- MAKE_STRING_FROM_ENUM(AUDIO_USAGE_NOTIFICATION_EVENT),
- MAKE_STRING_FROM_ENUM(AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY),
- MAKE_STRING_FROM_ENUM(AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE),
- MAKE_STRING_FROM_ENUM(AUDIO_USAGE_ASSISTANCE_SONIFICATION),
- MAKE_STRING_FROM_ENUM(AUDIO_USAGE_GAME),
- MAKE_STRING_FROM_ENUM(AUDIO_USAGE_VIRTUAL_SOURCE),
- MAKE_STRING_FROM_ENUM(AUDIO_USAGE_ASSISTANT),
- TERMINATOR
-};
-
-template <>
-const SourceTypeConverter::Table SourceTypeConverter::mTable[] = {
- MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_DEFAULT),
- MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_MIC),
- MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_VOICE_UPLINK),
- MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_VOICE_DOWNLINK),
- MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_VOICE_CALL),
- MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_CAMCORDER),
- MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_VOICE_RECOGNITION),
- MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_VOICE_COMMUNICATION),
- MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_REMOTE_SUBMIX),
- MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_UNPROCESSED),
- MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_VOICE_PERFORMANCE),
- MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_ECHO_REFERENCE),
- MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_FM_TUNER),
- MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_HOTWORD),
- TERMINATOR
-};
-
-template <>
-const AudioFlagConverter::Table AudioFlagConverter::mTable[] = {
- MAKE_STRING_FROM_ENUM(AUDIO_FLAG_NONE),
- MAKE_STRING_FROM_ENUM(AUDIO_FLAG_AUDIBILITY_ENFORCED),
- MAKE_STRING_FROM_ENUM(AUDIO_FLAG_SECURE),
- MAKE_STRING_FROM_ENUM(AUDIO_FLAG_SCO),
- MAKE_STRING_FROM_ENUM(AUDIO_FLAG_BEACON),
- MAKE_STRING_FROM_ENUM(AUDIO_FLAG_HW_AV_SYNC),
- MAKE_STRING_FROM_ENUM(AUDIO_FLAG_HW_HOTWORD),
- MAKE_STRING_FROM_ENUM(AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY),
- MAKE_STRING_FROM_ENUM(AUDIO_FLAG_BYPASS_MUTE),
- MAKE_STRING_FROM_ENUM(AUDIO_FLAG_LOW_LATENCY),
- MAKE_STRING_FROM_ENUM(AUDIO_FLAG_DEEP_BUFFER),
- MAKE_STRING_FROM_ENUM(AUDIO_FLAG_NO_MEDIA_PROJECTION),
- MAKE_STRING_FROM_ENUM(AUDIO_FLAG_NO_SYSTEM_CAPTURE),
- TERMINATOR
-};
-
-template class TypeConverter<OutputDeviceTraits>;
-template class TypeConverter<InputDeviceTraits>;
-template class TypeConverter<OutputFlagTraits>;
-template class TypeConverter<InputFlagTraits>;
-template class TypeConverter<FormatTraits>;
-template class TypeConverter<OutputChannelTraits>;
-template class TypeConverter<InputChannelTraits>;
-template class TypeConverter<ChannelIndexTraits>;
-template class TypeConverter<GainModeTraits>;
-template class TypeConverter<StreamTraits>;
-template class TypeConverter<AudioModeTraits>;
-template class TypeConverter<UsageTraits>;
-template class TypeConverter<SourceTraits>;
-template class TypeConverter<AudioFlagTraits>;
-
-bool deviceFromString(const std::string& literalDevice, audio_devices_t& device) {
- return InputDeviceConverter::fromString(literalDevice, device) ||
- OutputDeviceConverter::fromString(literalDevice, device);
-}
-
-SampleRateTraits::Collection samplingRatesFromString(
- const std::string &samplingRates, const char *del)
-{
- SampleRateTraits::Collection samplingRateCollection;
- collectionFromString<SampleRateTraits>(samplingRates, samplingRateCollection, del);
- return samplingRateCollection;
-}
-
-FormatTraits::Collection formatsFromString(
- const std::string &formats, const char *del)
-{
- FormatTraits::Collection formatCollection;
- FormatConverter::collectionFromString(formats, formatCollection, del);
- return formatCollection;
-}
-
-audio_format_t formatFromString(const std::string &literalFormat, audio_format_t defaultFormat)
-{
- audio_format_t format;
- if (literalFormat.empty()) {
- return defaultFormat;
- }
- FormatConverter::fromString(literalFormat, format);
- return format;
-}
-
-audio_channel_mask_t channelMaskFromString(const std::string &literalChannels)
-{
- audio_channel_mask_t channels;
- if (!OutputChannelConverter::fromString(literalChannels, channels) &&
- !InputChannelConverter::fromString(literalChannels, channels)) {
- return AUDIO_CHANNEL_INVALID;
- }
- return channels;
-}
-
-ChannelTraits::Collection channelMasksFromString(
- const std::string &channels, const char *del)
-{
- ChannelTraits::Collection channelMaskCollection;
- OutputChannelConverter::collectionFromString(channels, channelMaskCollection, del);
- InputChannelConverter::collectionFromString(channels, channelMaskCollection, del);
- ChannelIndexConverter::collectionFromString(channels, channelMaskCollection, del);
- return channelMaskCollection;
-}
-
-InputChannelTraits::Collection inputChannelMasksFromString(
- const std::string &inChannels, const char *del)
-{
- InputChannelTraits::Collection inputChannelMaskCollection;
- InputChannelConverter::collectionFromString(inChannels, inputChannelMaskCollection, del);
- ChannelIndexConverter::collectionFromString(inChannels, inputChannelMaskCollection, del);
- return inputChannelMaskCollection;
-}
-
-OutputChannelTraits::Collection outputChannelMasksFromString(
- const std::string &outChannels, const char *del)
-{
- OutputChannelTraits::Collection outputChannelMaskCollection;
- OutputChannelConverter::collectionFromString(outChannels, outputChannelMaskCollection, del);
- ChannelIndexConverter::collectionFromString(outChannels, outputChannelMaskCollection, del);
- return outputChannelMaskCollection;
-}
-
-}; // namespace android
diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp
deleted file mode 100644
index 2bf0802..0000000
--- a/media/libmedia/Visualizer.cpp
+++ /dev/null
@@ -1,445 +0,0 @@
-/*
-**
-** Copyright 2010, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "Visualizer"
-#include <utils/Log.h>
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <limits.h>
-
-#include <media/Visualizer.h>
-#include <audio_utils/fixedfft.h>
-#include <utils/Thread.h>
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-Visualizer::Visualizer (const String16& opPackageName,
- int32_t priority,
- effect_callback_t cbf,
- void* user,
- audio_session_t sessionId)
- : AudioEffect(SL_IID_VISUALIZATION, opPackageName, NULL, priority, cbf, user, sessionId),
- mCaptureRate(CAPTURE_RATE_DEF),
- mCaptureSize(CAPTURE_SIZE_DEF),
- mSampleRate(44100000),
- mScalingMode(VISUALIZER_SCALING_MODE_NORMALIZED),
- mMeasurementMode(MEASUREMENT_MODE_NONE),
- mCaptureCallBack(NULL),
- mCaptureCbkUser(NULL)
-{
- initCaptureSize();
-}
-
-Visualizer::~Visualizer()
-{
- ALOGV("Visualizer::~Visualizer()");
- setEnabled(false);
- setCaptureCallBack(NULL, NULL, 0, 0);
-}
-
-void Visualizer::release()
-{
- ALOGV("Visualizer::release()");
- setEnabled(false);
- Mutex::Autolock _l(mCaptureLock);
-
- mCaptureThread.clear();
- mCaptureCallBack = NULL;
- mCaptureCbkUser = NULL;
- mCaptureFlags = 0;
- mCaptureRate = 0;
-}
-
-status_t Visualizer::setEnabled(bool enabled)
-{
- Mutex::Autolock _l(mCaptureLock);
-
- sp<CaptureThread> t = mCaptureThread;
- if (t != 0) {
- if (enabled) {
- if (t->exitPending()) {
- mCaptureLock.unlock();
- if (t->requestExitAndWait() == WOULD_BLOCK) {
- mCaptureLock.lock();
- ALOGE("Visualizer::enable() called from thread");
- return INVALID_OPERATION;
- }
- mCaptureLock.lock();
- }
- }
- t->mLock.lock();
- }
-
- status_t status = AudioEffect::setEnabled(enabled);
-
- if (t != 0) {
- if (enabled && status == NO_ERROR) {
- t->run("Visualizer");
- } else {
- t->requestExit();
- }
- }
-
- if (t != 0) {
- t->mLock.unlock();
- }
-
- return status;
-}
-
-status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags,
- uint32_t rate)
-{
- if (rate > CAPTURE_RATE_MAX) {
- return BAD_VALUE;
- }
- Mutex::Autolock _l(mCaptureLock);
-
- if (mEnabled) {
- return INVALID_OPERATION;
- }
-
- if (mCaptureThread != 0) {
- mCaptureLock.unlock();
- mCaptureThread->requestExitAndWait();
- mCaptureLock.lock();
- }
-
- mCaptureThread.clear();
- mCaptureCallBack = cbk;
- mCaptureCbkUser = user;
- mCaptureFlags = flags;
- mCaptureRate = rate;
-
- if (cbk != NULL) {
- mCaptureThread = new CaptureThread(this, rate, ((flags & CAPTURE_CALL_JAVA) != 0));
- }
- ALOGV("setCaptureCallBack() rate: %d thread %p flags 0x%08x",
- rate, mCaptureThread.get(), mCaptureFlags);
- return NO_ERROR;
-}
-
-status_t Visualizer::setCaptureSize(uint32_t size)
-{
- if (size > VISUALIZER_CAPTURE_SIZE_MAX ||
- size < VISUALIZER_CAPTURE_SIZE_MIN ||
- popcount(size) != 1) {
- return BAD_VALUE;
- }
-
- Mutex::Autolock _l(mCaptureLock);
- if (mEnabled) {
- return INVALID_OPERATION;
- }
-
- uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
- effect_param_t *p = (effect_param_t *)buf32;
-
- p->psize = sizeof(uint32_t);
- p->vsize = sizeof(uint32_t);
- *(int32_t *)p->data = VISUALIZER_PARAM_CAPTURE_SIZE;
- *((int32_t *)p->data + 1)= size;
- status_t status = setParameter(p);
-
- ALOGV("setCaptureSize size %d status %d p->status %d", size, status, p->status);
-
- if (status == NO_ERROR) {
- status = p->status;
- if (status == NO_ERROR) {
- mCaptureSize = size;
- }
- }
-
- return status;
-}
-
-status_t Visualizer::setScalingMode(uint32_t mode) {
- if ((mode != VISUALIZER_SCALING_MODE_NORMALIZED)
- && (mode != VISUALIZER_SCALING_MODE_AS_PLAYED)) {
- return BAD_VALUE;
- }
-
- Mutex::Autolock _l(mCaptureLock);
-
- uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
- effect_param_t *p = (effect_param_t *)buf32;
-
- p->psize = sizeof(uint32_t);
- p->vsize = sizeof(uint32_t);
- *(int32_t *)p->data = VISUALIZER_PARAM_SCALING_MODE;
- *((int32_t *)p->data + 1)= mode;
- status_t status = setParameter(p);
-
- ALOGV("setScalingMode mode %d status %d p->status %d", mode, status, p->status);
-
- if (status == NO_ERROR) {
- status = p->status;
- if (status == NO_ERROR) {
- mScalingMode = mode;
- }
- }
-
- return status;
-}
-
-status_t Visualizer::setMeasurementMode(uint32_t mode) {
- if ((mode != MEASUREMENT_MODE_NONE)
- //Note: needs to be handled as a mask when more measurement modes are added
- && ((mode & MEASUREMENT_MODE_PEAK_RMS) != mode)) {
- return BAD_VALUE;
- }
-
- Mutex::Autolock _l(mCaptureLock);
-
- uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
- effect_param_t *p = (effect_param_t *)buf32;
-
- p->psize = sizeof(uint32_t);
- p->vsize = sizeof(uint32_t);
- *(int32_t *)p->data = VISUALIZER_PARAM_MEASUREMENT_MODE;
- *((int32_t *)p->data + 1)= mode;
- status_t status = setParameter(p);
-
- ALOGV("setMeasurementMode mode %d status %d p->status %d", mode, status, p->status);
-
- if (status == NO_ERROR) {
- status = p->status;
- if (status == NO_ERROR) {
- mMeasurementMode = mode;
- }
- }
- return status;
-}
-
-status_t Visualizer::getIntMeasurements(uint32_t type, uint32_t number, int32_t *measurements) {
- if (mMeasurementMode == MEASUREMENT_MODE_NONE) {
- ALOGE("Cannot retrieve int measurements, no measurement mode set");
- return INVALID_OPERATION;
- }
- if (!(mMeasurementMode & type)) {
- // measurement type has not been set on this Visualizer
- ALOGE("Cannot retrieve int measurements, requested measurement mode 0x%x not set(0x%x)",
- type, mMeasurementMode);
- return INVALID_OPERATION;
- }
- // only peak+RMS measurement supported
- if ((type != MEASUREMENT_MODE_PEAK_RMS)
- // for peak+RMS measurement, the results are 2 int32_t values
- || (number != 2)) {
- ALOGE("Cannot retrieve int measurements, MEASUREMENT_MODE_PEAK_RMS returns 2 ints, not %d",
- number);
- return BAD_VALUE;
- }
-
- status_t status = NO_ERROR;
- if (mEnabled) {
- uint32_t replySize = number * sizeof(int32_t);
- status = command(VISUALIZER_CMD_MEASURE,
- sizeof(uint32_t) /*cmdSize*/,
- &type /*cmdData*/,
- &replySize, measurements);
- ALOGV("getMeasurements() command returned %d", status);
- if ((status == NO_ERROR) && (replySize == 0)) {
- status = NOT_ENOUGH_DATA;
- }
- } else {
- ALOGV("getMeasurements() disabled");
- return INVALID_OPERATION;
- }
- return status;
-}
-
-status_t Visualizer::getWaveForm(uint8_t *waveform)
-{
- if (waveform == NULL) {
- return BAD_VALUE;
- }
- if (mCaptureSize == 0) {
- return NO_INIT;
- }
-
- status_t status = NO_ERROR;
- if (mEnabled) {
- uint32_t replySize = mCaptureSize;
- status = command(VISUALIZER_CMD_CAPTURE, 0, NULL, &replySize, waveform);
- ALOGV("getWaveForm() command returned %d", status);
- if ((status == NO_ERROR) && (replySize == 0)) {
- status = NOT_ENOUGH_DATA;
- }
- } else {
- ALOGV("getWaveForm() disabled");
- memset(waveform, 0x80, mCaptureSize);
- }
- return status;
-}
-
-status_t Visualizer::getFft(uint8_t *fft)
-{
- if (fft == NULL) {
- return BAD_VALUE;
- }
- if (mCaptureSize == 0) {
- return NO_INIT;
- }
-
- status_t status = NO_ERROR;
- if (mEnabled) {
- uint8_t buf[mCaptureSize];
- status = getWaveForm(buf);
- if (status == NO_ERROR) {
- status = doFft(fft, buf);
- }
- } else {
- memset(fft, 0, mCaptureSize);
- }
- return status;
-}
-
-status_t Visualizer::doFft(uint8_t *fft, uint8_t *waveform)
-{
- int32_t workspace[mCaptureSize >> 1];
- int32_t nonzero = 0;
-
- for (uint32_t i = 0; i < mCaptureSize; i += 2) {
- workspace[i >> 1] =
- ((waveform[i] ^ 0x80) << 24) | ((waveform[i + 1] ^ 0x80) << 8);
- nonzero |= workspace[i >> 1];
- }
-
- if (nonzero) {
- fixed_fft_real(mCaptureSize >> 1, workspace);
- }
-
- for (uint32_t i = 0; i < mCaptureSize; i += 2) {
- short tmp = workspace[i >> 1] >> 21;
- while (tmp > 127 || tmp < -128) tmp >>= 1;
- fft[i] = tmp;
- tmp = workspace[i >> 1];
- tmp >>= 5;
- while (tmp > 127 || tmp < -128) tmp >>= 1;
- fft[i + 1] = tmp;
- }
-
- return NO_ERROR;
-}
-
-void Visualizer::periodicCapture()
-{
- Mutex::Autolock _l(mCaptureLock);
- ALOGV("periodicCapture() %p mCaptureCallBack %p mCaptureFlags 0x%08x",
- this, mCaptureCallBack, mCaptureFlags);
- if (mCaptureCallBack != NULL &&
- (mCaptureFlags & (CAPTURE_WAVEFORM|CAPTURE_FFT)) &&
- mCaptureSize != 0) {
- uint8_t waveform[mCaptureSize];
- status_t status = getWaveForm(waveform);
- if (status != NO_ERROR) {
- return;
- }
- uint8_t fft[mCaptureSize];
- if (mCaptureFlags & CAPTURE_FFT) {
- status = doFft(fft, waveform);
- }
- if (status != NO_ERROR) {
- return;
- }
- uint8_t *wavePtr = NULL;
- uint8_t *fftPtr = NULL;
- uint32_t waveSize = 0;
- uint32_t fftSize = 0;
- if (mCaptureFlags & CAPTURE_WAVEFORM) {
- wavePtr = waveform;
- waveSize = mCaptureSize;
- }
- if (mCaptureFlags & CAPTURE_FFT) {
- fftPtr = fft;
- fftSize = mCaptureSize;
- }
- mCaptureCallBack(mCaptureCbkUser, waveSize, wavePtr, fftSize, fftPtr, mSampleRate);
- }
-}
-
-uint32_t Visualizer::initCaptureSize()
-{
- uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
- effect_param_t *p = (effect_param_t *)buf32;
-
- p->psize = sizeof(uint32_t);
- p->vsize = sizeof(uint32_t);
- *(int32_t *)p->data = VISUALIZER_PARAM_CAPTURE_SIZE;
- status_t status = getParameter(p);
-
- if (status == NO_ERROR) {
- status = p->status;
- }
-
- uint32_t size = 0;
- if (status == NO_ERROR) {
- size = *((int32_t *)p->data + 1);
- }
- mCaptureSize = size;
-
- ALOGV("initCaptureSize size %d status %d", mCaptureSize, status);
-
- return size;
-}
-
-void Visualizer::controlStatusChanged(bool controlGranted) {
- if (controlGranted) {
- // this Visualizer instance regained control of the effect, reset the scaling mode
- // and capture size as has been cached through it.
- ALOGV("controlStatusChanged(true) causes effect parameter reset:");
- ALOGV(" scaling mode reset to %d", mScalingMode);
- setScalingMode(mScalingMode);
- ALOGV(" capture size reset to %d", mCaptureSize);
- setCaptureSize(mCaptureSize);
- }
- AudioEffect::controlStatusChanged(controlGranted);
-}
-
-//-------------------------------------------------------------------------
-
-Visualizer::CaptureThread::CaptureThread(Visualizer* receiver, uint32_t captureRate,
- bool bCanCallJava)
- : Thread(bCanCallJava), mReceiver(receiver)
-{
- mSleepTimeUs = 1000000000 / captureRate;
- ALOGV("CaptureThread cstor %p captureRate %d mSleepTimeUs %d", this, captureRate, mSleepTimeUs);
-}
-
-bool Visualizer::CaptureThread::threadLoop()
-{
- ALOGV("CaptureThread %p enter", this);
- sp<Visualizer> receiver = mReceiver.promote();
- if (receiver == NULL) {
- return false;
- }
- while (!exitPending())
- {
- usleep(mSleepTimeUs);
- receiver->periodicCapture();
- }
- ALOGV("CaptureThread %p exiting", this);
- return false;
-}
-
-} // namespace android
diff --git a/media/libmedia/aidl/android/IDataSource.aidl b/media/libmedia/aidl/android/IDataSource.aidl
new file mode 100644
index 0000000..fb954bf
--- /dev/null
+++ b/media/libmedia/aidl/android/IDataSource.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+package android;
+
+/** @hide */
+interface IDataSource {
+ // Stub for manual implementation
+}
diff --git a/media/libmedia/aidl/android/IMediaExtractor.aidl b/media/libmedia/aidl/android/IMediaExtractor.aidl
new file mode 100644
index 0000000..5ba68e6
--- /dev/null
+++ b/media/libmedia/aidl/android/IMediaExtractor.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+package android;
+
+/** @hide */
+interface IMediaExtractor {
+ // Stub for manual implementation
+}
diff --git a/media/libmedia/aidl/android/IMediaExtractorService.aidl b/media/libmedia/aidl/android/IMediaExtractorService.aidl
new file mode 100644
index 0000000..c57fa16
--- /dev/null
+++ b/media/libmedia/aidl/android/IMediaExtractorService.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+package android;
+
+import android.IDataSource;
+import android.IMediaExtractor;
+
+/**
+ * Binder interface for the media extractor service
+ *
+ * @hide
+ */
+interface IMediaExtractorService {
+
+ IMediaExtractor makeExtractor(IDataSource source, @nullable @utf8InCpp String mime);
+ IDataSource makeIDataSource(in FileDescriptor fd, long offset, long length);
+ @utf8InCpp String[] getSupportedTypes();
+}
diff --git a/media/libmedia/aidl/android/media/IResourceManagerClient.aidl b/media/libmedia/aidl/android/media/IResourceManagerClient.aidl
new file mode 100644
index 0000000..4c3ef47
--- /dev/null
+++ b/media/libmedia/aidl/android/media/IResourceManagerClient.aidl
@@ -0,0 +1,39 @@
+/**
+ * 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.
+ */
+
+package android.media;
+
+/**
+ * IResourceManagerClient interface for the ResourceManagerService to
+ * call the client.
+ *
+ * {@hide}
+ */
+interface IResourceManagerClient {
+ /**
+ * Instruct the client to reclaim its resources.
+ *
+ * @return true if the reclaim was successful and false otherwise.
+ */
+ boolean reclaimResource();
+
+ /**
+ * Retrieve the name of the client.
+ *
+ * @return name of the client.
+ */
+ @utf8InCpp String getName();
+}
diff --git a/media/libmedia/aidl/android/media/IResourceManagerService.aidl b/media/libmedia/aidl/android/media/IResourceManagerService.aidl
new file mode 100644
index 0000000..3dd0859
--- /dev/null
+++ b/media/libmedia/aidl/android/media/IResourceManagerService.aidl
@@ -0,0 +1,97 @@
+/**
+ * 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.
+ */
+
+package android.media;
+
+import android.media.IResourceManagerClient;
+import android.media.MediaResourceParcel;
+import android.media.MediaResourcePolicyParcel;
+
+/**
+ * ResourceManagerService interface that keeps track of media resource
+ * owned by clients, and reclaims resources based on configured policies
+ * when necessary.
+ *
+ * {@hide}
+ */
+interface IResourceManagerService {
+ const @utf8InCpp String kPolicySupportsMultipleSecureCodecs
+ = "supports-multiple-secure-codecs";
+ const @utf8InCpp String kPolicySupportsSecureWithNonSecureCodec
+ = "supports-secure-with-non-secure-codec";
+
+ /**
+ * Configure the ResourceManagerService to adopted particular policies when
+ * managing the resources.
+ *
+ * @param policies an array of policies to be adopted.
+ */
+ void config(in MediaResourcePolicyParcel[] policies);
+
+ /**
+ * Add a client to a process with a list of resources.
+ *
+ * @param pid pid of the client.
+ * @param uid uid of the client.
+ * @param clientId an identifier that uniquely identifies the client within the pid.
+ * @param client interface for the ResourceManagerService to call the client.
+ * @param resources an array of resources to be added.
+ */
+ void addResource(
+ int pid,
+ int uid,
+ long clientId,
+ IResourceManagerClient client,
+ in MediaResourceParcel[] resources);
+
+ /**
+ * Remove the listed resources from a client.
+ *
+ * @param pid pid from which the list of resources will be removed.
+ * @param clientId clientId within the pid from which the list of resources will be removed.
+ * @param resources an array of resources to be removed from the client.
+ */
+ void removeResource(int pid, long clientId, in MediaResourceParcel[] resources);
+
+ /**
+ * Remove all resources from a client.
+ *
+ * @param pid pid from which the client's resources will be removed.
+ * @param clientId clientId within the pid that will be removed.
+ */
+ void removeClient(int pid, long clientId);
+
+ /**
+ * Tries to reclaim resource from processes with lower priority than the
+ * calling process according to the requested resources.
+ *
+ * @param callingPid pid of the calling process.
+ * @param resources an array of resources to be reclaimed.
+ *
+ * @return true if the reclaim was successful and false otherwise.
+ */
+ boolean reclaimResource(int callingPid, in MediaResourceParcel[] resources);
+
+ /**
+ * Override the pid of original calling process with the pid of the process
+ * who actually use the requested resources.
+ *
+ * @param originalPid pid of the original calling process.
+ * @param newPid pid of the actual process who use the resources.
+ * remove existing override on originalPid if newPid is -1.
+ */
+ void overridePid(int originalPid, int newPid);
+}
diff --git a/media/libmedia/aidl/android/media/MediaResourceParcel.aidl b/media/libmedia/aidl/android/media/MediaResourceParcel.aidl
new file mode 100644
index 0000000..b0f2b71
--- /dev/null
+++ b/media/libmedia/aidl/android/media/MediaResourceParcel.aidl
@@ -0,0 +1,50 @@
+/**
+ * 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.
+ */
+
+package android.media;
+
+import android.media.MediaResourceType;
+import android.media.MediaResourceSubType;
+
+/**
+ * Description of a media resource to be tracked by MediaResourceManager.
+ *
+ * {@hide}
+ */
+parcelable MediaResourceParcel {
+ // TODO: default enum value is not supported yet.
+ // Set default enum value when b/142739329 is fixed.
+
+ /**
+ * Type of the media resource.
+ */
+ MediaResourceType type;// = MediaResourceTypeEnum::kUnspecified;
+
+ /**
+ * Sub-type of the media resource.
+ */
+ MediaResourceSubType subType;// = MediaResourceSubTypeEnum::kUnspecifiedSubType;
+
+ /**
+ * Identifier of the media resource (eg. Drm session id).
+ */
+ byte[] id;
+
+ /**
+ * Number of units of the media resource (bytes of graphic memory, number of codecs, etc.).
+ */
+ long value = 0;
+}
diff --git a/media/libmedia/aidl/android/media/MediaResourcePolicyParcel.aidl b/media/libmedia/aidl/android/media/MediaResourcePolicyParcel.aidl
new file mode 100644
index 0000000..4ea859a
--- /dev/null
+++ b/media/libmedia/aidl/android/media/MediaResourcePolicyParcel.aidl
@@ -0,0 +1,33 @@
+/**
+ * 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.
+ */
+
+package android.media;
+
+/**
+ * Description of a policy to be adopted by ResourceManagerService.
+ * {@hide}
+ */
+parcelable MediaResourcePolicyParcel {
+ /**
+ * Name of the policy to be adopted.
+ */
+ @utf8InCpp String type;
+
+ /**
+ * Value of the policy to be adopted.
+ */
+ @utf8InCpp String value;
+}
diff --git a/media/libmedia/aidl/android/media/MediaResourceSubType.aidl b/media/libmedia/aidl/android/media/MediaResourceSubType.aidl
new file mode 100644
index 0000000..af2ba68
--- /dev/null
+++ b/media/libmedia/aidl/android/media/MediaResourceSubType.aidl
@@ -0,0 +1,29 @@
+/**
+ * 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.
+ */
+
+package android.media;
+
+/**
+ * Sub-type enums of media resources.
+ *
+ * {@hide}
+ */
+@Backing(type="int")
+enum MediaResourceSubType {
+ kUnspecifiedSubType = 0,
+ kAudioCodec = 1,
+ kVideoCodec = 2,
+}
diff --git a/media/libmedia/aidl/android/media/MediaResourceType.aidl b/media/libmedia/aidl/android/media/MediaResourceType.aidl
new file mode 100644
index 0000000..b2bb71b
--- /dev/null
+++ b/media/libmedia/aidl/android/media/MediaResourceType.aidl
@@ -0,0 +1,33 @@
+/**
+ * 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.
+ */
+
+package android.media;
+
+/**
+ * Type enums of media resources.
+ *
+ * {@hide}
+ */
+@Backing(type="int")
+enum MediaResourceType {
+ kUnspecified = 0,
+ kSecureCodec = 1,
+ kNonSecureCodec = 2,
+ kGraphicMemory = 3,
+ kCpuBoost = 4,
+ kBattery = 5,
+ kDrmSession = 6,
+}
diff --git a/media/libmedia/include/android/IDataSource.h b/media/libmedia/include/android/IDataSource.h
new file mode 100644
index 0000000..43e2b50
--- /dev/null
+++ b/media/libmedia/include/android/IDataSource.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_IDATASOURCE_H
+#define ANDROID_IDATASOURCE_H
+
+#include <binder/IInterface.h>
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/Errors.h>
+#include <utils/String8.h>
+
+namespace android {
+
+class IMemory;
+class DecryptHandle;
+
+// A binder interface for implementing a stagefright DataSource remotely.
+class IDataSource : public IInterface {
+public:
+ DECLARE_META_INTERFACE(DataSource);
+
+ // Get the memory that readAt writes into.
+ virtual sp<IMemory> getIMemory() = 0;
+ // Read up to |size| bytes into the memory returned by getIMemory(). Returns
+ // the number of bytes read, or negative value on error (eg.
+ // ERROR_END_OF_STREAM indicating EOS. This is needed by CallbackDataSource
+ // to properly handle reading of last chunk). |size| must not be larger than
+ // the buffer.
+ virtual ssize_t readAt(off64_t offset, size_t size) = 0;
+ // Get the size, or -1 if the size is unknown.
+ virtual status_t getSize(off64_t* size) = 0;
+ // This should be called before deleting |this|. The other methods may
+ // return errors if they're called after calling close().
+ virtual void close() = 0;
+ // Get the flags of the source.
+ // Refer to DataSource:Flags for the definition of the flags.
+ virtual uint32_t getFlags() = 0;
+ // get a description of the source, e.g. the url or filename it is based on
+ virtual String8 toString() = 0;
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(IDataSource);
+};
+
+// ----------------------------------------------------------------------------
+
+class BnDataSource : public BnInterface<IDataSource> {
+public:
+ virtual status_t onTransact(uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif // ANDROID_IDATASOURCE_H
diff --git a/media/libmedia/include/android/IMediaExtractor.h b/media/libmedia/include/android/IMediaExtractor.h
new file mode 100644
index 0000000..3e035ad
--- /dev/null
+++ b/media/libmedia/include/android/IMediaExtractor.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IMEDIA_EXTRACTOR_BASE_H_
+
+#define IMEDIA_EXTRACTOR_BASE_H_
+
+#include <media/DataSource.h>
+#include <media/IMediaSource.h>
+#include <vector>
+
+namespace android {
+
+class MetaData;
+typedef std::vector<uint8_t> HInterfaceToken;
+
+class IMediaExtractor : public IInterface {
+public:
+ DECLARE_META_INTERFACE(MediaExtractor);
+
+ virtual size_t countTracks() = 0;
+ // This function could return NULL IMediaSource even when index is within the
+ // track count returned by countTracks, since it's possible the track is malformed
+ // and it's not detected during countTracks call.
+ virtual sp<IMediaSource> getTrack(size_t index) = 0;
+
+ enum GetTrackMetaDataFlags {
+ kIncludeExtensiveMetaData = 1
+ };
+ virtual sp<MetaData> getTrackMetaData(
+ size_t index, uint32_t flags = 0) = 0;
+
+ // Return container specific meta-data. The default implementation
+ // returns an empty metadata object.
+ virtual sp<MetaData> getMetaData() = 0;
+
+ virtual status_t getMetrics(Parcel *reply) = 0;
+
+ enum Flags {
+ CAN_SEEK_BACKWARD = 1, // the "seek 10secs back button"
+ CAN_SEEK_FORWARD = 2, // the "seek 10secs forward button"
+ CAN_PAUSE = 4,
+ CAN_SEEK = 8, // the "seek bar"
+ };
+
+ // If subclasses do _not_ override this, the default is
+ // CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE
+ virtual uint32_t flags() const = 0;
+
+ virtual status_t setMediaCas(const HInterfaceToken &casToken) = 0;
+
+ virtual String8 name() = 0;
+};
+
+
+class BnMediaExtractor: public BnInterface<IMediaExtractor>
+{
+public:
+ virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags = 0);
+};
+
+void registerMediaExtractor(
+ const sp<IMediaExtractor> &extractor,
+ const sp<DataSource> &source,
+ const char *mime);
+
+void registerMediaSource(
+ const sp<IMediaExtractor> &extractor,
+ const sp<IMediaSource> &source);
+
+status_t dumpExtractors(int fd, const Vector<String16>& args);
+
+
+} // namespace android
+
+#endif // IMEDIA_EXTRACTOR_BASE_H_
diff --git a/media/libmedia/include/media/CounterMetric.h b/media/libmedia/include/media/CounterMetric.h
index b53470d..8bd4049 100644
--- a/media/libmedia/include/media/CounterMetric.h
+++ b/media/libmedia/include/media/CounterMetric.h
@@ -20,7 +20,7 @@
#include <map>
#include <string>
-#include <media/MediaAnalyticsItem.h>
+#include <media/MediaMetricsItem.h>
#include <utils/Log.h>
namespace android {
diff --git a/media/libmedia/include/media/CryptoHal.h b/media/libmedia/include/media/CryptoHal.h
deleted file mode 100644
index 73c029f..0000000
--- a/media/libmedia/include/media/CryptoHal.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CRYPTO_HAL_H_
-
-#define CRYPTO_HAL_H_
-
-#include <android/hardware/drm/1.0/ICryptoFactory.h>
-#include <android/hardware/drm/1.0/ICryptoPlugin.h>
-#include <android/hardware/drm/1.1/ICryptoFactory.h>
-#include <android/hardware/drm/1.2/ICryptoPlugin.h>
-
-#include <mediadrm/ICrypto.h>
-#include <utils/KeyedVector.h>
-#include <utils/threads.h>
-
-namespace drm = ::android::hardware::drm;
-using drm::V1_0::ICryptoFactory;
-using drm::V1_0::ICryptoPlugin;
-using drm::V1_0::SharedBuffer;
-
-class IMemoryHeap;
-
-namespace android {
-
-struct CryptoHal : public BnCrypto {
- CryptoHal();
- virtual ~CryptoHal();
-
- virtual status_t initCheck() const;
-
- virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]);
-
- virtual status_t createPlugin(
- const uint8_t uuid[16], const void *data, size_t size);
-
- virtual status_t destroyPlugin();
-
- virtual bool requiresSecureDecoderComponent(
- const char *mime) const;
-
- virtual void notifyResolution(uint32_t width, uint32_t height);
-
- virtual status_t setMediaDrmSession(const Vector<uint8_t> &sessionId);
-
- virtual ssize_t decrypt(const uint8_t key[16], const uint8_t iv[16],
- CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
- const ICrypto::SourceBuffer &source, size_t offset,
- const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
- const ICrypto::DestinationBuffer &destination,
- AString *errorDetailMsg);
-
- virtual int32_t setHeap(const sp<IMemoryHeap>& heap) {
- return setHeapBase(heap);
- }
- virtual void unsetHeap(int32_t seqNum) { clearHeapBase(seqNum); }
-
-private:
- mutable Mutex mLock;
-
- const Vector<sp<ICryptoFactory>> mFactories;
- sp<ICryptoPlugin> mPlugin;
- sp<drm::V1_2::ICryptoPlugin> mPluginV1_2;
-
- /**
- * mInitCheck is:
- * NO_INIT if a plugin hasn't been created yet
- * ERROR_UNSUPPORTED if a plugin can't be created for the uuid
- * OK after a plugin has been created and mPlugin is valid
- */
- status_t mInitCheck;
-
- struct HeapBase {
- HeapBase() : mBufferId(0), mSize(0) {}
- HeapBase(uint32_t bufferId, size_t size) :
- mBufferId(bufferId), mSize(size) {}
-
- uint32_t getBufferId() const {return mBufferId;}
- size_t getSize() const {return mSize;}
-
- private:
- uint32_t mBufferId;
- size_t mSize;
- };
-
- KeyedVector<int32_t, HeapBase> mHeapBases;
- uint32_t mNextBufferId;
- int32_t mHeapSeqNum;
-
- Vector<sp<ICryptoFactory>> makeCryptoFactories();
- sp<ICryptoPlugin> makeCryptoPlugin(const sp<ICryptoFactory>& factory,
- const uint8_t uuid[16], const void *initData, size_t size);
-
- int32_t setHeapBase(const sp<IMemoryHeap>& heap);
- void clearHeapBase(int32_t seqNum);
-
- status_t toSharedBuffer(const sp<IMemory>& memory, int32_t seqNum, ::SharedBuffer* buffer);
-
- DISALLOW_EVIL_CONSTRUCTORS(CryptoHal);
-};
-
-} // namespace android
-
-#endif // CRYPTO_HAL_H_
diff --git a/media/libmedia/include/media/DataSourceDesc.h b/media/libmedia/include/media/DataSourceDesc.h
deleted file mode 100644
index 4336767..0000000
--- a/media/libmedia/include/media/DataSourceDesc.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_DATASOURCEDESC_H
-#define ANDROID_DATASOURCEDESC_H
-
-#include <media/stagefright/foundation/ABase.h>
-#include <utils/RefBase.h>
-#include <utils/KeyedVector.h>
-#include <utils/String8.h>
-
-namespace android {
-
-class DataSource;
-struct MediaHTTPService;
-
-// A binder interface for implementing a stagefright DataSource remotely.
-struct DataSourceDesc : public RefBase {
-public:
- // intentionally less than INT64_MAX
- // keep consistent with JAVA code
- static const int64_t kMaxTimeMs = 0x7ffffffffffffffll / 1000;
- static const int64_t kMaxTimeUs = kMaxTimeMs * 1000;
-
- enum {
- /* No data source has been set yet */
- TYPE_NONE = 0,
- /* data source is type of MediaDataSource */
- TYPE_CALLBACK = 1,
- /* data source is type of FileDescriptor */
- TYPE_FD = 2,
- /* data source is type of Url */
- TYPE_URL = 3,
- };
-
- DataSourceDesc();
-
- int mType;
-
- sp<MediaHTTPService> mHttpService;
- String8 mUrl;
- KeyedVector<String8, String8> mHeaders;
-
- int mFD;
- int64_t mFDOffset;
- int64_t mFDLength;
-
- sp<DataSource> mCallbackSource;
-
- int64_t mId;
- int64_t mStartPositionMs;
- int64_t mEndPositionMs;
-
-private:
- DISALLOW_EVIL_CONSTRUCTORS(DataSourceDesc);
-};
-
-}; // namespace android
-
-#endif // ANDROID_DATASOURCEDESC_H
diff --git a/media/libmedia/include/media/DrmHal.h b/media/libmedia/include/media/DrmHal.h
deleted file mode 100644
index bdf1b30..0000000
--- a/media/libmedia/include/media/DrmHal.h
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef DRM_HAL_H_
-
-#define DRM_HAL_H_
-
-#include <android/hardware/drm/1.0/IDrmFactory.h>
-#include <android/hardware/drm/1.0/IDrmPlugin.h>
-#include <android/hardware/drm/1.1/IDrmFactory.h>
-#include <android/hardware/drm/1.1/IDrmPlugin.h>
-#include <android/hardware/drm/1.2/IDrmFactory.h>
-#include <android/hardware/drm/1.2/IDrmPlugin.h>
-#include <android/hardware/drm/1.2/IDrmPluginListener.h>
-
-#include <media/MediaAnalyticsItem.h>
-#include <mediadrm/DrmMetrics.h>
-#include <mediadrm/IDrm.h>
-#include <mediadrm/IDrmClient.h>
-#include <utils/threads.h>
-
-namespace drm = ::android::hardware::drm;
-using drm::V1_0::EventType;
-using drm::V1_0::IDrmFactory;
-using drm::V1_0::IDrmPlugin;
-using drm::V1_0::IDrmPluginListener;
-using drm::V1_1::SecurityLevel;
-using drm::V1_2::KeyStatus;
-using drm::V1_2::OfflineLicenseState;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-
-typedef drm::V1_2::IDrmPluginListener IDrmPluginListener_V1_2;
-typedef drm::V1_0::KeyStatus KeyStatus_V1_0;
-
-namespace android {
-
-struct DrmSessionClientInterface;
-
-inline bool operator==(const Vector<uint8_t> &l, const Vector<uint8_t> &r) {
- if (l.size() != r.size()) return false;
- return memcmp(l.array(), r.array(), l.size()) == 0;
-}
-
-struct DrmHal : public BnDrm,
- public IBinder::DeathRecipient,
- public IDrmPluginListener_V1_2 {
- DrmHal();
- virtual ~DrmHal();
-
- virtual status_t initCheck() const;
-
- virtual status_t isCryptoSchemeSupported(const uint8_t uuid[16],
- const String8& mimeType,
- DrmPlugin::SecurityLevel level,
- bool *isSupported);
-
- virtual status_t createPlugin(const uint8_t uuid[16],
- const String8 &appPackageName);
-
- virtual status_t destroyPlugin();
-
- virtual status_t openSession(DrmPlugin::SecurityLevel level,
- Vector<uint8_t> &sessionId);
-
- virtual status_t closeSession(Vector<uint8_t> const &sessionId);
-
- virtual status_t
- getKeyRequest(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &initData,
- String8 const &mimeType, DrmPlugin::KeyType keyType,
- KeyedVector<String8, String8> const &optionalParameters,
- Vector<uint8_t> &request, String8 &defaultUrl,
- DrmPlugin::KeyRequestType *keyRequestType);
-
- virtual status_t provideKeyResponse(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &response,
- Vector<uint8_t> &keySetId);
-
- virtual status_t removeKeys(Vector<uint8_t> const &keySetId);
-
- virtual status_t restoreKeys(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keySetId);
-
- virtual status_t queryKeyStatus(Vector<uint8_t> const &sessionId,
- KeyedVector<String8, String8> &infoMap) const;
-
- virtual status_t getProvisionRequest(String8 const &certType,
- String8 const &certAuthority,
- Vector<uint8_t> &request,
- String8 &defaulUrl);
-
- virtual status_t provideProvisionResponse(Vector<uint8_t> const &response,
- Vector<uint8_t> &certificate,
- Vector<uint8_t> &wrappedKey);
-
- virtual status_t getSecureStops(List<Vector<uint8_t>> &secureStops);
- virtual status_t getSecureStopIds(List<Vector<uint8_t>> &secureStopIds);
- virtual status_t getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop);
-
- virtual status_t releaseSecureStops(Vector<uint8_t> const &ssRelease);
- virtual status_t removeSecureStop(Vector<uint8_t> const &ssid);
- virtual status_t removeAllSecureStops();
-
- virtual status_t getHdcpLevels(DrmPlugin::HdcpLevel *connectedLevel,
- DrmPlugin::HdcpLevel *maxLevel) const;
- virtual status_t getNumberOfSessions(uint32_t *currentSessions,
- uint32_t *maxSessions) const;
- virtual status_t getSecurityLevel(Vector<uint8_t> const &sessionId,
- DrmPlugin::SecurityLevel *level) const;
-
- virtual status_t getOfflineLicenseKeySetIds(List<Vector<uint8_t>> &keySetIds) const;
- virtual status_t removeOfflineLicense(Vector<uint8_t> const &keySetId);
- virtual status_t getOfflineLicenseState(Vector<uint8_t> const &keySetId,
- DrmPlugin::OfflineLicenseState *licenseState) const;
-
- virtual status_t getPropertyString(String8 const &name, String8 &value ) const;
- virtual status_t getPropertyByteArray(String8 const &name,
- Vector<uint8_t> &value ) const;
- virtual status_t setPropertyString(String8 const &name, String8 const &value ) const;
- virtual status_t setPropertyByteArray(String8 const &name,
- Vector<uint8_t> const &value ) const;
- virtual status_t getMetrics(os::PersistableBundle *metrics);
-
- virtual status_t setCipherAlgorithm(Vector<uint8_t> const &sessionId,
- String8 const &algorithm);
-
- virtual status_t setMacAlgorithm(Vector<uint8_t> const &sessionId,
- String8 const &algorithm);
-
- virtual status_t encrypt(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId,
- Vector<uint8_t> const &input,
- Vector<uint8_t> const &iv,
- Vector<uint8_t> &output);
-
- virtual status_t decrypt(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId,
- Vector<uint8_t> const &input,
- Vector<uint8_t> const &iv,
- Vector<uint8_t> &output);
-
- virtual status_t sign(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId,
- Vector<uint8_t> const &message,
- Vector<uint8_t> &signature);
-
- virtual status_t verify(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId,
- Vector<uint8_t> const &message,
- Vector<uint8_t> const &signature,
- bool &match);
-
- virtual status_t signRSA(Vector<uint8_t> const &sessionId,
- String8 const &algorithm,
- Vector<uint8_t> const &message,
- Vector<uint8_t> const &wrappedKey,
- Vector<uint8_t> &signature);
-
- virtual status_t setListener(const sp<IDrmClient>& listener);
-
- // Methods of IDrmPluginListener
- Return<void> sendEvent(EventType eventType,
- const hidl_vec<uint8_t>& sessionId, const hidl_vec<uint8_t>& data);
-
- Return<void> sendExpirationUpdate(const hidl_vec<uint8_t>& sessionId,
- int64_t expiryTimeInMS);
-
- Return<void> sendKeysChange(const hidl_vec<uint8_t>& sessionId,
- const hidl_vec<KeyStatus_V1_0>& keyStatusList, bool hasNewUsableKey);
-
- Return<void> sendKeysChange_1_2(const hidl_vec<uint8_t>& sessionId,
- const hidl_vec<KeyStatus>& keyStatusList, bool hasNewUsableKey);
-
- Return<void> sendSessionLostState(const hidl_vec<uint8_t>& sessionId);
-
- virtual void binderDied(const wp<IBinder> &the_late_who);
-
-private:
- static Mutex mLock;
-
- sp<DrmSessionClientInterface> mDrmSessionClient;
-
- sp<IDrmClient> mListener;
- mutable Mutex mEventLock;
- mutable Mutex mNotifyLock;
-
- const Vector<sp<IDrmFactory>> mFactories;
- sp<IDrmPlugin> mPlugin;
- sp<drm::V1_1::IDrmPlugin> mPluginV1_1;
- sp<drm::V1_2::IDrmPlugin> mPluginV1_2;
- String8 mAppPackageName;
-
- // Mutable to allow modification within GetPropertyByteArray.
- mutable MediaDrmMetrics mMetrics;
-
- Vector<Vector<uint8_t>> mOpenSessions;
- void closeOpenSessions();
- void cleanup();
-
- /**
- * mInitCheck is:
- * NO_INIT if a plugin hasn't been created yet
- * ERROR_UNSUPPORTED if a plugin can't be created for the uuid
- * OK after a plugin has been created and mPlugin is valid
- */
- status_t mInitCheck;
-
- Vector<sp<IDrmFactory>> makeDrmFactories();
- sp<IDrmPlugin> makeDrmPlugin(const sp<IDrmFactory>& factory,
- const uint8_t uuid[16], const String8& appPackageName);
-
- void writeByteArray(Parcel &obj, const hidl_vec<uint8_t>& array);
-
- void reportPluginMetrics() const;
- void reportFrameworkMetrics() const;
- status_t getPropertyStringInternal(String8 const &name, String8 &value) const;
- status_t getPropertyByteArrayInternal(String8 const &name,
- Vector<uint8_t> &value) const;
- status_t matchMimeTypeAndSecurityLevel(const sp<IDrmFactory> &factory,
- const uint8_t uuid[16],
- const String8 &mimeType,
- DrmPlugin::SecurityLevel level,
- bool *isSupported);
-
- DISALLOW_EVIL_CONSTRUCTORS(DrmHal);
-};
-
-} // namespace android
-
-#endif // DRM_HAL_H_
diff --git a/media/libmedia/include/media/DrmMetrics.h b/media/libmedia/include/media/DrmMetrics.h
deleted file mode 100644
index 6f132bf..0000000
--- a/media/libmedia/include/media/DrmMetrics.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef DRM_METRICS_H_
-#define DRM_METRICS_H_
-
-#include <map>
-
-#include <android/hardware/drm/1.0/types.h>
-#include <android/hardware/drm/1.1/types.h>
-#include <android/hardware/drm/1.2/types.h>
-#include <binder/PersistableBundle.h>
-#include <media/CounterMetric.h>
-#include <media/EventMetric.h>
-
-namespace android {
-
-/**
- * This class contains the definition of metrics captured within MediaDrm.
- * It also contains a method for exporting all of the metrics to a
- * PersistableBundle.
- */
-class MediaDrmMetrics {
- public:
- explicit MediaDrmMetrics();
- virtual ~MediaDrmMetrics() {};
- // Count of openSession calls.
- CounterMetric<status_t> mOpenSessionCounter;
- // Count of closeSession calls.
- CounterMetric<status_t> mCloseSessionCounter;
- // Count and timing of getKeyRequest calls.
- EventMetric<status_t> mGetKeyRequestTimeUs;
- // Count and timing of provideKeyResponse calls.
- EventMetric<status_t> mProvideKeyResponseTimeUs;
- // Count of getProvisionRequest calls.
- CounterMetric<status_t> mGetProvisionRequestCounter;
- // Count of provideProvisionResponse calls.
- CounterMetric<status_t> mProvideProvisionResponseCounter;
-
- // Count of key status events broken out by status type.
- CounterMetric<::android::hardware::drm::V1_2::KeyStatusType>
- mKeyStatusChangeCounter;
- // Count of events broken out by event type
- CounterMetric<::android::hardware::drm::V1_0::EventType> mEventCounter;
-
- // Count getPropertyByteArray calls to retrieve the device unique id.
- CounterMetric<status_t> mGetDeviceUniqueIdCounter;
-
- // Adds a session start time record.
- void SetSessionStart(const Vector<uint8_t>& sessionId);
-
- // Adds a session end time record.
- void SetSessionEnd(const Vector<uint8_t>& sessionId);
-
- // The app package name is the application package name that is using the
- // instance. The app package name is held here for convenience. It is not
- // serialized or exported with the metrics.
- void SetAppPackageName(const String8& appPackageName) { mAppPackageName = appPackageName; }
- const String8& GetAppPackageName() { return mAppPackageName; }
-
- // Export the metrics to a PersistableBundle.
- void Export(os::PersistableBundle* metricsBundle);
-
- // Get the serialized metrics. Metrics are formatted as a serialized
- // DrmFrameworkMetrics proto. If there is a failure serializing the metrics,
- // this returns an error. The parameter |serlializedMetrics| is owned by the
- // caller and must not be null.
- status_t GetSerializedMetrics(std::string* serializedMetrics);
-
- // Converts the DRM plugin metrics to a PersistableBundle. All of the metrics
- // found in |pluginMetrics| are added to the |metricsBundle| parameter.
- // |pluginBundle| is owned by the caller and must not be null.
- //
- // Each item in the pluginMetrics vector is added as a new PersistableBundle. E.g.
- // DrmMetricGroup {
- // metrics[0] {
- // name: "buf_copy"
- // attributes[0] {
- // name: "size"
- // type: INT64_TYPE
- // int64Value: 1024
- // }
- // values[0] {
- // componentName: "operation_count"
- // type: INT64_TYPE
- // int64Value: 75
- // }
- // values[1] {
- // component_name: "average_time_seconds"
- // type: DOUBLE_TYPE
- // doubleValue: 0.00000042
- // }
- // }
- // }
- //
- // becomes
- //
- // metricsBundle {
- // "0": (PersistableBundle) {
- // "attributes" : (PersistableBundle) {
- // "size" : (int64) 1024
- // }
- // "operation_count" : (int64) 75
- // "average_time_seconds" : (double) 0.00000042
- // }
- //
- static status_t HidlMetricsToBundle(
- const hardware::hidl_vec<hardware::drm::V1_1::DrmMetricGroup>& pluginMetrics,
- os::PersistableBundle* metricsBundle);
-
- protected:
- // This is visible for testing only.
- virtual int64_t GetCurrentTimeMs();
-
- private:
- // Session lifetimes. A pair of values representing the milliseconds since
- // epoch, UTC. The first value is the start time, the second is the end time.
- std::map<std::string, std::pair<int64_t, int64_t>> mSessionLifespans;
-
- String8 mAppPackageName;
-};
-
-} // namespace android
-
-#endif // DRM_METRICS_H_
diff --git a/media/libmedia/include/media/DrmSessionManager.h b/media/libmedia/include/media/DrmSessionManager.h
deleted file mode 100644
index ba27199..0000000
--- a/media/libmedia/include/media/DrmSessionManager.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef DRM_SESSION_MANAGER_H_
-
-#define DRM_SESSION_MANAGER_H_
-
-#include <media/stagefright/foundation/ABase.h>
-#include <utils/RefBase.h>
-#include <utils/KeyedVector.h>
-#include <utils/threads.h>
-#include <utils/Vector.h>
-
-namespace android {
-
-class DrmSessionManagerTest;
-struct DrmSessionClientInterface;
-struct ProcessInfoInterface;
-
-bool isEqualSessionId(const Vector<uint8_t> &sessionId1, const Vector<uint8_t> &sessionId2);
-
-struct SessionInfo {
- sp<DrmSessionClientInterface> drm;
- Vector<uint8_t> sessionId;
- int64_t timeStamp;
-};
-
-typedef Vector<SessionInfo > SessionInfos;
-typedef KeyedVector<int, SessionInfos > PidSessionInfosMap;
-
-struct DrmSessionManager : public RefBase {
- static sp<DrmSessionManager> Instance();
-
- DrmSessionManager();
- explicit DrmSessionManager(sp<ProcessInfoInterface> processInfo);
-
- void addSession(int pid, const sp<DrmSessionClientInterface>& drm, const Vector<uint8_t>& sessionId);
- void useSession(const Vector<uint8_t>& sessionId);
- void removeSession(const Vector<uint8_t>& sessionId);
- void removeDrm(const sp<DrmSessionClientInterface>& drm);
- bool reclaimSession(int callingPid);
-
-protected:
- virtual ~DrmSessionManager();
-
-private:
- friend class DrmSessionManagerTest;
-
- int64_t getTime_l();
- bool getLowestPriority_l(int* lowestPriorityPid, int* lowestPriority);
- bool getLeastUsedSession_l(
- int pid, sp<DrmSessionClientInterface>* drm, Vector<uint8_t>* sessionId);
-
- sp<ProcessInfoInterface> mProcessInfo;
- mutable Mutex mLock;
- PidSessionInfosMap mSessionMap;
- int64_t mTime;
-
- DISALLOW_EVIL_CONSTRUCTORS(DrmSessionManager);
-};
-
-} // namespace android
-
-#endif // DRM_SESSION_MANAGER_H_
diff --git a/media/libmedia/include/media/EventMetric.h b/media/libmedia/include/media/EventMetric.h
index dbb736a..d6f3402 100644
--- a/media/libmedia/include/media/EventMetric.h
+++ b/media/libmedia/include/media/EventMetric.h
@@ -16,7 +16,7 @@
#ifndef ANDROID_EVENT_METRIC_H_
#define ANDROID_EVENT_METRIC_H_
-#include <media/MediaAnalyticsItem.h>
+#include <media/MediaMetricsItem.h>
#include <utils/Timers.h>
namespace android {
diff --git a/media/libmedia/include/media/ICrypto.h b/media/libmedia/include/media/ICrypto.h
deleted file mode 100644
index 6d896b8..0000000
--- a/media/libmedia/include/media/ICrypto.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <binder/IInterface.h>
-#include <cutils/native_handle.h>
-#include <media/hardware/CryptoAPI.h>
-#include <media/stagefright/foundation/ABase.h>
-
-#ifndef ANDROID_ICRYPTO_H_
-
-#define ANDROID_ICRYPTO_H_
-
-namespace android {
-
-struct AString;
-class IMemory;
-class IMemoryHeap;
-
-struct ICrypto : public IInterface {
- DECLARE_META_INTERFACE(Crypto);
-
- virtual status_t initCheck() const = 0;
-
- virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) = 0;
-
- virtual status_t createPlugin(
- const uint8_t uuid[16], const void *data, size_t size) = 0;
-
- virtual status_t destroyPlugin() = 0;
-
- virtual bool requiresSecureDecoderComponent(
- const char *mime) const = 0;
-
- virtual void notifyResolution(uint32_t width, uint32_t height) = 0;
-
- virtual status_t setMediaDrmSession(const Vector<uint8_t> &sessionId) = 0;
-
- struct SourceBuffer {
- sp<IMemory> mSharedMemory;
- int32_t mHeapSeqNum;
- };
-
- enum DestinationType {
- kDestinationTypeSharedMemory, // non-secure
- kDestinationTypeNativeHandle // secure
- };
-
- struct DestinationBuffer {
- DestinationType mType;
- native_handle_t *mHandle;
- sp<IMemory> mSharedMemory;
- };
-
- virtual ssize_t decrypt(const uint8_t key[16], const uint8_t iv[16],
- CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
- const SourceBuffer &source, size_t offset,
- const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
- const DestinationBuffer &destination, AString *errorDetailMsg) = 0;
-
- /**
- * Declare the heap that the shared memory source buffers passed
- * to decrypt will be allocated from. Returns a sequence number
- * that subsequent decrypt calls can use to refer to the heap,
- * with -1 indicating failure.
- */
- virtual int32_t setHeap(const sp<IMemoryHeap>& heap) = 0;
- virtual void unsetHeap(int32_t seqNum) = 0;
-
-private:
- DISALLOW_EVIL_CONSTRUCTORS(ICrypto);
-};
-
-struct BnCrypto : public BnInterface<ICrypto> {
- virtual status_t onTransact(
- uint32_t code, const Parcel &data, Parcel *reply,
- uint32_t flags = 0);
-private:
- void readVector(const Parcel &data, Vector<uint8_t> &vector) const;
- void writeVector(Parcel *reply, Vector<uint8_t> const &vector) const;
-};
-
-} // namespace android
-
-#endif // ANDROID_ICRYPTO_H_
diff --git a/media/libmedia/include/media/IDataSource.h b/media/libmedia/include/media/IDataSource.h
deleted file mode 100644
index 3858f78..0000000
--- a/media/libmedia/include/media/IDataSource.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_IDATASOURCE_H
-#define ANDROID_IDATASOURCE_H
-
-#include <binder/IInterface.h>
-#include <media/stagefright/foundation/ABase.h>
-#include <utils/Errors.h>
-#include <utils/String8.h>
-
-namespace android {
-
-class IMemory;
-class DecryptHandle;
-
-// A binder interface for implementing a stagefright DataSource remotely.
-class IDataSource : public IInterface {
-public:
- DECLARE_META_INTERFACE(DataSource);
-
- // Get the memory that readAt writes into.
- virtual sp<IMemory> getIMemory() = 0;
- // Read up to |size| bytes into the memory returned by getIMemory(). Returns
- // the number of bytes read, or negative value on error (eg.
- // ERROR_END_OF_STREAM indicating EOS. This is needed by CallbackDataSource
- // to properly handle reading of last chunk). |size| must not be larger than
- // the buffer.
- virtual ssize_t readAt(off64_t offset, size_t size) = 0;
- // Get the size, or -1 if the size is unknown.
- virtual status_t getSize(off64_t* size) = 0;
- // This should be called before deleting |this|. The other methods may
- // return errors if they're called after calling close().
- virtual void close() = 0;
- // Get the flags of the source.
- // Refer to DataSource:Flags for the definition of the flags.
- virtual uint32_t getFlags() = 0;
- // get a description of the source, e.g. the url or filename it is based on
- virtual String8 toString() = 0;
- // Initialize DRM and return a DecryptHandle.
- virtual sp<DecryptHandle> DrmInitialization(const char *mime) = 0;
-
-private:
- DISALLOW_EVIL_CONSTRUCTORS(IDataSource);
-};
-
-// ----------------------------------------------------------------------------
-
-class BnDataSource : public BnInterface<IDataSource> {
-public:
- virtual status_t onTransact(uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-};
-
-}; // namespace android
-
-#endif // ANDROID_IDATASOURCE_H
diff --git a/media/libmedia/include/media/IDrm.h b/media/libmedia/include/media/IDrm.h
deleted file mode 100644
index fbe80c6..0000000
--- a/media/libmedia/include/media/IDrm.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <binder/IInterface.h>
-#include <binder/PersistableBundle.h>
-#include <media/stagefright/foundation/ABase.h>
-#include <media/drm/DrmAPI.h>
-#include <media/MediaAnalyticsItem.h>
-#include <mediadrm/IDrmClient.h>
-
-#ifndef ANDROID_IDRM_H_
-
-#define ANDROID_IDRM_H_
-
-namespace android {
-
-struct AString;
-
-struct IDrm : public IInterface {
- DECLARE_META_INTERFACE(Drm);
-
- virtual status_t initCheck() const = 0;
-
- virtual status_t isCryptoSchemeSupported(const uint8_t uuid[16],
- const String8 &mimeType,
- DrmPlugin::SecurityLevel securityLevel,
- bool *result) = 0;
-
- virtual status_t createPlugin(const uint8_t uuid[16],
- const String8 &appPackageName) = 0;
-
- virtual status_t destroyPlugin() = 0;
-
- virtual status_t openSession(DrmPlugin::SecurityLevel securityLevel,
- Vector<uint8_t> &sessionId) = 0;
-
- virtual status_t closeSession(Vector<uint8_t> const &sessionId) = 0;
-
- virtual status_t
- getKeyRequest(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &initData,
- String8 const &mimeType, DrmPlugin::KeyType keyType,
- KeyedVector<String8, String8> const &optionalParameters,
- Vector<uint8_t> &request, String8 &defaultUrl,
- DrmPlugin::KeyRequestType *keyRequestType) = 0;
-
- virtual status_t provideKeyResponse(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &response,
- Vector<uint8_t> &keySetId) = 0;
-
- virtual status_t removeKeys(Vector<uint8_t> const &keySetId) = 0;
-
- virtual status_t restoreKeys(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keySetId) = 0;
-
- virtual status_t queryKeyStatus(Vector<uint8_t> const &sessionId,
- KeyedVector<String8, String8> &infoMap) const = 0;
-
- virtual status_t getProvisionRequest(String8 const &certType,
- String8 const &certAuthority,
- Vector<uint8_t> &request,
- String8 &defaulUrl) = 0;
-
- virtual status_t provideProvisionResponse(Vector<uint8_t> const &response,
- Vector<uint8_t> &certificate,
- Vector<uint8_t> &wrappedKey) = 0;
-
- virtual status_t getSecureStops(List<Vector<uint8_t>> &secureStops) = 0;
- virtual status_t getSecureStopIds(List<Vector<uint8_t>> &secureStopIds) = 0;
- virtual status_t getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop) = 0;
-
- virtual status_t releaseSecureStops(Vector<uint8_t> const &ssRelease) = 0;
- virtual status_t removeSecureStop(Vector<uint8_t> const &ssid) = 0;
- virtual status_t removeAllSecureStops() = 0;
-
- virtual status_t getHdcpLevels(DrmPlugin::HdcpLevel *connectedLevel,
- DrmPlugin::HdcpLevel *maxLevel)
- const = 0;
- virtual status_t getNumberOfSessions(uint32_t *currentSessions,
- uint32_t *maxSessions) const = 0;
- virtual status_t getSecurityLevel(Vector<uint8_t> const &sessionId,
- DrmPlugin::SecurityLevel *level) const = 0;
-
- virtual status_t getOfflineLicenseKeySetIds(List<Vector<uint8_t>> &keySetIds) const = 0;
- virtual status_t removeOfflineLicense(Vector<uint8_t> const &keySetId) = 0;
- virtual status_t getOfflineLicenseState(Vector<uint8_t> const &keySetId,
- DrmPlugin::OfflineLicenseState *licenseState) const = 0;
-
- virtual status_t getPropertyString(String8 const &name, String8 &value) const = 0;
- virtual status_t getPropertyByteArray(String8 const &name,
- Vector<uint8_t> &value) const = 0;
- virtual status_t setPropertyString(String8 const &name,
- String8 const &value ) const = 0;
- virtual status_t setPropertyByteArray(String8 const &name,
- Vector<uint8_t> const &value) const = 0;
-
- virtual status_t getMetrics(os::PersistableBundle *metrics) = 0;
-
- virtual status_t setCipherAlgorithm(Vector<uint8_t> const &sessionId,
- String8 const &algorithm) = 0;
-
- virtual status_t setMacAlgorithm(Vector<uint8_t> const &sessionId,
- String8 const &algorithm) = 0;
-
- virtual status_t encrypt(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId,
- Vector<uint8_t> const &input,
- Vector<uint8_t> const &iv,
- Vector<uint8_t> &output) = 0;
-
- virtual status_t decrypt(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId,
- Vector<uint8_t> const &input,
- Vector<uint8_t> const &iv,
- Vector<uint8_t> &output) = 0;
-
- virtual status_t sign(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId,
- Vector<uint8_t> const &message,
- Vector<uint8_t> &signature) = 0;
-
- virtual status_t verify(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId,
- Vector<uint8_t> const &message,
- Vector<uint8_t> const &signature,
- bool &match) = 0;
-
- virtual status_t signRSA(Vector<uint8_t> const &sessionId,
- String8 const &algorithm,
- Vector<uint8_t> const &message,
- Vector<uint8_t> const &wrappedKey,
- Vector<uint8_t> &signature) = 0;
-
- virtual status_t setListener(const sp<IDrmClient>& listener) = 0;
-
-private:
- DISALLOW_EVIL_CONSTRUCTORS(IDrm);
-};
-
-struct BnDrm : public BnInterface<IDrm> {
- virtual status_t onTransact(
- uint32_t code, const Parcel &data, Parcel *reply,
- uint32_t flags = 0);
-private:
- void readVector(const Parcel &data, Vector<uint8_t> &vector) const;
- void writeVector(Parcel *reply, Vector<uint8_t> const &vector) const;
-};
-
-} // namespace android
-
-#endif // ANDROID_IDRM_H_
diff --git a/media/libmedia/include/media/IDrmClient.h b/media/libmedia/include/media/IDrmClient.h
deleted file mode 100644
index 3b2fc7c..0000000
--- a/media/libmedia/include/media/IDrmClient.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_IDRMCLIENT_H
-#define ANDROID_IDRMCLIENT_H
-
-#include <utils/RefBase.h>
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-#include <media/drm/DrmAPI.h>
-
-namespace android {
-
-class IDrmClient: public IInterface
-{
-public:
- DECLARE_META_INTERFACE(DrmClient);
-
- virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) = 0;
-};
-
-// ----------------------------------------------------------------------------
-
-class BnDrmClient: public BnInterface<IDrmClient>
-{
-public:
- virtual status_t onTransact(uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-};
-
-}; // namespace android
-
-#endif // ANDROID_IDRMCLIENT_H
diff --git a/media/libmedia/include/media/IMediaDrmService.h b/media/libmedia/include/media/IMediaDrmService.h
deleted file mode 100644
index 323fae5..0000000
--- a/media/libmedia/include/media/IMediaDrmService.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_IMEDIADRMSERVICE_H
-#define ANDROID_IMEDIADRMSERVICE_H
-
-#include <utils/Errors.h> // for status_t
-#include <utils/RefBase.h>
-#include <utils/String8.h>
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-
-namespace android {
-
-struct ICrypto;
-struct IDrm;
-
-class IMediaDrmService: public IInterface
-{
-public:
- DECLARE_META_INTERFACE(MediaDrmService);
-
- virtual sp<ICrypto> makeCrypto() = 0;
- virtual sp<IDrm> makeDrm() = 0;
-};
-
-// ----------------------------------------------------------------------------
-
-class BnMediaDrmService: public BnInterface<IMediaDrmService>
-{
-public:
- virtual status_t onTransact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-};
-
-}; // namespace android
-
-#endif // ANDROID_IMEDIADRMSERVICE_H
diff --git a/media/libmedia/include/media/IMediaExtractor.h b/media/libmedia/include/media/IMediaExtractor.h
deleted file mode 100644
index 75e4ee2..0000000
--- a/media/libmedia/include/media/IMediaExtractor.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef IMEDIA_EXTRACTOR_BASE_H_
-
-#define IMEDIA_EXTRACTOR_BASE_H_
-
-#include <media/DataSource.h>
-#include <media/IMediaSource.h>
-#include <vector>
-
-namespace android {
-
-class MetaData;
-typedef std::vector<uint8_t> HInterfaceToken;
-
-class IMediaExtractor : public IInterface {
-public:
- DECLARE_META_INTERFACE(MediaExtractor);
-
- virtual size_t countTracks() = 0;
- // This function could return NULL IMediaSource even when index is within the
- // track count returned by countTracks, since it's possible the track is malformed
- // and it's not detected during countTracks call.
- virtual sp<IMediaSource> getTrack(size_t index) = 0;
-
- enum GetTrackMetaDataFlags {
- kIncludeExtensiveMetaData = 1
- };
- virtual sp<MetaData> getTrackMetaData(
- size_t index, uint32_t flags = 0) = 0;
-
- // Return container specific meta-data. The default implementation
- // returns an empty metadata object.
- virtual sp<MetaData> getMetaData() = 0;
-
- virtual status_t getMetrics(Parcel *reply) = 0;
-
- enum Flags {
- CAN_SEEK_BACKWARD = 1, // the "seek 10secs back button"
- CAN_SEEK_FORWARD = 2, // the "seek 10secs forward button"
- CAN_PAUSE = 4,
- CAN_SEEK = 8, // the "seek bar"
- };
-
- // If subclasses do _not_ override this, the default is
- // CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE
- virtual uint32_t flags() const = 0;
-
- virtual status_t setMediaCas(const HInterfaceToken &casToken) = 0;
-
- virtual const char * name() = 0;
-};
-
-
-class BnMediaExtractor: public BnInterface<IMediaExtractor>
-{
-public:
- virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
- uint32_t flags = 0);
-};
-
-void registerMediaExtractor(
- const sp<IMediaExtractor> &extractor,
- const sp<DataSource> &source,
- const char *mime);
-
-void registerMediaSource(
- const sp<IMediaExtractor> &extractor,
- const sp<IMediaSource> &source);
-
-status_t dumpExtractors(int fd, const Vector<String16>& args);
-
-
-} // namespace android
-
-#endif // IMEDIA_EXTRACTOR_BASE_H_
diff --git a/media/libmedia/include/media/IMediaExtractorService.h b/media/libmedia/include/media/IMediaExtractorService.h
deleted file mode 100644
index 5ce2cdb..0000000
--- a/media/libmedia/include/media/IMediaExtractorService.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_IMEDIAEXTRACTORSERVICE_H
-#define ANDROID_IMEDIAEXTRACTORSERVICE_H
-
-#include <unordered_set>
-
-#include <binder/IInterface.h>
-#include <binder/IMemory.h>
-#include <binder/Parcel.h>
-#include <media/IDataSource.h>
-#include <media/IMediaExtractor.h>
-
-namespace android {
-
-class IMediaExtractorService: public IInterface
-{
-public:
- DECLARE_META_INTERFACE(MediaExtractorService);
-
- virtual sp<IMediaExtractor> makeExtractor(const sp<IDataSource> &source, const char *mime) = 0;
-
- virtual sp<IDataSource> makeIDataSource(int fd, int64_t offset, int64_t length) = 0;
-
- virtual std::unordered_set<std::string> getSupportedTypes() = 0;
-};
-
-class BnMediaExtractorService: public BnInterface<IMediaExtractorService>
-{
-public:
- virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
- uint32_t flags = 0);
-};
-
-} // namespace android
-
-#endif // ANDROID_IMEDIAEXTRACTORSERVICE_H
diff --git a/media/libmedia/include/media/IMediaMetadataRetriever.h b/media/libmedia/include/media/IMediaMetadataRetriever.h
index c6f422d..28d2192 100644
--- a/media/libmedia/include/media/IMediaMetadataRetriever.h
+++ b/media/libmedia/include/media/IMediaMetadataRetriever.h
@@ -48,9 +48,8 @@
int index, int colorFormat, bool metaOnly, bool thumbnail) = 0;
virtual sp<IMemory> getImageRectAtIndex(
int index, int colorFormat, int left, int top, int right, int bottom) = 0;
- virtual status_t getFrameAtIndex(
- std::vector<sp<IMemory> > *frames,
- int frameIndex, int numFrames, int colorFormat, bool metaOnly) = 0;
+ virtual sp<IMemory> getFrameAtIndex(
+ int index, int colorFormat, bool metaOnly) = 0;
virtual sp<IMemory> extractAlbumArt() = 0;
virtual const char* extractMetadata(int keyCode) = 0;
};
diff --git a/media/libmedia/include/media/IMediaPlayer.h b/media/libmedia/include/media/IMediaPlayer.h
index 97a998e..a4c0ec6 100644
--- a/media/libmedia/include/media/IMediaPlayer.h
+++ b/media/libmedia/include/media/IMediaPlayer.h
@@ -23,7 +23,8 @@
#include <utils/KeyedVector.h>
#include <system/audio.h>
-#include <media/MediaSource.h>
+#include <media/AudioResamplerPublic.h>
+#include <media/stagefright/MediaSource.h>
#include <media/VolumeShaper.h>
// Fwd decl to make sure everyone agrees that the scope of struct sockaddr_in is
@@ -38,7 +39,6 @@
struct IStreamSource;
class IGraphicBufferProducer;
struct IMediaHTTPService;
-struct AudioPlaybackRate;
struct AVSyncSettings;
struct BufferingSettings;
diff --git a/media/libmedia/include/media/IMediaRecorder.h b/media/libmedia/include/media/IMediaRecorder.h
index f9c557c..651bd5e 100644
--- a/media/libmedia/include/media/IMediaRecorder.h
+++ b/media/libmedia/include/media/IMediaRecorder.h
@@ -44,6 +44,8 @@
virtual status_t setPreviewSurface(const sp<IGraphicBufferProducer>& surface) = 0;
virtual status_t setVideoSource(int vs) = 0;
virtual status_t setAudioSource(int as) = 0;
+ virtual status_t setPrivacySensitive(bool privacySensitive) = 0;
+ virtual status_t isPrivacySensitive(bool *privacySensitive) const = 0;
virtual status_t setOutputFormat(int of) = 0;
virtual status_t setVideoEncoder(int ve) = 0;
virtual status_t setAudioEncoder(int ae) = 0;
diff --git a/media/libmedia/include/media/IMediaSource.h b/media/libmedia/include/media/IMediaSource.h
index 381df24..f3fa39b 100644
--- a/media/libmedia/include/media/IMediaSource.h
+++ b/media/libmedia/include/media/IMediaSource.h
@@ -22,7 +22,7 @@
#include <binder/IInterface.h>
#include <binder/IMemory.h>
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaErrors.h>
diff --git a/media/libmedia/include/media/IOMX.h b/media/libmedia/include/media/IOMX.h
index 7e7c2d2..70c8a74 100644
--- a/media/libmedia/include/media/IOMX.h
+++ b/media/libmedia/include/media/IOMX.h
@@ -34,9 +34,17 @@
#include <media/openmax/OMX_VideoExt.h>
namespace android {
+namespace hardware {
+namespace media {
+namespace omx {
+namespace V1_0 {
+struct IGraphicBufferSource;
+} // namespace V1_0
+} // namespace omx
+} // namespace media
+} // namespace hardware
class IGraphicBufferProducer;
-class IGraphicBufferSource;
class IMemory;
class IOMXBufferSource;
class IOMXNode;
@@ -82,7 +90,7 @@
virtual status_t createInputSurface(
sp<IGraphicBufferProducer> *bufferProducer,
- sp<IGraphicBufferSource> *bufferSource) = 0;
+ sp<hardware::media::omx::V1_0::IGraphicBufferSource> *bufferSource) = 0;
};
class IOMXNode : public IInterface {
diff --git a/media/libmedia/include/media/IResourceManagerClient.h b/media/libmedia/include/media/IResourceManagerClient.h
deleted file mode 100644
index aa0cd88..0000000
--- a/media/libmedia/include/media/IResourceManagerClient.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_IRESOURCEMANAGERCLIENT_H
-#define ANDROID_IRESOURCEMANAGERCLIENT_H
-
-#include <utils/RefBase.h>
-#include <utils/String8.h>
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-
-namespace android {
-
-class IResourceManagerClient: public IInterface
-{
-public:
- DECLARE_META_INTERFACE(ResourceManagerClient);
-
- virtual bool reclaimResource() = 0;
- virtual String8 getName() = 0;
-};
-
-// ----------------------------------------------------------------------------
-
-class BnResourceManagerClient: public BnInterface<IResourceManagerClient>
-{
-public:
- virtual status_t onTransact(uint32_t code,
- const Parcel &data,
- Parcel *reply,
- uint32_t flags = 0);
-};
-
-}; // namespace android
-
-#endif // ANDROID_IRESOURCEMANAGERCLIENT_H
diff --git a/media/libmedia/include/media/IResourceManagerService.h b/media/libmedia/include/media/IResourceManagerService.h
deleted file mode 100644
index 8992f8b..0000000
--- a/media/libmedia/include/media/IResourceManagerService.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_IRESOURCEMANAGERSERVICE_H
-#define ANDROID_IRESOURCEMANAGERSERVICE_H
-
-#include <utils/Errors.h> // for status_t
-#include <utils/KeyedVector.h>
-#include <utils/RefBase.h>
-#include <utils/String8.h>
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-
-#include <media/IResourceManagerClient.h>
-#include <media/MediaResource.h>
-#include <media/MediaResourcePolicy.h>
-
-namespace android {
-
-class IResourceManagerService: public IInterface
-{
-public:
- DECLARE_META_INTERFACE(ResourceManagerService);
-
- virtual void config(const Vector<MediaResourcePolicy> &policies) = 0;
-
- virtual void addResource(
- int pid,
- int uid,
- int64_t clientId,
- const sp<IResourceManagerClient> client,
- const Vector<MediaResource> &resources) = 0;
-
- virtual void removeResource(int pid, int64_t clientId,
- const Vector<MediaResource> &resources) = 0;
-
- virtual void removeClient(int pid, int64_t clientId) = 0;
-
- virtual bool reclaimResource(
- int callingPid,
- const Vector<MediaResource> &resources) = 0;
-};
-
-// ----------------------------------------------------------------------------
-
-class BnResourceManagerService: public BnInterface<IResourceManagerService>
-{
-public:
- virtual status_t onTransact(uint32_t code,
- const Parcel &data,
- Parcel *reply,
- uint32_t flags = 0);
-};
-
-}; // namespace android
-
-#endif // ANDROID_IRESOURCEMANAGERSERVICE_H
diff --git a/media/libmedia/include/media/JetPlayer.h b/media/libmedia/include/media/JetPlayer.h
deleted file mode 100644
index bb569bc..0000000
--- a/media/libmedia/include/media/JetPlayer.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef JETPLAYER_H_
-#define JETPLAYER_H_
-
-#include <utils/threads.h>
-
-#include <libsonivox/jet.h>
-#include <libsonivox/eas_types.h>
-#include <media/AudioTrack.h>
-#include <media/MidiIoWrapper.h>
-
-
-namespace android {
-
-typedef void (*jetevent_callback)(int eventType, int val1, int val2, void *cookie);
-
-class JetPlayer {
-
-public:
-
- // to keep in sync with the JetPlayer class constants
- // defined in frameworks/base/media/java/android/media/JetPlayer.java
- static const int JET_EVENT = 1;
- static const int JET_USERID_UPDATE = 2;
- static const int JET_NUMQUEUEDSEGMENT_UPDATE = 3;
- static const int JET_PAUSE_UPDATE = 4;
-
- JetPlayer(void *javaJetPlayer,
- int maxTracks = 32,
- int trackBufferSize = 1200);
- ~JetPlayer();
- int init();
- int release();
-
- int loadFromFile(const char* url);
- int loadFromFD(const int fd, const long long offset, const long long length);
- int closeFile();
- int play();
- int pause();
- int queueSegment(int segmentNum, int libNum, int repeatCount, int transpose,
- EAS_U32 muteFlags, EAS_U8 userID);
- int setMuteFlags(EAS_U32 muteFlags, bool sync);
- int setMuteFlag(int trackNum, bool muteFlag, bool sync);
- int triggerClip(int clipId);
- int clearQueue();
-
- void setEventCallback(jetevent_callback callback);
-
- int getMaxTracks() { return mMaxTracks; };
-
-
-private:
- int render();
- void fireUpdateOnStatusChange();
- void fireEventsFromJetQueue();
-
- JetPlayer() {} // no default constructor
- void dump();
- void dumpJetStatus(S_JET_STATUS* pJetStatus);
-
- jetevent_callback mEventCallback;
-
- void* mJavaJetPlayerRef;
- Mutex mMutex; // mutex to sync the render and playback thread with the JET calls
- pid_t mTid;
- Condition mCondition;
- volatile bool mRender;
- bool mPaused;
-
- EAS_STATE mState;
- int* mMemFailedVar;
-
- int mMaxTracks; // max number of MIDI tracks, usually 32
- EAS_DATA_HANDLE mEasData;
- MidiIoWrapper* mIoWrapper;
- EAS_PCM* mAudioBuffer;// EAS renders the MIDI data into this buffer,
- sp<AudioTrack> mAudioTrack; // and we play it in this audio track
- int mTrackBufferSize;
- S_JET_STATUS mJetStatus;
- S_JET_STATUS mPreviousJetStatus;
-
- class JetPlayerThread : public Thread {
- public:
- JetPlayerThread(JetPlayer *player) : mPlayer(player) {
- }
-
- protected:
- virtual ~JetPlayerThread() {}
-
- private:
- JetPlayer *mPlayer;
-
- bool threadLoop() {
- int result;
- result = mPlayer->render();
- return false;
- }
-
- JetPlayerThread(const JetPlayerThread &);
- JetPlayerThread &operator=(const JetPlayerThread &);
- };
-
- sp<JetPlayerThread> mThread;
-
-}; // end class JetPlayer
-
-} // end namespace android
-
-
-
-#endif /*JETPLAYER_H_*/
diff --git a/media/libmedia/include/media/LinearMap.h b/media/libmedia/include/media/LinearMap.h
deleted file mode 100644
index 2220a0c..0000000
--- a/media/libmedia/include/media/LinearMap.h
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * Copyright 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_LINEAR_MAP_H
-#define ANDROID_LINEAR_MAP_H
-
-#include <stdint.h>
-
-namespace android {
-
-/*
-A general purpose lookup utility that defines a mapping between X and Y as a
-continuous set of line segments with shared (x, y) end-points.
-The (x, y) points must be added in order, monotonically increasing in both x and y;
-a log warning is emitted if this does not happen (See general usage notes below).
-
-A limited history of (x, y) points is kept for space reasons (See general usage notes).
-
-In AudioFlinger, we use the LinearMap to associate track frames to
-sink frames. When we want to obtain a client track timestamp, we first
-get a timestamp from the sink. The sink timestamp's position (mPosition)
-corresponds to the sink frames written. We use LinearMap to figure out which track frame
-the sink frame corresponds to. This allows us to substitute a track frame for the
-the sink frame (keeping the mTime identical) and return that timestamp back to the client.
-
-The method findX() can be used to retrieve an x value from a given y value and is
-used for timestamps, similarly for findY() which is provided for completeness.
-
-We update the (track frame, sink frame) points in the LinearMap each time we write data
-to the sink by the AudioFlinger PlaybackThread (MixerThread).
-
-
-AudioFlinger Timestamp Notes:
-
-1) Example: Obtaining a track timestamp during playback. In this case, the LinearMap
-looks something like this:
-
-Track Frame Sink Frame
-(track start)
-0 50000 (track starts here, the sink may already be running)
-1000 51000
-2000 52000
-
-When we request a track timestamp, we call the sink getTimestamp() and get for example
-mPosition = 51020. Using the LinearMap, we find we have played to track frame 1020.
-We substitute the sink mPosition of 51020 with the track position 1020,
-and return that timestamp to the app.
-
-2) Example: Obtaining a track timestamp duing pause. In this case, the LinearMap
-looks something like this:
-
-Track Frame Sink Frame
-... (some time has gone by)
-15000 30000
-16000 31000
-17000 32000
-(pause here)
-(suppose we call sink getTimestamp() here and get sink mPosition = 31100; that means
- we have played to track frame 16100. The track timestamp mPosition will
- continue to advance until the sink timestamp returns a value of mPosition
- greater than 32000, corresponding to track frame 17000 when the pause was called).
-17000 33000
-17000 34000
-...
-
-3) If the track underruns, it appears as if a pause was called on that track.
-
-4) If there is an underrun in the HAL layer, then it may be possible that
-the sink getTimestamp() will return a value greater than the number of frames written
-(it should always be less). This should be rare, if not impossible by some
-HAL implementations of the sink getTimestamp. In that case, timing is lost
-and we will return the most recent track frame written.
-
-5) When called with no points in the map, findX() returns the start value (default 0).
-This is consistent with starting after a stop() or flush().
-
-6) Resuming after Track standby will be similar to coming out of pause, as the HAL ensures
-framesWritten() and getTimestamp() are contiguous for non-offloaded/direct tracks.
-
-7) LinearMap works for different speeds and sample rates as it uses
-linear interpolation. Since AudioFlinger only updates speed and sample rate
-exactly at the sample points pushed into the LinearMap, the returned values
-from findX() and findY() are accurate regardless of how many speed or sample
-rate changes are made, so long as the coordinate looked up is within the
-sample history.
-
-General usage notes:
-
-1) In order for the LinearMap to work reliably, you cannot look backwards more
-than the size of its circular buffer history, set upon creation (typically 16).
-If you look back further, the position is extrapolated either from a passed in
-extrapolation parameter or from the oldest line segment.
-
-2) Points must monotonically increase in x and y. The increment between adjacent
-points cannot be greater than signed 32 bits. Wrap in the x, y coordinates are supported,
-since we use differences in our computation.
-
-3) If the frame data is discontinuous (due to stop or flush) call reset() to clear
-the sample counter.
-
-4) If (x, y) are not strictly monotonic increasing, i.e. (x2 > x1) and (y2 > y1),
-then one or both of the inverses y = f(x) or x = g(y) may have multiple solutions.
-In that case, the most recent solution is returned by findX() or findY(). We
-do not warn if (x2 == x1) or (y2 == y1), but we do logcat warn if (x2 < x1) or
-(y2 < y1).
-
-5) Due to rounding it is possible x != findX(findY(x)) or y != findY(findX(y))
-even when the inverse exists. Nevertheless, the values should be close.
-
-*/
-
-template <typename T>
-class LinearMap {
-public:
- // This enumeration describes the reliability of the findX() or findY() estimation
- // in descending order.
- enum FindMethod {
- FIND_METHOD_INTERPOLATION, // High reliability (errors due to rounding)
- FIND_METHOD_FORWARD_EXTRAPOLATION, // Reliability based on no future speed changes
- FIND_METHOD_BACKWARD_EXTRAPOLATION, // Reliability based on prior estimated speed
- FIND_METHOD_START_VALUE, // No samples in history, using start value
- };
-
- explicit LinearMap(size_t size)
- : mSize(size),
- mPos(0), // a circular buffer, so could start anywhere. the first sample is at 1.
- mSamples(0),
- // mStepValid(false), // only valid if mSamples > 1
- // mExtrapolateTail(false), // only valid if mSamples > 0
- mX(new T[size]),
- mY(new T[size]) { }
-
- ~LinearMap() {
- delete[] mX;
- delete[] mY;
- }
-
- // Add a new sample point to the linear map.
- //
- // The difference between the new sample and the previous sample
- // in the x or y coordinate must be less than INT32_MAX for purposes
- // of the linear interpolation or extrapolation.
- //
- // The value should be monotonic increasing (e.g. diff >= 0);
- // logcat warnings are issued if they are not.
- __attribute__((no_sanitize("integer")))
- void push(T x, T y) {
- // Assumption: we assume x, y are monotonic increasing values,
- // which (can) wrap in precision no less than 32 bits and have
- // "step" or differences between adjacent points less than 32 bits.
-
- if (mSamples > 0) {
- const bool lastStepValid = mStepValid;
- int32_t xdiff;
- int32_t ydiff;
- // check difference assumption here
- mStepValid = checkedDiff(&xdiff, x, mX[mPos], "x")
- & /* bitwise AND to always warn for ydiff, though logical AND is also OK */
- checkedDiff(&ydiff, y, mY[mPos], "y");
-
- // Optimization: do not add a new sample if the line segment would
- // simply extend the previous line segment. This extends the useful
- // history by removing redundant points.
- if (mSamples > 1 && mStepValid && lastStepValid) {
- const size_t prev = previousPosition();
- const int32_t xdiff2 = x - mX[prev];
- const int32_t ydiff2 = y - mY[prev];
-
- // if both current step and previous step are valid (non-negative and
- // less than INT32_MAX for precision greater than 4 bytes)
- // then the sum of the two steps is valid when the
- // int32_t difference is non-negative.
- if (xdiff2 >= 0 && ydiff2 >= 0
- && (int64_t)xdiff2 * ydiff == (int64_t)ydiff2 * xdiff) {
- // ALOGD("reusing sample! (%u, %u) sample depth %zd", x, y, mSamples);
- mX[mPos] = x;
- mY[mPos] = y;
- return;
- }
- }
- }
- if (++mPos >= mSize) {
- mPos = 0;
- }
- if (mSamples < mSize) {
- mExtrapolateTail = false;
- ++mSamples;
- } else {
- // we enable extrapolation beyond the oldest sample
- // if the sample buffers are completely full and we
- // no longer know the full history.
- mExtrapolateTail = true;
- }
- mX[mPos] = x;
- mY[mPos] = y;
- }
-
- // clear all samples from the circular array
- void reset() {
- // no need to reset mPos, we use a circular buffer.
- // computed values such as mStepValid are set after a subsequent push().
- mSamples = 0;
- }
-
- // returns true if LinearMap contains at least one sample.
- bool hasData() const {
- return mSamples != 0;
- }
-
- // find the corresponding X point from a Y point.
- // See findU for details.
- __attribute__((no_sanitize("integer")))
- T findX(T y, FindMethod *method = NULL, double extrapolation = 0.0, T startValue = 0) const {
- return findU(y, mX, mY, method, extrapolation, startValue);
- }
-
- // find the corresponding Y point from a X point.
- // See findU for details.
- __attribute__((no_sanitize("integer")))
- T findY(T x, FindMethod *method = NULL, double extrapolation = 0.0, T startValue = 0) const {
- return findU(x, mY, mX, method, extrapolation, startValue);
- }
-
-protected:
-
- // returns false if the diff is out of int32_t bounds or negative.
- __attribute__((no_sanitize("integer")))
- static inline bool checkedDiff(int32_t *diff, T x2, T x1, const char *coord) {
- if (sizeof(T) >= 8) {
- const int64_t diff64 = x2 - x1;
- *diff = (int32_t)diff64; // intentionally lose precision
- if (diff64 > INT32_MAX) {
- ALOGW("LinearMap: %s overflow diff(%lld) from %llu - %llu exceeds INT32_MAX",
- coord, (long long)diff64,
- (unsigned long long)x2, (unsigned long long)x1);
- return false;
- } else if (diff64 < 0) {
- ALOGW("LinearMap: %s negative diff(%lld) from %llu - %llu",
- coord, (long long)diff64,
- (unsigned long long)x2, (unsigned long long)x1);
- return false;
- }
- return true;
- }
- // for 32 bit integers we cannot detect overflow (it
- // shows up as a negative difference).
- *diff = x2 - x1;
- if (*diff < 0) {
- ALOGW("LinearMap: %s negative diff(%d) from %u - %u",
- coord, *diff, (unsigned)x2, (unsigned)x1);
- return false;
- }
- return true;
- }
-
- // Returns the previous position in the mSamples array
- // going backwards back steps.
- //
- // Parameters:
- // back: number of backward steps, cannot be less than zero or greater than mSamples.
- //
- __attribute__((no_sanitize("integer")))
- size_t previousPosition(ssize_t back = 1) const {
- LOG_ALWAYS_FATAL_IF(back < 0 || (size_t)back > mSamples, "Invalid back(%zd)", back);
- ssize_t position = mPos - back;
- if (position < 0) position += mSize;
- return (size_t)position;
- }
-
- // A generic implementation of finding the "other coordinate" with coordinates
- // (u, v) = (x, y) or (u, v) = (y, x).
- //
- // Parameters:
- // uArray: the u axis samples.
- // vArray: the v axis samples.
- // method: [out] how the returned value was computed.
- // extrapolation: the slope used when extrapolating from the
- // first sample value or the last sample value in the history.
- // If mExtrapolateTail is set, the slope of the last line segment
- // is used if the extrapolation parameter is zero to continue the tail of history.
- // At this time, we do not use a different value for forward extrapolation from the
- // head of history from backward extrapolation from the tail of history.
- // TODO: back extrapolation value could be stored along with mX, mY in history.
- // startValue: used only when there are no samples in history. One can detect
- // whether there are samples in history by the method hasData().
- //
- __attribute__((no_sanitize("integer")))
- T findU(T v, T *uArray, T *vArray, FindMethod *method,
- double extrapolation, T startValue) const {
- if (mSamples == 0) {
- if (method != NULL) {
- *method = FIND_METHOD_START_VALUE;
- }
- return startValue; // nothing yet
- }
- ssize_t previous = 0;
- int32_t diff = 0;
- for (ssize_t i = 0; i < (ssize_t)mSamples; ++i) {
- size_t current = previousPosition(i);
-
- // Assumption: even though the type "T" may have precision greater
- // than 32 bits, the difference between adjacent points is limited to 32 bits.
- diff = v - vArray[current];
- if (diff >= 0 ||
- (i == (ssize_t)mSamples - 1 && mExtrapolateTail && extrapolation == 0.0)) {
- // ALOGD("depth = %zd out of %zd", i, limit);
- if (i == 0) {
- if (method != NULL) {
- *method = FIND_METHOD_FORWARD_EXTRAPOLATION;
- }
- return uArray[current] + diff * extrapolation;
- }
- // interpolate / extrapolate: For this computation, we
- // must use differentials here otherwise we have inconsistent
- // values on modulo wrap. previous is always valid here since
- // i > 0. we also perform rounding with the assumption
- // that uStep, vStep, and diff are non-negative.
- int32_t uStep = uArray[previous] - uArray[current]; // non-negative
- int32_t vStep = vArray[previous] - vArray[current]; // positive
- T u = uStep <= 0 || vStep <= 0 ? // we do not permit negative ustep or vstep
- uArray[current]
- : ((int64_t)diff * uStep + (vStep >> 1)) / vStep + uArray[current];
- // ALOGD("u:%u diff:%d uStep:%d vStep:%d u_current:%d",
- // u, diff, uStep, vStep, uArray[current]);
- if (method != NULL) {
- *method = (diff >= 0) ?
- FIND_METHOD_INTERPOLATION : FIND_METHOD_BACKWARD_EXTRAPOLATION;
- }
- return u;
- }
- previous = current;
- }
- // previous is always valid here.
- if (method != NULL) {
- *method = FIND_METHOD_BACKWARD_EXTRAPOLATION;
- }
- return uArray[previous] + diff * extrapolation;
- }
-
-private:
- const size_t mSize; // Size of mX and mY arrays (history).
- size_t mPos; // Index in mX and mY of last pushed data;
- // (incremented after push) [0, mSize - 1].
- size_t mSamples; // Number of valid samples in the array [0, mSize].
- bool mStepValid; // Last sample step was valid (non-negative)
- bool mExtrapolateTail; // extrapolate tail using oldest line segment
- T * const mX; // History of X values as a circular array.
- T * const mY; // History of Y values as a circular array.
-};
-
-} // namespace android
-
-#endif // ANDROID_LINEAR_MAP_H
diff --git a/media/libmedia/include/media/MediaCodecBuffer.h b/media/libmedia/include/media/MediaCodecBuffer.h
index 2c16fba..101377c 100644
--- a/media/libmedia/include/media/MediaCodecBuffer.h
+++ b/media/libmedia/include/media/MediaCodecBuffer.h
@@ -22,6 +22,8 @@
#include <utils/RefBase.h>
#include <utils/StrongPointer.h>
+class C2Buffer;
+
namespace android {
struct ABuffer;
@@ -57,6 +59,36 @@
void setFormat(const sp<AMessage> &format);
+ /**
+ * \return C2Buffer object represents this buffer.
+ */
+ virtual std::shared_ptr<C2Buffer> asC2Buffer() { return nullptr; }
+
+ /**
+ * Test if we can copy the content of |buffer| into this object.
+ *
+ * \param buffer C2Buffer object to copy.
+ * \return true if the content of buffer can be copied over to this buffer
+ * false otherwise.
+ */
+ virtual bool canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
+ (void)buffer;
+ return false;
+ }
+
+ /**
+ * Copy the content of |buffer| into this object. This method assumes that
+ * canCopy() check already passed.
+ *
+ * \param buffer C2Buffer object to copy.
+ * \return true if successful
+ * false otherwise.
+ */
+ virtual bool copy(const std::shared_ptr<C2Buffer> &buffer) {
+ (void)buffer;
+ return false;
+ }
+
private:
MediaCodecBuffer() = delete;
diff --git a/media/libmedia/include/media/MediaMetadataRetrieverInterface.h b/media/libmedia/include/media/MediaMetadataRetrieverInterface.h
index 98d300f..37dc401 100644
--- a/media/libmedia/include/media/MediaMetadataRetrieverInterface.h
+++ b/media/libmedia/include/media/MediaMetadataRetrieverInterface.h
@@ -49,9 +49,8 @@
int index, int colorFormat, bool metaOnly, bool thumbnail) = 0;
virtual sp<IMemory> getImageRectAtIndex(
int index, int colorFormat, int left, int top, int right, int bottom) = 0;
- virtual status_t getFrameAtIndex(
- std::vector<sp<IMemory> >* frames,
- int frameIndex, int numFrames, int colorFormat, bool metaOnly) = 0;
+ virtual sp<IMemory> getFrameAtIndex(
+ int frameIndex, int colorFormat, bool metaOnly) = 0;
virtual MediaAlbumArt* extractAlbumArt() = 0;
virtual const char* extractMetadata(int keyCode) = 0;
};
diff --git a/media/libmedia/include/media/MediaProfiles.h b/media/libmedia/include/media/MediaProfiles.h
index 3e8e7c8..4cc5b95 100644
--- a/media/libmedia/include/media/MediaProfiles.h
+++ b/media/libmedia/include/media/MediaProfiles.h
@@ -1,18 +1,18 @@
/*
- **
- ** Copyright 2010, The Android Open Source Project.
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
+ *
+ * Copyright 2010, The Android Open Source Project.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
#ifndef ANDROID_MEDIAPROFILES_H
@@ -82,29 +82,12 @@
{
public:
- /*
- * If property media.settings.xml is not set:
- *
- * getInstance() will search through paths listed in xmlFiles.
- * The search goes through members of xmlFiles in the order that they are
- * defined, so files at lower indices have higher priority than those at
- * higher indices.
- *
- * TODO: Add runtime validation of xml files. A search should be considered
- * successful only when validation is successful.
- */
- static constexpr char const * const xmlFiles[] = {
- "odm/etc/media_profiles_V1_0.xml",
- "vendor/etc/media_profiles_V1_0.xml",
- "system/etc/media_profiles.xml"
- };
-
/**
* Returns the singleton instance for subsequence queries or NULL if error.
*
* If property media.settings.xml is set, getInstance() will attempt to read
* from file path in media.settings.xml. Otherwise, getInstance() will
- * search through the list xmlFiles as described above.
+ * search through the list of preset XML file paths.
*
* If the search is unsuccessful, the default instance will be created
* instead.
diff --git a/media/libmedia/include/media/MediaRecorderBase.h b/media/libmedia/include/media/MediaRecorderBase.h
index a2dff31..8493f64 100644
--- a/media/libmedia/include/media/MediaRecorderBase.h
+++ b/media/libmedia/include/media/MediaRecorderBase.h
@@ -39,6 +39,8 @@
virtual status_t init() = 0;
virtual status_t setAudioSource(audio_source_t as) = 0;
+ virtual status_t setPrivacySensitive(bool privacySensitive) = 0 ;
+ virtual status_t isPrivacySensitive(bool *privacySensitive) const = 0;
virtual status_t setVideoSource(video_source vs) = 0;
virtual status_t setOutputFormat(output_format of) = 0;
virtual status_t setAudioEncoder(audio_encoder ae) = 0;
@@ -79,6 +81,7 @@
protected:
+
String16 mOpPackageName;
private:
diff --git a/media/libmedia/include/media/MediaResource.h b/media/libmedia/include/media/MediaResource.h
index 10a07bb..e7362c1 100644
--- a/media/libmedia/include/media/MediaResource.h
+++ b/media/libmedia/include/media/MediaResource.h
@@ -18,66 +18,56 @@
#ifndef ANDROID_MEDIA_RESOURCE_H
#define ANDROID_MEDIA_RESOURCE_H
-#include <binder/Parcel.h>
+#include <aidl/android/media/MediaResourceParcel.h>
#include <utils/String8.h>
namespace android {
-class MediaResource {
+using aidl::android::media::MediaResourceParcel;
+using aidl::android::media::MediaResourceSubType;
+using aidl::android::media::MediaResourceType;
+
+class MediaResource : public MediaResourceParcel {
public:
- enum Type {
- kUnspecified = 0,
- kSecureCodec,
- kNonSecureCodec,
- kGraphicMemory,
- kCpuBoost,
- kBattery,
- };
+ using Type = MediaResourceType;
+ using SubType = MediaResourceSubType;
- enum SubType {
- kUnspecifiedSubType = 0,
- kAudioCodec,
- kVideoCodec,
- };
+ MediaResource() = delete;
+ MediaResource(Type type, int64_t value);
+ MediaResource(Type type, SubType subType, int64_t value);
+ MediaResource(Type type, const std::vector<int8_t> &id, int64_t value);
- MediaResource();
- MediaResource(Type type, uint64_t value);
- MediaResource(Type type, SubType subType, uint64_t value);
-
- void readFromParcel(const Parcel &parcel);
- void writeToParcel(Parcel *parcel) const;
-
- String8 toString() const;
-
- bool operator==(const MediaResource &other) const;
- bool operator!=(const MediaResource &other) const;
-
- Type mType;
- SubType mSubType;
- uint64_t mValue;
+ static MediaResource CodecResource(bool secure, bool video);
+ static MediaResource GraphicMemoryResource(int64_t value);
+ static MediaResource CpuBoostResource();
+ static MediaResource VideoBatteryResource();
+ static MediaResource DrmSessionResource(const std::vector<int8_t> &id, int64_t value);
};
inline static const char *asString(MediaResource::Type i, const char *def = "??") {
switch (i) {
- case MediaResource::kUnspecified: return "unspecified";
- case MediaResource::kSecureCodec: return "secure-codec";
- case MediaResource::kNonSecureCodec: return "non-secure-codec";
- case MediaResource::kGraphicMemory: return "graphic-memory";
- case MediaResource::kCpuBoost: return "cpu-boost";
- case MediaResource::kBattery: return "battery";
- default: return def;
+ case MediaResource::Type::kUnspecified: return "unspecified";
+ case MediaResource::Type::kSecureCodec: return "secure-codec";
+ case MediaResource::Type::kNonSecureCodec: return "non-secure-codec";
+ case MediaResource::Type::kGraphicMemory: return "graphic-memory";
+ case MediaResource::Type::kCpuBoost: return "cpu-boost";
+ case MediaResource::Type::kBattery: return "battery";
+ case MediaResource::Type::kDrmSession: return "drm-session";
+ default: return def;
}
}
inline static const char *asString(MediaResource::SubType i, const char *def = "??") {
switch (i) {
- case MediaResource::kUnspecifiedSubType: return "unspecified";
- case MediaResource::kAudioCodec: return "audio-codec";
- case MediaResource::kVideoCodec: return "video-codec";
+ case MediaResource::SubType::kUnspecifiedSubType: return "unspecified";
+ case MediaResource::SubType::kAudioCodec: return "audio-codec";
+ case MediaResource::SubType::kVideoCodec: return "video-codec";
default: return def;
}
}
+String8 toString(const MediaResourceParcel& resource);
+
}; // namespace android
#endif // ANDROID_MEDIA_RESOURCE_H
diff --git a/media/libmedia/include/media/MediaResourcePolicy.h b/media/libmedia/include/media/MediaResourcePolicy.h
index 9bc2eec..052395b 100644
--- a/media/libmedia/include/media/MediaResourcePolicy.h
+++ b/media/libmedia/include/media/MediaResourcePolicy.h
@@ -18,28 +18,24 @@
#ifndef ANDROID_MEDIA_RESOURCE_POLICY_H
#define ANDROID_MEDIA_RESOURCE_POLICY_H
-#include <binder/Parcel.h>
+#include <aidl/android/media/MediaResourcePolicyParcel.h>
#include <utils/String8.h>
namespace android {
-extern const char kPolicySupportsMultipleSecureCodecs[];
-extern const char kPolicySupportsSecureWithNonSecureCodec[];
+using aidl::android::media::MediaResourcePolicyParcel;
-class MediaResourcePolicy {
+class MediaResourcePolicy : public MediaResourcePolicyParcel {
public:
- MediaResourcePolicy();
- MediaResourcePolicy(String8 type, String8 value);
+ MediaResourcePolicy() = delete;
+ MediaResourcePolicy(const std::string& type, const std::string& value);
- void readFromParcel(const Parcel &parcel);
- void writeToParcel(Parcel *parcel) const;
-
- String8 toString() const;
-
- String8 mType;
- String8 mValue;
+ static const char* kPolicySupportsMultipleSecureCodecs();
+ static const char* kPolicySupportsSecureWithNonSecureCodec();
};
+String8 toString(const MediaResourcePolicyParcel &policy);
+
}; // namespace android
#endif // ANDROID_MEDIA_RESOURCE_POLICY_H
diff --git a/media/libmedia/include/media/MidiDeviceInfo.h b/media/libmedia/include/media/MidiDeviceInfo.h
deleted file mode 100644
index 5b4a241..0000000
--- a/media/libmedia/include/media/MidiDeviceInfo.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_MEDIA_MIDI_DEVICE_INFO_H
-#define ANDROID_MEDIA_MIDI_DEVICE_INFO_H
-
-#include <binder/Parcelable.h>
-#include <binder/PersistableBundle.h>
-#include <utils/String16.h>
-#include <utils/Vector.h>
-
-namespace android {
-namespace media {
-namespace midi {
-
-class MidiDeviceInfo : public Parcelable {
-public:
- MidiDeviceInfo() = default;
- virtual ~MidiDeviceInfo() = default;
- MidiDeviceInfo(const MidiDeviceInfo& midiDeviceInfo) = default;
-
- status_t writeToParcel(Parcel* parcel) const override;
- status_t readFromParcel(const Parcel* parcel) override;
-
- int getType() const { return mType; }
- int getUid() const { return mId; }
- bool isPrivate() const { return mIsPrivate; }
- const Vector<String16>& getInputPortNames() const { return mInputPortNames; }
- const Vector<String16>& getOutputPortNames() const { return mOutputPortNames; }
- String16 getProperty(const char* propertyName);
-
- // The constants need to be kept in sync with MidiDeviceInfo.java
- enum {
- TYPE_USB = 1,
- TYPE_VIRTUAL = 2,
- TYPE_BLUETOOTH = 3,
- };
- static const char* const PROPERTY_NAME;
- static const char* const PROPERTY_MANUFACTURER;
- static const char* const PROPERTY_PRODUCT;
- static const char* const PROPERTY_VERSION;
- static const char* const PROPERTY_SERIAL_NUMBER;
- static const char* const PROPERTY_ALSA_CARD;
- static const char* const PROPERTY_ALSA_DEVICE;
-
- friend bool operator==(const MidiDeviceInfo& lhs, const MidiDeviceInfo& rhs);
- friend bool operator!=(const MidiDeviceInfo& lhs, const MidiDeviceInfo& rhs) {
- return !(lhs == rhs);
- }
-
-private:
- status_t readStringVector(
- const Parcel* parcel, Vector<String16> *vectorPtr, size_t defaultLength);
- status_t writeStringVector(Parcel* parcel, const Vector<String16>& vector) const;
-
- int32_t mType;
- int32_t mId;
- Vector<String16> mInputPortNames;
- Vector<String16> mOutputPortNames;
- os::PersistableBundle mProperties;
- bool mIsPrivate;
-};
-
-} // namespace midi
-} // namespace media
-} // namespace android
-
-#endif // ANDROID_MEDIA_MIDI_DEVICE_INFO_H
diff --git a/media/libmedia/include/media/MidiIoWrapper.h b/media/libmedia/include/media/MidiIoWrapper.h
index b19d49e..0cdd4ad 100644
--- a/media/libmedia/include/media/MidiIoWrapper.h
+++ b/media/libmedia/include/media/MidiIoWrapper.h
@@ -19,12 +19,9 @@
#include <libsonivox/eas_types.h>
-#include <media/DataSourceBase.h>
-
namespace android {
struct CDataSource;
-class DataSourceUnwrapper;
class MidiIoWrapper {
public:
@@ -43,6 +40,7 @@
int mFd;
off64_t mBase;
int64_t mLength;
+ class DataSourceUnwrapper;
DataSourceUnwrapper *mDataSource;
EAS_FILE mEasFile;
};
diff --git a/media/libmedia/include/media/NdkWrapper.h b/media/libmedia/include/media/NdkWrapper.h
index 8a417f6..39c0574 100644
--- a/media/libmedia/include/media/NdkWrapper.h
+++ b/media/libmedia/include/media/NdkWrapper.h
@@ -19,7 +19,7 @@
#define NDK_WRAPPER_H_
#include <media/DataSource.h>
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/NdkMediaDataSource.h>
#include <media/NdkMediaError.h>
#include <media/NdkMediaExtractor.h>
diff --git a/media/libmedia/include/media/PluginMetricsReporting.h b/media/libmedia/include/media/PluginMetricsReporting.h
index e00bd43..f71c52d 100644
--- a/media/libmedia/include/media/PluginMetricsReporting.h
+++ b/media/libmedia/include/media/PluginMetricsReporting.h
@@ -18,6 +18,7 @@
#define PLUGIN_METRICS_REPORTING_H_
+#include <sys/types.h>
#include <utils/Errors.h>
#include <utils/String8.h>
@@ -26,7 +27,7 @@
status_t reportDrmPluginMetrics(const std::string& b64EncodedMetrics,
const String8& vendorName,
const String8& description,
- const String8& appPackageName);
+ uid_t appUid);
} // namespace android
diff --git a/media/libmedia/include/media/TypeConverter.h b/media/libmedia/include/media/TypeConverter.h
deleted file mode 100644
index 2f8c209..0000000
--- a/media/libmedia/include/media/TypeConverter.h
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_TYPE_CONVERTER_H_
-#define ANDROID_TYPE_CONVERTER_H_
-
-#include <string>
-#include <string.h>
-
-#include <vector>
-#include <system/audio.h>
-#include <utils/Log.h>
-#include <utils/Vector.h>
-#include <utils/SortedVector.h>
-
-#include <media/AudioParameter.h>
-#include "convert.h"
-
-namespace android {
-
-template <typename T>
-struct DefaultTraits
-{
- typedef T Type;
- typedef std::vector<Type> Collection;
- static void add(Collection &collection, Type value)
- {
- collection.push_back(value);
- }
-};
-template <typename T>
-struct VectorTraits
-{
- typedef T Type;
- typedef Vector<Type> Collection;
- static void add(Collection &collection, Type value)
- {
- collection.add(value);
- }
-};
-template <typename T>
-struct SortedVectorTraits
-{
- typedef T Type;
- typedef SortedVector<Type> Collection;
- static void add(Collection &collection, Type value)
- {
- collection.add(value);
- }
-};
-
-using SampleRateTraits = SortedVectorTraits<uint32_t>;
-using DeviceTraits = DefaultTraits<audio_devices_t>;
-struct OutputDeviceTraits : public DeviceTraits {};
-struct InputDeviceTraits : public DeviceTraits {};
-using ChannelTraits = SortedVectorTraits<audio_channel_mask_t>;
-struct OutputChannelTraits : public ChannelTraits {};
-struct InputChannelTraits : public ChannelTraits {};
-struct ChannelIndexTraits : public ChannelTraits {};
-using InputFlagTraits = DefaultTraits<audio_input_flags_t>;
-using OutputFlagTraits = DefaultTraits<audio_output_flags_t>;
-using FormatTraits = VectorTraits<audio_format_t>;
-using GainModeTraits = DefaultTraits<audio_gain_mode_t>;
-using StreamTraits = DefaultTraits<audio_stream_type_t>;
-using AudioModeTraits = DefaultTraits<audio_mode_t>;
-using AudioContentTraits = DefaultTraits<audio_content_type_t>;
-using UsageTraits = DefaultTraits<audio_usage_t>;
-using SourceTraits = DefaultTraits<audio_source_t>;
-struct AudioFlagTraits : public DefaultTraits<audio_flags_mask_t> {};
-
-template <class Traits>
-static void collectionFromString(const std::string &str, typename Traits::Collection &collection,
- const char *del = AudioParameter::valueListSeparator)
-{
- char *literal = strdup(str.c_str());
- for (const char *cstr = strtok(literal, del); cstr != NULL; cstr = strtok(NULL, del)) {
- typename Traits::Type value;
- if (utilities::convertTo<std::string, typename Traits::Type >(cstr, value)) {
- Traits::add(collection, value);
- }
- }
- free(literal);
-}
-
-template <class Traits>
-class TypeConverter
-{
-public:
- static bool toString(const typename Traits::Type &value, std::string &str);
-
- static bool fromString(const std::string &str, typename Traits::Type &result);
-
- static void collectionFromString(const std::string &str,
- typename Traits::Collection &collection,
- const char *del = AudioParameter::valueListSeparator);
-
- static uint32_t maskFromString(
- const std::string &str, const char *del = AudioParameter::valueListSeparator);
-
- static void maskToString(
- uint32_t mask, std::string &str, const char *del = AudioParameter::valueListSeparator);
-
-protected:
- struct Table {
- const char *literal;
- typename Traits::Type value;
- };
-
- static const Table mTable[];
-};
-
-template <class Traits>
-inline bool TypeConverter<Traits>::toString(const typename Traits::Type &value, std::string &str)
-{
- for (size_t i = 0; mTable[i].literal; i++) {
- if (mTable[i].value == value) {
- str = mTable[i].literal;
- return true;
- }
- }
- char result[64];
- snprintf(result, sizeof(result), "Unknown enum value %d", value);
- str = result;
- return false;
-}
-
-template <class Traits>
-inline bool TypeConverter<Traits>::fromString(const std::string &str, typename Traits::Type &result)
-{
- for (size_t i = 0; mTable[i].literal; i++) {
- if (strcmp(mTable[i].literal, str.c_str()) == 0) {
- ALOGV("stringToEnum() found %s", mTable[i].literal);
- result = mTable[i].value;
- return true;
- }
- }
- return false;
-}
-
-template <class Traits>
-inline void TypeConverter<Traits>::collectionFromString(const std::string &str,
- typename Traits::Collection &collection,
- const char *del)
-{
- char *literal = strdup(str.c_str());
-
- for (const char *cstr = strtok(literal, del); cstr != NULL; cstr = strtok(NULL, del)) {
- typename Traits::Type value;
- if (fromString(cstr, value)) {
- Traits::add(collection, value);
- }
- }
- free(literal);
-}
-
-template <class Traits>
-inline uint32_t TypeConverter<Traits>::maskFromString(const std::string &str, const char *del)
-{
- char *literal = strdup(str.c_str());
- uint32_t value = 0;
- for (const char *cstr = strtok(literal, del); cstr != NULL; cstr = strtok(NULL, del)) {
- typename Traits::Type type;
- if (fromString(cstr, type)) {
- value |= static_cast<uint32_t>(type);
- }
- }
- free(literal);
- return value;
-}
-
-template <class Traits>
-inline void TypeConverter<Traits>::maskToString(uint32_t mask, std::string &str, const char *del)
-{
- if (mask != 0) {
- bool first_flag = true;
- for (size_t i = 0; mTable[i].literal; i++) {
- uint32_t value = static_cast<uint32_t>(mTable[i].value);
- if (mTable[i].value != 0 && ((mask & value) == value)) {
- if (!first_flag) str += del;
- first_flag = false;
- str += mTable[i].literal;
- }
- }
- } else {
- toString(static_cast<typename Traits::Type>(0), str);
- }
-}
-
-typedef TypeConverter<OutputDeviceTraits> OutputDeviceConverter;
-typedef TypeConverter<InputDeviceTraits> InputDeviceConverter;
-typedef TypeConverter<OutputFlagTraits> OutputFlagConverter;
-typedef TypeConverter<InputFlagTraits> InputFlagConverter;
-typedef TypeConverter<FormatTraits> FormatConverter;
-typedef TypeConverter<OutputChannelTraits> OutputChannelConverter;
-typedef TypeConverter<InputChannelTraits> InputChannelConverter;
-typedef TypeConverter<ChannelIndexTraits> ChannelIndexConverter;
-typedef TypeConverter<GainModeTraits> GainModeConverter;
-typedef TypeConverter<StreamTraits> StreamTypeConverter;
-typedef TypeConverter<AudioModeTraits> AudioModeConverter;
-typedef TypeConverter<AudioContentTraits> AudioContentTypeConverter;
-typedef TypeConverter<UsageTraits> UsageTypeConverter;
-typedef TypeConverter<SourceTraits> SourceTypeConverter;
-typedef TypeConverter<AudioFlagTraits> AudioFlagConverter;
-
-template<> const OutputDeviceConverter::Table OutputDeviceConverter::mTable[];
-template<> const InputDeviceConverter::Table InputDeviceConverter::mTable[];
-template<> const OutputFlagConverter::Table OutputFlagConverter::mTable[];
-template<> const InputFlagConverter::Table InputFlagConverter::mTable[];
-template<> const FormatConverter::Table FormatConverter::mTable[];
-template<> const OutputChannelConverter::Table OutputChannelConverter::mTable[];
-template<> const InputChannelConverter::Table InputChannelConverter::mTable[];
-template<> const ChannelIndexConverter::Table ChannelIndexConverter::mTable[];
-template<> const GainModeConverter::Table GainModeConverter::mTable[];
-template<> const StreamTypeConverter::Table StreamTypeConverter::mTable[];
-template<> const AudioModeConverter::Table AudioModeConverter::mTable[];
-template<> const AudioContentTypeConverter::Table AudioContentTypeConverter::mTable[];
-template<> const UsageTypeConverter::Table UsageTypeConverter::mTable[];
-template<> const SourceTypeConverter::Table SourceTypeConverter::mTable[];
-template<> const AudioFlagConverter::Table AudioFlagConverter::mTable[];
-
-bool deviceFromString(const std::string& literalDevice, audio_devices_t& device);
-
-SampleRateTraits::Collection samplingRatesFromString(
- const std::string &samplingRates, const char *del = AudioParameter::valueListSeparator);
-
-FormatTraits::Collection formatsFromString(
- const std::string &formats, const char *del = AudioParameter::valueListSeparator);
-
-audio_format_t formatFromString(
- const std::string &literalFormat, audio_format_t defaultFormat = AUDIO_FORMAT_DEFAULT);
-
-audio_channel_mask_t channelMaskFromString(const std::string &literalChannels);
-
-ChannelTraits::Collection channelMasksFromString(
- const std::string &channels, const char *del = AudioParameter::valueListSeparator);
-
-InputChannelTraits::Collection inputChannelMasksFromString(
- const std::string &inChannels, const char *del = AudioParameter::valueListSeparator);
-
-OutputChannelTraits::Collection outputChannelMasksFromString(
- const std::string &outChannels, const char *del = AudioParameter::valueListSeparator);
-
-// counting enumerations
-template <typename T, std::enable_if_t<std::is_same<T, audio_content_type_t>::value
- || std::is_same<T, audio_mode_t>::value
- || std::is_same<T, audio_source_t>::value
- || std::is_same<T, audio_stream_type_t>::value
- || std::is_same<T, audio_usage_t>::value
- , int> = 0>
-static inline std::string toString(const T& value)
-{
- std::string result;
- return TypeConverter<DefaultTraits<T>>::toString(value, result)
- ? result : std::to_string(static_cast<int>(value));
-
-}
-
-// flag enumerations
-template <typename T, std::enable_if_t<std::is_same<T, audio_gain_mode_t>::value
- || std::is_same<T, audio_input_flags_t>::value
- || std::is_same<T, audio_output_flags_t>::value
- , int> = 0>
-static inline std::string toString(const T& value)
-{
- std::string result;
- TypeConverter<DefaultTraits<T>>::maskToString(value, result);
- return result;
-}
-
-static inline std::string toString(const audio_devices_t& devices)
-{
- std::string result;
- if ((devices & AUDIO_DEVICE_BIT_IN) != 0) {
- InputDeviceConverter::maskToString(devices, result);
- } else {
- OutputDeviceConverter::maskToString(devices, result);
- }
- return result;
-}
-
-// TODO: Remove when FormatTraits uses DefaultTraits.
-static inline std::string toString(const audio_format_t& format)
-{
- std::string result;
- return TypeConverter<VectorTraits<audio_format_t>>::toString(format, result)
- ? result : std::to_string(static_cast<int>(format));
-}
-
-static inline std::string toString(const audio_attributes_t& attributes)
-{
- std::ostringstream result;
- result << "{ Content type: " << toString(attributes.content_type)
- << " Usage: " << toString(attributes.usage)
- << " Source: " << toString(attributes.source)
- << std::hex << " Flags: 0x" << attributes.flags
- << std::dec << " Tags: " << attributes.tags
- << " }";
-
- return result.str();
-}
-
-}; // namespace android
-
-#endif /*ANDROID_TYPE_CONVERTER_H_*/
diff --git a/media/libmedia/include/media/Visualizer.h b/media/libmedia/include/media/Visualizer.h
deleted file mode 100644
index 8078e36..0000000
--- a/media/libmedia/include/media/Visualizer.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_MEDIA_VISUALIZER_H
-#define ANDROID_MEDIA_VISUALIZER_H
-
-#include <media/AudioEffect.h>
-#include <system/audio_effects/effect_visualizer.h>
-#include <utils/Thread.h>
-
-/**
- * The Visualizer class enables application to retrieve part of the currently playing audio for
- * visualization purpose. It is not an audio recording interface and only returns partial and low
- * quality audio content. However, to protect privacy of certain audio data (e.g voice mail) the use
- * of the visualizer requires the permission android.permission.RECORD_AUDIO.
- * The audio session ID passed to the constructor indicates which audio content should be
- * visualized:
- * - If the session is 0, the audio output mix is visualized
- * - If the session is not 0, the audio from a particular MediaPlayer or AudioTrack
- * using this audio session is visualized
- * Two types of representation of audio content can be captured:
- * - Waveform data: consecutive 8-bit (unsigned) mono samples by using the getWaveForm() method
- * - Frequency data: 8-bit magnitude FFT by using the getFft() method
- *
- * The length of the capture can be retrieved or specified by calling respectively
- * getCaptureSize() and setCaptureSize() methods. Note that the size of the FFT
- * is half of the specified capture size but both sides of the spectrum are returned yielding in a
- * number of bytes equal to the capture size. The capture size must be a power of 2 in the range
- * returned by getMinCaptureSize() and getMaxCaptureSize().
- * In addition to the polling capture mode, a callback mode is also available by installing a
- * callback function by use of the setCaptureCallBack() method. The rate at which the callback
- * is called as well as the type of data returned is specified.
- * Before capturing data, the Visualizer must be enabled by calling the setEnabled() method.
- * When data capture is not needed any more, the Visualizer should be disabled.
- */
-
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-class Visualizer: public AudioEffect {
-public:
-
- enum callback_flags {
- CAPTURE_WAVEFORM = 0x00000001, // capture callback returns a PCM wave form
- CAPTURE_FFT = 0x00000002, // apture callback returns a frequency representation
- CAPTURE_CALL_JAVA = 0x00000004 // the callback thread can call java
- };
-
-
- /* Constructor.
- * See AudioEffect constructor for details on parameters.
- */
- Visualizer(const String16& opPackageName,
- int32_t priority = 0,
- effect_callback_t cbf = NULL,
- void* user = NULL,
- audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX);
-
- ~Visualizer();
-
- virtual status_t setEnabled(bool enabled);
-
- // maximum capture size in samples
- static uint32_t getMaxCaptureSize() { return VISUALIZER_CAPTURE_SIZE_MAX; }
- // minimum capture size in samples
- static uint32_t getMinCaptureSize() { return VISUALIZER_CAPTURE_SIZE_MIN; }
- // maximum capture rate in millihertz
- static uint32_t getMaxCaptureRate() { return CAPTURE_RATE_MAX; }
-
- // callback used to return periodic PCM or FFT captures to the application. Either one or both
- // types of data are returned (PCM and FFT) according to flags indicated when installing the
- // callback. When a type of data is not present, the corresponding size (waveformSize or
- // fftSize) is 0.
- typedef void (*capture_cbk_t)(void* user,
- uint32_t waveformSize,
- uint8_t *waveform,
- uint32_t fftSize,
- uint8_t *fft,
- uint32_t samplingrate);
-
- // install a callback to receive periodic captures. The capture rate is specified in milliHertz
- // and the capture format is according to flags (see callback_flags).
- status_t setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, uint32_t rate);
-
- // set the capture size capture size must be a power of two in the range
- // [VISUALIZER_CAPTURE_SIZE_MAX. VISUALIZER_CAPTURE_SIZE_MIN]
- // must be called when the visualizer is not enabled
- status_t setCaptureSize(uint32_t size);
- uint32_t getCaptureSize() { return mCaptureSize; }
-
- // returns the capture rate indicated when installing the callback
- uint32_t getCaptureRate() { return mCaptureRate; }
-
- // returns the sampling rate of the audio being captured
- uint32_t getSamplingRate() { return mSampleRate; }
-
- // set the way volume affects the captured data
- // mode must one of VISUALIZER_SCALING_MODE_NORMALIZED,
- // VISUALIZER_SCALING_MODE_AS_PLAYED
- status_t setScalingMode(uint32_t mode);
- uint32_t getScalingMode() { return mScalingMode; }
-
- // set which measurements are done on the audio buffers processed by the effect.
- // valid measurements (mask): MEASUREMENT_MODE_PEAK_RMS
- status_t setMeasurementMode(uint32_t mode);
- uint32_t getMeasurementMode() { return mMeasurementMode; }
-
- // return a set of int32_t measurements
- status_t getIntMeasurements(uint32_t type, uint32_t number, int32_t *measurements);
-
- // return a capture in PCM 8 bit unsigned format. The size of the capture is equal to
- // getCaptureSize()
- status_t getWaveForm(uint8_t *waveform);
-
- // return a capture in FFT 8 bit signed format. The size of the capture is equal to
- // getCaptureSize() but the length of the FFT is half of the size (both parts of the spectrum
- // are returned
- status_t getFft(uint8_t *fft);
- void release();
-
-protected:
- // from IEffectClient
- virtual void controlStatusChanged(bool controlGranted);
-
-private:
-
- static const uint32_t CAPTURE_RATE_MAX = 20000;
- static const uint32_t CAPTURE_RATE_DEF = 10000;
- static const uint32_t CAPTURE_SIZE_DEF = VISUALIZER_CAPTURE_SIZE_MAX;
-
- /* internal class to handle the callback */
- class CaptureThread : public Thread
- {
- public:
- CaptureThread(Visualizer* visualizer, uint32_t captureRate, bool bCanCallJava = false);
-
- private:
- friend class Visualizer;
- virtual bool threadLoop();
- wp<Visualizer> mReceiver;
- Mutex mLock;
- uint32_t mSleepTimeUs;
- };
-
- status_t doFft(uint8_t *fft, uint8_t *waveform);
- void periodicCapture();
- uint32_t initCaptureSize();
-
- Mutex mCaptureLock;
- uint32_t mCaptureRate;
- uint32_t mCaptureSize;
- uint32_t mSampleRate;
- uint32_t mScalingMode;
- uint32_t mMeasurementMode;
- capture_cbk_t mCaptureCallBack;
- void *mCaptureCbkUser;
- sp<CaptureThread> mCaptureThread;
- uint32_t mCaptureFlags;
-};
-
-
-}; // namespace android
-
-#endif // ANDROID_MEDIA_VISUALIZER_H
diff --git a/media/libmedia/include/media/mediametadataretriever.h b/media/libmedia/include/media/mediametadataretriever.h
index d29e97d..138a014 100644
--- a/media/libmedia/include/media/mediametadataretriever.h
+++ b/media/libmedia/include/media/mediametadataretriever.h
@@ -98,9 +98,8 @@
int colorFormat = HAL_PIXEL_FORMAT_RGB_565, bool metaOnly = false, bool thumbnail = false);
sp<IMemory> getImageRectAtIndex(
int index, int colorFormat, int left, int top, int right, int bottom);
- status_t getFrameAtIndex(
- std::vector<sp<IMemory> > *frames, int frameIndex, int numFrames = 1,
- int colorFormat = HAL_PIXEL_FORMAT_RGB_565, bool metaOnly = false);
+ sp<IMemory> getFrameAtIndex(
+ int index, int colorFormat = HAL_PIXEL_FORMAT_RGB_565, bool metaOnly = false);
sp<IMemory> extractAlbumArt();
const char* extractMetadata(int keyCode);
diff --git a/media/libmedia/include/media/mediarecorder.h b/media/libmedia/include/media/mediarecorder.h
index 2dd4b7f..6e2d94d 100644
--- a/media/libmedia/include/media/mediarecorder.h
+++ b/media/libmedia/include/media/mediarecorder.h
@@ -236,6 +236,8 @@
status_t setPreviewSurface(const sp<IGraphicBufferProducer>& surface);
status_t setVideoSource(int vs);
status_t setAudioSource(int as);
+ status_t setPrivacySensitive(bool privacySensitive);
+ status_t isPrivacySensitive(bool *privacySensitive) const;
status_t setOutputFormat(int of);
status_t setVideoEncoder(int ve);
status_t setAudioEncoder(int ae);
diff --git a/media/libmedia/include/media/omx/1.0/Conversion.h b/media/libmedia/include/media/omx/1.0/Conversion.h
index 6dc46b7..811936b 100644
--- a/media/libmedia/include/media/omx/1.0/Conversion.h
+++ b/media/libmedia/include/media/omx/1.0/Conversion.h
@@ -45,7 +45,6 @@
#include <android/hardware/media/omx/1.0/IOmxObserver.h>
#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
-#include <android/IGraphicBufferSource.h>
#include <android/IOMXBufferSource.h>
namespace android {
diff --git a/media/libmedia/include/media/omx/1.0/WOmx.h b/media/libmedia/include/media/omx/1.0/WOmx.h
index 0680eec..46ada9b 100644
--- a/media/libmedia/include/media/omx/1.0/WOmx.h
+++ b/media/libmedia/include/media/omx/1.0/WOmx.h
@@ -67,7 +67,7 @@
sp<IOMXNode>* omxNode) override;
status_t createInputSurface(
sp<::android::IGraphicBufferProducer>* bufferProducer,
- sp<::android::IGraphicBufferSource>* bufferSource) override;
+ sp<::android::hardware::media::omx::V1_0::IGraphicBufferSource>* bufferSource) override;
};
} // namespace utils
diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp
index e61b04d..2ae76b3 100644
--- a/media/libmedia/mediametadataretriever.cpp
+++ b/media/libmedia/mediametadataretriever.cpp
@@ -179,18 +179,16 @@
index, colorFormat, left, top, right, bottom);
}
-status_t MediaMetadataRetriever::getFrameAtIndex(
- std::vector<sp<IMemory> > *frames,
- int frameIndex, int numFrames, int colorFormat, bool metaOnly) {
- ALOGV("getFrameAtIndex: frameIndex(%d), numFrames(%d), colorFormat(%d) metaOnly(%d)",
- frameIndex, numFrames, colorFormat, metaOnly);
+sp<IMemory> MediaMetadataRetriever::getFrameAtIndex(
+ int index, int colorFormat, bool metaOnly) {
+ ALOGV("getFrameAtIndex: index(%d), colorFormat(%d) metaOnly(%d)",
+ index, colorFormat, metaOnly);
Mutex::Autolock _l(mLock);
if (mRetriever == 0) {
ALOGE("retriever is not initialized");
- return INVALID_OPERATION;
+ return NULL;
}
- return mRetriever->getFrameAtIndex(
- frames, frameIndex, numFrames, colorFormat, metaOnly);
+ return mRetriever->getFrameAtIndex(index, colorFormat, metaOnly);
}
const char* MediaMetadataRetriever::extractMetadata(int keyCode)
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 26908e5..1fadc94 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -17,6 +17,7 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "MediaPlayerNative"
+#include <utils/Log.h>
#include <fcntl.h>
#include <inttypes.h>
@@ -24,25 +25,15 @@
#include <sys/types.h>
#include <unistd.h>
-#include <utils/Log.h>
-#include <binder/IServiceManager.h>
+#include <android/IDataSource.h>
#include <binder/IPCThreadState.h>
-
-#include <gui/Surface.h>
-
#include <media/mediaplayer.h>
#include <media/AudioResamplerPublic.h>
#include <media/AudioSystem.h>
#include <media/AVSyncSettings.h>
-#include <media/IDataSource.h>
-#include <media/MediaAnalyticsItem.h>
-
-#include <binder/MemoryBase.h>
-
#include <utils/KeyedVector.h>
#include <utils/String8.h>
-
#include <system/audio.h>
#include <system/window.h>
@@ -69,7 +60,7 @@
mVideoWidth = mVideoHeight = 0;
mLockThreadId = 0;
mAudioSessionId = (audio_session_t) AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
- AudioSystem::acquireAudioSessionId(mAudioSessionId, -1);
+ AudioSystem::acquireAudioSessionId(mAudioSessionId, (pid_t)-1, (uid_t)-1); // always in client.
mSendLevel = 0;
mRetransmitEndpointValid = false;
}
@@ -81,7 +72,7 @@
delete mAudioAttributesParcel;
mAudioAttributesParcel = NULL;
}
- AudioSystem::releaseAudioSessionId(mAudioSessionId, -1);
+ AudioSystem::releaseAudioSessionId(mAudioSessionId, (pid_t)-1);
disconnect();
IPCThreadState::self()->flushCommands();
}
@@ -718,8 +709,8 @@
return BAD_VALUE;
}
if (sessionId != mAudioSessionId) {
- AudioSystem::acquireAudioSessionId(sessionId, -1);
- AudioSystem::releaseAudioSessionId(mAudioSessionId, -1);
+ AudioSystem::acquireAudioSessionId(sessionId, (pid_t)-1, (uid_t)-1);
+ AudioSystem::releaseAudioSessionId(mAudioSessionId, (pid_t)-1);
mAudioSessionId = sessionId;
}
return NO_ERROR;
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index 4570af9..70655d5 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -178,6 +178,47 @@
return ret;
}
+status_t MediaRecorder::setPrivacySensitive(bool privacySensitive)
+{
+ ALOGV("%s(%s)", __func__, privacySensitive ? "true" : "false");
+ if (mMediaRecorder == NULL) {
+ ALOGE("%s: media recorder is not initialized yet", __func__);
+ return INVALID_OPERATION;
+ }
+
+ if (!(mCurrentState & MEDIA_RECORDER_INITIALIZED) || !mIsAudioSourceSet) {
+ ALOGE("%s called in an invalid state(%d) or audio source not (%d)",
+ __func__, mCurrentState, mIsAudioSourceSet);
+ return INVALID_OPERATION;
+ }
+
+ status_t ret = mMediaRecorder->setPrivacySensitive(privacySensitive);
+ if (OK != ret) {
+ ALOGV("%s failed: %d", __func__, ret);
+ mCurrentState = MEDIA_RECORDER_ERROR;
+ return ret;
+ }
+ return ret;
+}
+
+status_t MediaRecorder::isPrivacySensitive(bool *privacySensitive) const
+{
+ if (mMediaRecorder == NULL) {
+ ALOGE("%s: media recorder is not initialized yet", __func__);
+ return INVALID_OPERATION;
+ }
+
+ if (!(mCurrentState & MEDIA_RECORDER_INITIALIZED) || !mIsAudioSourceSet) {
+ ALOGE("%s called in an invalid state(%d) or audio source not (%d)",
+ __func__, mCurrentState, mIsAudioSourceSet);
+ return INVALID_OPERATION;
+ }
+
+ status_t ret = mMediaRecorder->isPrivacySensitive(privacySensitive);
+ ALOGV("%s status: %d eanbled %s", __func__, ret, *privacySensitive ? "enabled" : "disabled");
+ return ret;
+}
+
status_t MediaRecorder::setOutputFormat(int of)
{
ALOGV("setOutputFormat(%d)", of);
diff --git a/media/libmedia/omx/1.0/WOmx.cpp b/media/libmedia/omx/1.0/WOmx.cpp
index ce624fa..4bacdda 100644
--- a/media/libmedia/omx/1.0/WOmx.cpp
+++ b/media/libmedia/omx/1.0/WOmx.cpp
@@ -18,7 +18,6 @@
#include <media/omx/1.0/WOmx.h>
#include <media/omx/1.0/WOmxNode.h>
#include <media/omx/1.0/WOmxObserver.h>
-#include <media/omx/1.0/WGraphicBufferSource.h>
#include <media/omx/1.0/Conversion.h>
namespace android {
@@ -70,7 +69,7 @@
status_t LWOmx::createInputSurface(
sp<::android::IGraphicBufferProducer>* bufferProducer,
- sp<::android::IGraphicBufferSource>* bufferSource) {
+ sp<::android::hardware::media::omx::V1_0::IGraphicBufferSource>* bufferSource) {
status_t fnStatus;
status_t transStatus = toStatusT(mBase->createInputSurface(
[&fnStatus, bufferProducer, bufferSource] (
@@ -79,7 +78,7 @@
sp<IGraphicBufferSource> const& tSource) {
fnStatus = toStatusT(status);
*bufferProducer = new H2BGraphicBufferProducer(tProducer);
- *bufferSource = new LWGraphicBufferSource(tSource);
+ *bufferSource = tSource;
}));
return transStatus == NO_ERROR ? fnStatus : transStatus;
}
diff --git a/media/libmedia/xsd/vts/ValidateMediaProfiles.cpp b/media/libmedia/xsd/vts/ValidateMediaProfiles.cpp
index 7729d52..4f3951a 100644
--- a/media/libmedia/xsd/vts/ValidateMediaProfiles.cpp
+++ b/media/libmedia/xsd/vts/ValidateMediaProfiles.cpp
@@ -14,23 +14,68 @@
* limitations under the License.
*/
+#include <fstream>
#include <string>
#include <android-base/file.h>
#include <android-base/properties.h>
#include "utility/ValidateXml.h"
+bool isFileReadable(std::string const& path) {
+ std::ifstream f(path);
+ return f.good();
+}
+
TEST(CheckConfig, mediaProfilesValidation) {
RecordProperty("description",
"Verify that the media profiles file "
"is valid according to the schema");
+ // Schema path.
+ constexpr char const* xsdPath = "/data/local/tmp/media_profiles.xsd";
+
+ // If "media.settings.xml" is set, it will be used as an absolute path.
std::string mediaSettingsPath = android::base::GetProperty("media.settings.xml", "");
if (mediaSettingsPath.empty()) {
- mediaSettingsPath.assign("/vendor/etc/media_profiles_V1_0.xml");
- }
+ // If "media.settings.xml" is not set, we will search through a list of
+ // file paths.
- EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS(android::base::Basename(mediaSettingsPath).c_str(),
- {android::base::Dirname(mediaSettingsPath).c_str()},
- "/data/local/tmp/media_profiles.xsd");
+ constexpr char const* xmlSearchDirs[] = {
+ "/product/etc/",
+ "/odm/etc/",
+ "/vendor/etc/",
+ };
+
+ // The vendor may provide a vendor variant for the file name.
+ std::string variant = android::base::GetProperty(
+ "ro.media.xml_variant.profiles", "_V1_0");
+ std::string fileName = "media_profiles" + variant + ".xml";
+
+ // Fallback path does not depend on the property defined from the vendor
+ // partition.
+ constexpr char const* fallbackXmlPath =
+ "/system/etc/media_profiles_V1_0.xml";
+
+ std::vector<std::string> xmlPaths = {
+ xmlSearchDirs[0] + fileName,
+ xmlSearchDirs[1] + fileName,
+ xmlSearchDirs[2] + fileName,
+ fallbackXmlPath
+ };
+
+ auto findXmlPath =
+ std::find_if(xmlPaths.begin(), xmlPaths.end(), isFileReadable);
+ ASSERT_TRUE(findXmlPath != xmlPaths.end())
+ << "Cannot read from " << fileName
+ << " in any search directories ("
+ << xmlSearchDirs[0] << ", "
+ << xmlSearchDirs[1] << ", "
+ << xmlSearchDirs[2] << ") and from "
+ << fallbackXmlPath << ".";
+
+ char const* xmlPath = findXmlPath->c_str();
+ EXPECT_VALID_XML(xmlPath, xsdPath);
+ } else {
+ EXPECT_VALID_XML(mediaSettingsPath.c_str(), xsdPath);
+ }
}
diff --git a/media/libmediahelper/Android.bp b/media/libmediahelper/Android.bp
new file mode 100644
index 0000000..72edeec
--- /dev/null
+++ b/media/libmediahelper/Android.bp
@@ -0,0 +1,29 @@
+cc_library_headers {
+ name: "libmedia_helper_headers",
+ vendor_available: true,
+ export_include_dirs: ["include"],
+}
+
+cc_library {
+ name: "libmedia_helper",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ double_loadable: true,
+ srcs: ["AudioParameter.cpp", "TypeConverter.cpp"],
+ cflags: [
+ "-Werror",
+ "-Wextra",
+ "-Wall",
+ ],
+ shared_libs: ["libutils", "liblog"],
+ header_libs: [
+ "libmedia_helper_headers",
+ "libaudio_system_headers",
+ ],
+ export_header_lib_headers: [
+ "libmedia_helper_headers",
+ ],
+ clang: true,
+}
diff --git a/media/libmediahelper/AudioParameter.cpp b/media/libmediahelper/AudioParameter.cpp
new file mode 100644
index 0000000..9f34035
--- /dev/null
+++ b/media/libmediahelper/AudioParameter.cpp
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2006-2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AudioParameter"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+
+#include <media/AudioParameter.h>
+#include <system/audio.h>
+
+namespace android {
+
+// static
+const char * const AudioParameter::keyRouting = AUDIO_PARAMETER_STREAM_ROUTING;
+const char * const AudioParameter::keySamplingRate = AUDIO_PARAMETER_STREAM_SAMPLING_RATE;
+const char * const AudioParameter::keyFormat = AUDIO_PARAMETER_STREAM_FORMAT;
+const char * const AudioParameter::keyChannels = AUDIO_PARAMETER_STREAM_CHANNELS;
+const char * const AudioParameter::keyFrameCount = AUDIO_PARAMETER_STREAM_FRAME_COUNT;
+const char * const AudioParameter::keyInputSource = AUDIO_PARAMETER_STREAM_INPUT_SOURCE;
+const char * const AudioParameter::keyScreenState = AUDIO_PARAMETER_KEY_SCREEN_STATE;
+const char * const AudioParameter::keyBtNrec = AUDIO_PARAMETER_KEY_BT_NREC;
+const char * const AudioParameter::keyHwAvSync = AUDIO_PARAMETER_HW_AV_SYNC;
+const char * const AudioParameter::keyPresentationId = AUDIO_PARAMETER_STREAM_PRESENTATION_ID;
+const char * const AudioParameter::keyProgramId = AUDIO_PARAMETER_STREAM_PROGRAM_ID;
+const char * const AudioParameter::keyAudioLanguagePreferred =
+ AUDIO_PARAMETER_KEY_AUDIO_LANGUAGE_PREFERRED;
+const char * const AudioParameter::keyMonoOutput = AUDIO_PARAMETER_MONO_OUTPUT;
+const char * const AudioParameter::keyStreamHwAvSync = AUDIO_PARAMETER_STREAM_HW_AV_SYNC;
+const char * const AudioParameter::keyDeviceConnect = AUDIO_PARAMETER_DEVICE_CONNECT;
+const char * const AudioParameter::keyDeviceDisconnect = AUDIO_PARAMETER_DEVICE_DISCONNECT;
+const char * const AudioParameter::keyStreamConnect = AUDIO_PARAMETER_DEVICE_CONNECT;
+const char * const AudioParameter::keyStreamDisconnect = AUDIO_PARAMETER_DEVICE_DISCONNECT;
+const char * const AudioParameter::keyStreamSupportedFormats = AUDIO_PARAMETER_STREAM_SUP_FORMATS;
+const char * const AudioParameter::keyStreamSupportedChannels = AUDIO_PARAMETER_STREAM_SUP_CHANNELS;
+const char * const AudioParameter::keyStreamSupportedSamplingRates =
+ AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES;
+const char * const AudioParameter::valueOn = AUDIO_PARAMETER_VALUE_ON;
+const char * const AudioParameter::valueOff = AUDIO_PARAMETER_VALUE_OFF;
+const char * const AudioParameter::valueListSeparator = AUDIO_PARAMETER_VALUE_LIST_SEPARATOR;
+const char * const AudioParameter::keyReconfigA2dp = AUDIO_PARAMETER_RECONFIG_A2DP;
+const char * const AudioParameter::keyReconfigA2dpSupported = AUDIO_PARAMETER_A2DP_RECONFIG_SUPPORTED;
+
+AudioParameter::AudioParameter(const String8& keyValuePairs)
+{
+ char *str = new char[keyValuePairs.length()+1];
+ mKeyValuePairs = keyValuePairs;
+ char *last;
+
+ strcpy(str, keyValuePairs.string());
+ char *pair = strtok_r(str, ";", &last);
+ while (pair != NULL) {
+ if (strlen(pair) != 0) {
+ size_t eqIdx = strcspn(pair, "=");
+ String8 key = String8(pair, eqIdx);
+ String8 value;
+ if (eqIdx == strlen(pair)) {
+ value = String8("");
+ } else {
+ value = String8(pair + eqIdx + 1);
+ }
+ if (mParameters.indexOfKey(key) < 0) {
+ mParameters.add(key, value);
+ } else {
+ mParameters.replaceValueFor(key, value);
+ }
+ } else {
+ ALOGV("AudioParameter() cstor empty key value pair");
+ }
+ pair = strtok_r(NULL, ";", &last);
+ }
+
+ delete[] str;
+}
+
+AudioParameter::~AudioParameter()
+{
+ mParameters.clear();
+}
+
+String8 AudioParameter::toStringImpl(bool useValues) const
+{
+ String8 str = String8("");
+
+ size_t size = mParameters.size();
+ for (size_t i = 0; i < size; i++) {
+ str += mParameters.keyAt(i);
+ if (useValues) {
+ str += "=";
+ str += mParameters.valueAt(i);
+ }
+ if (i < (size - 1)) str += ";";
+ }
+ return str;
+}
+
+status_t AudioParameter::add(const String8& key, const String8& value)
+{
+ if (mParameters.indexOfKey(key) < 0) {
+ mParameters.add(key, value);
+ return NO_ERROR;
+ } else {
+ mParameters.replaceValueFor(key, value);
+ return ALREADY_EXISTS;
+ }
+}
+
+status_t AudioParameter::addKey(const String8& key)
+{
+ return add(key, String8());
+}
+
+status_t AudioParameter::addInt(const String8& key, const int value)
+{
+ char str[12];
+ if (snprintf(str, 12, "%d", value) > 0) {
+ String8 str8 = String8(str);
+ return add(key, str8);
+ } else {
+ return BAD_VALUE;
+ }
+}
+
+status_t AudioParameter::addFloat(const String8& key, const float value)
+{
+ char str[23];
+ if (snprintf(str, 23, "%.10f", value) > 0) {
+ String8 str8 = String8(str);
+ return add(key, str8);
+ } else {
+ return BAD_VALUE;
+ }
+}
+
+status_t AudioParameter::remove(const String8& key)
+{
+ if (mParameters.indexOfKey(key) >= 0) {
+ mParameters.removeItem(key);
+ return NO_ERROR;
+ } else {
+ return BAD_VALUE;
+ }
+}
+
+status_t AudioParameter::get(const String8& key, String8& value) const
+{
+ if (mParameters.indexOfKey(key) >= 0) {
+ value = mParameters.valueFor(key);
+ return NO_ERROR;
+ } else {
+ return BAD_VALUE;
+ }
+}
+
+status_t AudioParameter::getInt(const String8& key, int& value) const
+{
+ String8 str8;
+ status_t result = get(key, str8);
+ value = 0;
+ if (result == NO_ERROR) {
+ int val;
+ if (sscanf(str8.string(), "%d", &val) == 1) {
+ value = val;
+ } else {
+ result = INVALID_OPERATION;
+ }
+ }
+ return result;
+}
+
+status_t AudioParameter::getFloat(const String8& key, float& value) const
+{
+ String8 str8;
+ status_t result = get(key, str8);
+ value = 0;
+ if (result == NO_ERROR) {
+ float val;
+ if (sscanf(str8.string(), "%f", &val) == 1) {
+ value = val;
+ } else {
+ result = INVALID_OPERATION;
+ }
+ }
+ return result;
+}
+
+status_t AudioParameter::getAt(size_t index, String8& key) const
+{
+ if (mParameters.size() > index) {
+ key = mParameters.keyAt(index);
+ return NO_ERROR;
+ } else {
+ return BAD_VALUE;
+ }
+}
+
+status_t AudioParameter::getAt(size_t index, String8& key, String8& value) const
+{
+ if (mParameters.size() > index) {
+ key = mParameters.keyAt(index);
+ value = mParameters.valueAt(index);
+ return NO_ERROR;
+ } else {
+ return BAD_VALUE;
+ }
+}
+
+} // namespace android
diff --git a/media/libmediahelper/TypeConverter.cpp b/media/libmediahelper/TypeConverter.cpp
new file mode 100644
index 0000000..6382ce4
--- /dev/null
+++ b/media/libmediahelper/TypeConverter.cpp
@@ -0,0 +1,494 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <media/TypeConverter.h>
+
+namespace android {
+
+#define MAKE_STRING_FROM_ENUM(string) { #string, string }
+#define TERMINATOR { .literal = nullptr }
+
+template <>
+const OutputDeviceConverter::Table OutputDeviceConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_NONE),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_EARPIECE),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_SPEAKER),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_SPEAKER_SAFE),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADSET),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADPHONE),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_SCO),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_ALL_SCO),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_ALL_A2DP),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_AUX_DIGITAL),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_HDMI),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_USB_ACCESSORY),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_USB_DEVICE),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_ALL_USB),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_REMOTE_SUBMIX),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_TELEPHONY_TX),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_LINE),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_HDMI_ARC),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_SPDIF),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_FM),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_AUX_LINE),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_IP),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BUS),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_PROXY),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_USB_HEADSET),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_HEARING_AID),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_ECHO_CANCELLER),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_DEFAULT),
+ // STUB must be after DEFAULT, so the latter is picked up by toString first.
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_STUB),
+ TERMINATOR
+};
+
+template <>
+const InputDeviceConverter::Table InputDeviceConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_NONE),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_COMMUNICATION),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_AMBIENT),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BUILTIN_MIC),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_ALL_SCO),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_WIRED_HEADSET),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_AUX_DIGITAL),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_HDMI),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_HDMI_ARC),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_TELEPHONY_RX),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_VOICE_CALL),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BACK_MIC),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_REMOTE_SUBMIX),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_USB_ACCESSORY),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_USB_DEVICE),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_ALL_USB),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_FM_TUNER),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_TV_TUNER),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_LINE),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_SPDIF),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_A2DP),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_LOOPBACK),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_IP),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BUS),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_PROXY),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_USB_HEADSET),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_BLE),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_ECHO_REFERENCE),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_DEFAULT),
+ // STUB must be after DEFAULT, so the latter is picked up by toString first.
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_STUB),
+ TERMINATOR
+};
+
+
+template <>
+const OutputFlagConverter::Table OutputFlagConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_NONE),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_DIRECT),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_PRIMARY),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_FAST),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_DEEP_BUFFER),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_NON_BLOCKING),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_HW_AV_SYNC),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_TTS),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_RAW),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_SYNC),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_DIRECT_PCM),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_VOIP_RX),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_INCALL_MUSIC),
+ TERMINATOR
+};
+
+
+template <>
+const InputFlagConverter::Table InputFlagConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_NONE),
+ MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_FAST),
+ MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_HW_HOTWORD),
+ MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_RAW),
+ MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_SYNC),
+ MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_MMAP_NOIRQ),
+ MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_VOIP_TX),
+ MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_HW_AV_SYNC),
+ MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_DIRECT),
+ TERMINATOR
+};
+
+
+template <>
+const FormatConverter::Table FormatConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_PCM_16_BIT),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_PCM_8_BIT),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_PCM_32_BIT),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_PCM_8_24_BIT),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_PCM_FLOAT),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_PCM_24_BIT_PACKED),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_MP3),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AMR_NB),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AMR_WB),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_MAIN),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_LC),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_SSR),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_LTP),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_HE_V1),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_SCALABLE),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ERLC),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_LD),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_HE_V2),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ELD),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_XHE),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ADTS_MAIN),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ADTS_LC),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ADTS_SSR),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ADTS_LTP),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ADTS_HE_V1),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ADTS_SCALABLE),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ADTS_ERLC),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ADTS_LD),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ADTS_HE_V2),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ADTS_ELD),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ADTS_XHE),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_VORBIS),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_HE_AAC_V1),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_HE_AAC_V2),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_OPUS),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AC3),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_E_AC3),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_DTS),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_DTS_HD),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_IEC61937),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_DOLBY_TRUEHD),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_EVRC),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_EVRCB),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_EVRCWB),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_EVRCNW),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ADIF),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_WMA),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_WMA_PRO),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AMR_WB_PLUS),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_MP2),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_QCELP),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_DSD),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_FLAC),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_ALAC),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_APE),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ADTS),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_SBC),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_APTX),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_APTX_HD),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AC4),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_LDAC),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_MAT),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_E_AC3_JOC),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_MAT_1_0),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_MAT_2_0),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_MAT_2_1),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_LATM),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_LATM_LC),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_LATM_HE_V1),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_LATM_HE_V2),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_CELT),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_APTX_ADAPTIVE),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_LHDC),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_LHDC_LL),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_APTX_TWSP),
+ TERMINATOR
+};
+
+
+template <>
+const OutputChannelConverter::Table OutputChannelConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_MONO),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_STEREO),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_2POINT1),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_2POINT0POINT2),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_2POINT1POINT2),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_TRI),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_TRI_BACK),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_3POINT1),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_3POINT0POINT2),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_3POINT1POINT2),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_QUAD),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_QUAD_BACK),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_QUAD_SIDE),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_SURROUND),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_PENTA),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_5POINT1),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_5POINT1_BACK),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_5POINT1_SIDE),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_5POINT1POINT2),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_5POINT1POINT4),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_6POINT1),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_7POINT1POINT2),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_7POINT1POINT4),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_HAPTIC_A),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_MONO_HAPTIC_A),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_STEREO_HAPTIC_A),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_HAPTIC_AB),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_MONO_HAPTIC_AB),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_STEREO_HAPTIC_AB),
+ TERMINATOR
+};
+
+
+template <>
+const InputChannelConverter::Table InputChannelConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_MONO),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_STEREO),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_FRONT_BACK),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_6),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_2POINT0POINT2),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_2POINT1POINT2),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_3POINT0POINT2),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_3POINT1POINT2),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_5POINT1),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_VOICE_CALL_MONO),
+ TERMINATOR
+};
+
+template <>
+const ChannelIndexConverter::Table ChannelIndexConverter::mTable[] = {
+ {"AUDIO_CHANNEL_INDEX_MASK_1", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_1)},
+ {"AUDIO_CHANNEL_INDEX_MASK_2", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_2)},
+ {"AUDIO_CHANNEL_INDEX_MASK_3", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_3)},
+ {"AUDIO_CHANNEL_INDEX_MASK_4", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_4)},
+ {"AUDIO_CHANNEL_INDEX_MASK_5", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_5)},
+ {"AUDIO_CHANNEL_INDEX_MASK_6", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_6)},
+ {"AUDIO_CHANNEL_INDEX_MASK_7", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_7)},
+ {"AUDIO_CHANNEL_INDEX_MASK_8", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_8)},
+ TERMINATOR
+};
+
+
+template <>
+const GainModeConverter::Table GainModeConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(AUDIO_GAIN_MODE_JOINT),
+ MAKE_STRING_FROM_ENUM(AUDIO_GAIN_MODE_CHANNELS),
+ MAKE_STRING_FROM_ENUM(AUDIO_GAIN_MODE_RAMP),
+ TERMINATOR
+};
+
+
+template <>
+const StreamTypeConverter::Table StreamTypeConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_DEFAULT),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_VOICE_CALL),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_SYSTEM),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_RING),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_MUSIC),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_ALARM),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_NOTIFICATION),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_BLUETOOTH_SCO ),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_ENFORCED_AUDIBLE),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_DTMF),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_TTS),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_ACCESSIBILITY),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_ASSISTANT),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_REROUTING),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_PATCH),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_CALL_ASSISTANT),
+ TERMINATOR
+};
+
+template<>
+const AudioModeConverter::Table AudioModeConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(AUDIO_MODE_INVALID),
+ MAKE_STRING_FROM_ENUM(AUDIO_MODE_CURRENT),
+ MAKE_STRING_FROM_ENUM(AUDIO_MODE_NORMAL),
+ MAKE_STRING_FROM_ENUM(AUDIO_MODE_RINGTONE),
+ MAKE_STRING_FROM_ENUM(AUDIO_MODE_IN_CALL),
+ MAKE_STRING_FROM_ENUM(AUDIO_MODE_IN_COMMUNICATION),
+ MAKE_STRING_FROM_ENUM(AUDIO_MODE_CALL_SCREEN),
+ TERMINATOR
+};
+
+template<>
+const AudioContentTypeConverter::Table AudioContentTypeConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(AUDIO_CONTENT_TYPE_UNKNOWN),
+ MAKE_STRING_FROM_ENUM(AUDIO_CONTENT_TYPE_SPEECH),
+ MAKE_STRING_FROM_ENUM(AUDIO_CONTENT_TYPE_MUSIC),
+ MAKE_STRING_FROM_ENUM(AUDIO_CONTENT_TYPE_MOVIE),
+ MAKE_STRING_FROM_ENUM(AUDIO_CONTENT_TYPE_SONIFICATION),
+ TERMINATOR
+};
+
+template <>
+const UsageTypeConverter::Table UsageTypeConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(AUDIO_USAGE_UNKNOWN),
+ MAKE_STRING_FROM_ENUM(AUDIO_USAGE_MEDIA),
+ MAKE_STRING_FROM_ENUM(AUDIO_USAGE_VOICE_COMMUNICATION),
+ MAKE_STRING_FROM_ENUM(AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING),
+ MAKE_STRING_FROM_ENUM(AUDIO_USAGE_ALARM),
+ MAKE_STRING_FROM_ENUM(AUDIO_USAGE_NOTIFICATION),
+ MAKE_STRING_FROM_ENUM(AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE),
+ MAKE_STRING_FROM_ENUM(AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST),
+ MAKE_STRING_FROM_ENUM(AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT),
+ MAKE_STRING_FROM_ENUM(AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED),
+ MAKE_STRING_FROM_ENUM(AUDIO_USAGE_NOTIFICATION_EVENT),
+ MAKE_STRING_FROM_ENUM(AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY),
+ MAKE_STRING_FROM_ENUM(AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE),
+ MAKE_STRING_FROM_ENUM(AUDIO_USAGE_ASSISTANCE_SONIFICATION),
+ MAKE_STRING_FROM_ENUM(AUDIO_USAGE_GAME),
+ MAKE_STRING_FROM_ENUM(AUDIO_USAGE_VIRTUAL_SOURCE),
+ MAKE_STRING_FROM_ENUM(AUDIO_USAGE_ASSISTANT),
+ MAKE_STRING_FROM_ENUM(AUDIO_USAGE_CALL_ASSISTANT),
+ MAKE_STRING_FROM_ENUM(AUDIO_USAGE_EMERGENCY),
+ MAKE_STRING_FROM_ENUM(AUDIO_USAGE_SAFETY),
+ MAKE_STRING_FROM_ENUM(AUDIO_USAGE_VEHICLE_STATUS),
+ MAKE_STRING_FROM_ENUM(AUDIO_USAGE_ANNOUNCEMENT),
+ TERMINATOR
+};
+
+template <>
+const SourceTypeConverter::Table SourceTypeConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_DEFAULT),
+ MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_MIC),
+ MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_VOICE_UPLINK),
+ MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_VOICE_DOWNLINK),
+ MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_VOICE_CALL),
+ MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_CAMCORDER),
+ MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_VOICE_RECOGNITION),
+ MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_VOICE_COMMUNICATION),
+ MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_REMOTE_SUBMIX),
+ MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_UNPROCESSED),
+ MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_VOICE_PERFORMANCE),
+ MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_ECHO_REFERENCE),
+ MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_FM_TUNER),
+ MAKE_STRING_FROM_ENUM(AUDIO_SOURCE_HOTWORD),
+ TERMINATOR
+};
+
+template <>
+const AudioFlagConverter::Table AudioFlagConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(AUDIO_FLAG_NONE),
+ MAKE_STRING_FROM_ENUM(AUDIO_FLAG_AUDIBILITY_ENFORCED),
+ MAKE_STRING_FROM_ENUM(AUDIO_FLAG_SECURE),
+ MAKE_STRING_FROM_ENUM(AUDIO_FLAG_SCO),
+ MAKE_STRING_FROM_ENUM(AUDIO_FLAG_BEACON),
+ MAKE_STRING_FROM_ENUM(AUDIO_FLAG_HW_AV_SYNC),
+ MAKE_STRING_FROM_ENUM(AUDIO_FLAG_HW_HOTWORD),
+ MAKE_STRING_FROM_ENUM(AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY),
+ MAKE_STRING_FROM_ENUM(AUDIO_FLAG_BYPASS_MUTE),
+ MAKE_STRING_FROM_ENUM(AUDIO_FLAG_LOW_LATENCY),
+ MAKE_STRING_FROM_ENUM(AUDIO_FLAG_DEEP_BUFFER),
+ MAKE_STRING_FROM_ENUM(AUDIO_FLAG_NO_MEDIA_PROJECTION),
+ MAKE_STRING_FROM_ENUM(AUDIO_FLAG_MUTE_HAPTIC),
+ MAKE_STRING_FROM_ENUM(AUDIO_FLAG_NO_SYSTEM_CAPTURE),
+ MAKE_STRING_FROM_ENUM(AUDIO_FLAG_CAPTURE_PRIVATE),
+ TERMINATOR
+};
+
+template class TypeConverter<OutputDeviceTraits>;
+template class TypeConverter<InputDeviceTraits>;
+template class TypeConverter<OutputFlagTraits>;
+template class TypeConverter<InputFlagTraits>;
+template class TypeConverter<FormatTraits>;
+template class TypeConverter<OutputChannelTraits>;
+template class TypeConverter<InputChannelTraits>;
+template class TypeConverter<ChannelIndexTraits>;
+template class TypeConverter<GainModeTraits>;
+template class TypeConverter<StreamTraits>;
+template class TypeConverter<AudioModeTraits>;
+template class TypeConverter<UsageTraits>;
+template class TypeConverter<SourceTraits>;
+template class TypeConverter<AudioFlagTraits>;
+
+bool deviceFromString(const std::string& literalDevice, audio_devices_t& device) {
+ return InputDeviceConverter::fromString(literalDevice, device) ||
+ OutputDeviceConverter::fromString(literalDevice, device);
+}
+
+SampleRateTraits::Collection samplingRatesFromString(
+ const std::string &samplingRates, const char *del)
+{
+ SampleRateTraits::Collection samplingRateCollection;
+ collectionFromString<SampleRateTraits>(samplingRates, samplingRateCollection, del);
+ return samplingRateCollection;
+}
+
+FormatTraits::Collection formatsFromString(
+ const std::string &formats, const char *del)
+{
+ FormatTraits::Collection formatCollection;
+ FormatConverter::collectionFromString(formats, formatCollection, del);
+ return formatCollection;
+}
+
+audio_format_t formatFromString(const std::string &literalFormat, audio_format_t defaultFormat)
+{
+ audio_format_t format;
+ if (literalFormat.empty()) {
+ return defaultFormat;
+ }
+ FormatConverter::fromString(literalFormat, format);
+ return format;
+}
+
+audio_channel_mask_t channelMaskFromString(const std::string &literalChannels)
+{
+ audio_channel_mask_t channels;
+ if (!OutputChannelConverter::fromString(literalChannels, channels) &&
+ !InputChannelConverter::fromString(literalChannels, channels)) {
+ return AUDIO_CHANNEL_INVALID;
+ }
+ return channels;
+}
+
+ChannelTraits::Collection channelMasksFromString(
+ const std::string &channels, const char *del)
+{
+ ChannelTraits::Collection channelMaskCollection;
+ OutputChannelConverter::collectionFromString(channels, channelMaskCollection, del);
+ InputChannelConverter::collectionFromString(channels, channelMaskCollection, del);
+ ChannelIndexConverter::collectionFromString(channels, channelMaskCollection, del);
+ return channelMaskCollection;
+}
+
+InputChannelTraits::Collection inputChannelMasksFromString(
+ const std::string &inChannels, const char *del)
+{
+ InputChannelTraits::Collection inputChannelMaskCollection;
+ InputChannelConverter::collectionFromString(inChannels, inputChannelMaskCollection, del);
+ ChannelIndexConverter::collectionFromString(inChannels, inputChannelMaskCollection, del);
+ return inputChannelMaskCollection;
+}
+
+OutputChannelTraits::Collection outputChannelMasksFromString(
+ const std::string &outChannels, const char *del)
+{
+ OutputChannelTraits::Collection outputChannelMaskCollection;
+ OutputChannelConverter::collectionFromString(outChannels, outputChannelMaskCollection, del);
+ ChannelIndexConverter::collectionFromString(outChannels, outputChannelMaskCollection, del);
+ return outputChannelMaskCollection;
+}
+
+}; // namespace android
diff --git a/media/libmediahelper/include/media/AudioParameter.h b/media/libmediahelper/include/media/AudioParameter.h
new file mode 100644
index 0000000..3c190f2
--- /dev/null
+++ b/media/libmediahelper/include/media/AudioParameter.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2008-2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIOPARAMETER_H_
+#define ANDROID_AUDIOPARAMETER_H_
+
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+
+namespace android {
+
+class AudioParameter {
+
+public:
+ AudioParameter() {}
+ AudioParameter(const String8& keyValuePairs);
+ virtual ~AudioParameter();
+
+ // reserved parameter keys for changing standard parameters with setParameters() function.
+ // Using these keys is mandatory for AudioFlinger to properly monitor audio output/input
+ // configuration changes and act accordingly.
+ // keyRouting: to change audio routing, value is an int in audio_devices_t
+ // keySamplingRate: to change sampling rate routing, value is an int
+ // keyFormat: to change audio format, value is an int in audio_format_t
+ // keyChannels: to change audio channel configuration, value is an int in audio_channels_t
+ // keyFrameCount: to change audio output frame count, value is an int
+ // keyInputSource: to change audio input source, value is an int in audio_source_t
+ // (defined in media/mediarecorder.h)
+ // keyScreenState: either "on" or "off"
+ static const char * const keyRouting;
+ static const char * const keySamplingRate;
+ static const char * const keyFormat;
+ static const char * const keyChannels;
+ static const char * const keyFrameCount;
+ static const char * const keyInputSource;
+ static const char * const keyScreenState;
+
+ // keyBtNrec: BT SCO Noise Reduction + Echo Cancellation parameters
+ // keyHwAvSync: get HW synchronization source identifier from a device
+ // keyMonoOutput: Enable mono audio playback
+ // keyStreamHwAvSync: set HW synchronization source identifier on a stream
+ static const char * const keyBtNrec;
+ static const char * const keyHwAvSync;
+ static const char * const keyMonoOutput;
+ static const char * const keyStreamHwAvSync;
+
+ // keys for presentation selection
+ // keyPresentationId: Audio presentation identifier
+ // keyProgramId: Audio presentation program identifier
+ static const char * const keyPresentationId;
+ static const char * const keyProgramId;
+
+ // keyAudioLanguagePreferred: Preferred audio language
+ static const char * const keyAudioLanguagePreferred;
+
+ // keyDeviceConnect / Disconnect: value is an int in audio_devices_t
+ static const char * const keyDeviceConnect;
+ static const char * const keyDeviceDisconnect;
+ // Need to be here because vendors still use them.
+ static const char * const keyStreamConnect; // Deprecated: DO NOT USE.
+ static const char * const keyStreamDisconnect; // Deprecated: DO NOT USE.
+
+ // For querying stream capabilities. All the returned values are lists.
+ // keyStreamSupportedFormats: audio_format_t
+ // keyStreamSupportedChannels: audio_channel_mask_t
+ // keyStreamSupportedSamplingRates: sampling rate values
+ static const char * const keyStreamSupportedFormats;
+ static const char * const keyStreamSupportedChannels;
+ static const char * const keyStreamSupportedSamplingRates;
+
+ static const char * const valueOn;
+ static const char * const valueOff;
+
+ static const char * const valueListSeparator;
+
+ // keyReconfigA2dp: Ask HwModule to reconfigure A2DP offloaded codec
+ // keyReconfigA2dpSupported: Query if HwModule supports A2DP offload codec config
+ static const char * const keyReconfigA2dp;
+ static const char * const keyReconfigA2dpSupported;
+
+ String8 toString() const { return toStringImpl(true); }
+ String8 keysToString() const { return toStringImpl(false); }
+
+ status_t add(const String8& key, const String8& value);
+ status_t addInt(const String8& key, const int value);
+ status_t addKey(const String8& key);
+ status_t addFloat(const String8& key, const float value);
+
+ status_t remove(const String8& key);
+
+ status_t get(const String8& key, String8& value) const;
+ status_t getInt(const String8& key, int& value) const;
+ status_t getFloat(const String8& key, float& value) const;
+ status_t getAt(size_t index, String8& key) const;
+ status_t getAt(size_t index, String8& key, String8& value) const;
+
+ size_t size() const { return mParameters.size(); }
+
+private:
+ String8 mKeyValuePairs;
+ KeyedVector <String8, String8> mParameters;
+
+ String8 toStringImpl(bool useValues) const;
+};
+
+}; // namespace android
+
+#endif /*ANDROID_AUDIOPARAMETER_H_*/
diff --git a/media/libmediahelper/include/media/TypeConverter.h b/media/libmediahelper/include/media/TypeConverter.h
new file mode 100644
index 0000000..011498a
--- /dev/null
+++ b/media/libmediahelper/include/media/TypeConverter.h
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_TYPE_CONVERTER_H_
+#define ANDROID_TYPE_CONVERTER_H_
+
+#include <set>
+#include <string>
+#include <string.h>
+#include <vector>
+
+#include <system/audio.h>
+#include <utils/Log.h>
+#include <utils/Vector.h>
+#include <utils/SortedVector.h>
+
+#include <media/AudioParameter.h>
+#include "convert.h"
+
+namespace android {
+
+template <typename T>
+struct DefaultTraits
+{
+ typedef T Type;
+ typedef std::vector<Type> Collection;
+ static void add(Collection &collection, Type value)
+ {
+ collection.push_back(value);
+ }
+};
+template <typename T>
+struct SortedVectorTraits
+{
+ typedef T Type;
+ typedef SortedVector<Type> Collection;
+ static void add(Collection &collection, Type value)
+ {
+ collection.add(value);
+ }
+};
+template <typename T>
+struct SetTraits
+{
+ typedef T Type;
+ typedef std::set<Type> Collection;
+ static void add(Collection &collection, Type value)
+ {
+ collection.insert(value);
+ }
+};
+
+using SampleRateTraits = SetTraits<uint32_t>;
+using DeviceTraits = DefaultTraits<audio_devices_t>;
+struct OutputDeviceTraits : public DeviceTraits {};
+struct InputDeviceTraits : public DeviceTraits {};
+using ChannelTraits = SetTraits<audio_channel_mask_t>;
+struct OutputChannelTraits : public ChannelTraits {};
+struct InputChannelTraits : public ChannelTraits {};
+struct ChannelIndexTraits : public ChannelTraits {};
+using InputFlagTraits = DefaultTraits<audio_input_flags_t>;
+using OutputFlagTraits = DefaultTraits<audio_output_flags_t>;
+using FormatTraits = DefaultTraits<audio_format_t>;
+using GainModeTraits = DefaultTraits<audio_gain_mode_t>;
+using StreamTraits = DefaultTraits<audio_stream_type_t>;
+using AudioModeTraits = DefaultTraits<audio_mode_t>;
+using AudioContentTraits = DefaultTraits<audio_content_type_t>;
+using UsageTraits = DefaultTraits<audio_usage_t>;
+using SourceTraits = DefaultTraits<audio_source_t>;
+struct AudioFlagTraits : public DefaultTraits<audio_flags_mask_t> {};
+
+template <class Traits>
+static void collectionFromString(const std::string &str, typename Traits::Collection &collection,
+ const char *del = AudioParameter::valueListSeparator)
+{
+ char *literal = strdup(str.c_str());
+ for (const char *cstr = strtok(literal, del); cstr != NULL; cstr = strtok(NULL, del)) {
+ typename Traits::Type value;
+ if (utilities::convertTo<std::string, typename Traits::Type >(cstr, value)) {
+ Traits::add(collection, value);
+ }
+ }
+ free(literal);
+}
+
+template <class Traits>
+class TypeConverter
+{
+public:
+ static bool toString(const typename Traits::Type &value, std::string &str);
+
+ static bool fromString(const std::string &str, typename Traits::Type &result);
+
+ static void collectionFromString(const std::string &str,
+ typename Traits::Collection &collection,
+ const char *del = AudioParameter::valueListSeparator);
+
+ static uint32_t maskFromString(
+ const std::string &str, const char *del = AudioParameter::valueListSeparator);
+
+ static void maskToString(
+ uint32_t mask, std::string &str, const char *del = AudioParameter::valueListSeparator);
+
+protected:
+ struct Table {
+ const char *literal;
+ typename Traits::Type value;
+ };
+
+ static const Table mTable[];
+};
+
+template <class Traits>
+inline bool TypeConverter<Traits>::toString(const typename Traits::Type &value, std::string &str)
+{
+ for (size_t i = 0; mTable[i].literal; i++) {
+ if (mTable[i].value == value) {
+ str = mTable[i].literal;
+ return true;
+ }
+ }
+ char result[64];
+ snprintf(result, sizeof(result), "Unknown enum value %d", value);
+ str = result;
+ return false;
+}
+
+template <class Traits>
+inline bool TypeConverter<Traits>::fromString(const std::string &str, typename Traits::Type &result)
+{
+ for (size_t i = 0; mTable[i].literal; i++) {
+ if (strcmp(mTable[i].literal, str.c_str()) == 0) {
+ ALOGV("stringToEnum() found %s", mTable[i].literal);
+ result = mTable[i].value;
+ return true;
+ }
+ }
+ return false;
+}
+
+template <class Traits>
+inline void TypeConverter<Traits>::collectionFromString(const std::string &str,
+ typename Traits::Collection &collection,
+ const char *del)
+{
+ char *literal = strdup(str.c_str());
+
+ for (const char *cstr = strtok(literal, del); cstr != NULL; cstr = strtok(NULL, del)) {
+ typename Traits::Type value;
+ if (fromString(cstr, value)) {
+ Traits::add(collection, value);
+ }
+ }
+ free(literal);
+}
+
+template <class Traits>
+inline uint32_t TypeConverter<Traits>::maskFromString(const std::string &str, const char *del)
+{
+ char *literal = strdup(str.c_str());
+ uint32_t value = 0;
+ for (const char *cstr = strtok(literal, del); cstr != NULL; cstr = strtok(NULL, del)) {
+ typename Traits::Type type;
+ if (fromString(cstr, type)) {
+ value |= static_cast<uint32_t>(type);
+ }
+ }
+ free(literal);
+ return value;
+}
+
+template <class Traits>
+inline void TypeConverter<Traits>::maskToString(uint32_t mask, std::string &str, const char *del)
+{
+ if (mask != 0) {
+ bool first_flag = true;
+ for (size_t i = 0; mTable[i].literal; i++) {
+ uint32_t value = static_cast<uint32_t>(mTable[i].value);
+ if (mTable[i].value != 0 && ((mask & value) == value)) {
+ if (!first_flag) str += del;
+ first_flag = false;
+ str += mTable[i].literal;
+ }
+ }
+ } else {
+ toString(static_cast<typename Traits::Type>(0), str);
+ }
+}
+
+typedef TypeConverter<OutputDeviceTraits> OutputDeviceConverter;
+typedef TypeConverter<InputDeviceTraits> InputDeviceConverter;
+typedef TypeConverter<OutputFlagTraits> OutputFlagConverter;
+typedef TypeConverter<InputFlagTraits> InputFlagConverter;
+typedef TypeConverter<FormatTraits> FormatConverter;
+typedef TypeConverter<OutputChannelTraits> OutputChannelConverter;
+typedef TypeConverter<InputChannelTraits> InputChannelConverter;
+typedef TypeConverter<ChannelIndexTraits> ChannelIndexConverter;
+typedef TypeConverter<GainModeTraits> GainModeConverter;
+typedef TypeConverter<StreamTraits> StreamTypeConverter;
+typedef TypeConverter<AudioModeTraits> AudioModeConverter;
+typedef TypeConverter<AudioContentTraits> AudioContentTypeConverter;
+typedef TypeConverter<UsageTraits> UsageTypeConverter;
+typedef TypeConverter<SourceTraits> SourceTypeConverter;
+typedef TypeConverter<AudioFlagTraits> AudioFlagConverter;
+
+template<> const OutputDeviceConverter::Table OutputDeviceConverter::mTable[];
+template<> const InputDeviceConverter::Table InputDeviceConverter::mTable[];
+template<> const OutputFlagConverter::Table OutputFlagConverter::mTable[];
+template<> const InputFlagConverter::Table InputFlagConverter::mTable[];
+template<> const FormatConverter::Table FormatConverter::mTable[];
+template<> const OutputChannelConverter::Table OutputChannelConverter::mTable[];
+template<> const InputChannelConverter::Table InputChannelConverter::mTable[];
+template<> const ChannelIndexConverter::Table ChannelIndexConverter::mTable[];
+template<> const GainModeConverter::Table GainModeConverter::mTable[];
+template<> const StreamTypeConverter::Table StreamTypeConverter::mTable[];
+template<> const AudioModeConverter::Table AudioModeConverter::mTable[];
+template<> const AudioContentTypeConverter::Table AudioContentTypeConverter::mTable[];
+template<> const UsageTypeConverter::Table UsageTypeConverter::mTable[];
+template<> const SourceTypeConverter::Table SourceTypeConverter::mTable[];
+template<> const AudioFlagConverter::Table AudioFlagConverter::mTable[];
+
+bool deviceFromString(const std::string& literalDevice, audio_devices_t& device);
+
+SampleRateTraits::Collection samplingRatesFromString(
+ const std::string &samplingRates, const char *del = AudioParameter::valueListSeparator);
+
+FormatTraits::Collection formatsFromString(
+ const std::string &formats, const char *del = AudioParameter::valueListSeparator);
+
+audio_format_t formatFromString(
+ const std::string &literalFormat, audio_format_t defaultFormat = AUDIO_FORMAT_DEFAULT);
+
+audio_channel_mask_t channelMaskFromString(const std::string &literalChannels);
+
+ChannelTraits::Collection channelMasksFromString(
+ const std::string &channels, const char *del = AudioParameter::valueListSeparator);
+
+InputChannelTraits::Collection inputChannelMasksFromString(
+ const std::string &inChannels, const char *del = AudioParameter::valueListSeparator);
+
+OutputChannelTraits::Collection outputChannelMasksFromString(
+ const std::string &outChannels, const char *del = AudioParameter::valueListSeparator);
+
+// counting enumerations
+template <typename T, std::enable_if_t<std::is_same<T, audio_content_type_t>::value
+ || std::is_same<T, audio_mode_t>::value
+ || std::is_same<T, audio_source_t>::value
+ || std::is_same<T, audio_stream_type_t>::value
+ || std::is_same<T, audio_usage_t>::value
+ || std::is_same<T, audio_format_t>::value
+ , int> = 0>
+static inline std::string toString(const T& value)
+{
+ std::string result;
+ return TypeConverter<DefaultTraits<T>>::toString(value, result)
+ ? result : std::to_string(static_cast<int>(value));
+
+}
+
+// flag enumerations
+template <typename T, std::enable_if_t<std::is_same<T, audio_gain_mode_t>::value
+ || std::is_same<T, audio_input_flags_t>::value
+ || std::is_same<T, audio_output_flags_t>::value
+ , int> = 0>
+static inline std::string toString(const T& value)
+{
+ std::string result;
+ TypeConverter<DefaultTraits<T>>::maskToString(value, result);
+ return result;
+}
+
+static inline std::string toString(const audio_devices_t& devices)
+{
+ std::string result;
+ if ((devices & AUDIO_DEVICE_BIT_IN) != 0) {
+ InputDeviceConverter::maskToString(devices, result);
+ } else {
+ OutputDeviceConverter::maskToString(devices, result);
+ }
+ return result;
+}
+
+static inline std::string toString(const audio_attributes_t& attributes)
+{
+ std::ostringstream result;
+ result << "{ Content type: " << toString(attributes.content_type)
+ << " Usage: " << toString(attributes.usage)
+ << " Source: " << toString(attributes.source)
+ << std::hex << " Flags: 0x" << attributes.flags
+ << std::dec << " Tags: " << attributes.tags
+ << " }";
+
+ return result.str();
+}
+
+}; // namespace android
+
+#endif /*ANDROID_TYPE_CONVERTER_H_*/
diff --git a/media/libmedia/include/media/convert.h b/media/libmediahelper/include/media/convert.h
similarity index 100%
rename from media/libmedia/include/media/convert.h
rename to media/libmediahelper/include/media/convert.h
diff --git a/media/libmediametrics/Android.bp b/media/libmediametrics/Android.bp
index 15ea578..0cd5194 100644
--- a/media/libmediametrics/Android.bp
+++ b/media/libmediametrics/Android.bp
@@ -1,9 +1,14 @@
+cc_library_headers {
+ name: "libmediametrics_headers",
+ export_include_dirs: ["include"],
+}
+
cc_library_shared {
name: "libmediametrics",
srcs: [
- "IMediaAnalyticsService.cpp",
- "MediaAnalyticsItem.cpp",
+ "IMediaMetricsService.cpp",
+ "MediaMetricsItem.cpp",
"MediaMetrics.cpp",
],
@@ -37,6 +42,16 @@
"1" ,
]
},
+
+ header_abi_checker: {
+ enabled: true,
+ symbol_file: "libmediametrics.map.txt",
+ },
+
+ visibility: [
+ "//cts/tests/tests/nativemedia/mediametrics",
+ "//frameworks/av:__subpackages__",
+ "//frameworks/base/core/jni",
+ "//frameworks/base/media/jni",
+ ],
}
-
-
diff --git a/media/libmediametrics/IMediaAnalyticsService.cpp b/media/libmediametrics/IMediaAnalyticsService.cpp
deleted file mode 100644
index 9114927..0000000
--- a/media/libmediametrics/IMediaAnalyticsService.cpp
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "MediaAnalytics"
-
-#include <stdint.h>
-#include <inttypes.h>
-#include <sys/types.h>
-
-#include <binder/Parcel.h>
-#include <binder/IMemory.h>
-#include <binder/IPCThreadState.h>
-
-#include <utils/Errors.h> // for status_t
-#include <utils/List.h>
-#include <utils/Log.h>
-#include <utils/String8.h>
-
-#include <media/MediaAnalyticsItem.h>
-#include <media/IMediaAnalyticsService.h>
-
-#define DEBUGGING 0
-#define DEBUGGING_FLOW 0
-#define DEBUGGING_RETURNS 0
-
-namespace android {
-
-enum {
- GENERATE_UNIQUE_SESSIONID = IBinder::FIRST_CALL_TRANSACTION,
- SUBMIT_ITEM,
-};
-
-class BpMediaAnalyticsService: public BpInterface<IMediaAnalyticsService>
-{
-public:
- explicit BpMediaAnalyticsService(const sp<IBinder>& impl)
- : BpInterface<IMediaAnalyticsService>(impl)
- {
- }
-
- virtual MediaAnalyticsItem::SessionID_t generateUniqueSessionID() {
- Parcel data, reply;
- status_t err;
- MediaAnalyticsItem::SessionID_t sessionid =
- MediaAnalyticsItem::SessionIDInvalid;
-
- data.writeInterfaceToken(IMediaAnalyticsService::getInterfaceDescriptor());
- err = remote()->transact(GENERATE_UNIQUE_SESSIONID, data, &reply);
- if (err != NO_ERROR) {
- ALOGW("bad response from service for generateSessionId, err=%d", err);
- return MediaAnalyticsItem::SessionIDInvalid;
- }
- sessionid = reply.readInt64();
- if (DEBUGGING_RETURNS) {
- ALOGD("the caller gets a sessionid of %" PRId64 " back", sessionid);
- }
- return sessionid;
- }
-
- virtual MediaAnalyticsItem::SessionID_t submit(MediaAnalyticsItem *item, bool forcenew)
- {
- // have this record submit itself
- // this will be a binder call with appropriate timing
- // return value is the uuid that the system generated for it.
- // the return value 0 and -1 are reserved.
- // -1 to indicate that there was a problem recording...
-
- Parcel data, reply;
- status_t err;
-
- if (item == NULL) {
- return MediaAnalyticsItem::SessionIDInvalid;
- }
-
- data.writeInterfaceToken(IMediaAnalyticsService::getInterfaceDescriptor());
- if(DEBUGGING_FLOW) {
- ALOGD("client offers record: %s", item->toString().c_str());
- }
- data.writeBool(forcenew);
- item->writeToParcel(&data);
-
- err = remote()->transact(SUBMIT_ITEM, data, &reply);
- if (err != NO_ERROR) {
- ALOGW("bad response from service for submit, err=%d", err);
- return MediaAnalyticsItem::SessionIDInvalid;
- }
-
- // get an answer out of 'reply'
- int64_t sessionid = reply.readInt64();
- if (DEBUGGING_RETURNS) {
- ALOGD("the caller gets sessionid=%" PRId64 "", sessionid);
- }
- return sessionid;
- }
-
-};
-
-IMPLEMENT_META_INTERFACE(MediaAnalyticsService, "android.media.IMediaAnalyticsService");
-
-// ----------------------------------------------------------------------
-
-status_t BnMediaAnalyticsService::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
-
-
- // get calling pid/tid
- IPCThreadState *ipc = IPCThreadState::self();
- int clientPid = ipc->getCallingPid();
- // permission checking
-
- if(DEBUGGING_FLOW) {
- ALOGD("running in service, code %d, pid %d; called from pid %d",
- code, getpid(), clientPid);
- }
-
- switch (code) {
-
- case GENERATE_UNIQUE_SESSIONID: {
- CHECK_INTERFACE(IMediaAnalyticsService, data, reply);
-
- MediaAnalyticsItem::SessionID_t sessionid = generateUniqueSessionID();
- reply->writeInt64(sessionid);
-
- return NO_ERROR;
- } break;
-
- case SUBMIT_ITEM: {
- CHECK_INTERFACE(IMediaAnalyticsService, data, reply);
-
- bool forcenew;
- MediaAnalyticsItem *item = MediaAnalyticsItem::create();
-
- data.readBool(&forcenew);
- item->readFromParcel(data);
-
- item->setPid(clientPid);
-
- // submit() takes over ownership of 'item'
- MediaAnalyticsItem::SessionID_t sessionid = submit(item, forcenew);
- reply->writeInt64(sessionid);
-
- return NO_ERROR;
- } break;
-
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-// ----------------------------------------------------------------------------
-
-} // namespace android
diff --git a/media/libmediametrics/IMediaMetricsService.cpp b/media/libmediametrics/IMediaMetricsService.cpp
new file mode 100644
index 0000000..b5675e6
--- /dev/null
+++ b/media/libmediametrics/IMediaMetricsService.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MediaMetrics"
+
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+#include <binder/IMemory.h>
+#include <binder/IPCThreadState.h>
+
+#include <utils/Errors.h> // for status_t
+#include <utils/List.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include <media/MediaMetricsItem.h>
+#include <media/IMediaMetricsService.h>
+
+namespace android {
+
+// TODO: Currently ONE_WAY transactions, make both ONE_WAY and synchronous options.
+
+enum {
+ SUBMIT_ITEM = IBinder::FIRST_CALL_TRANSACTION,
+ SUBMIT_BUFFER,
+};
+
+class BpMediaMetricsService: public BpInterface<IMediaMetricsService>
+{
+public:
+ explicit BpMediaMetricsService(const sp<IBinder>& impl)
+ : BpInterface<IMediaMetricsService>(impl)
+ {
+ }
+
+ status_t submit(mediametrics::Item *item) override
+ {
+ if (item == nullptr) {
+ return BAD_VALUE;
+ }
+ ALOGV("%s: (ONEWAY) item=%s", __func__, item->toString().c_str());
+
+ Parcel data;
+ data.writeInterfaceToken(IMediaMetricsService::getInterfaceDescriptor());
+
+ status_t status = item->writeToParcel(&data);
+ if (status != NO_ERROR) { // assume failure logged in item
+ return status;
+ }
+
+ status = remote()->transact(
+ SUBMIT_ITEM, data, nullptr /* reply */, IBinder::FLAG_ONEWAY);
+ ALOGW_IF(status != NO_ERROR, "%s: bad response from service for submit, status=%d",
+ __func__, status);
+ return status;
+ }
+
+ status_t submitBuffer(const char *buffer, size_t length) override
+ {
+ if (buffer == nullptr || length > INT32_MAX) {
+ return BAD_VALUE;
+ }
+ ALOGV("%s: (ONEWAY) length:%zu", __func__, length);
+
+ Parcel data;
+ data.writeInterfaceToken(IMediaMetricsService::getInterfaceDescriptor());
+
+ status_t status = data.writeInt32(length)
+ ?: data.write((uint8_t*)buffer, length);
+ if (status != NO_ERROR) {
+ return status;
+ }
+
+ status = remote()->transact(
+ SUBMIT_BUFFER, data, nullptr /* reply */, IBinder::FLAG_ONEWAY);
+ ALOGW_IF(status != NO_ERROR, "%s: bad response from service for submit, status=%d",
+ __func__, status);
+ return status;
+ }
+};
+
+IMPLEMENT_META_INTERFACE(MediaMetricsService, "android.media.IMediaMetricsService");
+
+// ----------------------------------------------------------------------
+
+status_t BnMediaMetricsService::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch (code) {
+ case SUBMIT_ITEM: {
+ CHECK_INTERFACE(IMediaMetricsService, data, reply);
+
+ mediametrics::Item * const item = mediametrics::Item::create();
+ status_t status = item->readFromParcel(data);
+ if (status != NO_ERROR) { // assume failure logged in item
+ return status;
+ }
+ status = submitInternal(item, true /* release */);
+ // assume failure logged by submitInternal
+ return NO_ERROR;
+ }
+ case SUBMIT_BUFFER: {
+ CHECK_INTERFACE(IMediaMetricsService, data, reply);
+ int32_t length;
+ status_t status = data.readInt32(&length);
+ if (status != NO_ERROR || length <= 0) {
+ return BAD_VALUE;
+ }
+ const void *ptr = data.readInplace(length);
+ if (ptr == nullptr) {
+ return BAD_VALUE;
+ }
+ status = submitBuffer(static_cast<const char *>(ptr), length);
+ // assume failure logged by submitBuffer
+ return NO_ERROR;
+ }
+
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+} // namespace android
diff --git a/media/libmediametrics/MediaAnalyticsItem.cpp b/media/libmediametrics/MediaAnalyticsItem.cpp
deleted file mode 100644
index 02c23b1..0000000
--- a/media/libmediametrics/MediaAnalyticsItem.cpp
+++ /dev/null
@@ -1,1240 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#undef LOG_TAG
-#define LOG_TAG "MediaAnalyticsItem"
-
-#include <inttypes.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-
-#include <binder/Parcel.h>
-#include <utils/Errors.h>
-#include <utils/Log.h>
-#include <utils/Mutex.h>
-#include <utils/SortedVector.h>
-#include <utils/threads.h>
-
-#include <binder/IServiceManager.h>
-#include <media/IMediaAnalyticsService.h>
-#include <media/MediaAnalyticsItem.h>
-#include <private/android_filesystem_config.h>
-
-namespace android {
-
-#define DEBUG_SERVICEACCESS 0
-#define DEBUG_API 0
-#define DEBUG_ALLOCATIONS 0
-
-// after this many failed attempts, we stop trying [from this process] and just say that
-// the service is off.
-#define SVC_TRIES 2
-
-// the few universal keys we have
-const MediaAnalyticsItem::Key MediaAnalyticsItem::kKeyAny = "any";
-const MediaAnalyticsItem::Key MediaAnalyticsItem::kKeyNone = "none";
-
-const char * const MediaAnalyticsItem::EnabledProperty = "media.metrics.enabled";
-const char * const MediaAnalyticsItem::EnabledPropertyPersist = "persist.media.metrics.enabled";
-const int MediaAnalyticsItem::EnabledProperty_default = 1;
-
-// So caller doesn't need to know size of allocated space
-MediaAnalyticsItem *MediaAnalyticsItem::create()
-{
- return MediaAnalyticsItem::create(kKeyNone);
-}
-
-MediaAnalyticsItem *MediaAnalyticsItem::create(MediaAnalyticsItem::Key key)
-{
- MediaAnalyticsItem *item = new MediaAnalyticsItem(key);
- return item;
-}
-
-// access functions for the class
-MediaAnalyticsItem::MediaAnalyticsItem()
- : mPid(-1),
- mUid(-1),
- mPkgVersionCode(0),
- mSessionID(MediaAnalyticsItem::SessionIDNone),
- mTimestamp(0),
- mFinalized(1),
- mPropCount(0), mPropSize(0), mProps(NULL)
-{
- mKey = MediaAnalyticsItem::kKeyNone;
-}
-
-MediaAnalyticsItem::MediaAnalyticsItem(MediaAnalyticsItem::Key key)
- : mPid(-1),
- mUid(-1),
- mPkgVersionCode(0),
- mSessionID(MediaAnalyticsItem::SessionIDNone),
- mTimestamp(0),
- mFinalized(1),
- mPropCount(0), mPropSize(0), mProps(NULL)
-{
- if (DEBUG_ALLOCATIONS) {
- ALOGD("Allocate MediaAnalyticsItem @ %p", this);
- }
- mKey = key;
-}
-
-MediaAnalyticsItem::~MediaAnalyticsItem() {
- if (DEBUG_ALLOCATIONS) {
- ALOGD("Destroy MediaAnalyticsItem @ %p", this);
- }
- clear();
-}
-
-void MediaAnalyticsItem::clear() {
-
- // clean allocated storage from key
- mKey.clear();
-
- // clean various major parameters
- mSessionID = MediaAnalyticsItem::SessionIDNone;
-
- // clean attributes
- // contents of the attributes
- for (size_t i = 0 ; i < mPropCount; i++ ) {
- clearProp(&mProps[i]);
- }
- // the attribute records themselves
- if (mProps != NULL) {
- free(mProps);
- mProps = NULL;
- }
- mPropSize = 0;
- mPropCount = 0;
-
- return;
-}
-
-// make a deep copy of myself
-MediaAnalyticsItem *MediaAnalyticsItem::dup() {
- MediaAnalyticsItem *dst = new MediaAnalyticsItem(this->mKey);
-
- if (dst != NULL) {
- // key as part of constructor
- dst->mPid = this->mPid;
- dst->mUid = this->mUid;
- dst->mPkgName = this->mPkgName;
- dst->mPkgVersionCode = this->mPkgVersionCode;
- dst->mSessionID = this->mSessionID;
- dst->mTimestamp = this->mTimestamp;
- dst->mFinalized = this->mFinalized;
-
- // properties aka attributes
- dst->growProps(this->mPropCount);
- for(size_t i=0;i<mPropCount;i++) {
- copyProp(&dst->mProps[i], &this->mProps[i]);
- }
- dst->mPropCount = this->mPropCount;
- }
-
- return dst;
-}
-
-MediaAnalyticsItem &MediaAnalyticsItem::setSessionID(MediaAnalyticsItem::SessionID_t id) {
- mSessionID = id;
- return *this;
-}
-
-MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::getSessionID() const {
- return mSessionID;
-}
-
-MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::generateSessionID() {
-
- if (mSessionID == SessionIDNone) {
- // get one from the server
- MediaAnalyticsItem::SessionID_t newid = SessionIDNone;
- sp<IMediaAnalyticsService> svc = getInstance();
- if (svc != NULL) {
- newid = svc->generateUniqueSessionID();
- }
- mSessionID = newid;
- }
-
- return mSessionID;
-}
-
-MediaAnalyticsItem &MediaAnalyticsItem::clearSessionID() {
- mSessionID = MediaAnalyticsItem::SessionIDNone;
- return *this;
-}
-
-MediaAnalyticsItem &MediaAnalyticsItem::setTimestamp(nsecs_t ts) {
- mTimestamp = ts;
- return *this;
-}
-
-nsecs_t MediaAnalyticsItem::getTimestamp() const {
- return mTimestamp;
-}
-
-MediaAnalyticsItem &MediaAnalyticsItem::setPid(pid_t pid) {
- mPid = pid;
- return *this;
-}
-
-pid_t MediaAnalyticsItem::getPid() const {
- return mPid;
-}
-
-MediaAnalyticsItem &MediaAnalyticsItem::setUid(uid_t uid) {
- mUid = uid;
- return *this;
-}
-
-uid_t MediaAnalyticsItem::getUid() const {
- return mUid;
-}
-
-MediaAnalyticsItem &MediaAnalyticsItem::setPkgName(const std::string &pkgName) {
- mPkgName = pkgName;
- return *this;
-}
-
-MediaAnalyticsItem &MediaAnalyticsItem::setPkgVersionCode(int64_t pkgVersionCode) {
- mPkgVersionCode = pkgVersionCode;
- return *this;
-}
-
-int64_t MediaAnalyticsItem::getPkgVersionCode() const {
- return mPkgVersionCode;
-}
-
-// this key is for the overall record -- "codec", "player", "drm", etc
-MediaAnalyticsItem &MediaAnalyticsItem::setKey(MediaAnalyticsItem::Key key) {
- mKey = key;
- return *this;
-}
-
-MediaAnalyticsItem::Key MediaAnalyticsItem::getKey() {
- return mKey;
-}
-
-// number of attributes we have in this record
-int32_t MediaAnalyticsItem::count() const {
- return mPropCount;
-}
-
-// find the proper entry in the list
-size_t MediaAnalyticsItem::findPropIndex(const char *name, size_t len)
-{
- size_t i = 0;
- for (; i < mPropCount; i++) {
- Prop *prop = &mProps[i];
- if (prop->mNameLen != len) {
- continue;
- }
- if (memcmp(name, prop->mName, len) == 0) {
- break;
- }
- }
- return i;
-}
-
-MediaAnalyticsItem::Prop *MediaAnalyticsItem::findProp(const char *name) {
- size_t len = strlen(name);
- size_t i = findPropIndex(name, len);
- if (i < mPropCount) {
- return &mProps[i];
- }
- return NULL;
-}
-
-void MediaAnalyticsItem::Prop::setName(const char *name, size_t len) {
- free((void *)mName);
- mName = (const char *) malloc(len+1);
- LOG_ALWAYS_FATAL_IF(mName == NULL,
- "failed malloc() for property '%s' (len %zu)",
- name, len);
- memcpy ((void *)mName, name, len+1);
- mNameLen = len;
-}
-
-// consider this "find-or-allocate".
-// caller validates type and uses clearPropValue() accordingly
-MediaAnalyticsItem::Prop *MediaAnalyticsItem::allocateProp(const char *name) {
- size_t len = strlen(name);
- size_t i = findPropIndex(name, len);
- Prop *prop;
-
- if (i < mPropCount) {
- prop = &mProps[i];
- } else {
- if (i == mPropSize) {
- if (growProps() == false) {
- ALOGE("failed allocation for new props");
- return NULL;
- }
- }
- i = mPropCount++;
- prop = &mProps[i];
- prop->setName(name, len);
- }
-
- return prop;
-}
-
-// used within the summarizers; return whether property existed
-bool MediaAnalyticsItem::removeProp(const char *name) {
- size_t len = strlen(name);
- size_t i = findPropIndex(name, len);
- if (i < mPropCount) {
- Prop *prop = &mProps[i];
- clearProp(prop);
- if (i != mPropCount-1) {
- // in the middle, bring last one down to fill gap
- copyProp(prop, &mProps[mPropCount-1]);
- clearProp(&mProps[mPropCount-1]);
- }
- mPropCount--;
- return true;
- }
- return false;
-}
-
-// set the values
-void MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr name, int32_t value) {
- Prop *prop = allocateProp(name);
- if (prop != NULL) {
- clearPropValue(prop);
- prop->mType = kTypeInt32;
- prop->u.int32Value = value;
- }
-}
-
-void MediaAnalyticsItem::setInt64(MediaAnalyticsItem::Attr name, int64_t value) {
- Prop *prop = allocateProp(name);
- if (prop != NULL) {
- clearPropValue(prop);
- prop->mType = kTypeInt64;
- prop->u.int64Value = value;
- }
-}
-
-void MediaAnalyticsItem::setDouble(MediaAnalyticsItem::Attr name, double value) {
- Prop *prop = allocateProp(name);
- if (prop != NULL) {
- clearPropValue(prop);
- prop->mType = kTypeDouble;
- prop->u.doubleValue = value;
- }
-}
-
-void MediaAnalyticsItem::setCString(MediaAnalyticsItem::Attr name, const char *value) {
-
- Prop *prop = allocateProp(name);
- // any old value will be gone
- if (prop != NULL) {
- clearPropValue(prop);
- prop->mType = kTypeCString;
- prop->u.CStringValue = strdup(value);
- }
-}
-
-void MediaAnalyticsItem::setRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
- Prop *prop = allocateProp(name);
- if (prop != NULL) {
- clearPropValue(prop);
- prop->mType = kTypeRate;
- prop->u.rate.count = count;
- prop->u.rate.duration = duration;
- }
-}
-
-
-// find/add/set fused into a single operation
-void MediaAnalyticsItem::addInt32(MediaAnalyticsItem::Attr name, int32_t value) {
- Prop *prop = allocateProp(name);
- if (prop == NULL) {
- return;
- }
- switch (prop->mType) {
- case kTypeInt32:
- prop->u.int32Value += value;
- break;
- default:
- clearPropValue(prop);
- prop->mType = kTypeInt32;
- prop->u.int32Value = value;
- break;
- }
-}
-
-void MediaAnalyticsItem::addInt64(MediaAnalyticsItem::Attr name, int64_t value) {
- Prop *prop = allocateProp(name);
- if (prop == NULL) {
- return;
- }
- switch (prop->mType) {
- case kTypeInt64:
- prop->u.int64Value += value;
- break;
- default:
- clearPropValue(prop);
- prop->mType = kTypeInt64;
- prop->u.int64Value = value;
- break;
- }
-}
-
-void MediaAnalyticsItem::addRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
- Prop *prop = allocateProp(name);
- if (prop == NULL) {
- return;
- }
- switch (prop->mType) {
- case kTypeRate:
- prop->u.rate.count += count;
- prop->u.rate.duration += duration;
- break;
- default:
- clearPropValue(prop);
- prop->mType = kTypeRate;
- prop->u.rate.count = count;
- prop->u.rate.duration = duration;
- break;
- }
-}
-
-void MediaAnalyticsItem::addDouble(MediaAnalyticsItem::Attr name, double value) {
- Prop *prop = allocateProp(name);
- if (prop == NULL) {
- return;
- }
- switch (prop->mType) {
- case kTypeDouble:
- prop->u.doubleValue += value;
- break;
- default:
- clearPropValue(prop);
- prop->mType = kTypeDouble;
- prop->u.doubleValue = value;
- break;
- }
-}
-
-// find & extract values
-bool MediaAnalyticsItem::getInt32(MediaAnalyticsItem::Attr name, int32_t *value) {
- Prop *prop = findProp(name);
- if (prop == NULL || prop->mType != kTypeInt32) {
- return false;
- }
- if (value != NULL) {
- *value = prop->u.int32Value;
- }
- return true;
-}
-
-bool MediaAnalyticsItem::getInt64(MediaAnalyticsItem::Attr name, int64_t *value) {
- Prop *prop = findProp(name);
- if (prop == NULL || prop->mType != kTypeInt64) {
- return false;
- }
- if (value != NULL) {
- *value = prop->u.int64Value;
- }
- return true;
-}
-
-bool MediaAnalyticsItem::getRate(MediaAnalyticsItem::Attr name, int64_t *count, int64_t *duration, double *rate) {
- Prop *prop = findProp(name);
- if (prop == NULL || prop->mType != kTypeRate) {
- return false;
- }
- if (count != NULL) {
- *count = prop->u.rate.count;
- }
- if (duration != NULL) {
- *duration = prop->u.rate.duration;
- }
- if (rate != NULL) {
- double r = 0.0;
- if (prop->u.rate.duration != 0) {
- r = prop->u.rate.count / (double) prop->u.rate.duration;
- }
- *rate = r;
- }
- return true;
-}
-
-bool MediaAnalyticsItem::getDouble(MediaAnalyticsItem::Attr name, double *value) {
- Prop *prop = findProp(name);
- if (prop == NULL || prop->mType != kTypeDouble) {
- return false;
- }
- if (value != NULL) {
- *value = prop->u.doubleValue;
- }
- return true;
-}
-
-// caller responsible for the returned string
-bool MediaAnalyticsItem::getCString(MediaAnalyticsItem::Attr name, char **value) {
- Prop *prop = findProp(name);
- if (prop == NULL || prop->mType != kTypeCString) {
- return false;
- }
- if (value != NULL) {
- *value = strdup(prop->u.CStringValue);
- }
- return true;
-}
-
-bool MediaAnalyticsItem::getString(MediaAnalyticsItem::Attr name, std::string *value) {
- Prop *prop = findProp(name);
- if (prop == NULL || prop->mType != kTypeCString) {
- return false;
- }
- if (value != NULL) {
- // std::string makes a copy for us
- *value = prop->u.CStringValue;
- }
- return true;
-}
-
-// remove indicated keys and their values
-// return value is # keys removed
-int32_t MediaAnalyticsItem::filter(int n, MediaAnalyticsItem::Attr attrs[]) {
- int zapped = 0;
- if (attrs == NULL || n <= 0) {
- return -1;
- }
- for (ssize_t i = 0 ; i < n ; i++) {
- const char *name = attrs[i];
- size_t len = strlen(name);
- size_t j = findPropIndex(name, len);
- if (j >= mPropCount) {
- // not there
- continue;
- } else if (j+1 == mPropCount) {
- // last one, shorten
- zapped++;
- clearProp(&mProps[j]);
- mPropCount--;
- } else {
- // in the middle, bring last one down and shorten
- zapped++;
- clearProp(&mProps[j]);
- mProps[j] = mProps[mPropCount-1];
- mPropCount--;
- }
- }
- return zapped;
-}
-
-// remove any keys NOT in the provided list
-// return value is # keys removed
-int32_t MediaAnalyticsItem::filterNot(int n, MediaAnalyticsItem::Attr attrs[]) {
- int zapped = 0;
- if (attrs == NULL || n <= 0) {
- return -1;
- }
- for (ssize_t i = mPropCount-1 ; i >=0 ; i--) {
- Prop *prop = &mProps[i];
- for (ssize_t j = 0; j < n ; j++) {
- if (strcmp(prop->mName, attrs[j]) == 0) {
- clearProp(prop);
- zapped++;
- if (i != (ssize_t)(mPropCount-1)) {
- *prop = mProps[mPropCount-1];
- }
- initProp(&mProps[mPropCount-1]);
- mPropCount--;
- break;
- }
- }
- }
- return zapped;
-}
-
-// remove a single key
-// return value is 0 (not found) or 1 (found and removed)
-int32_t MediaAnalyticsItem::filter(MediaAnalyticsItem::Attr name) {
- return filter(1, &name);
-}
-
-// handle individual items/properties stored within the class
-//
-
-void MediaAnalyticsItem::initProp(Prop *prop) {
- if (prop != NULL) {
- prop->mName = NULL;
- prop->mNameLen = 0;
-
- prop->mType = kTypeNone;
- }
-}
-
-void MediaAnalyticsItem::clearProp(Prop *prop)
-{
- if (prop != NULL) {
- if (prop->mName != NULL) {
- free((void *)prop->mName);
- prop->mName = NULL;
- prop->mNameLen = 0;
- }
-
- clearPropValue(prop);
- }
-}
-
-void MediaAnalyticsItem::clearPropValue(Prop *prop)
-{
- if (prop != NULL) {
- if (prop->mType == kTypeCString && prop->u.CStringValue != NULL) {
- free(prop->u.CStringValue);
- prop->u.CStringValue = NULL;
- }
- prop->mType = kTypeNone;
- }
-}
-
-void MediaAnalyticsItem::copyProp(Prop *dst, const Prop *src)
-{
- // get rid of any pointers in the dst
- clearProp(dst);
-
- *dst = *src;
-
- // fix any pointers that we blindly copied, so we have our own copies
- if (dst->mName) {
- void *p = malloc(dst->mNameLen + 1);
- LOG_ALWAYS_FATAL_IF(p == NULL,
- "failed malloc() duping property '%s' (len %zu)",
- dst->mName, dst->mNameLen);
- memcpy (p, src->mName, dst->mNameLen + 1);
- dst->mName = (const char *) p;
- }
- if (dst->mType == kTypeCString) {
- dst->u.CStringValue = strdup(src->u.CStringValue);
- }
-}
-
-bool MediaAnalyticsItem::growProps(int increment)
-{
- if (increment <= 0) {
- increment = kGrowProps;
- }
- int nsize = mPropSize + increment;
- Prop *ni = (Prop *)realloc(mProps, sizeof(Prop) * nsize);
-
- if (ni != NULL) {
- for (int i = mPropSize; i < nsize; i++) {
- initProp(&ni[i]);
- }
- mProps = ni;
- mPropSize = nsize;
- return true;
- } else {
- ALOGW("MediaAnalyticsItem::growProps fails");
- return false;
- }
-}
-
-// Parcel / serialize things for binder calls
-//
-
-int32_t MediaAnalyticsItem::readFromParcel(const Parcel& data) {
- int32_t version = data.readInt32();
-
- switch(version) {
- case 0:
- return readFromParcel0(data);
- break;
- default:
- ALOGE("Unsupported MediaAnalyticsItem Parcel version: %d", version);
- return -1;
- }
-}
-
-int32_t MediaAnalyticsItem::readFromParcel0(const Parcel& data) {
- // into 'this' object
- // .. we make a copy of the string to put away.
- mKey = data.readCString();
- mPid = data.readInt32();
- mUid = data.readInt32();
- mPkgName = data.readCString();
- mPkgVersionCode = data.readInt64();
- mSessionID = data.readInt64();
- // We no longer pay attention to user setting of finalized, BUT it's
- // still part of the wire packet -- so read & discard.
- mFinalized = data.readInt32();
- mFinalized = 1;
- mTimestamp = data.readInt64();
-
- int count = data.readInt32();
- for (int i = 0; i < count ; i++) {
- MediaAnalyticsItem::Attr attr = data.readCString();
- int32_t ztype = data.readInt32();
- switch (ztype) {
- case MediaAnalyticsItem::kTypeInt32:
- setInt32(attr, data.readInt32());
- break;
- case MediaAnalyticsItem::kTypeInt64:
- setInt64(attr, data.readInt64());
- break;
- case MediaAnalyticsItem::kTypeDouble:
- setDouble(attr, data.readDouble());
- break;
- case MediaAnalyticsItem::kTypeCString:
- setCString(attr, data.readCString());
- break;
- case MediaAnalyticsItem::kTypeRate:
- {
- int64_t count = data.readInt64();
- int64_t duration = data.readInt64();
- setRate(attr, count, duration);
- }
- break;
- default:
- ALOGE("reading bad item type: %d, idx %d",
- ztype, i);
- return -1;
- }
- }
-
- return 0;
-}
-
-int32_t MediaAnalyticsItem::writeToParcel(Parcel *data) {
-
- if (data == NULL) return -1;
-
- int32_t version = 0;
- data->writeInt32(version);
-
- switch(version) {
- case 0:
- return writeToParcel0(data);
- break;
- default:
- ALOGE("Unsupported MediaAnalyticsItem Parcel version: %d", version);
- return -1;
- }
-}
-
-int32_t MediaAnalyticsItem::writeToParcel0(Parcel *data) {
-
- data->writeCString(mKey.c_str());
- data->writeInt32(mPid);
- data->writeInt32(mUid);
- data->writeCString(mPkgName.c_str());
- data->writeInt64(mPkgVersionCode);
- data->writeInt64(mSessionID);
- data->writeInt32(mFinalized);
- data->writeInt64(mTimestamp);
-
- // set of items
- int count = mPropCount;
- data->writeInt32(count);
- for (int i = 0 ; i < count; i++ ) {
- Prop *prop = &mProps[i];
- data->writeCString(prop->mName);
- data->writeInt32(prop->mType);
- switch (prop->mType) {
- case MediaAnalyticsItem::kTypeInt32:
- data->writeInt32(prop->u.int32Value);
- break;
- case MediaAnalyticsItem::kTypeInt64:
- data->writeInt64(prop->u.int64Value);
- break;
- case MediaAnalyticsItem::kTypeDouble:
- data->writeDouble(prop->u.doubleValue);
- break;
- case MediaAnalyticsItem::kTypeRate:
- data->writeInt64(prop->u.rate.count);
- data->writeInt64(prop->u.rate.duration);
- break;
- case MediaAnalyticsItem::kTypeCString:
- data->writeCString(prop->u.CStringValue);
- break;
- default:
- ALOGE("found bad Prop type: %d, idx %d, name %s",
- prop->mType, i, prop->mName);
- break;
- }
- }
-
- return 0;
-}
-
-const char *MediaAnalyticsItem::toCString() {
- return toCString(PROTO_LAST);
-}
-
-const char * MediaAnalyticsItem::toCString(int version) {
- std::string val = toString(version);
- return strdup(val.c_str());
-}
-
-std::string MediaAnalyticsItem::toString() {
- return toString(PROTO_LAST);
-}
-
-std::string MediaAnalyticsItem::toString(int version) {
-
- // v0 : released with 'o'
- // v1 : bug fix (missing pid/finalized separator),
- // adds apk name, apk version code
-
- if (version <= PROTO_FIRST) {
- // default to original v0 format, until proper parsers are in place
- version = PROTO_V0;
- } else if (version > PROTO_LAST) {
- version = PROTO_LAST;
- }
-
- std::string result;
- char buffer[512];
-
- if (version == PROTO_V0) {
- result = "(";
- } else {
- snprintf(buffer, sizeof(buffer), "[%d:", version);
- result.append(buffer);
- }
-
- // same order as we spill into the parcel, although not required
- // key+session are our primary matching criteria
- result.append(mKey.c_str());
- result.append(":");
- snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mSessionID);
- result.append(buffer);
-
- snprintf(buffer, sizeof(buffer), "%d:", mUid);
- result.append(buffer);
-
- if (version >= PROTO_V1) {
- result.append(mPkgName);
- snprintf(buffer, sizeof(buffer), ":%" PRId64 ":", mPkgVersionCode);
- result.append(buffer);
- }
-
- // in 'o' (v1) , the separator between pid and finalized was omitted
- if (version <= PROTO_V0) {
- snprintf(buffer, sizeof(buffer), "%d", mPid);
- } else {
- snprintf(buffer, sizeof(buffer), "%d:", mPid);
- }
- result.append(buffer);
-
- snprintf(buffer, sizeof(buffer), "%d:", mFinalized);
- result.append(buffer);
- snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mTimestamp);
- result.append(buffer);
-
- // set of items
- int count = mPropCount;
- snprintf(buffer, sizeof(buffer), "%d:", count);
- result.append(buffer);
- for (int i = 0 ; i < count; i++ ) {
- Prop *prop = &mProps[i];
- switch (prop->mType) {
- case MediaAnalyticsItem::kTypeInt32:
- snprintf(buffer,sizeof(buffer),
- "%s=%d:", prop->mName, prop->u.int32Value);
- break;
- case MediaAnalyticsItem::kTypeInt64:
- snprintf(buffer,sizeof(buffer),
- "%s=%" PRId64 ":", prop->mName, prop->u.int64Value);
- break;
- case MediaAnalyticsItem::kTypeDouble:
- snprintf(buffer,sizeof(buffer),
- "%s=%e:", prop->mName, prop->u.doubleValue);
- break;
- case MediaAnalyticsItem::kTypeRate:
- snprintf(buffer,sizeof(buffer),
- "%s=%" PRId64 "/%" PRId64 ":", prop->mName,
- prop->u.rate.count, prop->u.rate.duration);
- break;
- case MediaAnalyticsItem::kTypeCString:
- snprintf(buffer,sizeof(buffer), "%s=", prop->mName);
- result.append(buffer);
- // XXX: sanitize string for ':' '='
- result.append(prop->u.CStringValue);
- buffer[0] = ':';
- buffer[1] = '\0';
- break;
- default:
- ALOGE("to_String bad item type: %d for %s",
- prop->mType, prop->mName);
- break;
- }
- result.append(buffer);
- }
-
- if (version == PROTO_V0) {
- result.append(")");
- } else {
- result.append("]");
- }
-
- return result;
-}
-
-// for the lazy, we offer methods that finds the service and
-// calls the appropriate daemon
-bool MediaAnalyticsItem::selfrecord() {
- return selfrecord(false);
-}
-
-bool MediaAnalyticsItem::selfrecord(bool forcenew) {
-
- if (DEBUG_API) {
- std::string p = this->toString();
- ALOGD("selfrecord of: %s [forcenew=%d]", p.c_str(), forcenew);
- }
-
- sp<IMediaAnalyticsService> svc = getInstance();
-
- if (svc != NULL) {
- MediaAnalyticsItem::SessionID_t newid = svc->submit(this, forcenew);
- if (newid == SessionIDInvalid) {
- std::string p = this->toString();
- ALOGW("Failed to record: %s [forcenew=%d]", p.c_str(), forcenew);
- return false;
- }
- return true;
- } else {
- return false;
- }
-}
-
-// get a connection we can reuse for most of our lifetime
-// static
-sp<IMediaAnalyticsService> MediaAnalyticsItem::sAnalyticsService;
-static Mutex sInitMutex;
-static int remainingBindAttempts = SVC_TRIES;
-
-//static
-bool MediaAnalyticsItem::isEnabled() {
- int enabled = property_get_int32(MediaAnalyticsItem::EnabledProperty, -1);
-
- if (enabled == -1) {
- enabled = property_get_int32(MediaAnalyticsItem::EnabledPropertyPersist, -1);
- }
- if (enabled == -1) {
- enabled = MediaAnalyticsItem::EnabledProperty_default;
- }
- if (enabled <= 0) {
- return false;
- }
- return true;
-}
-
-
-// monitor health of our connection to the metrics service
-class MediaMetricsDeathNotifier : public IBinder::DeathRecipient {
- virtual void binderDied(const wp<IBinder> &) {
- ALOGW("Reacquire service connection on next request");
- MediaAnalyticsItem::dropInstance();
- }
-};
-
-static sp<MediaMetricsDeathNotifier> sNotifier = NULL;
-
-// static
-void MediaAnalyticsItem::dropInstance() {
- Mutex::Autolock _l(sInitMutex);
- remainingBindAttempts = SVC_TRIES;
- sAnalyticsService = NULL;
-}
-
-//static
-sp<IMediaAnalyticsService> MediaAnalyticsItem::getInstance() {
-
- static const char *servicename = "media.metrics";
- int enabled = isEnabled();
-
- if (enabled == false) {
- if (DEBUG_SERVICEACCESS) {
- ALOGD("disabled");
- }
- return NULL;
- }
-
- // completely skip logging from certain UIDs. We do this here
- // to avoid the multi-second timeouts while we learn that
- // sepolicy will not let us find the service.
- // We do this only for a select set of UIDs
- // The sepolicy protection is still in place, we just want a faster
- // response from this specific, small set of uids.
- {
- uid_t uid = getuid();
- switch (uid) {
- case AID_RADIO: // telephony subsystem, RIL
- return NULL;
- break;
- default:
- // let sepolicy deny access if appropriate
- break;
- }
- }
-
- {
- Mutex::Autolock _l(sInitMutex);
- const char *badness = "";
-
- // think of remainingBindAttempts as telling us whether service==NULL because
- // (1) we haven't tried to initialize it yet
- // (2) we've tried to initialize it, but failed.
- if (sAnalyticsService == NULL && remainingBindAttempts > 0) {
- sp<IServiceManager> sm = defaultServiceManager();
- if (sm != NULL) {
- sp<IBinder> binder = sm->getService(String16(servicename));
- if (binder != NULL) {
- sAnalyticsService = interface_cast<IMediaAnalyticsService>(binder);
- if (sNotifier != NULL) {
- sNotifier = NULL;
- }
- sNotifier = new MediaMetricsDeathNotifier();
- binder->linkToDeath(sNotifier);
- } else {
- badness = "did not find service";
- }
- } else {
- badness = "No Service Manager access";
- }
-
- if (sAnalyticsService == NULL) {
- if (remainingBindAttempts > 0) {
- remainingBindAttempts--;
- }
- if (DEBUG_SERVICEACCESS) {
- ALOGD("Unable to bind to service %s: %s", servicename, badness);
- }
- }
- }
-
- return sAnalyticsService;
- }
-}
-
-// merge the info from 'incoming' into this record.
-// we finish with a union of this+incoming and special handling for collisions
-bool MediaAnalyticsItem::merge(MediaAnalyticsItem *incoming) {
-
- // if I don't have key or session id, take them from incoming
- // 'this' should never be missing both of them...
- if (mKey.empty()) {
- mKey = incoming->mKey;
- } else if (mSessionID == 0) {
- mSessionID = incoming->mSessionID;
- }
-
- // for each attribute from 'incoming', resolve appropriately
- int nattr = incoming->mPropCount;
- for (int i = 0 ; i < nattr; i++ ) {
- Prop *iprop = &incoming->mProps[i];
- const char *p = iprop->mName;
- size_t len = strlen(p);
-
- // should ignore a zero length name...
- if (len == 0) {
- continue;
- }
-
- Prop *oprop = findProp(iprop->mName);
-
- if (oprop == NULL) {
- // no oprop, so we insert the new one
- oprop = allocateProp(p);
- if (oprop != NULL) {
- copyProp(oprop, iprop);
- } else {
- ALOGW("dropped property '%s'", iprop->mName);
- }
- } else {
- copyProp(oprop, iprop);
- }
- }
-
- // not sure when we'd return false...
- return true;
-}
-
-// a byte array; contents are
-// overall length (uint32) including the length field itself
-// encoding version (uint32)
-// count of properties (uint32)
-// N copies of:
-// property name as length(int16), bytes
-// the bytes WILL include the null terminator of the name
-// type (uint8 -- 1 byte)
-// size of value field (int16 -- 2 bytes)
-// value (size based on type)
-// int32, int64, double -- little endian 4/8/8 bytes respectively
-// cstring -- N bytes of value [WITH terminator]
-
-enum { kInt32 = 0, kInt64, kDouble, kRate, kCString};
-
-bool MediaAnalyticsItem::dumpAttributes(char **pbuffer, size_t *plength) {
-
- char *build = NULL;
-
- if (pbuffer == NULL || plength == NULL)
- return false;
-
- // consistency for the caller, who owns whatever comes back in this pointer.
- *pbuffer = NULL;
-
- // first, let's calculate sizes
- int32_t goal = 0;
- int32_t version = 0;
-
- goal += sizeof(uint32_t); // overall length, including the length field
- goal += sizeof(uint32_t); // encoding version
- goal += sizeof(uint32_t); // # properties
-
- int32_t count = mPropCount;
- for (int i = 0 ; i < count; i++ ) {
- Prop *prop = &mProps[i];
- goal += sizeof(uint16_t); // name length
- goal += strlen(prop->mName) + 1; // string + null
- goal += sizeof(uint8_t); // type
- goal += sizeof(uint16_t); // size of value
- switch (prop->mType) {
- case MediaAnalyticsItem::kTypeInt32:
- goal += sizeof(uint32_t);
- break;
- case MediaAnalyticsItem::kTypeInt64:
- goal += sizeof(uint64_t);
- break;
- case MediaAnalyticsItem::kTypeDouble:
- goal += sizeof(double);
- break;
- case MediaAnalyticsItem::kTypeRate:
- goal += 2 * sizeof(uint64_t);
- break;
- case MediaAnalyticsItem::kTypeCString:
- // length + actual string + null
- goal += strlen(prop->u.CStringValue) + 1;
- break;
- default:
- ALOGE("found bad Prop type: %d, idx %d, name %s",
- prop->mType, i, prop->mName);
- return false;
- }
- }
-
- // now that we have a size... let's allocate and fill
- build = (char *)malloc(goal);
- if (build == NULL)
- return false;
-
- memset(build, 0, goal);
-
- char *filling = build;
-
-#define _INSERT(val, size) \
- { memcpy(filling, &(val), (size)); filling += (size);}
-#define _INSERTSTRING(val, size) \
- { memcpy(filling, (val), (size)); filling += (size);}
-
- _INSERT(goal, sizeof(int32_t));
- _INSERT(version, sizeof(int32_t));
- _INSERT(count, sizeof(int32_t));
-
- for (int i = 0 ; i < count; i++ ) {
- Prop *prop = &mProps[i];
- int16_t attrNameLen = strlen(prop->mName) + 1;
- _INSERT(attrNameLen, sizeof(int16_t));
- _INSERTSTRING(prop->mName, attrNameLen); // termination included
- int8_t elemtype;
- int16_t elemsize;
- switch (prop->mType) {
- case MediaAnalyticsItem::kTypeInt32:
- {
- elemtype = kInt32;
- _INSERT(elemtype, sizeof(int8_t));
- elemsize = sizeof(int32_t);
- _INSERT(elemsize, sizeof(int16_t));
-
- _INSERT(prop->u.int32Value, sizeof(int32_t));
- break;
- }
- case MediaAnalyticsItem::kTypeInt64:
- {
- elemtype = kInt64;
- _INSERT(elemtype, sizeof(int8_t));
- elemsize = sizeof(int64_t);
- _INSERT(elemsize, sizeof(int16_t));
-
- _INSERT(prop->u.int64Value, sizeof(int64_t));
- break;
- }
- case MediaAnalyticsItem::kTypeDouble:
- {
- elemtype = kDouble;
- _INSERT(elemtype, sizeof(int8_t));
- elemsize = sizeof(double);
- _INSERT(elemsize, sizeof(int16_t));
-
- _INSERT(prop->u.doubleValue, sizeof(double));
- break;
- }
- case MediaAnalyticsItem::kTypeRate:
- {
- elemtype = kRate;
- _INSERT(elemtype, sizeof(int8_t));
- elemsize = 2 * sizeof(uint64_t);
- _INSERT(elemsize, sizeof(int16_t));
-
- _INSERT(prop->u.rate.count, sizeof(uint64_t));
- _INSERT(prop->u.rate.duration, sizeof(uint64_t));
- break;
- }
- case MediaAnalyticsItem::kTypeCString:
- {
- elemtype = kCString;
- _INSERT(elemtype, sizeof(int8_t));
- elemsize = strlen(prop->u.CStringValue) + 1;
- _INSERT(elemsize, sizeof(int16_t));
-
- _INSERTSTRING(prop->u.CStringValue, elemsize);
- break;
- }
- default:
- // error if can't encode; warning if can't decode
- ALOGE("found bad Prop type: %d, idx %d, name %s",
- prop->mType, i, prop->mName);
- goto badness;
- }
- }
-
- if (build + goal != filling) {
- ALOGE("problems populating; wrote=%d planned=%d",
- (int)(filling-build), goal);
- goto badness;
- }
-
- *pbuffer = build;
- *plength = goal;
-
- return true;
-
- badness:
- free(build);
- return false;
-}
-
-} // namespace android
-
diff --git a/media/libmediametrics/MediaMetrics.cpp b/media/libmediametrics/MediaMetrics.cpp
index 6109190..a3c2f1a 100644
--- a/media/libmediametrics/MediaMetrics.cpp
+++ b/media/libmediametrics/MediaMetrics.cpp
@@ -21,7 +21,7 @@
#include <string.h>
#include <sys/types.h>
-#include <media/MediaAnalyticsItem.h>
+#include <media/MediaMetricsItem.h>
#include <media/MediaMetrics.h>
//
@@ -31,28 +31,31 @@
// ALL functions returning a char * give responsibility for the allocated buffer
// to the caller. The caller is responsible to call free() on that pointer.
//
+//
+
+using namespace android::mediametrics;
// manage the overall record
mediametrics_handle_t mediametrics_create(mediametricskey_t key) {
- android::MediaAnalyticsItem *item = android::MediaAnalyticsItem::create(key);
+ Item *item = Item::create(key);
return (mediametrics_handle_t) item;
}
void mediametrics_delete(mediametrics_handle_t handle) {
- android::MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
+ Item *item = (Item *) handle;
if (item == NULL) return;
delete item;
}
mediametricskey_t mediametrics_getKey(mediametrics_handle_t handle) {
- android::MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
+ Item *item = (Item *) handle;
if (item == NULL) return NULL;
return strdup(item->getKey().c_str());
}
// nuplayer, et al use it when acting as proxies
void mediametrics_setUid(mediametrics_handle_t handle, uid_t uid) {
- android::MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
+ Item *item = (Item *) handle;
if (item != NULL) item->setUid(uid);
}
@@ -61,31 +64,31 @@
void mediametrics_setInt32(mediametrics_handle_t handle, attr_t attr,
int32_t value) {
- android::MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
+ Item *item = (Item *) handle;
if (item != NULL) item->setInt32(attr, value);
}
void mediametrics_setInt64(mediametrics_handle_t handle, attr_t attr,
int64_t value) {
- android::MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
+ Item *item = (Item *) handle;
if (item != NULL) item->setInt64(attr, value);
}
void mediametrics_setDouble(mediametrics_handle_t handle, attr_t attr,
double value) {
- android::MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
+ Item *item = (Item *) handle;
if (item != NULL) item->setDouble(attr, value);
}
void mediametrics_setRate(mediametrics_handle_t handle, attr_t attr,
int64_t count, int64_t duration) {
- android::MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
+ Item *item = (Item *) handle;
if (item != NULL) item->setRate(attr, count, duration);
}
void mediametrics_setCString(mediametrics_handle_t handle, attr_t attr,
const char *value) {
- android::MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
+ Item *item = (Item *) handle;
if (item != NULL) item->setCString(attr, value);
}
@@ -94,25 +97,25 @@
void mediametrics_addInt32(mediametrics_handle_t handle, attr_t attr,
int32_t value) {
- android::MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
+ Item *item = (Item *) handle;
if (item != NULL) item->addInt32(attr, value);
}
void mediametrics_addInt64(mediametrics_handle_t handle, attr_t attr,
int64_t value) {
- android::MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
+ Item *item = (Item *) handle;
if (item != NULL) item->addInt64(attr, value);
}
void mediametrics_addDouble(mediametrics_handle_t handle, attr_t attr,
double value) {
- android::MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
+ Item *item = (Item *) handle;
if (item != NULL) item->addDouble(attr, value);
}
void mediametrics_addRate(mediametrics_handle_t handle, attr_t attr,
int64_t count, int64_t duration) {
- android::MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
+ Item *item = (Item *) handle;
if (item != NULL) item->addRate(attr, count, duration);
}
@@ -123,28 +126,28 @@
bool mediametrics_getInt32(mediametrics_handle_t handle, attr_t attr,
int32_t * value) {
- android::MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
+ Item *item = (Item *) handle;
if (item == NULL) return false;
return item->getInt32(attr, value);
}
bool mediametrics_getInt64(mediametrics_handle_t handle, attr_t attr,
int64_t * value) {
- android::MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
+ Item *item = (Item *) handle;
if (item == NULL) return false;
return item->getInt64(attr, value);
}
bool mediametrics_getDouble(mediametrics_handle_t handle, attr_t attr,
double *value) {
- android::MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
+ Item *item = (Item *) handle;
if (item == NULL) return false;
return item->getDouble(attr, value);
}
bool mediametrics_getRate(mediametrics_handle_t handle, attr_t attr,
int64_t * count, int64_t * duration, double *rate) {
- android::MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
+ Item *item = (Item *) handle;
if (item == NULL) return false;
return item->getRate(attr, count, duration, rate);
}
@@ -152,7 +155,7 @@
// NB: caller owns the string that comes back, is responsible for freeing it
bool mediametrics_getCString(mediametrics_handle_t handle, attr_t attr,
char **value) {
- android::MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
+ Item *item = (Item *) handle;
if (item == NULL) return false;
return item->getCString(attr, value);
@@ -164,32 +167,37 @@
}
bool mediametrics_selfRecord(mediametrics_handle_t handle) {
- android::MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
+ Item *item = (Item *) handle;
if (item == NULL) return false;
return item->selfrecord();
}
+mediametrics_handle_t mediametrics_dup(mediametrics_handle_t handle) {
+ Item *item = (Item *) handle;
+ if (item == NULL) return Item::convert(item);
+ return Item::convert(item->dup());
+}
const char *mediametrics_readable(mediametrics_handle_t handle) {
- android::MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
+ Item *item = (Item *) handle;
if (item == NULL) return "";
return item->toCString();
}
int32_t mediametrics_count(mediametrics_handle_t handle) {
- android::MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
+ Item *item = (Item *) handle;
if (item == NULL) return 0;
return item->count();
}
bool mediametrics_isEnabled() {
// static, so doesn't need an instance
- return android::MediaAnalyticsItem::isEnabled();
+ return Item::isEnabled();
}
bool mediametrics_getAttributes(mediametrics_handle_t handle, char **buffer, size_t *length) {
- android::MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
+ Item *item = (Item *) handle;
if (item == NULL) return false;
- return item->dumpAttributes(buffer, length);
+ return item->writeToByteString(buffer, length) == android::NO_ERROR;
}
diff --git a/media/libmediametrics/MediaMetricsItem.cpp b/media/libmediametrics/MediaMetricsItem.cpp
new file mode 100644
index 0000000..4371668
--- /dev/null
+++ b/media/libmediametrics/MediaMetricsItem.cpp
@@ -0,0 +1,642 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "mediametrics::Item"
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <mutex>
+#include <set>
+
+#include <binder/Parcel.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/SortedVector.h>
+#include <utils/threads.h>
+
+#include <binder/IServiceManager.h>
+#include <media/IMediaMetricsService.h>
+#include <media/MediaMetricsItem.h>
+#include <private/android_filesystem_config.h>
+
+// Max per-property string size before truncation in toString().
+// Do not make too large, as this is used for dumpsys purposes.
+static constexpr size_t kMaxPropertyStringSize = 4096;
+
+namespace android::mediametrics {
+
+#define DEBUG_SERVICEACCESS 0
+#define DEBUG_API 0
+#define DEBUG_ALLOCATIONS 0
+
+// after this many failed attempts, we stop trying [from this process] and just say that
+// the service is off.
+#define SVC_TRIES 2
+
+mediametrics::Item* mediametrics::Item::convert(mediametrics_handle_t handle) {
+ mediametrics::Item *item = (android::mediametrics::Item *) handle;
+ return item;
+}
+
+mediametrics_handle_t mediametrics::Item::convert(mediametrics::Item *item ) {
+ mediametrics_handle_t handle = (mediametrics_handle_t) item;
+ return handle;
+}
+
+mediametrics::Item::~Item() {
+ if (DEBUG_ALLOCATIONS) {
+ ALOGD("Destroy mediametrics::Item @ %p", this);
+ }
+}
+
+mediametrics::Item &mediametrics::Item::setTimestamp(nsecs_t ts) {
+ mTimestamp = ts;
+ return *this;
+}
+
+nsecs_t mediametrics::Item::getTimestamp() const {
+ return mTimestamp;
+}
+
+mediametrics::Item &mediametrics::Item::setPid(pid_t pid) {
+ mPid = pid;
+ return *this;
+}
+
+pid_t mediametrics::Item::getPid() const {
+ return mPid;
+}
+
+mediametrics::Item &mediametrics::Item::setUid(uid_t uid) {
+ mUid = uid;
+ return *this;
+}
+
+uid_t mediametrics::Item::getUid() const {
+ return mUid;
+}
+
+mediametrics::Item &mediametrics::Item::setPkgName(const std::string &pkgName) {
+ mPkgName = pkgName;
+ return *this;
+}
+
+mediametrics::Item &mediametrics::Item::setPkgVersionCode(int64_t pkgVersionCode) {
+ mPkgVersionCode = pkgVersionCode;
+ return *this;
+}
+
+int64_t mediametrics::Item::getPkgVersionCode() const {
+ return mPkgVersionCode;
+}
+
+// remove indicated keys and their values
+// return value is # keys removed
+size_t mediametrics::Item::filter(size_t n, const char *attrs[]) {
+ size_t zapped = 0;
+ for (size_t i = 0; i < n; ++i) {
+ zapped += mProps.erase(attrs[i]);
+ }
+ return zapped;
+}
+
+// remove any keys NOT in the provided list
+// return value is # keys removed
+size_t mediametrics::Item::filterNot(size_t n, const char *attrs[]) {
+ std::set<std::string> check(attrs, attrs + n);
+ size_t zapped = 0;
+ for (auto it = mProps.begin(); it != mProps.end();) {
+ if (check.find(it->first) != check.end()) {
+ ++it;
+ } else {
+ it = mProps.erase(it);
+ ++zapped;
+ }
+ }
+ return zapped;
+}
+
+// Parcel / serialize things for binder calls
+//
+
+status_t mediametrics::Item::readFromParcel(const Parcel& data) {
+ int32_t version;
+ status_t status = data.readInt32(&version);
+ if (status != NO_ERROR) return status;
+
+ switch (version) {
+ case 0:
+ return readFromParcel0(data);
+ default:
+ ALOGE("%s: unsupported parcel version: %d", __func__, version);
+ return INVALID_OPERATION;
+ }
+}
+
+status_t mediametrics::Item::readFromParcel0(const Parcel& data) {
+ const char *s = data.readCString();
+ mKey = s == nullptr ? "" : s;
+ int32_t pid, uid;
+ status_t status = data.readInt32(&pid) ?: data.readInt32(&uid);
+ if (status != NO_ERROR) return status;
+ mPid = (pid_t)pid;
+ mUid = (uid_t)uid;
+ s = data.readCString();
+ mPkgName = s == nullptr ? "" : s;
+ int32_t count;
+ int64_t version, timestamp;
+ status = data.readInt64(&version) ?: data.readInt64(×tamp) ?: data.readInt32(&count);
+ if (status != NO_ERROR) return status;
+ if (count < 0) return BAD_VALUE;
+ mPkgVersionCode = version;
+ mTimestamp = timestamp;
+ for (int i = 0; i < count; i++) {
+ Prop prop;
+ status_t status = prop.readFromParcel(data);
+ if (status != NO_ERROR) return status;
+ mProps[prop.getName()] = std::move(prop);
+ }
+ return NO_ERROR;
+}
+
+status_t mediametrics::Item::writeToParcel(Parcel *data) const {
+ if (data == nullptr) return BAD_VALUE;
+
+ const int32_t version = 0;
+ status_t status = data->writeInt32(version);
+ if (status != NO_ERROR) return status;
+
+ switch (version) {
+ case 0:
+ return writeToParcel0(data);
+ default:
+ ALOGE("%s: unsupported parcel version: %d", __func__, version);
+ return INVALID_OPERATION;
+ }
+}
+
+status_t mediametrics::Item::writeToParcel0(Parcel *data) const {
+ status_t status =
+ data->writeCString(mKey.c_str())
+ ?: data->writeInt32(mPid)
+ ?: data->writeInt32(mUid)
+ ?: data->writeCString(mPkgName.c_str())
+ ?: data->writeInt64(mPkgVersionCode)
+ ?: data->writeInt64(mTimestamp);
+ if (status != NO_ERROR) return status;
+
+ data->writeInt32((int32_t)mProps.size());
+ for (auto &prop : *this) {
+ status = prop.writeToParcel(data);
+ if (status != NO_ERROR) return status;
+ }
+ return NO_ERROR;
+}
+
+const char *mediametrics::Item::toCString() {
+ std::string val = toString();
+ return strdup(val.c_str());
+}
+
+/*
+ * Similar to audio_utils/clock.h but customized for displaying mediametrics time.
+ */
+
+void nsToString(int64_t ns, char *buffer, size_t bufferSize, PrintFormat format)
+{
+ if (bufferSize == 0) return;
+
+ const int one_second = 1000000000;
+ const time_t sec = ns / one_second;
+ struct tm tm;
+
+ // Supported on bionic, glibc, and macOS, but not mingw.
+ if (localtime_r(&sec, &tm) == NULL) {
+ buffer[0] = '\0';
+ return;
+ }
+
+ switch (format) {
+ default:
+ case kPrintFormatLong:
+ if (snprintf(buffer, bufferSize, "%02d-%02d %02d:%02d:%02d.%03d",
+ tm.tm_mon + 1, // localtime_r uses months in 0 - 11 range
+ tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
+ (int)(ns % one_second / 1000000)) < 0) {
+ buffer[0] = '\0'; // null terminate on format error, which should not happen
+ }
+ break;
+ case kPrintFormatShort:
+ if (snprintf(buffer, bufferSize, "%02d:%02d:%02d.%03d",
+ tm.tm_hour, tm.tm_min, tm.tm_sec,
+ (int)(ns % one_second / 1000000)) < 0) {
+ buffer[0] = '\0'; // null terminate on format error, which should not happen
+ }
+ break;
+ }
+}
+
+std::string mediametrics::Item::toString() const {
+ std::string result;
+ char buffer[kMaxPropertyStringSize];
+
+ snprintf(buffer, sizeof(buffer), "{%s, (%s), (%s, %d, %d)",
+ mKey.c_str(),
+ timeStringFromNs(mTimestamp, kPrintFormatLong).time,
+ mPkgName.c_str(), mPid, mUid
+ );
+ result.append(buffer);
+ bool first = true;
+ for (auto &prop : *this) {
+ prop.toStringBuffer(buffer, sizeof(buffer));
+ result += first ? ", (" : ", ";
+ result += buffer;
+ first = false;
+ }
+ result.append(")}");
+ return result;
+}
+
+// for the lazy, we offer methods that finds the service and
+// calls the appropriate daemon
+bool mediametrics::Item::selfrecord() {
+ ALOGD_IF(DEBUG_API, "%s: delivering %s", __func__, this->toString().c_str());
+ sp<IMediaMetricsService> svc = getService();
+ if (svc != NULL) {
+ status_t status = svc->submit(this);
+ if (status != NO_ERROR) {
+ ALOGW("%s: failed to record: %s", __func__, this->toString().c_str());
+ return false;
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+//static
+bool BaseItem::isEnabled() {
+ // completely skip logging from certain UIDs. We do this here
+ // to avoid the multi-second timeouts while we learn that
+ // sepolicy will not let us find the service.
+ // We do this only for a select set of UIDs
+ // The sepolicy protection is still in place, we just want a faster
+ // response from this specific, small set of uids.
+
+ // This is checked only once in the lifetime of the process.
+ const uid_t uid = getuid();
+ switch (uid) {
+ case AID_RADIO: // telephony subsystem, RIL
+ return false;
+ }
+
+ int enabled = property_get_int32(Item::EnabledProperty, -1);
+ if (enabled == -1) {
+ enabled = property_get_int32(Item::EnabledPropertyPersist, -1);
+ }
+ if (enabled == -1) {
+ enabled = Item::EnabledProperty_default;
+ }
+ return enabled > 0;
+}
+
+// monitor health of our connection to the metrics service
+class MediaMetricsDeathNotifier : public IBinder::DeathRecipient {
+ virtual void binderDied(const wp<IBinder> &) {
+ ALOGW("Reacquire service connection on next request");
+ BaseItem::dropInstance();
+ }
+};
+
+static sp<MediaMetricsDeathNotifier> sNotifier;
+// static
+sp<IMediaMetricsService> BaseItem::sMediaMetricsService;
+static std::mutex sServiceMutex;
+static int sRemainingBindAttempts = SVC_TRIES;
+
+// static
+void BaseItem::dropInstance() {
+ std::lock_guard _l(sServiceMutex);
+ sRemainingBindAttempts = SVC_TRIES;
+ sMediaMetricsService = nullptr;
+}
+
+// static
+bool BaseItem::submitBuffer(const char *buffer, size_t size) {
+/*
+ mediametrics::Item item;
+ status_t status = item.readFromByteString(buffer, size);
+ ALOGD("%s: status:%d, size:%zu, item:%s", __func__, status, size, item.toString().c_str());
+ return item.selfrecord();
+ */
+
+ ALOGD_IF(DEBUG_API, "%s: delivering %zu bytes", __func__, size);
+ sp<IMediaMetricsService> svc = getService();
+ if (svc != nullptr) {
+ const status_t status = svc->submitBuffer(buffer, size);
+ if (status != NO_ERROR) {
+ ALOGW("%s: failed(%d) to record: %zu bytes", __func__, status, size);
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+//static
+sp<IMediaMetricsService> BaseItem::getService() {
+ static const char *servicename = "media.metrics";
+ static const bool enabled = isEnabled(); // singleton initialized
+
+ if (enabled == false) {
+ ALOGD_IF(DEBUG_SERVICEACCESS, "disabled");
+ return nullptr;
+ }
+ std::lock_guard _l(sServiceMutex);
+ // think of remainingBindAttempts as telling us whether service == nullptr because
+ // (1) we haven't tried to initialize it yet
+ // (2) we've tried to initialize it, but failed.
+ if (sMediaMetricsService == nullptr && sRemainingBindAttempts > 0) {
+ const char *badness = "";
+ sp<IServiceManager> sm = defaultServiceManager();
+ if (sm != nullptr) {
+ sp<IBinder> binder = sm->getService(String16(servicename));
+ if (binder != nullptr) {
+ sMediaMetricsService = interface_cast<IMediaMetricsService>(binder);
+ sNotifier = new MediaMetricsDeathNotifier();
+ binder->linkToDeath(sNotifier);
+ } else {
+ badness = "did not find service";
+ }
+ } else {
+ badness = "No Service Manager access";
+ }
+ if (sMediaMetricsService == nullptr) {
+ if (sRemainingBindAttempts > 0) {
+ sRemainingBindAttempts--;
+ }
+ ALOGD_IF(DEBUG_SERVICEACCESS, "%s: unable to bind to service %s: %s",
+ __func__, servicename, badness);
+ }
+ }
+ return sMediaMetricsService;
+}
+
+
+status_t mediametrics::Item::writeToByteString(char **pbuffer, size_t *plength) const
+{
+ if (pbuffer == nullptr || plength == nullptr)
+ return BAD_VALUE;
+
+ // get size
+ const size_t keySizeZeroTerminated = strlen(mKey.c_str()) + 1;
+ if (keySizeZeroTerminated > UINT16_MAX) {
+ ALOGW("%s: key size %zu too large", __func__, keySizeZeroTerminated);
+ return INVALID_OPERATION;
+ }
+ const uint16_t version = 0;
+ const uint32_t header_size =
+ sizeof(uint32_t) // total size
+ + sizeof(header_size) // header size
+ + sizeof(version) // encoding version
+ + sizeof(uint16_t) // key size
+ + keySizeZeroTerminated // key, zero terminated
+ + sizeof(int32_t) // pid
+ + sizeof(int32_t) // uid
+ + sizeof(int64_t) // timestamp
+ ;
+
+ uint32_t size = header_size
+ + sizeof(uint32_t) // # properties
+ ;
+ for (auto &prop : *this) {
+ const size_t propSize = prop.getByteStringSize();
+ if (propSize > UINT16_MAX) {
+ ALOGW("%s: prop %s size %zu too large", __func__, prop.getName(), propSize);
+ return INVALID_OPERATION;
+ }
+ if (__builtin_add_overflow(size, propSize, &size)) {
+ ALOGW("%s: item size overflow at property %s", __func__, prop.getName());
+ return INVALID_OPERATION;
+ }
+ }
+
+ // since we fill every byte in the buffer (there is no padding),
+ // malloc is used here instead of calloc.
+ char * const build = (char *)malloc(size);
+ if (build == nullptr) return NO_MEMORY;
+
+ char *filling = build;
+ char *buildmax = build + size;
+ if (insert((uint32_t)size, &filling, buildmax) != NO_ERROR
+ || insert(header_size, &filling, buildmax) != NO_ERROR
+ || insert(version, &filling, buildmax) != NO_ERROR
+ || insert((uint16_t)keySizeZeroTerminated, &filling, buildmax) != NO_ERROR
+ || insert(mKey.c_str(), &filling, buildmax) != NO_ERROR
+ || insert((int32_t)mPid, &filling, buildmax) != NO_ERROR
+ || insert((int32_t)mUid, &filling, buildmax) != NO_ERROR
+ || insert((int64_t)mTimestamp, &filling, buildmax) != NO_ERROR
+ || insert((uint32_t)mProps.size(), &filling, buildmax) != NO_ERROR) {
+ ALOGE("%s:could not write header", __func__); // shouldn't happen
+ free(build);
+ return INVALID_OPERATION;
+ }
+ for (auto &prop : *this) {
+ if (prop.writeToByteString(&filling, buildmax) != NO_ERROR) {
+ free(build);
+ // shouldn't happen
+ ALOGE("%s:could not write prop %s", __func__, prop.getName());
+ return INVALID_OPERATION;
+ }
+ }
+
+ if (filling != buildmax) {
+ ALOGE("%s: problems populating; wrote=%d planned=%d",
+ __func__, (int)(filling - build), (int)size);
+ free(build);
+ return INVALID_OPERATION;
+ }
+ *pbuffer = build;
+ *plength = size;
+ return NO_ERROR;
+}
+
+status_t mediametrics::Item::readFromByteString(const char *bufferptr, size_t length)
+{
+ if (bufferptr == nullptr) return BAD_VALUE;
+
+ const char *read = bufferptr;
+ const char *readend = bufferptr + length;
+
+ uint32_t size;
+ uint32_t header_size;
+ uint16_t version;
+ uint16_t key_size;
+ std::string key;
+ int32_t pid;
+ int32_t uid;
+ int64_t timestamp;
+ uint32_t propCount;
+ if (extract(&size, &read, readend) != NO_ERROR
+ || extract(&header_size, &read, readend) != NO_ERROR
+ || extract(&version, &read, readend) != NO_ERROR
+ || extract(&key_size, &read, readend) != NO_ERROR
+ || extract(&key, &read, readend) != NO_ERROR
+ || extract(&pid, &read, readend) != NO_ERROR
+ || extract(&uid, &read, readend) != NO_ERROR
+ || extract(×tamp, &read, readend) != NO_ERROR
+ || size > length
+ || key.size() + 1 != key_size
+ || header_size > size) {
+ ALOGW("%s: invalid header", __func__);
+ return INVALID_OPERATION;
+ }
+ mKey = std::move(key);
+ const size_t pos = read - bufferptr;
+ if (pos > header_size) {
+ ALOGW("%s: invalid header pos:%zu > header_size:%u",
+ __func__, pos, header_size);
+ return INVALID_OPERATION;
+ } else if (pos < header_size) {
+ ALOGW("%s: mismatched header pos:%zu < header_size:%u, advancing",
+ __func__, pos, header_size);
+ read += (header_size - pos);
+ }
+ if (extract(&propCount, &read, readend) != NO_ERROR) {
+ ALOGD("%s: cannot read prop count", __func__);
+ return INVALID_OPERATION;
+ }
+ mPid = pid;
+ mUid = uid;
+ mTimestamp = timestamp;
+ for (size_t i = 0; i < propCount; ++i) {
+ Prop prop;
+ if (prop.readFromByteString(&read, readend) != NO_ERROR) {
+ ALOGW("%s: cannot read prop %zu", __func__, i);
+ return INVALID_OPERATION;
+ }
+ mProps[prop.getName()] = std::move(prop);
+ }
+ return NO_ERROR;
+}
+
+status_t mediametrics::Item::Prop::readFromParcel(const Parcel& data)
+{
+ const char *key = data.readCString();
+ if (key == nullptr) return BAD_VALUE;
+ int32_t type;
+ status_t status = data.readInt32(&type);
+ if (status != NO_ERROR) return status;
+ switch (type) {
+ case mediametrics::kTypeInt32: {
+ int32_t value;
+ status = data.readInt32(&value);
+ if (status != NO_ERROR) return status;
+ mElem = value;
+ } break;
+ case mediametrics::kTypeInt64: {
+ int64_t value;
+ status = data.readInt64(&value);
+ if (status != NO_ERROR) return status;
+ mElem = value;
+ } break;
+ case mediametrics::kTypeDouble: {
+ double value;
+ status = data.readDouble(&value);
+ if (status != NO_ERROR) return status;
+ mElem = value;
+ } break;
+ case mediametrics::kTypeCString: {
+ const char *s = data.readCString();
+ if (s == nullptr) return BAD_VALUE;
+ mElem = s;
+ } break;
+ case mediametrics::kTypeRate: {
+ std::pair<int64_t, int64_t> rate;
+ status = data.readInt64(&rate.first)
+ ?: data.readInt64(&rate.second);
+ if (status != NO_ERROR) return status;
+ mElem = rate;
+ } break;
+ case mediametrics::kTypeNone: {
+ mElem = std::monostate{};
+ } break;
+ default:
+ ALOGE("%s: reading bad item type: %d", __func__, type);
+ return BAD_VALUE;
+ }
+ setName(key);
+ return NO_ERROR;
+}
+
+status_t mediametrics::Item::Prop::readFromByteString(
+ const char **bufferpptr, const char *bufferptrmax)
+{
+ uint16_t len;
+ std::string name;
+ uint8_t type;
+ status_t status = extract(&len, bufferpptr, bufferptrmax)
+ ?: extract(&type, bufferpptr, bufferptrmax)
+ ?: extract(&name, bufferpptr, bufferptrmax);
+ if (status != NO_ERROR) return status;
+ switch (type) {
+ case mediametrics::kTypeInt32: {
+ int32_t value;
+ status = extract(&value, bufferpptr, bufferptrmax);
+ if (status != NO_ERROR) return status;
+ mElem = value;
+ } break;
+ case mediametrics::kTypeInt64: {
+ int64_t value;
+ status = extract(&value, bufferpptr, bufferptrmax);
+ if (status != NO_ERROR) return status;
+ mElem = value;
+ } break;
+ case mediametrics::kTypeDouble: {
+ double value;
+ status = extract(&value, bufferpptr, bufferptrmax);
+ if (status != NO_ERROR) return status;
+ mElem = value;
+ } break;
+ case mediametrics::kTypeRate: {
+ std::pair<int64_t, int64_t> value;
+ status = extract(&value.first, bufferpptr, bufferptrmax)
+ ?: extract(&value.second, bufferpptr, bufferptrmax);
+ if (status != NO_ERROR) return status;
+ mElem = value;
+ } break;
+ case mediametrics::kTypeCString: {
+ std::string value;
+ status = extract(&value, bufferpptr, bufferptrmax);
+ if (status != NO_ERROR) return status;
+ mElem = std::move(value);
+ } break;
+ case mediametrics::kTypeNone: {
+ mElem = std::monostate{};
+ } break;
+ default:
+ ALOGE("%s: found bad prop type: %d, name %s",
+ __func__, (int)type, mName.c_str()); // no payload sent
+ return BAD_VALUE;
+ }
+ mName = name;
+ return NO_ERROR;
+}
+
+} // namespace android::mediametrics
diff --git a/media/libmediametrics/TEST_MAPPING b/media/libmediametrics/TEST_MAPPING
new file mode 100644
index 0000000..01e9e46
--- /dev/null
+++ b/media/libmediametrics/TEST_MAPPING
@@ -0,0 +1,10 @@
+{
+ "presubmit": [
+ {
+ "name": "mediametrics_tests"
+ },
+ {
+ "name": "CtsNativeMediaMetricsTestCases"
+ }
+ ]
+}
diff --git a/media/libmediametrics/include/IMediaAnalyticsService.h b/media/libmediametrics/include/IMediaAnalyticsService.h
deleted file mode 100644
index f635e94..0000000
--- a/media/libmediametrics/include/IMediaAnalyticsService.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_IMEDIAANALYTICSSERVICE_H
-#define ANDROID_IMEDIAANALYTICSSERVICE_H
-
-#include <utils/String8.h>
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-
-#include <sys/types.h>
-#include <utils/Errors.h>
-#include <utils/Log.h>
-#include <utils/RefBase.h>
-#include <utils/List.h>
-
-#include <binder/IServiceManager.h>
-
-#include <media/MediaAnalyticsItem.h>
-// nope...#include <media/MediaAnalytics.h>
-
-namespace android {
-
-class IMediaAnalyticsService: public IInterface
-{
-public:
- DECLARE_META_INTERFACE(MediaAnalyticsService);
-
- // generate a unique sessionID to use across multiple requests
- // 'unique' is within this device, since last reboot
- virtual MediaAnalyticsItem::SessionID_t generateUniqueSessionID() = 0;
-
- // submit the indicated record to the mediaanalytics service, where
- // it will be merged (if appropriate) with incomplete records that
- // share the same key and sessionid.
- // 'forcenew' marks any matching incomplete record as complete before
- // inserting this new record.
- // returns the sessionID associated with that item.
- // caller continues to own the passed item
- virtual MediaAnalyticsItem::SessionID_t submit(MediaAnalyticsItem *item, bool forcenew) = 0;
-
-};
-
-// ----------------------------------------------------------------------------
-
-class BnMediaAnalyticsService: public BnInterface<IMediaAnalyticsService>
-{
-public:
- virtual status_t onTransact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-};
-
-}; // namespace android
-
-#endif // ANDROID_IMEDIASTATISTICSSERVICE_H
diff --git a/media/libmediametrics/include/MediaAnalyticsItem.h b/media/libmediametrics/include/MediaAnalyticsItem.h
deleted file mode 100644
index 4a36f6a..0000000
--- a/media/libmediametrics/include/MediaAnalyticsItem.h
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_MEDIA_MEDIAANALYTICSITEM_H
-#define ANDROID_MEDIA_MEDIAANALYTICSITEM_H
-
-#include <string>
-#include <sys/types.h>
-
-#include <cutils/properties.h>
-#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
-#include <utils/RefBase.h>
-#include <utils/StrongPointer.h>
-#include <utils/Timers.h>
-
-namespace android {
-
-class IMediaAnalyticsService;
-class Parcel;
-
-// the class interface
-//
-
-class MediaAnalyticsItem {
-
- friend class MediaAnalyticsService;
- friend class IMediaAnalyticsService;
- friend class MediaMetricsJNI;
- friend class MetricsSummarizer;
- friend class MediaMetricsDeathNotifier;
-
- public:
-
- enum Type {
- kTypeNone = 0,
- kTypeInt32 = 1,
- kTypeInt64 = 2,
- kTypeDouble = 3,
- kTypeCString = 4,
- kTypeRate = 5,
- };
-
- // sessionid
- // unique within device, within boot,
- typedef int64_t SessionID_t;
- static constexpr SessionID_t SessionIDInvalid = -1;
- static constexpr SessionID_t SessionIDNone = 0;
-
- // Key: the record descriminator
- // values for the record discriminator
- // values can be "component/component"
- // basic values: "video", "audio", "drm"
- // XXX: need to better define the format
- typedef std::string Key;
- static const Key kKeyNone; // ""
- static const Key kKeyAny; // "*"
-
- // Attr: names for attributes within a record
- // format "prop1" or "prop/subprop"
- // XXX: need to better define the format
- typedef const char *Attr;
-
-
- enum {
- PROTO_V0 = 0,
- PROTO_FIRST = PROTO_V0,
- PROTO_V1 = 1,
- PROTO_LAST = PROTO_V1,
- };
-
- private:
- // use the ::create() method instead
- MediaAnalyticsItem();
- MediaAnalyticsItem(Key);
- MediaAnalyticsItem(const MediaAnalyticsItem&);
- MediaAnalyticsItem &operator=(const MediaAnalyticsItem&);
-
- public:
-
- static MediaAnalyticsItem* create(Key key);
- static MediaAnalyticsItem* create();
-
- // access functions for the class
- ~MediaAnalyticsItem();
-
- // SessionID ties multiple submissions for same key together
- // so that if video "height" and "width" are known at one point
- // and "framerate" is only known later, they can be be brought
- // together.
- MediaAnalyticsItem &setSessionID(SessionID_t);
- MediaAnalyticsItem &clearSessionID();
- SessionID_t getSessionID() const;
- // generates and stores a new ID iff mSessionID == SessionIDNone
- SessionID_t generateSessionID();
-
- // reset all contents, discarding any extra data
- void clear();
- MediaAnalyticsItem *dup();
-
- // set the key discriminator for the record.
- // most often initialized as part of the constructor
- MediaAnalyticsItem &setKey(MediaAnalyticsItem::Key);
- MediaAnalyticsItem::Key getKey();
-
- // # of attributes in the record
- int32_t count() const;
-
- // set values appropriately
- void setInt32(Attr, int32_t value);
- void setInt64(Attr, int64_t value);
- void setDouble(Attr, double value);
- void setRate(Attr, int64_t count, int64_t duration);
- void setCString(Attr, const char *value);
-
- // fused get/add/set; if attr wasn't there, it's a simple set.
- // type-mismatch counts as "wasn't there".
- void addInt32(Attr, int32_t value);
- void addInt64(Attr, int64_t value);
- void addDouble(Attr, double value);
- void addRate(Attr, int64_t count, int64_t duration);
-
- // find & extract values
- // return indicates whether attr exists (and thus value filled in)
- // NULL parameter value suppresses storage of value.
- bool getInt32(Attr, int32_t *value);
- bool getInt64(Attr, int64_t *value);
- bool getDouble(Attr, double *value);
- bool getRate(Attr, int64_t *count, int64_t *duration, double *rate);
- // Caller owns the returned string
- bool getCString(Attr, char **value);
- bool getString(Attr, std::string *value);
-
- // parameter indicates whether to close any existing open
- // record with same key before establishing a new record
- // caller retains ownership of 'this'.
- bool selfrecord(bool);
- bool selfrecord();
-
- // remove indicated attributes and their values
- // filterNot() could also be called keepOnly()
- // return value is # attributes removed
- // XXX: perhaps 'remove' instead of 'filter'
- // XXX: filterNot would become 'keep'
- int32_t filter(int count, Attr attrs[]);
- int32_t filterNot(int count, Attr attrs[]);
- int32_t filter(Attr attr);
-
- // below here are used on server side or to talk to server
- // clients need not worry about these.
-
- // timestamp, pid, and uid only used on server side
- // timestamp is in 'nanoseconds, unix time'
- MediaAnalyticsItem &setTimestamp(nsecs_t);
- nsecs_t getTimestamp() const;
-
- MediaAnalyticsItem &setPid(pid_t);
- pid_t getPid() const;
-
- MediaAnalyticsItem &setUid(uid_t);
- uid_t getUid() const;
-
- MediaAnalyticsItem &setPkgName(const std::string &pkgName);
- std::string getPkgName() const { return mPkgName; }
-
- MediaAnalyticsItem &setPkgVersionCode(int64_t);
- int64_t getPkgVersionCode() const;
-
- // our serialization code for binder calls
- int32_t writeToParcel(Parcel *);
- int32_t readFromParcel(const Parcel&);
-
- // supports the stable interface
- bool dumpAttributes(char **pbuffer, size_t *plength);
-
- std::string toString();
- std::string toString(int version);
- const char *toCString();
- const char *toCString(int version);
-
- // are we collecting analytics data
- static bool isEnabled();
-
- private:
- // handle Parcel version 0
- int32_t writeToParcel0(Parcel *);
- int32_t readFromParcel0(const Parcel&);
-
- protected:
-
- // merge fields from arg into this
- // with rules for first/last/add, etc
- // XXX: document semantics and how they are indicated
- // caller continues to own 'incoming'
- bool merge(MediaAnalyticsItem *incoming);
-
- // enabled 1, disabled 0
- static const char * const EnabledProperty;
- static const char * const EnabledPropertyPersist;
- static const int EnabledProperty_default;
-
- private:
-
- // to help validate that A doesn't mess with B's records
- pid_t mPid;
- uid_t mUid;
- std::string mPkgName;
- int64_t mPkgVersionCode;
-
- // let's reuse a binder connection
- static sp<IMediaAnalyticsService> sAnalyticsService;
- static sp<IMediaAnalyticsService> getInstance();
- static void dropInstance();
-
- // tracking information
- SessionID_t mSessionID; // grouping similar records
- nsecs_t mTimestamp; // ns, system_time_monotonic
-
- // will this record accept further updates
- bool mFinalized;
-
- Key mKey;
-
- struct Prop {
-
- Type mType;
- const char *mName;
- size_t mNameLen; // the strlen(), doesn't include the null
- union {
- int32_t int32Value;
- int64_t int64Value;
- double doubleValue;
- char *CStringValue;
- struct { int64_t count, duration; } rate;
- } u;
- void setName(const char *name, size_t len);
- };
-
- void initProp(Prop *item);
- void clearProp(Prop *item);
- void clearPropValue(Prop *item);
- void copyProp(Prop *dst, const Prop *src);
- enum {
- kGrowProps = 10
- };
- bool growProps(int increment = kGrowProps);
- size_t findPropIndex(const char *name, size_t len);
- Prop *findProp(const char *name);
- Prop *allocateProp(const char *name);
- bool removeProp(const char *name);
-
- size_t mPropCount;
- size_t mPropSize;
- Prop *mProps;
-};
-
-} // namespace android
-
-#endif
diff --git a/media/libmediametrics/include/MediaMetrics.h b/media/libmediametrics/include/MediaMetrics.h
deleted file mode 100644
index a4e1ed2..0000000
--- a/media/libmediametrics/include/MediaMetrics.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_MEDIA_MEDIAMETRICS_H
-#define ANDROID_MEDIA_MEDIAMETRICS_H
-
-//
-// define a C interface to the media metrics functionality
-//
-// All functions that return a char * or const char * also give responsibility
-// for that string to the caller. The caller is responsible for calling free()
-// on that pointer when done using the value.
-
-__BEGIN_DECLS
-
-// internally re-cast to the behind-the-scenes C++ class instance
-typedef int64_t mediametrics_handle_t;
-typedef const char *mediametricskey_t;
-typedef const char *attr_t;
-
-mediametrics_handle_t mediametrics_create(mediametricskey_t key);
-void mediametrics_delete(mediametrics_handle_t handle);
-
-mediametricskey_t mediametrics_getKey(mediametrics_handle_t handle);
-
-
-// set
-void mediametrics_setInt32(mediametrics_handle_t handle, attr_t attr,
- int32_t value);
-void mediametrics_setInt64(mediametrics_handle_t handle, attr_t attr,
- int64_t value);
-void mediametrics_setDouble(mediametrics_handle_t handle, attr_t attr,
- double value);
-void mediametrics_setRate(mediametrics_handle_t handle, attr_t attr,
- int64_t count, int64_t duration);
-void mediametrics_setCString(mediametrics_handle_t handle, attr_t attr,
- const char * value);
-
-// fused get/add/set; if attr wasn't there, it's a simple set.
-// these do not provide atomicity or mutual exclusion, only simpler code sequences.
-void mediametrics_addInt32(mediametrics_handle_t handle, attr_t attr,
- int32_t value);
-void mediametrics_addInt64(mediametrics_handle_t handle, attr_t attr,
- int64_t value);
-void mediametrics_addDouble(mediametrics_handle_t handle, attr_t attr,
- double value);
-void mediametrics_addRate(mediametrics_handle_t handle, attr_t attr,
- int64_t count, int64_t duration);
-
-// find & extract values
-// return indicates whether attr exists (and thus whether value filled in)
-// NULL parameter value suppresses storage of value.
-bool mediametrics_getInt32(mediametrics_handle_t handle, attr_t attr,
- int32_t * value);
-bool mediametrics_getInt64(mediametrics_handle_t handle, attr_t attr,
- int64_t * value);
-bool mediametrics_getDouble(mediametrics_handle_t handle, attr_t attr,
- double *value);
-bool mediametrics_getRate(mediametrics_handle_t handle, attr_t attr,
- int64_t * count, int64_t * duration, double *rate);
-bool mediametrics_getCString(mediametrics_handle_t handle, attr_t attr,
- char **value);
-// to release strings returned via getCString()
-void mediametrics_freeCString(char *value);
-
-// # of attributes set within this record.
-int32_t mediametrics_count(mediametrics_handle_t handle);
-
-bool mediametrics_selfRecord(mediametrics_handle_t handle);
-
-const char *mediametrics_readable(mediametrics_handle_t handle);
-void mediametrics_setUid(mediametrics_handle_t handle, uid_t uid);
-bool mediametrics_isEnabled();
-
-// serialized copy of the attributes/values, mostly for upstream getMetrics() calls
-// caller owns the buffer allocated as part of this call.
-bool mediametrics_getAttributes(mediametrics_handle_t handle, char **buffer, size_t *length);
-
-__END_DECLS
-
-#endif
diff --git a/media/libmediametrics/include/MediaMetricsConstants.h b/media/libmediametrics/include/MediaMetricsConstants.h
new file mode 100644
index 0000000..eb7ac7d
--- /dev/null
+++ b/media/libmediametrics/include/MediaMetricsConstants.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_MEDIAMETRICSCONSTANTS_H
+#define ANDROID_MEDIA_MEDIAMETRICSCONSTANTS_H
+
+/*
+ * MediaMetrics Keys and Properties.
+ *
+ * C/C++ friendly constants that ensure
+ * 1) Compilation error on misspelling
+ * 2) Consistent behavior and documentation.
+ */
+
+/*
+ * Taxonomy of audio keys
+ *
+ * To build longer keys, we use compiler string concatenation of
+ * adjacent string literals. This is done in the translation phase
+ * of compilation to make a single string token.
+ */
+
+// Key Prefixes are used for MediaMetrics Item Keys and ends with a ".".
+// They must be appended with another value to make a key.
+#define AMEDIAMETRICS_KEY_PREFIX_AUDIO "audio."
+
+// The AudioRecord key appends the "trackId" to the prefix.
+#define AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD AMEDIAMETRICS_KEY_PREFIX_AUDIO "record."
+
+// The AudioThread key appends the "threadId" to the prefix.
+#define AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD AMEDIAMETRICS_KEY_PREFIX_AUDIO "thread."
+
+// The AudioTrack key appends the "trackId" to the prefix.
+#define AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK AMEDIAMETRICS_KEY_PREFIX_AUDIO "track."
+
+// Keys are strings used for MediaMetrics Item Keys
+#define AMEDIAMETRICS_KEY_AUDIO_FLINGER AMEDIAMETRICS_KEY_PREFIX_AUDIO "flinger"
+#define AMEDIAMETRICS_KEY_AUDIO_POLICY AMEDIAMETRICS_KEY_PREFIX_AUDIO "policy"
+
+/*
+ * MediaMetrics Properties are unified space for consistency and readability.
+ */
+
+// Property prefixes may be applied before a property name to indicate a specific
+// category to which it is associated.
+#define AMEDIAMETRICS_PROP_PREFIX_EFFECTIVE "effective."
+#define AMEDIAMETRICS_PROP_PREFIX_HAL "hal."
+#define AMEDIAMETRICS_PROP_PREFIX_HAPTIC "haptic."
+#define AMEDIAMETRICS_PROP_PREFIX_SERVER "server."
+
+// Properties within mediametrics are string constants denoted by
+// a macro name beginning with AMEDIAMETRICS_PROP_*
+//
+// For a property name like "auxEffectId" we write this as a single upper case word
+// at the end of the macro name, such as AMEDIAMETRICS_PROP_AUXEFFECTID.
+//
+// Underscores after the AMEDIAMETRICS_PROP_* prefix indicate
+// a "dot" in the property name. For example AMEDIAMETRICS_PROP_VOLUME_LEFT
+// corresponds to "volume.left".
+//
+// The property names are camel case, typically a lowercase letter [a-z]
+// followed by one or more characters in the range [a-zA-Z0-9_.].
+// Special symbols such as !@#$%^&*()[]{}<>,:;'"\/?|+-=~ are reserved.
+//
+// Properties within this header should include special suffixes like '#'
+// directly in the string for brevity. Code outside of this header should
+// use the macro constant for the special symbols for searchability.
+
+// Any property that ends with a # will have duplicate values listed instead
+// of suppressed in the Time Machine.
+#define AMEDIAMETRICS_PROP_SUFFIX_CHAR_DUPLICATES_ALLOWED '#'
+
+#define AMEDIAMETRICS_PROP_AUXEFFECTID "auxEffectId" // int32 (AudioTrack)
+#define AMEDIAMETRICS_PROP_CHANNELCOUNT "channelCount" // int32
+#define AMEDIAMETRICS_PROP_CHANNELMASK "channelMask" // int32
+#define AMEDIAMETRICS_PROP_CONTENTTYPE "contentType" // string attributes (AudioTrack)
+#define AMEDIAMETRICS_PROP_DURATIONNS "durationNs" // int64 duration time span
+#define AMEDIAMETRICS_PROP_ENCODING "encoding" // string value of format
+#define AMEDIAMETRICS_PROP_EVENT "event#" // string value (often func name)
+
+// TODO: fix inconsistency in flags: AudioRecord / AudioTrack int32, AudioThread string
+#define AMEDIAMETRICS_PROP_FLAGS "flags"
+
+#define AMEDIAMETRICS_PROP_FRAMECOUNT "frameCount" // int32
+#define AMEDIAMETRICS_PROP_INPUTDEVICES "inputDevices" // string value
+#define AMEDIAMETRICS_PROP_LATENCYMS "latencyMs" // double value
+#define AMEDIAMETRICS_PROP_ORIGINALFLAGS "originalFlags" // int32
+#define AMEDIAMETRICS_PROP_OUTPUTDEVICES "outputDevices" // string value
+#define AMEDIAMETRICS_PROP_PLAYBACK_PITCH "playback.pitch" // double value (AudioTrack)
+#define AMEDIAMETRICS_PROP_PLAYBACK_SPEED "playback.speed" // double value (AudioTrack)
+#define AMEDIAMETRICS_PROP_ROUTEDDEVICEID "routedDeviceId" // int32
+#define AMEDIAMETRICS_PROP_SAMPLERATE "sampleRate" // int32
+#define AMEDIAMETRICS_PROP_SELECTEDDEVICEID "selectedDeviceId" // int32
+#define AMEDIAMETRICS_PROP_SELECTEDMICDIRECTION "selectedMicDirection" // int32
+#define AMEDIAMETRICS_PROP_SELECTEDMICFIELDDIRECTION "selectedMicFieldDimension" // double
+#define AMEDIAMETRICS_PROP_SESSIONID "sessionId" // int32
+#define AMEDIAMETRICS_PROP_SOURCE "source" // string (AudioAttributes)
+#define AMEDIAMETRICS_PROP_STARTUPMS "startupMs" // double value
+// State is "ACTIVE" or "STOPPED" for AudioRecord
+#define AMEDIAMETRICS_PROP_STATE "state" // string
+#define AMEDIAMETRICS_PROP_STATUS "status" // int32 status_t
+#define AMEDIAMETRICS_PROP_STREAMTYPE "streamType" // string (AudioTrack)
+#define AMEDIAMETRICS_PROP_THREADID "threadId" // int32 value io handle
+#define AMEDIAMETRICS_PROP_THROTTLEMS "throttleMs" // double
+#define AMEDIAMETRICS_PROP_TRACKID "trackId" // int32 port id of track/record
+#define AMEDIAMETRICS_PROP_TYPE "type" // string (thread type)
+#define AMEDIAMETRICS_PROP_UNDERRUN "underrun" // int32
+#define AMEDIAMETRICS_PROP_USAGE "usage" // string attributes (ATrack)
+#define AMEDIAMETRICS_PROP_VOLUME_LEFT "volume.left" // double (AudioTrack)
+#define AMEDIAMETRICS_PROP_VOLUME_RIGHT "volume.right" // double (AudioTrack)
+#define AMEDIAMETRICS_PROP_WHERE "where" // string value
+
+// Timing values: millisecond values are suffixed with MS and the type is double
+// nanosecond values are suffixed with NS and the type is int64.
+
+// Values are strings accepted for a given property.
+
+// An event is a general description, which often is a function name.
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE "create"
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_CREATEAUDIOPATCH "createAudioPatch"
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR "ctor"
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_DTOR "dtor"
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_FLUSH "flush" // AudioTrack
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_INVALIDATE "invalidate" // server track, record
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_PAUSE "pause" // AudioTrack
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_READPARAMETERS "readParameters" // Thread
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_RESTORE "restore"
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_SETPLAYBACKPARAM "setPlaybackParam" // AudioTrack
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOLUME "setVolume" // AudioTrack
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_START "start" // AudioTrack, AudioRecord
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_STOP "stop" // AudioTrack, AudioRecord
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_UNDERRUN "underrun" // from Thread
+
+#endif // ANDROID_MEDIA_MEDIAMETRICSCONSTANTS_H
diff --git a/media/libmediametrics/include/media/IMediaMetricsService.h b/media/libmediametrics/include/media/IMediaMetricsService.h
new file mode 100644
index 0000000..d6871ec
--- /dev/null
+++ b/media/libmediametrics/include/media/IMediaMetricsService.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_IMEDIAANALYTICSSERVICE_H
+#define ANDROID_IMEDIAANALYTICSSERVICE_H
+
+#include <utils/String8.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+#include <sys/types.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/RefBase.h>
+#include <utils/List.h>
+
+#include <binder/IServiceManager.h>
+
+#include <media/MediaMetricsItem.h>
+
+namespace android {
+
+class IMediaMetricsService: public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(MediaMetricsService);
+
+ /**
+ * Submits the indicated record to the mediaanalytics service, where
+ * it will be merged (if appropriate) with incomplete records that
+ * share the same key and sessionID.
+ *
+ * \param item the item to submit.
+ * \return status which is negative if an error is detected (some errors
+ may be silent and return 0 - success).
+ */
+ virtual status_t submit(mediametrics::Item *item) = 0;
+
+ virtual status_t submitBuffer(const char *buffer, size_t length) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnMediaMetricsService: public BnInterface<IMediaMetricsService>
+{
+public:
+ status_t onTransact(uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0) override;
+
+protected:
+ // Internal call where release is true if the service is to delete the item.
+ virtual status_t submitInternal(
+ mediametrics::Item *item, bool release) = 0;
+};
+
+}; // namespace android
+
+#endif // ANDROID_IMEDIASTATISTICSSERVICE_H
diff --git a/media/libmediametrics/include/media/MediaMetrics.h b/media/libmediametrics/include/media/MediaMetrics.h
new file mode 100644
index 0000000..76abe86
--- /dev/null
+++ b/media/libmediametrics/include/media/MediaMetrics.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_MEDIAMETRICS_H
+#define ANDROID_MEDIA_MEDIAMETRICS_H
+
+//
+// define a C interface to the media metrics functionality
+//
+// All functions that return a char * or const char * also give responsibility
+// for that string to the caller. The caller is responsible for calling free()
+// on that pointer when done using the value.
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+// internally re-cast to the behind-the-scenes C++ class instance
+typedef int64_t mediametrics_handle_t;
+typedef const char *mediametricskey_t;
+typedef const char *attr_t;
+
+mediametrics_handle_t mediametrics_create(mediametricskey_t key);
+void mediametrics_delete(mediametrics_handle_t handle);
+
+mediametricskey_t mediametrics_getKey(mediametrics_handle_t handle);
+
+
+// set
+void mediametrics_setInt32(mediametrics_handle_t handle, attr_t attr,
+ int32_t value);
+void mediametrics_setInt64(mediametrics_handle_t handle, attr_t attr,
+ int64_t value);
+void mediametrics_setDouble(mediametrics_handle_t handle, attr_t attr,
+ double value);
+void mediametrics_setRate(mediametrics_handle_t handle, attr_t attr,
+ int64_t count, int64_t duration);
+void mediametrics_setCString(mediametrics_handle_t handle, attr_t attr,
+ const char * value);
+
+// fused get/add/set; if attr wasn't there, it's a simple set.
+// these do not provide atomicity or mutual exclusion, only simpler code sequences.
+void mediametrics_addInt32(mediametrics_handle_t handle, attr_t attr,
+ int32_t value);
+void mediametrics_addInt64(mediametrics_handle_t handle, attr_t attr,
+ int64_t value);
+void mediametrics_addDouble(mediametrics_handle_t handle, attr_t attr,
+ double value);
+void mediametrics_addRate(mediametrics_handle_t handle, attr_t attr,
+ int64_t count, int64_t duration);
+
+// find & extract values
+// return indicates whether attr exists (and thus whether value filled in)
+// NULL parameter value suppresses storage of value.
+bool mediametrics_getInt32(mediametrics_handle_t handle, attr_t attr,
+ int32_t * value);
+bool mediametrics_getInt64(mediametrics_handle_t handle, attr_t attr,
+ int64_t * value);
+bool mediametrics_getDouble(mediametrics_handle_t handle, attr_t attr,
+ double *value);
+bool mediametrics_getRate(mediametrics_handle_t handle, attr_t attr,
+ int64_t * count, int64_t * duration, double *rate);
+bool mediametrics_getCString(mediametrics_handle_t handle, attr_t attr,
+ char **value);
+// to release strings returned via getCString()
+void mediametrics_freeCString(char *value);
+
+// # of attributes set within this record.
+int32_t mediametrics_count(mediametrics_handle_t handle);
+
+mediametrics_handle_t mediametrics_dup(mediametrics_handle_t handle);
+bool mediametrics_selfRecord(mediametrics_handle_t handle);
+
+const char *mediametrics_readable(mediametrics_handle_t handle);
+void mediametrics_setUid(mediametrics_handle_t handle, uid_t uid);
+bool mediametrics_isEnabled();
+
+// serialized copy of the attributes/values, mostly for upstream getMetrics() calls
+// caller owns the buffer allocated as part of this call.
+bool mediametrics_getAttributes(mediametrics_handle_t handle, char **buffer, size_t *length);
+
+__END_DECLS
+
+#endif
diff --git a/media/libmediametrics/include/media/MediaMetricsItem.h b/media/libmediametrics/include/media/MediaMetricsItem.h
new file mode 100644
index 0000000..08720f1
--- /dev/null
+++ b/media/libmediametrics/include/media/MediaMetricsItem.h
@@ -0,0 +1,1187 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_MEDIAMETRICSITEM_H
+#define ANDROID_MEDIA_MEDIAMETRICSITEM_H
+
+#include "MediaMetrics.h"
+#include "MediaMetricsConstants.h"
+
+#include <algorithm>
+#include <map>
+#include <string>
+#include <sys/types.h>
+#include <variant>
+
+#include <binder/Parcel.h>
+#include <cutils/properties.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+#include <utils/StrongPointer.h>
+#include <utils/Timers.h>
+
+namespace android {
+
+class IMediaMetricsService;
+class Parcel;
+
+/*
+ * MediaMetrics Item
+ *
+ * The MediaMetrics Item allows get/set operations and recording to the service.
+ *
+ * The MediaMetrics LogItem is a faster logging variant. It allows set operations only,
+ * and then recording to the service.
+ *
+ * The Byte String format is as follows:
+ *
+ * For Java
+ * int64 corresponds to long
+ * int32, uint32 corresponds to int
+ * uint16 corresponds to char
+ * uint8, int8 corresponds to byte
+ *
+ * For items transmitted from Java, uint8 and uint32 values are limited
+ * to INT8_MAX and INT32_MAX. This constrains the size of large items
+ * to 2GB, which is consistent with ByteBuffer max size. A native item
+ * can conceivably have size of 4GB.
+ *
+ * Physical layout of integers and doubles within the MediaMetrics byte string
+ * is in Native / host order, which is usually little endian.
+ *
+ * Note that primitive data (ints, doubles) within a Byte String has
+ * no extra padding or alignment requirements, like ByteBuffer.
+ *
+ * -- begin of item
+ * -- begin of header
+ * (uint32) item size: including the item size field
+ * (uint32) header size, including the item size and header size fields.
+ * (uint16) version: exactly 0
+ * (uint16) key size, that is key strlen + 1 for zero termination.
+ * (int8)+ key, a string which is 0 terminated (UTF-8).
+ * (int32) pid
+ * (int32) uid
+ * (int64) timestamp
+ * -- end of header
+ * -- begin body
+ * (uint32) number of properties
+ * -- repeat for number of properties
+ * (uint16) property size, including property size field itself
+ * (uint8) type of property
+ * (int8)+ key string, including 0 termination
+ * based on type of property (given above), one of:
+ * (int32)
+ * (int64)
+ * (double)
+ * (int8)+ for TYPE_CSTRING, including 0 termination
+ * (int64, int64) for rate
+ * -- end body
+ * -- end of item
+ *
+ * The Byte String format must match MediaMetrics.java.
+ */
+
+namespace mediametrics {
+
+// Type must match MediaMetrics.java
+enum Type {
+ kTypeNone = 0,
+ kTypeInt32 = 1,
+ kTypeInt64 = 2,
+ kTypeDouble = 3,
+ kTypeCString = 4,
+ kTypeRate = 5,
+};
+
+/*
+ * Time printing
+ *
+ * kPrintFormatLong time string is 19 characters (including null termination).
+ * Example Long Form: "03-27 16:47:06.187"
+ * MM DD HH MM SS MS
+ *
+ * kPrintFormatShort time string is 13 characters (including null termination).
+ * Example Short Form: "16:47:06.187"
+ * HH MM SS MS
+ */
+
+enum PrintFormat {
+ kPrintFormatLong = 0,
+ kPrintFormatShort = 1,
+};
+
+/**
+ * Converts real time in ns to a time string object, with format similar to logcat.
+ *
+ * \param ns input real time in nanoseconds to convert.
+ * \param buffer the buffer location to put the converted string.
+ * \param bufferSize the size of buffer in bytes.
+ * \param format format, from enum PrintFormat.
+ */
+void nsToString(
+ int64_t ns, char *buffer, size_t bufferSize, PrintFormat format = kPrintFormatLong);
+
+// Contains the time string
+struct time_string_t {
+ char time[19]; /* minimum size buffer */
+};
+
+/**
+ * Converts real time in ns to a time string object, with format similar to logcat.
+ *
+ * \param ns input real time in nanoseconds to convert.
+ * \param format format, from enum PrintFormat.
+ * \return a time_string_t object with the time string encoded.
+ */
+static inline time_string_t timeStringFromNs(int64_t ns, PrintFormat format = kPrintFormatLong) {
+ time_string_t ts;
+ nsToString(ns, ts.time, sizeof(ts.time), format);
+ return ts;
+}
+
+/**
+ * Finds the end of the common time prefix.
+ *
+ * This is as an option to remove the common time prefix to avoid
+ * unnecessary duplicated strings.
+ *
+ * \param time1 a time string from timeStringFromNs
+ * \param time2 a time string from timeStringFromNs
+ * \return the position where the common time prefix ends. For abbreviated
+ * printing of time2, offset the character pointer by this position.
+ */
+static inline size_t commonTimePrefixPosition(const char *time1, const char *time2) {
+ size_t i;
+
+ // Find location of the first mismatch between strings
+ for (i = 0; ; ++i) {
+ if (time1[i] != time2[i]) {
+ break;
+ }
+ if (time1[i] == 0) {
+ return i; // strings match completely
+ }
+ }
+
+ // Go backwards until we find a delimeter or space.
+ for (; i > 0
+ && isdigit(time1[i]) // still a number
+ && time1[i - 1] != ' '
+ ; --i) {
+ }
+ return i;
+}
+
+/**
+ * The MediaMetrics Item has special Item properties,
+ * derived internally or through dedicated setters.
+ *
+ * For consistency we use the following keys to represent
+ * these special Item properties when in a generic Bundle
+ * or in a std::map.
+ *
+ * These values must match MediaMetrics.java
+ */
+static inline constexpr const char *BUNDLE_TOTAL_SIZE = "_totalSize";
+static inline constexpr const char *BUNDLE_HEADER_SIZE = "_headerSize";
+static inline constexpr const char *BUNDLE_VERSION = "_version";
+static inline constexpr const char *BUNDLE_KEY_SIZE = "_keySize";
+static inline constexpr const char *BUNDLE_KEY = "_key";
+static inline constexpr const char *BUNDLE_PID = "_pid";
+static inline constexpr const char *BUNDLE_UID = "_uid";
+static inline constexpr const char *BUNDLE_TIMESTAMP = "_timestamp";
+static inline constexpr const char *BUNDLE_PROPERTY_COUNT = "_propertyCount";
+
+template<size_t N>
+static inline bool startsWith(const std::string &s, const char (&comp)[N]) {
+ return !strncmp(s.c_str(), comp, N - 1);
+}
+
+static inline bool startsWith(const std::string& s, const std::string& comp) {
+ return !strncmp(s.c_str(), comp.c_str(), comp.size() - 1);
+}
+
+/**
+ * Defers a function to run in the destructor.
+ *
+ * This helper class is used to log results on exit of a method.
+ */
+class Defer {
+public:
+ template <typename U>
+ Defer(U &&f) : mThunk(std::forward<U>(f)) {}
+ ~Defer() { mThunk(); }
+
+private:
+ const std::function<void()> mThunk;
+};
+
+/**
+ * Media Metrics BaseItem
+ *
+ * A base class which contains utility static functions to write to a byte stream
+ * and access the Media Metrics service.
+ */
+
+class BaseItem {
+ friend class MediaMetricsDeathNotifier; // for dropInstance
+ // enabled 1, disabled 0
+public:
+ // are we collecting metrics data
+ static bool isEnabled();
+ static sp<IMediaMetricsService> getService();
+
+protected:
+ static constexpr const char * const EnabledProperty = "media.metrics.enabled";
+ static constexpr const char * const EnabledPropertyPersist = "persist.media.metrics.enabled";
+ static const int EnabledProperty_default = 1;
+
+ // let's reuse a binder connection
+ static sp<IMediaMetricsService> sMediaMetricsService;
+
+ static void dropInstance();
+ static bool submitBuffer(const char *buffer, size_t len);
+
+ template <typename T>
+ struct is_item_type {
+ static constexpr inline bool value =
+ std::is_same<T, int32_t>::value
+ || std::is_same<T, int64_t>::value
+ || std::is_same<T, double>::value
+ || std::is_same<T, std::pair<int64_t, int64_t>>:: value
+ || std::is_same<T, std::string>::value
+ || std::is_same<T, std::monostate>::value;
+ };
+
+ template <typename T>
+ struct get_type_of {
+ static_assert(is_item_type<T>::value);
+ static constexpr inline Type value =
+ std::is_same<T, int32_t>::value ? kTypeInt32
+ : std::is_same<T, int64_t>::value ? kTypeInt64
+ : std::is_same<T, double>::value ? kTypeDouble
+ : std::is_same<T, std::pair<int64_t, int64_t>>:: value ? kTypeRate
+ : std::is_same<T, std::string>::value ? kTypeCString
+ : std::is_same<T, std::monostate>::value ? kTypeNone
+ : kTypeNone;
+ };
+
+ template <typename T>
+ static size_t sizeOfByteString(const char *name, const T& value) {
+ static_assert(is_item_type<T>::value);
+ return 2 + 1 + strlen(name) + 1 + sizeof(value);
+ }
+ template <> // static
+ size_t sizeOfByteString(const char *name, const std::string& value) {
+ return 2 + 1 + strlen(name) + 1 + value.size() + 1;
+ }
+ template <> // static
+ size_t sizeOfByteString(const char *name, const std::monostate&) {
+ return 2 + 1 + strlen(name) + 1;
+ }
+ // for speed
+ static size_t sizeOfByteString(const char *name, const char *value) {
+ return 2 + 1 + strlen(name) + 1 + strlen(value) + 1;
+ }
+
+ template <typename T>
+ static status_t insert(const T& val, char **bufferpptr, char *bufferptrmax) {
+ static_assert(std::is_trivially_constructible<T>::value);
+ const size_t size = sizeof(val);
+ if (*bufferpptr + size > bufferptrmax) {
+ ALOGE("%s: buffer exceeded with size %zu", __func__, size);
+ return BAD_VALUE;
+ }
+ memcpy(*bufferpptr, &val, size);
+ *bufferpptr += size;
+ return NO_ERROR;
+ }
+ template <> // static
+ status_t insert(const std::string& val, char **bufferpptr, char *bufferptrmax) {
+ const size_t size = val.size() + 1;
+ if (size > UINT16_MAX || *bufferpptr + size > bufferptrmax) {
+ ALOGE("%s: buffer exceeded with size %zu", __func__, size);
+ return BAD_VALUE;
+ }
+ memcpy(*bufferpptr, val.c_str(), size);
+ *bufferpptr += size;
+ return NO_ERROR;
+ }
+ template <> // static
+ status_t insert(const std::pair<int64_t, int64_t>& val,
+ char **bufferpptr, char *bufferptrmax) {
+ const size_t size = sizeof(val.first) + sizeof(val.second);
+ if (*bufferpptr + size > bufferptrmax) {
+ ALOGE("%s: buffer exceeded with size %zu", __func__, size);
+ return BAD_VALUE;
+ }
+ memcpy(*bufferpptr, &val.first, sizeof(val.first));
+ memcpy(*bufferpptr + sizeof(val.first), &val.second, sizeof(val.second));
+ *bufferpptr += size;
+ return NO_ERROR;
+ }
+ template <> // static
+ status_t insert(const std::monostate&, char **, char *) {
+ return NO_ERROR;
+ }
+ // for speed
+ static status_t insert(const char *val, char **bufferpptr, char *bufferptrmax) {
+ const size_t size = strlen(val) + 1;
+ if (size > UINT16_MAX || *bufferpptr + size > bufferptrmax) {
+ ALOGE("%s: buffer exceeded with size %zu", __func__, size);
+ return BAD_VALUE;
+ }
+ memcpy(*bufferpptr, val, size);
+ *bufferpptr += size;
+ return NO_ERROR;
+ }
+
+ template <typename T>
+ static status_t writeToByteString(
+ const char *name, const T& value, char **bufferpptr, char *bufferptrmax) {
+ static_assert(is_item_type<T>::value);
+ const size_t len = sizeOfByteString(name, value);
+ if (len > UINT16_MAX) return BAD_VALUE;
+ return insert((uint16_t)len, bufferpptr, bufferptrmax)
+ ?: insert((uint8_t)get_type_of<T>::value, bufferpptr, bufferptrmax)
+ ?: insert(name, bufferpptr, bufferptrmax)
+ ?: insert(value, bufferpptr, bufferptrmax);
+ }
+ // for speed
+ static status_t writeToByteString(
+ const char *name, const char *value, char **bufferpptr, char *bufferptrmax) {
+ const size_t len = sizeOfByteString(name, value);
+ if (len > UINT16_MAX) return BAD_VALUE;
+ return insert((uint16_t)len, bufferpptr, bufferptrmax)
+ ?: insert((uint8_t)kTypeCString, bufferpptr, bufferptrmax)
+ ?: insert(name, bufferpptr, bufferptrmax)
+ ?: insert(value, bufferpptr, bufferptrmax);
+ }
+
+ template <typename T>
+ static void toStringBuffer(
+ const char *name, const T& value, char *buffer, size_t length) = delete;
+ template <> // static
+ void toStringBuffer(
+ const char *name, const int32_t& value, char *buffer, size_t length) {
+ snprintf(buffer, length, "%s=%d", name, value);
+ }
+ template <> // static
+ void toStringBuffer(
+ const char *name, const int64_t& value, char *buffer, size_t length) {
+ snprintf(buffer, length, "%s=%lld", name, (long long)value);
+ }
+ template <> // static
+ void toStringBuffer(
+ const char *name, const double& value, char *buffer, size_t length) {
+ snprintf(buffer, length, "%s=%e", name, value);
+ }
+ template <> // static
+ void toStringBuffer(
+ const char *name, const std::pair<int64_t, int64_t>& value,
+ char *buffer, size_t length) {
+ snprintf(buffer, length, "%s=%lld/%lld",
+ name, (long long)value.first, (long long)value.second);
+ }
+ template <> // static
+ void toStringBuffer(
+ const char *name, const std::string& value, char *buffer, size_t length) {
+ // TODO sanitize string for ':' '='
+ snprintf(buffer, length, "%s=%s", name, value.c_str());
+ }
+ template <> // static
+ void toStringBuffer(
+ const char *name, const std::monostate&, char *buffer, size_t length) {
+ snprintf(buffer, length, "%s=()", name);
+ }
+
+ template <typename T>
+ static status_t writeToParcel(
+ const char *name, const T& value, Parcel *parcel) = delete;
+ template <> // static
+ status_t writeToParcel(
+ const char *name, const int32_t& value, Parcel *parcel) {
+ return parcel->writeCString(name)
+ ?: parcel->writeInt32(get_type_of<int32_t>::value)
+ ?: parcel->writeInt32(value);
+ }
+ template <> // static
+ status_t writeToParcel(
+ const char *name, const int64_t& value, Parcel *parcel) {
+ return parcel->writeCString(name)
+ ?: parcel->writeInt32(get_type_of<int64_t>::value)
+ ?: parcel->writeInt64(value);
+ }
+ template <> // static
+ status_t writeToParcel(
+ const char *name, const double& value, Parcel *parcel) {
+ return parcel->writeCString(name)
+ ?: parcel->writeInt32(get_type_of<double>::value)
+ ?: parcel->writeDouble(value);
+ }
+ template <> // static
+ status_t writeToParcel(
+ const char *name, const std::pair<int64_t, int64_t>& value, Parcel *parcel) {
+ return parcel->writeCString(name)
+ ?: parcel->writeInt32(get_type_of< std::pair<int64_t, int64_t>>::value)
+ ?: parcel->writeInt64(value.first)
+ ?: parcel->writeInt64(value.second);
+ }
+ template <> // static
+ status_t writeToParcel(
+ const char *name, const std::string& value, Parcel *parcel) {
+ return parcel->writeCString(name)
+ ?: parcel->writeInt32(get_type_of<std::string>::value)
+ ?: parcel->writeCString(value.c_str());
+ }
+ template <> // static
+ status_t writeToParcel(
+ const char *name, const std::monostate&, Parcel *parcel) {
+ return parcel->writeCString(name)
+ ?: parcel->writeInt32(get_type_of<std::monostate>::value);
+ }
+
+ template <typename T>
+ static status_t extract(T *val, const char **bufferpptr, const char *bufferptrmax) {
+ static_assert(std::is_trivially_constructible<T>::value);
+ const size_t size = sizeof(*val);
+ if (*bufferpptr + size > bufferptrmax) {
+ ALOGE("%s: buffer exceeded with size %zu", __func__, size);
+ return BAD_VALUE;
+ }
+ memcpy(val, *bufferpptr, size);
+ *bufferpptr += size;
+ return NO_ERROR;
+ }
+ template <> // static
+ status_t extract(std::string *val, const char **bufferpptr, const char *bufferptrmax) {
+ const char *ptr = *bufferpptr;
+ while (*ptr != 0) {
+ if (ptr >= bufferptrmax) {
+ ALOGE("%s: buffer exceeded", __func__);
+ return BAD_VALUE;
+ }
+ ++ptr;
+ }
+ const size_t size = (ptr - *bufferpptr) + 1;
+ *val = *bufferpptr;
+ *bufferpptr += size;
+ return NO_ERROR;
+ }
+ template <> // static
+ status_t extract(std::pair<int64_t, int64_t> *val,
+ const char **bufferpptr, const char *bufferptrmax) {
+ const size_t size = sizeof(val->first) + sizeof(val->second);
+ if (*bufferpptr + size > bufferptrmax) {
+ ALOGE("%s: buffer exceeded with size %zu", __func__, size);
+ return BAD_VALUE;
+ }
+ memcpy(&val->first, *bufferpptr, sizeof(val->first));
+ memcpy(&val->second, *bufferpptr + sizeof(val->first), sizeof(val->second));
+ *bufferpptr += size;
+ return NO_ERROR;
+ }
+ template <> // static
+ status_t extract(std::monostate *, const char **, const char *) {
+ return NO_ERROR;
+ }
+};
+
+/**
+ * Media Metrics BufferedItem
+ *
+ * A base class which represents a put-only Media Metrics item, storing
+ * the Media Metrics data in a buffer with begin and end pointers.
+ *
+ * If a property key is entered twice, it will be stored in the buffer twice,
+ * and (implementation defined) the last value for that key will be used
+ * by the Media Metrics service.
+ *
+ * For realloc, a baseRealloc pointer must be passed in either explicitly
+ * or implicitly in the constructor. This will be updated with the value used on realloc.
+ */
+class BufferedItem : public BaseItem {
+public:
+ static inline constexpr uint16_t kVersion = 0;
+
+ virtual ~BufferedItem() = default;
+ BufferedItem(const BufferedItem&) = delete;
+ BufferedItem& operator=(const BufferedItem&) = delete;
+
+ BufferedItem(const std::string key, char *begin, char *end)
+ : BufferedItem(key.c_str(), begin, end) { }
+
+ BufferedItem(const char *key, char *begin, char *end)
+ : BufferedItem(key, begin, end, nullptr) { }
+
+ BufferedItem(const char *key, char **begin, char *end)
+ : BufferedItem(key, *begin, end, begin) { }
+
+ BufferedItem(const char *key, char *begin, char *end, char **baseRealloc)
+ : mBegin(begin)
+ , mEnd(end)
+ , mBaseRealloc(baseRealloc)
+ {
+ init(key);
+ }
+
+ template<typename T>
+ BufferedItem &set(const char *key, const T& value) {
+ reallocFor(sizeOfByteString(key, value));
+ if (mStatus == NO_ERROR) {
+ mStatus = BaseItem::writeToByteString(key, value, &mBptr, mEnd);
+ ++mPropCount;
+ }
+ return *this;
+ }
+
+ template<typename T>
+ BufferedItem &set(const std::string& key, const T& value) {
+ return set(key.c_str(), value);
+ }
+
+ BufferedItem &setPid(pid_t pid) {
+ if (mStatus == NO_ERROR) {
+ copyTo(mBegin + mHeaderLen - 16, (int32_t)pid);
+ }
+ return *this;
+ }
+
+ BufferedItem &setUid(uid_t uid) {
+ if (mStatus == NO_ERROR) {
+ copyTo(mBegin + mHeaderLen - 12, (int32_t)uid);
+ }
+ return *this;
+ }
+
+ BufferedItem &setTimestamp(nsecs_t timestamp) {
+ if (mStatus == NO_ERROR) {
+ copyTo(mBegin + mHeaderLen - 8, (int64_t)timestamp);
+ }
+ return *this;
+ }
+
+ bool record() {
+ return updateHeader()
+ && BaseItem::submitBuffer(getBuffer(), getLength());
+ }
+
+ bool isValid () const {
+ return mStatus == NO_ERROR;
+ }
+
+ char *getBuffer() const { return mBegin; }
+ size_t getLength() const { return mBptr - mBegin; }
+ size_t getRemaining() const { return mEnd - mBptr; }
+ size_t getCapacity() const { return mEnd - mBegin; }
+
+ bool updateHeader() {
+ if (mStatus != NO_ERROR) return false;
+ copyTo(mBegin + 0, (uint32_t)getLength());
+ copyTo(mBegin + 4, (uint32_t)mHeaderLen);
+ copyTo(mBegin + mHeaderLen, (uint32_t)mPropCount);
+ return true;
+ }
+
+protected:
+ BufferedItem() = default;
+
+ void reallocFor(size_t required) {
+ if (mStatus != NO_ERROR) return;
+ const size_t remaining = getRemaining();
+ if (required <= remaining) return;
+ if (mBaseRealloc == nullptr) {
+ mStatus = NO_MEMORY;
+ return;
+ }
+
+ const size_t current = getLength();
+ size_t minimum = current + required;
+ if (minimum > SSIZE_MAX >> 1) {
+ mStatus = NO_MEMORY;
+ return;
+ }
+ minimum <<= 1;
+ void *newptr = realloc(*mBaseRealloc, minimum);
+ if (newptr == nullptr) {
+ mStatus = NO_MEMORY;
+ return;
+ }
+ if (newptr != *mBaseRealloc) {
+ // ALOGD("base changed! current:%zu new size %zu", current, minimum);
+ if (*mBaseRealloc == nullptr) {
+ memcpy(newptr, mBegin, current);
+ }
+ mBegin = (char *)newptr;
+ *mBaseRealloc = mBegin;
+ mEnd = mBegin + minimum;
+ mBptr = mBegin + current;
+ } else {
+ // ALOGD("base kept! current:%zu new size %zu", current, minimum);
+ mEnd = mBegin + minimum;
+ }
+ }
+ template<typename T>
+ void copyTo(char *ptr, const T& value) {
+ memcpy(ptr, &value, sizeof(value));
+ }
+
+ void init(const char *key) {
+ mBptr = mBegin;
+ const size_t keylen = key == nullptr ? 0 : strlen(key) + 1;
+ if (keylen <= 1) {
+ mStatus = BAD_VALUE; // prevent null pointer or empty keys.
+ return;
+ }
+ mHeaderLen = 4 + 4 + 2 + 2 + keylen + 4 + 4 + 8;
+ reallocFor(mHeaderLen);
+ if (mStatus != NO_ERROR) return;
+ mBptr = mBegin + mHeaderLen + 4; // this includes propcount.
+
+ if (mEnd < mBptr || keylen > UINT16_MAX) {
+ mStatus = NO_MEMORY;
+ mBptr = mEnd;
+ return;
+ }
+ copyTo(mBegin + 8, kVersion);
+ copyTo(mBegin + 10, (uint16_t)keylen);
+ strcpy(mBegin + 12, key);
+
+ // initialize some parameters (that could be overridden)
+ setPid(-1);
+ setUid(-1);
+ setTimestamp(0);
+ }
+
+ char *mBegin = nullptr;
+ char *mEnd = nullptr;
+ char **mBaseRealloc = nullptr; // set to an address if realloc should be done.
+ // upon return, that pointer is updated with
+ // whatever needs to be freed.
+ char *mBptr = nullptr;
+ status_t mStatus = NO_ERROR;
+ uint32_t mPropCount = 0;
+ uint32_t mHeaderLen = 0;
+};
+
+/**
+ * MediaMetrics LogItem is a stack allocated mediametrics item used for
+ * fast logging. It falls over to a malloc if needed.
+ *
+ * This is templated with a buffer size to allocate on the stack.
+ */
+template <size_t N = 4096>
+class LogItem : public BufferedItem {
+public:
+ explicit LogItem(const std::string key) : LogItem(key.c_str()) { }
+
+ // Since this class will not be defined before the base class, we initialize variables
+ // in our own order.
+ explicit LogItem(const char *key) {
+ mBegin = mBuffer;
+ mEnd = mBuffer + N;
+ mBaseRealloc = &mReallocPtr;
+ init(key);
+ }
+
+ ~LogItem() override {
+ if (mReallocPtr != nullptr) { // do the check before calling free to avoid overhead.
+ free(mReallocPtr);
+ }
+ }
+
+private:
+ char *mReallocPtr = nullptr; // set non-null by base class if realloc happened.
+ char mBuffer[N];
+};
+
+
+/**
+ * Media Metrics Item
+ *
+ * A mutable item representing an event or record that will be
+ * logged with the Media Metrics service. For client logging, one should
+ * use the mediametrics::Item.
+ *
+ * The Item is designed for the service as it has getters.
+ */
+class Item final : public mediametrics::BaseItem {
+public:
+
+ class Prop {
+ public:
+ using Elem = std::variant<
+ std::monostate, // kTypeNone
+ int32_t, // kTypeInt32
+ int64_t, // kTypeInt64
+ double, // kTypeDouble
+ std::string, // kTypeCString
+ std::pair<int64_t, int64_t> // kTypeRate
+ >;
+
+ Prop() = default;
+ Prop(const Prop& other) {
+ *this = other;
+ }
+ Prop& operator=(const Prop& other) {
+ mName = other.mName;
+ mElem = other.mElem;
+ return *this;
+ }
+ Prop(Prop&& other) {
+ *this = std::move(other);
+ }
+ Prop& operator=(Prop&& other) {
+ mName = std::move(other.mName);
+ mElem = std::move(other.mElem);
+ return *this;
+ }
+
+ bool operator==(const Prop& other) const {
+ return mName == other.mName && mElem == other.mElem;
+ }
+ bool operator!=(const Prop& other) const {
+ return !(*this == other);
+ }
+
+ void clear() {
+ mName.clear();
+ mElem = std::monostate{};
+ }
+ void clearValue() {
+ mElem = std::monostate{};
+ }
+
+ const char *getName() const {
+ return mName.c_str();
+ }
+
+ void swap(Prop& other) {
+ std::swap(mName, other.mName);
+ std::swap(mElem, other.mElem);
+ }
+
+ void setName(const char *name) {
+ mName = name;
+ }
+
+ bool isNamed(const char *name) const {
+ return mName == name;
+ }
+
+ template <typename T> void visit(T f) const {
+ std::visit(f, mElem);
+ }
+
+ template <typename T> bool get(T *value) const {
+ auto pval = std::get_if<T>(&mElem);
+ if (pval != nullptr) {
+ *value = *pval;
+ return true;
+ }
+ return false;
+ }
+
+ const Elem& get() const {
+ return mElem;
+ }
+
+ template <typename T> void set(const T& value) {
+ mElem = value;
+ }
+
+ template <typename T> void add(const T& value) {
+ auto pval = std::get_if<T>(&mElem);
+ if (pval != nullptr) {
+ *pval += value;
+ } else {
+ mElem = value;
+ }
+ }
+
+ template <> void add(const std::pair<int64_t, int64_t>& value) {
+ auto pval = std::get_if<std::pair<int64_t, int64_t>>(&mElem);
+ if (pval != nullptr) {
+ pval->first += value.first;
+ pval->second += value.second;
+ } else {
+ mElem = value;
+ }
+ }
+
+ status_t writeToParcel(Parcel *parcel) const {
+ return std::visit([this, parcel](auto &value) {
+ return BaseItem::writeToParcel(mName.c_str(), value, parcel);}, mElem);
+ }
+
+ void toStringBuffer(char *buffer, size_t length) const {
+ return std::visit([this, buffer, length](auto &value) {
+ BaseItem::toStringBuffer(mName.c_str(), value, buffer, length);}, mElem);
+ }
+
+ size_t getByteStringSize() const {
+ return std::visit([this](auto &value) {
+ return BaseItem::sizeOfByteString(mName.c_str(), value);}, mElem);
+ }
+
+ status_t writeToByteString(char **bufferpptr, char *bufferptrmax) const {
+ return std::visit([this, bufferpptr, bufferptrmax](auto &value) {
+ return BaseItem::writeToByteString(mName.c_str(), value, bufferpptr, bufferptrmax);
+ }, mElem);
+ }
+
+ status_t readFromParcel(const Parcel& data);
+
+ status_t readFromByteString(const char **bufferpptr, const char *bufferptrmax);
+
+ private:
+ std::string mName;
+ Elem mElem;
+ };
+
+ // Iteration of props within item
+ class iterator {
+ public:
+ iterator(const std::map<std::string, Prop>::const_iterator &_it) : it(_it) { }
+ iterator &operator++() {
+ ++it;
+ return *this;
+ }
+ bool operator!=(iterator &other) const {
+ return it != other.it;
+ }
+ const Prop &operator*() const {
+ return it->second;
+ }
+
+ private:
+ std::map<std::string, Prop>::const_iterator it;
+ };
+
+ iterator begin() const {
+ return iterator(mProps.cbegin());
+ }
+
+ iterator end() const {
+ return iterator(mProps.cend());
+ }
+
+ // T must be convertible to mKey
+ template <typename T>
+ explicit Item(T key)
+ : mKey(key) { }
+ Item() = default;
+
+ // We enable default copy and move constructors and make this class final
+ // to prevent a derived class; this avoids possible data slicing.
+ Item(const Item& other) = default;
+ Item(Item&& other) = default;
+ Item& operator=(const Item& other) = default;
+ Item& operator=(Item&& other) = default;
+
+ bool operator==(const Item& other) const {
+ return mPid == other.mPid
+ && mUid == other.mUid
+ && mPkgName == other.mPkgName
+ && mPkgVersionCode == other.mPkgVersionCode
+ && mKey == other.mKey
+ && mTimestamp == other.mTimestamp
+ && mProps == other.mProps
+ ;
+ }
+ bool operator!=(const Item& other) const {
+ return !(*this == other);
+ }
+
+ template <typename T>
+ static Item* create(T key) {
+ return new Item(key);
+ }
+ static Item* create() {
+ return new Item();
+ }
+
+ static Item* convert(mediametrics_handle_t);
+ static mediametrics_handle_t convert(Item *);
+
+ // access functions for the class
+ ~Item();
+
+ void clear() {
+ mPid = -1;
+ mUid = -1;
+ mPkgName.clear();
+ mPkgVersionCode = 0;
+ mTimestamp = 0;
+ mKey.clear();
+ mProps.clear();
+ }
+
+ Item *dup() const { return new Item(*this); }
+
+ Item &setKey(const char *key) {
+ mKey = key;
+ return *this;
+ }
+ const std::string& getKey() const { return mKey; }
+
+ // # of properties in the record
+ size_t count() const { return mProps.size(); }
+
+ template<typename S, typename T>
+ Item &set(S key, T value) {
+ findOrAllocateProp(key).set(value);
+ return *this;
+ }
+
+ // set values appropriately
+ Item &setInt32(const char *key, int32_t value) {
+ return set(key, value);
+ }
+ Item &setInt64(const char *key, int64_t value) {
+ return set(key, value);
+ }
+ Item &setDouble(const char *key, double value) {
+ return set(key, value);
+ }
+ Item &setRate(const char *key, int64_t count, int64_t duration) {
+ return set(key, std::make_pair(count, duration));
+ }
+ Item &setCString(const char *key, const char *value) {
+ return set(key, value);
+ }
+
+ // fused get/add/set; if attr wasn't there, it's a simple set.
+ // type-mismatch counts as "wasn't there".
+ template<typename S, typename T>
+ Item &add(S key, T value) {
+ findOrAllocateProp(key).add(value);
+ return *this;
+ }
+
+ Item &addInt32(const char *key, int32_t value) {
+ return add(key, value);
+ }
+ Item &addInt64(const char *key, int64_t value) {
+ return add(key, value);
+ }
+ Item &addDouble(const char *key, double value) {
+ return add(key, value);
+ }
+ Item &addRate(const char *key, int64_t count, int64_t duration) {
+ return add(key, std::make_pair(count, duration));
+ }
+
+ // find & extract values
+ // return indicates whether attr exists (and thus value filled in)
+ // NULL parameter value suppresses storage of value.
+ template<typename S, typename T>
+ bool get(S key, T *value) const {
+ const Prop *prop = findProp(key);
+ return prop != nullptr && prop->get(value);
+ }
+
+ bool getInt32(const char *key, int32_t *value) const {
+ return get(key, value);
+ }
+ bool getInt64(const char *key, int64_t *value) const {
+ return get(key, value);
+ }
+ bool getDouble(const char *key, double *value) const {
+ return get(key, value);
+ }
+ bool getRate(const char *key, int64_t *count, int64_t *duration, double *rate) const {
+ std::pair<int64_t, int64_t> value;
+ if (!get(key, &value)) return false;
+ if (count != nullptr) *count = value.first;
+ if (duration != nullptr) *duration = value.second;
+ if (rate != nullptr) {
+ if (value.second != 0) {
+ *rate = (double)value.first / value.second; // TODO: isn't INF OK?
+ } else {
+ *rate = 0.;
+ }
+ }
+ return true;
+ }
+ // Caller owns the returned string
+ bool getCString(const char *key, char **value) const {
+ std::string s;
+ if (get(key, &s)) {
+ *value = strdup(s.c_str());
+ return true;
+ }
+ return false;
+ }
+ bool getString(const char *key, std::string *value) const {
+ return get(key, value);
+ }
+
+ const Prop::Elem* get(const char *key) const {
+ const Prop *prop = findProp(key);
+ return prop == nullptr ? nullptr : &prop->get();
+ }
+
+ // Deliver the item to MediaMetrics
+ bool selfrecord();
+
+ // remove indicated attributes and their values
+ // filterNot() could also be called keepOnly()
+ // return value is # attributes removed
+ // XXX: perhaps 'remove' instead of 'filter'
+ // XXX: filterNot would become 'keep'
+ size_t filter(size_t count, const char *attrs[]);
+ size_t filterNot(size_t count, const char *attrs[]);
+ size_t filter(const char *attr) { return filter(1, &attr); }
+
+ // below here are used on server side or to talk to server
+ // clients need not worry about these.
+
+ // timestamp, pid, and uid only used on server side
+ // timestamp is in 'nanoseconds, unix time'
+ Item &setTimestamp(nsecs_t);
+ nsecs_t getTimestamp() const;
+
+ Item &setPid(pid_t);
+ pid_t getPid() const;
+
+ Item &setUid(uid_t);
+ uid_t getUid() const;
+
+ Item &setPkgName(const std::string &pkgName);
+ std::string getPkgName() const { return mPkgName; }
+
+ Item &setPkgVersionCode(int64_t);
+ int64_t getPkgVersionCode() const;
+
+ // our serialization code for binder calls
+ status_t writeToParcel(Parcel *) const;
+ status_t readFromParcel(const Parcel&);
+
+ status_t writeToByteString(char **bufferptr, size_t *length) const;
+ status_t readFromByteString(const char *bufferptr, size_t length);
+
+
+ std::string toString() const;
+ const char *toCString();
+
+ /**
+ * Returns true if the item has a property with a target value.
+ *
+ * If propName is nullptr, hasPropElem() returns false.
+ *
+ * \param propName is the property name.
+ * \param elem is the value to match. std::monostate matches any.
+ */
+ bool hasPropElem(const char *propName, const Prop::Elem& elem) const {
+ if (propName == nullptr) return false;
+ const Prop::Elem *e = get(propName);
+ return e != nullptr && (std::holds_alternative<std::monostate>(elem) || elem == *e);
+ }
+
+ /**
+ * Returns -2, -1, 0 (success) if the item has a property (wildcard matched) with a
+ * target value.
+ *
+ * The enum RecursiveWildcardCheck designates the meaning of the returned value.
+ *
+ * RECURSIVE_WILDCARD_CHECK_NO_MATCH_NO_WILDCARD = -2,
+ * RECURSIVE_WILDCARD_CHECK_NO_MATCH_WILDCARD_FOUND = -1,
+ * RECURSIVE_WILDCARD_CHECK_MATCH_FOUND = 0.
+ *
+ * If url is nullptr, RECURSIVE_WILDCARD_CHECK_NO_MATCH_NO_WILDCARD is returned.
+ *
+ * \param url is the full item + property name, which may have wildcards '*'
+ * denoting an arbitrary sequence of 0 or more characters.
+ * \param elem is the target property value to match. std::monostate matches any.
+ * \return 0 if the property was matched,
+ * -1 if the property was not matched and a wildcard char was encountered,
+ * -2 if the property was not matched with no wildcard char encountered.
+ */
+ enum RecursiveWildcardCheck {
+ RECURSIVE_WILDCARD_CHECK_NO_MATCH_NO_WILDCARD = -2,
+ RECURSIVE_WILDCARD_CHECK_NO_MATCH_WILDCARD_FOUND = -1,
+ RECURSIVE_WILDCARD_CHECK_MATCH_FOUND = 0,
+ };
+
+ enum RecursiveWildcardCheck recursiveWildcardCheckElem(
+ const char *url, const Prop::Elem& elem) const {
+ if (url == nullptr) return RECURSIVE_WILDCARD_CHECK_NO_MATCH_NO_WILDCARD;
+ return recursiveWildcardCheckElem(getKey().c_str(), url, elem);
+ }
+
+private:
+
+ enum RecursiveWildcardCheck recursiveWildcardCheckElem(
+ const char *itemKeyPtr, const char *url, const Prop::Elem& elem) const {
+ for (; *url && *itemKeyPtr; ++url, ++itemKeyPtr) {
+ if (*url != *itemKeyPtr) {
+ if (*url == '*') { // wildcard
+ ++url;
+ while (true) {
+ if (recursiveWildcardCheckElem(itemKeyPtr, url, elem)
+ == RECURSIVE_WILDCARD_CHECK_MATCH_FOUND) {
+ return RECURSIVE_WILDCARD_CHECK_MATCH_FOUND;
+ }
+ if (*itemKeyPtr == 0) break;
+ ++itemKeyPtr;
+ }
+ return RECURSIVE_WILDCARD_CHECK_NO_MATCH_WILDCARD_FOUND;
+ }
+ return RECURSIVE_WILDCARD_CHECK_NO_MATCH_NO_WILDCARD;
+ }
+ }
+ if (itemKeyPtr[0] != 0 || url[0] != '.') {
+ return RECURSIVE_WILDCARD_CHECK_NO_MATCH_NO_WILDCARD;
+ }
+ const char *propName = url + 1; // skip the '.'
+ return hasPropElem(propName, elem)
+ ? RECURSIVE_WILDCARD_CHECK_MATCH_FOUND
+ : RECURSIVE_WILDCARD_CHECK_NO_MATCH_NO_WILDCARD;
+ }
+
+ // handle Parcel version 0
+ int32_t writeToParcel0(Parcel *) const;
+ int32_t readFromParcel0(const Parcel&);
+
+ const Prop *findProp(const char *key) const {
+ auto it = mProps.find(key);
+ return it != mProps.end() ? &it->second : nullptr;
+ }
+
+ Prop &findOrAllocateProp(const char *key) {
+ auto it = mProps.find(key);
+ if (it != mProps.end()) return it->second;
+ Prop &prop = mProps[key];
+ prop.setName(key);
+ return prop;
+ }
+
+ // Changes to member variables below require changes to clear().
+ pid_t mPid = -1;
+ uid_t mUid = -1;
+ std::string mPkgName;
+ int64_t mPkgVersionCode = 0;
+ std::string mKey;
+ nsecs_t mTimestamp = 0;
+ std::map<std::string, Prop> mProps;
+};
+
+} // namespace mediametrics
+} // namespace android
+
+#endif // ANDROID_MEDIA_MEDIAMETRICSITEM_H
diff --git a/media/libmediaplayer2/Android.bp b/media/libmediaplayer2/Android.bp
deleted file mode 100644
index dca6bb6..0000000
--- a/media/libmediaplayer2/Android.bp
+++ /dev/null
@@ -1,129 +0,0 @@
-cc_library_headers {
- name: "libmediaplayer2_headers",
- vendor_available: true,
- export_include_dirs: ["include"],
-}
-
-cc_library_static {
- name: "libmediaplayer2",
-
- srcs: [
- "MediaPlayer2AudioOutput.cpp",
- "mediaplayer2.cpp",
- ],
-
- shared_libs: [
- "libandroid_runtime",
- "libaudioclient",
- "libbinder",
- "libbinder_ndk",
- "libcutils",
- "libgui",
- "liblog",
- "libmedia_omx",
- "libui",
- "libutils",
-
- "libcrypto",
- "libmediametrics",
- "libmediandk",
- "libmediandk_utils",
- "libmediautils",
- "libmemunreachable",
- "libnativewindow",
- "libpowermanager",
- "libstagefright_httplive",
- ],
-
- export_shared_lib_headers: [
- "libaudioclient",
- "libbinder",
- "libgui",
- "libmedia_omx",
- ],
-
- header_libs: [
- "media_plugin_headers",
- ],
-
- include_dirs: [
- "frameworks/base/core/jni",
- ],
-
- static_libs: [
- "libmedia_helper",
- "libmediaplayer2-protos",
- "libmedia_player2_util",
- "libprotobuf-cpp-lite",
- "libstagefright_foundation_without_imemory",
- "libstagefright_nuplayer2",
- "libstagefright_player2",
- "libstagefright_rtsp",
- "libstagefright_timedtext2",
- "libmedia2_jni_core",
- ],
-
- export_include_dirs: [
- "include",
- ],
-
- cflags: [
- "-Werror",
- "-Wno-error=deprecated-declarations",
- "-Wall",
- ],
-
- sanitize: {
- misc_undefined: [
- "unsigned-integer-overflow",
- "signed-integer-overflow",
- ],
- cfi: true,
- },
-}
-
-cc_library {
- name: "libmedia2_jni_core",
-
- srcs: [
- "JavaVMHelper.cpp",
- "JAudioTrack.cpp",
- "JMedia2HTTPService.cpp",
- "JMedia2HTTPConnection.cpp",
- ],
-
- header_libs: [
- "libbinder_headers",
- "libnativehelper_header_only",
- ],
-
- shared_libs: [
- "liblog",
- "libutils",
- "libdl",
- ],
-
- include_dirs: [
- "frameworks/av/media/libmedia/include",
- "frameworks/base/core/jni",
- ],
-
- export_include_dirs: [
- "include",
- ],
-
- cflags: [
- "-Werror",
- "-Wno-error=deprecated-declarations",
- "-Wall",
- ],
-
- sanitize: {
- misc_undefined: [
- "unsigned-integer-overflow",
- "signed-integer-overflow",
- ],
- cfi: true,
- },
-
-}
diff --git a/media/libmediaplayer2/JAudioTrack.cpp b/media/libmediaplayer2/JAudioTrack.cpp
deleted file mode 100644
index fab6c64..0000000
--- a/media/libmediaplayer2/JAudioTrack.cpp
+++ /dev/null
@@ -1,768 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "JAudioTrack"
-
-#include "media/JAudioAttributes.h"
-#include "media/JAudioFormat.h"
-#include "mediaplayer2/JAudioTrack.h"
-
-#include <android_media_AudioErrors.h>
-#include <mediaplayer2/JavaVMHelper.h>
-
-namespace android {
-
-// TODO: Store Java class/methodID as a member variable in the class.
-// TODO: Add NULL && Exception checks after every JNI call.
-JAudioTrack::JAudioTrack( // < Usages of the arguments are below >
- uint32_t sampleRate, // AudioFormat && bufferSizeInBytes
- audio_format_t format, // AudioFormat && bufferSizeInBytes
- audio_channel_mask_t channelMask, // AudioFormat && bufferSizeInBytes
- callback_t cbf, // Offload
- void* user, // Offload
- size_t frameCount, // bufferSizeInBytes
- int32_t sessionId, // AudioTrack
- const jobject attributes, // AudioAttributes
- float maxRequiredSpeed) { // bufferSizeInBytes
-
- JNIEnv *env = JavaVMHelper::getJNIEnv();
-
- jclass jAudioTrackCls = env->FindClass("android/media/AudioTrack");
- mAudioTrackCls = reinterpret_cast<jclass>(env->NewGlobalRef(jAudioTrackCls));
- env->DeleteLocalRef(jAudioTrackCls);
-
- maxRequiredSpeed = std::min(std::max(maxRequiredSpeed, 1.0f), AUDIO_TIMESTRETCH_SPEED_MAX);
-
- int bufferSizeInBytes = 0;
- if (sampleRate == 0 || frameCount > 0) {
- // Manually calculate buffer size.
- bufferSizeInBytes = audio_channel_count_from_out_mask(channelMask)
- * audio_bytes_per_sample(format) * (frameCount > 0 ? frameCount : 1);
- } else if (sampleRate > 0) {
- // Call Java AudioTrack::getMinBufferSize().
- jmethodID jGetMinBufferSize =
- env->GetStaticMethodID(mAudioTrackCls, "getMinBufferSize", "(III)I");
- bufferSizeInBytes = env->CallStaticIntMethod(mAudioTrackCls, jGetMinBufferSize,
- sampleRate, outChannelMaskFromNative(channelMask), audioFormatFromNative(format));
- }
- bufferSizeInBytes = (int) (bufferSizeInBytes * maxRequiredSpeed);
-
- // Create a Java AudioTrack object through its Builder.
- jclass jBuilderCls = env->FindClass("android/media/AudioTrack$Builder");
- jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
- jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
-
- {
- sp<JObjectHolder> audioAttributesObj;
- if (attributes != NULL) {
- audioAttributesObj = new JObjectHolder(attributes);
- } else {
- audioAttributesObj = new JObjectHolder(
- JAudioAttributes::createAudioAttributesObj(env, NULL));
- }
- jmethodID jSetAudioAttributes = env->GetMethodID(jBuilderCls, "setAudioAttributes",
- "(Landroid/media/AudioAttributes;)Landroid/media/AudioTrack$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderObj,
- jSetAudioAttributes, audioAttributesObj->getJObject());
- }
-
- jmethodID jSetAudioFormat = env->GetMethodID(jBuilderCls, "setAudioFormat",
- "(Landroid/media/AudioFormat;)Landroid/media/AudioTrack$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetAudioFormat,
- JAudioFormat::createAudioFormatObj(env, sampleRate, format, channelMask));
-
- jmethodID jSetBufferSizeInBytes = env->GetMethodID(jBuilderCls, "setBufferSizeInBytes",
- "(I)Landroid/media/AudioTrack$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetBufferSizeInBytes, bufferSizeInBytes);
-
- // We only use streaming mode of Java AudioTrack.
- jfieldID jModeStream = env->GetStaticFieldID(mAudioTrackCls, "MODE_STREAM", "I");
- jint transferMode = env->GetStaticIntField(mAudioTrackCls, jModeStream);
- jmethodID jSetTransferMode = env->GetMethodID(jBuilderCls, "setTransferMode",
- "(I)Landroid/media/AudioTrack$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetTransferMode,
- transferMode /* Java AudioTrack::MODE_STREAM */);
-
- if (sessionId != 0) {
- jmethodID jSetSessionId = env->GetMethodID(jBuilderCls, "setSessionId",
- "(I)Landroid/media/AudioTrack$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetSessionId, sessionId);
- }
-
- mFlags = AUDIO_OUTPUT_FLAG_NONE;
- if (cbf != NULL) {
- jmethodID jSetOffloadedPlayback = env->GetMethodID(jBuilderCls, "setOffloadedPlayback",
- "(Z)Landroid/media/AudioTrack$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetOffloadedPlayback, true);
- mFlags = AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
- }
-
- jmethodID jBuild = env->GetMethodID(jBuilderCls, "build", "()Landroid/media/AudioTrack;");
- jobject jAudioTrackObj = env->CallObjectMethod(jBuilderObj, jBuild);
- mAudioTrackObj = reinterpret_cast<jobject>(env->NewGlobalRef(jAudioTrackObj));
- env->DeleteLocalRef(jBuilderObj);
-
- if (cbf != NULL) {
- // Set offload mode callback
- jobject jStreamEventCallbackObj = createStreamEventCallback(cbf, user);
- jobject jExecutorObj = createCallbackExecutor();
- jmethodID jSetStreamEventCallback = env->GetMethodID(
- jAudioTrackCls,
- "setStreamEventCallback",
- "(Ljava/util/concurrent/Executor;Landroid/media/AudioTrack$StreamEventCallback;)V");
- env->CallVoidMethod(
- mAudioTrackObj, jSetStreamEventCallback, jExecutorObj, jStreamEventCallbackObj);
- }
-}
-
-JAudioTrack::~JAudioTrack() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- env->DeleteGlobalRef(mAudioTrackCls);
- env->DeleteGlobalRef(mAudioTrackObj);
-}
-
-size_t JAudioTrack::frameCount() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetBufferSizeInFrames = env->GetMethodID(
- mAudioTrackCls, "getBufferSizeInFrames", "()I");
- return env->CallIntMethod(mAudioTrackObj, jGetBufferSizeInFrames);
-}
-
-size_t JAudioTrack::channelCount() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetChannelCount = env->GetMethodID(mAudioTrackCls, "getChannelCount", "()I");
- return env->CallIntMethod(mAudioTrackObj, jGetChannelCount);
-}
-
-uint32_t JAudioTrack::latency() {
- // TODO: Currently hard-coded as returning zero.
- return 0;
-}
-
-status_t JAudioTrack::getPosition(uint32_t *position) {
- if (position == NULL) {
- return BAD_VALUE;
- }
-
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetPlaybackHeadPosition = env->GetMethodID(
- mAudioTrackCls, "getPlaybackHeadPosition", "()I");
- *position = env->CallIntMethod(mAudioTrackObj, jGetPlaybackHeadPosition);
-
- return NO_ERROR;
-}
-
-status_t JAudioTrack::getTimestamp(AudioTimestamp& timestamp) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
-
- jclass jAudioTimeStampCls = env->FindClass("android/media/AudioTimestamp");
- jobject jAudioTimeStampObj = env->AllocObject(jAudioTimeStampCls);
-
- jfieldID jFramePosition = env->GetFieldID(jAudioTimeStampCls, "framePosition", "J");
- jfieldID jNanoTime = env->GetFieldID(jAudioTimeStampCls, "nanoTime", "J");
-
- jmethodID jGetTimestamp = env->GetMethodID(mAudioTrackCls,
- "getTimestamp", "(Landroid/media/AudioTimestamp;)Z");
- bool success = env->CallBooleanMethod(mAudioTrackObj, jGetTimestamp, jAudioTimeStampObj);
-
- if (!success) {
- return NO_INIT;
- }
-
- long long framePosition = env->GetLongField(jAudioTimeStampObj, jFramePosition);
- long long nanoTime = env->GetLongField(jAudioTimeStampObj, jNanoTime);
-
- struct timespec ts;
- const long long secondToNano = 1000000000LL; // 1E9
- ts.tv_sec = nanoTime / secondToNano;
- ts.tv_nsec = nanoTime % secondToNano;
- timestamp.mTime = ts;
- timestamp.mPosition = (uint32_t) framePosition;
-
- return NO_ERROR;
-}
-
-status_t JAudioTrack::getTimestamp(ExtendedTimestamp *timestamp __unused) {
- // TODO: Implement this after appropriate Java AudioTrack method is available.
- return NO_ERROR;
-}
-
-status_t JAudioTrack::setPlaybackRate(const AudioPlaybackRate &playbackRate) {
- // TODO: existing native AudioTrack returns INVALID_OPERATION on offload/direct/fast tracks.
- // Should we do the same thing?
- JNIEnv *env = JavaVMHelper::getJNIEnv();
-
- jclass jPlaybackParamsCls = env->FindClass("android/media/PlaybackParams");
- jmethodID jPlaybackParamsCtor = env->GetMethodID(jPlaybackParamsCls, "<init>", "()V");
- jobject jPlaybackParamsObj = env->NewObject(jPlaybackParamsCls, jPlaybackParamsCtor);
-
- jmethodID jSetAudioFallbackMode = env->GetMethodID(
- jPlaybackParamsCls, "setAudioFallbackMode", "(I)Landroid/media/PlaybackParams;");
- jPlaybackParamsObj = env->CallObjectMethod(
- jPlaybackParamsObj, jSetAudioFallbackMode, playbackRate.mFallbackMode);
-
- jmethodID jSetAudioStretchMode = env->GetMethodID(
- jPlaybackParamsCls, "setAudioStretchMode", "(I)Landroid/media/PlaybackParams;");
- jPlaybackParamsObj = env->CallObjectMethod(
- jPlaybackParamsObj, jSetAudioStretchMode, playbackRate.mStretchMode);
-
- jmethodID jSetPitch = env->GetMethodID(
- jPlaybackParamsCls, "setPitch", "(F)Landroid/media/PlaybackParams;");
- jPlaybackParamsObj = env->CallObjectMethod(jPlaybackParamsObj, jSetPitch, playbackRate.mPitch);
-
- jmethodID jSetSpeed = env->GetMethodID(
- jPlaybackParamsCls, "setSpeed", "(F)Landroid/media/PlaybackParams;");
- jPlaybackParamsObj = env->CallObjectMethod(jPlaybackParamsObj, jSetSpeed, playbackRate.mSpeed);
-
-
- // Set this Java PlaybackParams object into Java AudioTrack.
- jmethodID jSetPlaybackParams = env->GetMethodID(
- mAudioTrackCls, "setPlaybackParams", "(Landroid/media/PlaybackParams;)V");
- env->CallVoidMethod(mAudioTrackObj, jSetPlaybackParams, jPlaybackParamsObj);
- // TODO: Should we catch the Java IllegalArgumentException?
-
- return NO_ERROR;
-}
-
-const AudioPlaybackRate JAudioTrack::getPlaybackRate() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
-
- jmethodID jGetPlaybackParams = env->GetMethodID(
- mAudioTrackCls, "getPlaybackParams", "()Landroid/media/PlaybackParams;");
- jobject jPlaybackParamsObj = env->CallObjectMethod(mAudioTrackObj, jGetPlaybackParams);
-
- AudioPlaybackRate playbackRate;
- jclass jPlaybackParamsCls = env->FindClass("android/media/PlaybackParams");
-
- jmethodID jGetAudioFallbackMode = env->GetMethodID(
- jPlaybackParamsCls, "getAudioFallbackMode", "()I");
- // TODO: Should we enable passing AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT?
- // The enum is internal only, so it is not defined in PlaybackParmas.java.
- // TODO: Is this right way to convert an int to an enum?
- playbackRate.mFallbackMode = static_cast<AudioTimestretchFallbackMode>(
- env->CallIntMethod(jPlaybackParamsObj, jGetAudioFallbackMode));
-
- jmethodID jGetAudioStretchMode = env->GetMethodID(
- jPlaybackParamsCls, "getAudioStretchMode", "()I");
- playbackRate.mStretchMode = static_cast<AudioTimestretchStretchMode>(
- env->CallIntMethod(jPlaybackParamsObj, jGetAudioStretchMode));
-
- jmethodID jGetPitch = env->GetMethodID(jPlaybackParamsCls, "getPitch", "()F");
- playbackRate.mPitch = env->CallFloatMethod(jPlaybackParamsObj, jGetPitch);
-
- jmethodID jGetSpeed = env->GetMethodID(jPlaybackParamsCls, "getSpeed", "()F");
- playbackRate.mSpeed = env->CallFloatMethod(jPlaybackParamsObj, jGetSpeed);
-
- return playbackRate;
-}
-
-media::VolumeShaper::Status JAudioTrack::applyVolumeShaper(
- const sp<media::VolumeShaper::Configuration>& configuration,
- const sp<media::VolumeShaper::Operation>& operation) {
-
- jobject jConfigurationObj = createVolumeShaperConfigurationObj(configuration);
- jobject jOperationObj = createVolumeShaperOperationObj(operation);
-
- if (jConfigurationObj == NULL || jOperationObj == NULL) {
- return media::VolumeShaper::Status(BAD_VALUE);
- }
-
- JNIEnv *env = JavaVMHelper::getJNIEnv();
-
- jmethodID jCreateVolumeShaper = env->GetMethodID(mAudioTrackCls, "createVolumeShaper",
- "(Landroid/media/VolumeShaper$Configuration;)Landroid/media/VolumeShaper;");
- jobject jVolumeShaperObj = env->CallObjectMethod(
- mAudioTrackObj, jCreateVolumeShaper, jConfigurationObj);
-
- jclass jVolumeShaperCls = env->FindClass("android/media/VolumeShaper");
- jmethodID jApply = env->GetMethodID(jVolumeShaperCls, "apply",
- "(Landroid/media/VolumeShaper$Operation;)V");
- env->CallVoidMethod(jVolumeShaperObj, jApply, jOperationObj);
-
- return media::VolumeShaper::Status(NO_ERROR);
-}
-
-status_t JAudioTrack::setAuxEffectSendLevel(float level) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jSetAuxEffectSendLevel = env->GetMethodID(
- mAudioTrackCls, "setAuxEffectSendLevel", "(F)I");
- int result = env->CallIntMethod(mAudioTrackObj, jSetAuxEffectSendLevel, level);
- return javaToNativeStatus(result);
-}
-
-status_t JAudioTrack::attachAuxEffect(int effectId) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jAttachAuxEffect = env->GetMethodID(mAudioTrackCls, "attachAuxEffect", "(I)I");
- int result = env->CallIntMethod(mAudioTrackObj, jAttachAuxEffect, effectId);
- return javaToNativeStatus(result);
-}
-
-status_t JAudioTrack::setVolume(float left, float right) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- // TODO: Java setStereoVolume is deprecated. Do we really need this method?
- jmethodID jSetStereoVolume = env->GetMethodID(mAudioTrackCls, "setStereoVolume", "(FF)I");
- int result = env->CallIntMethod(mAudioTrackObj, jSetStereoVolume, left, right);
- return javaToNativeStatus(result);
-}
-
-status_t JAudioTrack::setVolume(float volume) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jSetVolume = env->GetMethodID(mAudioTrackCls, "setVolume", "(F)I");
- int result = env->CallIntMethod(mAudioTrackObj, jSetVolume, volume);
- return javaToNativeStatus(result);
-}
-
-status_t JAudioTrack::start() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jPlay = env->GetMethodID(mAudioTrackCls, "play", "()V");
- // TODO: Should we catch the Java IllegalStateException from play()?
- env->CallVoidMethod(mAudioTrackObj, jPlay);
- return NO_ERROR;
-}
-
-ssize_t JAudioTrack::write(const void* buffer, size_t size, bool blocking) {
- if (buffer == NULL) {
- return BAD_VALUE;
- }
-
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jbyteArray jAudioData = env->NewByteArray(size);
- env->SetByteArrayRegion(jAudioData, 0, size, (jbyte *) buffer);
-
- jclass jByteBufferCls = env->FindClass("java/nio/ByteBuffer");
- jmethodID jWrap = env->GetStaticMethodID(jByteBufferCls, "wrap", "([B)Ljava/nio/ByteBuffer;");
- jobject jByteBufferObj = env->CallStaticObjectMethod(jByteBufferCls, jWrap, jAudioData);
-
- int writeMode = 0;
- if (blocking) {
- jfieldID jWriteBlocking = env->GetStaticFieldID(mAudioTrackCls, "WRITE_BLOCKING", "I");
- writeMode = env->GetStaticIntField(mAudioTrackCls, jWriteBlocking);
- } else {
- jfieldID jWriteNonBlocking = env->GetStaticFieldID(
- mAudioTrackCls, "WRITE_NON_BLOCKING", "I");
- writeMode = env->GetStaticIntField(mAudioTrackCls, jWriteNonBlocking);
- }
-
- jmethodID jWrite = env->GetMethodID(mAudioTrackCls, "write", "(Ljava/nio/ByteBuffer;II)I");
- int result = env->CallIntMethod(mAudioTrackObj, jWrite, jByteBufferObj, size, writeMode);
-
- if (result >= 0) {
- return result;
- } else {
- return javaToNativeStatus(result);
- }
-}
-
-void JAudioTrack::stop() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jStop = env->GetMethodID(mAudioTrackCls, "stop", "()V");
- env->CallVoidMethod(mAudioTrackObj, jStop);
- // TODO: Should we catch IllegalStateException?
-}
-
-// TODO: Is the right implementation?
-bool JAudioTrack::stopped() const {
- return !isPlaying();
-}
-
-void JAudioTrack::flush() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jFlush = env->GetMethodID(mAudioTrackCls, "flush", "()V");
- env->CallVoidMethod(mAudioTrackObj, jFlush);
-}
-
-void JAudioTrack::pause() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jPause = env->GetMethodID(mAudioTrackCls, "pause", "()V");
- env->CallVoidMethod(mAudioTrackObj, jPause);
- // TODO: Should we catch IllegalStateException?
-}
-
-bool JAudioTrack::isPlaying() const {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetPlayState = env->GetMethodID(mAudioTrackCls, "getPlayState", "()I");
- int currentPlayState = env->CallIntMethod(mAudioTrackObj, jGetPlayState);
-
- // TODO: In Java AudioTrack, there is no STOPPING state.
- // This means while stopping, isPlaying() will return different value in two class.
- // - in existing native AudioTrack: true
- // - in JAudioTrack: false
- // If not okay, also modify the implementation of stopped().
- jfieldID jPlayStatePlaying = env->GetStaticFieldID(mAudioTrackCls, "PLAYSTATE_PLAYING", "I");
- int statePlaying = env->GetStaticIntField(mAudioTrackCls, jPlayStatePlaying);
- return currentPlayState == statePlaying;
-}
-
-uint32_t JAudioTrack::getSampleRate() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetSampleRate = env->GetMethodID(mAudioTrackCls, "getSampleRate", "()I");
- return env->CallIntMethod(mAudioTrackObj, jGetSampleRate);
-}
-
-status_t JAudioTrack::getBufferDurationInUs(int64_t *duration) {
- if (duration == nullptr) {
- return BAD_VALUE;
- }
-
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetBufferSizeInFrames = env->GetMethodID(
- mAudioTrackCls, "getBufferSizeInFrames", "()I");
- int bufferSizeInFrames = env->CallIntMethod(mAudioTrackObj, jGetBufferSizeInFrames);
-
- const double secondToMicro = 1000000LL; // 1E6
- int sampleRate = JAudioTrack::getSampleRate();
- float speed = JAudioTrack::getPlaybackRate().mSpeed;
-
- *duration = (int64_t) (bufferSizeInFrames * secondToMicro / (sampleRate * speed));
- return NO_ERROR;
-}
-
-audio_format_t JAudioTrack::format() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetAudioFormat = env->GetMethodID(mAudioTrackCls, "getAudioFormat", "()I");
- int javaFormat = env->CallIntMethod(mAudioTrackObj, jGetAudioFormat);
- return audioFormatToNative(javaFormat);
-}
-
-size_t JAudioTrack::frameSize() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetFormat = env->GetMethodID(mAudioTrackCls,
- "getFormat", "()Landroid/media/AudioFormat;");
- jobject jAudioFormatObj = env->CallObjectMethod(mAudioTrackObj, jGetFormat);
-
- jclass jAudioFormatCls = env->FindClass("android/media/AudioFormat");
- jmethodID jGetFrameSizeInBytes = env->GetMethodID(
- jAudioFormatCls, "getFrameSizeInBytes", "()I");
- jint javaFrameSizeInBytes = env->CallIntMethod(jAudioFormatObj, jGetFrameSizeInBytes);
-
- return (size_t)javaFrameSizeInBytes;
-}
-
-status_t JAudioTrack::dump(int fd, const Vector<String16>& args __unused) const
-{
- String8 result;
-
- result.append(" JAudioTrack::dump\n");
-
- // TODO: Remove logs that includes unavailable information from below.
-// result.appendFormat(" status(%d), state(%d), session Id(%d), flags(%#x)\n",
-// mStatus, mState, mSessionId, mFlags);
-// result.appendFormat(" format(%#x), channel mask(%#x), channel count(%u)\n",
-// format(), mChannelMask, channelCount());
-// result.appendFormat(" sample rate(%u), original sample rate(%u), speed(%f)\n",
-// getSampleRate(), mOriginalSampleRate, mPlaybackRate.mSpeed);
-// result.appendFormat(" frame count(%zu), req. frame count(%zu)\n",
-// frameCount(), mReqFrameCount);
-// result.appendFormat(" notif. frame count(%u), req. notif. frame count(%u),"
-// " req. notif. per buff(%u)\n",
-// mNotificationFramesAct, mNotificationFramesReq, mNotificationsPerBufferReq);
-// result.appendFormat(" latency (%d), selected device Id(%d), routed device Id(%d)\n",
-// latency(), mSelectedDeviceId, getRoutedDeviceId());
-// result.appendFormat(" output(%d) AF latency (%u) AF frame count(%zu) AF SampleRate(%u)\n",
-// mOutput, mAfLatency, mAfFrameCount, mAfSampleRate);
- ::write(fd, result.string(), result.size());
- return NO_ERROR;
-}
-
-jobject JAudioTrack::getRoutedDevice() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetRoutedDevice = env->GetMethodID(mAudioTrackCls, "getRoutedDevice",
- "()Landroid/media/AudioDeviceInfo;");
- return env->CallObjectMethod(mAudioTrackObj, jGetRoutedDevice);
-}
-
-int32_t JAudioTrack::getAudioSessionId() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetAudioSessionId = env->GetMethodID(mAudioTrackCls, "getAudioSessionId", "()I");
- jint sessionId = env->CallIntMethod(mAudioTrackObj, jGetAudioSessionId);
- return sessionId;
-}
-
-status_t JAudioTrack::setPreferredDevice(jobject device) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jSetPreferredDeviceId = env->GetMethodID(mAudioTrackCls, "setPreferredDevice",
- "(Landroid/media/AudioDeviceInfo;)Z");
- jboolean result = env->CallBooleanMethod(mAudioTrackObj, jSetPreferredDeviceId, device);
- return result == true ? NO_ERROR : BAD_VALUE;
-}
-
-audio_stream_type_t JAudioTrack::getAudioStreamType() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetAudioAttributes = env->GetMethodID(mAudioTrackCls, "getAudioAttributes",
- "()Landroid/media/AudioAttributes;");
- jobject jAudioAttributes = env->CallObjectMethod(mAudioTrackObj, jGetAudioAttributes);
- jclass jAudioAttributesCls = env->FindClass("android/media/AudioAttributes");
- jmethodID jGetVolumeControlStream = env->GetMethodID(jAudioAttributesCls,
- "getVolumeControlStream", "()I");
- int javaAudioStreamType = env->CallIntMethod(jAudioAttributes, jGetVolumeControlStream);
- return (audio_stream_type_t)javaAudioStreamType;
-}
-
-status_t JAudioTrack::pendingDuration(int32_t *msec) {
- if (msec == nullptr) {
- return BAD_VALUE;
- }
-
- bool isPurePcmData = audio_is_linear_pcm(format()) && (getFlags() & AUDIO_FLAG_HW_AV_SYNC) == 0;
- if (!isPurePcmData) {
- return INVALID_OPERATION;
- }
-
- // TODO: Need to know the difference btw. client and server time.
- // If getTimestamp(ExtendedTimestamp) is ready, and un-comment below and modify appropriately.
- // (copied from AudioTrack.cpp)
-
-// ExtendedTimestamp ets;
-// ExtendedTimestamp::LOCATION location = ExtendedTimestamp::LOCATION_SERVER;
-// if (getTimestamp_l(&ets) == OK && ets.mTimeNs[location] > 0) {
-// int64_t diff = ets.mPosition[ExtendedTimestamp::LOCATION_CLIENT]
-// - ets.mPosition[location];
-// if (diff < 0) {
-// *msec = 0;
-// } else {
-// // ms is the playback time by frames
-// int64_t ms = (int64_t)((double)diff * 1000 /
-// ((double)mSampleRate * mPlaybackRate.mSpeed));
-// // clockdiff is the timestamp age (negative)
-// int64_t clockdiff = (mState != STATE_ACTIVE) ? 0 :
-// ets.mTimeNs[location]
-// + ets.mTimebaseOffset[ExtendedTimestamp::TIMEBASE_MONOTONIC]
-// - systemTime(SYSTEM_TIME_MONOTONIC);
-//
-// //ALOGV("ms: %lld clockdiff: %lld", (long long)ms, (long long)clockdiff);
-// static const int NANOS_PER_MILLIS = 1000000;
-// *msec = (int32_t)(ms + clockdiff / NANOS_PER_MILLIS);
-// }
-// return NO_ERROR;
-// }
-
- return NO_ERROR;
-}
-
-status_t JAudioTrack::addAudioDeviceCallback(jobject listener, jobject handler) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jAddOnRoutingChangedListener = env->GetMethodID(mAudioTrackCls,
- "addOnRoutingChangedListener",
- "(Landroid/media/AudioRouting$OnRoutingChangedListener;Landroid/os/Handler;)V");
- env->CallVoidMethod(mAudioTrackObj, jAddOnRoutingChangedListener, listener, handler);
- return NO_ERROR;
-}
-
-status_t JAudioTrack::removeAudioDeviceCallback(jobject listener) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jRemoveOnRoutingChangedListener = env->GetMethodID(mAudioTrackCls,
- "removeOnRoutingChangedListener",
- "(Landroid/media/AudioRouting$OnRoutingChangedListener;)V");
- env->CallVoidMethod(mAudioTrackObj, jRemoveOnRoutingChangedListener, listener);
- return NO_ERROR;
-}
-
-void JAudioTrack::registerRoutingDelegates(
- Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>>& routingDelegates) {
- for (auto it = routingDelegates.begin(); it != routingDelegates.end(); it++) {
- addAudioDeviceCallback(it->second->getJObject(), getHandler(it->second->getJObject()));
- }
-}
-
-/////////////////////////////////////////////////////////////
-/// Static methods begin ///
-/////////////////////////////////////////////////////////////
-jobject JAudioTrack::getListener(const jobject routingDelegateObj) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jclass jRoutingDelegateCls = env->FindClass("android/media/RoutingDelegate");
- jmethodID jGetListener = env->GetMethodID(jRoutingDelegateCls,
- "getListener", "()Landroid/media/AudioRouting$OnRoutingChangedListener;");
- return env->CallObjectMethod(routingDelegateObj, jGetListener);
-}
-
-jobject JAudioTrack::getHandler(const jobject routingDelegateObj) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jclass jRoutingDelegateCls = env->FindClass("android/media/RoutingDelegate");
- jmethodID jGetHandler = env->GetMethodID(jRoutingDelegateCls,
- "getHandler", "()Landroid/os/Handler;");
- return env->CallObjectMethod(routingDelegateObj, jGetHandler);
-}
-
-jobject JAudioTrack::findByKey(
- Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>>& mp, const jobject key) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- for (auto it = mp.begin(); it != mp.end(); it++) {
- if (env->IsSameObject(it->first->getJObject(), key)) {
- return it->second->getJObject();
- }
- }
- return nullptr;
-}
-
-void JAudioTrack::eraseByKey(
- Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>>& mp, const jobject key) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- for (auto it = mp.begin(); it != mp.end(); it++) {
- if (env->IsSameObject(it->first->getJObject(), key)) {
- mp.erase(it);
- return;
- }
- }
-}
-
-/////////////////////////////////////////////////////////////
-/// Private method begins ///
-/////////////////////////////////////////////////////////////
-
-jobject JAudioTrack::createVolumeShaperConfigurationObj(
- const sp<media::VolumeShaper::Configuration>& config) {
-
- // TODO: Java VolumeShaper's setId() / setOptionFlags() are hidden.
- if (config == NULL || config->getType() == media::VolumeShaper::Configuration::TYPE_ID) {
- return NULL;
- }
-
- JNIEnv *env = JavaVMHelper::getJNIEnv();
-
- // Referenced "android_media_VolumeShaper.h".
- jfloatArray xarray = nullptr;
- jfloatArray yarray = nullptr;
- if (config->getType() == media::VolumeShaper::Configuration::TYPE_SCALE) {
- // convert curve arrays
- xarray = env->NewFloatArray(config->size());
- yarray = env->NewFloatArray(config->size());
- float * const x = env->GetFloatArrayElements(xarray, nullptr /* isCopy */);
- float * const y = env->GetFloatArrayElements(yarray, nullptr /* isCopy */);
- float *xptr = x, *yptr = y;
- for (const auto &pt : *config.get()) {
- *xptr++ = pt.first;
- *yptr++ = pt.second;
- }
- env->ReleaseFloatArrayElements(xarray, x, 0 /* mode */);
- env->ReleaseFloatArrayElements(yarray, y, 0 /* mode */);
- }
-
- jclass jBuilderCls = env->FindClass("android/media/VolumeShaper$Configuration$Builder");
- jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
- jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
-
- jmethodID jSetDuration = env->GetMethodID(jBuilderCls, "setDuration",
- "(L)Landroid/media/VolumeShaper$Configuration$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetDuration, (jlong) config->getDurationMs());
-
- jmethodID jSetInterpolatorType = env->GetMethodID(jBuilderCls, "setInterpolatorType",
- "(I)Landroid/media/VolumeShaper$Configuration$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetInterpolatorType,
- config->getInterpolatorType());
-
- jmethodID jSetCurve = env->GetMethodID(jBuilderCls, "setCurve",
- "([F[F)Landroid/media/VolumeShaper$Configuration$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetCurve, xarray, yarray);
-
- jmethodID jBuild = env->GetMethodID(jBuilderCls, "build",
- "()Landroid/media/VolumeShaper$Configuration;");
- return env->CallObjectMethod(jBuilderObj, jBuild);
-}
-
-jobject JAudioTrack::createVolumeShaperOperationObj(
- const sp<media::VolumeShaper::Operation>& operation) {
-
- JNIEnv *env = JavaVMHelper::getJNIEnv();
-
- jclass jBuilderCls = env->FindClass("android/media/VolumeShaper$Operation$Builder");
- jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
- jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
-
- // Set XOffset
- jmethodID jSetXOffset = env->GetMethodID(jBuilderCls, "setXOffset",
- "(F)Landroid/media/VolumeShaper$Operation$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetXOffset, operation->getXOffset());
-
- int32_t flags = operation->getFlags();
-
- if (operation->getReplaceId() >= 0) {
- jmethodID jReplace = env->GetMethodID(jBuilderCls, "replace",
- "(IB)Landroid/media/VolumeShaper$Operation$Builder;");
- bool join = (flags | media::VolumeShaper::Operation::FLAG_JOIN) != 0;
- jBuilderObj = env->CallObjectMethod(jBuilderCls, jReplace, operation->getReplaceId(), join);
- }
-
- if (flags | media::VolumeShaper::Operation::FLAG_REVERSE) {
- jmethodID jReverse = env->GetMethodID(jBuilderCls, "reverse",
- "()Landroid/media/VolumeShaper$Operation$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderCls, jReverse);
- }
-
- // TODO: VolumeShaper Javadoc says "Do not call terminate() directly". Can we call this?
- if (flags | media::VolumeShaper::Operation::FLAG_TERMINATE) {
- jmethodID jTerminate = env->GetMethodID(jBuilderCls, "terminate",
- "()Landroid/media/VolumeShaper$Operation$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderCls, jTerminate);
- }
-
- if (flags | media::VolumeShaper::Operation::FLAG_DELAY) {
- jmethodID jDefer = env->GetMethodID(jBuilderCls, "defer",
- "()Landroid/media/VolumeShaper$Operation$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderCls, jDefer);
- }
-
- if (flags | media::VolumeShaper::Operation::FLAG_CREATE_IF_NECESSARY) {
- jmethodID jCreateIfNeeded = env->GetMethodID(jBuilderCls, "createIfNeeded",
- "()Landroid/media/VolumeShaper$Operation$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderCls, jCreateIfNeeded);
- }
-
- // TODO: Handle error case (can it be NULL?)
- jmethodID jBuild = env->GetMethodID(jBuilderCls, "build",
- "()Landroid/media/VolumeShaper$Operation;");
- return env->CallObjectMethod(jBuilderObj, jBuild);
-}
-
-jobject JAudioTrack::createStreamEventCallback(callback_t cbf, void* user) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jclass jCallbackCls = env->FindClass("android/media/MediaPlayer2$StreamEventCallback");
- jmethodID jCallbackCtor = env->GetMethodID(jCallbackCls, "<init>", "(JJJ)V");
- jobject jCallbackObj = env->NewObject(jCallbackCls, jCallbackCtor, this, cbf, user);
- return jCallbackObj;
-}
-
-jobject JAudioTrack::createCallbackExecutor() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jclass jExecutorsCls = env->FindClass("java/util/concurrent/Executors");
- jmethodID jNewSingleThreadExecutor = env->GetStaticMethodID(jExecutorsCls,
- "newSingleThreadExecutor", "()Ljava/util/concurrent/ExecutorService;");
- jobject jSingleThreadExecutorObj =
- env->CallStaticObjectMethod(jExecutorsCls, jNewSingleThreadExecutor);
- return jSingleThreadExecutorObj;
-}
-
-status_t JAudioTrack::javaToNativeStatus(int javaStatus) {
- switch (javaStatus) {
- case AUDIO_JAVA_SUCCESS:
- return NO_ERROR;
- case AUDIO_JAVA_BAD_VALUE:
- return BAD_VALUE;
- case AUDIO_JAVA_INVALID_OPERATION:
- return INVALID_OPERATION;
- case AUDIO_JAVA_PERMISSION_DENIED:
- return PERMISSION_DENIED;
- case AUDIO_JAVA_NO_INIT:
- return NO_INIT;
- case AUDIO_JAVA_WOULD_BLOCK:
- return WOULD_BLOCK;
- case AUDIO_JAVA_DEAD_OBJECT:
- return DEAD_OBJECT;
- default:
- return UNKNOWN_ERROR;
- }
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/JMedia2HTTPConnection.cpp b/media/libmediaplayer2/JMedia2HTTPConnection.cpp
deleted file mode 100644
index e1baa104..0000000
--- a/media/libmediaplayer2/JMedia2HTTPConnection.cpp
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "JMedia2HTTPConnection"
-#include <utils/Log.h>
-
-#include <mediaplayer2/JavaVMHelper.h>
-#include <mediaplayer2/JMedia2HTTPConnection.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <nativehelper/scoped_local_ref.h>
-
-#include "log/log.h"
-#include "jni.h"
-
-namespace android {
-
-static const size_t kBufferSize = 32768;
-
-JMedia2HTTPConnection::JMedia2HTTPConnection(JNIEnv *env, jobject thiz) {
- mMedia2HTTPConnectionObj = env->NewGlobalRef(thiz);
- CHECK(mMedia2HTTPConnectionObj != NULL);
-
- ScopedLocalRef<jclass> media2HTTPConnectionClass(
- env, env->GetObjectClass(mMedia2HTTPConnectionObj));
- CHECK(media2HTTPConnectionClass.get() != NULL);
-
- mConnectMethod = env->GetMethodID(
- media2HTTPConnectionClass.get(),
- "connect",
- "(Ljava/lang/String;Ljava/lang/String;)Z");
- CHECK(mConnectMethod != NULL);
-
- mDisconnectMethod = env->GetMethodID(
- media2HTTPConnectionClass.get(),
- "disconnect",
- "()V");
- CHECK(mDisconnectMethod != NULL);
-
- mReadAtMethod = env->GetMethodID(
- media2HTTPConnectionClass.get(),
- "readAt",
- "(J[BI)I");
- CHECK(mReadAtMethod != NULL);
-
- mGetSizeMethod = env->GetMethodID(
- media2HTTPConnectionClass.get(),
- "getSize",
- "()J");
- CHECK(mGetSizeMethod != NULL);
-
- mGetMIMETypeMethod = env->GetMethodID(
- media2HTTPConnectionClass.get(),
- "getMIMEType",
- "()Ljava/lang/String;");
- CHECK(mGetMIMETypeMethod != NULL);
-
- mGetUriMethod = env->GetMethodID(
- media2HTTPConnectionClass.get(),
- "getUri",
- "()Ljava/lang/String;");
- CHECK(mGetUriMethod != NULL);
-
- ScopedLocalRef<jbyteArray> tmp(
- env, env->NewByteArray(kBufferSize));
- mByteArrayObj = (jbyteArray)env->NewGlobalRef(tmp.get());
- CHECK(mByteArrayObj != NULL);
-}
-
-JMedia2HTTPConnection::~JMedia2HTTPConnection() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- env->DeleteGlobalRef(mMedia2HTTPConnectionObj);
- env->DeleteGlobalRef(mByteArrayObj);
-}
-
-bool JMedia2HTTPConnection::connect(
- const char *uri, const KeyedVector<String8, String8> *headers) {
- String8 tmp("");
- if (headers != NULL) {
- for (size_t i = 0; i < headers->size(); ++i) {
- tmp.append(headers->keyAt(i));
- tmp.append(String8(": "));
- tmp.append(headers->valueAt(i));
- tmp.append(String8("\r\n"));
- }
- }
-
- JNIEnv* env = JavaVMHelper::getJNIEnv();
- jstring juri = env->NewStringUTF(uri);
- jstring jheaders = env->NewStringUTF(tmp.string());
-
- jboolean ret =
- env->CallBooleanMethod(mMedia2HTTPConnectionObj, mConnectMethod, juri, jheaders);
-
- env->DeleteLocalRef(juri);
- env->DeleteLocalRef(jheaders);
-
- return (bool)ret;
-}
-
-void JMedia2HTTPConnection::disconnect() {
- JNIEnv* env = JavaVMHelper::getJNIEnv();
- env->CallVoidMethod(mMedia2HTTPConnectionObj, mDisconnectMethod);
-}
-
-ssize_t JMedia2HTTPConnection::readAt(off64_t offset, void *data, size_t size) {
- JNIEnv* env = JavaVMHelper::getJNIEnv();
-
- if (size > kBufferSize) {
- size = kBufferSize;
- }
-
- jint n = env->CallIntMethod(
- mMedia2HTTPConnectionObj, mReadAtMethod, (jlong)offset, mByteArrayObj, (jint)size);
-
- if (n > 0) {
- env->GetByteArrayRegion(
- mByteArrayObj,
- 0,
- n,
- (jbyte *)data);
- }
-
- return n;
-}
-
-off64_t JMedia2HTTPConnection::getSize() {
- JNIEnv* env = JavaVMHelper::getJNIEnv();
- return (off64_t)(env->CallLongMethod(mMedia2HTTPConnectionObj, mGetSizeMethod));
-}
-
-status_t JMedia2HTTPConnection::getMIMEType(String8 *mimeType) {
- JNIEnv* env = JavaVMHelper::getJNIEnv();
- jstring jmime = (jstring)env->CallObjectMethod(mMedia2HTTPConnectionObj, mGetMIMETypeMethod);
- jboolean flag = env->ExceptionCheck();
- if (flag) {
- env->ExceptionClear();
- return UNKNOWN_ERROR;
- }
-
- const char *str = env->GetStringUTFChars(jmime, 0);
- if (str != NULL) {
- *mimeType = String8(str);
- } else {
- *mimeType = "application/octet-stream";
- }
- env->ReleaseStringUTFChars(jmime, str);
- return OK;
-}
-
-status_t JMedia2HTTPConnection::getUri(String8 *uri) {
- JNIEnv* env = JavaVMHelper::getJNIEnv();
- jstring juri = (jstring)env->CallObjectMethod(mMedia2HTTPConnectionObj, mGetUriMethod);
- jboolean flag = env->ExceptionCheck();
- if (flag) {
- env->ExceptionClear();
- return UNKNOWN_ERROR;
- }
-
- const char *str = env->GetStringUTFChars(juri, 0);
- *uri = String8(str);
- env->ReleaseStringUTFChars(juri, str);
- return OK;
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/JMedia2HTTPService.cpp b/media/libmediaplayer2/JMedia2HTTPService.cpp
deleted file mode 100644
index 20e3573..0000000
--- a/media/libmediaplayer2/JMedia2HTTPService.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "JMedia2HTTPService"
-#include <utils/Log.h>
-
-#include <jni.h>
-
-#include <mediaplayer2/JavaVMHelper.h>
-#include <mediaplayer2/JMedia2HTTPService.h>
-#include <mediaplayer2/JMedia2HTTPConnection.h>
-#include <media/stagefright/foundation/ADebug.h>
-
-#include <nativehelper/scoped_local_ref.h>
-
-namespace android {
-
-JMedia2HTTPService::JMedia2HTTPService(JNIEnv *env, jobject thiz) {
- mMedia2HTTPServiceObj = env->NewGlobalRef(thiz);
- CHECK(mMedia2HTTPServiceObj != NULL);
-
- ScopedLocalRef<jclass> media2HTTPServiceClass(env, env->GetObjectClass(mMedia2HTTPServiceObj));
- CHECK(media2HTTPServiceClass.get() != NULL);
-
- mMakeHTTPConnectionMethod = env->GetMethodID(
- media2HTTPServiceClass.get(),
- "makeHTTPConnection",
- "()Landroid/media/Media2HTTPConnection;");
- CHECK(mMakeHTTPConnectionMethod != NULL);
-}
-
-JMedia2HTTPService::~JMedia2HTTPService() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- env->DeleteGlobalRef(mMedia2HTTPServiceObj);
-}
-
-sp<MediaHTTPConnection> JMedia2HTTPService::makeHTTPConnection() {
- JNIEnv* env = JavaVMHelper::getJNIEnv();
- jobject media2HTTPConnectionObj =
- env->CallObjectMethod(mMedia2HTTPServiceObj, mMakeHTTPConnectionMethod);
-
- return new JMedia2HTTPConnection(env, media2HTTPConnectionObj);
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/JavaVMHelper.cpp b/media/libmediaplayer2/JavaVMHelper.cpp
deleted file mode 100644
index 8d03ed0..0000000
--- a/media/libmediaplayer2/JavaVMHelper.cpp
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "JavaVMHelper"
-
-#include "mediaplayer2/JavaVMHelper.h"
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <utils/threads.h>
-
-#include <stdlib.h>
-
-namespace android {
-
-// static
-std::atomic<JavaVM *> JavaVMHelper::sJavaVM(NULL);
-
-/*
- * Makes the current thread visible to the VM.
- *
- * The JNIEnv pointer returned is only valid for the current thread, and
- * thus must be tucked into thread-local storage.
- */
-static int javaAttachThread(const char* threadName, JNIEnv** pEnv) {
- JavaVMAttachArgs args;
- JavaVM* vm;
- jint result;
-
- vm = JavaVMHelper::getJavaVM();
- if (vm == NULL) {
- return JNI_ERR;
- }
-
- args.version = JNI_VERSION_1_4;
- args.name = (char*) threadName;
- args.group = NULL;
-
- result = vm->AttachCurrentThread(pEnv, (void*) &args);
- if (result != JNI_OK) {
- ALOGI("NOTE: attach of thread '%s' failed\n", threadName);
- }
-
- return result;
-}
-
-/*
- * Detach the current thread from the set visible to the VM.
- */
-static int javaDetachThread(void) {
- JavaVM* vm;
- jint result;
-
- vm = JavaVMHelper::getJavaVM();
- if (vm == NULL) {
- return JNI_ERR;
- }
-
- result = vm->DetachCurrentThread();
- if (result != JNI_OK) {
- ALOGE("ERROR: thread detach failed\n");
- }
- return result;
-}
-
-/*
- * When starting a native thread that will be visible from the VM, we
- * bounce through this to get the right attach/detach action.
- * Note that this function calls free(args)
- */
-static int javaThreadShell(void* args) {
- void* start = ((void**)args)[0];
- void* userData = ((void **)args)[1];
- char* name = (char*) ((void **)args)[2]; // we own this storage
- free(args);
- JNIEnv* env;
- int result;
-
- /* hook us into the VM */
- if (javaAttachThread(name, &env) != JNI_OK) {
- return -1;
- }
-
- /* start the thread running */
- result = (*(android_thread_func_t)start)(userData);
-
- /* unhook us */
- javaDetachThread();
- free(name);
-
- return result;
-}
-
-/*
- * This is invoked from androidCreateThreadEtc() via the callback
- * set with androidSetCreateThreadFunc().
- *
- * We need to create the new thread in such a way that it gets hooked
- * into the VM before it really starts executing.
- */
-static int javaCreateThreadEtc(
- android_thread_func_t entryFunction,
- void* userData,
- const char* threadName,
- int32_t threadPriority,
- size_t threadStackSize,
- android_thread_id_t* threadId) {
- void** args = (void**) malloc(3 * sizeof(void*)); // javaThreadShell must free
- int result;
-
- LOG_ALWAYS_FATAL_IF(threadName == nullptr, "threadName not provided to javaCreateThreadEtc");
-
- args[0] = (void*) entryFunction;
- args[1] = userData;
- args[2] = (void*) strdup(threadName); // javaThreadShell must free
-
- result = androidCreateRawThreadEtc(javaThreadShell, args,
- threadName, threadPriority, threadStackSize, threadId);
- return result;
-}
-
-// static
-JNIEnv *JavaVMHelper::getJNIEnv() {
- JNIEnv *env;
- JavaVM *vm = sJavaVM.load();
- CHECK(vm != NULL);
-
- if (vm->GetEnv((void **)&env, JNI_VERSION_1_4) != JNI_OK) {
- return NULL;
- }
-
- return env;
-}
-
-//static
-JavaVM *JavaVMHelper::getJavaVM() {
- return sJavaVM.load();
-}
-
-// static
-void JavaVMHelper::setJavaVM(JavaVM *vm) {
- sJavaVM.store(vm);
-
- // Ensure that Thread(/*canCallJava*/ true) in libutils is attached to the VM.
- // This is supposed to be done by runtime, but when libutils is used with linker
- // namespace, CreateThreadFunc should be initialized separately within the namespace.
- androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp b/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
deleted file mode 100644
index b4fa0c1..0000000
--- a/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
+++ /dev/null
@@ -1,656 +0,0 @@
-/*
-**
-** Copyright 2018, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MediaPlayer2AudioOutput"
-#include <mediaplayer2/MediaPlayer2AudioOutput.h>
-
-#include <cutils/properties.h> // for property_get
-#include <utils/Log.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-
-namespace {
-
-const float kMaxRequiredSpeed = 8.0f; // for PCM tracks allow up to 8x speedup.
-
-} // anonymous namespace
-
-namespace android {
-
-// TODO: Find real cause of Audio/Video delay in PV framework and remove this workaround
-/* static */ int MediaPlayer2AudioOutput::mMinBufferCount = 4;
-/* static */ bool MediaPlayer2AudioOutput::mIsOnEmulator = false;
-
-status_t MediaPlayer2AudioOutput::dump(int fd, const Vector<String16>& args) const {
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- result.append(" MediaPlayer2AudioOutput\n");
- snprintf(buffer, 255, " volume(%f)\n", mVolume);
- result.append(buffer);
- snprintf(buffer, 255, " msec per frame(%f), latency (%d)\n",
- mMsecsPerFrame, (mJAudioTrack != nullptr) ? mJAudioTrack->latency() : -1);
- result.append(buffer);
- snprintf(buffer, 255, " aux effect id(%d), send level (%f)\n",
- mAuxEffectId, mSendLevel);
- result.append(buffer);
-
- ::write(fd, result.string(), result.size());
- if (mJAudioTrack != nullptr) {
- mJAudioTrack->dump(fd, args);
- }
- return NO_ERROR;
-}
-
-MediaPlayer2AudioOutput::MediaPlayer2AudioOutput(int32_t sessionId, uid_t uid, int pid,
- const jobject attributes)
- : mCallback(nullptr),
- mCallbackCookie(nullptr),
- mCallbackData(nullptr),
- mVolume(1.0),
- mPlaybackRate(AUDIO_PLAYBACK_RATE_DEFAULT),
- mSampleRateHz(0),
- mMsecsPerFrame(0),
- mFrameSize(0),
- mSessionId(sessionId),
- mUid(uid),
- mPid(pid),
- mSendLevel(0.0),
- mAuxEffectId(0),
- mFlags(AUDIO_OUTPUT_FLAG_NONE) {
- ALOGV("MediaPlayer2AudioOutput(%d)", sessionId);
-
- if (attributes != nullptr) {
- mAttributes = new JObjectHolder(attributes);
- }
-
- setMinBufferCount();
- mRoutingDelegates.clear();
-}
-
-MediaPlayer2AudioOutput::~MediaPlayer2AudioOutput() {
- close();
- delete mCallbackData;
-}
-
-//static
-void MediaPlayer2AudioOutput::setMinBufferCount() {
- char value[PROPERTY_VALUE_MAX];
- if (property_get("ro.kernel.qemu", value, 0)) {
- mIsOnEmulator = true;
- mMinBufferCount = 12; // to prevent systematic buffer underrun for emulator
- }
-}
-
-// static
-bool MediaPlayer2AudioOutput::isOnEmulator() {
- setMinBufferCount(); // benign race wrt other threads
- return mIsOnEmulator;
-}
-
-// static
-int MediaPlayer2AudioOutput::getMinBufferCount() {
- setMinBufferCount(); // benign race wrt other threads
- return mMinBufferCount;
-}
-
-ssize_t MediaPlayer2AudioOutput::bufferSize() const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == nullptr) {
- return NO_INIT;
- }
- return mJAudioTrack->frameCount() * mFrameSize;
-}
-
-ssize_t MediaPlayer2AudioOutput::frameCount() const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == nullptr) {
- return NO_INIT;
- }
- return mJAudioTrack->frameCount();
-}
-
-ssize_t MediaPlayer2AudioOutput::channelCount() const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == nullptr) {
- return NO_INIT;
- }
- return mJAudioTrack->channelCount();
-}
-
-ssize_t MediaPlayer2AudioOutput::frameSize() const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == nullptr) {
- return NO_INIT;
- }
- return mFrameSize;
-}
-
-uint32_t MediaPlayer2AudioOutput::latency () const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == nullptr) {
- return 0;
- }
- return mJAudioTrack->latency();
-}
-
-float MediaPlayer2AudioOutput::msecsPerFrame() const {
- Mutex::Autolock lock(mLock);
- return mMsecsPerFrame;
-}
-
-status_t MediaPlayer2AudioOutput::getPosition(uint32_t *position) const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == nullptr) {
- return NO_INIT;
- }
- return mJAudioTrack->getPosition(position);
-}
-
-status_t MediaPlayer2AudioOutput::getTimestamp(AudioTimestamp &ts) const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == nullptr) {
- return NO_INIT;
- }
- return mJAudioTrack->getTimestamp(ts);
-}
-
-// TODO: Remove unnecessary calls to getPlayedOutDurationUs()
-// as it acquires locks and may query the audio driver.
-//
-// Some calls could conceivably retrieve extrapolated data instead of
-// accessing getTimestamp() or getPosition() every time a data buffer with
-// a media time is received.
-//
-// Calculate duration of played samples if played at normal rate (i.e., 1.0).
-int64_t MediaPlayer2AudioOutput::getPlayedOutDurationUs(int64_t nowUs) const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == nullptr || mSampleRateHz == 0) {
- return 0;
- }
-
- uint32_t numFramesPlayed;
- int64_t numFramesPlayedAtUs;
- AudioTimestamp ts;
-
- status_t res = mJAudioTrack->getTimestamp(ts);
-
- if (res == OK) { // case 1: mixing audio tracks and offloaded tracks.
- numFramesPlayed = ts.mPosition;
- numFramesPlayedAtUs = ts.mTime.tv_sec * 1000000LL + ts.mTime.tv_nsec / 1000;
- //ALOGD("getTimestamp: OK %d %lld", numFramesPlayed, (long long)numFramesPlayedAtUs);
- } else { // case 2: transitory state on start of a new track
- // case 3: transitory at new track or audio fast tracks.
- numFramesPlayed = 0;
- numFramesPlayedAtUs = nowUs;
- //ALOGD("getTimestamp: WOULD_BLOCK %d %lld",
- // numFramesPlayed, (long long)numFramesPlayedAtUs);
- }
-
- // CHECK_EQ(numFramesPlayed & (1 << 31), 0); // can't be negative until 12.4 hrs, test
- // TODO: remove the (int32_t) casting below as it may overflow at 12.4 hours.
- int64_t durationUs = (int64_t)((int32_t)numFramesPlayed * 1000000LL / mSampleRateHz)
- + nowUs - numFramesPlayedAtUs;
- if (durationUs < 0) {
- // Occurs when numFramesPlayed position is very small and the following:
- // (1) In case 1, the time nowUs is computed before getTimestamp() is called and
- // numFramesPlayedAtUs is greater than nowUs by time more than numFramesPlayed.
- // (2) In case 3, using getPosition and adding mAudioSink->latency() to
- // numFramesPlayedAtUs, by a time amount greater than numFramesPlayed.
- //
- // Both of these are transitory conditions.
- ALOGV("getPlayedOutDurationUs: negative duration %lld set to zero", (long long)durationUs);
- durationUs = 0;
- }
- ALOGV("getPlayedOutDurationUs(%lld) nowUs(%lld) frames(%u) framesAt(%lld)",
- (long long)durationUs, (long long)nowUs,
- numFramesPlayed, (long long)numFramesPlayedAtUs);
- return durationUs;
-}
-
-status_t MediaPlayer2AudioOutput::getFramesWritten(uint32_t *frameswritten) const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == nullptr) {
- return NO_INIT;
- }
- ExtendedTimestamp ets;
- status_t status = mJAudioTrack->getTimestamp(&ets);
- if (status == OK || status == WOULD_BLOCK) {
- *frameswritten = (uint32_t)ets.mPosition[ExtendedTimestamp::LOCATION_CLIENT];
- }
- return status;
-}
-
-void MediaPlayer2AudioOutput::setAudioAttributes(const jobject attributes) {
- Mutex::Autolock lock(mLock);
- mAttributes = (attributes == nullptr) ? nullptr : new JObjectHolder(attributes);
-}
-
-audio_stream_type_t MediaPlayer2AudioOutput::getAudioStreamType() const {
- ALOGV("getAudioStreamType");
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == nullptr) {
- return AUDIO_STREAM_DEFAULT;
- }
- return mJAudioTrack->getAudioStreamType();
-}
-
-void MediaPlayer2AudioOutput::close_l() {
- mJAudioTrack.clear();
-}
-
-status_t MediaPlayer2AudioOutput::open(
- uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
- audio_format_t format,
- AudioCallback cb, void *cookie,
- audio_output_flags_t flags,
- const audio_offload_info_t *offloadInfo,
- uint32_t suggestedFrameCount) {
- ALOGV("open(%u, %d, 0x%x, 0x%x, %d 0x%x)", sampleRate, channelCount, channelMask,
- format, mSessionId, flags);
-
- // offloading is only supported in callback mode for now.
- // offloadInfo must be present if offload flag is set
- if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) &&
- ((cb == nullptr) || (offloadInfo == nullptr))) {
- return BAD_VALUE;
- }
-
- // compute frame count for the AudioTrack internal buffer
- const size_t frameCount =
- ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) ? 0 : suggestedFrameCount;
-
- if (channelMask == CHANNEL_MASK_USE_CHANNEL_ORDER) {
- channelMask = audio_channel_out_mask_from_count(channelCount);
- if (0 == channelMask) {
- ALOGE("open() error, can\'t derive mask for %d audio channels", channelCount);
- return NO_INIT;
- }
- }
-
- Mutex::Autolock lock(mLock);
- mCallback = cb;
- mCallbackCookie = cookie;
-
- sp<JAudioTrack> jT;
- CallbackData *newcbd = nullptr;
-
- ALOGV("creating new JAudioTrack");
-
- if (mCallback != nullptr) {
- newcbd = new CallbackData(this);
- jT = new JAudioTrack(
- sampleRate,
- format,
- channelMask,
- CallbackWrapper,
- newcbd,
- frameCount,
- mSessionId,
- mAttributes != nullptr ? mAttributes->getJObject() : nullptr,
- 1.0f); // default value for maxRequiredSpeed
- } else {
- // TODO: Due to buffer memory concerns, we use a max target playback speed
- // based on mPlaybackRate at the time of open (instead of kMaxRequiredSpeed),
- // also clamping the target speed to 1.0 <= targetSpeed <= kMaxRequiredSpeed.
- const float targetSpeed =
- std::min(std::max(mPlaybackRate.mSpeed, 1.0f), kMaxRequiredSpeed);
- ALOGW_IF(targetSpeed != mPlaybackRate.mSpeed,
- "track target speed:%f clamped from playback speed:%f",
- targetSpeed, mPlaybackRate.mSpeed);
- jT = new JAudioTrack(
- sampleRate,
- format,
- channelMask,
- nullptr,
- nullptr,
- frameCount,
- mSessionId,
- mAttributes != nullptr ? mAttributes->getJObject() : nullptr,
- targetSpeed);
- }
-
- if (jT == 0) {
- ALOGE("Unable to create audio track");
- delete newcbd;
- // t goes out of scope, so reference count drops to zero
- return NO_INIT;
- }
-
- CHECK((jT != nullptr) && ((mCallback == nullptr) || (newcbd != nullptr)));
-
- mCallbackData = newcbd;
- ALOGV("setVolume");
- jT->setVolume(mVolume);
-
- mSampleRateHz = sampleRate;
- mFlags = flags;
- mMsecsPerFrame = 1E3f / (mPlaybackRate.mSpeed * sampleRate);
- mFrameSize = jT->frameSize();
- mJAudioTrack = jT;
-
- return updateTrack_l();
-}
-
-status_t MediaPlayer2AudioOutput::updateTrack_l() {
- if (mJAudioTrack == nullptr) {
- return NO_ERROR;
- }
-
- status_t res = NO_ERROR;
- // Note some output devices may give us a direct track even though we don't specify it.
- // Example: Line application b/17459982.
- if ((mJAudioTrack->getFlags()
- & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD | AUDIO_OUTPUT_FLAG_DIRECT)) == 0) {
- res = mJAudioTrack->setPlaybackRate(mPlaybackRate);
- if (res == NO_ERROR) {
- mJAudioTrack->setAuxEffectSendLevel(mSendLevel);
- res = mJAudioTrack->attachAuxEffect(mAuxEffectId);
- }
- }
- if (mPreferredDevice != nullptr) {
- mJAudioTrack->setPreferredDevice(mPreferredDevice->getJObject());
- }
-
- mJAudioTrack->registerRoutingDelegates(mRoutingDelegates);
-
- ALOGV("updateTrack_l() DONE status %d", res);
- return res;
-}
-
-status_t MediaPlayer2AudioOutput::start() {
- ALOGV("start");
- Mutex::Autolock lock(mLock);
- if (mCallbackData != nullptr) {
- mCallbackData->endTrackSwitch();
- }
- if (mJAudioTrack != nullptr) {
- mJAudioTrack->setVolume(mVolume);
- mJAudioTrack->setAuxEffectSendLevel(mSendLevel);
- status_t status = mJAudioTrack->start();
- return status;
- }
- return NO_INIT;
-}
-
-ssize_t MediaPlayer2AudioOutput::write(const void* buffer, size_t size, bool blocking) {
- Mutex::Autolock lock(mLock);
- LOG_ALWAYS_FATAL_IF(mCallback != nullptr, "Don't call write if supplying a callback.");
-
- //ALOGV("write(%p, %u)", buffer, size);
- if (mJAudioTrack != nullptr) {
- return mJAudioTrack->write(buffer, size, blocking);
- }
- return NO_INIT;
-}
-
-void MediaPlayer2AudioOutput::stop() {
- ALOGV("stop");
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack != nullptr) {
- mJAudioTrack->stop();
- }
-}
-
-void MediaPlayer2AudioOutput::flush() {
- ALOGV("flush");
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack != nullptr) {
- mJAudioTrack->flush();
- }
-}
-
-void MediaPlayer2AudioOutput::pause() {
- ALOGV("pause");
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack != nullptr) {
- mJAudioTrack->pause();
- }
-}
-
-void MediaPlayer2AudioOutput::close() {
- ALOGV("close");
- sp<JAudioTrack> track;
- {
- Mutex::Autolock lock(mLock);
- track = mJAudioTrack;
- close_l(); // clears mJAudioTrack
- }
- // destruction of the track occurs outside of mutex.
-}
-
-void MediaPlayer2AudioOutput::setVolume(float volume) {
- ALOGV("setVolume(%f)", volume);
- Mutex::Autolock lock(mLock);
- mVolume = volume;
- if (mJAudioTrack != nullptr) {
- mJAudioTrack->setVolume(volume);
- }
-}
-
-status_t MediaPlayer2AudioOutput::setPlaybackRate(const AudioPlaybackRate &rate) {
- ALOGV("setPlaybackRate(%f %f %d %d)",
- rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode);
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == 0) {
- // remember rate so that we can set it when the track is opened
- mPlaybackRate = rate;
- return OK;
- }
- status_t res = mJAudioTrack->setPlaybackRate(rate);
- if (res != NO_ERROR) {
- return res;
- }
- // rate.mSpeed is always greater than 0 if setPlaybackRate succeeded
- CHECK_GT(rate.mSpeed, 0.f);
- mPlaybackRate = rate;
- if (mSampleRateHz != 0) {
- mMsecsPerFrame = 1E3f / (rate.mSpeed * mSampleRateHz);
- }
- return res;
-}
-
-status_t MediaPlayer2AudioOutput::getPlaybackRate(AudioPlaybackRate *rate) {
- ALOGV("getPlaybackRate");
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == 0) {
- return NO_INIT;
- }
- *rate = mJAudioTrack->getPlaybackRate();
- return NO_ERROR;
-}
-
-status_t MediaPlayer2AudioOutput::setAuxEffectSendLevel(float level) {
- ALOGV("setAuxEffectSendLevel(%f)", level);
- Mutex::Autolock lock(mLock);
- mSendLevel = level;
- if (mJAudioTrack != nullptr) {
- return mJAudioTrack->setAuxEffectSendLevel(level);
- }
- return NO_ERROR;
-}
-
-status_t MediaPlayer2AudioOutput::attachAuxEffect(int effectId) {
- ALOGV("attachAuxEffect(%d)", effectId);
- Mutex::Autolock lock(mLock);
- mAuxEffectId = effectId;
- if (mJAudioTrack != nullptr) {
- return mJAudioTrack->attachAuxEffect(effectId);
- }
- return NO_ERROR;
-}
-
-status_t MediaPlayer2AudioOutput::setPreferredDevice(jobject device) {
- ALOGV("setPreferredDevice");
- Mutex::Autolock lock(mLock);
- status_t ret = NO_ERROR;
- if (mJAudioTrack != nullptr) {
- ret = mJAudioTrack->setPreferredDevice(device);
- }
- if (ret == NO_ERROR) {
- mPreferredDevice = new JObjectHolder(device);
- }
- return ret;
-}
-
-jobject MediaPlayer2AudioOutput::getRoutedDevice() {
- ALOGV("getRoutedDevice");
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack != nullptr) {
- return mJAudioTrack->getRoutedDevice();
- }
- return nullptr;
-}
-
-status_t MediaPlayer2AudioOutput::addAudioDeviceCallback(jobject jRoutingDelegate) {
- ALOGV("addAudioDeviceCallback");
- Mutex::Autolock lock(mLock);
- jobject listener = JAudioTrack::getListener(jRoutingDelegate);
- if (JAudioTrack::findByKey(mRoutingDelegates, listener) == nullptr) {
- sp<JObjectHolder> listenerHolder = new JObjectHolder(listener);
- jobject handler = JAudioTrack::getHandler(jRoutingDelegate);
- sp<JObjectHolder> routingDelegateHolder = new JObjectHolder(jRoutingDelegate);
-
- mRoutingDelegates.push_back(std::pair<sp<JObjectHolder>, sp<JObjectHolder>>(
- listenerHolder, routingDelegateHolder));
-
- if (mJAudioTrack != nullptr) {
- return mJAudioTrack->addAudioDeviceCallback(
- routingDelegateHolder->getJObject(), handler);
- }
- }
- return NO_ERROR;
-}
-
-status_t MediaPlayer2AudioOutput::removeAudioDeviceCallback(jobject listener) {
- ALOGV("removeAudioDeviceCallback");
- Mutex::Autolock lock(mLock);
- jobject routingDelegate = nullptr;
- if ((routingDelegate = JAudioTrack::findByKey(mRoutingDelegates, listener)) != nullptr) {
- if (mJAudioTrack != nullptr) {
- mJAudioTrack->removeAudioDeviceCallback(routingDelegate);
- }
- JAudioTrack::eraseByKey(mRoutingDelegates, listener);
- }
- return NO_ERROR;
-}
-
-// static
-void MediaPlayer2AudioOutput::CallbackWrapper(
- int event, void *cookie, void *info) {
- //ALOGV("callbackwrapper");
- CallbackData *data = (CallbackData*)cookie;
- // lock to ensure we aren't caught in the middle of a track switch.
- data->lock();
- MediaPlayer2AudioOutput *me = data->getOutput();
- JAudioTrack::Buffer *buffer = (JAudioTrack::Buffer *)info;
- if (me == nullptr) {
- // no output set, likely because the track was scheduled to be reused
- // by another player, but the format turned out to be incompatible.
- data->unlock();
- if (buffer != nullptr) {
- buffer->mSize = 0;
- }
- return;
- }
-
- switch(event) {
- case JAudioTrack::EVENT_MORE_DATA: {
- size_t actualSize = (*me->mCallback)(
- me, buffer->mData, buffer->mSize, me->mCallbackCookie,
- CB_EVENT_FILL_BUFFER);
-
- // Log when no data is returned from the callback.
- // (1) We may have no data (especially with network streaming sources).
- // (2) We may have reached the EOS and the audio track is not stopped yet.
- // Note that AwesomePlayer/AudioPlayer will only return zero size when it reaches the EOS.
- // NuPlayer2Renderer will return zero when it doesn't have data (it doesn't block to fill).
- //
- // This is a benign busy-wait, with the next data request generated 10 ms or more later;
- // nevertheless for power reasons, we don't want to see too many of these.
-
- ALOGV_IF(actualSize == 0 && buffer->mSize > 0, "callbackwrapper: empty buffer returned");
-
- buffer->mSize = actualSize;
- } break;
-
- case JAudioTrack::EVENT_STREAM_END:
- // currently only occurs for offloaded callbacks
- ALOGV("callbackwrapper: deliver EVENT_STREAM_END");
- (*me->mCallback)(me, nullptr /* buffer */, 0 /* size */,
- me->mCallbackCookie, CB_EVENT_STREAM_END);
- break;
-
- case JAudioTrack::EVENT_NEW_IAUDIOTRACK :
- ALOGV("callbackwrapper: deliver EVENT_TEAR_DOWN");
- (*me->mCallback)(me, nullptr /* buffer */, 0 /* size */,
- me->mCallbackCookie, CB_EVENT_TEAR_DOWN);
- break;
-
- case JAudioTrack::EVENT_UNDERRUN:
- // This occurs when there is no data available, typically
- // when there is a failure to supply data to the AudioTrack. It can also
- // occur in non-offloaded mode when the audio device comes out of standby.
- //
- // If an AudioTrack underruns it outputs silence. Since this happens suddenly
- // it may sound like an audible pop or glitch.
- //
- // The underrun event is sent once per track underrun; the condition is reset
- // when more data is sent to the AudioTrack.
- ALOGD("callbackwrapper: EVENT_UNDERRUN (discarded)");
- break;
-
- default:
- ALOGE("received unknown event type: %d inside CallbackWrapper !", event);
- }
-
- data->unlock();
-}
-
-int32_t MediaPlayer2AudioOutput::getSessionId() const {
- Mutex::Autolock lock(mLock);
- return mSessionId;
-}
-
-void MediaPlayer2AudioOutput::setSessionId(const int32_t sessionId) {
- Mutex::Autolock lock(mLock);
- mSessionId = sessionId;
-}
-
-uint32_t MediaPlayer2AudioOutput::getSampleRate() const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == 0) {
- return 0;
- }
- return mJAudioTrack->getSampleRate();
-}
-
-int64_t MediaPlayer2AudioOutput::getBufferDurationInUs() const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == 0) {
- return 0;
- }
- int64_t duration;
- if (mJAudioTrack->getBufferDurationInUs(&duration) != OK) {
- return 0;
- }
- return duration;
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h b/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h
deleted file mode 100644
index 2ed4632..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h
+++ /dev/null
@@ -1,461 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_JAUDIOTRACK_H
-#define ANDROID_JAUDIOTRACK_H
-
-#include <utility>
-#include <jni.h>
-#include <media/AudioResamplerPublic.h>
-#include <media/AudioSystem.h>
-#include <media/VolumeShaper.h>
-#include <system/audio.h>
-#include <utils/Errors.h>
-#include <utils/Vector.h>
-#include <mediaplayer2/JObjectHolder.h>
-#include <media/AudioTimestamp.h> // It has dependency on audio.h/Errors.h, but doesn't
- // include them in it. Therefore it is included here at last.
-
-namespace android {
-
-class JAudioTrack : public RefBase {
-public:
-
- /* Events used by AudioTrack callback function (callback_t).
- * Keep in sync with frameworks/base/media/java/android/media/AudioTrack.java NATIVE_EVENT_*.
- */
- enum event_type {
- EVENT_MORE_DATA = 0, // Request to write more data to buffer.
- EVENT_UNDERRUN = 1, // Buffer underrun occurred. This will not occur for
- // static tracks.
- EVENT_NEW_IAUDIOTRACK = 6, // IAudioTrack was re-created, either due to re-routing and
- // voluntary invalidation by mediaserver, or mediaserver crash.
- EVENT_STREAM_END = 7, // Sent after all the buffers queued in AF and HW are played
- // back (after stop is called) for an offloaded track.
- };
-
- class Buffer
- {
- public:
- size_t mSize; // input/output in bytes.
- void* mData; // pointer to the audio data.
- };
-
- /* As a convenience, if a callback is supplied, a handler thread
- * is automatically created with the appropriate priority. This thread
- * invokes the callback when a new buffer becomes available or various conditions occur.
- *
- * Parameters:
- *
- * event: type of event notified (see enum AudioTrack::event_type).
- * user: Pointer to context for use by the callback receiver.
- * info: Pointer to optional parameter according to event type:
- * - EVENT_MORE_DATA: pointer to JAudioTrack::Buffer struct. The callback must not
- * write more bytes than indicated by 'size' field and update 'size' if fewer bytes
- * are written.
- * - EVENT_NEW_IAUDIOTRACK: unused.
- * - EVENT_STREAM_END: unused.
- */
-
- typedef void (*callback_t)(int event, void* user, void *info);
-
- /* Creates an JAudioTrack object for non-offload mode.
- * Once created, the track needs to be started before it can be used.
- * Unspecified values are set to appropriate default values.
- *
- * Parameters:
- *
- * streamType: Select the type of audio stream this track is attached to
- * (e.g. AUDIO_STREAM_MUSIC).
- * sampleRate: Data source sampling rate in Hz. Zero means to use the sink sample rate.
- * A non-zero value must be specified if AUDIO_OUTPUT_FLAG_DIRECT is set.
- * 0 will not work with current policy implementation for direct output
- * selection where an exact match is needed for sampling rate.
- * (TODO: Check direct output after flags can be used in Java AudioTrack.)
- * format: Audio format. For mixed tracks, any PCM format supported by server is OK.
- * For direct and offloaded tracks, the possible format(s) depends on the
- * output sink.
- * (TODO: How can we check whether a format is supported?)
- * channelMask: Channel mask, such that audio_is_output_channel(channelMask) is true.
- * cbf: Callback function. If not null, this function is called periodically
- * to provide new data and inform of marker, position updates, etc.
- * user: Context for use by the callback receiver.
- * frameCount: Minimum size of track PCM buffer in frames. This defines the
- * application's contribution to the latency of the track.
- * The actual size selected by the JAudioTrack could be larger if the
- * requested size is not compatible with current audio HAL configuration.
- * Zero means to use a default value.
- * sessionId: Specific session ID, or zero to use default.
- * pAttributes: If not NULL, supersedes streamType for use case selection.
- * maxRequiredSpeed: For PCM tracks, this creates an appropriate buffer size that will allow
- * maxRequiredSpeed playback. Values less than 1.0f and greater than
- * AUDIO_TIMESTRETCH_SPEED_MAX will be clamped. For non-PCM tracks
- * and direct or offloaded tracks, this parameter is ignored.
- * (TODO: Handle this after offload / direct track is supported.)
- *
- * TODO: Revive removed arguments after offload mode is supported.
- */
- JAudioTrack(uint32_t sampleRate,
- audio_format_t format,
- audio_channel_mask_t channelMask,
- callback_t cbf,
- void* user,
- size_t frameCount = 0,
- int32_t sessionId = AUDIO_SESSION_ALLOCATE,
- const jobject pAttributes = NULL,
- float maxRequiredSpeed = 1.0f);
-
- /*
- // Q. May be used in AudioTrack.setPreferredDevice(AudioDeviceInfo)?
- audio_port_handle_t selectedDeviceId,
-
- // TODO: No place to use these values.
- int32_t notificationFrames,
- const audio_offload_info_t *offloadInfo,
- */
-
- virtual ~JAudioTrack();
-
- size_t frameCount();
- size_t channelCount();
-
- /* Returns this track's estimated latency in milliseconds.
- * This includes the latency due to AudioTrack buffer size, AudioMixer (if any)
- * and audio hardware driver.
- */
- uint32_t latency();
-
- /* Return the total number of frames played since playback start.
- * The counter will wrap (overflow) periodically, e.g. every ~27 hours at 44.1 kHz.
- * It is reset to zero by flush(), reload(), and stop().
- *
- * Parameters:
- *
- * position: Address where to return play head position.
- *
- * Returned status (from utils/Errors.h) can be:
- * - NO_ERROR: successful operation
- * - BAD_VALUE: position is NULL
- */
- status_t getPosition(uint32_t *position);
-
- // TODO: Does this comment apply same to Java AudioTrack::getTimestamp?
- // Changed the return type from status_t to bool, since Java AudioTrack::getTimestamp returns
- // boolean. Will Java getTimestampWithStatus() be public?
- /* Poll for a timestamp on demand.
- * Use if EVENT_NEW_TIMESTAMP is not delivered often enough for your needs,
- * or if you need to get the most recent timestamp outside of the event callback handler.
- * Caution: calling this method too often may be inefficient;
- * if you need a high resolution mapping between frame position and presentation time,
- * consider implementing that at application level, based on the low resolution timestamps.
- * Returns NO_ERROR if timestamp is valid.
- * NO_INIT if finds error, and timestamp parameter will be undefined on return.
- */
- status_t getTimestamp(AudioTimestamp& timestamp);
-
- // TODO: This doc is just copied from AudioTrack.h. Revise it after implemenation.
- /* Return the extended timestamp, with additional timebase info and improved drain behavior.
- *
- * This is similar to the AudioTrack.java API:
- * getTimestamp(@NonNull AudioTimestamp timestamp, @AudioTimestamp.Timebase int timebase)
- *
- * Some differences between this method and the getTimestamp(AudioTimestamp& timestamp) method
- *
- * 1. stop() by itself does not reset the frame position.
- * A following start() resets the frame position to 0.
- * 2. flush() by itself does not reset the frame position.
- * The frame position advances by the number of frames flushed,
- * when the first frame after flush reaches the audio sink.
- * 3. BOOTTIME clock offsets are provided to help synchronize with
- * non-audio streams, e.g. sensor data.
- * 4. Position is returned with 64 bits of resolution.
- *
- * Parameters:
- * timestamp: A pointer to the caller allocated ExtendedTimestamp.
- *
- * Returns NO_ERROR on success; timestamp is filled with valid data.
- * BAD_VALUE if timestamp is NULL.
- * WOULD_BLOCK if called immediately after start() when the number
- * of frames consumed is less than the
- * overall hardware latency to physical output. In WOULD_BLOCK cases,
- * one might poll again, or use getPosition(), or use 0 position and
- * current time for the timestamp.
- * If WOULD_BLOCK is returned, the timestamp is still
- * modified with the LOCATION_CLIENT portion filled.
- * DEAD_OBJECT if AudioFlinger dies or the output device changes and
- * the track cannot be automatically restored.
- * The application needs to recreate the AudioTrack
- * because the audio device changed or AudioFlinger died.
- * This typically occurs for direct or offloaded tracks
- * or if mDoNotReconnect is true.
- * INVALID_OPERATION if called on a offloaded or direct track.
- * Use getTimestamp(AudioTimestamp& timestamp) instead.
- */
- status_t getTimestamp(ExtendedTimestamp *timestamp);
-
- /* Set source playback rate for timestretch
- * 1.0 is normal speed: < 1.0 is slower, > 1.0 is faster
- * 1.0 is normal pitch: < 1.0 is lower pitch, > 1.0 is higher pitch
- *
- * AUDIO_TIMESTRETCH_SPEED_MIN <= speed <= AUDIO_TIMESTRETCH_SPEED_MAX
- * AUDIO_TIMESTRETCH_PITCH_MIN <= pitch <= AUDIO_TIMESTRETCH_PITCH_MAX
- *
- * Speed increases the playback rate of media, but does not alter pitch.
- * Pitch increases the "tonal frequency" of media, but does not affect the playback rate.
- */
- status_t setPlaybackRate(const AudioPlaybackRate &playbackRate);
-
- /* Return current playback rate */
- const AudioPlaybackRate getPlaybackRate();
-
- /* Sets the volume shaper object */
- media::VolumeShaper::Status applyVolumeShaper(
- const sp<media::VolumeShaper::Configuration>& configuration,
- const sp<media::VolumeShaper::Operation>& operation);
-
- /* Set the send level for this track. An auxiliary effect should be attached
- * to the track with attachEffect(). Level must be >= 0.0 and <= 1.0.
- */
- status_t setAuxEffectSendLevel(float level);
-
- /* Attach track auxiliary output to specified effect. Use effectId = 0
- * to detach track from effect.
- *
- * Parameters:
- *
- * effectId: effectId obtained from AudioEffect::id().
- *
- * Returned status (from utils/Errors.h) can be:
- * - NO_ERROR: successful operation
- * - INVALID_OPERATION: The effect is not an auxiliary effect.
- * - BAD_VALUE: The specified effect ID is invalid.
- */
- status_t attachAuxEffect(int effectId);
-
- /* Set volume for this track, mostly used for games' sound effects
- * left and right volumes. Levels must be >= 0.0 and <= 1.0.
- * This is the older API. New applications should use setVolume(float) when possible.
- */
- status_t setVolume(float left, float right);
-
- /* Set volume for all channels. This is the preferred API for new applications,
- * especially for multi-channel content.
- */
- status_t setVolume(float volume);
-
- // TODO: Does this comment equally apply to the Java AudioTrack::play()?
- /* After it's created the track is not active. Call start() to
- * make it active. If set, the callback will start being called.
- * If the track was previously paused, volume is ramped up over the first mix buffer.
- */
- status_t start();
-
- // TODO: Does this comment still applies? It seems not. (obtainBuffer, AudioFlinger, ...)
- /* As a convenience we provide a write() interface to the audio buffer.
- * Input parameter 'size' is in byte units.
- * This is implemented on top of obtainBuffer/releaseBuffer. For best
- * performance use callbacks. Returns actual number of bytes written >= 0,
- * or one of the following negative status codes:
- * INVALID_OPERATION AudioTrack is configured for static buffer or streaming mode
- * BAD_VALUE size is invalid
- * WOULD_BLOCK when obtainBuffer() returns same, or
- * AudioTrack was stopped during the write
- * DEAD_OBJECT when AudioFlinger dies or the output device changes and
- * the track cannot be automatically restored.
- * The application needs to recreate the AudioTrack
- * because the audio device changed or AudioFlinger died.
- * This typically occurs for direct or offload tracks
- * or if mDoNotReconnect is true.
- * or any other error code returned by IAudioTrack::start() or restoreTrack_l().
- * Default behavior is to only return when all data has been transferred. Set 'blocking' to
- * false for the method to return immediately without waiting to try multiple times to write
- * the full content of the buffer.
- */
- ssize_t write(const void* buffer, size_t size, bool blocking = true);
-
- // TODO: Does this comment equally apply to the Java AudioTrack::stop()?
- /* Stop a track.
- * In static buffer mode, the track is stopped immediately.
- * In streaming mode, the callback will cease being called. Note that obtainBuffer() still
- * works and will fill up buffers until the pool is exhausted, and then will return WOULD_BLOCK.
- * In streaming mode the stop does not occur immediately: any data remaining in the buffer
- * is first drained, mixed, and output, and only then is the track marked as stopped.
- */
- void stop();
- bool stopped() const;
-
- // TODO: Does this comment equally apply to the Java AudioTrack::flush()?
- /* 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.
- * This function is a no-op if the track is not stopped or paused, or uses a static buffer.
- */
- void flush();
-
- // TODO: Does this comment equally apply to the Java AudioTrack::pause()?
- // At least we are not using obtainBuffer.
- /* Pause a track. After pause, the callback will cease being called and
- * obtainBuffer returns WOULD_BLOCK. Note that obtainBuffer() still works
- * and will fill up buffers until the pool is exhausted.
- * Volume is ramped down over the next mix buffer following the pause request,
- * and then the track is marked as paused. It can be resumed with ramp up by start().
- */
- void pause();
-
- bool isPlaying() const;
-
- /* Return current source sample rate in Hz.
- * If specified as zero in constructor, this will be the sink sample rate.
- */
- uint32_t getSampleRate();
-
- /* Returns the buffer duration in microseconds at current playback rate. */
- status_t getBufferDurationInUs(int64_t *duration);
-
- audio_format_t format();
-
- size_t frameSize();
-
- /*
- * Dumps the state of an audio track.
- * Not a general-purpose API; intended only for use by media player service to dump its tracks.
- */
- status_t dump(int fd, const Vector<String16>& args) const;
-
- /* Returns the AudioDeviceInfo used by the output to which this AudioTrack is
- * attached.
- */
- jobject getRoutedDevice();
-
- /* Returns the ID of the audio session this AudioTrack belongs to. */
- int32_t getAudioSessionId();
-
- /* Sets the preferred audio device to use for output of this AudioTrack.
- *
- * Parameters:
- * Device: an AudioDeviceInfo object.
- *
- * Returned value:
- * - NO_ERROR: successful operation
- * - BAD_VALUE: failed to set the device
- */
- status_t setPreferredDevice(jobject device);
-
- // TODO: Add AUDIO_OUTPUT_FLAG_DIRECT when it is possible to check.
- // TODO: Add AUDIO_FLAG_HW_AV_SYNC when it is possible to check.
- /* Returns the flags */
- audio_output_flags_t getFlags() const { return mFlags; }
-
- /* We don't keep stream type here,
- * instead, we keep attributes and call getVolumeControlStream() to get stream type
- */
- audio_stream_type_t getAudioStreamType();
-
- /* Obtain the pending duration in milliseconds for playback of pure PCM data remaining in
- * AudioTrack.
- *
- * Returns NO_ERROR if successful.
- * INVALID_OPERATION if the AudioTrack does not contain pure PCM data.
- * BAD_VALUE if msec is nullptr.
- */
- status_t pendingDuration(int32_t *msec);
-
- /* Adds an AudioDeviceCallback. The caller will be notified when the audio device to which this
- * AudioTrack is routed is updated.
- * Replaces any previously installed callback.
- *
- * Parameters:
- * Listener: the listener to receive notification of rerouting events.
- * Handler: the handler to handler the rerouting events.
- *
- * Returns NO_ERROR if successful.
- * (TODO) INVALID_OPERATION if the same callback is already installed.
- * (TODO) NO_INIT or PREMISSION_DENIED if AudioFlinger service is not reachable
- * (TODO) BAD_VALUE if the callback is NULL
- */
- status_t addAudioDeviceCallback(jobject listener, jobject rd);
-
- /* Removes an AudioDeviceCallback.
- *
- * Parameters:
- * Listener: the listener to receive notification of rerouting events.
- *
- * Returns NO_ERROR if successful.
- * (TODO) INVALID_OPERATION if the callback is not installed
- * (TODO) BAD_VALUE if the callback is NULL
- */
- status_t removeAudioDeviceCallback(jobject listener);
-
- /* Register all backed-up routing delegates.
- *
- * Parameters:
- * routingDelegates: backed-up routing delegates
- *
- */
- void registerRoutingDelegates(
- Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>>& routingDelegates);
-
- /* get listener from RoutingDelegate object
- */
- static jobject getListener(const jobject routingDelegateObj);
-
- /* get handler from RoutingDelegate object
- */
- static jobject getHandler(const jobject routingDelegateObj);
-
- /*
- * Parameters:
- * map and key
- *
- * Returns value if key is in the map
- * nullptr if key is not in the map
- */
- static jobject findByKey(
- Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>>& mp, const jobject key);
-
- /*
- * Parameters:
- * map and key
- */
- static void eraseByKey(
- Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>>& mp, const jobject key);
-
-private:
- audio_output_flags_t mFlags;
-
- jclass mAudioTrackCls;
- jobject mAudioTrackObj;
-
- /* Creates a Java VolumeShaper.Configuration object from VolumeShaper::Configuration */
- jobject createVolumeShaperConfigurationObj(
- const sp<media::VolumeShaper::Configuration>& config);
-
- /* Creates a Java VolumeShaper.Operation object from VolumeShaper::Operation */
- jobject createVolumeShaperOperationObj(
- const sp<media::VolumeShaper::Operation>& operation);
-
- /* Creates a Java StreamEventCallback object */
- jobject createStreamEventCallback(callback_t cbf, void* user);
-
- /* Creates a Java Executor object for running a callback */
- jobject createCallbackExecutor();
-
- status_t javaToNativeStatus(int javaStatus);
-};
-
-}; // namespace android
-
-#endif // ANDROID_JAUDIOTRACK_H
diff --git a/media/libmediaplayer2/include/mediaplayer2/JMedia2HTTPConnection.h b/media/libmediaplayer2/include/mediaplayer2/JMedia2HTTPConnection.h
deleted file mode 100644
index 15f7f83..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/JMedia2HTTPConnection.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _J_MEDIA2_HTTP_CONNECTION_H_
-#define _J_MEDIA2_HTTP_CONNECTION_H_
-
-#include "jni.h"
-
-#include <media/MediaHTTPConnection.h>
-#include <media/stagefright/foundation/ABase.h>
-
-namespace android {
-
-struct JMedia2HTTPConnection : public MediaHTTPConnection {
- JMedia2HTTPConnection(JNIEnv *env, jobject thiz);
-
- virtual bool connect(
- const char *uri, const KeyedVector<String8, String8> *headers) override;
-
- virtual void disconnect() override;
- virtual ssize_t readAt(off64_t offset, void *data, size_t size) override;
- virtual off64_t getSize() override;
- virtual status_t getMIMEType(String8 *mimeType) override;
- virtual status_t getUri(String8 *uri) override;
-
-protected:
- virtual ~JMedia2HTTPConnection();
-
-private:
- jobject mMedia2HTTPConnectionObj;
- jmethodID mConnectMethod;
- jmethodID mDisconnectMethod;
- jmethodID mReadAtMethod;
- jmethodID mGetSizeMethod;
- jmethodID mGetMIMETypeMethod;
- jmethodID mGetUriMethod;
-
- jbyteArray mByteArrayObj;
-
- DISALLOW_EVIL_CONSTRUCTORS(JMedia2HTTPConnection);
-};
-
-} // namespace android
-
-#endif // _J_MEDIA2_HTTP_CONNECTION_H_
diff --git a/media/libmediaplayer2/include/mediaplayer2/JMedia2HTTPService.h b/media/libmediaplayer2/include/mediaplayer2/JMedia2HTTPService.h
deleted file mode 100644
index bf61a7f..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/JMedia2HTTPService.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _J_MEDIA2_HTTP_SERVICE_H_
-#define _J_MEDIA2_HTTP_SERVICE_H_
-
-#include <jni.h>
-#include <utils/RefBase.h>
-
-#include <media/MediaHTTPService.h>
-#include <media/MediaHTTPConnection.h>
-#include <media/stagefright/foundation/ABase.h>
-
-namespace android {
-
-struct JMedia2HTTPService : public MediaHTTPService {
- JMedia2HTTPService(JNIEnv *env, jobject thiz);
-
- virtual sp<MediaHTTPConnection> makeHTTPConnection() override;
-
-protected:
- virtual ~JMedia2HTTPService();
-
-private:
- jobject mMedia2HTTPServiceObj;
-
- jmethodID mMakeHTTPConnectionMethod;
-
- DISALLOW_EVIL_CONSTRUCTORS(JMedia2HTTPService);
-};
-
-} // namespace android
-
-#endif // _J_MEDIA2_HTTP_SERVICE_H_
diff --git a/media/libmediaplayer2/include/mediaplayer2/JObjectHolder.h b/media/libmediaplayer2/include/mediaplayer2/JObjectHolder.h
deleted file mode 100644
index 93d8b40..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/JObjectHolder.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef JOBJECT_HOLDER_H_
-
-#define JOBJECT_HOLDER_H_
-
-#include "jni.h"
-#include <mediaplayer2/JavaVMHelper.h>
-#include <utils/RefBase.h>
-
-namespace android {
-
-// Helper class for managing global reference of jobject.
-struct JObjectHolder : public RefBase {
- JObjectHolder(jobject obj) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- mJObject = reinterpret_cast<jobject>(env->NewGlobalRef(obj));
- }
-
- virtual ~JObjectHolder() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- env->DeleteGlobalRef(mJObject);
- }
-
- jobject getJObject() { return mJObject; }
-
-private:
- jobject mJObject;
-};
-
-} //" android
-
-#endif // JOBJECT_HOLDER_H_
diff --git a/media/libmediaplayer2/include/mediaplayer2/JavaVMHelper.h b/media/libmediaplayer2/include/mediaplayer2/JavaVMHelper.h
deleted file mode 100644
index 4b56aca..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/JavaVMHelper.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef JAVA_VM_HELPER_H_
-
-#define JAVA_VM_HELPER_H_
-
-#include "jni.h"
-
-#include <atomic>
-
-namespace android {
-
-struct JavaVMHelper {
- static JNIEnv *getJNIEnv();
- static JavaVM *getJavaVM();
- static void setJavaVM(JavaVM *vm);
-
-private:
- // Once a valid JavaVM has been set, it should never be reset or changed.
- // However, as it may be accessed from multiple threads, access needs to be
- // synchronized.
- static std::atomic<JavaVM *> sJavaVM;
-};
-
-} // namespace android
-
-#endif // JAVA_VM_HELPER_H_
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
deleted file mode 100644
index f38b7cc..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
-**
-** Copyright 2018, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef ANDROID_MEDIAPLAYER2AUDIOOUTPUT_H
-#define ANDROID_MEDIAPLAYER2AUDIOOUTPUT_H
-
-#include <mediaplayer2/MediaPlayer2Interface.h>
-#include <mediaplayer2/JAudioTrack.h>
-#include <mediaplayer2/JObjectHolder.h>
-
-#include <utility>
-#include <utils/String16.h>
-#include <utils/Vector.h>
-
-#include "jni.h"
-
-namespace android {
-
-class AudioTrack;
-
-class MediaPlayer2AudioOutput : public MediaPlayer2Interface::AudioSink
-{
- class CallbackData;
-
-public:
- MediaPlayer2AudioOutput(int32_t sessionId,
- uid_t uid,
- int pid,
- const jobject attributes);
- virtual ~MediaPlayer2AudioOutput();
-
- virtual bool ready() const {
- return mJAudioTrack != nullptr;
- }
- virtual ssize_t bufferSize() const;
- virtual ssize_t frameCount() const;
- virtual ssize_t channelCount() const;
- virtual ssize_t frameSize() const;
- virtual uint32_t latency() const;
- virtual float msecsPerFrame() const;
- virtual status_t getPosition(uint32_t *position) const;
- virtual status_t getTimestamp(AudioTimestamp &ts) const;
- virtual int64_t getPlayedOutDurationUs(int64_t nowUs) const;
- virtual status_t getFramesWritten(uint32_t *frameswritten) const;
- virtual int32_t getSessionId() const;
- virtual void setSessionId(const int32_t id);
- virtual uint32_t getSampleRate() const;
- virtual int64_t getBufferDurationInUs() const;
-
- virtual status_t open(
- uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
- audio_format_t format,
- AudioCallback cb, void *cookie,
- audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
- const audio_offload_info_t *offloadInfo = NULL,
- uint32_t suggestedFrameCount = 0);
-
- virtual status_t start();
- virtual ssize_t write(const void* buffer, size_t size, bool blocking = true);
- virtual void stop();
- virtual void flush();
- virtual void pause();
- virtual void close();
- void setAudioAttributes(const jobject attributes);
- virtual audio_stream_type_t getAudioStreamType() const;
-
- void setVolume(float volume);
- virtual status_t setPlaybackRate(const AudioPlaybackRate& rate);
- virtual status_t getPlaybackRate(AudioPlaybackRate* rate /* nonnull */);
-
- status_t setAuxEffectSendLevel(float level);
- status_t attachAuxEffect(int effectId);
- virtual status_t dump(int fd, const Vector<String16>& args) const;
-
- static bool isOnEmulator();
- static int getMinBufferCount();
- virtual bool needsTrailingPadding() {
- return true;
- // TODO: return correct value.
- //return mNextOutput == NULL;
- }
- // AudioRouting
- virtual status_t setPreferredDevice(jobject device);
- virtual jobject getRoutedDevice();
- virtual status_t addAudioDeviceCallback(jobject routingDelegate);
- virtual status_t removeAudioDeviceCallback(jobject listener);
-
-private:
- static void setMinBufferCount();
- static void CallbackWrapper(int event, void *me, void *info);
- void deleteRecycledTrack_l();
- void close_l();
- status_t updateTrack_l();
-
- sp<JAudioTrack> mJAudioTrack;
- AudioCallback mCallback;
- void * mCallbackCookie;
- CallbackData * mCallbackData;
- sp<JObjectHolder> mAttributes;
- float mVolume;
- AudioPlaybackRate mPlaybackRate;
- uint32_t mSampleRateHz; // sample rate of the content, as set in open()
- float mMsecsPerFrame;
- size_t mFrameSize;
- int32_t mSessionId;
- uid_t mUid;
- int mPid;
- float mSendLevel;
- int mAuxEffectId;
- audio_output_flags_t mFlags;
- sp<JObjectHolder> mPreferredDevice;
- mutable Mutex mLock;
-
- // <listener, routingDelegate>
- Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>> mRoutingDelegates;
-
- // static variables below not protected by mutex
- static bool mIsOnEmulator;
- static int mMinBufferCount; // 12 for emulator; otherwise 4
-
- // CallbackData is what is passed to the AudioTrack as the "user" data.
- // We need to be able to target this to a different Output on the fly,
- // so we can't use the Output itself for this.
- class CallbackData {
- friend MediaPlayer2AudioOutput;
- public:
- explicit CallbackData(MediaPlayer2AudioOutput *cookie) {
- mData = cookie;
- mSwitching = false;
- }
- MediaPlayer2AudioOutput *getOutput() const {
- return mData;
- }
- void setOutput(MediaPlayer2AudioOutput* newcookie) {
- mData = newcookie;
- }
- // lock/unlock are used by the callback before accessing the payload of this object
- void lock() const {
- mLock.lock();
- }
- void unlock() const {
- mLock.unlock();
- }
-
- // tryBeginTrackSwitch/endTrackSwitch are used when the CallbackData is handed over
- // to the next sink.
-
- // tryBeginTrackSwitch() returns true only if it obtains the lock.
- bool tryBeginTrackSwitch() {
- LOG_ALWAYS_FATAL_IF(mSwitching, "tryBeginTrackSwitch() already called");
- if (mLock.tryLock() != OK) {
- return false;
- }
- mSwitching = true;
- return true;
- }
- void endTrackSwitch() {
- if (mSwitching) {
- mLock.unlock();
- }
- mSwitching = false;
- }
-
- private:
- MediaPlayer2AudioOutput *mData;
- mutable Mutex mLock; // a recursive mutex might make this unnecessary.
- bool mSwitching;
- DISALLOW_EVIL_CONSTRUCTORS(CallbackData);
- };
-};
-
-}; // namespace android
-
-#endif // ANDROID_MEDIAPLAYER2AUDIOOUTPUT_H
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
deleted file mode 100644
index 7804a62..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_MEDIAPLAYER2INTERFACE_H
-#define ANDROID_MEDIAPLAYER2INTERFACE_H
-
-#ifdef __cplusplus
-
-#include <sys/types.h>
-#include <utils/Errors.h>
-#include <utils/String8.h>
-#include <utils/RefBase.h>
-#include <jni.h>
-
-#include <media/AVSyncSettings.h>
-#include <media/AudioResamplerPublic.h>
-#include <media/AudioSystem.h>
-#include <media/AudioTimestamp.h>
-#include <media/BufferingSettings.h>
-#include <media/stagefright/foundation/AHandler.h>
-#include <mediaplayer2/MediaPlayer2Types.h>
-
-#include "jni.h"
-#include "mediaplayer2.pb.h"
-
-using android::media::MediaPlayer2Proto::PlayerMessage;
-
-// Fwd decl to make sure everyone agrees that the scope of struct sockaddr_in is
-// global, and not in android::
-struct sockaddr_in;
-
-namespace android {
-
-struct DataSourceDesc;
-class Parcel;
-struct ANativeWindowWrapper;
-
-#define DEFAULT_AUDIOSINK_BUFFERSIZE 1200
-#define DEFAULT_AUDIOSINK_SAMPLERATE 44100
-
-// when the channel mask isn't known, use the channel count to derive a mask in AudioSink::open()
-#define CHANNEL_MASK_USE_CHANNEL_ORDER 0
-
-// duration below which we do not allow deep audio buffering
-#define AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US 5000000
-
-class MediaPlayer2InterfaceListener: public RefBase
-{
-public:
- virtual void notify(int64_t srcId, int msg, int ext1, int ext2,
- const PlayerMessage *obj) = 0;
-};
-
-class MediaPlayer2Interface : public AHandler {
-public:
- // AudioSink: abstraction layer for audio output
- class AudioSink : public RefBase {
- public:
- enum cb_event_t {
- CB_EVENT_FILL_BUFFER, // Request to write more data to buffer.
- CB_EVENT_STREAM_END, // Sent after all the buffers queued in AF and HW are played
- // back (after stop is called)
- CB_EVENT_TEAR_DOWN // The AudioTrack was invalidated due to use case change:
- // Need to re-evaluate offloading options
- };
-
- // Callback returns the number of bytes actually written to the buffer.
- typedef size_t (*AudioCallback)(
- AudioSink *audioSink, void *buffer, size_t size, void *cookie, cb_event_t event);
-
- virtual ~AudioSink() {}
- virtual bool ready() const = 0; // audio output is open and ready
- virtual ssize_t bufferSize() const = 0;
- virtual ssize_t frameCount() const = 0;
- virtual ssize_t channelCount() const = 0;
- virtual ssize_t frameSize() const = 0;
- virtual uint32_t latency() const = 0;
- virtual float msecsPerFrame() const = 0;
- virtual status_t getPosition(uint32_t *position) const = 0;
- virtual status_t getTimestamp(AudioTimestamp &ts) const = 0;
- virtual int64_t getPlayedOutDurationUs(int64_t nowUs) const = 0;
- virtual status_t getFramesWritten(uint32_t *frameswritten) const = 0;
- virtual int32_t getSessionId() const = 0;
- virtual audio_stream_type_t getAudioStreamType() const = 0;
- virtual uint32_t getSampleRate() const = 0;
- virtual int64_t getBufferDurationInUs() const = 0;
-
- // If no callback is specified, use the "write" API below to submit
- // audio data.
- virtual status_t open(
- uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
- audio_format_t format=AUDIO_FORMAT_PCM_16_BIT,
- AudioCallback cb = NULL,
- void *cookie = NULL,
- audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
- const audio_offload_info_t *offloadInfo = NULL,
- uint32_t suggestedFrameCount = 0) = 0;
-
- virtual status_t start() = 0;
-
- /* Input parameter |size| is in byte units stored in |buffer|.
- * Data is copied over and actual number of bytes written (>= 0)
- * is returned, or no data is copied and a negative status code
- * is returned (even when |blocking| is true).
- * When |blocking| is false, AudioSink will immediately return after
- * part of or full |buffer| is copied over.
- * When |blocking| is true, AudioSink will wait to copy the entire
- * buffer, unless an error occurs or the copy operation is
- * prematurely stopped.
- */
- virtual ssize_t write(const void* buffer, size_t size, bool blocking = true) = 0;
-
- virtual void stop() = 0;
- virtual void flush() = 0;
- virtual void pause() = 0;
- virtual void close() = 0;
-
- virtual status_t setPlaybackRate(const AudioPlaybackRate& rate) = 0;
- virtual status_t getPlaybackRate(AudioPlaybackRate* rate /* nonnull */) = 0;
- virtual bool needsTrailingPadding() {
- return true;
- }
-
- virtual status_t setParameters(const String8& /* keyValuePairs */) {
- return NO_ERROR;
- }
- virtual String8 getParameters(const String8& /* keys */) {
- return String8::empty();
- }
-
- // AudioRouting
- virtual status_t setPreferredDevice(jobject device);
- virtual jobject getRoutedDevice();
- virtual status_t addAudioDeviceCallback(jobject routingDelegate);
- virtual status_t removeAudioDeviceCallback(jobject listener);
- };
-
- MediaPlayer2Interface() : mListener(NULL) { }
- virtual ~MediaPlayer2Interface() { }
- virtual status_t initCheck() = 0;
-
- virtual void setAudioSink(const sp<AudioSink>& audioSink) {
- mAudioSink = audioSink;
- }
-
- virtual status_t setDataSource(const sp<DataSourceDesc> &dsd) = 0;
-
- virtual status_t prepareNextDataSource(const sp<DataSourceDesc> &dsd) = 0;
-
- virtual status_t playNextDataSource(int64_t srcId) = 0;
-
- // pass the buffered native window to the media player service
- virtual status_t setVideoSurfaceTexture(const sp<ANativeWindowWrapper>& nww) = 0;
-
- virtual status_t getBufferingSettings(BufferingSettings* buffering /* nonnull */) {
- *buffering = BufferingSettings();
- return OK;
- }
- virtual status_t setBufferingSettings(const BufferingSettings& /* buffering */) {
- return OK;
- }
-
- virtual status_t prepareAsync() = 0;
- virtual status_t start() = 0;
- virtual status_t pause() = 0;
- virtual bool isPlaying() = 0;
- virtual status_t setPlaybackSettings(const AudioPlaybackRate& rate) {
- // by default, players only support setting rate to the default
- if (!isAudioPlaybackRateEqual(rate, AUDIO_PLAYBACK_RATE_DEFAULT)) {
- return BAD_VALUE;
- }
- return OK;
- }
- virtual status_t getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */) {
- *rate = AUDIO_PLAYBACK_RATE_DEFAULT;
- return OK;
- }
- virtual status_t setSyncSettings(const AVSyncSettings& sync, float /* videoFps */) {
- // By default, players only support setting sync source to default; all other sync
- // settings are ignored. There is no requirement for getters to return set values.
- if (sync.mSource != AVSYNC_SOURCE_DEFAULT) {
- return BAD_VALUE;
- }
- return OK;
- }
- virtual status_t getSyncSettings(
- AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */) {
- *sync = AVSyncSettings();
- *videoFps = -1.f;
- return OK;
- }
- virtual status_t seekTo(
- int64_t msec, MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC) = 0;
- virtual status_t getCurrentPosition(int64_t *msec) = 0;
- virtual status_t getDuration(int64_t *msec) = 0;
- virtual status_t reset() = 0;
- virtual status_t notifyAt(int64_t /* mediaTimeUs */) {
- return INVALID_OPERATION;
- }
- virtual status_t setLooping(int loop) = 0;
- virtual status_t setParameter(int key, const Parcel &request) = 0;
- virtual status_t getParameter(int key, Parcel *reply) = 0;
-
- virtual status_t getMetrics(char **buffer, size_t *length) = 0;
-
- // Invoke a generic method on the player by using opaque parcels
- // for the request and reply.
- //
- // @param request Parcel that is positioned at the start of the
- // data sent by the java layer.
- // @param[out] reply Parcel to hold the reply data. Cannot be null.
- // @return OK if the call was successful.
- virtual status_t invoke(const PlayerMessage &request, PlayerMessage *reply) = 0;
-
- void setListener(const sp<MediaPlayer2InterfaceListener> &listener) {
- Mutex::Autolock autoLock(mListenerLock);
- mListener = listener;
- }
-
- void sendEvent(int64_t srcId, int msg, int ext1=0, int ext2=0, const PlayerMessage *obj=NULL) {
- sp<MediaPlayer2InterfaceListener> listener;
- {
- Mutex::Autolock autoLock(mListenerLock);
- listener = mListener;
- }
-
- if (listener) {
- listener->notify(srcId, msg, ext1, ext2, obj);
- }
- }
-
- virtual status_t dump(int /* fd */, const Vector<String16>& /* args */) const {
- return INVALID_OPERATION;
- }
-
- virtual void onMessageReceived(const sp<AMessage> & /* msg */) override { }
-
- // Modular DRM
- virtual status_t prepareDrm(int64_t /*srcId*/, const uint8_t /* uuid */[16],
- const Vector<uint8_t>& /* drmSessionId */) {
- return INVALID_OPERATION;
- }
- virtual status_t releaseDrm(int64_t /*srcId*/) {
- return INVALID_OPERATION;
- }
-
-protected:
- sp<AudioSink> mAudioSink;
-
-private:
- Mutex mListenerLock;
- sp<MediaPlayer2InterfaceListener> mListener;
-};
-
-}; // namespace android
-
-#endif // __cplusplus
-
-
-#endif // ANDROID_MEDIAPLAYER2INTERFACE_H
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
deleted file mode 100644
index 2430289..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_MEDIAPLAYER2_TYPES_H
-#define ANDROID_MEDIAPLAYER2_TYPES_H
-
-#include <media/mediaplayer_common.h>
-
-#include <media/MediaSource.h>
-
-namespace android {
-
-typedef MediaSource::ReadOptions::SeekMode MediaPlayer2SeekMode;
-
-enum media2_event_type {
- MEDIA2_NOP = 0, // interface test message
- MEDIA2_PREPARED = 1,
- MEDIA2_PLAYBACK_COMPLETE = 2,
- MEDIA2_BUFFERING_UPDATE = 3,
- MEDIA2_SEEK_COMPLETE = 4,
- MEDIA2_SET_VIDEO_SIZE = 5,
- MEDIA2_STARTED = 6,
- MEDIA2_PAUSED = 7,
- MEDIA2_SKIPPED = 8,
- MEDIA2_NOTIFY_TIME = 98,
- MEDIA2_TIMED_TEXT = 99,
- MEDIA2_ERROR = 100,
- MEDIA2_INFO = 200,
- MEDIA2_SUBTITLE_DATA = 201,
- MEDIA2_META_DATA = 202,
- MEDIA2_DRM_INFO = 210,
-};
-
-// Generic error codes for the media player framework. Errors are fatal, the
-// playback must abort.
-//
-// Errors are communicated back to the client using the
-// MediaPlayer2Listener::notify method defined below.
-// In this situation, 'notify' is invoked with the following:
-// 'msg' is set to MEDIA_ERROR.
-// 'ext1' should be a value from the enum media2_error_type.
-// 'ext2' contains an implementation dependant error code to provide
-// more details. Should default to 0 when not used.
-//
-// The codes are distributed as follow:
-// 0xx: Reserved
-// 1xx: Android Player errors. Something went wrong inside the MediaPlayer2.
-// 2xx: Media errors (e.g Codec not supported). There is a problem with the
-// media itself.
-// 3xx: Runtime errors. Some extraordinary condition arose making the playback
-// impossible.
-//
-enum media2_error_type {
- // 0xx
- MEDIA2_ERROR_UNKNOWN = 1,
- // 1xx
- // MEDIA2_ERROR_SERVER_DIED = 100,
- // 2xx
- MEDIA2_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200,
- // 3xx
- MEDIA2_ERROR_FAILED_TO_SET_DATA_SOURCE = 300,
-};
-
-
-// Info and warning codes for the media player framework. These are non fatal,
-// the playback is going on but there might be some user visible issues.
-//
-// Info and warning messages are communicated back to the client using the
-// MediaPlayer2Listener::notify method defined below. In this situation,
-// 'notify' is invoked with the following:
-// 'msg' is set to MEDIA_INFO.
-// 'ext1' should be a value from the enum media2_info_type.
-// 'ext2' contains an implementation dependant info code to provide
-// more details. Should default to 0 when not used.
-//
-// The codes are distributed as follow:
-// 0xx: Reserved
-// 7xx: Android Player info/warning (e.g player lagging behind.)
-// 8xx: Media info/warning (e.g media badly interleaved.)
-//
-enum media2_info_type {
- // 0xx
- MEDIA2_INFO_UNKNOWN = 1,
- // The player just started the playback of this data source.
- MEDIA2_INFO_DATA_SOURCE_START = 2,
- // The player just pushed the very first video frame for rendering
- MEDIA2_INFO_VIDEO_RENDERING_START = 3,
- // The player just pushed the very first audio frame for rendering
- MEDIA2_INFO_AUDIO_RENDERING_START = 4,
- // The player just completed the playback of this data source
- MEDIA2_INFO_DATA_SOURCE_END = 5,
- // The player just completed the playback of all data sources.
- // But this is not visible in native code. Just keep this entry for completeness.
- MEDIA2_INFO_DATA_SOURCE_LIST_END = 6,
- // The player just completed an iteration of playback loop. This event is sent only when
- // looping is enabled.
- MEDIA2_INFO_DATA_SOURCE_REPEAT = 7,
-
- //1xx
- // The player just prepared a data source.
- MEDIA2_INFO_PREPARED = 100,
- // The player just completed a call play().
- MEDIA2_INFO_COMPLETE_CALL_PLAY = 101,
- // The player just completed a call pause().
- MEDIA2_INFO_COMPLETE_CALL_PAUSE = 102,
- // The player just completed a call seekTo.
- MEDIA2_INFO_COMPLETE_CALL_SEEK = 103,
-
- // 7xx
- // The video is too complex for the decoder: it can't decode frames fast
- // enough. Possibly only the audio plays fine at this stage.
- MEDIA2_INFO_VIDEO_TRACK_LAGGING = 700,
- // MediaPlayer2 is temporarily pausing playback internally in order to
- // buffer more data.
- MEDIA2_INFO_BUFFERING_START = 701,
- // MediaPlayer2 is resuming playback after filling buffers.
- MEDIA2_INFO_BUFFERING_END = 702,
- // Bandwidth in recent past
- MEDIA2_INFO_NETWORK_BANDWIDTH = 703,
-
- // 8xx
- // Bad interleaving means that a media has been improperly interleaved or not
- // interleaved at all, e.g has all the video samples first then all the audio
- // ones. Video is playing but a lot of disk seek may be happening.
- MEDIA2_INFO_BAD_INTERLEAVING = 800,
- // The media is not seekable (e.g live stream).
- MEDIA2_INFO_NOT_SEEKABLE = 801,
- // New media metadata is available.
- MEDIA2_INFO_METADATA_UPDATE = 802,
- // Audio can not be played.
- MEDIA2_INFO_PLAY_AUDIO_ERROR = 804,
- // Video can not be played.
- MEDIA2_INFO_PLAY_VIDEO_ERROR = 805,
-
- //9xx
- MEDIA2_INFO_TIMED_TEXT_ERROR = 900,
-};
-
-// Do not change these values without updating their counterparts in MediaPlayer2.java
-enum mediaplayer2_states {
- MEDIAPLAYER2_STATE_IDLE = 1001,
- MEDIAPLAYER2_STATE_PREPARED = 1002,
- MEDIAPLAYER2_STATE_PAUSED = 1003,
- MEDIAPLAYER2_STATE_PLAYING = 1004,
- MEDIAPLAYER2_STATE_ERROR = 1005,
-};
-
-enum media_player2_internal_states {
- MEDIA_PLAYER2_STATE_ERROR = 0,
- MEDIA_PLAYER2_IDLE = 1 << 0,
- MEDIA_PLAYER2_INITIALIZED = 1 << 1,
- MEDIA_PLAYER2_PREPARING = 1 << 2,
- MEDIA_PLAYER2_PREPARED = 1 << 3,
- MEDIA_PLAYER2_STARTED = 1 << 4,
- MEDIA_PLAYER2_PAUSED = 1 << 5,
- MEDIA_PLAYER2_PLAYBACK_COMPLETE = 1 << 6
-};
-
-// Keep KEY_PARAMETER_* in sync with MediaPlayer2.java.
-// The same enum space is used for both set and get, in case there are future keys that
-// can be both set and get. But as of now, all parameters are either set only or get only.
-enum media2_parameter_keys {
- // Streaming/buffering parameters
- MEDIA2_KEY_PARAMETER_CACHE_STAT_COLLECT_FREQ_MS = 1100, // set only
-
- // Return a Parcel containing a single int, which is the channel count of the
- // audio track, or zero for error (e.g. no audio track) or unknown.
- MEDIA2_KEY_PARAMETER_AUDIO_CHANNEL_COUNT = 1200, // get only
-
- // Playback rate expressed in permille (1000 is normal speed), saved as int32_t, with negative
- // values used for rewinding or reverse playback.
- MEDIA2_KEY_PARAMETER_PLAYBACK_RATE_PERMILLE = 1300, // set only
-
- // Set a Parcel containing the value of a parcelled Java AudioAttribute instance
- MEDIA2_KEY_PARAMETER_AUDIO_ATTRIBUTES = 1400 // set only
-};
-
-// Keep INVOKE_ID_* in sync with MediaPlayer2.java.
-enum media_player2_invoke_ids {
- MEDIA_PLAYER2_INVOKE_ID_GET_TRACK_INFO = 1,
- MEDIA_PLAYER2_INVOKE_ID_ADD_EXTERNAL_SOURCE = 2,
- MEDIA_PLAYER2_INVOKE_ID_ADD_EXTERNAL_SOURCE_FD = 3,
- MEDIA_PLAYER2_INVOKE_ID_SELECT_TRACK = 4,
- MEDIA_PLAYER2_INVOKE_ID_UNSELECT_TRACK = 5,
- MEDIA_PLAYER2_INVOKE_ID_SET_VIDEO_SCALING_MODE = 6,
- MEDIA_PLAYER2_INVOKE_ID_GET_SELECTED_TRACK = 7
-};
-
-}; // namespace android
-
-#endif // ANDROID_MEDIAPLAYER2_TYPES_H
diff --git a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
deleted file mode 100644
index 1e8a1d5..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_MEDIAPLAYER2_H
-#define ANDROID_MEDIAPLAYER2_H
-
-#include <media/AVSyncSettings.h>
-#include <media/AudioResamplerPublic.h>
-#include <media/BufferingSettings.h>
-#include <media/mediaplayer_common.h>
-#include <mediaplayer2/MediaPlayer2Interface.h>
-#include <mediaplayer2/MediaPlayer2Types.h>
-#include <mediaplayer2/JObjectHolder.h>
-
-#include <jni.h>
-#include <utils/Errors.h>
-#include <utils/Mutex.h>
-#include <utils/RefBase.h>
-#include <utils/String16.h>
-#include <utils/Vector.h>
-#include <system/audio-base.h>
-
-#include "jni.h"
-
-namespace android {
-
-struct ANativeWindowWrapper;
-struct DataSourceDesc;
-class MediaPlayer2AudioOutput;
-
-// ref-counted object for callbacks
-class MediaPlayer2Listener: virtual public RefBase
-{
-public:
- virtual void notify(int64_t srcId, int msg, int ext1, int ext2,
- const PlayerMessage *obj = NULL) = 0;
-};
-
-class MediaPlayer2 : public MediaPlayer2InterfaceListener
-{
-public:
- ~MediaPlayer2();
-
- static sp<MediaPlayer2> Create(int32_t sessionId, jobject context);
- static status_t DumpAll(int fd, const Vector<String16>& args);
-
- void disconnect();
-
- status_t getSrcId(int64_t *srcId);
- status_t setDataSource(const sp<DataSourceDesc> &dsd);
- status_t prepareNextDataSource(const sp<DataSourceDesc> &dsd);
- status_t playNextDataSource(int64_t srcId);
- status_t setVideoSurfaceTexture(const sp<ANativeWindowWrapper>& nww);
- status_t setListener(const sp<MediaPlayer2Listener>& listener);
- status_t getBufferingSettings(BufferingSettings* buffering /* nonnull */);
- status_t setBufferingSettings(const BufferingSettings& buffering);
- status_t prepareAsync();
- status_t start();
- status_t pause();
- bool isPlaying();
- mediaplayer2_states getState();
- status_t setPlaybackSettings(const AudioPlaybackRate& rate);
- status_t getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */);
- status_t setSyncSettings(const AVSyncSettings& sync, float videoFpsHint);
- status_t getSyncSettings(
- AVSyncSettings* sync /* nonnull */,
- float* videoFps /* nonnull */);
- status_t getVideoWidth(int *w);
- status_t getVideoHeight(int *h);
- status_t seekTo(
- int64_t msec,
- MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC);
- status_t notifyAt(int64_t mediaTimeUs);
- status_t getCurrentPosition(int64_t *msec);
- status_t getDuration(int64_t srcId, int64_t *msec);
- status_t reset();
- status_t setAudioStreamType(audio_stream_type_t type);
- status_t getAudioStreamType(audio_stream_type_t *type);
- status_t setLooping(int loop);
- bool isLooping();
- status_t setVolume(float volume);
- void notify(int64_t srcId, int msg, int ext1, int ext2,
- const PlayerMessage *obj = NULL);
- status_t invoke(const PlayerMessage &request, PlayerMessage *reply);
- status_t setAudioSessionId(int32_t sessionId);
- int32_t getAudioSessionId();
- status_t setAuxEffectSendLevel(float level);
- status_t attachAuxEffect(int effectId);
- status_t setAudioAttributes(const jobject attributes);
- jobject getAudioAttributes();
- status_t getParameter(int key, Parcel* reply);
- status_t getMetrics(char **buffer, size_t *length);
-
- // Modular DRM
- status_t prepareDrm(int64_t srcId,
- const uint8_t uuid[16],
- const Vector<uint8_t>& drmSessionId);
- status_t releaseDrm(int64_t srcId);
- // AudioRouting
- status_t setPreferredDevice(jobject device);
- jobject getRoutedDevice();
- status_t addAudioDeviceCallback(jobject routingDelegate);
- status_t removeAudioDeviceCallback(jobject listener);
-
- status_t dump(int fd, const Vector<String16>& args);
-
-private:
- MediaPlayer2(int32_t sessionId, jobject context);
- bool init();
-
- // Disconnect from the currently connected ANativeWindow.
- void disconnectNativeWindow_l();
-
- status_t setAudioAttributes_l(const jobject attributes);
-
- void clear_l();
- status_t seekTo_l(int64_t msec, MediaPlayer2SeekMode mode);
- status_t prepareAsync_l();
- status_t getDuration_l(int64_t *msec);
- status_t reset_l();
- status_t checkState_l();
-
- pid_t mPid;
- uid_t mUid;
- sp<MediaPlayer2Interface> mPlayer;
- sp<MediaPlayer2AudioOutput> mAudioOutput;
- int64_t mSrcId;
- thread_id_t mLockThreadId;
- mutable Mutex mLock;
- Mutex mNotifyLock;
- sp<MediaPlayer2Listener> mListener;
- media_player2_internal_states mCurrentState;
- bool mTransitionToNext;
- int64_t mCurrentPosition;
- MediaPlayer2SeekMode mCurrentSeekMode;
- int64_t mSeekPosition;
- MediaPlayer2SeekMode mSeekMode;
- audio_stream_type_t mStreamType;
- bool mLoop;
- float mVolume;
- int mVideoWidth;
- int mVideoHeight;
- int32_t mAudioSessionId;
- sp<JObjectHolder> mAudioAttributes;
- sp<JObjectHolder> mContext;
- float mSendLevel;
- sp<ANativeWindowWrapper> mConnectedWindow;
-};
-
-}; // namespace android
-
-#endif // ANDROID_MEDIAPLAYER2_H
diff --git a/media/libmediaplayer2/mediaplayer2.cpp b/media/libmediaplayer2/mediaplayer2.cpp
deleted file mode 100644
index de65f8d..0000000
--- a/media/libmediaplayer2/mediaplayer2.cpp
+++ /dev/null
@@ -1,1261 +0,0 @@
-/*
-**
-** Copyright 2017, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MediaPlayer2Native"
-
-#include <android/binder_ibinder.h>
-#include <media/AudioSystem.h>
-#include <media/DataSourceDesc.h>
-#include <media/MemoryLeakTrackUtil.h>
-#include <media/NdkWrapper.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/ALooperRoster.h>
-#include <mediaplayer2/MediaPlayer2AudioOutput.h>
-#include <mediaplayer2/mediaplayer2.h>
-
-#include <utils/Log.h>
-#include <utils/SortedVector.h>
-#include <utils/String8.h>
-
-#include <system/audio.h>
-#include <system/window.h>
-
-#include <nuplayer2/NuPlayer2Driver.h>
-
-#include <dirent.h>
-#include <sys/stat.h>
-
-namespace android {
-
-extern ALooperRoster gLooperRoster;
-
-namespace {
-
-const int kDumpLockRetries = 50;
-const int kDumpLockSleepUs = 20000;
-
-class proxyListener : public MediaPlayer2InterfaceListener {
-public:
- proxyListener(const wp<MediaPlayer2> &player)
- : mPlayer(player) { }
-
- ~proxyListener() { };
-
- virtual void notify(int64_t srcId, int msg, int ext1, int ext2,
- const PlayerMessage *obj) override {
- sp<MediaPlayer2> player = mPlayer.promote();
- if (player != NULL) {
- player->notify(srcId, msg, ext1, ext2, obj);
- }
- }
-
-private:
- wp<MediaPlayer2> mPlayer;
-};
-
-Mutex sRecordLock;
-SortedVector<wp<MediaPlayer2> > *sPlayers;
-
-void ensureInit_l() {
- if (sPlayers == NULL) {
- sPlayers = new SortedVector<wp<MediaPlayer2> >();
- }
-}
-
-void addPlayer(const wp<MediaPlayer2>& player) {
- Mutex::Autolock lock(sRecordLock);
- ensureInit_l();
- sPlayers->add(player);
-}
-
-void removePlayer(const wp<MediaPlayer2>& player) {
- Mutex::Autolock lock(sRecordLock);
- ensureInit_l();
- sPlayers->remove(player);
-}
-
-/**
- * The only arguments this understands right now are -c, -von and -voff,
- * which are parsed by ALooperRoster::dump()
- */
-status_t dumpPlayers(int fd, const Vector<String16>& args) {
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
- SortedVector< sp<MediaPlayer2> > players; //to serialise the mutex unlock & client destruction.
-
- {
- Mutex::Autolock lock(sRecordLock);
- ensureInit_l();
- for (int i = 0, n = sPlayers->size(); i < n; ++i) {
- sp<MediaPlayer2> p = (*sPlayers)[i].promote();
- if (p != 0) {
- p->dump(fd, args);
- }
- players.add(p);
- }
- }
-
- result.append(" Files opened and/or mapped:\n");
- snprintf(buffer, SIZE, "/proc/%d/maps", getpid());
- FILE *f = fopen(buffer, "r");
- if (f) {
- while (!feof(f)) {
- fgets(buffer, SIZE, f);
- if (strstr(buffer, " /storage/") ||
- strstr(buffer, " /system/sounds/") ||
- strstr(buffer, " /data/") ||
- strstr(buffer, " /system/media/")) {
- result.append(" ");
- result.append(buffer);
- }
- }
- fclose(f);
- } else {
- result.append("couldn't open ");
- result.append(buffer);
- result.append("\n");
- }
-
- snprintf(buffer, SIZE, "/proc/%d/fd", getpid());
- DIR *d = opendir(buffer);
- if (d) {
- struct dirent *ent;
- while((ent = readdir(d)) != NULL) {
- if (strcmp(ent->d_name,".") && strcmp(ent->d_name,"..")) {
- snprintf(buffer, SIZE, "/proc/%d/fd/%s", getpid(), ent->d_name);
- struct stat s;
- if (lstat(buffer, &s) == 0) {
- if ((s.st_mode & S_IFMT) == S_IFLNK) {
- char linkto[256];
- int len = readlink(buffer, linkto, sizeof(linkto));
- if(len > 0) {
- if(len > 255) {
- linkto[252] = '.';
- linkto[253] = '.';
- linkto[254] = '.';
- linkto[255] = 0;
- } else {
- linkto[len] = 0;
- }
- if (strstr(linkto, "/storage/") == linkto ||
- strstr(linkto, "/system/sounds/") == linkto ||
- strstr(linkto, "/data/") == linkto ||
- strstr(linkto, "/system/media/") == linkto) {
- result.append(" ");
- result.append(buffer);
- result.append(" -> ");
- result.append(linkto);
- result.append("\n");
- }
- }
- } else {
- result.append(" unexpected type for ");
- result.append(buffer);
- result.append("\n");
- }
- }
- }
- }
- closedir(d);
- } else {
- result.append("couldn't open ");
- result.append(buffer);
- result.append("\n");
- }
-
- gLooperRoster.dump(fd, args);
-
- bool dumpMem = false;
- bool unreachableMemory = false;
- for (size_t i = 0; i < args.size(); i++) {
- if (args[i] == String16("-m")) {
- dumpMem = true;
- } else if (args[i] == String16("--unreachable")) {
- unreachableMemory = true;
- }
- }
- if (dumpMem) {
- result.append("\nDumping memory:\n");
- std::string s = dumpMemoryAddresses(100 /* limit */);
- result.append(s.c_str(), s.size());
- }
- if (unreachableMemory) {
- result.append("\nDumping unreachable memory:\n");
- // TODO - should limit be an argument parameter?
- // TODO: enable GetUnreachableMemoryString if it's part of stable API
- //std::string s = GetUnreachableMemoryString(true /* contents */, 10000 /* limit */);
- //result.append(s.c_str(), s.size());
- }
-
- write(fd, result.string(), result.size());
- return NO_ERROR;
-}
-
-} // anonymous namespace
-
-//static
-sp<MediaPlayer2> MediaPlayer2::Create(int32_t sessionId, jobject context) {
- sp<MediaPlayer2> player = new MediaPlayer2(sessionId, context);
-
- if (!player->init()) {
- return NULL;
- }
-
- ALOGV("Create new player(%p)", player.get());
-
- addPlayer(player);
- return player;
-}
-
-// static
-status_t MediaPlayer2::DumpAll(int fd, const Vector<String16>& args) {
- return dumpPlayers(fd, args);
-}
-
-MediaPlayer2::MediaPlayer2(int32_t sessionId, jobject context) {
- ALOGV("constructor");
- mSrcId = 0;
- mLockThreadId = 0;
- mListener = NULL;
- mStreamType = AUDIO_STREAM_MUSIC;
- mAudioAttributes = NULL;
- mContext = new JObjectHolder(context);
- mCurrentPosition = -1;
- mCurrentSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
- mSeekPosition = -1;
- mSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
- mCurrentState = MEDIA_PLAYER2_IDLE;
- mTransitionToNext = false;
- mLoop = false;
- mVolume = 1.0;
- mVideoWidth = mVideoHeight = 0;
- mSendLevel = 0;
-
- mPid = AIBinder_getCallingPid();
- mUid = AIBinder_getCallingUid();
-
- mAudioOutput = new MediaPlayer2AudioOutput(sessionId, mUid, mPid, NULL /*attributes*/);
-}
-
-MediaPlayer2::~MediaPlayer2() {
- ALOGV("destructor");
- disconnect();
- removePlayer(this);
-}
-
-bool MediaPlayer2::init() {
- // TODO: after merge with NuPlayer2Driver, MediaPlayer2 will have its own
- // looper for notification.
- return true;
-}
-
-void MediaPlayer2::disconnect() {
- ALOGV("disconnect");
- sp<MediaPlayer2Interface> p;
- {
- Mutex::Autolock _l(mLock);
- p = mPlayer;
- mPlayer.clear();
- }
-
- if (p != 0) {
- p->setListener(NULL);
- p->reset();
- }
-
- {
- Mutex::Autolock _l(mLock);
- disconnectNativeWindow_l();
- }
-}
-
-void MediaPlayer2::clear_l() {
- mCurrentPosition = -1;
- mCurrentSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
- mSeekPosition = -1;
- mSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
- mVideoWidth = mVideoHeight = 0;
-}
-
-status_t MediaPlayer2::setListener(const sp<MediaPlayer2Listener>& listener) {
- ALOGV("setListener");
- Mutex::Autolock _l(mLock);
- mListener = listener;
- return NO_ERROR;
-}
-
-status_t MediaPlayer2::getSrcId(int64_t *srcId) {
- if (srcId == NULL) {
- return BAD_VALUE;
- }
-
- Mutex::Autolock _l(mLock);
- *srcId = mSrcId;
- return OK;
-}
-
-status_t MediaPlayer2::setDataSource(const sp<DataSourceDesc> &dsd) {
- if (dsd == NULL) {
- return BAD_VALUE;
- }
- // Microsecond is used in NuPlayer2.
- if (dsd->mStartPositionMs > DataSourceDesc::kMaxTimeMs) {
- dsd->mStartPositionMs = DataSourceDesc::kMaxTimeMs;
- ALOGW("setDataSource, start poistion clamped to %lld ms", (long long)dsd->mStartPositionMs);
- }
- if (dsd->mEndPositionMs > DataSourceDesc::kMaxTimeMs) {
- dsd->mEndPositionMs = DataSourceDesc::kMaxTimeMs;
- ALOGW("setDataSource, end poistion clamped to %lld ms", (long long)dsd->mStartPositionMs);
- }
- ALOGV("setDataSource type(%d), srcId(%lld)", dsd->mType, (long long)dsd->mId);
-
- sp<MediaPlayer2Interface> oldPlayer;
-
- {
- Mutex::Autolock _l(mLock);
- if (!((mCurrentState & MEDIA_PLAYER2_IDLE)
- || mCurrentState == MEDIA_PLAYER2_STATE_ERROR)) {
- ALOGE("setDataSource called in wrong state %d", mCurrentState);
- return INVALID_OPERATION;
- }
-
- sp<MediaPlayer2Interface> player = new NuPlayer2Driver(mPid, mUid, mContext);
- status_t err = player->initCheck();
- if (err != NO_ERROR) {
- ALOGE("Failed to create player object, initCheck failed(%d)", err);
- return err;
- }
-
- clear_l();
-
- player->setListener(new proxyListener(this));
- player->setAudioSink(mAudioOutput);
-
- err = player->setDataSource(dsd);
- if (err != OK) {
- ALOGE("setDataSource error: %d", err);
- return err;
- }
-
- sp<MediaPlayer2Interface> oldPlayer = mPlayer;
- mPlayer = player;
- mSrcId = dsd->mId;
- mCurrentState = MEDIA_PLAYER2_INITIALIZED;
- }
-
- if (oldPlayer != NULL) {
- oldPlayer->setListener(NULL);
- oldPlayer->reset();
- }
-
- return OK;
-}
-
-status_t MediaPlayer2::prepareNextDataSource(const sp<DataSourceDesc> &dsd) {
- if (dsd == NULL) {
- return BAD_VALUE;
- }
- ALOGV("prepareNextDataSource type(%d), srcId(%lld)", dsd->mType, (long long)dsd->mId);
-
- Mutex::Autolock _l(mLock);
- if (mPlayer == NULL) {
- ALOGE("prepareNextDataSource failed: state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
- return INVALID_OPERATION;
- }
- return mPlayer->prepareNextDataSource(dsd);
-}
-
-status_t MediaPlayer2::playNextDataSource(int64_t srcId) {
- ALOGV("playNextDataSource srcId(%lld)", (long long)srcId);
-
- Mutex::Autolock _l(mLock);
- if (mPlayer == NULL) {
- ALOGE("playNextDataSource failed: state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
- return INVALID_OPERATION;
- }
- mSrcId = srcId;
- mTransitionToNext = true;
- return mPlayer->playNextDataSource(srcId);
-}
-
-status_t MediaPlayer2::invoke(const PlayerMessage &request, PlayerMessage *reply) {
- Mutex::Autolock _l(mLock);
- const bool hasBeenInitialized =
- (mCurrentState != MEDIA_PLAYER2_STATE_ERROR) &&
- ((mCurrentState & MEDIA_PLAYER2_IDLE) != MEDIA_PLAYER2_IDLE);
- if ((mPlayer == NULL) || !hasBeenInitialized) {
- ALOGE("invoke() failed: wrong state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
- return INVALID_OPERATION;
- }
- return mPlayer->invoke(request, reply);
-}
-
-void MediaPlayer2::disconnectNativeWindow_l() {
- if (mConnectedWindow != NULL && mConnectedWindow->getANativeWindow() != NULL) {
- status_t err = native_window_api_disconnect(
- mConnectedWindow->getANativeWindow(), NATIVE_WINDOW_API_MEDIA);
-
- if (err != OK) {
- ALOGW("nativeWindowDisconnect returned an error: %s (%d)",
- strerror(-err), err);
- }
- }
- mConnectedWindow.clear();
-}
-
-status_t MediaPlayer2::setVideoSurfaceTexture(const sp<ANativeWindowWrapper>& nww) {
- ANativeWindow *anw = (nww == NULL ? NULL : nww->getANativeWindow());
- ALOGV("setVideoSurfaceTexture(%p)", anw);
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return NO_INIT;
- }
-
- if (anw != NULL) {
- if (mConnectedWindow != NULL
- && mConnectedWindow->getANativeWindow() == anw) {
- return OK;
- }
- status_t err = native_window_api_connect(anw, NATIVE_WINDOW_API_MEDIA);
-
- if (err != OK) {
- ALOGE("setVideoSurfaceTexture failed: %d", err);
- // Note that we must do the reset before disconnecting from the ANW.
- // Otherwise queue/dequeue calls could be made on the disconnected
- // ANW, which may result in errors.
- mPlayer->reset();
- disconnectNativeWindow_l();
- return err;
- }
- }
-
- // Note that we must set the player's new GraphicBufferProducer before
- // disconnecting the old one. Otherwise queue/dequeue calls could be made
- // on the disconnected ANW, which may result in errors.
- status_t err = mPlayer->setVideoSurfaceTexture(nww);
-
- disconnectNativeWindow_l();
-
- if (err == OK) {
- mConnectedWindow = nww;
- mLock.unlock();
- } else if (anw != NULL) {
- mLock.unlock();
- status_t err = native_window_api_disconnect(anw, NATIVE_WINDOW_API_MEDIA);
-
- if (err != OK) {
- ALOGW("nativeWindowDisconnect returned an error: %s (%d)",
- strerror(-err), err);
- }
- }
-
- return err;
-}
-
-status_t MediaPlayer2::getBufferingSettings(BufferingSettings* buffering /* nonnull */) {
- ALOGV("getBufferingSettings");
-
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return NO_INIT;
- }
-
- status_t ret = mPlayer->getBufferingSettings(buffering);
- if (ret == NO_ERROR) {
- ALOGV("getBufferingSettings{%s}", buffering->toString().string());
- } else {
- ALOGE("getBufferingSettings returned %d", ret);
- }
- return ret;
-}
-
-status_t MediaPlayer2::setBufferingSettings(const BufferingSettings& buffering) {
- ALOGV("setBufferingSettings{%s}", buffering.toString().string());
-
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return NO_INIT;
- }
- return mPlayer->setBufferingSettings(buffering);
-}
-
-status_t MediaPlayer2::setAudioAttributes_l(const jobject attributes) {
- if (mAudioOutput != NULL) {
- mAudioOutput->setAudioAttributes(attributes);
- }
- return NO_ERROR;
-}
-
-status_t MediaPlayer2::prepareAsync() {
- ALOGV("prepareAsync");
- Mutex::Autolock _l(mLock);
- if ((mPlayer != 0) && (mCurrentState & MEDIA_PLAYER2_INITIALIZED)) {
- if (mAudioAttributes != NULL) {
- status_t err = setAudioAttributes_l(mAudioAttributes->getJObject());
- if (err != OK) {
- return err;
- }
- }
- mCurrentState = MEDIA_PLAYER2_PREPARING;
- return mPlayer->prepareAsync();
- }
- ALOGE("prepareAsync called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());
- return INVALID_OPERATION;
-}
-
-status_t MediaPlayer2::start() {
- ALOGV("start");
-
- status_t ret = NO_ERROR;
- Mutex::Autolock _l(mLock);
-
- mLockThreadId = getThreadId();
-
- if (mCurrentState & MEDIA_PLAYER2_STARTED) {
- ret = NO_ERROR;
- } else if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER2_PREPARED |
- MEDIA_PLAYER2_PLAYBACK_COMPLETE | MEDIA_PLAYER2_PAUSED ) ) ) {
- mPlayer->setLooping(mLoop);
-
- if (mAudioOutput != 0) {
- mAudioOutput->setVolume(mVolume);
- }
-
- if (mAudioOutput != 0) {
- mAudioOutput->setAuxEffectSendLevel(mSendLevel);
- }
- mCurrentState = MEDIA_PLAYER2_STARTED;
- ret = mPlayer->start();
- if (ret != NO_ERROR) {
- mCurrentState = MEDIA_PLAYER2_STATE_ERROR;
- } else {
- if (mCurrentState == MEDIA_PLAYER2_PLAYBACK_COMPLETE) {
- ALOGV("playback completed immediately following start()");
- }
- }
- } else {
- ALOGE("start called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());
- ret = INVALID_OPERATION;
- }
-
- mLockThreadId = 0;
-
- return ret;
-}
-
-status_t MediaPlayer2::pause() {
- ALOGV("pause");
- Mutex::Autolock _l(mLock);
- if (mCurrentState & (MEDIA_PLAYER2_PAUSED|MEDIA_PLAYER2_PLAYBACK_COMPLETE))
- return NO_ERROR;
- if ((mPlayer != 0) && (mCurrentState & (MEDIA_PLAYER2_STARTED | MEDIA_PLAYER2_PREPARED))) {
- status_t ret = mPlayer->pause();
- if (ret != NO_ERROR) {
- mCurrentState = MEDIA_PLAYER2_STATE_ERROR;
- } else {
- mCurrentState = MEDIA_PLAYER2_PAUSED;
- mTransitionToNext = false;
- }
- return ret;
- }
- ALOGE("pause called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());
- return INVALID_OPERATION;
-}
-
-bool MediaPlayer2::isPlaying() {
- Mutex::Autolock _l(mLock);
- if (mPlayer != 0) {
- bool temp = mPlayer->isPlaying();
- ALOGV("isPlaying: %d", temp);
- if ((mCurrentState & MEDIA_PLAYER2_STARTED) && ! temp) {
- ALOGE("internal/external state mismatch corrected");
- mCurrentState = MEDIA_PLAYER2_PAUSED;
- } else if ((mCurrentState & MEDIA_PLAYER2_PAUSED) && temp) {
- ALOGE("internal/external state mismatch corrected");
- mCurrentState = MEDIA_PLAYER2_STARTED;
- }
- return temp;
- }
- ALOGV("isPlaying: no active player");
- return false;
-}
-
-mediaplayer2_states MediaPlayer2::getState() {
- Mutex::Autolock _l(mLock);
- if (mCurrentState & MEDIA_PLAYER2_STATE_ERROR) {
- return MEDIAPLAYER2_STATE_ERROR;
- }
- if (mPlayer == 0
- || (mCurrentState &
- (MEDIA_PLAYER2_IDLE | MEDIA_PLAYER2_INITIALIZED | MEDIA_PLAYER2_PREPARING))) {
- return MEDIAPLAYER2_STATE_IDLE;
- }
- if (mCurrentState & MEDIA_PLAYER2_STARTED) {
- return MEDIAPLAYER2_STATE_PLAYING;
- }
- if (mCurrentState & (MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_PLAYBACK_COMPLETE)) {
- return MEDIAPLAYER2_STATE_PAUSED;
- }
- // now only mCurrentState & MEDIA_PLAYER2_PREPARED is true
- return MEDIAPLAYER2_STATE_PREPARED;
-}
-
-status_t MediaPlayer2::setPlaybackSettings(const AudioPlaybackRate& rate) {
- ALOGV("setPlaybackSettings: %f %f %d %d",
- rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode);
- // Negative speed and pitch does not make sense. Further validation will
- // be done by the respective mediaplayers.
- if (rate.mSpeed <= 0.f || rate.mPitch < 0.f) {
- return BAD_VALUE;
- }
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return INVALID_OPERATION;
- }
-
- status_t err = mPlayer->setPlaybackSettings(rate);
- return err;
-}
-
-status_t MediaPlayer2::getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */) {
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return INVALID_OPERATION;
- }
- status_t ret = mPlayer->getPlaybackSettings(rate);
- if (ret == NO_ERROR) {
- ALOGV("getPlaybackSettings(%f, %f, %d, %d)",
- rate->mSpeed, rate->mPitch, rate->mFallbackMode, rate->mStretchMode);
- } else {
- ALOGV("getPlaybackSettings returned %d", ret);
- }
- return ret;
-}
-
-status_t MediaPlayer2::setSyncSettings(const AVSyncSettings& sync, float videoFpsHint) {
- ALOGV("setSyncSettings: %u %u %f %f",
- sync.mSource, sync.mAudioAdjustMode, sync.mTolerance, videoFpsHint);
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) return INVALID_OPERATION;
- return mPlayer->setSyncSettings(sync, videoFpsHint);
-}
-
-status_t MediaPlayer2::getSyncSettings(
- AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */) {
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return INVALID_OPERATION;
- }
- status_t ret = mPlayer->getSyncSettings(sync, videoFps);
- if (ret == NO_ERROR) {
- ALOGV("getSyncSettings(%u, %u, %f, %f)",
- sync->mSource, sync->mAudioAdjustMode, sync->mTolerance, *videoFps);
- } else {
- ALOGV("getSyncSettings returned %d", ret);
- }
- return ret;
-
-}
-
-status_t MediaPlayer2::getVideoWidth(int *w) {
- ALOGV("getVideoWidth");
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return INVALID_OPERATION;
- }
- *w = mVideoWidth;
- return NO_ERROR;
-}
-
-status_t MediaPlayer2::getVideoHeight(int *h) {
- ALOGV("getVideoHeight");
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return INVALID_OPERATION;
- }
- *h = mVideoHeight;
- return NO_ERROR;
-}
-
-status_t MediaPlayer2::getCurrentPosition(int64_t *msec) {
- ALOGV("getCurrentPosition");
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return INVALID_OPERATION;
- }
- if (mCurrentPosition >= 0) {
- ALOGV("Using cached seek position: %lld", (long long)mCurrentPosition);
- *msec = mCurrentPosition;
- return NO_ERROR;
- }
- status_t ret = mPlayer->getCurrentPosition(msec);
- if (ret == NO_ERROR) {
- ALOGV("getCurrentPosition = %lld", (long long)*msec);
- } else {
- ALOGE("getCurrentPosition returned %d", ret);
- }
- return ret;
-}
-
-status_t MediaPlayer2::getDuration(int64_t srcId, int64_t *msec) {
- Mutex::Autolock _l(mLock);
- // TODO: cache duration for currentSrcId and nextSrcId, and return correct
- // value for nextSrcId.
- if (srcId != mSrcId) {
- *msec = -1;
- return OK;
- }
-
- ALOGV("getDuration_l");
- bool isValidState = (mCurrentState & (MEDIA_PLAYER2_PREPARED | MEDIA_PLAYER2_STARTED |
- MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_PLAYBACK_COMPLETE));
- if (mPlayer == 0 || !isValidState) {
- ALOGE("Attempt to call getDuration in wrong state: mPlayer=%p, mCurrentState=%u",
- mPlayer.get(), mCurrentState);
- return INVALID_OPERATION;
- }
- int64_t durationMs;
- status_t ret = mPlayer->getDuration(&durationMs);
-
- if (ret == NO_ERROR) {
- ALOGV("getDuration = %lld", (long long)durationMs);
- } else {
- ALOGE("getDuration returned %d", ret);
- // Do not enter error state just because no duration was available.
- durationMs = -1;
- }
-
- if (msec) {
- *msec = durationMs;
- }
- return OK;
-}
-
-status_t MediaPlayer2::seekTo_l(int64_t msec, MediaPlayer2SeekMode mode) {
- ALOGV("seekTo (%lld, %d)", (long long)msec, mode);
- if ((mPlayer == 0) || !(mCurrentState & (MEDIA_PLAYER2_STARTED | MEDIA_PLAYER2_PREPARED |
- MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_PLAYBACK_COMPLETE))) {
- ALOGE("Attempt to perform seekTo in wrong state: mPlayer=%p, mCurrentState=%u",
- mPlayer.get(), mCurrentState);
- return INVALID_OPERATION;
- }
- if (msec < 0) {
- ALOGW("Attempt to seek to invalid position: %lld", (long long)msec);
- msec = 0;
- }
-
- int64_t durationMs;
- status_t err = mPlayer->getDuration(&durationMs);
-
- if (err != OK) {
- ALOGW("Stream has no duration and is therefore not seekable.");
- return err;
- }
-
- if (msec > durationMs) {
- ALOGW("Attempt to seek to past end of file: request = %lld, durationMs = %lld",
- (long long)msec, (long long)durationMs);
-
- msec = durationMs;
- }
-
- // cache duration
- mCurrentPosition = msec;
- mCurrentSeekMode = mode;
- if (mSeekPosition < 0) {
- mSeekPosition = msec;
- mSeekMode = mode;
- return mPlayer->seekTo(msec, mode);
- }
- ALOGV("Seek in progress - queue up seekTo[%lld, %d]", (long long)msec, mode);
- return NO_ERROR;
-}
-
-status_t MediaPlayer2::seekTo(int64_t msec, MediaPlayer2SeekMode mode) {
- mLockThreadId = getThreadId();
- Mutex::Autolock _l(mLock);
- status_t result = seekTo_l(msec, mode);
- mLockThreadId = 0;
-
- return result;
-}
-
-status_t MediaPlayer2::notifyAt(int64_t mediaTimeUs) {
- Mutex::Autolock _l(mLock);
- if (mPlayer != 0) {
- return INVALID_OPERATION;
- }
-
- return mPlayer->notifyAt(mediaTimeUs);
-}
-
-status_t MediaPlayer2::reset_l() {
- mLoop = false;
- if (mCurrentState == MEDIA_PLAYER2_IDLE) {
- return NO_ERROR;
- }
- if (mPlayer != 0) {
- status_t ret = mPlayer->reset();
- if (ret != NO_ERROR) {
- ALOGE("reset() failed with return code (%d)", ret);
- mCurrentState = MEDIA_PLAYER2_STATE_ERROR;
- } else {
- mPlayer->setListener(NULL);
- mCurrentState = MEDIA_PLAYER2_IDLE;
- mTransitionToNext = false;
- }
- // setDataSource has to be called again to create a
- // new mediaplayer.
- mPlayer = 0;
- return ret;
- }
- clear_l();
- return NO_ERROR;
-}
-
-status_t MediaPlayer2::reset() {
- ALOGV("reset");
- mLockThreadId = getThreadId();
- Mutex::Autolock _l(mLock);
- status_t result = reset_l();
- mLockThreadId = 0;
-
- return result;
-}
-
-status_t MediaPlayer2::setAudioStreamType(audio_stream_type_t type) {
- ALOGV("MediaPlayer2::setAudioStreamType");
- Mutex::Autolock _l(mLock);
- if (mStreamType == type) return NO_ERROR;
- if (mCurrentState & ( MEDIA_PLAYER2_PREPARED | MEDIA_PLAYER2_STARTED |
- MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_PLAYBACK_COMPLETE ) ) {
- // Can't change the stream type after prepare
- ALOGE("setAudioStream called in state %d", mCurrentState);
- return INVALID_OPERATION;
- }
- // cache
- mStreamType = type;
- return OK;
-}
-
-status_t MediaPlayer2::getAudioStreamType(audio_stream_type_t *type) {
- ALOGV("getAudioStreamType");
- Mutex::Autolock _l(mLock);
- *type = mStreamType;
- return OK;
-}
-
-status_t MediaPlayer2::setLooping(int loop) {
- ALOGV("MediaPlayer2::setLooping");
- Mutex::Autolock _l(mLock);
- mLoop = (loop != 0);
- if (mPlayer != 0) {
- return mPlayer->setLooping(loop);
- }
- return OK;
-}
-
-bool MediaPlayer2::isLooping() {
- ALOGV("isLooping");
- Mutex::Autolock _l(mLock);
- if (mPlayer != 0) {
- return mLoop;
- }
- ALOGV("isLooping: no active player");
- return false;
-}
-
-status_t MediaPlayer2::setVolume(float volume) {
- ALOGV("MediaPlayer2::setVolume(%f)", volume);
- Mutex::Autolock _l(mLock);
- mVolume = volume;
- if (mAudioOutput != 0) {
- mAudioOutput->setVolume(volume);
- }
- return OK;
-}
-
-status_t MediaPlayer2::setAudioSessionId(int32_t sessionId) {
- ALOGV("MediaPlayer2::setAudioSessionId(%d)", sessionId);
- Mutex::Autolock _l(mLock);
- if (!(mCurrentState & MEDIA_PLAYER2_IDLE)) {
- ALOGE("setAudioSessionId called in state %d", mCurrentState);
- return INVALID_OPERATION;
- }
- if (sessionId < 0) {
- return BAD_VALUE;
- }
- if (mAudioOutput != NULL && sessionId != mAudioOutput->getSessionId()) {
- mAudioOutput->setSessionId(sessionId);
- }
- return NO_ERROR;
-}
-
-int32_t MediaPlayer2::getAudioSessionId() {
- Mutex::Autolock _l(mLock);
- if (mAudioOutput != NULL) {
- return mAudioOutput->getSessionId();
- }
- return 0;
-}
-
-status_t MediaPlayer2::setAuxEffectSendLevel(float level) {
- ALOGV("MediaPlayer2::setAuxEffectSendLevel(%f)", level);
- Mutex::Autolock _l(mLock);
- mSendLevel = level;
- if (mAudioOutput != 0) {
- return mAudioOutput->setAuxEffectSendLevel(level);
- }
- return OK;
-}
-
-status_t MediaPlayer2::attachAuxEffect(int effectId) {
- ALOGV("MediaPlayer2::attachAuxEffect(%d)", effectId);
- Mutex::Autolock _l(mLock);
- if (mAudioOutput == 0 ||
- (mCurrentState & MEDIA_PLAYER2_IDLE) ||
- (mCurrentState == MEDIA_PLAYER2_STATE_ERROR )) {
- ALOGE("attachAuxEffect called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());
- return INVALID_OPERATION;
- }
-
- return mAudioOutput->attachAuxEffect(effectId);
-}
-
-// always call with lock held
-status_t MediaPlayer2::checkState_l() {
- if (mCurrentState & ( MEDIA_PLAYER2_PREPARED | MEDIA_PLAYER2_STARTED |
- MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_PLAYBACK_COMPLETE) ) {
- // Can't change the audio attributes after prepare
- ALOGE("trying to set audio attributes called in state %d", mCurrentState);
- return INVALID_OPERATION;
- }
- return OK;
-}
-
-status_t MediaPlayer2::setAudioAttributes(const jobject attributes) {
- ALOGV("MediaPlayer2::setAudioAttributes");
- status_t status = INVALID_OPERATION;
- Mutex::Autolock _l(mLock);
- if (checkState_l() != OK) {
- return status;
- }
- mAudioAttributes = new JObjectHolder(attributes);
- status = setAudioAttributes_l(attributes);
- return status;
-}
-
-jobject MediaPlayer2::getAudioAttributes() {
- ALOGV("MediaPlayer2::getAudioAttributes)");
- Mutex::Autolock _l(mLock);
- return mAudioAttributes != NULL ? mAudioAttributes->getJObject() : NULL;
-}
-
-status_t MediaPlayer2::getParameter(int key, Parcel *reply) {
- ALOGV("MediaPlayer2::getParameter(%d)", key);
- Mutex::Autolock _l(mLock);
- if (mPlayer == NULL) {
- ALOGV("getParameter: no active player");
- return INVALID_OPERATION;
- }
-
- status_t status = mPlayer->getParameter(key, reply);
- if (status != OK) {
- ALOGD("getParameter returns %d", status);
- }
- return status;
-}
-
-// for mediametrics
-status_t MediaPlayer2::getMetrics(char **buffer, size_t *length) {
- ALOGD("MediaPlayer2::getMetrics()");
- Mutex::Autolock _l(mLock);
- if (mPlayer == NULL) {
- ALOGV("getMetrics: no active player");
- return INVALID_OPERATION;
- }
-
- status_t status = mPlayer->getMetrics(buffer, length);
- if (status != OK) {
- ALOGD("getMetrics returns %d", status);
- }
- return status;
-}
-
-void MediaPlayer2::notify(int64_t srcId, int msg, int ext1, int ext2, const PlayerMessage *obj) {
- ALOGV("message received srcId=%lld, msg=%d, ext1=%d, ext2=%d",
- (long long)srcId, msg, ext1, ext2);
-
- bool send = true;
- bool locked = false;
-
- // TODO: In the future, we might be on the same thread if the app is
- // running in the same process as the media server. In that case,
- // this will deadlock.
- //
- // The threadId hack below works around this for the care of prepare,
- // seekTo, start, and reset within the same process.
- // FIXME: Remember, this is a hack, it's not even a hack that is applied
- // consistently for all use-cases, this needs to be revisited.
- if (mLockThreadId != getThreadId()) {
- mLock.lock();
- locked = true;
- }
-
- // Allows calls from JNI in idle state to notify errors
- if (!(msg == MEDIA2_ERROR && mCurrentState == MEDIA_PLAYER2_IDLE) && mPlayer == 0) {
- ALOGV("notify(%lld, %d, %d, %d) callback on disconnected mediaplayer",
- (long long)srcId, msg, ext1, ext2);
- if (locked) mLock.unlock(); // release the lock when done.
- return;
- }
-
- switch (msg) {
- case MEDIA2_NOP: // interface test message
- break;
- case MEDIA2_PREPARED:
- ALOGV("MediaPlayer2::notify() prepared, srcId=%lld", (long long)srcId);
- if (srcId == mSrcId) {
- mCurrentState = MEDIA_PLAYER2_PREPARED;
- }
- break;
- case MEDIA2_DRM_INFO:
- ALOGV("MediaPlayer2::notify() MEDIA2_DRM_INFO(%lld, %d, %d, %d, %p)",
- (long long)srcId, msg, ext1, ext2, obj);
- break;
- case MEDIA2_PLAYBACK_COMPLETE:
- ALOGV("playback complete");
- if (mCurrentState == MEDIA_PLAYER2_IDLE) {
- ALOGE("playback complete in idle state");
- }
- if (!mLoop && srcId == mSrcId) {
- mCurrentState = MEDIA_PLAYER2_PLAYBACK_COMPLETE;
- }
- break;
- case MEDIA2_ERROR:
- // Always log errors.
- // ext1: Media framework error code.
- // ext2: Implementation dependant error code.
- ALOGE("error (%d, %d)", ext1, ext2);
- mCurrentState = MEDIA_PLAYER2_STATE_ERROR;
- break;
- case MEDIA2_INFO:
- // ext1: Media framework error code.
- // ext2: Implementation dependant error code.
- if (ext1 != MEDIA2_INFO_VIDEO_TRACK_LAGGING) {
- ALOGW("info/warning (%d, %d)", ext1, ext2);
-
- if (ext1 == MEDIA2_INFO_DATA_SOURCE_START && srcId == mSrcId && mTransitionToNext) {
- mCurrentState = MEDIA_PLAYER2_STARTED;
- mTransitionToNext = false;
- }
- }
- break;
- case MEDIA2_SEEK_COMPLETE:
- ALOGV("Received seek complete");
- if (mSeekPosition != mCurrentPosition || (mSeekMode != mCurrentSeekMode)) {
- ALOGV("Executing queued seekTo(%lld, %d)",
- (long long)mCurrentPosition, mCurrentSeekMode);
- mSeekPosition = -1;
- mSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
- seekTo_l(mCurrentPosition, mCurrentSeekMode);
- }
- else {
- ALOGV("All seeks complete - return to regularly scheduled program");
- mCurrentPosition = mSeekPosition = -1;
- mCurrentSeekMode = mSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
- }
- break;
- case MEDIA2_BUFFERING_UPDATE:
- ALOGV("buffering %d", ext1);
- break;
- case MEDIA2_SET_VIDEO_SIZE:
- ALOGV("New video size %d x %d", ext1, ext2);
- mVideoWidth = ext1;
- mVideoHeight = ext2;
- break;
- case MEDIA2_NOTIFY_TIME:
- ALOGV("Received notify time message");
- break;
- case MEDIA2_TIMED_TEXT:
- ALOGV("Received timed text message");
- break;
- case MEDIA2_SUBTITLE_DATA:
- ALOGV("Received subtitle data message");
- break;
- case MEDIA2_META_DATA:
- ALOGV("Received timed metadata message");
- break;
- default:
- ALOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
- break;
- }
-
- sp<MediaPlayer2Listener> listener = mListener;
- if (locked) mLock.unlock();
-
- // this prevents re-entrant calls into client code
- if ((listener != 0) && send) {
- Mutex::Autolock _l(mNotifyLock);
- ALOGV("callback application");
- listener->notify(srcId, msg, ext1, ext2, obj);
- ALOGV("back from callback");
- }
-}
-
-// Modular DRM
-status_t MediaPlayer2::prepareDrm(
- int64_t srcId, const uint8_t uuid[16], const Vector<uint8_t>& drmSessionId) {
- // TODO change to ALOGV
- ALOGD("prepareDrm: uuid: %p drmSessionId: %p(%zu)", uuid,
- drmSessionId.array(), drmSessionId.size());
- Mutex::Autolock _l(mLock);
- if (mPlayer == NULL) {
- return NO_INIT;
- }
-
- // Only allowed it in player's preparing/prepared state.
- // We get here only if MEDIA_DRM_INFO has already arrived (e.g., prepare is half-way through or
- // completed) so the state change to "prepared" might not have happened yet (e.g., buffering).
- // Still, we can allow prepareDrm for the use case of being called in OnDrmInfoListener.
- if (!(mCurrentState & (MEDIA_PLAYER2_PREPARING | MEDIA_PLAYER2_PREPARED))) {
- ALOGW("prepareDrm(%lld) called in non-prepare state(%d)", (long long)srcId, mCurrentState);
- if (srcId == mSrcId) {
- return INVALID_OPERATION;
- }
- }
-
- if (drmSessionId.isEmpty()) {
- ALOGE("prepareDrm: Unexpected. Can't proceed with crypto. Empty drmSessionId.");
- return INVALID_OPERATION;
- }
-
- // Passing down to mediaserver mainly for creating the crypto
- status_t status = mPlayer->prepareDrm(srcId, uuid, drmSessionId);
- ALOGE_IF(status != OK, "prepareDrm: Failed at mediaserver with ret: %d", status);
-
- // TODO change to ALOGV
- ALOGD("prepareDrm: mediaserver::prepareDrm ret=%d", status);
-
- return status;
-}
-
-status_t MediaPlayer2::releaseDrm(int64_t srcId) {
- Mutex::Autolock _l(mLock);
- if (mPlayer == NULL) {
- return NO_INIT;
- }
-
- // Not allowing releaseDrm in an active/resumable state
- if (mCurrentState & (MEDIA_PLAYER2_STARTED |
- MEDIA_PLAYER2_PAUSED |
- MEDIA_PLAYER2_PLAYBACK_COMPLETE |
- MEDIA_PLAYER2_STATE_ERROR)) {
- ALOGE("releaseDrm Unexpected state %d. Can only be called in stopped/idle.", mCurrentState);
- return INVALID_OPERATION;
- }
-
- status_t status = mPlayer->releaseDrm(srcId);
- // TODO change to ALOGV
- ALOGD("releaseDrm: mediaserver::releaseDrm ret: %d", status);
- if (status != OK) {
- ALOGE("releaseDrm: Failed at mediaserver with ret: %d", status);
- // Overriding to OK so the client proceed with its own cleanup
- // Client can't do more cleanup. mediaserver release its crypto at end of session anyway.
- status = OK;
- }
-
- return status;
-}
-
-status_t MediaPlayer2::setPreferredDevice(jobject device) {
- Mutex::Autolock _l(mLock);
- if (mAudioOutput == NULL) {
- ALOGV("setPreferredDevice: audio sink not init");
- return NO_INIT;
- }
- return mAudioOutput->setPreferredDevice(device);
-}
-
-jobject MediaPlayer2::getRoutedDevice() {
- Mutex::Autolock _l(mLock);
- if (mAudioOutput == NULL) {
- ALOGV("getRoutedDevice: audio sink not init");
- return nullptr;
- }
- return mAudioOutput->getRoutedDevice();
-}
-
-status_t MediaPlayer2::addAudioDeviceCallback(jobject routingDelegate) {
- Mutex::Autolock _l(mLock);
- if (mAudioOutput == NULL) {
- ALOGV("addAudioDeviceCallback: player not init");
- return NO_INIT;
- }
- return mAudioOutput->addAudioDeviceCallback(routingDelegate);
-}
-
-status_t MediaPlayer2::removeAudioDeviceCallback(jobject listener) {
- Mutex::Autolock _l(mLock);
- if (mAudioOutput == NULL) {
- ALOGV("addAudioDeviceCallback: player not init");
- return NO_INIT;
- }
- return mAudioOutput->removeAudioDeviceCallback(listener);
-}
-
-status_t MediaPlayer2::dump(int fd, const Vector<String16>& args) {
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
- result.append(" MediaPlayer2\n");
- snprintf(buffer, 255, " pid(%d), looping(%s)\n", mPid, mLoop?"true": "false");
- result.append(buffer);
-
- sp<MediaPlayer2Interface> player;
- sp<MediaPlayer2AudioOutput> audioOutput;
- bool locked = false;
- for (int i = 0; i < kDumpLockRetries; ++i) {
- if (mLock.tryLock() == NO_ERROR) {
- locked = true;
- break;
- }
- usleep(kDumpLockSleepUs);
- }
-
- if (locked) {
- player = mPlayer;
- audioOutput = mAudioOutput;
- mLock.unlock();
- } else {
- result.append(" lock is taken, no dump from player and audio output\n");
- }
- write(fd, result.string(), result.size());
-
- if (player != NULL) {
- player->dump(fd, args);
- }
- if (audioOutput != 0) {
- audioOutput->dump(fd, args);
- }
- write(fd, "\n", 1);
- return NO_ERROR;
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/Android.bp b/media/libmediaplayer2/nuplayer2/Android.bp
deleted file mode 100644
index 0f69b2e..0000000
--- a/media/libmediaplayer2/nuplayer2/Android.bp
+++ /dev/null
@@ -1,72 +0,0 @@
-cc_library_static {
-
- srcs: [
- "JMediaPlayer2Utils.cpp",
- "JWakeLock.cpp",
- "GenericSource2.cpp",
- "HTTPLiveSource2.cpp",
- "NuPlayer2.cpp",
- "NuPlayer2CCDecoder.cpp",
- "NuPlayer2Decoder.cpp",
- "NuPlayer2DecoderBase.cpp",
- "NuPlayer2DecoderPassThrough.cpp",
- "NuPlayer2Driver.cpp",
- "NuPlayer2Drm.cpp",
- "NuPlayer2Renderer.cpp",
- "RTSPSource2.cpp",
- ],
-
- header_libs: [
- "libbase_headers",
- "libmediaplayer2_headers",
- "media_plugin_headers",
- ],
-
- include_dirs: [
- "frameworks/av/media/libstagefright",
- "frameworks/av/media/libstagefright/httplive",
- "frameworks/av/media/libstagefright/include",
- "frameworks/av/media/libstagefright/mpeg2ts",
- "frameworks/av/media/libstagefright/rtsp",
- "frameworks/av/media/libstagefright/timedtext",
- "frameworks/av/media/ndk",
- "frameworks/base/core/jni",
- ],
-
- cflags: [
- "-Werror",
- "-Wall",
- ],
-
- product_variables: {
- debuggable: {
- cflags: [
- "-DENABLE_STAGEFRIGHT_EXPERIMENTS",
- ],
- }
- },
-
- shared_libs: [
- "libbinder",
- "libui",
- "libgui",
- "libmedia",
- "libmediametrics",
- "libmediandk",
- "libmediandk_utils",
- "libpowermanager",
- ],
-
- static_libs: [
- "libmedia_helper",
- "libmediaplayer2-protos",
- "libmedia2_jni_core",
- ],
-
- name: "libstagefright_nuplayer2",
-
- sanitize: {
- cfi: true,
- },
-
-}
diff --git a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
deleted file mode 100644
index 9552580..0000000
--- a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
+++ /dev/null
@@ -1,1547 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "GenericSource2"
-
-#include "GenericSource2.h"
-#include "NuPlayer2Drm.h"
-
-#include "AnotherPacketSource.h"
-#include <cutils/properties.h>
-#include <media/DataSource.h>
-#include <media/MediaBufferHolder.h>
-#include <media/NdkWrapper.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaClock.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/NdkUtils.h>
-#include <media/stagefright/Utils.h>
-
-namespace android {
-
-static const int kInitialMarkMs = 5000; // 5secs
-
-//static const int kPausePlaybackMarkMs = 2000; // 2secs
-static const int kResumePlaybackMarkMs = 15000; // 15secs
-
-NuPlayer2::GenericSource2::GenericSource2(
- const sp<AMessage> ¬ify,
- uid_t uid,
- const sp<MediaClock> &mediaClock)
- : Source(notify),
- mAudioTimeUs(0),
- mAudioLastDequeueTimeUs(0),
- mVideoTimeUs(0),
- mVideoLastDequeueTimeUs(0),
- mPrevBufferPercentage(-1),
- mPollBufferingGeneration(0),
- mSentPauseOnBuffering(false),
- mAudioDataGeneration(0),
- mVideoDataGeneration(0),
- mFetchSubtitleDataGeneration(0),
- mFetchTimedTextDataGeneration(0),
- mDurationUs(-1ll),
- mAudioIsVorbis(false),
- mIsSecure(false),
- mIsStreaming(false),
- mUID(uid),
- mMediaClock(mediaClock),
- mFd(-1),
- mBitrate(-1ll),
- mPendingReadBufferTypes(0) {
- ALOGV("GenericSource2");
- CHECK(mediaClock != NULL);
-
- mBufferingSettings.mInitialMarkMs = kInitialMarkMs;
- mBufferingSettings.mResumePlaybackMarkMs = kResumePlaybackMarkMs;
- resetDataSource();
-}
-
-void NuPlayer2::GenericSource2::resetDataSource() {
- ALOGV("resetDataSource");
-
- mDisconnected = false;
- mUri.clear();
- mUriHeaders.clear();
- if (mFd >= 0) {
- close(mFd);
- mFd = -1;
- }
- mOffset = 0;
- mLength = 0;
- mStarted = false;
- mPreparing = false;
-
- mIsDrmProtected = false;
- mIsDrmReleased = false;
- mIsSecure = false;
- mMimes.clear();
-}
-
-status_t NuPlayer2::GenericSource2::setDataSource(
- const char *url,
- const KeyedVector<String8, String8> *headers) {
- Mutex::Autolock _l(mLock);
- ALOGV("setDataSource url: %s", url);
-
- resetDataSource();
-
- mUri = url;
-
- if (headers) {
- mUriHeaders = *headers;
- }
-
- // delay data source creation to prepareAsync() to avoid blocking
- // the calling thread in setDataSource for any significant time.
- return OK;
-}
-
-status_t NuPlayer2::GenericSource2::setDataSource(
- int fd, int64_t offset, int64_t length) {
- Mutex::Autolock _l(mLock);
- ALOGV("setDataSource %d/%lld/%lld", fd, (long long)offset, (long long)length);
-
- resetDataSource();
-
- mFd = dup(fd);
- mOffset = offset;
- mLength = length;
-
- // delay data source creation to prepareAsync() to avoid blocking
- // the calling thread in setDataSource for any significant time.
- return OK;
-}
-
-status_t NuPlayer2::GenericSource2::setDataSource(const sp<DataSource>& source) {
- Mutex::Autolock _l(mLock);
- ALOGV("setDataSource (source: %p)", source.get());
-
- resetDataSource();
- mDataSourceWrapper = new AMediaDataSourceWrapper(source);
- return OK;
-}
-
-sp<MetaData> NuPlayer2::GenericSource2::getFileFormatMeta() const {
- Mutex::Autolock _l(mLock);
- return mFileMeta;
-}
-
-status_t NuPlayer2::GenericSource2::initFromDataSource() {
- mExtractor = new AMediaExtractorWrapper(AMediaExtractor_new());
- CHECK(mFd >=0 || mDataSourceWrapper != NULL);
- sp<AMediaDataSourceWrapper> aSourceWrapper = mDataSourceWrapper;
- const int fd = mFd;
-
- mLock.unlock();
- // This might take long time if data source is not reliable.
- status_t err;
- if (aSourceWrapper != NULL) {
- err = mExtractor->setDataSource(aSourceWrapper->getAMediaDataSource());
- } else {
- err = mExtractor->setDataSource(fd, mOffset, mLength);
- }
-
- if (err != OK) {
- ALOGE("initFromDataSource, failed to set extractor data source!");
- mLock.lock();
- return UNKNOWN_ERROR;
- }
-
- size_t numtracks = mExtractor->getTrackCount();
- if (numtracks == 0) {
- ALOGE("initFromDataSource, source has no track!");
- mLock.lock();
- return UNKNOWN_ERROR;
- }
-
- mFileMeta = convertMediaFormatWrapperToMetaData(mExtractor->getFormat());
- mLock.lock();
- if (mFileMeta != NULL) {
- int64_t duration;
- if (mFileMeta->findInt64(kKeyDuration, &duration)) {
- mDurationUs = duration;
- }
- }
-
- int32_t totalBitrate = 0;
-
- mMimes.clear();
-
- for (size_t i = 0; i < numtracks; ++i) {
-
- sp<AMediaFormatWrapper> trackFormat = mExtractor->getTrackFormat(i);
- if (trackFormat == NULL) {
- ALOGE("no metadata for track %zu", i);
- return UNKNOWN_ERROR;
- }
-
- sp<AMediaExtractorWrapper> trackExtractor = new AMediaExtractorWrapper(AMediaExtractor_new());
- if (aSourceWrapper != NULL) {
- trackExtractor->setDataSource(aSourceWrapper->getAMediaDataSource());
- } else {
- trackExtractor->setDataSource(fd, mOffset, mLength);
- }
-
- const char *mime;
- sp<MetaData> meta = convertMediaFormatWrapperToMetaData(trackFormat);
- CHECK(meta->findCString(kKeyMIMEType, &mime));
-
- ALOGV("initFromDataSource track[%zu]: %s", i, mime);
-
- // Do the string compare immediately with "mime",
- // we can't assume "mime" would stay valid after another
- // extractor operation, some extractors might modify meta
- // during getTrack() and make it invalid.
- if (!strncasecmp(mime, "audio/", 6)) {
- if (mAudioTrack.mExtractor == NULL) {
- mAudioTrack.mIndex = i;
- mAudioTrack.mExtractor = trackExtractor;
- mAudioTrack.mExtractor->selectTrack(i);
- mAudioTrack.mPackets = new AnotherPacketSource(meta);
-
- if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
- mAudioIsVorbis = true;
- } else {
- mAudioIsVorbis = false;
- }
-
- mMimes.add(String8(mime));
- }
- } else if (!strncasecmp(mime, "video/", 6)) {
- if (mVideoTrack.mExtractor == NULL) {
- mVideoTrack.mIndex = i;
- mVideoTrack.mExtractor = trackExtractor;
- mVideoTrack.mExtractor->selectTrack(i);
- mVideoTrack.mPackets = new AnotherPacketSource(meta);
-
- // video always at the beginning
- mMimes.insertAt(String8(mime), 0);
- }
- }
-
- mExtractors.push(trackExtractor);
- int64_t durationUs;
- if (meta->findInt64(kKeyDuration, &durationUs)) {
- if (durationUs > mDurationUs) {
- mDurationUs = durationUs;
- }
- }
-
- int32_t bitrate;
- if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
- totalBitrate += bitrate;
- } else {
- totalBitrate = -1;
- }
- }
-
- ALOGV("initFromDataSource mExtractors.size(): %zu mIsSecure: %d mime[0]: %s", mExtractors.size(),
- mIsSecure, (mMimes.isEmpty() ? "NONE" : mMimes[0].string()));
-
- if (mExtractors.size() == 0) {
- ALOGE("b/23705695");
- return UNKNOWN_ERROR;
- }
-
- // Modular DRM: The return value doesn't affect source initialization.
- (void)checkDrmInfo();
-
- mBitrate = totalBitrate;
-
- return OK;
-}
-
-status_t NuPlayer2::GenericSource2::getBufferingSettings(
- BufferingSettings* buffering /* nonnull */) {
- {
- Mutex::Autolock _l(mLock);
- *buffering = mBufferingSettings;
- }
-
- ALOGV("getBufferingSettings{%s}", buffering->toString().string());
- return OK;
-}
-
-status_t NuPlayer2::GenericSource2::setBufferingSettings(const BufferingSettings& buffering) {
- ALOGV("setBufferingSettings{%s}", buffering.toString().string());
-
- Mutex::Autolock _l(mLock);
- mBufferingSettings = buffering;
- return OK;
-}
-
-int64_t NuPlayer2::GenericSource2::getLastReadPosition() {
- if (mAudioTrack.mExtractor != NULL) {
- return mAudioTimeUs;
- } else if (mVideoTrack.mExtractor != NULL) {
- return mVideoTimeUs;
- } else {
- return 0;
- }
-}
-
-bool NuPlayer2::GenericSource2::isStreaming() const {
- Mutex::Autolock _l(mLock);
- return mIsStreaming;
-}
-
-NuPlayer2::GenericSource2::~GenericSource2() {
- ALOGV("~GenericSource2");
- if (mLooper != NULL) {
- mLooper->unregisterHandler(id());
- mLooper->stop();
- }
- if (mDataSourceWrapper != NULL) {
- mDataSourceWrapper->close();
- }
- resetDataSource();
-}
-
-void NuPlayer2::GenericSource2::prepareAsync(int64_t startTimeUs) {
- Mutex::Autolock _l(mLock);
- ALOGV("prepareAsync: (looper: %d)", (mLooper != NULL));
-
- if (mLooper == NULL) {
- mLooper = new ALooper;
- mLooper->setName("generic2");
- mLooper->start(false, /* runOnCallingThread */
- true, /* canCallJava */
- PRIORITY_DEFAULT);
-
- mLooper->registerHandler(this);
- }
-
- sp<AMessage> msg = new AMessage(kWhatPrepareAsync, this);
- msg->setInt64("startTimeUs", startTimeUs);
-
- msg->post();
-}
-
-void NuPlayer2::GenericSource2::onPrepareAsync(int64_t startTimeUs) {
- ALOGV("onPrepareAsync: mFd %d mUri %s mDataSourceWrapper: %p",
- mFd, mUri.c_str(), mDataSourceWrapper.get());
-
- if (!mUri.empty()) {
- const char* uri = mUri.c_str();
- size_t numheaders = mUriHeaders.size();
- const char **key_values = numheaders ? new const char *[numheaders * 2] : NULL;
- for (size_t i = 0; i < numheaders; ++i) {
- key_values[i * 2] = mUriHeaders.keyAt(i).c_str();
- key_values[i * 2 + 1] = mUriHeaders.valueAt(i).c_str();
- }
- mLock.unlock();
- AMediaDataSource *aSource = AMediaDataSource_newUri(uri, numheaders, key_values);
- mLock.lock();
- mDataSourceWrapper = aSource ? new AMediaDataSourceWrapper(aSource) : NULL;
- delete[] key_values;
- // For cached streaming cases, we need to wait for enough
- // buffering before reporting prepared.
- mIsStreaming = !strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8);
- }
-
- if (mDisconnected || (mFd < 0 && mDataSourceWrapper == NULL)) {
- ALOGE("mDisconnected(%d) or Failed to create data source!", mDisconnected);
- notifyPreparedAndCleanup(UNKNOWN_ERROR);
- return;
- }
-
- // init extractor from data source
- status_t err = initFromDataSource();
- if (mFd >= 0) {
- close(mFd);
- mFd = -1;
- }
-
- if (err != OK) {
- ALOGE("Failed to init from data source!");
- notifyPreparedAndCleanup(err);
- return;
- }
-
- if (mVideoTrack.mExtractor != NULL) {
- sp<MetaData> meta = getFormatMeta_l(false /* audio */);
- sp<AMessage> msg = new AMessage;
- err = convertMetaDataToMessage(meta, &msg);
- if(err != OK) {
- notifyPreparedAndCleanup(err);
- return;
- }
- notifyVideoSizeChanged(msg);
- }
-
- notifyFlagsChanged(
- // FLAG_SECURE will be known if/when prepareDrm is called by the app
- // FLAG_PROTECTED will be known if/when prepareDrm is called by the app
- FLAG_CAN_PAUSE |
- FLAG_CAN_SEEK_BACKWARD |
- FLAG_CAN_SEEK_FORWARD |
- FLAG_CAN_SEEK);
-
- doSeek(startTimeUs, MediaPlayer2SeekMode::SEEK_CLOSEST);
- finishPrepareAsync();
-
- ALOGV("onPrepareAsync: Done");
-}
-
-void NuPlayer2::GenericSource2::finishPrepareAsync() {
- ALOGV("finishPrepareAsync");
-
- if (mIsStreaming) {
- mPreparing = true;
- ++mPollBufferingGeneration;
- schedulePollBuffering();
- } else {
- notifyPrepared();
- }
-
- if (mAudioTrack.mExtractor != NULL) {
- postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
- }
-
- if (mVideoTrack.mExtractor != NULL) {
- postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
- }
-}
-
-void NuPlayer2::GenericSource2::notifyPreparedAndCleanup(status_t err) {
- if (err != OK) {
- mDataSourceWrapper.clear();
-
- mBitrate = -1;
- mPrevBufferPercentage = -1;
- ++mPollBufferingGeneration;
- }
- notifyPrepared(err);
-}
-
-void NuPlayer2::GenericSource2::start() {
- Mutex::Autolock _l(mLock);
- ALOGI("start");
-
- if (mAudioTrack.mExtractor != NULL) {
- postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
- }
-
- if (mVideoTrack.mExtractor != NULL) {
- postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
- }
-
- mStarted = true;
-}
-
-void NuPlayer2::GenericSource2::stop() {
- Mutex::Autolock _l(mLock);
- mStarted = false;
-}
-
-void NuPlayer2::GenericSource2::pause() {
- Mutex::Autolock _l(mLock);
- mStarted = false;
-}
-
-void NuPlayer2::GenericSource2::resume() {
- Mutex::Autolock _l(mLock);
- mStarted = true;
-}
-
-void NuPlayer2::GenericSource2::disconnect() {
- {
- Mutex::Autolock _l(mLock);
- mDisconnected = true;
- }
- if (mDataSourceWrapper != NULL) {
- mDataSourceWrapper->close();
- }
-}
-
-status_t NuPlayer2::GenericSource2::feedMoreTSData() {
- return OK;
-}
-
-void NuPlayer2::GenericSource2::onMessageReceived(const sp<AMessage> &msg) {
- Mutex::Autolock _l(mLock);
- switch (msg->what()) {
- case kWhatPrepareAsync:
- {
- int64_t startTimeUs;
- CHECK(msg->findInt64("startTimeUs", &startTimeUs));
- onPrepareAsync(startTimeUs);
- break;
- }
- case kWhatFetchSubtitleData:
- {
- fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
- mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
- break;
- }
-
- case kWhatFetchTimedTextData:
- {
- fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
- mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
- break;
- }
-
- case kWhatSendSubtitleData:
- {
- sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
- mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
- break;
- }
-
- case kWhatSendGlobalTimedTextData:
- {
- sendGlobalTextData(kWhatTimedTextData, mFetchTimedTextDataGeneration, msg);
- break;
- }
- case kWhatSendTimedTextData:
- {
- sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
- mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
- break;
- }
-
- case kWhatChangeAVSource:
- {
- int32_t trackIndex;
- CHECK(msg->findInt32("trackIndex", &trackIndex));
- const sp<AMediaExtractorWrapper> extractor = mExtractors.itemAt(trackIndex);
-
- Track* track;
- AString mime;
- media_track_type trackType, counterpartType;
- sp<AMediaFormatWrapper> format = extractor->getTrackFormat(trackIndex);
- format->getString(AMEDIAFORMAT_KEY_MIME, &mime);
- if (!strncasecmp(mime.c_str(), "audio/", 6)) {
- track = &mAudioTrack;
- trackType = MEDIA_TRACK_TYPE_AUDIO;
- counterpartType = MEDIA_TRACK_TYPE_VIDEO;;
- } else {
- CHECK(!strncasecmp(mime.c_str(), "video/", 6));
- track = &mVideoTrack;
- trackType = MEDIA_TRACK_TYPE_VIDEO;
- counterpartType = MEDIA_TRACK_TYPE_AUDIO;;
- }
-
-
- track->mExtractor = extractor;
- track->mExtractor->selectSingleTrack(trackIndex);
- track->mIndex = trackIndex;
- ++mAudioDataGeneration;
- ++mVideoDataGeneration;
-
- int64_t timeUs, actualTimeUs;
- const bool formatChange = true;
- if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
- timeUs = mAudioLastDequeueTimeUs;
- } else {
- timeUs = mVideoLastDequeueTimeUs;
- }
- readBuffer(trackType, timeUs, MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */,
- &actualTimeUs, formatChange);
- readBuffer(counterpartType, -1, MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */,
- NULL, !formatChange);
- ALOGV("timeUs %lld actualTimeUs %lld", (long long)timeUs, (long long)actualTimeUs);
-
- break;
- }
-
- case kWhatSeek:
- {
- onSeek(msg);
- break;
- }
-
- case kWhatReadBuffer:
- {
- onReadBuffer(msg);
- break;
- }
-
- case kWhatPollBuffering:
- {
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
- if (generation == mPollBufferingGeneration) {
- onPollBuffering();
- }
- break;
- }
-
- default:
- Source::onMessageReceived(msg);
- break;
- }
-}
-
-void NuPlayer2::GenericSource2::fetchTextData(
- uint32_t sendWhat,
- media_track_type type,
- int32_t curGen,
- const sp<AnotherPacketSource>& packets,
- const sp<AMessage>& msg) {
- int32_t msgGeneration;
- CHECK(msg->findInt32("generation", &msgGeneration));
- if (msgGeneration != curGen) {
- // stale
- return;
- }
-
- int32_t avail;
- if (packets->hasBufferAvailable(&avail)) {
- return;
- }
-
- int64_t timeUs;
- CHECK(msg->findInt64("timeUs", &timeUs));
-
- int64_t subTimeUs = 0;
- readBuffer(type, timeUs, MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */, &subTimeUs);
-
- status_t eosResult;
- if (!packets->hasBufferAvailable(&eosResult)) {
- return;
- }
-
- if (msg->what() == kWhatFetchSubtitleData) {
- subTimeUs -= 1000000ll; // send subtile data one second earlier
- }
- sp<AMessage> msg2 = new AMessage(sendWhat, this);
- msg2->setInt32("generation", msgGeneration);
- mMediaClock->addTimer(msg2, subTimeUs);
-}
-
-void NuPlayer2::GenericSource2::sendTextData(
- uint32_t what,
- media_track_type type,
- int32_t curGen,
- const sp<AnotherPacketSource>& packets,
- const sp<AMessage>& msg) {
- int32_t msgGeneration;
- CHECK(msg->findInt32("generation", &msgGeneration));
- if (msgGeneration != curGen) {
- // stale
- return;
- }
-
- int64_t subTimeUs;
- if (packets->nextBufferTime(&subTimeUs) != OK) {
- return;
- }
-
- int64_t nextSubTimeUs;
- readBuffer(type, -1, MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */, &nextSubTimeUs);
-
- sp<ABuffer> buffer;
- status_t dequeueStatus = packets->dequeueAccessUnit(&buffer);
- if (dequeueStatus == OK) {
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", what);
- notify->setBuffer("buffer", buffer);
- notify->post();
-
- if (msg->what() == kWhatSendSubtitleData) {
- nextSubTimeUs -= 1000000ll; // send subtile data one second earlier
- }
- mMediaClock->addTimer(msg, nextSubTimeUs);
- }
-}
-
-void NuPlayer2::GenericSource2::sendGlobalTextData(
- uint32_t what,
- int32_t curGen,
- sp<AMessage> msg) {
- int32_t msgGeneration;
- CHECK(msg->findInt32("generation", &msgGeneration));
- if (msgGeneration != curGen) {
- // stale
- return;
- }
-
- void *data = NULL;
- size_t size = 0;
- if (mTimedTextTrack.mExtractor->getTrackFormat(mTimedTextTrack.mIndex)->getBuffer(
- "text", &data, &size)) {
- mGlobalTimedText = new ABuffer(size);
- if (mGlobalTimedText->data()) {
- memcpy(mGlobalTimedText->data(), data, size);
- sp<AMessage> globalMeta = mGlobalTimedText->meta();
- globalMeta->setInt64("timeUs", 0);
- globalMeta->setString("mime", MEDIA_MIMETYPE_TEXT_3GPP);
- globalMeta->setInt32("global", 1);
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", what);
- notify->setBuffer("buffer", mGlobalTimedText);
- notify->post();
- }
- }
-}
-
-sp<AMessage> NuPlayer2::GenericSource2::getFormat(bool audio) {
- Mutex::Autolock _l(mLock);
- return getFormat_l(audio);
-}
-
-sp<MetaData> NuPlayer2::GenericSource2::getFormatMeta(bool audio) {
- Mutex::Autolock _l(mLock);
- return getFormatMeta_l(audio);
-}
-
-sp<AMessage> NuPlayer2::GenericSource2::getFormat_l(bool audio) {
- sp<AMediaExtractorWrapper> extractor = audio ? mAudioTrack.mExtractor : mVideoTrack.mExtractor;
- size_t trackIndex = audio ? mAudioTrack.mIndex : mVideoTrack.mIndex;
-
- if (extractor == NULL) {
- return NULL;
- }
-
- return extractor->getTrackFormat(trackIndex)->toAMessage();
-}
-
-sp<MetaData> NuPlayer2::GenericSource2::getFormatMeta_l(bool audio) {
- sp<AMediaExtractorWrapper> extractor = audio ? mAudioTrack.mExtractor : mVideoTrack.mExtractor;
- size_t trackIndex = audio ? mAudioTrack.mIndex : mVideoTrack.mIndex;
-
- if (extractor == NULL) {
- return NULL;
- }
-
- return convertMediaFormatWrapperToMetaData(extractor->getTrackFormat(trackIndex));
-}
-
-status_t NuPlayer2::GenericSource2::dequeueAccessUnit(
- bool audio, sp<ABuffer> *accessUnit) {
- Mutex::Autolock _l(mLock);
- // If has gone through stop/releaseDrm sequence, we no longer send down any buffer b/c
- // the codec's crypto object has gone away (b/37960096).
- // Note: This will be unnecessary when stop() changes behavior and releases codec (b/35248283).
- if (!mStarted && mIsDrmReleased) {
- return -EWOULDBLOCK;
- }
-
- Track *track = audio ? &mAudioTrack : &mVideoTrack;
-
- if (track->mExtractor == NULL) {
- return -EWOULDBLOCK;
- }
-
- status_t finalResult;
- if (!track->mPackets->hasBufferAvailable(&finalResult)) {
- if (finalResult == OK) {
- postReadBuffer(
- audio ? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
- return -EWOULDBLOCK;
- }
- return finalResult;
- }
-
- status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
-
- // start pulling in more buffers if cache is running low
- // so that decoder has less chance of being starved
- if (!mIsStreaming) {
- if (track->mPackets->getAvailableBufferCount(&finalResult) < 2) {
- postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
- }
- } else {
- int64_t durationUs = track->mPackets->getBufferedDurationUs(&finalResult);
- // TODO: maxRebufferingMarkMs could be larger than
- // mBufferingSettings.mResumePlaybackMarkMs
- int64_t restartBufferingMarkUs =
- mBufferingSettings.mResumePlaybackMarkMs * 1000ll / 2;
- if (finalResult == OK) {
- if (durationUs < restartBufferingMarkUs) {
- postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
- }
- if (track->mPackets->getAvailableBufferCount(&finalResult) < 2
- && !mSentPauseOnBuffering && !mPreparing) {
- mSentPauseOnBuffering = true;
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatPauseOnBufferingStart);
- notify->post();
- }
- }
- }
-
- if (result != OK) {
- if (mSubtitleTrack.mExtractor != NULL) {
- mSubtitleTrack.mPackets->clear();
- mFetchSubtitleDataGeneration++;
- }
- if (mTimedTextTrack.mExtractor != NULL) {
- mTimedTextTrack.mPackets->clear();
- mFetchTimedTextDataGeneration++;
- }
- return result;
- }
-
- int64_t timeUs;
- status_t eosResult; // ignored
- CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
- if (audio) {
- mAudioLastDequeueTimeUs = timeUs;
- } else {
- mVideoLastDequeueTimeUs = timeUs;
- }
-
- if (mSubtitleTrack.mExtractor != NULL
- && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
- sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, this);
- msg->setInt64("timeUs", timeUs);
- msg->setInt32("generation", mFetchSubtitleDataGeneration);
- msg->post();
- }
-
- if (mTimedTextTrack.mExtractor != NULL
- && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
- sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this);
- msg->setInt64("timeUs", timeUs);
- msg->setInt32("generation", mFetchTimedTextDataGeneration);
- msg->post();
- }
-
- return result;
-}
-
-status_t NuPlayer2::GenericSource2::getDuration(int64_t *durationUs) {
- Mutex::Autolock _l(mLock);
- *durationUs = mDurationUs;
- return OK;
-}
-
-size_t NuPlayer2::GenericSource2::getTrackCount() const {
- Mutex::Autolock _l(mLock);
- return mExtractors.size();
-}
-
-sp<AMessage> NuPlayer2::GenericSource2::getTrackInfo(size_t trackIndex) const {
- Mutex::Autolock _l(mLock);
- size_t trackCount = mExtractors.size();
- if (trackIndex >= trackCount) {
- return NULL;
- }
-
- sp<AMessage> format = mExtractors.itemAt(trackIndex)->getTrackFormat(trackIndex)->toAMessage();
- if (format == NULL) {
- ALOGE("no metadata for track %zu", trackIndex);
- return NULL;
- }
-
- AString mime;
- CHECK(format->findString(AMEDIAFORMAT_KEY_MIME, &mime));
-
- int32_t trackType;
- if (!strncasecmp(mime.c_str(), "video/", 6)) {
- trackType = MEDIA_TRACK_TYPE_VIDEO;
- } else if (!strncasecmp(mime.c_str(), "audio/", 6)) {
- trackType = MEDIA_TRACK_TYPE_AUDIO;
- } else if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_TEXT_3GPP)) {
- trackType = MEDIA_TRACK_TYPE_TIMEDTEXT;
- } else {
- trackType = MEDIA_TRACK_TYPE_UNKNOWN;
- }
- format->setInt32("type", trackType);
-
- AString lang;
- if (!format->findString("language", &lang)) {
- format->setString("language", "und");
- }
-
- if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
- int32_t isAutoselect = 1, isDefault = 0, isForced = 0;
- format->findInt32(AMEDIAFORMAT_KEY_IS_AUTOSELECT, &isAutoselect);
- format->findInt32(AMEDIAFORMAT_KEY_IS_DEFAULT, &isDefault);
- format->findInt32(AMEDIAFORMAT_KEY_IS_FORCED_SUBTITLE, &isForced);
-
- format->setInt32("auto", !!isAutoselect);
- format->setInt32("default", !!isDefault);
- format->setInt32("forced", !!isForced);
- }
-
- return format;
-}
-
-ssize_t NuPlayer2::GenericSource2::getSelectedTrack(media_track_type type) const {
- Mutex::Autolock _l(mLock);
- const Track *track = NULL;
- switch (type) {
- case MEDIA_TRACK_TYPE_VIDEO:
- track = &mVideoTrack;
- break;
- case MEDIA_TRACK_TYPE_AUDIO:
- track = &mAudioTrack;
- break;
- case MEDIA_TRACK_TYPE_TIMEDTEXT:
- track = &mTimedTextTrack;
- break;
- case MEDIA_TRACK_TYPE_SUBTITLE:
- track = &mSubtitleTrack;
- break;
- default:
- break;
- }
-
- if (track != NULL && track->mExtractor != NULL) {
- return track->mIndex;
- }
-
- return -1;
-}
-
-status_t NuPlayer2::GenericSource2::selectTrack(size_t trackIndex, bool select, int64_t timeUs) {
- Mutex::Autolock _l(mLock);
- ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex);
-
- if (trackIndex >= mExtractors.size()) {
- return BAD_INDEX;
- }
-
- if (!select) {
- Track* track = NULL;
- if (mSubtitleTrack.mExtractor != NULL && trackIndex == mSubtitleTrack.mIndex) {
- track = &mSubtitleTrack;
- mFetchSubtitleDataGeneration++;
- } else if (mTimedTextTrack.mExtractor != NULL && trackIndex == mTimedTextTrack.mIndex) {
- track = &mTimedTextTrack;
- mFetchTimedTextDataGeneration++;
- }
- if (track == NULL) {
- return INVALID_OPERATION;
- }
- track->mExtractor = NULL;
- track->mPackets->clear();
- return OK;
- }
-
- const sp<AMediaExtractorWrapper> extractor = mExtractors.itemAt(trackIndex);
- sp<MetaData> meta = convertMediaFormatWrapperToMetaData(extractor->getTrackFormat(trackIndex));
- const char *mime;
- CHECK(meta->findCString(kKeyMIMEType, &mime));
- if (!strncasecmp(mime, "text/", 5)) {
- bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP);
- Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack;
- if (track->mExtractor != NULL && track->mIndex == trackIndex) {
- return OK;
- }
- track->mIndex = trackIndex;
- track->mExtractor = mExtractors.itemAt(trackIndex);
- track->mExtractor->selectSingleTrack(trackIndex);
- if (track->mPackets == NULL) {
- track->mPackets = new AnotherPacketSource(meta);
- } else {
- track->mPackets->clear();
- track->mPackets->setFormat(meta);
-
- }
-
- if (isSubtitle) {
- mFetchSubtitleDataGeneration++;
- } else {
- mFetchTimedTextDataGeneration++;
- }
-
- status_t eosResult; // ignored
- if (mSubtitleTrack.mExtractor != NULL
- && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
- sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, this);
- msg->setInt64("timeUs", timeUs);
- msg->setInt32("generation", mFetchSubtitleDataGeneration);
- msg->post();
- }
-
- sp<AMessage> msg2 = new AMessage(kWhatSendGlobalTimedTextData, this);
- msg2->setInt32("generation", mFetchTimedTextDataGeneration);
- msg2->post();
-
- if (mTimedTextTrack.mExtractor != NULL
- && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
- sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this);
- msg->setInt64("timeUs", timeUs);
- msg->setInt32("generation", mFetchTimedTextDataGeneration);
- msg->post();
- }
-
- return OK;
- } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) {
- bool audio = !strncasecmp(mime, "audio/", 6);
- Track *track = audio ? &mAudioTrack : &mVideoTrack;
- if (track->mExtractor != NULL && track->mIndex == trackIndex) {
- return OK;
- }
-
- sp<AMessage> msg = new AMessage(kWhatChangeAVSource, this);
- msg->setInt32("trackIndex", trackIndex);
- msg->post();
- return OK;
- }
-
- return INVALID_OPERATION;
-}
-
-status_t NuPlayer2::GenericSource2::seekTo(int64_t seekTimeUs, MediaPlayer2SeekMode mode) {
- ALOGV("seekTo: %lld, %d", (long long)seekTimeUs, mode);
- sp<AMessage> msg = new AMessage(kWhatSeek, this);
- msg->setInt64("seekTimeUs", seekTimeUs);
- msg->setInt32("mode", mode);
-
- // Need to call readBuffer on |mLooper| to ensure the calls to
- // IMediaSource::read* are serialized. Note that IMediaSource::read*
- // is called without |mLock| acquired and MediaSource is not thread safe.
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- }
-
- return err;
-}
-
-void NuPlayer2::GenericSource2::onSeek(const sp<AMessage>& msg) {
- int64_t seekTimeUs;
- int32_t mode;
- CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
- CHECK(msg->findInt32("mode", &mode));
-
- sp<AMessage> response = new AMessage;
- status_t err = doSeek(seekTimeUs, (MediaPlayer2SeekMode)mode);
- response->setInt32("err", err);
-
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
-}
-
-status_t NuPlayer2::GenericSource2::doSeek(int64_t seekTimeUs, MediaPlayer2SeekMode mode) {
- if (mVideoTrack.mExtractor != NULL) {
- ++mVideoDataGeneration;
-
- int64_t actualTimeUs;
- readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, mode, &actualTimeUs);
-
- if (mode != MediaPlayer2SeekMode::SEEK_CLOSEST) {
- seekTimeUs = actualTimeUs;
- }
- mVideoLastDequeueTimeUs = actualTimeUs;
- }
-
- if (mAudioTrack.mExtractor != NULL) {
- ++mAudioDataGeneration;
- readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs, MediaPlayer2SeekMode::SEEK_CLOSEST);
- mAudioLastDequeueTimeUs = seekTimeUs;
- }
-
- if (mSubtitleTrack.mExtractor != NULL) {
- mSubtitleTrack.mPackets->clear();
- mFetchSubtitleDataGeneration++;
- }
-
- if (mTimedTextTrack.mExtractor != NULL) {
- mTimedTextTrack.mPackets->clear();
- mFetchTimedTextDataGeneration++;
- }
-
- ++mPollBufferingGeneration;
- schedulePollBuffering();
- return OK;
-}
-
-sp<ABuffer> NuPlayer2::GenericSource2::mediaBufferToABuffer(
- MediaBufferBase* mb,
- media_track_type trackType) {
- bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO;
- size_t outLength = mb->range_length();
-
- if (audio && mAudioIsVorbis) {
- outLength += sizeof(int32_t);
- }
-
- sp<ABuffer> ab;
-
- if (mIsDrmProtected) {
- // Modular DRM
- // Enabled for both video/audio so 1) media buffer is reused without extra copying
- // 2) meta data can be retrieved in onInputBufferFetched for calling queueSecureInputBuffer.
-
- // data is already provided in the buffer
- ab = new ABuffer(NULL, mb->range_length());
- ab->meta()->setObject("mediaBufferHolder", new MediaBufferHolder(mb));
-
- // Modular DRM: Required b/c of the above add_ref.
- // If ref>0, there must be an observer, or it'll crash at release().
- // TODO: MediaBuffer might need to be revised to ease such need.
- mb->setObserver(this);
- // setMediaBufferBase() interestingly doesn't increment the ref count on its own.
- // Extra increment (since we want to keep mb alive and attached to ab beyond this function
- // call. This is to counter the effect of mb->release() towards the end.
- mb->add_ref();
-
- } else {
- ab = new ABuffer(outLength);
- memcpy(ab->data(),
- (const uint8_t *)mb->data() + mb->range_offset(),
- mb->range_length());
- }
-
- if (audio && mAudioIsVorbis) {
- int32_t numPageSamples;
- if (!mb->meta_data().findInt32(kKeyValidSamples, &numPageSamples)) {
- numPageSamples = -1;
- }
-
- uint8_t* abEnd = ab->data() + mb->range_length();
- memcpy(abEnd, &numPageSamples, sizeof(numPageSamples));
- }
-
- sp<AMessage> meta = ab->meta();
-
- int64_t timeUs;
- CHECK(mb->meta_data().findInt64(kKeyTime, &timeUs));
- meta->setInt64("timeUs", timeUs);
-
- if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
- int32_t layerId;
- if (mb->meta_data().findInt32(kKeyTemporalLayerId, &layerId)) {
- meta->setInt32("temporal-layer-id", layerId);
- }
- }
-
- if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
- AString mime;
- sp<AMediaExtractorWrapper> extractor = mTimedTextTrack.mExtractor;
- size_t trackIndex = mTimedTextTrack.mIndex;
- CHECK(extractor != NULL
- && extractor->getTrackFormat(trackIndex)->getString(AMEDIAFORMAT_KEY_MIME, &mime));
- meta->setString("mime", mime.c_str());
- }
-
- int64_t durationUs;
- if (mb->meta_data().findInt64(kKeyDuration, &durationUs)) {
- meta->setInt64("durationUs", durationUs);
- }
-
- if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
- meta->setInt32(AMEDIAFORMAT_KEY_TRACK_INDEX, mSubtitleTrack.mIndex);
- }
-
- uint32_t dataType; // unused
- const void *seiData;
- size_t seiLength;
- if (mb->meta_data().findData(kKeySEI, &dataType, &seiData, &seiLength)) {
- sp<ABuffer> sei = ABuffer::CreateAsCopy(seiData, seiLength);;
- meta->setBuffer("sei", sei);
- }
-
- const void *mpegUserDataPointer;
- size_t mpegUserDataLength;
- if (mb->meta_data().findData(
- kKeyMpegUserData, &dataType, &mpegUserDataPointer, &mpegUserDataLength)) {
- sp<ABuffer> mpegUserData = ABuffer::CreateAsCopy(mpegUserDataPointer, mpegUserDataLength);
- meta->setBuffer(AMEDIAFORMAT_KEY_MPEG_USER_DATA, mpegUserData);
- }
-
- mb->release();
- mb = NULL;
-
- return ab;
-}
-
-int32_t NuPlayer2::GenericSource2::getDataGeneration(media_track_type type) const {
- int32_t generation = -1;
- switch (type) {
- case MEDIA_TRACK_TYPE_VIDEO:
- generation = mVideoDataGeneration;
- break;
- case MEDIA_TRACK_TYPE_AUDIO:
- generation = mAudioDataGeneration;
- break;
- case MEDIA_TRACK_TYPE_TIMEDTEXT:
- generation = mFetchTimedTextDataGeneration;
- break;
- case MEDIA_TRACK_TYPE_SUBTITLE:
- generation = mFetchSubtitleDataGeneration;
- break;
- default:
- break;
- }
-
- return generation;
-}
-
-void NuPlayer2::GenericSource2::postReadBuffer(media_track_type trackType) {
- if ((mPendingReadBufferTypes & (1 << trackType)) == 0) {
- mPendingReadBufferTypes |= (1 << trackType);
- sp<AMessage> msg = new AMessage(kWhatReadBuffer, this);
- msg->setInt32("trackType", trackType);
- msg->post();
- }
-}
-
-void NuPlayer2::GenericSource2::onReadBuffer(const sp<AMessage>& msg) {
- int32_t tmpType;
- CHECK(msg->findInt32("trackType", &tmpType));
- media_track_type trackType = (media_track_type)tmpType;
- mPendingReadBufferTypes &= ~(1 << trackType);
- readBuffer(trackType);
-}
-
-void NuPlayer2::GenericSource2::readBuffer(
- media_track_type trackType, int64_t seekTimeUs, MediaPlayer2SeekMode mode,
- int64_t *actualTimeUs, bool formatChange) {
- Track *track;
- size_t maxBuffers = 1;
- switch (trackType) {
- case MEDIA_TRACK_TYPE_VIDEO:
- track = &mVideoTrack;
- maxBuffers = 8; // too large of a number may influence seeks
- break;
- case MEDIA_TRACK_TYPE_AUDIO:
- track = &mAudioTrack;
- maxBuffers = 64;
- break;
- case MEDIA_TRACK_TYPE_SUBTITLE:
- track = &mSubtitleTrack;
- break;
- case MEDIA_TRACK_TYPE_TIMEDTEXT:
- track = &mTimedTextTrack;
- break;
- default:
- TRESPASS();
- }
-
- if (track->mExtractor == NULL) {
- return;
- }
-
- if (actualTimeUs) {
- *actualTimeUs = seekTimeUs;
- }
-
-
- bool seeking = false;
- sp<AMediaExtractorWrapper> extractor = track->mExtractor;
- if (seekTimeUs >= 0) {
- extractor->seekTo(seekTimeUs, mode);
- seeking = true;
- }
-
- int32_t generation = getDataGeneration(trackType);
- for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
- Vector<sp<ABuffer> > aBuffers;
-
- mLock.unlock();
-
- sp<AMediaFormatWrapper> format;
- ssize_t sampleSize = -1;
- status_t err = extractor->getSampleFormat(format);
- if (err == OK) {
- sampleSize = extractor->getSampleSize();
- }
-
- if (err != OK || sampleSize < 0) {
- mLock.lock();
- track->mPackets->signalEOS(err != OK ? err : ERROR_END_OF_STREAM);
- break;
- }
-
- sp<ABuffer> abuf = new ABuffer(sampleSize);
- sampleSize = extractor->readSampleData(abuf);
- mLock.lock();
-
- // in case track has been changed since we don't have lock for some time.
- if (generation != getDataGeneration(trackType)) {
- break;
- }
-
- int64_t timeUs = extractor->getSampleTime();
- if (timeUs < 0) {
- track->mPackets->signalEOS(ERROR_MALFORMED);
- break;
- }
-
- sp<AMessage> meta = abuf->meta();
- format->writeToAMessage(meta);
- meta->setInt64("timeUs", timeUs);
- if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
- mAudioTimeUs = timeUs;
- } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
- mVideoTimeUs = timeUs;
- }
-
- sp<AMediaCodecCryptoInfoWrapper> cryptInfo = extractor->getSampleCryptoInfo();
- if (cryptInfo != NULL) {
- meta->setObject("cryptInfo", cryptInfo);
- }
-
- queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track);
-
- if (numBuffers == 0 && actualTimeUs != nullptr) {
- *actualTimeUs = timeUs;
- }
- if (seeking) {
- if (meta != nullptr && mode == MediaPlayer2SeekMode::SEEK_CLOSEST
- && seekTimeUs > timeUs) {
- sp<AMessage> extra = new AMessage;
- extra->setInt64("resume-at-mediaTimeUs", seekTimeUs);
- meta->setMessage("extra", extra);
- }
- }
-
- track->mPackets->queueAccessUnit(abuf);
- formatChange = false;
- seeking = false;
- ++numBuffers;
- extractor->advance();
-
- }
-
- if (mIsStreaming
- && (trackType == MEDIA_TRACK_TYPE_VIDEO || trackType == MEDIA_TRACK_TYPE_AUDIO)) {
- status_t finalResult;
- int64_t durationUs = track->mPackets->getBufferedDurationUs(&finalResult);
-
- // TODO: maxRebufferingMarkMs could be larger than
- // mBufferingSettings.mResumePlaybackMarkMs
- int64_t markUs = (mPreparing ? mBufferingSettings.mInitialMarkMs
- : mBufferingSettings.mResumePlaybackMarkMs) * 1000ll;
- if (finalResult == ERROR_END_OF_STREAM || durationUs >= markUs) {
- if (mPreparing || mSentPauseOnBuffering) {
- Track *counterTrack =
- (trackType == MEDIA_TRACK_TYPE_VIDEO ? &mAudioTrack : &mVideoTrack);
- if (counterTrack->mExtractor != NULL) {
- durationUs = counterTrack->mPackets->getBufferedDurationUs(&finalResult);
- }
- if (finalResult == ERROR_END_OF_STREAM || durationUs >= markUs) {
- if (mPreparing) {
- notifyPrepared();
- mPreparing = false;
- } else {
- mSentPauseOnBuffering = false;
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatResumeOnBufferingEnd);
- notify->post();
- }
- }
- }
- return;
- }
-
- postReadBuffer(trackType);
- }
-}
-
-void NuPlayer2::GenericSource2::queueDiscontinuityIfNeeded(
- bool seeking, bool formatChange, media_track_type trackType, Track *track) {
- // formatChange && seeking: track whose source is changed during selection
- // formatChange && !seeking: track whose source is not changed during selection
- // !formatChange: normal seek
- if ((seeking || formatChange)
- && (trackType == MEDIA_TRACK_TYPE_AUDIO
- || trackType == MEDIA_TRACK_TYPE_VIDEO)) {
- ATSParser::DiscontinuityType type = (formatChange && seeking)
- ? ATSParser::DISCONTINUITY_FORMATCHANGE
- : ATSParser::DISCONTINUITY_NONE;
- track->mPackets->queueDiscontinuity(type, NULL /* extra */, true /* discard */);
- }
-}
-
-void NuPlayer2::GenericSource2::notifyBufferingUpdate(int32_t percentage) {
- // Buffering percent could go backward as it's estimated from remaining
- // data and last access time. This could cause the buffering position
- // drawn on media control to jitter slightly. Remember previously reported
- // percentage and don't allow it to go backward.
- if (percentage < mPrevBufferPercentage) {
- percentage = mPrevBufferPercentage;
- } else if (percentage > 100) {
- percentage = 100;
- }
-
- mPrevBufferPercentage = percentage;
-
- ALOGV("notifyBufferingUpdate: buffering %d%%", percentage);
-
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatBufferingUpdate);
- notify->setInt32("percentage", percentage);
- notify->post();
-}
-
-void NuPlayer2::GenericSource2::schedulePollBuffering() {
- if (mIsStreaming) {
- sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
- msg->setInt32("generation", mPollBufferingGeneration);
- // Enquires buffering status every second.
- msg->post(1000000ll);
- }
-}
-
-void NuPlayer2::GenericSource2::onPollBuffering() {
- int64_t cachedDurationUs = -1ll;
-
- sp<AMediaExtractorWrapper> extractor;
- if (mVideoTrack.mExtractor != NULL) {
- extractor = mVideoTrack.mExtractor;
- } else if (mAudioTrack.mExtractor != NULL) {
- extractor = mAudioTrack.mExtractor;
- }
-
- if (extractor != NULL) {
- cachedDurationUs = extractor->getCachedDuration();
- }
-
- if (cachedDurationUs >= 0ll) {
- ssize_t sampleSize = extractor->getSampleSize();
- if (sampleSize >= 0ll) {
- int64_t cachedPosUs = getLastReadPosition() + cachedDurationUs;
- int percentage = 100.0 * cachedPosUs / mDurationUs;
- if (percentage > 100) {
- percentage = 100;
- }
-
- notifyBufferingUpdate(percentage);
- ALOGV("onPollBuffering: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f);
- } else {
- notifyBufferingUpdate(100);
- ALOGV("onPollBuffering: EOS");
- }
- }
-
- schedulePollBuffering();
-}
-
-// Modular DRM
-status_t NuPlayer2::GenericSource2::prepareDrm(
- const uint8_t uuid[16],
- const Vector<uint8_t> &drmSessionId,
- sp<AMediaCryptoWrapper> *outCrypto) {
- Mutex::Autolock _l(mLock);
- ALOGV("prepareDrm");
-
- mIsDrmProtected = false;
- mIsDrmReleased = false;
- mIsSecure = false;
-
- status_t status = OK;
- sp<AMediaCryptoWrapper> crypto =
- new AMediaCryptoWrapper(uuid, drmSessionId.array(), drmSessionId.size());
- if (crypto == NULL) {
- ALOGE("prepareDrm: failed to create crypto.");
- return UNKNOWN_ERROR;
- }
- ALOGV("prepareDrm: crypto created for uuid: %s",
- DrmUUID::toHexString(uuid).string());
-
- *outCrypto = crypto;
- // as long a there is an active crypto
- mIsDrmProtected = true;
-
- if (mMimes.size() == 0) {
- status = UNKNOWN_ERROR;
- ALOGE("prepareDrm: Unexpected. Must have at least one track. status: %d", status);
- return status;
- }
-
- // first mime in this list is either the video track, or the first audio track
- const char *mime = mMimes[0].string();
- mIsSecure = crypto->requiresSecureDecoderComponent(mime);
- ALOGV("prepareDrm: requiresSecureDecoderComponent mime: %s isSecure: %d",
- mime, mIsSecure);
-
- // Checking the member flags while in the looper to send out the notification.
- // The legacy mDecryptHandle!=NULL check (for FLAG_PROTECTED) is equivalent to mIsDrmProtected.
- notifyFlagsChanged(
- (mIsSecure ? FLAG_SECURE : 0) |
- // Setting "protected screen" only for L1: b/38390836
- (mIsSecure ? FLAG_PROTECTED : 0) |
- FLAG_CAN_PAUSE |
- FLAG_CAN_SEEK_BACKWARD |
- FLAG_CAN_SEEK_FORWARD |
- FLAG_CAN_SEEK);
-
- if (status == OK) {
- ALOGV("prepareDrm: mCrypto: %p", outCrypto->get());
- ALOGD("prepareDrm ret: %d ", status);
- } else {
- ALOGE("prepareDrm err: %d", status);
- }
- return status;
-}
-
-status_t NuPlayer2::GenericSource2::releaseDrm() {
- Mutex::Autolock _l(mLock);
- ALOGV("releaseDrm");
-
- if (mIsDrmProtected) {
- mIsDrmProtected = false;
- // to prevent returning any more buffer after stop/releaseDrm (b/37960096)
- mIsDrmReleased = true;
- ALOGV("releaseDrm: mIsDrmProtected is reset.");
- } else {
- ALOGE("releaseDrm: mIsDrmProtected is already false.");
- }
-
- return OK;
-}
-
-status_t NuPlayer2::GenericSource2::checkDrmInfo()
-{
- // clearing the flag at prepare in case the player is reused after stop/releaseDrm with the
- // same source without being reset (called by prepareAsync/initFromDataSource)
- mIsDrmReleased = false;
-
- if (mExtractor == NULL) {
- ALOGV("checkDrmInfo: No extractor");
- return OK; // letting the caller responds accordingly
- }
-
- PsshInfo *psshInfo = mExtractor->getPsshInfo();
- if (psshInfo == NULL) {
- ALOGV("checkDrmInfo: No PSSH");
- return OK; // source without DRM info
- }
-
- PlayerMessage playerMsg;
- status_t ret = NuPlayer2Drm::retrieveDrmInfo(psshInfo, &playerMsg);
- ALOGV("checkDrmInfo: MEDIA_DRM_INFO PSSH drm info size: %d", (int)playerMsg.ByteSize());
-
- if (ret != OK) {
- ALOGE("checkDrmInfo: failed to retrive DrmInfo %d", ret);
- return UNKNOWN_ERROR;
- }
-
- int size = playerMsg.ByteSize();
- sp<ABuffer> drmInfoBuf = new ABuffer(size);
- playerMsg.SerializeToArray(drmInfoBuf->data(), size);
- drmInfoBuf->setRange(0, size);
- notifyDrmInfo(drmInfoBuf);
-
- return OK;
-}
-
-void NuPlayer2::GenericSource2::signalBufferReturned(MediaBufferBase *buffer)
-{
- //ALOGV("signalBufferReturned %p refCount: %d", buffer, buffer->localRefcount());
-
- buffer->setObserver(NULL);
- buffer->release(); // this leads to delete since that there is no observor
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/GenericSource2.h b/media/libmediaplayer2/nuplayer2/GenericSource2.h
deleted file mode 100644
index ade1aa3..0000000
--- a/media/libmediaplayer2/nuplayer2/GenericSource2.h
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef GENERIC_SOURCE2_H_
-
-#define GENERIC_SOURCE2_H_
-
-#include "NuPlayer2.h"
-#include "NuPlayer2Source.h"
-
-#include "ATSParser.h"
-
-#include <media/stagefright/MediaBuffer.h>
-#include <mediaplayer2/mediaplayer2.h>
-#include <media/NdkMediaDataSource.h>
-#include <media/NdkMediaExtractor.h>
-#include <media/NdkWrapper.h>
-
-namespace android {
-
-class DecryptHandle;
-struct AnotherPacketSource;
-struct ARTSPController;
-class DataSource;
-class IDataSource;
-class IMediaSource;
-struct MediaSource;
-class MediaBuffer;
-struct MediaClock;
-
-struct NuPlayer2::GenericSource2 : public NuPlayer2::Source,
- public MediaBufferObserver // Modular DRM
-{
- GenericSource2(const sp<AMessage> ¬ify, uid_t uid,
- const sp<MediaClock> &mediaClock);
-
- status_t setDataSource(
- const char *url,
- const KeyedVector<String8, String8> *headers);
-
- status_t setDataSource(int fd, int64_t offset, int64_t length);
-
- status_t setDataSource(const sp<DataSource>& dataSource);
-
- virtual status_t getBufferingSettings(
- BufferingSettings* buffering /* nonnull */) override;
- virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
-
- virtual void prepareAsync(int64_t startTimeUs);
-
- virtual void start();
- virtual void stop();
- virtual void pause();
- virtual void resume();
-
- virtual void disconnect();
-
- virtual status_t feedMoreTSData();
-
- virtual sp<MetaData> getFileFormatMeta() const;
-
- virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
-
- virtual status_t getDuration(int64_t *durationUs);
- virtual size_t getTrackCount() const;
- virtual sp<AMessage> getTrackInfo(size_t trackIndex) const;
- virtual ssize_t getSelectedTrack(media_track_type type) const;
- virtual status_t selectTrack(size_t trackIndex, bool select, int64_t timeUs);
- virtual status_t seekTo(
- int64_t seekTimeUs,
- MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC) override;
-
- virtual bool isStreaming() const;
-
- // Modular DRM
- virtual void signalBufferReturned(MediaBufferBase *buffer);
-
- virtual status_t prepareDrm(
- const uint8_t uuid[16],
- const Vector<uint8_t> &drmSessionId,
- sp<AMediaCryptoWrapper> *outCrypto);
-
- virtual status_t releaseDrm();
-
-
-protected:
- virtual ~GenericSource2();
-
- virtual void onMessageReceived(const sp<AMessage> &msg);
-
- virtual sp<AMessage> getFormat(bool audio);
- virtual sp<MetaData> getFormatMeta(bool audio);
-
-private:
- enum {
- kWhatPrepareAsync,
- kWhatFetchSubtitleData,
- kWhatFetchTimedTextData,
- kWhatSendSubtitleData,
- kWhatSendGlobalTimedTextData,
- kWhatSendTimedTextData,
- kWhatChangeAVSource,
- kWhatPollBuffering,
- kWhatSeek,
- kWhatReadBuffer,
- kWhatStart,
- kWhatResume,
- kWhatSecureDecodersInstantiated,
- };
-
- struct Track {
- size_t mIndex;
- sp<AMediaExtractorWrapper> mExtractor;
- sp<AnotherPacketSource> mPackets;
- };
-
- int64_t mAudioTimeUs;
- int64_t mAudioLastDequeueTimeUs;
- int64_t mVideoTimeUs;
- int64_t mVideoLastDequeueTimeUs;
-
- BufferingSettings mBufferingSettings;
- int32_t mPrevBufferPercentage;
- int32_t mPollBufferingGeneration;
- bool mSentPauseOnBuffering;
-
- int32_t mAudioDataGeneration;
- int32_t mVideoDataGeneration;
- int32_t mFetchSubtitleDataGeneration;
- int32_t mFetchTimedTextDataGeneration;
- int64_t mDurationUs;
- bool mAudioIsVorbis;
- // Secure codec is required.
- bool mIsSecure;
- bool mIsStreaming;
- uid_t mUID;
- const sp<MediaClock> mMediaClock;
- AString mUri;
- KeyedVector<String8, String8> mUriHeaders;
- int mFd;
- int64_t mOffset;
- int64_t mLength;
-
- bool mDisconnected;
- sp<MetaData> mFileMeta;
- sp<AMediaDataSourceWrapper> mDataSourceWrapper;
- sp<AMediaExtractorWrapper> mExtractor;
- Vector<sp<AMediaExtractorWrapper> > mExtractors;
- bool mStarted;
- bool mPreparing;
- int64_t mBitrate;
- uint32_t mPendingReadBufferTypes;
- sp<ABuffer> mGlobalTimedText;
-
- Track mVideoTrack;
- Track mAudioTrack;
- Track mSubtitleTrack;
- Track mTimedTextTrack;
-
- mutable Mutex mLock;
-
- sp<ALooper> mLooper;
-
- void resetDataSource();
-
- status_t initFromDataSource();
- int64_t getLastReadPosition();
-
- void notifyPreparedAndCleanup(status_t err);
- void onSecureDecodersInstantiated(status_t err);
- void finishPrepareAsync();
- status_t startSources();
-
- void onSeek(const sp<AMessage>& msg);
- status_t doSeek(int64_t seekTimeUs, MediaPlayer2SeekMode mode);
-
- void onPrepareAsync(int64_t startTimeUs);
-
- void fetchTextData(
- uint32_t what, media_track_type type,
- int32_t curGen, const sp<AnotherPacketSource>& packets, const sp<AMessage>& msg);
-
- void sendGlobalTextData(
- uint32_t what,
- int32_t curGen, sp<AMessage> msg);
-
- void sendTextData(
- uint32_t what, media_track_type type,
- int32_t curGen, const sp<AnotherPacketSource>& packets, const sp<AMessage>& msg);
-
- sp<ABuffer> mediaBufferToABuffer(
- MediaBufferBase *mbuf,
- media_track_type trackType);
-
- void postReadBuffer(media_track_type trackType);
- void onReadBuffer(const sp<AMessage>& msg);
- // When |mode| is MediaPlayer2SeekMode::SEEK_CLOSEST, the buffer read shall
- // include an item indicating skipping rendering all buffers with timestamp
- // earlier than |seekTimeUs|.
- // For other modes, the buffer read will not include the item as above in order
- // to facilitate fast seek operation.
- void readBuffer(
- media_track_type trackType,
- int64_t seekTimeUs = -1ll,
- MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC,
- int64_t *actualTimeUs = NULL, bool formatChange = false);
-
- void queueDiscontinuityIfNeeded(
- bool seeking, bool formatChange, media_track_type trackType, Track *track);
-
- void schedulePollBuffering();
- void onPollBuffering();
- void notifyBufferingUpdate(int32_t percentage);
-
- sp<AMessage> getFormat_l(bool audio);
- sp<MetaData> getFormatMeta_l(bool audio);
- int32_t getDataGeneration(media_track_type type) const;
-
- // Modular DRM
- // The source is DRM protected and is prepared for DRM.
- bool mIsDrmProtected;
- // releaseDrm has been processed.
- bool mIsDrmReleased;
- Vector<String8> mMimes;
-
- status_t checkDrmInfo();
-
- DISALLOW_EVIL_CONSTRUCTORS(GenericSource2);
-};
-
-} // namespace android
-
-#endif // GENERIC_SOURCE2_H_
diff --git a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp b/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp
deleted file mode 100644
index e53900b..0000000
--- a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp
+++ /dev/null
@@ -1,450 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "HTTPLiveSource2"
-#include <utils/Log.h>
-
-#include "HTTPLiveSource2.h"
-
-#include "AnotherPacketSource.h"
-#include "LiveDataSource.h"
-
-#include <media/MediaHTTPService.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/Utils.h>
-
-// default buffer prepare/ready/underflow marks
-static const int kReadyMarkMs = 5000; // 5 seconds
-static const int kPrepareMarkMs = 1500; // 1.5 seconds
-
-namespace android {
-
-NuPlayer2::HTTPLiveSource2::HTTPLiveSource2(
- const sp<AMessage> ¬ify,
- const sp<MediaHTTPService> &httpService,
- const char *url,
- const KeyedVector<String8, String8> *headers)
- : Source(notify),
- mHTTPService(httpService),
- mURL(url),
- mFlags(0),
- mFinalResult(OK),
- mOffset(0),
- mFetchSubtitleDataGeneration(0),
- mFetchMetaDataGeneration(0),
- mHasMetadata(false),
- mMetadataSelected(false) {
- mBufferingSettings.mInitialMarkMs = kPrepareMarkMs;
- mBufferingSettings.mResumePlaybackMarkMs = kReadyMarkMs;
- if (headers) {
- mExtraHeaders = *headers;
-
- ssize_t index =
- mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log"));
-
- if (index >= 0) {
- mFlags |= kFlagIncognito;
-
- mExtraHeaders.removeItemsAt(index);
- }
- }
-}
-
-NuPlayer2::HTTPLiveSource2::~HTTPLiveSource2() {
- if (mLiveSession != NULL) {
- mLiveSession->disconnect();
-
- mLiveLooper->unregisterHandler(mLiveSession->id());
- mLiveLooper->unregisterHandler(id());
- mLiveLooper->stop();
-
- mLiveSession.clear();
- mLiveLooper.clear();
- }
-}
-
-status_t NuPlayer2::HTTPLiveSource2::getBufferingSettings(
- BufferingSettings* buffering /* nonnull */) {
- *buffering = mBufferingSettings;
-
- return OK;
-}
-
-status_t NuPlayer2::HTTPLiveSource2::setBufferingSettings(const BufferingSettings& buffering) {
- mBufferingSettings = buffering;
-
- if (mLiveSession != NULL) {
- mLiveSession->setBufferingSettings(mBufferingSettings);
- }
-
- return OK;
-}
-
-// TODO: fetch data starting from |startTimeUs|
-void NuPlayer2::HTTPLiveSource2::prepareAsync(int64_t /* startTimeUs */) {
- if (mLiveLooper == NULL) {
- mLiveLooper = new ALooper;
- mLiveLooper->setName("http live2");
- mLiveLooper->start(false, /* runOnCallingThread */
- true /* canCallJava */);
-
- mLiveLooper->registerHandler(this);
- }
-
- sp<AMessage> notify = new AMessage(kWhatSessionNotify, this);
-
- mLiveSession = new LiveSession(
- notify,
- (mFlags & kFlagIncognito) ? LiveSession::kFlagIncognito : 0,
- mHTTPService);
-
- mLiveLooper->registerHandler(mLiveSession);
-
- mLiveSession->setBufferingSettings(mBufferingSettings);
- mLiveSession->connectAsync(
- mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
-}
-
-void NuPlayer2::HTTPLiveSource2::start() {
-}
-
-sp<MetaData> NuPlayer2::HTTPLiveSource2::getFormatMeta(bool audio) {
- sp<MetaData> meta;
- if (mLiveSession != NULL) {
- mLiveSession->getStreamFormatMeta(
- audio ? LiveSession::STREAMTYPE_AUDIO
- : LiveSession::STREAMTYPE_VIDEO,
- &meta);
- }
-
- return meta;
-}
-
-sp<AMessage> NuPlayer2::HTTPLiveSource2::getFormat(bool audio) {
- sp<MetaData> meta;
- status_t err = -EWOULDBLOCK;
- if (mLiveSession != NULL) {
- err = mLiveSession->getStreamFormatMeta(
- audio ? LiveSession::STREAMTYPE_AUDIO
- : LiveSession::STREAMTYPE_VIDEO,
- &meta);
- }
-
- sp<AMessage> format;
- if (err == -EWOULDBLOCK) {
- format = new AMessage();
- format->setInt32("err", err);
- return format;
- }
-
- if (err != OK || convertMetaDataToMessage(meta, &format) != OK) {
- return NULL;
- }
- return format;
-}
-
-status_t NuPlayer2::HTTPLiveSource2::feedMoreTSData() {
- return OK;
-}
-
-status_t NuPlayer2::HTTPLiveSource2::dequeueAccessUnit(
- bool audio, sp<ABuffer> *accessUnit) {
- return mLiveSession->dequeueAccessUnit(
- audio ? LiveSession::STREAMTYPE_AUDIO
- : LiveSession::STREAMTYPE_VIDEO,
- accessUnit);
-}
-
-status_t NuPlayer2::HTTPLiveSource2::getDuration(int64_t *durationUs) {
- return mLiveSession->getDuration(durationUs);
-}
-
-size_t NuPlayer2::HTTPLiveSource2::getTrackCount() const {
- return mLiveSession->getTrackCount();
-}
-
-sp<AMessage> NuPlayer2::HTTPLiveSource2::getTrackInfo(size_t trackIndex) const {
- return mLiveSession->getTrackInfo(trackIndex);
-}
-
-ssize_t NuPlayer2::HTTPLiveSource2::getSelectedTrack(media_track_type type) const {
- if (mLiveSession == NULL) {
- return -1;
- } else if (type == MEDIA_TRACK_TYPE_METADATA) {
- // MEDIA_TRACK_TYPE_METADATA is always last track
- // mMetadataSelected can only be true when mHasMetadata is true
- return mMetadataSelected ? (mLiveSession->getTrackCount() - 1) : -1;
- } else {
- return mLiveSession->getSelectedTrack(type);
- }
-}
-
-status_t NuPlayer2::HTTPLiveSource2::selectTrack(size_t trackIndex, bool select, int64_t /*timeUs*/) {
- if (mLiveSession == NULL) {
- return INVALID_OPERATION;
- }
-
- status_t err = INVALID_OPERATION;
- bool postFetchMsg = false, isSub = false;
- if (!mHasMetadata || trackIndex != mLiveSession->getTrackCount() - 1) {
- err = mLiveSession->selectTrack(trackIndex, select);
- postFetchMsg = select;
- isSub = true;
- } else {
- // metadata track; i.e. (mHasMetadata && trackIndex == mLiveSession->getTrackCount() - 1)
- if (mMetadataSelected && !select) {
- err = OK;
- } else if (!mMetadataSelected && select) {
- postFetchMsg = true;
- err = OK;
- } else {
- err = BAD_VALUE; // behave as LiveSession::selectTrack
- }
-
- mMetadataSelected = select;
- }
-
- if (err == OK) {
- int32_t &generation = isSub ? mFetchSubtitleDataGeneration : mFetchMetaDataGeneration;
- generation++;
- if (postFetchMsg) {
- int32_t what = isSub ? kWhatFetchSubtitleData : kWhatFetchMetaData;
- sp<AMessage> msg = new AMessage(what, this);
- msg->setInt32("generation", generation);
- msg->post();
- }
- }
-
- // LiveSession::selectTrack returns BAD_VALUE when selecting the currently
- // selected track, or unselecting a non-selected track. In this case it's an
- // no-op so we return OK.
- return (err == OK || err == BAD_VALUE) ? (status_t)OK : err;
-}
-
-status_t NuPlayer2::HTTPLiveSource2::seekTo(int64_t seekTimeUs, MediaPlayer2SeekMode mode) {
- if (mLiveSession->isSeekable()) {
- return mLiveSession->seekTo(seekTimeUs, mode);
- } else {
- return INVALID_OPERATION;
- }
-}
-
-void NuPlayer2::HTTPLiveSource2::pollForRawData(
- const sp<AMessage> &msg, int32_t currentGeneration,
- LiveSession::StreamType fetchType, int32_t pushWhat) {
-
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
-
- if (generation != currentGeneration) {
- return;
- }
-
- sp<ABuffer> buffer;
- while (mLiveSession->dequeueAccessUnit(fetchType, &buffer) == OK) {
-
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", pushWhat);
- notify->setBuffer("buffer", buffer);
-
- int64_t timeUs, baseUs, delayUs;
- CHECK(buffer->meta()->findInt64("baseUs", &baseUs));
- CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
- delayUs = baseUs + timeUs - ALooper::GetNowUs();
-
- if (fetchType == LiveSession::STREAMTYPE_SUBTITLES) {
- notify->post();
- msg->post(delayUs > 0LL ? delayUs : 0LL);
- return;
- } else if (fetchType == LiveSession::STREAMTYPE_METADATA) {
- if (delayUs < -1000000LL) { // 1 second
- continue;
- }
- notify->post();
- // push all currently available metadata buffers in each invocation of pollForRawData
- // continue;
- } else {
- TRESPASS();
- }
- }
-
- // try again in 1 second
- msg->post(1000000LL);
-}
-
-void NuPlayer2::HTTPLiveSource2::onMessageReceived(const sp<AMessage> &msg) {
- switch (msg->what()) {
- case kWhatSessionNotify:
- {
- onSessionNotify(msg);
- break;
- }
-
- case kWhatFetchSubtitleData:
- {
- pollForRawData(
- msg, mFetchSubtitleDataGeneration,
- /* fetch */ LiveSession::STREAMTYPE_SUBTITLES,
- /* push */ kWhatSubtitleData);
-
- break;
- }
-
- case kWhatFetchMetaData:
- {
- if (!mMetadataSelected) {
- break;
- }
-
- pollForRawData(
- msg, mFetchMetaDataGeneration,
- /* fetch */ LiveSession::STREAMTYPE_METADATA,
- /* push */ kWhatTimedMetaData);
-
- break;
- }
-
- default:
- Source::onMessageReceived(msg);
- break;
- }
-}
-
-void NuPlayer2::HTTPLiveSource2::onSessionNotify(const sp<AMessage> &msg) {
- int32_t what;
- CHECK(msg->findInt32("what", &what));
-
- switch (what) {
- case LiveSession::kWhatPrepared:
- {
- // notify the current size here if we have it, otherwise report an initial size of (0,0)
- sp<AMessage> format = getFormat(false /* audio */);
- int32_t width;
- int32_t height;
- if (format != NULL &&
- format->findInt32("width", &width) && format->findInt32("height", &height)) {
- notifyVideoSizeChanged(format);
- } else {
- notifyVideoSizeChanged();
- }
-
- uint32_t flags = 0;
- if (mLiveSession->isSeekable()) {
- flags |= FLAG_CAN_PAUSE;
- flags |= FLAG_CAN_SEEK;
- flags |= FLAG_CAN_SEEK_BACKWARD;
- flags |= FLAG_CAN_SEEK_FORWARD;
- }
-
- if (mLiveSession->hasDynamicDuration()) {
- flags |= FLAG_DYNAMIC_DURATION;
- }
-
- notifyFlagsChanged(flags);
-
- notifyPrepared();
- break;
- }
-
- case LiveSession::kWhatPreparationFailed:
- {
- status_t err;
- CHECK(msg->findInt32("err", &err));
-
- notifyPrepared(err);
- break;
- }
-
- case LiveSession::kWhatStreamsChanged:
- {
- uint32_t changedMask;
- CHECK(msg->findInt32(
- "changedMask", (int32_t *)&changedMask));
-
- bool audio = changedMask & LiveSession::STREAMTYPE_AUDIO;
- bool video = changedMask & LiveSession::STREAMTYPE_VIDEO;
-
- sp<AMessage> reply;
- CHECK(msg->findMessage("reply", &reply));
-
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatQueueDecoderShutdown);
- notify->setInt32("audio", audio);
- notify->setInt32("video", video);
- notify->setMessage("reply", reply);
- notify->post();
- break;
- }
-
- case LiveSession::kWhatBufferingStart:
- {
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatPauseOnBufferingStart);
- notify->post();
- break;
- }
-
- case LiveSession::kWhatBufferingEnd:
- {
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatResumeOnBufferingEnd);
- notify->post();
- break;
- }
-
-
- case LiveSession::kWhatBufferingUpdate:
- {
- sp<AMessage> notify = dupNotify();
- int32_t percentage;
- CHECK(msg->findInt32("percentage", &percentage));
- notify->setInt32("what", kWhatBufferingUpdate);
- notify->setInt32("percentage", percentage);
- notify->post();
- break;
- }
-
- case LiveSession::kWhatMetadataDetected:
- {
- if (!mHasMetadata) {
- mHasMetadata = true;
-
- sp<AMessage> notify = dupNotify();
- // notification without buffer triggers MEDIA2_INFO_METADATA_UPDATE
- notify->setInt32("what", kWhatTimedMetaData);
- notify->post();
- }
- break;
- }
-
- case LiveSession::kWhatError:
- {
- break;
- }
-
- default:
- TRESPASS();
- }
-}
-
-} // namespace android
-
diff --git a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h b/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h
deleted file mode 100644
index 8fc71e2..0000000
--- a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef HTTP_LIVE_SOURCE2_H_
-
-#define HTTP_LIVE_SOURCE2_H_
-
-#include "NuPlayer2.h"
-#include "NuPlayer2Source.h"
-
-#include "LiveSession.h"
-
-namespace android {
-
-struct LiveSession;
-
-struct NuPlayer2::HTTPLiveSource2 : public NuPlayer2::Source {
- HTTPLiveSource2(
- const sp<AMessage> ¬ify,
- const sp<MediaHTTPService> &httpService,
- const char *url,
- const KeyedVector<String8, String8> *headers);
-
- virtual status_t getBufferingSettings(
- BufferingSettings* buffering /* nonnull */) override;
- virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
-
- virtual void prepareAsync(int64_t startTimeUs);
- virtual void start();
-
- virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
- virtual sp<MetaData> getFormatMeta(bool audio);
- virtual sp<AMessage> getFormat(bool audio);
-
- virtual status_t feedMoreTSData();
- virtual status_t getDuration(int64_t *durationUs);
- virtual size_t getTrackCount() const;
- virtual sp<AMessage> getTrackInfo(size_t trackIndex) const;
- virtual ssize_t getSelectedTrack(media_track_type /* type */) const;
- virtual status_t selectTrack(size_t trackIndex, bool select, int64_t timeUs);
- virtual status_t seekTo(
- int64_t seekTimeUs,
- MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC) override;
-
-protected:
- virtual ~HTTPLiveSource2();
-
- virtual void onMessageReceived(const sp<AMessage> &msg);
-
-private:
- enum Flags {
- // Don't log any URLs.
- kFlagIncognito = 1,
- };
-
- enum {
- kWhatSessionNotify,
- kWhatFetchSubtitleData,
- kWhatFetchMetaData,
- };
-
- sp<MediaHTTPService> mHTTPService;
- AString mURL;
- KeyedVector<String8, String8> mExtraHeaders;
- uint32_t mFlags;
- status_t mFinalResult;
- off64_t mOffset;
- sp<ALooper> mLiveLooper;
- sp<LiveSession> mLiveSession;
- int32_t mFetchSubtitleDataGeneration;
- int32_t mFetchMetaDataGeneration;
- bool mHasMetadata;
- bool mMetadataSelected;
- BufferingSettings mBufferingSettings;
-
- void onSessionNotify(const sp<AMessage> &msg);
- void pollForRawData(
- const sp<AMessage> &msg, int32_t currentGeneration,
- LiveSession::StreamType fetchType, int32_t pushWhat);
-
- DISALLOW_EVIL_CONSTRUCTORS(HTTPLiveSource2);
-};
-
-} // namespace android
-
-#endif // HTTP_LIVE_SOURCE2_H_
diff --git a/media/libmediaplayer2/nuplayer2/JMediaPlayer2Utils.cpp b/media/libmediaplayer2/nuplayer2/JMediaPlayer2Utils.cpp
deleted file mode 100644
index 89703de..0000000
--- a/media/libmediaplayer2/nuplayer2/JMediaPlayer2Utils.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "JMediaPlayer2Utils"
-
-#include "JMediaPlayer2Utils.h"
-#include <mediaplayer2/JavaVMHelper.h>
-
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/Utils.h>
-#include <utils/Log.h>
-
-#include "log/log.h"
-
-namespace android {
-
-static const int64_t kOffloadMinDurationSec = 60;
-
-// static
-bool JMediaPlayer2Utils::isOffloadedAudioPlaybackSupported(
- const sp<MetaData>& meta, bool hasVideo, bool isStreaming, audio_stream_type_t streamType)
-{
- if (hasVideo || streamType != AUDIO_STREAM_MUSIC) {
- return false;
- }
-
- audio_offload_info_t info = AUDIO_INFO_INITIALIZER;
- if (OK != getAudioOffloadInfo(meta, hasVideo, isStreaming, streamType, &info)) {
- return false;
- }
-
- if (info.duration_us < kOffloadMinDurationSec * 1000000) {
- return false;
- }
-
- int32_t audioFormat = audioFormatFromNative(info.format);
- int32_t channelMask = outChannelMaskFromNative(info.channel_mask);
- if (audioFormat == ENCODING_INVALID || channelMask == CHANNEL_INVALID) {
- return false;
- }
-
- JNIEnv* env = JavaVMHelper::getJNIEnv();
- jclass jMP2UtilsCls = env->FindClass("android/media/MediaPlayer2Utils");
- jmethodID jSetAudioOutputDeviceById = env->GetStaticMethodID(
- jMP2UtilsCls, "isOffloadedAudioPlaybackSupported", "(III)Z");
- jboolean result = env->CallStaticBooleanMethod(
- jMP2UtilsCls, jSetAudioOutputDeviceById, audioFormat, info.sample_rate, channelMask);
- return result;
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/JMediaPlayer2Utils.h b/media/libmediaplayer2/nuplayer2/JMediaPlayer2Utils.h
deleted file mode 100644
index fcbd43c..0000000
--- a/media/libmediaplayer2/nuplayer2/JMediaPlayer2Utils.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _J_MEDIAPLAYER2_UTILS2_H_
-#define _J_MEDIAPLAYER2_UTILS2_H_
-
-#include <media/stagefright/MetaData.h>
-
-#include "jni.h"
-#include "android_media_AudioFormat.h"
-
-namespace android {
-
-struct JMediaPlayer2Utils {
- static bool isOffloadedAudioPlaybackSupported(
- const sp<MetaData>& meta, bool hasVideo, bool isStreaming,
- audio_stream_type_t streamType);
-};
-
-} // namespace android
-
-#endif // _J_MEDIAPLAYER2_UTILS2_H_
diff --git a/media/libmediaplayer2/nuplayer2/JWakeLock.cpp b/media/libmediaplayer2/nuplayer2/JWakeLock.cpp
deleted file mode 100644
index 983d77e..0000000
--- a/media/libmediaplayer2/nuplayer2/JWakeLock.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "JWakeLock"
-#include <utils/Log.h>
-
-#include "JWakeLock.h"
-
-#include <media/stagefright/foundation/ADebug.h>
-
-namespace android {
-
-JWakeLock::JWakeLock(const sp<JObjectHolder> &context) :
- mWakeLockCount(0),
- mWakeLock(NULL),
- mContext(context) {}
-
-JWakeLock::~JWakeLock() {
- clearJavaWakeLock();
-}
-
-bool JWakeLock::acquire() {
- if (mWakeLockCount == 0) {
- if (mWakeLock == NULL) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jclass jContextCls = env->FindClass("android/content/Context");
- jclass jPowerManagerCls = env->FindClass("android/os/PowerManager");
-
- jmethodID jGetSystemService = env->GetMethodID(jContextCls,
- "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
- jobject javaPowerManagerObj = env->CallObjectMethod(mContext->getJObject(),
- jGetSystemService, env->NewStringUTF("power"));
-
- jfieldID jPARTIAL_WAKE_LOCK = env->GetStaticFieldID(jPowerManagerCls,
- "PARTIAL_WAKE_LOCK", "I");
- jint PARTIAL_WAKE_LOCK = env->GetStaticIntField(jPowerManagerCls, jPARTIAL_WAKE_LOCK);
-
- jmethodID jNewWakeLock = env->GetMethodID(jPowerManagerCls,
- "newWakeLock", "(ILjava/lang/String;)Landroid/os/PowerManager$WakeLock;");
- jobject javaWakeLock = env->CallObjectMethod(javaPowerManagerObj,
- jNewWakeLock, PARTIAL_WAKE_LOCK, env->NewStringUTF("JWakeLock"));
- mWakeLock = new JObjectHolder(javaWakeLock);
- env->DeleteLocalRef(javaPowerManagerObj);
- env->DeleteLocalRef(javaWakeLock);
- }
- if (mWakeLock != NULL) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jclass wakeLockCls = env->FindClass("android/os/PowerManager$WakeLock");
- jmethodID jAcquire = env->GetMethodID(wakeLockCls, "acquire", "()V");
- env->CallVoidMethod(mWakeLock->getJObject(), jAcquire);
- mWakeLockCount++;
- return true;
- }
- } else {
- mWakeLockCount++;
- return true;
- }
- return false;
-}
-
-void JWakeLock::release(bool force) {
- if (mWakeLockCount == 0) {
- return;
- }
- if (force) {
- // Force wakelock release below by setting reference count to 1.
- mWakeLockCount = 1;
- }
- if (--mWakeLockCount == 0) {
- if (mWakeLock != NULL) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jclass wakeLockCls = env->FindClass("android/os/PowerManager$WakeLock");
- jmethodID jRelease = env->GetMethodID(wakeLockCls, "release", "()V");
- env->CallVoidMethod(mWakeLock->getJObject(), jRelease);
- }
- }
-}
-
-void JWakeLock::clearJavaWakeLock() {
- release(true);
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/JWakeLock.h b/media/libmediaplayer2/nuplayer2/JWakeLock.h
deleted file mode 100644
index 36c542e..0000000
--- a/media/libmediaplayer2/nuplayer2/JWakeLock.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef J_WAKELOCK_H_
-#define J_WAKELOCK_H_
-
-#include <media/stagefright/foundation/ABase.h>
-#include <mediaplayer2/JObjectHolder.h>
-#include <utils/RefBase.h>
-
-namespace android {
-
-class JWakeLock : public RefBase {
-
-public:
- JWakeLock(const sp<JObjectHolder> &context);
-
- // NOTE: acquire and release are not thread safe
-
- // returns true if wakelock was acquired
- bool acquire();
- void release(bool force = false);
-
- virtual ~JWakeLock();
-
-private:
- uint32_t mWakeLockCount;
- sp<JObjectHolder> mWakeLock;
- const sp<JObjectHolder> mContext;
-
- void clearJavaWakeLock();
-
- DISALLOW_EVIL_CONSTRUCTORS(JWakeLock);
-};
-
-} // namespace android
-
-#endif // J_WAKELOCK_H_
diff --git a/media/libmediaplayer2/nuplayer2/NOTICE b/media/libmediaplayer2/nuplayer2/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/media/libmediaplayer2/nuplayer2/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
- Copyright (c) 2005-2008, 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.
-
- 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.
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
deleted file mode 100644
index d608d4a..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
+++ /dev/null
@@ -1,3308 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NuPlayer2"
-
-#include <inttypes.h>
-
-#include <utils/Log.h>
-
-#include "NuPlayer2.h"
-
-#include "HTTPLiveSource2.h"
-#include "JMediaPlayer2Utils.h"
-#include "NuPlayer2CCDecoder.h"
-#include "NuPlayer2Decoder.h"
-#include "NuPlayer2DecoderBase.h"
-#include "NuPlayer2DecoderPassThrough.h"
-#include "NuPlayer2Driver.h"
-#include "NuPlayer2Renderer.h"
-#include "NuPlayer2Source.h"
-#include "RTSPSource2.h"
-#include "GenericSource2.h"
-#include "TextDescriptions2.h"
-
-#include "ATSParser.h"
-
-#include <cutils/properties.h>
-
-#include <media/AudioParameter.h>
-#include <media/AudioResamplerPublic.h>
-#include <media/AVSyncSettings.h>
-#include <media/DataSourceDesc.h>
-#include <media/MediaCodecBuffer.h>
-#include <media/NdkWrapper.h>
-
-#include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/foundation/avc_utils.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaClock.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MetaData.h>
-
-#include "ESDS.h"
-#include <media/stagefright/Utils.h>
-
-#include <system/window.h>
-
-namespace android {
-
-static status_t sendMetaDataToHal(sp<MediaPlayer2Interface::AudioSink>& sink,
- const sp<MetaData>& meta) {
- int32_t sampleRate = 0;
- int32_t bitRate = 0;
- int32_t channelMask = 0;
- int32_t delaySamples = 0;
- int32_t paddingSamples = 0;
-
- AudioParameter param = AudioParameter();
-
- if (meta->findInt32(kKeySampleRate, &sampleRate)) {
- param.addInt(String8(AUDIO_OFFLOAD_CODEC_SAMPLE_RATE), sampleRate);
- }
- if (meta->findInt32(kKeyChannelMask, &channelMask)) {
- param.addInt(String8(AUDIO_OFFLOAD_CODEC_NUM_CHANNEL), channelMask);
- }
- if (meta->findInt32(kKeyBitRate, &bitRate)) {
- param.addInt(String8(AUDIO_OFFLOAD_CODEC_AVG_BIT_RATE), bitRate);
- }
- if (meta->findInt32(kKeyEncoderDelay, &delaySamples)) {
- param.addInt(String8(AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES), delaySamples);
- }
- if (meta->findInt32(kKeyEncoderPadding, &paddingSamples)) {
- param.addInt(String8(AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES), paddingSamples);
- }
-
- ALOGV("sendMetaDataToHal: bitRate %d, sampleRate %d, chanMask %d,"
- "delaySample %d, paddingSample %d", bitRate, sampleRate,
- channelMask, delaySamples, paddingSamples);
-
- sink->setParameters(param.toString());
- return OK;
-}
-
-
-struct NuPlayer2::Action : public RefBase {
- Action() {}
-
- virtual void execute(NuPlayer2 *player) = 0;
-
-private:
- DISALLOW_EVIL_CONSTRUCTORS(Action);
-};
-
-struct NuPlayer2::SeekAction : public Action {
- explicit SeekAction(int64_t seekTimeUs, MediaPlayer2SeekMode mode)
- : mSeekTimeUs(seekTimeUs),
- mMode(mode) {
- }
-
- virtual void execute(NuPlayer2 *player) {
- player->performSeek(mSeekTimeUs, mMode);
- }
-
-private:
- int64_t mSeekTimeUs;
- MediaPlayer2SeekMode mMode;
-
- DISALLOW_EVIL_CONSTRUCTORS(SeekAction);
-};
-
-struct NuPlayer2::ResumeDecoderAction : public Action {
- explicit ResumeDecoderAction(bool needNotify)
- : mNeedNotify(needNotify) {
- }
-
- virtual void execute(NuPlayer2 *player) {
- player->performResumeDecoders(mNeedNotify);
- }
-
-private:
- bool mNeedNotify;
-
- DISALLOW_EVIL_CONSTRUCTORS(ResumeDecoderAction);
-};
-
-struct NuPlayer2::SetSurfaceAction : public Action {
- explicit SetSurfaceAction(const sp<ANativeWindowWrapper> &nww)
- : mNativeWindow(nww) {
- }
-
- virtual void execute(NuPlayer2 *player) {
- player->performSetSurface(mNativeWindow);
- }
-
-private:
- sp<ANativeWindowWrapper> mNativeWindow;
-
- DISALLOW_EVIL_CONSTRUCTORS(SetSurfaceAction);
-};
-
-struct NuPlayer2::FlushDecoderAction : public Action {
- FlushDecoderAction(FlushCommand audio, FlushCommand video)
- : mAudio(audio),
- mVideo(video) {
- }
-
- virtual void execute(NuPlayer2 *player) {
- player->performDecoderFlush(mAudio, mVideo);
- }
-
-private:
- FlushCommand mAudio;
- FlushCommand mVideo;
-
- DISALLOW_EVIL_CONSTRUCTORS(FlushDecoderAction);
-};
-
-struct NuPlayer2::PostMessageAction : public Action {
- explicit PostMessageAction(const sp<AMessage> &msg)
- : mMessage(msg) {
- }
-
- virtual void execute(NuPlayer2 *) {
- mMessage->post();
- }
-
-private:
- sp<AMessage> mMessage;
-
- DISALLOW_EVIL_CONSTRUCTORS(PostMessageAction);
-};
-
-// Use this if there's no state necessary to save in order to execute
-// the action.
-struct NuPlayer2::SimpleAction : public Action {
- typedef void (NuPlayer2::*ActionFunc)();
-
- explicit SimpleAction(ActionFunc func)
- : mFunc(func) {
- }
-
- virtual void execute(NuPlayer2 *player) {
- (player->*mFunc)();
- }
-
-private:
- ActionFunc mFunc;
-
- DISALLOW_EVIL_CONSTRUCTORS(SimpleAction);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-NuPlayer2::NuPlayer2(
- pid_t pid, uid_t uid, const sp<MediaClock> &mediaClock, const sp<JObjectHolder> &context)
- : mPID(pid),
- mUID(uid),
- mMediaClock(mediaClock),
- mOffloadAudio(false),
- mAudioDecoderGeneration(0),
- mVideoDecoderGeneration(0),
- mRendererGeneration(0),
- mEOSMonitorGeneration(0),
- mLastStartedPlayingTimeNs(0),
- mPreviousSeekTimeUs(0),
- mAudioEOS(false),
- mVideoEOS(false),
- mScanSourcesPending(false),
- mScanSourcesGeneration(0),
- mPollDurationGeneration(0),
- mTimedTextGeneration(0),
- mFlushingAudio(NONE),
- mFlushingVideo(NONE),
- mResumePending(false),
- mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW),
- mPlaybackSettings(AUDIO_PLAYBACK_RATE_DEFAULT),
- mVideoFpsHint(-1.f),
- mStarted(false),
- mPrepared(false),
- mResetting(false),
- mSourceStarted(false),
- mAudioDecoderError(false),
- mVideoDecoderError(false),
- mPaused(false),
- mPausedByClient(true),
- mPausedForBuffering(false),
- mContext(context) {
- CHECK(mediaClock != NULL);
- clearFlushComplete();
-}
-
-NuPlayer2::~NuPlayer2() {
-}
-
-void NuPlayer2::setDriver(const wp<NuPlayer2Driver> &driver) {
- mDriver = driver;
-}
-
-static bool IsHTTPLiveURL(const char *url) {
- if (!strncasecmp("http://", url, 7)
- || !strncasecmp("https://", url, 8)
- || !strncasecmp("file://", url, 7)) {
- size_t len = strlen(url);
- if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
- return true;
- }
-
- if (strstr(url,"m3u8")) {
- return true;
- }
- }
-
- return false;
-}
-
-status_t NuPlayer2::createNuPlayer2Source(const sp<DataSourceDesc> &dsd,
- sp<Source> *source,
- DATA_SOURCE_TYPE *dataSourceType) {
- status_t err = NO_ERROR;
- sp<AMessage> notify = new AMessage(kWhatSourceNotify, this);
- notify->setInt64("srcId", dsd->mId);
-
- switch (dsd->mType) {
- case DataSourceDesc::TYPE_URL:
- {
- const char *url = dsd->mUrl.c_str();
- size_t len = strlen(url);
-
- const sp<MediaHTTPService> &httpService = dsd->mHttpService;
- KeyedVector<String8, String8> *headers = &(dsd->mHeaders);
-
- if (IsHTTPLiveURL(url)) {
- *source = new HTTPLiveSource2(notify, httpService, url, headers);
- ALOGV("createNuPlayer2Source HTTPLiveSource2 %s", url);
- *dataSourceType = DATA_SOURCE_TYPE_HTTP_LIVE;
- } else if (!strncasecmp(url, "rtsp://", 7)) {
- *source = new RTSPSource2(
- notify, httpService, url, headers, mUID);
- ALOGV("createNuPlayer2Source RTSPSource2 %s", url);
- *dataSourceType = DATA_SOURCE_TYPE_RTSP;
- } else if ((!strncasecmp(url, "http://", 7)
- || !strncasecmp(url, "https://", 8))
- && ((len >= 4 && !strcasecmp(".sdp", &url[len - 4]))
- || strstr(url, ".sdp?"))) {
- *source = new RTSPSource2(
- notify, httpService, url, headers, mUID, true);
- ALOGV("createNuPlayer2Source RTSPSource2 http/https/.sdp %s", url);
- *dataSourceType = DATA_SOURCE_TYPE_RTSP;
- } else {
- ALOGV("createNuPlayer2Source GenericSource2 %s", url);
-
- sp<GenericSource2> genericSource =
- new GenericSource2(notify, mUID, mMediaClock);
-
- err = genericSource->setDataSource(url, headers);
-
- if (err == OK) {
- *source = genericSource;
- } else {
- *source = NULL;
- ALOGE("Failed to create NuPlayer2Source!");
- }
-
- // regardless of success/failure
- *dataSourceType = DATA_SOURCE_TYPE_GENERIC_URL;
- }
- break;
- }
-
- case DataSourceDesc::TYPE_FD:
- {
- sp<GenericSource2> genericSource =
- new GenericSource2(notify, mUID, mMediaClock);
-
- ALOGV("createNuPlayer2Source fd %d/%lld/%lld source: %p",
- dsd->mFD, (long long)dsd->mFDOffset, (long long)dsd->mFDLength,
- genericSource.get());
-
- err = genericSource->setDataSource(dsd->mFD, dsd->mFDOffset, dsd->mFDLength);
-
- if (err != OK) {
- ALOGE("Failed to create NuPlayer2Source!");
- *source = NULL;
- } else {
- *source = genericSource;
- }
-
- *dataSourceType = DATA_SOURCE_TYPE_GENERIC_FD;
- break;
- }
-
- case DataSourceDesc::TYPE_CALLBACK:
- {
- sp<GenericSource2> genericSource =
- new GenericSource2(notify, mUID, mMediaClock);
- err = genericSource->setDataSource(dsd->mCallbackSource);
-
- if (err != OK) {
- ALOGE("Failed to create NuPlayer2Source!");
- *source = NULL;
- } else {
- *source = genericSource;
- }
-
- *dataSourceType = DATA_SOURCE_TYPE_MEDIA;
- break;
- }
-
- default:
- err = BAD_TYPE;
- *source = NULL;
- *dataSourceType = DATA_SOURCE_TYPE_NONE;
- ALOGE("invalid data source type!");
- break;
- }
-
- return err;
-}
-
-void NuPlayer2::setDataSourceAsync(const sp<DataSourceDesc> &dsd) {
- DATA_SOURCE_TYPE dataSourceType;
- sp<Source> source;
- createNuPlayer2Source(dsd, &source, &dataSourceType);
-
- // TODO: currently NuPlayer2Driver makes blocking call to setDataSourceAsync
- // and expects notifySetDataSourceCompleted regardless of success or failure.
- // This will be changed since setDataSource should be asynchronous at JAVA level.
- // When it succeeds, app will get onInfo notification. Otherwise, onError
- // will be called.
- /*
- if (err != OK) {
- notifyListener(dsd->mId, MEDIA2_ERROR, MEDIA2_ERROR_FAILED_TO_SET_DATA_SOURCE, err);
- return;
- }
-
- // Now, source != NULL.
- */
-
- mCurrentSourceInfo.mDataSourceType = dataSourceType;
-
- sp<AMessage> msg = new AMessage(kWhatSetDataSource, this);
- msg->setObject("source", source);
- msg->setInt64("srcId", dsd->mId);
- msg->setInt64("startTimeUs", dsd->mStartPositionMs * 1000);
- msg->setInt64("endTimeUs", dsd->mEndPositionMs * 1000);
- msg->post();
-}
-
-void NuPlayer2::prepareNextDataSourceAsync(const sp<DataSourceDesc> &dsd) {
- DATA_SOURCE_TYPE dataSourceType;
- sp<Source> source;
- createNuPlayer2Source(dsd, &source, &dataSourceType);
-
- /*
- if (err != OK) {
- notifyListener(dsd->mId, MEDIA2_ERROR, MEDIA2_ERROR_FAILED_TO_SET_DATA_SOURCE, err);
- return;
- }
-
- // Now, source != NULL.
- */
-
- mNextSourceInfo.mDataSourceType = dataSourceType;
-
- sp<AMessage> msg = new AMessage(kWhatPrepareNextDataSource, this);
- msg->setObject("source", source);
- msg->setInt64("srcId", dsd->mId);
- msg->setInt64("startTimeUs", dsd->mStartPositionMs * 1000);
- msg->setInt64("endTimeUs", dsd->mEndPositionMs * 1000);
- msg->post();
-}
-
-void NuPlayer2::playNextDataSource(int64_t srcId) {
- disconnectSource();
-
- sp<AMessage> msg = new AMessage(kWhatPlayNextDataSource, this);
- msg->setInt64("srcId", srcId);
- msg->post();
-}
-
-status_t NuPlayer2::getBufferingSettings(
- BufferingSettings *buffering /* nonnull */) {
- sp<AMessage> msg = new AMessage(kWhatGetBufferingSettings, this);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- if (err == OK) {
- readFromAMessage(response, buffering);
- }
- }
- return err;
-}
-
-status_t NuPlayer2::setBufferingSettings(const BufferingSettings& buffering) {
- sp<AMessage> msg = new AMessage(kWhatSetBufferingSettings, this);
- writeToAMessage(msg, buffering);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- }
- return err;
-}
-
-void NuPlayer2::prepareAsync() {
- ALOGV("prepareAsync");
-
- (new AMessage(kWhatPrepare, this))->post();
-}
-
-void NuPlayer2::setVideoSurfaceTextureAsync(const sp<ANativeWindowWrapper> &nww) {
- sp<AMessage> msg = new AMessage(kWhatSetVideoSurface, this);
-
- if (nww == NULL || nww->getANativeWindow() == NULL) {
- msg->setObject("surface", NULL);
- } else {
- msg->setObject("surface", nww);
- }
-
- msg->post();
-}
-
-void NuPlayer2::setAudioSink(const sp<MediaPlayer2Interface::AudioSink> &sink) {
- sp<AMessage> msg = new AMessage(kWhatSetAudioSink, this);
- msg->setObject("sink", sink);
- msg->post();
-}
-
-void NuPlayer2::start() {
- (new AMessage(kWhatStart, this))->post();
-}
-
-status_t NuPlayer2::setPlaybackSettings(const AudioPlaybackRate &rate) {
- // do some cursory validation of the settings here. audio modes are
- // only validated when set on the audiosink.
- if (rate.mSpeed < AUDIO_TIMESTRETCH_SPEED_MIN
- || rate.mSpeed > AUDIO_TIMESTRETCH_SPEED_MAX
- || rate.mPitch < AUDIO_TIMESTRETCH_SPEED_MIN
- || rate.mPitch > AUDIO_TIMESTRETCH_SPEED_MAX) {
- return BAD_VALUE;
- }
- sp<AMessage> msg = new AMessage(kWhatConfigPlayback, this);
- writeToAMessage(msg, rate);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- }
- return err;
-}
-
-status_t NuPlayer2::getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) {
- sp<AMessage> msg = new AMessage(kWhatGetPlaybackSettings, this);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- if (err == OK) {
- readFromAMessage(response, rate);
- }
- }
- return err;
-}
-
-status_t NuPlayer2::setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) {
- sp<AMessage> msg = new AMessage(kWhatConfigSync, this);
- writeToAMessage(msg, sync, videoFpsHint);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- }
- return err;
-}
-
-status_t NuPlayer2::getSyncSettings(
- AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */) {
- sp<AMessage> msg = new AMessage(kWhatGetSyncSettings, this);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- if (err == OK) {
- readFromAMessage(response, sync, videoFps);
- }
- }
- return err;
-}
-
-void NuPlayer2::pause() {
- (new AMessage(kWhatPause, this))->post();
-}
-
-void NuPlayer2::resetAsync() {
- disconnectSource();
- (new AMessage(kWhatReset, this))->post();
-}
-
-void NuPlayer2::disconnectSource() {
- sp<Source> source;
- {
- Mutex::Autolock autoLock(mSourceLock);
- source = mCurrentSourceInfo.mSource;
- }
-
- if (source != NULL) {
- // During a reset, the data source might be unresponsive already, we need to
- // disconnect explicitly so that reads exit promptly.
- // We can't queue the disconnect request to the looper, as it might be
- // queued behind a stuck read and never gets processed.
- // Doing a disconnect outside the looper to allows the pending reads to exit
- // (either successfully or with error).
- source->disconnect();
- }
-
-}
-
-status_t NuPlayer2::notifyAt(int64_t mediaTimeUs) {
- sp<AMessage> notify = new AMessage(kWhatNotifyTime, this);
- notify->setInt64("timerUs", mediaTimeUs);
- mMediaClock->addTimer(notify, mediaTimeUs);
- return OK;
-}
-
-void NuPlayer2::seekToAsync(int64_t seekTimeUs, MediaPlayer2SeekMode mode, bool needNotify) {
- sp<AMessage> msg = new AMessage(kWhatSeek, this);
- msg->setInt64("seekTimeUs", seekTimeUs);
- msg->setInt32("mode", mode);
- msg->setInt32("needNotify", needNotify);
- msg->post();
-}
-
-void NuPlayer2::rewind() {
- sp<AMessage> msg = new AMessage(kWhatRewind, this);
- msg->post();
-}
-
-void NuPlayer2::writeTrackInfo(
- PlayerMessage* reply, const sp<AMessage>& format) const {
- if (format == NULL) {
- ALOGE("NULL format");
- return;
- }
- int32_t trackType;
- if (!format->findInt32("type", &trackType)) {
- ALOGE("no track type");
- return;
- }
-
- AString mime;
- if (!format->findString("mime", &mime)) {
- // Java MediaPlayer only uses mimetype for subtitle and timedtext tracks.
- // If we can't find the mimetype here it means that we wouldn't be needing
- // the mimetype on the Java end. We still write a placeholder mime to keep the
- // (de)serialization logic simple.
- if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
- mime = "audio/";
- } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
- mime = "video/";
- } else {
- ALOGE("unknown track type: %d", trackType);
- return;
- }
- }
-
- AString lang;
- if (!format->findString("language", &lang)) {
- ALOGE("no language");
- return;
- }
-
- reply->add_values()->set_int32_value(trackType);
- reply->add_values()->set_string_value(mime.c_str());
- reply->add_values()->set_string_value(lang.c_str());
-
- if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
- int32_t isAuto, isDefault, isForced;
- CHECK(format->findInt32("auto", &isAuto));
- CHECK(format->findInt32("default", &isDefault));
- CHECK(format->findInt32("forced", &isForced));
-
- reply->add_values()->set_int32_value(isAuto);
- reply->add_values()->set_int32_value(isDefault);
- reply->add_values()->set_int32_value(isForced);
- }
-}
-
-void NuPlayer2::onMessageReceived(const sp<AMessage> &msg) {
-
- switch (msg->what()) {
- case kWhatSetDataSource:
- {
- ALOGV("kWhatSetDataSource");
-
- CHECK(mCurrentSourceInfo.mSource == NULL);
-
- status_t err = OK;
- sp<RefBase> obj;
- CHECK(msg->findObject("source", &obj));
- if (obj != NULL) {
- Mutex::Autolock autoLock(mSourceLock);
- CHECK(msg->findInt64("srcId", &mCurrentSourceInfo.mSrcId));
- CHECK(msg->findInt64("startTimeUs", &mCurrentSourceInfo.mStartTimeUs));
- CHECK(msg->findInt64("endTimeUs", &mCurrentSourceInfo.mEndTimeUs));
- mCurrentSourceInfo.mSource = static_cast<Source *>(obj.get());
- } else {
- err = UNKNOWN_ERROR;
- ALOGE("kWhatSetDataSource, source should not be NULL");
- }
-
- CHECK(mDriver != NULL);
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- driver->notifySetDataSourceCompleted(mCurrentSourceInfo.mSrcId, err);
- }
- break;
- }
-
- case kWhatPrepareNextDataSource:
- {
- ALOGV("kWhatPrepareNextDataSource");
-
- status_t err = OK;
- sp<RefBase> obj;
- CHECK(msg->findObject("source", &obj));
- if (obj != NULL) {
- Mutex::Autolock autoLock(mSourceLock);
- CHECK(msg->findInt64("srcId", &mNextSourceInfo.mSrcId));
- CHECK(msg->findInt64("startTimeUs", &mNextSourceInfo.mStartTimeUs));
- CHECK(msg->findInt64("endTimeUs", &mNextSourceInfo.mEndTimeUs));
- mNextSourceInfo.mSource = static_cast<Source *>(obj.get());
- mNextSourceInfo.mSource->prepareAsync(mNextSourceInfo.mStartTimeUs);
- } else {
- err = UNKNOWN_ERROR;
- }
-
- break;
- }
-
- case kWhatPlayNextDataSource:
- {
- ALOGV("kWhatPlayNextDataSource");
- int64_t srcId;
- CHECK(msg->findInt64("srcId", &srcId));
- if (srcId != mNextSourceInfo.mSrcId) {
- notifyListener(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, 0);
- return;
- }
-
- mResetting = true;
- stopPlaybackTimer("kWhatPlayNextDataSource");
- stopRebufferingTimer(true);
-
- mDeferredActions.push_back(
- new FlushDecoderAction(
- FLUSH_CMD_SHUTDOWN /* audio */,
- FLUSH_CMD_SHUTDOWN /* video */));
-
- mDeferredActions.push_back(
- new SimpleAction(&NuPlayer2::performPlayNextDataSource));
-
- processDeferredActions();
- break;
- }
-
- case kWhatEOSMonitor:
- {
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
- int32_t reason;
- CHECK(msg->findInt32("reason", &reason));
-
- if (generation != mEOSMonitorGeneration || reason != MediaClock::TIMER_REASON_REACHED) {
- break; // stale or reset
- }
-
- ALOGV("kWhatEOSMonitor");
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
- break;
- }
-
- case kWhatGetBufferingSettings:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
- ALOGV("kWhatGetBufferingSettings");
- BufferingSettings buffering;
- status_t err = OK;
- if (mCurrentSourceInfo.mSource != NULL) {
- err = mCurrentSourceInfo.mSource->getBufferingSettings(&buffering);
- } else {
- err = INVALID_OPERATION;
- }
- sp<AMessage> response = new AMessage;
- if (err == OK) {
- writeToAMessage(response, buffering);
- }
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatSetBufferingSettings:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
- ALOGV("kWhatSetBufferingSettings");
- BufferingSettings buffering;
- readFromAMessage(msg, &buffering);
- status_t err = OK;
- if (mCurrentSourceInfo.mSource != NULL) {
- err = mCurrentSourceInfo.mSource->setBufferingSettings(buffering);
- } else {
- err = INVALID_OPERATION;
- }
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatPrepare:
- {
- ALOGV("onMessageReceived kWhatPrepare");
-
- mCurrentSourceInfo.mSource->prepareAsync(mCurrentSourceInfo.mStartTimeUs);
- break;
- }
-
- case kWhatGetTrackInfo:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
- int64_t srcId;
- CHECK(msg->findInt64("srcId", (int64_t*)&srcId));
-
- PlayerMessage* reply;
- CHECK(msg->findPointer("reply", (void**)&reply));
-
- // TODO: use correct source info based on srcId.
- size_t inbandTracks = 0;
- if (mCurrentSourceInfo.mSource != NULL) {
- inbandTracks = mCurrentSourceInfo.mSource->getTrackCount();
- }
-
- size_t ccTracks = 0;
- if (mCCDecoder != NULL) {
- ccTracks = mCCDecoder->getTrackCount();
- }
-
- // total track count
- reply->add_values()->set_int32_value(inbandTracks + ccTracks);
-
- // write inband tracks
- for (size_t i = 0; i < inbandTracks; ++i) {
- writeTrackInfo(reply, mCurrentSourceInfo.mSource->getTrackInfo(i));
- }
-
- // write CC track
- for (size_t i = 0; i < ccTracks; ++i) {
- writeTrackInfo(reply, mCCDecoder->getTrackInfo(i));
- }
-
- sp<AMessage> response = new AMessage;
- response->postReply(replyID);
- break;
- }
-
- case kWhatGetSelectedTrack:
- {
- int64_t srcId;
- CHECK(msg->findInt64("srcId", (int64_t*)&srcId));
-
- int32_t type32;
- CHECK(msg->findInt32("type", (int32_t*)&type32));
- media_track_type type = (media_track_type)type32;
-
- // TODO: use correct source info based on srcId.
- size_t inbandTracks = 0;
- status_t err = INVALID_OPERATION;
- ssize_t selectedTrack = -1;
- if (mCurrentSourceInfo.mSource != NULL) {
- err = OK;
- inbandTracks = mCurrentSourceInfo.mSource->getTrackCount();
- selectedTrack = mCurrentSourceInfo.mSource->getSelectedTrack(type);
- }
-
- if (selectedTrack == -1 && mCCDecoder != NULL) {
- err = OK;
- selectedTrack = mCCDecoder->getSelectedTrack(type);
- if (selectedTrack != -1) {
- selectedTrack += inbandTracks;
- }
- }
-
- PlayerMessage* reply;
- CHECK(msg->findPointer("reply", (void**)&reply));
- reply->add_values()->set_int32_value(selectedTrack);
-
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
-
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
- break;
- }
-
- case kWhatSelectTrack:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
- int64_t srcId;
- size_t trackIndex;
- int32_t select;
- int64_t timeUs;
- CHECK(msg->findInt64("srcId", (int64_t*)&srcId));
- CHECK(msg->findSize("trackIndex", &trackIndex));
- CHECK(msg->findInt32("select", &select));
- CHECK(msg->findInt64("timeUs", &timeUs));
-
- status_t err = INVALID_OPERATION;
-
- // TODO: use correct source info based on srcId.
- size_t inbandTracks = 0;
- if (mCurrentSourceInfo.mSource != NULL) {
- inbandTracks = mCurrentSourceInfo.mSource->getTrackCount();
- }
- size_t ccTracks = 0;
- if (mCCDecoder != NULL) {
- ccTracks = mCCDecoder->getTrackCount();
- }
-
- if (trackIndex < inbandTracks) {
- err = mCurrentSourceInfo.mSource->selectTrack(trackIndex, select, timeUs);
-
- if (!select && err == OK) {
- int32_t type;
- sp<AMessage> info = mCurrentSourceInfo.mSource->getTrackInfo(trackIndex);
- if (info != NULL
- && info->findInt32("type", &type)
- && type == MEDIA_TRACK_TYPE_TIMEDTEXT) {
- ++mTimedTextGeneration;
- }
- }
- } else {
- trackIndex -= inbandTracks;
-
- if (trackIndex < ccTracks) {
- err = mCCDecoder->selectTrack(trackIndex, select);
- }
- }
-
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
-
- response->postReply(replyID);
- break;
- }
-
- case kWhatPollDuration:
- {
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
-
- if (generation != mPollDurationGeneration) {
- // stale
- break;
- }
-
- int64_t durationUs;
- if (mDriver != NULL && mCurrentSourceInfo.mSource->getDuration(&durationUs) == OK) {
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- driver->notifyDuration(mCurrentSourceInfo.mSrcId, durationUs);
- }
- }
-
- msg->post(1000000LL); // poll again in a second.
- break;
- }
-
- case kWhatSetVideoSurface:
- {
-
- sp<RefBase> obj;
- CHECK(msg->findObject("surface", &obj));
- sp<ANativeWindowWrapper> nww = static_cast<ANativeWindowWrapper *>(obj.get());
-
- ALOGD("onSetVideoSurface(%p, %s video decoder)",
- (nww == NULL ? NULL : nww->getANativeWindow()),
- (mCurrentSourceInfo.mSource != NULL && mStarted
- && mCurrentSourceInfo.mSource->getFormat(false /* audio */) != NULL
- && mVideoDecoder != NULL) ? "have" : "no");
-
- // Need to check mStarted before calling mCurrentSourceInfo.mSource->getFormat
- // because NuPlayer2 might be in preparing state and it could take long time.
- // When mStarted is true, mCurrentSourceInfo.mSource must have been set.
- if (mCurrentSourceInfo.mSource == NULL || !mStarted
- || mCurrentSourceInfo.mSource->getFormat(false /* audio */) == NULL
- // NOTE: mVideoDecoder's mNativeWindow is always non-null
- || (mVideoDecoder != NULL && mVideoDecoder->setVideoSurface(nww) == OK)) {
- performSetSurface(nww);
- break;
- }
-
- mDeferredActions.push_back(
- new FlushDecoderAction(
- (obj != NULL ? FLUSH_CMD_FLUSH : FLUSH_CMD_NONE) /* audio */,
- FLUSH_CMD_SHUTDOWN /* video */));
-
- mDeferredActions.push_back(new SetSurfaceAction(nww));
-
- if (obj != NULL) {
- if (mStarted) {
- // Issue a seek to refresh the video screen only if started otherwise
- // the extractor may not yet be started and will assert.
- // If the video decoder is not set (perhaps audio only in this case)
- // do not perform a seek as it is not needed.
- int64_t currentPositionUs = 0;
- if (getCurrentPosition(¤tPositionUs) == OK) {
- mDeferredActions.push_back(
- new SeekAction(currentPositionUs,
- MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */));
- }
- }
-
- // If there is a new surface texture, instantiate decoders
- // again if possible.
- mDeferredActions.push_back(
- new SimpleAction(&NuPlayer2::performScanSources));
-
- // After a flush without shutdown, decoder is paused.
- // Don't resume it until source seek is done, otherwise it could
- // start pulling stale data too soon.
- mDeferredActions.push_back(
- new ResumeDecoderAction(false /* needNotify */));
- }
-
- processDeferredActions();
- break;
- }
-
- case kWhatSetAudioSink:
- {
- ALOGV("kWhatSetAudioSink");
-
- sp<RefBase> obj;
- CHECK(msg->findObject("sink", &obj));
-
- mAudioSink = static_cast<MediaPlayer2Interface::AudioSink *>(obj.get());
- break;
- }
-
- case kWhatStart:
- {
- ALOGV("kWhatStart");
- if (mStarted) {
- // do not resume yet if the source is still buffering
- if (!mPausedForBuffering) {
- onResume();
- }
- } else {
- onStart(true /* play */);
- }
- mPausedByClient = false;
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_STARTED, 0, 0);
- break;
- }
-
- case kWhatConfigPlayback:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- AudioPlaybackRate rate /* sanitized */;
- readFromAMessage(msg, &rate);
- status_t err = OK;
- if (mRenderer != NULL) {
- // AudioSink allows only 1.f and 0.f for offload mode.
- // For other speed, switch to non-offload mode.
- if (mOffloadAudio && (rate.mSpeed != 1.f || rate.mPitch != 1.f)) {
- int64_t currentPositionUs;
- if (getCurrentPosition(¤tPositionUs) != OK) {
- currentPositionUs = mPreviousSeekTimeUs;
- }
-
- // Set mPlaybackSettings so that the new audio decoder can
- // be created correctly.
- mPlaybackSettings = rate;
- if (!mPaused) {
- mRenderer->pause();
- }
- restartAudio(
- currentPositionUs, true /* forceNonOffload */,
- true /* needsToCreateAudioDecoder */);
- if (!mPaused) {
- mRenderer->resume();
- }
- }
-
- err = mRenderer->setPlaybackSettings(rate);
- }
- if (err == OK) {
- mPlaybackSettings = rate;
-
- if (mVideoDecoder != NULL) {
- sp<AMessage> params = new AMessage();
- params->setFloat("playback-speed", mPlaybackSettings.mSpeed);
- mVideoDecoder->setParameters(params);
- }
- }
-
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatGetPlaybackSettings:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- AudioPlaybackRate rate = mPlaybackSettings;
- status_t err = OK;
- if (mRenderer != NULL) {
- err = mRenderer->getPlaybackSettings(&rate);
- }
- if (err == OK) {
- // get playback settings used by renderer, as it may be
- // slightly off due to audiosink not taking small changes.
- mPlaybackSettings = rate;
- }
- sp<AMessage> response = new AMessage;
- if (err == OK) {
- writeToAMessage(response, rate);
- }
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatConfigSync:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
- ALOGV("kWhatConfigSync");
- AVSyncSettings sync;
- float videoFpsHint;
- readFromAMessage(msg, &sync, &videoFpsHint);
- status_t err = OK;
- if (mRenderer != NULL) {
- err = mRenderer->setSyncSettings(sync, videoFpsHint);
- }
- if (err == OK) {
- mSyncSettings = sync;
- mVideoFpsHint = videoFpsHint;
- }
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatGetSyncSettings:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- AVSyncSettings sync = mSyncSettings;
- float videoFps = mVideoFpsHint;
- status_t err = OK;
- if (mRenderer != NULL) {
- err = mRenderer->getSyncSettings(&sync, &videoFps);
- if (err == OK) {
- mSyncSettings = sync;
- mVideoFpsHint = videoFps;
- }
- }
- sp<AMessage> response = new AMessage;
- if (err == OK) {
- writeToAMessage(response, sync, videoFps);
- }
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatScanSources:
- {
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
- if (generation != mScanSourcesGeneration) {
- // Drop obsolete msg.
- break;
- }
-
- mScanSourcesPending = false;
-
- ALOGV("scanning sources haveAudio=%d, haveVideo=%d",
- mAudioDecoder != NULL, mVideoDecoder != NULL);
-
- bool mHadAnySourcesBefore =
- (mAudioDecoder != NULL) || (mVideoDecoder != NULL);
- bool rescan = false;
-
- // initialize video before audio because successful initialization of
- // video may change deep buffer mode of audio.
- if (mNativeWindow != NULL && mNativeWindow->getANativeWindow() != NULL) {
- if (instantiateDecoder(false, &mVideoDecoder) == -EWOULDBLOCK) {
- rescan = true;
- }
- }
-
- // Don't try to re-open audio sink if there's an existing decoder.
- if (mAudioSink != NULL && mAudioDecoder == NULL) {
- if (instantiateDecoder(true, &mAudioDecoder) == -EWOULDBLOCK) {
- rescan = true;
- }
- }
-
- if (!mHadAnySourcesBefore
- && (mAudioDecoder != NULL || mVideoDecoder != NULL)) {
- // This is the first time we've found anything playable.
-
- if (mCurrentSourceInfo.mSourceFlags & Source::FLAG_DYNAMIC_DURATION) {
- schedulePollDuration();
- }
- }
-
- status_t err;
- if ((err = mCurrentSourceInfo.mSource->feedMoreTSData()) != OK) {
- if (mAudioDecoder == NULL && mVideoDecoder == NULL) {
- // We're not currently decoding anything (no audio or
- // video tracks found) and we just ran out of input data.
-
- if (err == ERROR_END_OF_STREAM) {
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
- } else {
- notifyListener(
- mCurrentSourceInfo.mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
- }
- }
- break;
- }
-
- if (rescan) {
- msg->post(100000LL);
- mScanSourcesPending = true;
- }
- break;
- }
-
- case kWhatVideoNotify:
- case kWhatAudioNotify:
- {
- bool audio = msg->what() == kWhatAudioNotify;
-
- int32_t currentDecoderGeneration =
- (audio? mAudioDecoderGeneration : mVideoDecoderGeneration);
- int32_t requesterGeneration = currentDecoderGeneration - 1;
- CHECK(msg->findInt32("generation", &requesterGeneration));
-
- if (requesterGeneration != currentDecoderGeneration) {
- ALOGV("got message from old %s decoder, generation(%d:%d)",
- audio ? "audio" : "video", requesterGeneration,
- currentDecoderGeneration);
- sp<AMessage> reply;
- if (!(msg->findMessage("reply", &reply))) {
- return;
- }
-
- reply->setInt32("err", INFO_DISCONTINUITY);
- reply->post();
- return;
- }
-
- int32_t what;
- CHECK(msg->findInt32("what", &what));
-
- if (what == DecoderBase::kWhatInputDiscontinuity) {
- int32_t formatChange;
- CHECK(msg->findInt32("formatChange", &formatChange));
-
- ALOGV("%s discontinuity: formatChange %d",
- audio ? "audio" : "video", formatChange);
-
- if (formatChange) {
- mDeferredActions.push_back(
- new FlushDecoderAction(
- audio ? FLUSH_CMD_SHUTDOWN : FLUSH_CMD_NONE,
- audio ? FLUSH_CMD_NONE : FLUSH_CMD_SHUTDOWN));
- }
-
- mDeferredActions.push_back(
- new SimpleAction(
- &NuPlayer2::performScanSources));
-
- processDeferredActions();
- } else if (what == DecoderBase::kWhatEOS) {
- int32_t err;
- CHECK(msg->findInt32("err", &err));
-
- if (err == ERROR_END_OF_STREAM) {
- ALOGV("got %s decoder EOS", audio ? "audio" : "video");
- } else {
- ALOGV("got %s decoder EOS w/ error %d",
- audio ? "audio" : "video",
- err);
- }
-
- mRenderer->queueEOS(audio, err);
- } else if (what == DecoderBase::kWhatFlushCompleted) {
- ALOGV("decoder %s flush completed", audio ? "audio" : "video");
-
- handleFlushComplete(audio, true /* isDecoder */);
- finishFlushIfPossible();
- } else if (what == DecoderBase::kWhatVideoSizeChanged) {
- sp<AMessage> format;
- CHECK(msg->findMessage("format", &format));
-
- sp<AMessage> inputFormat =
- mCurrentSourceInfo.mSource->getFormat(false /* audio */);
-
- setVideoScalingMode(mVideoScalingMode);
- updateVideoSize(mCurrentSourceInfo.mSrcId, inputFormat, format);
- } else if (what == DecoderBase::kWhatShutdownCompleted) {
- ALOGV("%s shutdown completed", audio ? "audio" : "video");
- if (audio) {
- Mutex::Autolock autoLock(mDecoderLock);
- mAudioDecoder.clear();
- mAudioDecoderError = false;
- ++mAudioDecoderGeneration;
-
- CHECK_EQ((int)mFlushingAudio, (int)SHUTTING_DOWN_DECODER);
- mFlushingAudio = SHUT_DOWN;
- } else {
- Mutex::Autolock autoLock(mDecoderLock);
- mVideoDecoder.clear();
- mVideoDecoderError = false;
- ++mVideoDecoderGeneration;
-
- CHECK_EQ((int)mFlushingVideo, (int)SHUTTING_DOWN_DECODER);
- mFlushingVideo = SHUT_DOWN;
- }
-
- finishFlushIfPossible();
- } else if (what == DecoderBase::kWhatResumeCompleted) {
- finishResume();
- } else if (what == DecoderBase::kWhatError) {
- status_t err;
- if (!msg->findInt32("err", &err) || err == OK) {
- err = UNKNOWN_ERROR;
- }
-
- // Decoder errors can be due to Source (e.g. from streaming),
- // or from decoding corrupted bitstreams, or from other decoder
- // MediaCodec operations (e.g. from an ongoing reset or seek).
- // They may also be due to openAudioSink failure at
- // decoder start or after a format change.
- //
- // We try to gracefully shut down the affected decoder if possible,
- // rather than trying to force the shutdown with something
- // similar to performReset(). This method can lead to a hang
- // if MediaCodec functions block after an error, but they should
- // typically return INVALID_OPERATION instead of blocking.
-
- FlushStatus *flushing = audio ? &mFlushingAudio : &mFlushingVideo;
- ALOGE("received error(%#x) from %s decoder, flushing(%d), now shutting down",
- err, audio ? "audio" : "video", *flushing);
-
- switch (*flushing) {
- case NONE:
- mDeferredActions.push_back(
- new FlushDecoderAction(
- audio ? FLUSH_CMD_SHUTDOWN : FLUSH_CMD_NONE,
- audio ? FLUSH_CMD_NONE : FLUSH_CMD_SHUTDOWN));
- processDeferredActions();
- break;
- case FLUSHING_DECODER:
- *flushing = FLUSHING_DECODER_SHUTDOWN; // initiate shutdown after flush.
- break; // Wait for flush to complete.
- case FLUSHING_DECODER_SHUTDOWN:
- break; // Wait for flush to complete.
- case SHUTTING_DOWN_DECODER:
- break; // Wait for shutdown to complete.
- case FLUSHED:
- getDecoder(audio)->initiateShutdown(); // In the middle of a seek.
- *flushing = SHUTTING_DOWN_DECODER; // Shut down.
- break;
- case SHUT_DOWN:
- finishFlushIfPossible(); // Should not occur.
- break; // Finish anyways.
- }
- if (mCurrentSourceInfo.mSource != nullptr) {
- if (audio) {
- if (mVideoDecoderError
- || mCurrentSourceInfo.mSource->getFormat(false /* audio */) == NULL
- || mNativeWindow == NULL
- || mNativeWindow->getANativeWindow() == NULL
- || mVideoDecoder == NULL) {
- // When both audio and video have error, or this stream has only audio
- // which has error, notify client of error.
- notifyListener(
- mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
- MEDIA2_ERROR_UNKNOWN, err);
- } else {
- // Only audio track has error. Video track could be still good to play.
- notifyListener(
- mCurrentSourceInfo.mSrcId, MEDIA2_INFO,
- MEDIA2_INFO_PLAY_AUDIO_ERROR, err);
- }
- mAudioDecoderError = true;
- } else {
- if (mAudioDecoderError
- || mCurrentSourceInfo.mSource->getFormat(true /* audio */) == NULL
- || mAudioSink == NULL || mAudioDecoder == NULL) {
- // When both audio and video have error, or this stream has only video
- // which has error, notify client of error.
- notifyListener(
- mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
- MEDIA2_ERROR_UNKNOWN, err);
- } else {
- // Only video track has error. Audio track could be still good to play.
- notifyListener(
- mCurrentSourceInfo.mSrcId, MEDIA2_INFO,
- MEDIA2_INFO_PLAY_VIDEO_ERROR, err);
- }
- mVideoDecoderError = true;
- }
- }
- } else {
- ALOGV("Unhandled decoder notification %d '%c%c%c%c'.",
- what,
- what >> 24,
- (what >> 16) & 0xff,
- (what >> 8) & 0xff,
- what & 0xff);
- }
-
- break;
- }
-
- case kWhatRendererNotify:
- {
- int32_t requesterGeneration = mRendererGeneration - 1;
- CHECK(msg->findInt32("generation", &requesterGeneration));
- if (requesterGeneration != mRendererGeneration) {
- ALOGV("got message from old renderer, generation(%d:%d)",
- requesterGeneration, mRendererGeneration);
- return;
- }
-
- int32_t what;
- CHECK(msg->findInt32("what", &what));
-
- if (what == Renderer::kWhatEOS) {
- int32_t audio;
- CHECK(msg->findInt32("audio", &audio));
-
- int32_t finalResult;
- CHECK(msg->findInt32("finalResult", &finalResult));
-
- if (audio) {
- mAudioEOS = true;
- } else {
- mVideoEOS = true;
- }
-
- if (finalResult == ERROR_END_OF_STREAM) {
- ALOGV("reached %s EOS", audio ? "audio" : "video");
- } else {
- ALOGE("%s track encountered an error (%d)",
- audio ? "audio" : "video", finalResult);
-
- notifyListener(
- mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
- MEDIA2_ERROR_UNKNOWN, finalResult);
- }
-
- if ((mAudioEOS || mAudioDecoder == NULL)
- && (mVideoEOS || mVideoDecoder == NULL)) {
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
- }
- } else if (what == Renderer::kWhatFlushComplete) {
- int32_t audio;
- CHECK(msg->findInt32("audio", &audio));
-
- if (audio) {
- mAudioEOS = false;
- } else {
- mVideoEOS = false;
- }
-
- ALOGV("renderer %s flush completed.", audio ? "audio" : "video");
- if (audio && (mFlushingAudio == NONE || mFlushingAudio == FLUSHED
- || mFlushingAudio == SHUT_DOWN)) {
- // Flush has been handled by tear down.
- break;
- }
- handleFlushComplete(audio, false /* isDecoder */);
- finishFlushIfPossible();
- } else if (what == Renderer::kWhatVideoRenderingStart) {
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_INFO,
- MEDIA2_INFO_VIDEO_RENDERING_START, 0);
- } else if (what == Renderer::kWhatMediaRenderingStart) {
- ALOGV("media rendering started");
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_STARTED, 0, 0);
- } else if (what == Renderer::kWhatAudioTearDown) {
- int32_t reason;
- CHECK(msg->findInt32("reason", &reason));
- ALOGV("Tear down audio with reason %d.", reason);
- if (reason == Renderer::kDueToTimeout && !(mPaused && mOffloadAudio)) {
- // TimeoutWhenPaused is only for offload mode.
- ALOGW("Receive a stale message for teardown.");
- break;
- }
- int64_t positionUs;
- if (!msg->findInt64("positionUs", &positionUs)) {
- positionUs = mPreviousSeekTimeUs;
- }
-
- restartAudio(
- positionUs, reason == Renderer::kForceNonOffload /* forceNonOffload */,
- reason != Renderer::kDueToTimeout /* needsToCreateAudioDecoder */);
- }
- break;
- }
-
- case kWhatMoreDataQueued:
- {
- break;
- }
-
- case kWhatReset:
- {
- ALOGV("kWhatReset");
-
- mResetting = true;
- stopPlaybackTimer("kWhatReset");
- stopRebufferingTimer(true);
-
- mDeferredActions.push_back(
- new FlushDecoderAction(
- FLUSH_CMD_SHUTDOWN /* audio */,
- FLUSH_CMD_SHUTDOWN /* video */));
-
- mDeferredActions.push_back(
- new SimpleAction(&NuPlayer2::performReset));
-
- processDeferredActions();
- break;
- }
-
- case kWhatNotifyTime:
- {
- ALOGV("kWhatNotifyTime");
- int64_t timerUs;
- CHECK(msg->findInt64("timerUs", &timerUs));
-
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_NOTIFY_TIME, timerUs, 0);
- break;
- }
-
- case kWhatSeek:
- {
- int64_t seekTimeUs;
- int32_t mode;
- int32_t needNotify;
- CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
- CHECK(msg->findInt32("mode", &mode));
- CHECK(msg->findInt32("needNotify", &needNotify));
-
- ALOGV("kWhatSeek seekTimeUs=%lld us, mode=%d, needNotify=%d",
- (long long)seekTimeUs, mode, needNotify);
-
- if (!mStarted) {
- if (!mSourceStarted) {
- mSourceStarted = true;
- mCurrentSourceInfo.mSource->start();
- }
- if (seekTimeUs > 0) {
- performSeek(seekTimeUs, (MediaPlayer2SeekMode)mode);
- }
-
- if (needNotify) {
- notifyDriverSeekComplete(mCurrentSourceInfo.mSrcId);
- }
- break;
- }
-
- // seeks can take a while, so we essentially paused
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PAUSED, 0, 0);
-
- mDeferredActions.push_back(
- new FlushDecoderAction(FLUSH_CMD_FLUSH /* audio */,
- FLUSH_CMD_FLUSH /* video */));
-
- mDeferredActions.push_back(
- new SeekAction(seekTimeUs, (MediaPlayer2SeekMode)mode));
-
- // After a flush without shutdown, decoder is paused.
- // Don't resume it until source seek is done, otherwise it could
- // start pulling stale data too soon.
- mDeferredActions.push_back(
- new ResumeDecoderAction(needNotify));
-
- processDeferredActions();
- break;
- }
-
- case kWhatRewind:
- {
- ALOGV("kWhatRewind");
-
- int64_t seekTimeUs = mCurrentSourceInfo.mStartTimeUs;
- int32_t mode = MediaPlayer2SeekMode::SEEK_CLOSEST;
-
- if (!mStarted) {
- if (!mSourceStarted) {
- mSourceStarted = true;
- mCurrentSourceInfo.mSource->start();
- }
- performSeek(seekTimeUs, (MediaPlayer2SeekMode)mode);
- break;
- }
-
- // seeks can take a while, so we essentially paused
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PAUSED, 0, 0);
-
- mDeferredActions.push_back(
- new FlushDecoderAction(FLUSH_CMD_FLUSH /* audio */,
- FLUSH_CMD_FLUSH /* video */));
-
- mDeferredActions.push_back(
- new SeekAction(seekTimeUs, (MediaPlayer2SeekMode)mode));
-
- // After a flush without shutdown, decoder is paused.
- // Don't resume it until source seek is done, otherwise it could
- // start pulling stale data too soon.
- mDeferredActions.push_back(
- new ResumeDecoderAction(false /* needNotify */));
-
- processDeferredActions();
- break;
- }
-
- case kWhatPause:
- {
- if (!mStarted) {
- onStart(false /* play */);
- }
- onPause();
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PAUSED, 0, 0);
- mPausedByClient = true;
- break;
- }
-
- case kWhatSourceNotify:
- {
- onSourceNotify(msg);
- break;
- }
-
- case kWhatClosedCaptionNotify:
- {
- onClosedCaptionNotify(msg);
- break;
- }
-
- case kWhatPrepareDrm:
- {
- status_t status = onPrepareDrm(msg);
-
- sp<AMessage> response = new AMessage;
- response->setInt32("status", status);
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
- break;
- }
-
- case kWhatReleaseDrm:
- {
- status_t status = onReleaseDrm(msg);
-
- sp<AMessage> response = new AMessage;
- response->setInt32("status", status);
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
- break;
- }
-
- default:
- TRESPASS();
- break;
- }
-}
-
-void NuPlayer2::onResume() {
- if (!mPaused || mResetting) {
- ALOGD_IF(mResetting, "resetting, onResume discarded");
- return;
- }
- mPaused = false;
- if (mCurrentSourceInfo.mSource != NULL) {
- mCurrentSourceInfo.mSource->resume();
- } else {
- ALOGW("resume called when source is gone or not set");
- }
- // |mAudioDecoder| may have been released due to the pause timeout, so re-create it if
- // needed.
- if (audioDecoderStillNeeded() && mAudioDecoder == NULL) {
- instantiateDecoder(true /* audio */, &mAudioDecoder);
- }
- if (mRenderer != NULL) {
- mRenderer->resume();
- } else {
- ALOGW("resume called when renderer is gone or not set");
- }
-
- startPlaybackTimer("onresume");
-}
-
-void NuPlayer2::onStart(bool play) {
- ALOGV("onStart: mCrypto: %p", mCurrentSourceInfo.mCrypto.get());
-
- if (!mSourceStarted) {
- mSourceStarted = true;
- mCurrentSourceInfo.mSource->start();
- }
-
- mOffloadAudio = false;
- mAudioEOS = false;
- mVideoEOS = false;
- mStarted = true;
- mPaused = false;
-
- uint32_t flags = 0;
-
- if (mCurrentSourceInfo.mSource->isRealTime()) {
- flags |= Renderer::FLAG_REAL_TIME;
- }
-
- bool hasAudio = (mCurrentSourceInfo.mSource->getFormat(true /* audio */) != NULL);
- bool hasVideo = (mCurrentSourceInfo.mSource->getFormat(false /* audio */) != NULL);
- if (!hasAudio && !hasVideo) {
- ALOGE("no metadata for either audio or video source");
- mCurrentSourceInfo.mSource->stop();
- mSourceStarted = false;
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
- MEDIA2_ERROR_UNKNOWN, ERROR_MALFORMED);
- return;
- }
- ALOGV_IF(!hasAudio, "no metadata for audio source"); // video only stream
-
- sp<MetaData> audioMeta = mCurrentSourceInfo.mSource->getFormatMeta(true /* audio */);
-
- audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
- if (mAudioSink != NULL) {
- streamType = mAudioSink->getAudioStreamType();
- }
-
- mOffloadAudio =
- JMediaPlayer2Utils::isOffloadedAudioPlaybackSupported(
- audioMeta, hasVideo, mCurrentSourceInfo.mSource->isStreaming(), streamType)
- && (mPlaybackSettings.mSpeed == 1.f && mPlaybackSettings.mPitch == 1.f);
-
- // Modular DRM: Disabling audio offload if the source is protected
- if (mOffloadAudio && mCurrentSourceInfo.mIsDrmProtected) {
- mOffloadAudio = false;
- ALOGV("onStart: Disabling mOffloadAudio now that the source is protected.");
- }
-
- if (mOffloadAudio) {
- flags |= Renderer::FLAG_OFFLOAD_AUDIO;
- }
-
- sp<AMessage> notify = new AMessage(kWhatRendererNotify, this);
- ++mRendererGeneration;
- notify->setInt32("generation", mRendererGeneration);
- mRenderer = new Renderer(mAudioSink, mMediaClock, notify, mContext, flags);
- mRendererLooper = new ALooper;
- mRendererLooper->setName("NuPlayer2Renderer");
- mRendererLooper->start(false, true, ANDROID_PRIORITY_AUDIO);
- mRendererLooper->registerHandler(mRenderer);
-
- status_t err = mRenderer->setPlaybackSettings(mPlaybackSettings);
- if (err != OK) {
- mCurrentSourceInfo.mSource->stop();
- mSourceStarted = false;
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
- return;
- }
-
- float rate = getFrameRate();
- if (rate > 0) {
- mRenderer->setVideoFrameRate(rate);
- }
-
- addEndTimeMonitor();
- // Renderer is created in paused state.
- if (play) {
- mRenderer->resume();
- }
-
- if (mVideoDecoder != NULL) {
- mVideoDecoder->setRenderer(mRenderer);
- }
- if (mAudioDecoder != NULL) {
- mAudioDecoder->setRenderer(mRenderer);
- }
-
- startPlaybackTimer("onstart");
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_START, 0);
-
- postScanSources();
-}
-
-void NuPlayer2::addEndTimeMonitor() {
- ++mEOSMonitorGeneration;
-
- if (mCurrentSourceInfo.mEndTimeUs == DataSourceDesc::kMaxTimeUs) {
- return;
- }
-
- sp<AMessage> msg = new AMessage(kWhatEOSMonitor, this);
- msg->setInt32("generation", mEOSMonitorGeneration);
- mMediaClock->addTimer(msg, mCurrentSourceInfo.mEndTimeUs);
-}
-
-void NuPlayer2::startPlaybackTimer(const char *where) {
- Mutex::Autolock autoLock(mPlayingTimeLock);
- if (mLastStartedPlayingTimeNs == 0) {
- mLastStartedPlayingTimeNs = systemTime();
- ALOGV("startPlaybackTimer() time %20" PRId64 " (%s)", mLastStartedPlayingTimeNs, where);
- }
-}
-
-void NuPlayer2::stopPlaybackTimer(const char *where) {
- Mutex::Autolock autoLock(mPlayingTimeLock);
-
- ALOGV("stopPlaybackTimer() time %20" PRId64 " (%s)", mLastStartedPlayingTimeNs, where);
-
- if (mLastStartedPlayingTimeNs != 0) {
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- int64_t now = systemTime();
- int64_t played = now - mLastStartedPlayingTimeNs;
- ALOGV("stopPlaybackTimer() log %20" PRId64 "", played);
-
- if (played > 0) {
- driver->notifyMorePlayingTimeUs(mCurrentSourceInfo.mSrcId, (played+500)/1000);
- }
- }
- mLastStartedPlayingTimeNs = 0;
- }
-}
-
-void NuPlayer2::startRebufferingTimer() {
- Mutex::Autolock autoLock(mPlayingTimeLock);
- if (mLastStartedRebufferingTimeNs == 0) {
- mLastStartedRebufferingTimeNs = systemTime();
- ALOGV("startRebufferingTimer() time %20" PRId64 "", mLastStartedRebufferingTimeNs);
- }
-}
-
-void NuPlayer2::stopRebufferingTimer(bool exitingPlayback) {
- Mutex::Autolock autoLock(mPlayingTimeLock);
-
- ALOGV("stopRebufferTimer() time %20" PRId64 " (exiting %d)",
- mLastStartedRebufferingTimeNs, exitingPlayback);
-
- if (mLastStartedRebufferingTimeNs != 0) {
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- int64_t now = systemTime();
- int64_t rebuffered = now - mLastStartedRebufferingTimeNs;
- ALOGV("stopRebufferingTimer() log %20" PRId64 "", rebuffered);
-
- if (rebuffered > 0) {
- driver->notifyMoreRebufferingTimeUs(
- mCurrentSourceInfo.mSrcId, (rebuffered+500)/1000);
- if (exitingPlayback) {
- driver->notifyRebufferingWhenExit(mCurrentSourceInfo.mSrcId, true);
- }
- }
- }
- mLastStartedRebufferingTimeNs = 0;
- }
-}
-
-void NuPlayer2::onPause() {
-
- stopPlaybackTimer("onPause");
-
- if (mPaused) {
- return;
- }
- mPaused = true;
- if (mCurrentSourceInfo.mSource != NULL) {
- mCurrentSourceInfo.mSource->pause();
- } else {
- ALOGW("pause called when source is gone or not set");
- }
- if (mRenderer != NULL) {
- mRenderer->pause();
- } else {
- ALOGW("pause called when renderer is gone or not set");
- }
-
-}
-
-bool NuPlayer2::audioDecoderStillNeeded() {
- // Audio decoder is no longer needed if it's in shut/shutting down status.
- return ((mFlushingAudio != SHUT_DOWN) && (mFlushingAudio != SHUTTING_DOWN_DECODER));
-}
-
-void NuPlayer2::handleFlushComplete(bool audio, bool isDecoder) {
- // We wait for both the decoder flush and the renderer flush to complete
- // before entering either the FLUSHED or the SHUTTING_DOWN_DECODER state.
-
- mFlushComplete[audio][isDecoder] = true;
- if (!mFlushComplete[audio][!isDecoder]) {
- return;
- }
-
- FlushStatus *state = audio ? &mFlushingAudio : &mFlushingVideo;
- switch (*state) {
- case FLUSHING_DECODER:
- {
- *state = FLUSHED;
- break;
- }
-
- case FLUSHING_DECODER_SHUTDOWN:
- {
- *state = SHUTTING_DOWN_DECODER;
-
- ALOGV("initiating %s decoder shutdown", audio ? "audio" : "video");
- getDecoder(audio)->initiateShutdown();
- break;
- }
-
- default:
- // decoder flush completes only occur in a flushing state.
- LOG_ALWAYS_FATAL_IF(isDecoder, "decoder flush in invalid state %d", *state);
- break;
- }
-}
-
-void NuPlayer2::finishFlushIfPossible() {
- if (mFlushingAudio != NONE && mFlushingAudio != FLUSHED
- && mFlushingAudio != SHUT_DOWN) {
- return;
- }
-
- if (mFlushingVideo != NONE && mFlushingVideo != FLUSHED
- && mFlushingVideo != SHUT_DOWN) {
- return;
- }
-
- ALOGV("both audio and video are flushed now.");
-
- mFlushingAudio = NONE;
- mFlushingVideo = NONE;
-
- clearFlushComplete();
-
- processDeferredActions();
-}
-
-void NuPlayer2::postScanSources() {
- if (mScanSourcesPending) {
- return;
- }
-
- sp<AMessage> msg = new AMessage(kWhatScanSources, this);
- msg->setInt32("generation", mScanSourcesGeneration);
- msg->post();
-
- mScanSourcesPending = true;
-}
-
-void NuPlayer2::tryOpenAudioSinkForOffload(
- const sp<AMessage> &format, const sp<MetaData> &audioMeta, bool hasVideo) {
- // Note: This is called early in NuPlayer2 to determine whether offloading
- // is possible; otherwise the decoders call the renderer openAudioSink directly.
-
- status_t err = mRenderer->openAudioSink(
- format, true /* offloadOnly */, hasVideo,
- AUDIO_OUTPUT_FLAG_NONE, &mOffloadAudio, mCurrentSourceInfo.mSource->isStreaming());
- if (err != OK) {
- // Any failure we turn off mOffloadAudio.
- mOffloadAudio = false;
- } else if (mOffloadAudio) {
- sendMetaDataToHal(mAudioSink, audioMeta);
- }
-}
-
-void NuPlayer2::closeAudioSink() {
- mRenderer->closeAudioSink();
-}
-
-void NuPlayer2::restartAudio(
- int64_t currentPositionUs, bool forceNonOffload, bool needsToCreateAudioDecoder) {
- if (mAudioDecoder != NULL) {
- mAudioDecoder->pause();
- Mutex::Autolock autoLock(mDecoderLock);
- mAudioDecoder.clear();
- mAudioDecoderError = false;
- ++mAudioDecoderGeneration;
- }
- if (mFlushingAudio == FLUSHING_DECODER) {
- mFlushComplete[1 /* audio */][1 /* isDecoder */] = true;
- mFlushingAudio = FLUSHED;
- finishFlushIfPossible();
- } else if (mFlushingAudio == FLUSHING_DECODER_SHUTDOWN
- || mFlushingAudio == SHUTTING_DOWN_DECODER) {
- mFlushComplete[1 /* audio */][1 /* isDecoder */] = true;
- mFlushingAudio = SHUT_DOWN;
- finishFlushIfPossible();
- needsToCreateAudioDecoder = false;
- }
- if (mRenderer == NULL) {
- return;
- }
- closeAudioSink();
- mRenderer->flush(true /* audio */, false /* notifyComplete */);
- if (mVideoDecoder != NULL) {
- mDeferredActions.push_back(
- new FlushDecoderAction(FLUSH_CMD_NONE /* audio */,
- FLUSH_CMD_FLUSH /* video */));
- mDeferredActions.push_back(
- new SeekAction(currentPositionUs,
- MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */));
- // After a flush without shutdown, decoder is paused.
- // Don't resume it until source seek is done, otherwise it could
- // start pulling stale data too soon.
- mDeferredActions.push_back(new ResumeDecoderAction(false));
- processDeferredActions();
- } else {
- performSeek(currentPositionUs, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */);
- }
-
- if (forceNonOffload) {
- mRenderer->signalDisableOffloadAudio();
- mOffloadAudio = false;
- }
- if (needsToCreateAudioDecoder) {
- instantiateDecoder(true /* audio */, &mAudioDecoder, !forceNonOffload);
- }
-}
-
-void NuPlayer2::determineAudioModeChange(const sp<AMessage> &audioFormat) {
- if (mCurrentSourceInfo.mSource == NULL || mAudioSink == NULL) {
- return;
- }
-
- if (mRenderer == NULL) {
- ALOGW("No renderer can be used to determine audio mode. Use non-offload for safety.");
- mOffloadAudio = false;
- return;
- }
-
- sp<MetaData> audioMeta = mCurrentSourceInfo.mSource->getFormatMeta(true /* audio */);
- sp<AMessage> videoFormat = mCurrentSourceInfo.mSource->getFormat(false /* audio */);
- audio_stream_type_t streamType = mAudioSink->getAudioStreamType();
- const bool hasVideo = (videoFormat != NULL);
- bool canOffload = JMediaPlayer2Utils::isOffloadedAudioPlaybackSupported(
- audioMeta, hasVideo, mCurrentSourceInfo.mSource->isStreaming(), streamType)
- && (mPlaybackSettings.mSpeed == 1.f && mPlaybackSettings.mPitch == 1.f);
-
- // Modular DRM: Disabling audio offload if the source is protected
- if (canOffload && mCurrentSourceInfo.mIsDrmProtected) {
- canOffload = false;
- ALOGV("determineAudioModeChange: Disabling mOffloadAudio b/c the source is protected.");
- }
-
- if (canOffload) {
- if (!mOffloadAudio) {
- mRenderer->signalEnableOffloadAudio();
- }
- // open audio sink early under offload mode.
- tryOpenAudioSinkForOffload(audioFormat, audioMeta, hasVideo);
- } else {
- if (mOffloadAudio) {
- mRenderer->signalDisableOffloadAudio();
- mOffloadAudio = false;
- }
- }
-}
-
-status_t NuPlayer2::instantiateDecoder(
- bool audio, sp<DecoderBase> *decoder, bool checkAudioModeChange) {
- // The audio decoder could be cleared by tear down. If still in shut down
- // process, no need to create a new audio decoder.
- if (*decoder != NULL || (audio && mFlushingAudio == SHUT_DOWN)) {
- return OK;
- }
-
- sp<AMessage> format = mCurrentSourceInfo.mSource->getFormat(audio);
-
- if (format == NULL) {
- return UNKNOWN_ERROR;
- } else {
- status_t err;
- if (format->findInt32("err", &err) && err) {
- return err;
- }
- }
-
- format->setInt32("priority", 0 /* realtime */);
-
- if (!audio) {
- AString mime;
- CHECK(format->findString("mime", &mime));
-
- sp<AMessage> ccNotify = new AMessage(kWhatClosedCaptionNotify, this);
- if (mCCDecoder == NULL) {
- mCCDecoder = new CCDecoder(ccNotify);
- }
-
- if (mCurrentSourceInfo.mSourceFlags & Source::FLAG_SECURE) {
- format->setInt32("secure", true);
- }
-
- if (mCurrentSourceInfo.mSourceFlags & Source::FLAG_PROTECTED) {
- format->setInt32("protected", true);
- }
-
- float rate = getFrameRate();
- if (rate > 0) {
- format->setFloat("operating-rate", rate * mPlaybackSettings.mSpeed);
- }
- }
-
- Mutex::Autolock autoLock(mDecoderLock);
-
- if (audio) {
- sp<AMessage> notify = new AMessage(kWhatAudioNotify, this);
- ++mAudioDecoderGeneration;
- notify->setInt32("generation", mAudioDecoderGeneration);
-
- if (checkAudioModeChange) {
- determineAudioModeChange(format);
- }
- if (mOffloadAudio) {
- mCurrentSourceInfo.mSource->setOffloadAudio(true /* offload */);
-
- const bool hasVideo = (mCurrentSourceInfo.mSource->getFormat(false /*audio */) != NULL);
- format->setInt32("has-video", hasVideo);
- *decoder = new DecoderPassThrough(notify, mCurrentSourceInfo.mSource, mRenderer);
- ALOGV("instantiateDecoder audio DecoderPassThrough hasVideo: %d", hasVideo);
- } else {
- mCurrentSourceInfo.mSource->setOffloadAudio(false /* offload */);
-
- *decoder = new Decoder(notify, mCurrentSourceInfo.mSource, mPID, mUID, mRenderer);
- ALOGV("instantiateDecoder audio Decoder");
- }
- mAudioDecoderError = false;
- } else {
- sp<AMessage> notify = new AMessage(kWhatVideoNotify, this);
- ++mVideoDecoderGeneration;
- notify->setInt32("generation", mVideoDecoderGeneration);
-
- *decoder = new Decoder(
- notify, mCurrentSourceInfo.mSource, mPID, mUID, mRenderer, mNativeWindow,
- mCCDecoder);
- mVideoDecoderError = false;
-
- // enable FRC if high-quality AV sync is requested, even if not
- // directly queuing to display, as this will even improve textureview
- // playback.
- {
- if (property_get_bool("persist.sys.media.avsync", false)) {
- format->setInt32("auto-frc", 1);
- }
- }
- }
- (*decoder)->init();
-
- // Modular DRM
- if (mCurrentSourceInfo.mIsDrmProtected) {
- format->setObject("crypto", mCurrentSourceInfo.mCrypto);
- ALOGV("instantiateDecoder: mCrypto: %p isSecure: %d",
- mCurrentSourceInfo.mCrypto.get(),
- (mCurrentSourceInfo.mSourceFlags & Source::FLAG_SECURE) != 0);
- }
-
- (*decoder)->configure(format);
-
- if (!audio) {
- sp<AMessage> params = new AMessage();
- float rate = getFrameRate();
- if (rate > 0) {
- params->setFloat("frame-rate-total", rate);
- }
-
- sp<MetaData> fileMeta = getFileMeta();
- if (fileMeta != NULL) {
- int32_t videoTemporalLayerCount;
- if (fileMeta->findInt32(kKeyTemporalLayerCount, &videoTemporalLayerCount)
- && videoTemporalLayerCount > 0) {
- params->setInt32("temporal-layer-count", videoTemporalLayerCount);
- }
- }
-
- if (params->countEntries() > 0) {
- (*decoder)->setParameters(params);
- }
- }
- return OK;
-}
-
-void NuPlayer2::updateVideoSize(
- int64_t srcId,
- const sp<AMessage> &inputFormat,
- const sp<AMessage> &outputFormat) {
- if (inputFormat == NULL) {
- ALOGW("Unknown video size, reporting 0x0!");
- notifyListener(srcId, MEDIA2_SET_VIDEO_SIZE, 0, 0);
- return;
- }
- int32_t err = OK;
- inputFormat->findInt32("err", &err);
- if (err == -EWOULDBLOCK) {
- ALOGW("Video meta is not available yet!");
- return;
- }
- if (err != OK) {
- ALOGW("Something is wrong with video meta!");
- return;
- }
-
- int32_t displayWidth, displayHeight;
- if (outputFormat != NULL) {
- int32_t width, height;
- CHECK(outputFormat->findInt32("width", &width));
- CHECK(outputFormat->findInt32("height", &height));
-
- int32_t cropLeft, cropTop, cropRight, cropBottom;
- CHECK(outputFormat->findRect(
- "crop",
- &cropLeft, &cropTop, &cropRight, &cropBottom));
-
- displayWidth = cropRight - cropLeft + 1;
- displayHeight = cropBottom - cropTop + 1;
-
- ALOGV("Video output format changed to %d x %d "
- "(crop: %d x %d @ (%d, %d))",
- width, height,
- displayWidth,
- displayHeight,
- cropLeft, cropTop);
- } else {
- CHECK(inputFormat->findInt32("width", &displayWidth));
- CHECK(inputFormat->findInt32("height", &displayHeight));
-
- ALOGV("Video input format %d x %d", displayWidth, displayHeight);
- }
-
- // Take into account sample aspect ratio if necessary:
- int32_t sarWidth, sarHeight;
- if (inputFormat->findInt32("sar-width", &sarWidth)
- && inputFormat->findInt32("sar-height", &sarHeight)
- && sarWidth > 0 && sarHeight > 0) {
- ALOGV("Sample aspect ratio %d : %d", sarWidth, sarHeight);
-
- displayWidth = (displayWidth * sarWidth) / sarHeight;
-
- ALOGV("display dimensions %d x %d", displayWidth, displayHeight);
- } else {
- int32_t width, height;
- if (inputFormat->findInt32("display-width", &width)
- && inputFormat->findInt32("display-height", &height)
- && width > 0 && height > 0
- && displayWidth > 0 && displayHeight > 0) {
- if (displayHeight * (int64_t)width / height > (int64_t)displayWidth) {
- displayHeight = (int32_t)(displayWidth * (int64_t)height / width);
- } else {
- displayWidth = (int32_t)(displayHeight * (int64_t)width / height);
- }
- ALOGV("Video display width and height are overridden to %d x %d",
- displayWidth, displayHeight);
- }
- }
-
- int32_t rotationDegrees;
- if (!inputFormat->findInt32("rotation-degrees", &rotationDegrees)) {
- rotationDegrees = 0;
- }
-
- if (rotationDegrees == 90 || rotationDegrees == 270) {
- int32_t tmp = displayWidth;
- displayWidth = displayHeight;
- displayHeight = tmp;
- }
-
- notifyListener(
- srcId,
- MEDIA2_SET_VIDEO_SIZE,
- displayWidth,
- displayHeight);
-}
-
-void NuPlayer2::notifyListener(
- int64_t srcId, int msg, int ext1, int ext2, const PlayerMessage *in) {
- if (mDriver == NULL) {
- return;
- }
-
- sp<NuPlayer2Driver> driver = mDriver.promote();
-
- if (driver == NULL) {
- return;
- }
-
- driver->notifyListener(srcId, msg, ext1, ext2, in);
-}
-
-void NuPlayer2::flushDecoder(bool audio, bool needShutdown) {
- ALOGV("[%s] flushDecoder needShutdown=%d",
- audio ? "audio" : "video", needShutdown);
-
- const sp<DecoderBase> &decoder = getDecoder(audio);
- if (decoder == NULL) {
- ALOGI("flushDecoder %s without decoder present",
- audio ? "audio" : "video");
- return;
- }
-
- // Make sure we don't continue to scan sources until we finish flushing.
- ++mScanSourcesGeneration;
- if (mScanSourcesPending) {
- if (!needShutdown) {
- mDeferredActions.push_back(
- new SimpleAction(&NuPlayer2::performScanSources));
- }
- mScanSourcesPending = false;
- }
-
- decoder->signalFlush();
-
- FlushStatus newStatus =
- needShutdown ? FLUSHING_DECODER_SHUTDOWN : FLUSHING_DECODER;
-
- mFlushComplete[audio][false /* isDecoder */] = (mRenderer == NULL);
- mFlushComplete[audio][true /* isDecoder */] = false;
- if (audio) {
- ALOGE_IF(mFlushingAudio != NONE,
- "audio flushDecoder() is called in state %d", mFlushingAudio);
- mFlushingAudio = newStatus;
- } else {
- ALOGE_IF(mFlushingVideo != NONE,
- "video flushDecoder() is called in state %d", mFlushingVideo);
- mFlushingVideo = newStatus;
- }
-}
-
-void NuPlayer2::queueDecoderShutdown(
- bool audio, bool video, const sp<AMessage> &reply) {
- ALOGI("queueDecoderShutdown audio=%d, video=%d", audio, video);
-
- mDeferredActions.push_back(
- new FlushDecoderAction(
- audio ? FLUSH_CMD_SHUTDOWN : FLUSH_CMD_NONE,
- video ? FLUSH_CMD_SHUTDOWN : FLUSH_CMD_NONE));
-
- mDeferredActions.push_back(
- new SimpleAction(&NuPlayer2::performScanSources));
-
- mDeferredActions.push_back(new PostMessageAction(reply));
-
- processDeferredActions();
-}
-
-status_t NuPlayer2::setVideoScalingMode(int32_t mode) {
- mVideoScalingMode = mode;
- if (mNativeWindow != NULL && mNativeWindow->getANativeWindow() != NULL) {
- status_t ret = native_window_set_scaling_mode(
- mNativeWindow->getANativeWindow(), mVideoScalingMode);
- if (ret != OK) {
- ALOGE("Failed to set scaling mode (%d): %s",
- -ret, strerror(-ret));
- return ret;
- }
- }
- return OK;
-}
-
-status_t NuPlayer2::getTrackInfo(int64_t srcId, PlayerMessage* reply) const {
- sp<AMessage> msg = new AMessage(kWhatGetTrackInfo, this);
- msg->setInt64("srcId", srcId);
- msg->setPointer("reply", reply);
-
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- return err;
-}
-
-status_t NuPlayer2::getSelectedTrack(int64_t srcId, int32_t type, PlayerMessage* reply) const {
- sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, this);
- msg->setPointer("reply", reply);
- msg->setInt64("srcId", srcId);
- msg->setInt32("type", type);
-
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- }
- return err;
-}
-
-status_t NuPlayer2::selectTrack(int64_t srcId, size_t trackIndex, bool select, int64_t timeUs) {
- sp<AMessage> msg = new AMessage(kWhatSelectTrack, this);
- msg->setInt64("srcId", srcId);
- msg->setSize("trackIndex", trackIndex);
- msg->setInt32("select", select);
- msg->setInt64("timeUs", timeUs);
-
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
-
- if (err != OK) {
- return err;
- }
-
- if (!response->findInt32("err", &err)) {
- err = OK;
- }
-
- return err;
-}
-
-status_t NuPlayer2::getCurrentPosition(int64_t *mediaUs) {
- sp<Renderer> renderer = mRenderer;
- if (renderer == NULL) {
- return NO_INIT;
- }
-
- return renderer->getCurrentPosition(mediaUs);
-}
-
-void NuPlayer2::getStats(Vector<sp<AMessage> > *mTrackStats) {
- CHECK(mTrackStats != NULL);
-
- mTrackStats->clear();
-
- Mutex::Autolock autoLock(mDecoderLock);
- if (mVideoDecoder != NULL) {
- mTrackStats->push_back(mVideoDecoder->getStats());
- }
- if (mAudioDecoder != NULL) {
- mTrackStats->push_back(mAudioDecoder->getStats());
- }
-}
-
-sp<MetaData> NuPlayer2::getFileMeta() {
- return mCurrentSourceInfo.mSource->getFileFormatMeta();
-}
-
-float NuPlayer2::getFrameRate() {
- sp<MetaData> meta = mCurrentSourceInfo.mSource->getFormatMeta(false /* audio */);
- if (meta == NULL) {
- return 0;
- }
- int32_t rate;
- if (!meta->findInt32(kKeyFrameRate, &rate)) {
- // fall back to try file meta
- sp<MetaData> fileMeta = getFileMeta();
- if (fileMeta == NULL) {
- ALOGW("source has video meta but not file meta");
- return -1;
- }
- int32_t fileMetaRate;
- if (!fileMeta->findInt32(kKeyFrameRate, &fileMetaRate)) {
- return -1;
- }
- return fileMetaRate;
- }
- return rate;
-}
-
-void NuPlayer2::schedulePollDuration() {
- sp<AMessage> msg = new AMessage(kWhatPollDuration, this);
- msg->setInt32("generation", mPollDurationGeneration);
- msg->post();
-}
-
-void NuPlayer2::cancelPollDuration() {
- ++mPollDurationGeneration;
-}
-
-void NuPlayer2::processDeferredActions() {
- while (!mDeferredActions.empty()) {
- // We won't execute any deferred actions until we're no longer in
- // an intermediate state, i.e. one more more decoders are currently
- // flushing or shutting down.
-
- if (mFlushingAudio != NONE || mFlushingVideo != NONE) {
- // We're currently flushing, postpone the reset until that's
- // completed.
-
- ALOGV("postponing action mFlushingAudio=%d, mFlushingVideo=%d",
- mFlushingAudio, mFlushingVideo);
-
- break;
- }
-
- sp<Action> action = *mDeferredActions.begin();
- mDeferredActions.erase(mDeferredActions.begin());
-
- action->execute(this);
- }
-}
-
-void NuPlayer2::performSeek(int64_t seekTimeUs, MediaPlayer2SeekMode mode) {
- ALOGV("performSeek seekTimeUs=%lld us (%.2f secs), mode=%d",
- (long long)seekTimeUs, seekTimeUs / 1E6, mode);
-
- if (mCurrentSourceInfo.mSource == NULL) {
- // This happens when reset occurs right before the loop mode
- // asynchronously seeks to the start of the stream.
- LOG_ALWAYS_FATAL_IF(mAudioDecoder != NULL || mVideoDecoder != NULL,
- "mCurrentSourceInfo.mSource is NULL and decoders not NULL audio(%p) video(%p)",
- mAudioDecoder.get(), mVideoDecoder.get());
- return;
- }
- mPreviousSeekTimeUs = seekTimeUs;
- mCurrentSourceInfo.mSource->seekTo(seekTimeUs, mode);
- ++mTimedTextGeneration;
-
- // everything's flushed, continue playback.
-}
-
-void NuPlayer2::performDecoderFlush(FlushCommand audio, FlushCommand video) {
- ALOGV("performDecoderFlush audio=%d, video=%d", audio, video);
-
- if ((audio == FLUSH_CMD_NONE || mAudioDecoder == NULL)
- && (video == FLUSH_CMD_NONE || mVideoDecoder == NULL)) {
- return;
- }
-
- if (audio != FLUSH_CMD_NONE && mAudioDecoder != NULL) {
- flushDecoder(true /* audio */, (audio == FLUSH_CMD_SHUTDOWN));
- }
-
- if (video != FLUSH_CMD_NONE && mVideoDecoder != NULL) {
- flushDecoder(false /* audio */, (video == FLUSH_CMD_SHUTDOWN));
- }
-}
-
-void NuPlayer2::performReset() {
- ALOGV("performReset");
-
- CHECK(mAudioDecoder == NULL);
- CHECK(mVideoDecoder == NULL);
-
- stopPlaybackTimer("performReset");
- stopRebufferingTimer(true);
-
- cancelPollDuration();
-
- ++mScanSourcesGeneration;
- mScanSourcesPending = false;
-
- if (mRendererLooper != NULL) {
- if (mRenderer != NULL) {
- mRendererLooper->unregisterHandler(mRenderer->id());
- }
- mRendererLooper->stop();
- mRendererLooper.clear();
- }
- mRenderer.clear();
- ++mRendererGeneration;
-
- resetSourceInfo(mCurrentSourceInfo);
- resetSourceInfo(mNextSourceInfo);
-
- if (mDriver != NULL) {
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- driver->notifyResetComplete(mCurrentSourceInfo.mSrcId);
- }
- }
-
- mStarted = false;
- mPrepared = false;
- mResetting = false;
- mSourceStarted = false;
-
-}
-
-void NuPlayer2::performPlayNextDataSource() {
- ALOGV("performPlayNextDataSource");
-
- CHECK(mAudioDecoder == NULL);
- CHECK(mVideoDecoder == NULL);
-
- stopPlaybackTimer("performPlayNextDataSource");
- stopRebufferingTimer(true);
-
- cancelPollDuration();
-
- ++mScanSourcesGeneration;
- mScanSourcesPending = false;
-
- ++mRendererGeneration;
-
- if (mCurrentSourceInfo.mSource != NULL) {
- mCurrentSourceInfo.mSource->stop();
- }
-
- long previousSrcId;
- {
- Mutex::Autolock autoLock(mSourceLock);
- previousSrcId = mCurrentSourceInfo.mSrcId;
-
- mCurrentSourceInfo = mNextSourceInfo;
- mNextSourceInfo = SourceInfo();
- mNextSourceInfo.mSrcId = ~mCurrentSourceInfo.mSrcId; // to distinguish the two sources.
- }
-
- if (mDriver != NULL) {
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- notifyListener(previousSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_END, 0);
-
- int64_t durationUs;
- if (mCurrentSourceInfo.mSource->getDuration(&durationUs) == OK) {
- driver->notifyDuration(mCurrentSourceInfo.mSrcId, durationUs);
- }
- notifyListener(
- mCurrentSourceInfo.mSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_START, 0);
- }
- }
-
- mStarted = false;
- mPrepared = true; // TODO: what if it's not prepared
- mResetting = false;
- mSourceStarted = false;
-
- addEndTimeMonitor();
-
- if (mRenderer != NULL) {
- mRenderer->resume();
- }
-
- onStart(true /* play */);
- mPausedByClient = false;
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_STARTED, 0, 0);
-}
-
-void NuPlayer2::performScanSources() {
- ALOGV("performScanSources");
-
- if (!mStarted) {
- return;
- }
-
- if (mAudioDecoder == NULL || mVideoDecoder == NULL) {
- postScanSources();
- }
-}
-
-void NuPlayer2::performSetSurface(const sp<ANativeWindowWrapper> &nww) {
- ALOGV("performSetSurface");
-
- mNativeWindow = nww;
-
- // XXX - ignore error from setVideoScalingMode for now
- setVideoScalingMode(mVideoScalingMode);
-
- if (mDriver != NULL) {
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- driver->notifySetSurfaceComplete(mCurrentSourceInfo.mSrcId);
- }
- }
-}
-
-void NuPlayer2::performResumeDecoders(bool needNotify) {
- if (needNotify) {
- mResumePending = true;
- if (mVideoDecoder == NULL) {
- // if audio-only, we can notify seek complete now,
- // as the resume operation will be relatively fast.
- finishResume();
- }
- }
-
- if (mVideoDecoder != NULL) {
- // When there is continuous seek, MediaPlayer will cache the seek
- // position, and send down new seek request when previous seek is
- // complete. Let's wait for at least one video output frame before
- // notifying seek complete, so that the video thumbnail gets updated
- // when seekbar is dragged.
- mVideoDecoder->signalResume(needNotify);
- }
-
- if (mAudioDecoder != NULL) {
- mAudioDecoder->signalResume(false /* needNotify */);
- }
-}
-
-void NuPlayer2::finishResume() {
- if (mResumePending) {
- mResumePending = false;
- notifyDriverSeekComplete(mCurrentSourceInfo.mSrcId);
- }
-}
-
-void NuPlayer2::notifyDriverSeekComplete(int64_t srcId) {
- if (mDriver != NULL) {
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- driver->notifySeekComplete(srcId);
- }
- }
-}
-
-void NuPlayer2::onSourceNotify(const sp<AMessage> &msg) {
- int32_t what;
- CHECK(msg->findInt32("what", &what));
-
- int64_t srcId;
- CHECK(msg->findInt64("srcId", &srcId));
- switch (what) {
- case Source::kWhatPrepared:
- {
- ALOGV("NuPlayer2::onSourceNotify Source::kWhatPrepared source:%p, Id(%lld)",
- mCurrentSourceInfo.mSource.get(), (long long)srcId);
- if (srcId == mCurrentSourceInfo.mSrcId) {
- if (mCurrentSourceInfo.mSource == NULL) {
- // This is a stale notification from a source that was
- // asynchronously preparing when the client called reset().
- // We handled the reset, the source is gone.
- break;
- }
-
- int32_t err;
- CHECK(msg->findInt32("err", &err));
-
- if (err != OK) {
- // shut down potential secure codecs in case client never calls reset
- mDeferredActions.push_back(
- new FlushDecoderAction(FLUSH_CMD_SHUTDOWN /* audio */,
- FLUSH_CMD_SHUTDOWN /* video */));
- processDeferredActions();
- } else {
- mPrepared = true;
- }
-
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- // notify duration first, so that it's definitely set when
- // the app received the "prepare complete" callback.
- int64_t durationUs;
- if (mCurrentSourceInfo.mSource->getDuration(&durationUs) == OK) {
- driver->notifyDuration(srcId, durationUs);
- }
- driver->notifyPrepareCompleted(srcId, err);
- }
- } else if (srcId == mNextSourceInfo.mSrcId) {
- if (mNextSourceInfo.mSource == NULL) {
- break; // stale
- }
-
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- int32_t err;
- CHECK(msg->findInt32("err", &err));
- driver->notifyPrepareCompleted(srcId, err);
- }
- }
-
- break;
- }
-
- // Modular DRM
- case Source::kWhatDrmInfo:
- {
- PlayerMessage playerMsg;
- sp<ABuffer> drmInfo;
- CHECK(msg->findBuffer("drmInfo", &drmInfo));
- playerMsg.ParseFromArray(drmInfo->data(), drmInfo->size());
-
- ALOGV("onSourceNotify() kWhatDrmInfo MEDIA2_DRM_INFO drmInfo: %p playerMsg size: %d",
- drmInfo.get(), playerMsg.ByteSize());
-
- notifyListener(srcId, MEDIA2_DRM_INFO, 0 /* ext1 */, 0 /* ext2 */, &playerMsg);
-
- break;
- }
-
- case Source::kWhatFlagsChanged:
- {
- uint32_t flags;
- CHECK(msg->findInt32("flags", (int32_t *)&flags));
-
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
-
- ALOGV("onSourceNotify() kWhatFlagsChanged FLAG_CAN_PAUSE: %d "
- "FLAG_CAN_SEEK_BACKWARD: %d \n\t\t\t\t FLAG_CAN_SEEK_FORWARD: %d "
- "FLAG_CAN_SEEK: %d FLAG_DYNAMIC_DURATION: %d \n"
- "\t\t\t\t FLAG_SECURE: %d FLAG_PROTECTED: %d",
- (flags & Source::FLAG_CAN_PAUSE) != 0,
- (flags & Source::FLAG_CAN_SEEK_BACKWARD) != 0,
- (flags & Source::FLAG_CAN_SEEK_FORWARD) != 0,
- (flags & Source::FLAG_CAN_SEEK) != 0,
- (flags & Source::FLAG_DYNAMIC_DURATION) != 0,
- (flags & Source::FLAG_SECURE) != 0,
- (flags & Source::FLAG_PROTECTED) != 0);
-
- if ((flags & NuPlayer2::Source::FLAG_CAN_SEEK) == 0) {
- driver->notifyListener(
- srcId, MEDIA2_INFO, MEDIA2_INFO_NOT_SEEKABLE, 0);
- }
- if (srcId == mCurrentSourceInfo.mSrcId) {
- driver->notifyFlagsChanged(srcId, flags);
- }
- }
-
- if (srcId == mCurrentSourceInfo.mSrcId) {
- if ((mCurrentSourceInfo.mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
- && (!(flags & Source::FLAG_DYNAMIC_DURATION))) {
- cancelPollDuration();
- } else if (!(mCurrentSourceInfo.mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
- && (flags & Source::FLAG_DYNAMIC_DURATION)
- && (mAudioDecoder != NULL || mVideoDecoder != NULL)) {
- schedulePollDuration();
- }
-
- mCurrentSourceInfo.mSourceFlags = flags;
- } else if (srcId == mNextSourceInfo.mSrcId) {
- // TODO: handle duration polling for next source.
- mNextSourceInfo.mSourceFlags = flags;
- }
- break;
- }
-
- case Source::kWhatVideoSizeChanged:
- {
- sp<AMessage> format;
- CHECK(msg->findMessage("format", &format));
-
- updateVideoSize(srcId, format);
- break;
- }
-
- case Source::kWhatBufferingUpdate:
- {
- int32_t percentage;
- CHECK(msg->findInt32("percentage", &percentage));
-
- notifyListener(srcId, MEDIA2_BUFFERING_UPDATE, percentage, 0);
- break;
- }
-
- case Source::kWhatPauseOnBufferingStart:
- {
- // ignore if not playing
- if (mStarted) {
- ALOGI("buffer low, pausing...");
-
- startRebufferingTimer();
- mPausedForBuffering = true;
- onPause();
- }
- notifyListener(srcId, MEDIA2_INFO, MEDIA2_INFO_BUFFERING_START, 0);
- break;
- }
-
- case Source::kWhatResumeOnBufferingEnd:
- {
- // ignore if not playing
- if (mStarted) {
- ALOGI("buffer ready, resuming...");
-
- stopRebufferingTimer(false);
- mPausedForBuffering = false;
-
- // do not resume yet if client didn't unpause
- if (!mPausedByClient) {
- onResume();
- }
- }
- notifyListener(srcId, MEDIA2_INFO, MEDIA2_INFO_BUFFERING_END, 0);
- break;
- }
-
- case Source::kWhatCacheStats:
- {
- int32_t kbps;
- CHECK(msg->findInt32("bandwidth", &kbps));
-
- notifyListener(srcId, MEDIA2_INFO, MEDIA2_INFO_NETWORK_BANDWIDTH, kbps);
- break;
- }
-
- case Source::kWhatSubtitleData:
- {
- sp<ABuffer> buffer;
- CHECK(msg->findBuffer("buffer", &buffer));
-
- sendSubtitleData(buffer, 0 /* baseIndex */);
- break;
- }
-
- case Source::kWhatTimedMetaData:
- {
- sp<ABuffer> buffer;
- if (!msg->findBuffer("buffer", &buffer)) {
- notifyListener(srcId, MEDIA2_INFO, MEDIA2_INFO_METADATA_UPDATE, 0);
- } else {
- sendTimedMetaData(buffer);
- }
- break;
- }
-
- case Source::kWhatTimedTextData:
- {
- int32_t generation;
- if (msg->findInt32("generation", &generation)
- && generation != mTimedTextGeneration) {
- break;
- }
-
- sp<ABuffer> buffer;
- CHECK(msg->findBuffer("buffer", &buffer));
-
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver == NULL) {
- break;
- }
-
- int64_t posMs;
- int64_t timeUs, posUs;
- driver->getCurrentPosition(&posMs);
- posUs = posMs * 1000LL;
- CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
-
- if (posUs < timeUs) {
- if (!msg->findInt32("generation", &generation)) {
- msg->setInt32("generation", mTimedTextGeneration);
- }
- msg->post(timeUs - posUs);
- } else {
- sendTimedTextData(buffer);
- }
- break;
- }
-
- case Source::kWhatQueueDecoderShutdown:
- {
- int32_t audio, video;
- CHECK(msg->findInt32("audio", &audio));
- CHECK(msg->findInt32("video", &video));
-
- sp<AMessage> reply;
- CHECK(msg->findMessage("reply", &reply));
-
- queueDecoderShutdown(audio, video, reply);
- break;
- }
-
- case Source::kWhatDrmNoLicense:
- {
- notifyListener(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
- break;
- }
-
- default:
- TRESPASS();
- }
-}
-
-void NuPlayer2::onClosedCaptionNotify(const sp<AMessage> &msg) {
- int32_t what;
- CHECK(msg->findInt32("what", &what));
-
- switch (what) {
- case NuPlayer2::CCDecoder::kWhatClosedCaptionData:
- {
- sp<ABuffer> buffer;
- CHECK(msg->findBuffer("buffer", &buffer));
-
- size_t inbandTracks = 0;
- if (mCurrentSourceInfo.mSource != NULL) {
- inbandTracks = mCurrentSourceInfo.mSource->getTrackCount();
- }
-
- sendSubtitleData(buffer, inbandTracks);
- break;
- }
-
- case NuPlayer2::CCDecoder::kWhatTrackAdded:
- {
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_INFO, MEDIA2_INFO_METADATA_UPDATE, 0);
-
- break;
- }
-
- default:
- TRESPASS();
- }
-
-
-}
-
-void NuPlayer2::sendSubtitleData(const sp<ABuffer> &buffer, int32_t baseIndex) {
- int32_t trackIndex;
- int64_t timeUs, durationUs;
- CHECK(buffer->meta()->findInt32(AMEDIAFORMAT_KEY_TRACK_INDEX, &trackIndex));
- CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
- CHECK(buffer->meta()->findInt64("durationUs", &durationUs));
-
- PlayerMessage playerMsg;
- playerMsg.add_values()->set_int32_value(trackIndex + baseIndex);
- playerMsg.add_values()->set_int64_value(timeUs);
- playerMsg.add_values()->set_int64_value(durationUs);
- playerMsg.add_values()->set_bytes_value(buffer->data(), buffer->size());
-
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_SUBTITLE_DATA, 0, 0, &playerMsg);
-}
-
-void NuPlayer2::sendTimedMetaData(const sp<ABuffer> &buffer) {
- int64_t timeUs;
- CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
-
- PlayerMessage playerMsg;
- playerMsg.add_values()->set_int64_value(timeUs);
- playerMsg.add_values()->set_bytes_value(buffer->data(), buffer->size());
-
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_META_DATA, 0, 0, &playerMsg);
-}
-
-void NuPlayer2::sendTimedTextData(const sp<ABuffer> &buffer) {
- const void *data;
- size_t size = 0;
- int64_t timeUs;
- int32_t flag = TextDescriptions2::IN_BAND_TEXT_3GPP;
-
- AString mime;
- CHECK(buffer->meta()->findString("mime", &mime));
- CHECK(strcasecmp(mime.c_str(), MEDIA_MIMETYPE_TEXT_3GPP) == 0);
-
- data = buffer->data();
- size = buffer->size();
-
- PlayerMessage playerMsg;
- if (size > 0) {
- CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
- int32_t global = 0;
- if (buffer->meta()->findInt32("global", &global) && global) {
- flag |= TextDescriptions2::GLOBAL_DESCRIPTIONS;
- } else {
- flag |= TextDescriptions2::LOCAL_DESCRIPTIONS;
- }
- TextDescriptions2::getPlayerMessageOfDescriptions(
- (const uint8_t *)data, size, flag, timeUs / 1000, &playerMsg);
- }
-
- if (playerMsg.values_size() > 0) {
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_TIMED_TEXT, 0, 0, &playerMsg);
- } else { // send an empty timed text
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_TIMED_TEXT, 0, 0);
- }
-}
-
-const char *NuPlayer2::getDataSourceType() {
- switch (mCurrentSourceInfo.mDataSourceType) {
- case DATA_SOURCE_TYPE_HTTP_LIVE:
- return "HTTPLive";
-
- case DATA_SOURCE_TYPE_RTSP:
- return "RTSP";
-
- case DATA_SOURCE_TYPE_GENERIC_URL:
- return "GenURL";
-
- case DATA_SOURCE_TYPE_GENERIC_FD:
- return "GenFD";
-
- case DATA_SOURCE_TYPE_MEDIA:
- return "Media";
-
- case DATA_SOURCE_TYPE_NONE:
- default:
- return "None";
- }
- }
-
-NuPlayer2::SourceInfo* NuPlayer2::getSourceInfoByIdInMsg(const sp<AMessage> &msg) {
- int64_t srcId;
- CHECK(msg->findInt64("srcId", &srcId));
- if (mCurrentSourceInfo.mSrcId == srcId) {
- return &mCurrentSourceInfo;
- } else if (mNextSourceInfo.mSrcId == srcId) {
- return &mNextSourceInfo;
- } else {
- return NULL;
- }
-}
-
-void NuPlayer2::resetSourceInfo(NuPlayer2::SourceInfo &srcInfo) {
- if (srcInfo.mSource != NULL) {
- srcInfo.mSource->stop();
-
- Mutex::Autolock autoLock(mSourceLock);
- srcInfo.mSource.clear();
- }
- // Modular DRM
- ALOGD("performReset mCrypto: %p", srcInfo.mCrypto.get());
- srcInfo.mCrypto.clear();
- srcInfo.mIsDrmProtected = false;
-}
-
-// Modular DRM begin
-status_t NuPlayer2::prepareDrm(
- int64_t srcId, const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId)
-{
- ALOGV("prepareDrm ");
-
- // Passing to the looper anyway; called in a pre-config prepared state so no race on mCrypto
- sp<AMessage> msg = new AMessage(kWhatPrepareDrm, this);
- // synchronous call so just passing the address but with local copies of "const" args
- uint8_t UUID[16];
- memcpy(UUID, uuid, sizeof(UUID));
- Vector<uint8_t> sessionId = drmSessionId;
- msg->setInt64("srcId", srcId);
- msg->setPointer("uuid", (void*)UUID);
- msg->setPointer("drmSessionId", (void*)&sessionId);
-
- sp<AMessage> response;
- status_t status = msg->postAndAwaitResponse(&response);
-
- if (status == OK && response != NULL) {
- CHECK(response->findInt32("status", &status));
- ALOGV("prepareDrm ret: %d ", status);
- } else {
- ALOGE("prepareDrm err: %d", status);
- }
-
- return status;
-}
-
-status_t NuPlayer2::releaseDrm(int64_t srcId)
-{
- ALOGV("releaseDrm ");
-
- sp<AMessage> msg = new AMessage(kWhatReleaseDrm, this);
- msg->setInt64("srcId", srcId);
-
- sp<AMessage> response;
- status_t status = msg->postAndAwaitResponse(&response);
-
- if (status == OK && response != NULL) {
- CHECK(response->findInt32("status", &status));
- ALOGV("releaseDrm ret: %d ", status);
- } else {
- ALOGE("releaseDrm err: %d", status);
- }
-
- return status;
-}
-
-status_t NuPlayer2::onPrepareDrm(const sp<AMessage> &msg)
-{
- // TODO change to ALOGV
- ALOGD("onPrepareDrm ");
-
- status_t status = INVALID_OPERATION;
- SourceInfo *srcInfo = getSourceInfoByIdInMsg(msg);
- if (srcInfo == NULL) {
- return status;
- }
-
- int64_t srcId = srcInfo->mSrcId;
- if (srcInfo->mSource == NULL) {
- ALOGE("onPrepareDrm: srcInfo(%lld) No source. onPrepareDrm failed with %d.",
- (long long)srcId, status);
- return status;
- }
-
- uint8_t *uuid;
- Vector<uint8_t> *drmSessionId;
- CHECK(msg->findPointer("uuid", (void**)&uuid));
- CHECK(msg->findPointer("drmSessionId", (void**)&drmSessionId));
-
- status = OK;
- sp<AMediaCryptoWrapper> crypto = NULL;
-
- status = srcInfo->mSource->prepareDrm(uuid, *drmSessionId, &crypto);
- if (crypto == NULL) {
- ALOGE("onPrepareDrm: srcInfo(%lld).mSource->prepareDrm failed. status: %d",
- (long long)srcId, status);
- return status;
- }
- ALOGV("onPrepareDrm: srcInfo(%lld).mSource->prepareDrm succeeded", (long long)srcId);
-
- if (srcInfo->mCrypto != NULL) {
- ALOGE("onPrepareDrm: srcInfo(%lld) Unexpected. Already having mCrypto: %p",
- (long long)srcId, srcInfo->mCrypto.get());
- srcInfo->mCrypto.clear();
- }
-
- srcInfo->mCrypto = crypto;
- srcInfo->mIsDrmProtected = true;
- // TODO change to ALOGV
- ALOGD("onPrepareDrm: mCrypto: %p", srcInfo->mCrypto.get());
-
- return status;
-}
-
-status_t NuPlayer2::onReleaseDrm(const sp<AMessage> &msg)
-{
- // TODO change to ALOGV
- ALOGD("onReleaseDrm ");
- SourceInfo *srcInfo = getSourceInfoByIdInMsg(msg);;
- if (srcInfo == NULL) {
- return INVALID_OPERATION;
- }
-
- int64_t srcId = srcInfo->mSrcId;
- if (!srcInfo->mIsDrmProtected) {
- ALOGW("onReleaseDrm: srcInfo(%lld) Unexpected. mIsDrmProtected is already false.",
- (long long)srcId);
- }
-
- srcInfo->mIsDrmProtected = false;
-
- status_t status;
- if (srcInfo->mCrypto != NULL) {
- // notifying the source first before removing crypto from codec
- if (srcInfo->mSource != NULL) {
- srcInfo->mSource->releaseDrm();
- }
-
- status=OK;
- // first making sure the codecs have released their crypto reference
- const sp<DecoderBase> &videoDecoder = getDecoder(false/*audio*/);
- if (videoDecoder != NULL) {
- status = videoDecoder->releaseCrypto();
- ALOGV("onReleaseDrm: video decoder ret: %d", status);
- }
-
- const sp<DecoderBase> &audioDecoder = getDecoder(true/*audio*/);
- if (audioDecoder != NULL) {
- status_t status_audio = audioDecoder->releaseCrypto();
- if (status == OK) { // otherwise, returning the first error
- status = status_audio;
- }
- ALOGV("onReleaseDrm: audio decoder ret: %d", status_audio);
- }
-
- // TODO change to ALOGV
- ALOGD("onReleaseDrm: mCrypto: %p", srcInfo->mCrypto.get());
- srcInfo->mCrypto.clear();
- } else { // srcInfo->mCrypto == NULL
- ALOGE("onReleaseDrm: Unexpected. There is no crypto.");
- status = INVALID_OPERATION;
- }
-
- return status;
-}
-// Modular DRM end
-////////////////////////////////////////////////////////////////////////////////
-
-sp<AMessage> NuPlayer2::Source::getFormat(bool audio) {
- sp<MetaData> meta = getFormatMeta(audio);
-
- if (meta == NULL) {
- return NULL;
- }
-
- sp<AMessage> msg = new AMessage;
-
- if(convertMetaDataToMessage(meta, &msg) == OK) {
- return msg;
- }
- return NULL;
-}
-
-void NuPlayer2::Source::notifyFlagsChanged(uint32_t flags) {
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatFlagsChanged);
- notify->setInt32("flags", flags);
- notify->post();
-}
-
-void NuPlayer2::Source::notifyVideoSizeChanged(const sp<AMessage> &format) {
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatVideoSizeChanged);
- notify->setMessage("format", format);
- notify->post();
-}
-
-void NuPlayer2::Source::notifyPrepared(status_t err) {
- ALOGV("Source::notifyPrepared %d", err);
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatPrepared);
- notify->setInt32("err", err);
- notify->post();
-}
-
-void NuPlayer2::Source::notifyDrmInfo(const sp<ABuffer> &drmInfoBuffer)
-{
- ALOGV("Source::notifyDrmInfo");
-
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatDrmInfo);
- notify->setBuffer("drmInfo", drmInfoBuffer);
-
- notify->post();
-}
-
-void NuPlayer2::Source::onMessageReceived(const sp<AMessage> & /* msg */) {
- TRESPASS();
-}
-
-NuPlayer2::SourceInfo::SourceInfo()
- : mDataSourceType(DATA_SOURCE_TYPE_NONE),
- mSrcId(0),
- mSourceFlags(0),
- mStartTimeUs(0),
- mEndTimeUs(DataSourceDesc::kMaxTimeUs) {
-}
-
-NuPlayer2::SourceInfo & NuPlayer2::SourceInfo::operator=(const NuPlayer2::SourceInfo &other) {
- mSource = other.mSource;
- mCrypto = other.mCrypto;
- mDataSourceType = (DATA_SOURCE_TYPE)other.mDataSourceType;
- mSrcId = other.mSrcId;
- mSourceFlags = other.mSourceFlags;
- mStartTimeUs = other.mStartTimeUs;
- mEndTimeUs = other.mEndTimeUs;
- mIsDrmProtected = other.mIsDrmProtected;
- return *this;
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.h b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
deleted file mode 100644
index b8fb988..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.h
+++ /dev/null
@@ -1,369 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NU_PLAYER2_H_
-
-#define NU_PLAYER2_H_
-
-#include <media/AudioResamplerPublic.h>
-#include <media/stagefright/foundation/AHandler.h>
-
-#include <mediaplayer2/MediaPlayer2Interface.h>
-#include <mediaplayer2/JObjectHolder.h>
-
-#include "mediaplayer2.pb.h"
-
-using android::media::MediaPlayer2Proto::PlayerMessage;
-
-namespace android {
-
-struct ABuffer;
-struct AMediaCryptoWrapper;
-struct AMessage;
-struct ANativeWindowWrapper;
-struct AudioPlaybackRate;
-struct AVSyncSettings;
-struct DataSourceDesc;
-struct MediaClock;
-struct MediaHTTPService;
-class MetaData;
-struct NuPlayer2Driver;
-
-struct NuPlayer2 : public AHandler {
- explicit NuPlayer2(pid_t pid, uid_t uid,
- const sp<MediaClock> &mediaClock, const sp<JObjectHolder> &context);
-
- void setDriver(const wp<NuPlayer2Driver> &driver);
-
- void setDataSourceAsync(const sp<DataSourceDesc> &dsd);
- void prepareNextDataSourceAsync(const sp<DataSourceDesc> &dsd);
- void playNextDataSource(int64_t srcId);
-
- status_t getBufferingSettings(BufferingSettings* buffering /* nonnull */);
- status_t setBufferingSettings(const BufferingSettings& buffering);
-
- void prepareAsync();
-
- void setVideoSurfaceTextureAsync(const sp<ANativeWindowWrapper> &nww);
-
- void setAudioSink(const sp<MediaPlayer2Interface::AudioSink> &sink);
- status_t setPlaybackSettings(const AudioPlaybackRate &rate);
- status_t getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */);
- status_t setSyncSettings(const AVSyncSettings &sync, float videoFpsHint);
- status_t getSyncSettings(AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */);
-
- void start();
-
- void pause();
-
- // Will notify the driver through "notifyResetComplete" once finished.
- void resetAsync();
-
- // Request a notification when specified media time is reached.
- status_t notifyAt(int64_t mediaTimeUs);
-
- // Will notify the driver through "notifySeekComplete" once finished
- // and needNotify is true.
- void seekToAsync(
- int64_t seekTimeUs,
- MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC,
- bool needNotify = false);
- void rewind();
-
- status_t setVideoScalingMode(int32_t mode);
- status_t getTrackInfo(int64_t srcId, PlayerMessage* reply) const;
- status_t getSelectedTrack(int64_t srcId, int32_t type, PlayerMessage* reply) const;
- status_t selectTrack(int64_t srcId, size_t trackIndex, bool select, int64_t timeUs);
- status_t getCurrentPosition(int64_t *mediaUs);
- void getStats(Vector<sp<AMessage> > *mTrackStats);
-
- sp<MetaData> getFileMeta();
- float getFrameRate();
-
- // Modular DRM
- status_t prepareDrm(int64_t srcId, const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId);
- status_t releaseDrm(int64_t srcId);
-
- const char *getDataSourceType();
-
-protected:
- virtual ~NuPlayer2();
-
- virtual void onMessageReceived(const sp<AMessage> &msg);
-
-public:
- struct StreamListener;
- struct Source;
-
-private:
- struct Decoder;
- struct DecoderBase;
- struct DecoderPassThrough;
- struct CCDecoder;
- struct GenericSource2;
- struct HTTPLiveSource2;
- struct Renderer;
- struct RTSPSource2;
- struct Action;
- struct SeekAction;
- struct SetSurfaceAction;
- struct ResumeDecoderAction;
- struct FlushDecoderAction;
- struct PostMessageAction;
- struct SimpleAction;
-
- enum {
- kWhatSetDataSource = '=DaS',
- kWhatPrepare = 'prep',
- kWhatPrepareNextDataSource = 'pNDS',
- kWhatPlayNextDataSource = 'plNS',
- kWhatSetVideoSurface = '=VSu',
- kWhatSetAudioSink = '=AuS',
- kWhatMoreDataQueued = 'more',
- kWhatConfigPlayback = 'cfPB',
- kWhatConfigSync = 'cfSy',
- kWhatGetPlaybackSettings = 'gPbS',
- kWhatGetSyncSettings = 'gSyS',
- kWhatStart = 'strt',
- kWhatScanSources = 'scan',
- kWhatVideoNotify = 'vidN',
- kWhatAudioNotify = 'audN',
- kWhatClosedCaptionNotify = 'capN',
- kWhatRendererNotify = 'renN',
- kWhatReset = 'rset',
- kWhatNotifyTime = 'nfyT',
- kWhatSeek = 'seek',
- kWhatPause = 'paus',
- kWhatResume = 'rsme',
- kWhatPollDuration = 'polD',
- kWhatSourceNotify = 'srcN',
- kWhatGetTrackInfo = 'gTrI',
- kWhatGetSelectedTrack = 'gSel',
- kWhatSelectTrack = 'selT',
- kWhatGetBufferingSettings = 'gBus',
- kWhatSetBufferingSettings = 'sBuS',
- kWhatPrepareDrm = 'pDrm',
- kWhatReleaseDrm = 'rDrm',
- kWhatRewind = 'reWd',
- kWhatEOSMonitor = 'eosM',
- };
-
- typedef enum {
- DATA_SOURCE_TYPE_NONE,
- DATA_SOURCE_TYPE_HTTP_LIVE,
- DATA_SOURCE_TYPE_RTSP,
- DATA_SOURCE_TYPE_GENERIC_URL,
- DATA_SOURCE_TYPE_GENERIC_FD,
- DATA_SOURCE_TYPE_MEDIA,
- } DATA_SOURCE_TYPE;
-
- struct SourceInfo {
- SourceInfo();
- SourceInfo &operator=(const SourceInfo &);
-
- sp<Source> mSource;
- std::atomic<DATA_SOURCE_TYPE> mDataSourceType;
- int64_t mSrcId;
- uint32_t mSourceFlags;
- int64_t mStartTimeUs;
- int64_t mEndTimeUs;
- // Modular DRM
- sp<AMediaCryptoWrapper> mCrypto;
- bool mIsDrmProtected = false;
- };
-
- wp<NuPlayer2Driver> mDriver;
- pid_t mPID;
- uid_t mUID;
- const sp<MediaClock> mMediaClock;
- Mutex mSourceLock; // guard |mSource|.
- SourceInfo mCurrentSourceInfo;
- SourceInfo mNextSourceInfo;
- sp<ANativeWindowWrapper> mNativeWindow;
- sp<MediaPlayer2Interface::AudioSink> mAudioSink;
- sp<DecoderBase> mVideoDecoder;
- bool mOffloadAudio;
- sp<DecoderBase> mAudioDecoder;
- Mutex mDecoderLock; // guard |mAudioDecoder| and |mVideoDecoder|.
- sp<CCDecoder> mCCDecoder;
- sp<Renderer> mRenderer;
- sp<ALooper> mRendererLooper;
- int32_t mAudioDecoderGeneration;
- int32_t mVideoDecoderGeneration;
- int32_t mRendererGeneration;
- int32_t mEOSMonitorGeneration;
-
- Mutex mPlayingTimeLock;
- int64_t mLastStartedPlayingTimeNs;
- void stopPlaybackTimer(const char *where);
- void startPlaybackTimer(const char *where);
-
- int64_t mLastStartedRebufferingTimeNs;
- void startRebufferingTimer();
- void stopRebufferingTimer(bool exitingPlayback);
-
- int64_t mPreviousSeekTimeUs;
-
- List<sp<Action> > mDeferredActions;
-
- bool mAudioEOS;
- bool mVideoEOS;
-
- bool mScanSourcesPending;
- int32_t mScanSourcesGeneration;
-
- int32_t mPollDurationGeneration;
- int32_t mTimedTextGeneration;
-
- enum FlushStatus {
- NONE,
- FLUSHING_DECODER,
- FLUSHING_DECODER_SHUTDOWN,
- SHUTTING_DOWN_DECODER,
- FLUSHED,
- SHUT_DOWN,
- };
-
- enum FlushCommand {
- FLUSH_CMD_NONE,
- FLUSH_CMD_FLUSH,
- FLUSH_CMD_SHUTDOWN,
- };
-
- // Status of flush responses from the decoder and renderer.
- bool mFlushComplete[2][2];
-
- FlushStatus mFlushingAudio;
- FlushStatus mFlushingVideo;
-
- // Status of flush responses from the decoder and renderer.
- bool mResumePending;
-
- int32_t mVideoScalingMode;
-
- AudioPlaybackRate mPlaybackSettings;
- AVSyncSettings mSyncSettings;
- float mVideoFpsHint;
- bool mStarted;
- bool mPrepared;
- bool mResetting;
- bool mSourceStarted;
- bool mAudioDecoderError;
- bool mVideoDecoderError;
-
- // Actual pause state, either as requested by client or due to buffering.
- bool mPaused;
-
- // Pause state as requested by client. Note that if mPausedByClient is
- // true, mPaused is always true; if mPausedByClient is false, mPaused could
- // still become true, when we pause internally due to buffering.
- bool mPausedByClient;
-
- // Pause state as requested by source (internally) due to buffering
- bool mPausedForBuffering;
-
- // Passed from JAVA
- const sp<JObjectHolder> mContext;
-
- inline const sp<DecoderBase> &getDecoder(bool audio) {
- return audio ? mAudioDecoder : mVideoDecoder;
- }
-
- inline void clearFlushComplete() {
- mFlushComplete[0][0] = false;
- mFlushComplete[0][1] = false;
- mFlushComplete[1][0] = false;
- mFlushComplete[1][1] = false;
- }
-
- void disconnectSource();
-
- status_t createNuPlayer2Source(const sp<DataSourceDesc> &dsd,
- sp<Source> *source,
- DATA_SOURCE_TYPE *dataSourceType);
-
- void tryOpenAudioSinkForOffload(
- const sp<AMessage> &format, const sp<MetaData> &audioMeta, bool hasVideo);
- void closeAudioSink();
- void restartAudio(
- int64_t currentPositionUs, bool forceNonOffload, bool needsToCreateAudioDecoder);
- void determineAudioModeChange(const sp<AMessage> &audioFormat);
-
- status_t instantiateDecoder(
- bool audio, sp<DecoderBase> *decoder, bool checkAudioModeChange = true);
-
- void updateVideoSize(
- int64_t srcId,
- const sp<AMessage> &inputFormat,
- const sp<AMessage> &outputFormat = NULL);
-
- void notifyListener(int64_t srcId, int msg, int ext1, int ext2, const PlayerMessage *in = NULL);
-
- void addEndTimeMonitor();
-
- void handleFlushComplete(bool audio, bool isDecoder);
- void finishFlushIfPossible();
-
- void onStart(bool play);
- void onResume();
- void onPause();
-
- bool audioDecoderStillNeeded();
-
- void flushDecoder(bool audio, bool needShutdown);
-
- void finishResume();
- void notifyDriverSeekComplete(int64_t srcId);
-
- void postScanSources();
-
- void schedulePollDuration();
- void cancelPollDuration();
-
- void processDeferredActions();
-
- void performSeek(int64_t seekTimeUs, MediaPlayer2SeekMode mode);
- void performDecoderFlush(FlushCommand audio, FlushCommand video);
- void performReset();
- void performPlayNextDataSource();
- void performScanSources();
- void performSetSurface(const sp<ANativeWindowWrapper> &nw);
- void performResumeDecoders(bool needNotify);
-
- void onSourceNotify(const sp<AMessage> &msg);
- void onClosedCaptionNotify(const sp<AMessage> &msg);
-
- void queueDecoderShutdown(
- bool audio, bool video, const sp<AMessage> &reply);
-
- void sendSubtitleData(const sp<ABuffer> &buffer, int32_t baseIndex);
- void sendTimedMetaData(const sp<ABuffer> &buffer);
- void sendTimedTextData(const sp<ABuffer> &buffer);
-
- void writeTrackInfo(PlayerMessage* reply, const sp<AMessage>& format) const;
-
- status_t onPrepareDrm(const sp<AMessage> &msg);
- status_t onReleaseDrm(const sp<AMessage> &msg);
-
- SourceInfo* getSourceInfoByIdInMsg(const sp<AMessage> &msg);
- void resetSourceInfo(SourceInfo &srcInfo);
-
- DISALLOW_EVIL_CONSTRUCTORS(NuPlayer2);
-};
-
-} // namespace android
-
-#endif // NU_PLAYER2_H_
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.cpp
deleted file mode 100644
index 98c3403..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.cpp
+++ /dev/null
@@ -1,606 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NuPlayer2CCDecoder"
-#include <utils/Log.h>
-#include <inttypes.h>
-
-#include "NuPlayer2CCDecoder.h"
-
-#include <media/NdkMediaFormat.h>
-#include <media/stagefright/foundation/ABitReader.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/foundation/avc_utils.h>
-#include <media/stagefright/MediaDefs.h>
-
-namespace android {
-
-// In CEA-708B, the maximum bandwidth of CC is set to 9600bps.
-static const size_t kMaxBandwithSizeBytes = 9600 / 8;
-
-struct CCData {
- CCData(uint8_t type, uint8_t data1, uint8_t data2)
- : mType(type), mData1(data1), mData2(data2) {
- }
- bool getChannel(size_t *channel) const {
- if (mData1 >= 0x10 && mData1 <= 0x1f) {
- *channel = (mData1 >= 0x18 ? 1 : 0) + (mType ? 2 : 0);
- return true;
- }
- return false;
- }
-
- uint8_t mType;
- uint8_t mData1;
- uint8_t mData2;
-};
-
-static bool isNullPad(CCData *cc) {
- return cc->mData1 < 0x10 && cc->mData2 < 0x10;
-}
-
-static void dumpBytePair(const sp<ABuffer> &ccBuf) __attribute__ ((unused));
-static void dumpBytePair(const sp<ABuffer> &ccBuf) {
- size_t offset = 0;
- AString out;
-
- while (offset < ccBuf->size()) {
- char tmp[128];
-
- CCData *cc = (CCData *) (ccBuf->data() + offset);
-
- if (isNullPad(cc)) {
- // 1 null pad or XDS metadata, ignore
- offset += sizeof(CCData);
- continue;
- }
-
- if (cc->mData1 >= 0x20 && cc->mData1 <= 0x7f) {
- // 2 basic chars
- snprintf(tmp, sizeof(tmp), "[%d]Basic: %c %c", cc->mType, cc->mData1, cc->mData2);
- } else if ((cc->mData1 == 0x11 || cc->mData1 == 0x19)
- && cc->mData2 >= 0x30 && cc->mData2 <= 0x3f) {
- // 1 special char
- snprintf(tmp, sizeof(tmp), "[%d]Special: %02x %02x", cc->mType, cc->mData1, cc->mData2);
- } else if ((cc->mData1 == 0x12 || cc->mData1 == 0x1A)
- && cc->mData2 >= 0x20 && cc->mData2 <= 0x3f){
- // 1 Spanish/French char
- snprintf(tmp, sizeof(tmp), "[%d]Spanish: %02x %02x", cc->mType, cc->mData1, cc->mData2);
- } else if ((cc->mData1 == 0x13 || cc->mData1 == 0x1B)
- && cc->mData2 >= 0x20 && cc->mData2 <= 0x3f){
- // 1 Portuguese/German/Danish char
- snprintf(tmp, sizeof(tmp), "[%d]German: %02x %02x", cc->mType, cc->mData1, cc->mData2);
- } else if ((cc->mData1 == 0x11 || cc->mData1 == 0x19)
- && cc->mData2 >= 0x20 && cc->mData2 <= 0x2f){
- // Mid-Row Codes (Table 69)
- snprintf(tmp, sizeof(tmp), "[%d]Mid-row: %02x %02x", cc->mType, cc->mData1, cc->mData2);
- } else if (((cc->mData1 == 0x14 || cc->mData1 == 0x1c)
- && cc->mData2 >= 0x20 && cc->mData2 <= 0x2f)
- ||
- ((cc->mData1 == 0x17 || cc->mData1 == 0x1f)
- && cc->mData2 >= 0x21 && cc->mData2 <= 0x23)){
- // Misc Control Codes (Table 70)
- snprintf(tmp, sizeof(tmp), "[%d]Ctrl: %02x %02x", cc->mType, cc->mData1, cc->mData2);
- } else if ((cc->mData1 & 0x70) == 0x10
- && (cc->mData2 & 0x40) == 0x40
- && ((cc->mData1 & 0x07) || !(cc->mData2 & 0x20)) ) {
- // Preamble Address Codes (Table 71)
- snprintf(tmp, sizeof(tmp), "[%d]PAC: %02x %02x", cc->mType, cc->mData1, cc->mData2);
- } else {
- snprintf(tmp, sizeof(tmp), "[%d]Invalid: %02x %02x", cc->mType, cc->mData1, cc->mData2);
- }
-
- if (out.size() > 0) {
- out.append(", ");
- }
-
- out.append(tmp);
-
- offset += sizeof(CCData);
- }
-
- ALOGI("%s", out.c_str());
-}
-
-NuPlayer2::CCDecoder::CCDecoder(const sp<AMessage> ¬ify)
- : mNotify(notify),
- mSelectedTrack(-1),
- mDTVCCPacket(new ABuffer(kMaxBandwithSizeBytes)) {
- mDTVCCPacket->setRange(0, 0);
-
- // In CEA-608, streams from packets which have the value 0 of cc_type contain CC1 and CC2, and
- // streams from packets which have the value 1 of cc_type contain CC3 and CC4.
- // The following array indicates the current transmitting channels for each value of cc_type.
- mLine21Channels[0] = 0; // CC1
- mLine21Channels[1] = 2; // CC3
-}
-
-size_t NuPlayer2::CCDecoder::getTrackCount() const {
- return mTracks.size();
-}
-
-sp<AMessage> NuPlayer2::CCDecoder::getTrackInfo(size_t index) const {
- if (!isTrackValid(index)) {
- return NULL;
- }
-
- sp<AMessage> format = new AMessage();
-
- CCTrack track = mTracks[index];
-
- format->setInt32("type", MEDIA_TRACK_TYPE_SUBTITLE);
- format->setString("language", "und");
-
- switch (track.mTrackType) {
- case kTrackTypeCEA608:
- format->setString("mime", MEDIA_MIMETYPE_TEXT_CEA_608);
- break;
- case kTrackTypeCEA708:
- format->setString("mime", MEDIA_MIMETYPE_TEXT_CEA_708);
- break;
- default:
- ALOGE("Unknown track type: %d", track.mTrackType);
- return NULL;
- }
-
- // For CEA-608 CC1, field 0 channel 0
- bool isDefaultAuto = track.mTrackType == kTrackTypeCEA608
- && track.mTrackChannel == 0;
- // For CEA-708, Primary Caption Service.
- bool isDefaultOnly = track.mTrackType == kTrackTypeCEA708
- && track.mTrackChannel == 1;
- format->setInt32("auto", isDefaultAuto);
- format->setInt32("default", isDefaultAuto || isDefaultOnly);
- format->setInt32("forced", 0);
-
- return format;
-}
-
-status_t NuPlayer2::CCDecoder::selectTrack(size_t index, bool select) {
- if (!isTrackValid(index)) {
- return BAD_VALUE;
- }
-
- if (select) {
- if (mSelectedTrack == (ssize_t)index) {
- ALOGE("track %zu already selected", index);
- return BAD_VALUE;
- }
- ALOGV("selected track %zu", index);
- mSelectedTrack = index;
- } else {
- if (mSelectedTrack != (ssize_t)index) {
- ALOGE("track %zu is not selected", index);
- return BAD_VALUE;
- }
- ALOGV("unselected track %zu", index);
- mSelectedTrack = -1;
- }
-
- // Clear the previous track payloads
- mCCMap.clear();
-
- return OK;
-}
-
-ssize_t NuPlayer2::CCDecoder::getSelectedTrack(media_track_type type) const {
- if (mSelectedTrack != -1) {
- CCTrack track = mTracks[mSelectedTrack];
- if (track.mTrackType == kTrackTypeCEA608 || track.mTrackType == kTrackTypeCEA708) {
- return (type == MEDIA_TRACK_TYPE_SUBTITLE ? mSelectedTrack : -1);
- }
- return (type == MEDIA_TRACK_TYPE_UNKNOWN ? mSelectedTrack : -1);
- }
-
- return -1;
-}
-
-bool NuPlayer2::CCDecoder::isSelected() const {
- return mSelectedTrack >= 0 && mSelectedTrack < (int32_t)getTrackCount();
-}
-
-bool NuPlayer2::CCDecoder::isTrackValid(size_t index) const {
- return index < getTrackCount();
-}
-
-// returns true if a new CC track is found
-bool NuPlayer2::CCDecoder::extractFromSEI(const sp<ABuffer> &accessUnit) {
- sp<ABuffer> sei;
- if (!accessUnit->meta()->findBuffer("sei", &sei) || sei == NULL) {
- return false;
- }
-
- int64_t timeUs;
- CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
-
- bool trackAdded = false;
-
- const NALPosition *nal = (NALPosition *)sei->data();
-
- for (size_t i = 0; i < sei->size() / sizeof(NALPosition); ++i, ++nal) {
- trackAdded |= parseSEINalUnit(
- timeUs, accessUnit->data() + nal->nalOffset, nal->nalSize);
- }
-
- return trackAdded;
-}
-
-// returns true if a new CC track is found
-bool NuPlayer2::CCDecoder::parseSEINalUnit(int64_t timeUs, const uint8_t *data, size_t size) {
- unsigned nalType = data[0] & 0x1f;
-
- // the buffer should only have SEI in it
- if (nalType != 6) {
- return false;
- }
-
- bool trackAdded = false;
- NALBitReader br(data + 1, size - 1);
-
- // sei_message()
- while (br.atLeastNumBitsLeft(16)) { // at least 16-bit for sei_message()
- uint32_t payload_type = 0;
- size_t payload_size = 0;
- uint8_t last_byte;
-
- do {
- last_byte = br.getBits(8);
- payload_type += last_byte;
- } while (last_byte == 0xFF);
-
- do {
- last_byte = br.getBits(8);
- payload_size += last_byte;
- } while (last_byte == 0xFF);
-
- if (payload_size > SIZE_MAX / 8
- || !br.atLeastNumBitsLeft(payload_size * 8)) {
- ALOGV("Malformed SEI payload");
- break;
- }
-
- // sei_payload()
- if (payload_type == 4) {
- bool isCC = false;
- if (payload_size > 1 + 2 + 4 + 1) {
- // user_data_registered_itu_t_t35()
-
- // ATSC A/72: 6.4.2
- uint8_t itu_t_t35_country_code = br.getBits(8);
- uint16_t itu_t_t35_provider_code = br.getBits(16);
- uint32_t user_identifier = br.getBits(32);
- uint8_t user_data_type_code = br.getBits(8);
-
- payload_size -= 1 + 2 + 4 + 1;
-
- isCC = itu_t_t35_country_code == 0xB5
- && itu_t_t35_provider_code == 0x0031
- && user_identifier == 'GA94'
- && user_data_type_code == 0x3;
- }
-
- if (isCC && payload_size > 2) {
- trackAdded |= parseMPEGCCData(timeUs, br.data(), br.numBitsLeft() / 8);
- } else {
- ALOGV("Malformed SEI payload type 4");
- }
- } else {
- ALOGV("Unsupported SEI payload type %d", payload_type);
- }
-
- // skipping remaining bits of this payload
- br.skipBits(payload_size * 8);
- }
-
- return trackAdded;
-}
-
-// returns true if a new CC track is found
-bool NuPlayer2::CCDecoder::extractFromMPEGUserData(const sp<ABuffer> &accessUnit) {
- sp<ABuffer> mpegUserData;
- if (!accessUnit->meta()->findBuffer(AMEDIAFORMAT_KEY_MPEG_USER_DATA, &mpegUserData)
- || mpegUserData == NULL) {
- return false;
- }
-
- int64_t timeUs;
- CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
-
- bool trackAdded = false;
-
- const size_t *userData = (size_t *)mpegUserData->data();
-
- for (size_t i = 0; i < mpegUserData->size() / sizeof(size_t); ++i) {
- trackAdded |= parseMPEGUserDataUnit(
- timeUs, accessUnit->data() + userData[i], accessUnit->size() - userData[i]);
- }
-
- return trackAdded;
-}
-
-// returns true if a new CC track is found
-bool NuPlayer2::CCDecoder::parseMPEGUserDataUnit(int64_t timeUs, const uint8_t *data, size_t size) {
- ABitReader br(data + 4, 5);
-
- uint32_t user_identifier = br.getBits(32);
- uint8_t user_data_type = br.getBits(8);
-
- if (user_identifier == 'GA94' && user_data_type == 0x3) {
- return parseMPEGCCData(timeUs, data + 9, size - 9);
- }
-
- return false;
-}
-
-// returns true if a new CC track is found
-bool NuPlayer2::CCDecoder::parseMPEGCCData(int64_t timeUs, const uint8_t *data, size_t size) {
- bool trackAdded = false;
-
- // MPEG_cc_data()
- // ATSC A/53 Part 4: 6.2.3.1
- ABitReader br(data, size);
-
- if (br.numBitsLeft() <= 16) {
- return false;
- }
-
- br.skipBits(1);
- bool process_cc_data_flag = br.getBits(1);
- br.skipBits(1);
- size_t cc_count = br.getBits(5);
- br.skipBits(8);
-
- if (!process_cc_data_flag || 3 * 8 * cc_count >= br.numBitsLeft()) {
- return false;
- }
-
- sp<ABuffer> line21CCBuf = NULL;
-
- for (size_t i = 0; i < cc_count; ++i) {
- br.skipBits(5);
- bool cc_valid = br.getBits(1);
- uint8_t cc_type = br.getBits(2);
-
- if (cc_valid) {
- if (cc_type == 3) {
- if (mDTVCCPacket->size() > 0) {
- trackAdded |= parseDTVCCPacket(
- timeUs, mDTVCCPacket->data(), mDTVCCPacket->size());
- mDTVCCPacket->setRange(0, 0);
- }
- if (mDTVCCPacket->size() + 2 > mDTVCCPacket->capacity()) {
- return false;
- }
- memcpy(mDTVCCPacket->data() + mDTVCCPacket->size(), br.data(), 2);
- mDTVCCPacket->setRange(0, mDTVCCPacket->size() + 2);
- br.skipBits(16);
- } else if (mDTVCCPacket->size() > 0 && cc_type == 2) {
- if (mDTVCCPacket->size() + 2 > mDTVCCPacket->capacity()) {
- return false;
- }
- memcpy(mDTVCCPacket->data() + mDTVCCPacket->size(), br.data(), 2);
- mDTVCCPacket->setRange(0, mDTVCCPacket->size() + 2);
- br.skipBits(16);
- } else if (cc_type == 0 || cc_type == 1) {
- uint8_t cc_data_1 = br.getBits(8) & 0x7f;
- uint8_t cc_data_2 = br.getBits(8) & 0x7f;
-
- CCData cc(cc_type, cc_data_1, cc_data_2);
-
- if (isNullPad(&cc)) {
- continue;
- }
-
- size_t channel;
- if (cc.getChannel(&channel)) {
- mLine21Channels[cc_type] = channel;
-
- // create a new track if it does not exist.
- getTrackIndex(kTrackTypeCEA608, channel, &trackAdded);
- }
-
- if (isSelected() && mTracks[mSelectedTrack].mTrackType == kTrackTypeCEA608
- && mTracks[mSelectedTrack].mTrackChannel == mLine21Channels[cc_type]) {
- if (line21CCBuf == NULL) {
- line21CCBuf = new ABuffer((cc_count - i) * sizeof(CCData));
- line21CCBuf->setRange(0, 0);
- }
- if (line21CCBuf->size() + sizeof(cc) > line21CCBuf->capacity()) {
- return false;
- }
- memcpy(line21CCBuf->data() + line21CCBuf->size(), &cc, sizeof(cc));
- line21CCBuf->setRange(0, line21CCBuf->size() + sizeof(CCData));
- }
- } else {
- br.skipBits(16);
- }
- } else {
- if ((cc_type == 3 || cc_type == 2) && mDTVCCPacket->size() > 0) {
- trackAdded |= parseDTVCCPacket(timeUs, mDTVCCPacket->data(), mDTVCCPacket->size());
- mDTVCCPacket->setRange(0, 0);
- }
- br.skipBits(16);
- }
- }
-
- if (isSelected() && mTracks[mSelectedTrack].mTrackType == kTrackTypeCEA608
- && line21CCBuf != NULL && line21CCBuf->size() > 0) {
- mCCMap.add(timeUs, line21CCBuf);
- }
-
- return trackAdded;
-}
-
-// returns true if a new CC track is found
-bool NuPlayer2::CCDecoder::parseDTVCCPacket(int64_t timeUs, const uint8_t *data, size_t size) {
- // CEA-708B 5 DTVCC Packet Layer.
- ABitReader br(data, size);
- br.skipBits(2);
-
- size_t packet_size = br.getBits(6);
- if (packet_size == 0) packet_size = 64;
- packet_size *= 2;
-
- if (size != packet_size) {
- return false;
- }
-
- bool trackAdded = false;
-
- while (br.numBitsLeft() >= 16) {
- // CEA-708B Figure 5 and 6.
- uint8_t service_number = br.getBits(3);
- size_t block_size = br.getBits(5);
-
- if (service_number == 64) {
- br.skipBits(2);
- service_number = br.getBits(6);
-
- if (service_number < 64) {
- return trackAdded;
- }
- }
-
- if (br.numBitsLeft() < block_size * 8) {
- return trackAdded;
- }
-
- if (block_size > 0) {
- size_t trackIndex = getTrackIndex(kTrackTypeCEA708, service_number, &trackAdded);
- if (mSelectedTrack == (ssize_t)trackIndex) {
- sp<ABuffer> ccPacket = new ABuffer(block_size);
- if (ccPacket->capacity() == 0) {
- return false;
- }
- memcpy(ccPacket->data(), br.data(), block_size);
- mCCMap.add(timeUs, ccPacket);
- }
- }
- br.skipBits(block_size * 8);
- }
-
- return trackAdded;
-}
-
-// return the track index for a given type and channel.
-// if the track does not exist, creates a new one.
-size_t NuPlayer2::CCDecoder::getTrackIndex(
- int32_t trackType, size_t channel, bool *trackAdded) {
- CCTrack track(trackType, channel);
- ssize_t index = mTrackIndices.indexOfKey(track);
-
- if (index < 0) {
- // A new track is added.
- index = mTracks.size();
- mTrackIndices.add(track, index);
- mTracks.add(track);
- *trackAdded = true;
- return index;
- }
-
- return mTrackIndices.valueAt(index);
-}
-
-void NuPlayer2::CCDecoder::decode(const sp<ABuffer> &accessUnit) {
- if (extractFromMPEGUserData(accessUnit) || extractFromSEI(accessUnit)) {
- sp<AMessage> msg = mNotify->dup();
- msg->setInt32("what", kWhatTrackAdded);
- msg->post();
- }
- // TODO: extract CC from other sources
-}
-
-void NuPlayer2::CCDecoder::display(int64_t timeUs) {
- if (!isSelected()) {
- return;
- }
-
- ssize_t index = mCCMap.indexOfKey(timeUs);
- if (index < 0) {
- ALOGV("cc for timestamp %" PRId64 " not found", timeUs);
- return;
- }
-
- sp<ABuffer> ccBuf;
-
- if (index == 0) {
- ccBuf = mCCMap.valueAt(index);
- } else {
- size_t size = 0;
-
- for (ssize_t i = 0; i <= index; ++i) {
- size += mCCMap.valueAt(i)->size();
- }
-
- ccBuf = new ABuffer(size);
- ccBuf->setRange(0, 0);
-
- if (ccBuf->capacity() > 0) {
- for (ssize_t i = 0; i <= index; ++i) {
- sp<ABuffer> buf = mCCMap.valueAt(i);
- memcpy(ccBuf->data() + ccBuf->size(), buf->data(), buf->size());
- ccBuf->setRange(0, ccBuf->size() + buf->size());
- }
- }
- }
-
- if (ccBuf->size() > 0) {
-#if 0
- dumpBytePair(ccBuf);
-#endif
-
- ccBuf->meta()->setInt32(AMEDIAFORMAT_KEY_TRACK_INDEX, mSelectedTrack);
- ccBuf->meta()->setInt64("timeUs", timeUs);
- ccBuf->meta()->setInt64("durationUs", 0LL);
-
- sp<AMessage> msg = mNotify->dup();
- msg->setInt32("what", kWhatClosedCaptionData);
- msg->setBuffer("buffer", ccBuf);
- msg->post();
- }
-
- // remove all entries before timeUs
- mCCMap.removeItemsAt(0, index + 1);
-}
-
-void NuPlayer2::CCDecoder::flush() {
- mCCMap.clear();
- mDTVCCPacket->setRange(0, 0);
-}
-
-int32_t NuPlayer2::CCDecoder::CCTrack::compare(const NuPlayer2::CCDecoder::CCTrack& rhs) const {
- int32_t cmp = mTrackType - rhs.mTrackType;
- if (cmp != 0) return cmp;
- return mTrackChannel - rhs.mTrackChannel;
-}
-
-bool NuPlayer2::CCDecoder::CCTrack::operator<(const NuPlayer2::CCDecoder::CCTrack& rhs) const {
- return compare(rhs) < 0;
-}
-
-bool NuPlayer2::CCDecoder::CCTrack::operator==(const NuPlayer2::CCDecoder::CCTrack& rhs) const {
- return compare(rhs) == 0;
-}
-
-bool NuPlayer2::CCDecoder::CCTrack::operator!=(const NuPlayer2::CCDecoder::CCTrack& rhs) const {
- return compare(rhs) != 0;
-}
-
-} // namespace android
-
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.h b/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.h
deleted file mode 100644
index 97834d1..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NUPLAYER2_CCDECODER_H_
-
-#define NUPLAYER2_CCDECODER_H_
-
-#include "NuPlayer2.h"
-
-namespace android {
-
-struct NuPlayer2::CCDecoder : public RefBase {
- enum {
- kWhatClosedCaptionData,
- kWhatTrackAdded,
- };
-
- enum {
- kTrackTypeCEA608,
- kTrackTypeCEA708,
- };
-
- explicit CCDecoder(const sp<AMessage> ¬ify);
-
- size_t getTrackCount() const;
- sp<AMessage> getTrackInfo(size_t index) const;
- status_t selectTrack(size_t index, bool select);
- ssize_t getSelectedTrack(media_track_type type) const;
- bool isSelected() const;
- void decode(const sp<ABuffer> &accessUnit);
- void display(int64_t timeUs);
- void flush();
-
-private:
- // CC track identifier.
- struct CCTrack {
- CCTrack() : mTrackType(0), mTrackChannel(0) { }
-
- CCTrack(const int32_t trackType, const size_t trackChannel)
- : mTrackType(trackType), mTrackChannel(trackChannel) { }
-
- int32_t mTrackType;
- size_t mTrackChannel;
-
- // The ordering of CCTracks is to build a map of track to index.
- // It is necessary to find the index of the matched CCTrack when CC data comes.
- int compare(const NuPlayer2::CCDecoder::CCTrack& rhs) const;
- inline bool operator<(const NuPlayer2::CCDecoder::CCTrack& rhs) const;
- inline bool operator==(const NuPlayer2::CCDecoder::CCTrack& rhs) const;
- inline bool operator!=(const NuPlayer2::CCDecoder::CCTrack& rhs) const;
- };
-
- sp<AMessage> mNotify;
- KeyedVector<int64_t, sp<ABuffer> > mCCMap;
- ssize_t mSelectedTrack;
- KeyedVector<CCTrack, size_t> mTrackIndices;
- Vector<CCTrack> mTracks;
-
- // CEA-608 closed caption
- size_t mLine21Channels[2]; // The current channels of NTSC_CC_FIELD_{1, 2}
-
- // CEA-708 closed caption
- sp<ABuffer> mDTVCCPacket;
-
- bool isTrackValid(size_t index) const;
- size_t getTrackIndex(int32_t trackType, size_t channel, bool *trackAdded);
-
- // Extract from H.264 SEIs
- bool extractFromSEI(const sp<ABuffer> &accessUnit);
- bool parseSEINalUnit(int64_t timeUs, const uint8_t *data, size_t size);
-
- // Extract from MPEG user data
- bool extractFromMPEGUserData(const sp<ABuffer> &accessUnit);
- bool parseMPEGUserDataUnit(int64_t timeUs, const uint8_t *data, size_t size);
-
- // Extract CC tracks from MPEG_cc_data
- bool parseMPEGCCData(int64_t timeUs, const uint8_t *data, size_t size);
- bool parseDTVCCPacket(int64_t timeUs, const uint8_t *data, size_t size);
-
- DISALLOW_EVIL_CONSTRUCTORS(CCDecoder);
-};
-
-} // namespace android
-
-#endif // NUPLAYER2_CCDECODER_H_
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp
deleted file mode 100644
index 66bfae5..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp
+++ /dev/null
@@ -1,1315 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NuPlayer2Decoder"
-#include <utils/Log.h>
-#include <inttypes.h>
-
-#include <algorithm>
-
-#include "NuPlayer2CCDecoder.h"
-#include "NuPlayer2Decoder.h"
-#include "NuPlayer2Drm.h"
-#include "NuPlayer2Renderer.h"
-#include "NuPlayer2Source.h"
-
-#include <cutils/properties.h>
-#include <media/MediaBufferHolder.h>
-#include <media/MediaCodecBuffer.h>
-#include <media/NdkMediaCodec.h>
-#include <media/NdkWrapper.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/foundation/avc_utils.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/SurfaceUtils.h>
-
-#include <system/window.h>
-#include "ATSParser.h"
-
-namespace android {
-
-static float kDisplayRefreshingRate = 60.f; // TODO: get this from the display
-
-// The default total video frame rate of a stream when that info is not available from
-// the source.
-static float kDefaultVideoFrameRateTotal = 30.f;
-
-static inline bool getAudioDeepBufferSetting() {
- return property_get_bool("media.stagefright.audio.deep", false /* default_value */);
-}
-
-NuPlayer2::Decoder::Decoder(
- const sp<AMessage> ¬ify,
- const sp<Source> &source,
- pid_t pid,
- uid_t uid,
- const sp<Renderer> &renderer,
- const sp<ANativeWindowWrapper> &nww,
- const sp<CCDecoder> &ccDecoder)
- : DecoderBase(notify),
- mNativeWindow(nww),
- mSource(source),
- mRenderer(renderer),
- mCCDecoder(ccDecoder),
- mPid(pid),
- mUid(uid),
- mSkipRenderingUntilMediaTimeUs(-1LL),
- mNumFramesTotal(0LL),
- mNumInputFramesDropped(0LL),
- mNumOutputFramesDropped(0LL),
- mVideoWidth(0),
- mVideoHeight(0),
- mIsAudio(true),
- mIsVideoAVC(false),
- mIsSecure(false),
- mIsEncrypted(false),
- mIsEncryptedObservedEarlier(false),
- mFormatChangePending(false),
- mTimeChangePending(false),
- mFrameRateTotal(kDefaultVideoFrameRateTotal),
- mPlaybackSpeed(1.0f),
- mNumVideoTemporalLayerTotal(1), // decode all layers
- mNumVideoTemporalLayerAllowed(1),
- mCurrentMaxVideoTemporalLayerId(0),
- mResumePending(false),
- mComponentName("decoder") {
- mVideoTemporalLayerAggregateFps[0] = mFrameRateTotal;
-}
-
-NuPlayer2::Decoder::~Decoder() {
- // Need to stop looper first since mCodec could be accessed on the mDecoderLooper.
- stopLooper();
- if (mCodec != NULL) {
- mCodec->release();
- }
- releaseAndResetMediaBuffers();
-}
-
-sp<AMessage> NuPlayer2::Decoder::getStats() const {
- mStats->setInt64("frames-total", mNumFramesTotal);
- mStats->setInt64("frames-dropped-input", mNumInputFramesDropped);
- mStats->setInt64("frames-dropped-output", mNumOutputFramesDropped);
- mStats->setFloat("frame-rate-total", mFrameRateTotal);
-
- // i'm mutexed right now.
- // make our own copy, so we aren't victim to any later changes.
- sp<AMessage> copiedStats = mStats->dup();
- return copiedStats;
-}
-
-status_t NuPlayer2::Decoder::setVideoSurface(const sp<ANativeWindowWrapper> &nww) {
- if (nww == NULL || nww->getANativeWindow() == NULL
- || ADebug::isExperimentEnabled("legacy-setsurface")) {
- return BAD_VALUE;
- }
-
- sp<AMessage> msg = new AMessage(kWhatSetVideoSurface, this);
-
- msg->setObject("surface", nww);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- }
- return err;
-}
-
-void NuPlayer2::Decoder::onMessageReceived(const sp<AMessage> &msg) {
- ALOGV("[%s] onMessage: %s", mComponentName.c_str(), msg->debugString().c_str());
-
- switch (msg->what()) {
- case kWhatCodecNotify:
- {
- int32_t cbID;
- CHECK(msg->findInt32("callbackID", &cbID));
-
- ALOGV("[%s] kWhatCodecNotify: cbID = %d, paused = %d",
- mIsAudio ? "audio" : "video", cbID, mPaused);
-
- if (mPaused) {
- break;
- }
-
- switch (cbID) {
- case AMediaCodecWrapper::CB_INPUT_AVAILABLE:
- {
- int32_t index;
- CHECK(msg->findInt32("index", &index));
-
- handleAnInputBuffer(index);
- break;
- }
-
- case AMediaCodecWrapper::CB_OUTPUT_AVAILABLE:
- {
- int32_t index;
- size_t offset;
- size_t size;
- int64_t timeUs;
- int32_t flags;
-
- CHECK(msg->findInt32("index", &index));
- CHECK(msg->findSize("offset", &offset));
- CHECK(msg->findSize("size", &size));
- CHECK(msg->findInt64("timeUs", &timeUs));
- CHECK(msg->findInt32("flags", &flags));
-
- handleAnOutputBuffer(index, offset, size, timeUs, flags);
- break;
- }
-
- case AMediaCodecWrapper::CB_OUTPUT_FORMAT_CHANGED:
- {
- sp<AMessage> format;
- CHECK(msg->findMessage("format", &format));
-
- handleOutputFormatChange(format);
- break;
- }
-
- case AMediaCodecWrapper::CB_ERROR:
- {
- status_t err;
- CHECK(msg->findInt32("err", &err));
- ALOGE("Decoder (%s) reported error : 0x%x",
- mIsAudio ? "audio" : "video", err);
-
- handleError(err);
- break;
- }
-
- default:
- {
- TRESPASS();
- break;
- }
- }
-
- break;
- }
-
- case kWhatRenderBuffer:
- {
- if (!isStaleReply(msg)) {
- onRenderBuffer(msg);
- }
- break;
- }
-
- case kWhatAudioOutputFormatChanged:
- {
- if (!isStaleReply(msg)) {
- status_t err;
- if (msg->findInt32("err", &err) && err != OK) {
- ALOGE("Renderer reported 0x%x when changing audio output format", err);
- handleError(err);
- }
- }
- break;
- }
-
- case kWhatSetVideoSurface:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
- sp<RefBase> obj;
- CHECK(msg->findObject("surface", &obj));
- sp<ANativeWindowWrapper> nww =
- static_cast<ANativeWindowWrapper *>(obj.get()); // non-null
- if (nww == NULL || nww->getANativeWindow() == NULL) {
- break;
- }
- int32_t err = INVALID_OPERATION;
- // NOTE: in practice mNativeWindow is always non-null,
- // but checking here for completeness
- if (mCodec != NULL
- && mNativeWindow != NULL && mNativeWindow->getANativeWindow() != NULL) {
- // TODO: once AwesomePlayer is removed, remove this automatic connecting
- // to the surface by MediaPlayerService.
- //
- // at this point MediaPlayer2Manager::client has already connected to the
- // surface, which MediaCodec does not expect
- err = native_window_api_disconnect(nww->getANativeWindow(),
- NATIVE_WINDOW_API_MEDIA);
- if (err == OK) {
- err = mCodec->setOutputSurface(nww);
- ALOGI_IF(err, "codec setOutputSurface returned: %d", err);
- if (err == OK) {
- // reconnect to the old surface as MPS::Client will expect to
- // be able to disconnect from it.
- (void)native_window_api_connect(mNativeWindow->getANativeWindow(),
- NATIVE_WINDOW_API_MEDIA);
-
- mNativeWindow = nww;
- }
- }
- if (err != OK) {
- // reconnect to the new surface on error as MPS::Client will expect to
- // be able to disconnect from it.
- (void)native_window_api_connect(nww->getANativeWindow(),
- NATIVE_WINDOW_API_MEDIA);
- }
- }
-
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatDrmReleaseCrypto:
- {
- ALOGV("kWhatDrmReleaseCrypto");
- onReleaseCrypto(msg);
- break;
- }
-
- default:
- DecoderBase::onMessageReceived(msg);
- break;
- }
-}
-
-void NuPlayer2::Decoder::onConfigure(const sp<AMessage> &format) {
- ALOGV("[%s] onConfigure (format=%s)", mComponentName.c_str(), format->debugString().c_str());
- CHECK(mCodec == NULL);
-
- mFormatChangePending = false;
- mTimeChangePending = false;
-
- ++mBufferGeneration;
-
- AString mime;
- CHECK(format->findString("mime", &mime));
-
- mIsAudio = !strncasecmp("audio/", mime.c_str(), 6);
- mIsVideoAVC = !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime.c_str());
-
- mComponentName = mime;
- mComponentName.append(" decoder");
- ALOGV("[%s] onConfigure (nww=%p)", mComponentName.c_str(),
- (mNativeWindow == NULL ? NULL : mNativeWindow->getANativeWindow()));
-
- mCodec = AMediaCodecWrapper::CreateDecoderByType(mime);
- int32_t secure = 0;
- if (format->findInt32("secure", &secure) && secure != 0) {
- if (mCodec != NULL) {
- if (mCodec->getName(&mComponentName) == OK) {
- mComponentName.append(".secure");
- mCodec->release();
- ALOGI("[%s] creating", mComponentName.c_str());
- mCodec = AMediaCodecWrapper::CreateCodecByName(mComponentName);
- } else {
- mCodec = NULL;
- }
- }
- }
- if (mCodec == NULL) {
- ALOGE("Failed to create %s%s decoder",
- (secure ? "secure " : ""), mime.c_str());
- handleError(NO_INIT);
- return;
- }
- mIsSecure = secure;
-
- mCodec->getName(&mComponentName);
-
- status_t err;
- if (mNativeWindow != NULL && mNativeWindow->getANativeWindow() != NULL) {
- // disconnect from surface as MediaCodec will reconnect
- err = native_window_api_disconnect(mNativeWindow->getANativeWindow(),
- NATIVE_WINDOW_API_MEDIA);
- // We treat this as a warning, as this is a preparatory step.
- // Codec will try to connect to the surface, which is where
- // any error signaling will occur.
- ALOGW_IF(err != OK, "failed to disconnect from surface: %d", err);
- }
-
- // Modular DRM
- sp<RefBase> objCrypto;
- format->findObject("crypto", &objCrypto);
- sp<AMediaCryptoWrapper> crypto = static_cast<AMediaCryptoWrapper *>(objCrypto.get());
- // non-encrypted source won't have a crypto
- mIsEncrypted = (crypto != NULL);
- // configure is called once; still using OR in case the behavior changes.
- mIsEncryptedObservedEarlier = mIsEncryptedObservedEarlier || mIsEncrypted;
- ALOGV("onConfigure mCrypto: %p, mIsSecure: %d", crypto.get(), mIsSecure);
-
- err = mCodec->configure(
- AMediaFormatWrapper::Create(format),
- mNativeWindow,
- crypto,
- 0 /* flags */);
-
- if (err != OK) {
- ALOGE("Failed to configure [%s] decoder (err=%d)", mComponentName.c_str(), err);
- mCodec->release();
- mCodec.clear();
- handleError(err);
- return;
- }
- rememberCodecSpecificData(format);
-
- // the following should work in configured state
- sp<AMediaFormatWrapper> outputFormat = mCodec->getOutputFormat();
- if (outputFormat == NULL) {
- handleError(INVALID_OPERATION);
- return;
- }
- mInputFormat = mCodec->getInputFormat();
- if (mInputFormat == NULL) {
- handleError(INVALID_OPERATION);
- return;
- }
-
- mStats->setString("mime", mime.c_str());
- mStats->setString("component-name", mComponentName.c_str());
-
- if (!mIsAudio) {
- int32_t width, height;
- if (outputFormat->getInt32("width", &width)
- && outputFormat->getInt32("height", &height)) {
- mStats->setInt32("width", width);
- mStats->setInt32("height", height);
- }
- }
-
- sp<AMessage> reply = new AMessage(kWhatCodecNotify, this);
- mCodec->setCallback(reply);
-
- err = mCodec->start();
- if (err != OK) {
- ALOGE("Failed to start [%s] decoder (err=%d)", mComponentName.c_str(), err);
- mCodec->release();
- mCodec.clear();
- handleError(err);
- return;
- }
-
- releaseAndResetMediaBuffers();
-
- mPaused = false;
- mResumePending = false;
-}
-
-void NuPlayer2::Decoder::onSetParameters(const sp<AMessage> ¶ms) {
- bool needAdjustLayers = false;
- float frameRateTotal;
- if (params->findFloat("frame-rate-total", &frameRateTotal)
- && mFrameRateTotal != frameRateTotal) {
- needAdjustLayers = true;
- mFrameRateTotal = frameRateTotal;
- }
-
- int32_t numVideoTemporalLayerTotal;
- if (params->findInt32("temporal-layer-count", &numVideoTemporalLayerTotal)
- && numVideoTemporalLayerTotal >= 0
- && numVideoTemporalLayerTotal <= kMaxNumVideoTemporalLayers
- && mNumVideoTemporalLayerTotal != numVideoTemporalLayerTotal) {
- needAdjustLayers = true;
- mNumVideoTemporalLayerTotal = std::max(numVideoTemporalLayerTotal, 1);
- }
-
- if (needAdjustLayers && mNumVideoTemporalLayerTotal > 1) {
- // TODO: For now, layer fps is calculated for some specific architectures.
- // But it really should be extracted from the stream.
- mVideoTemporalLayerAggregateFps[0] =
- mFrameRateTotal / (float)(1LL << (mNumVideoTemporalLayerTotal - 1));
- for (int32_t i = 1; i < mNumVideoTemporalLayerTotal; ++i) {
- mVideoTemporalLayerAggregateFps[i] =
- mFrameRateTotal / (float)(1LL << (mNumVideoTemporalLayerTotal - i))
- + mVideoTemporalLayerAggregateFps[i - 1];
- }
- }
-
- float playbackSpeed;
- if (params->findFloat("playback-speed", &playbackSpeed)
- && mPlaybackSpeed != playbackSpeed) {
- needAdjustLayers = true;
- mPlaybackSpeed = playbackSpeed;
- }
-
- if (needAdjustLayers) {
- float decodeFrameRate = mFrameRateTotal;
- // enable temporal layering optimization only if we know the layering depth
- if (mNumVideoTemporalLayerTotal > 1) {
- int32_t layerId;
- for (layerId = 0; layerId < mNumVideoTemporalLayerTotal - 1; ++layerId) {
- if (mVideoTemporalLayerAggregateFps[layerId] * mPlaybackSpeed
- >= kDisplayRefreshingRate * 0.9) {
- break;
- }
- }
- mNumVideoTemporalLayerAllowed = layerId + 1;
- decodeFrameRate = mVideoTemporalLayerAggregateFps[layerId];
- }
- ALOGV("onSetParameters: allowed layers=%d, decodeFps=%g",
- mNumVideoTemporalLayerAllowed, decodeFrameRate);
-
- if (mCodec == NULL) {
- ALOGW("onSetParameters called before codec is created.");
- return;
- }
-
- sp<AMediaFormatWrapper> codecParams = new AMediaFormatWrapper();
- codecParams->setFloat("operating-rate", decodeFrameRate * mPlaybackSpeed);
- mCodec->setParameters(codecParams);
- }
-}
-
-void NuPlayer2::Decoder::onSetRenderer(const sp<Renderer> &renderer) {
- mRenderer = renderer;
-}
-
-void NuPlayer2::Decoder::onResume(bool notifyComplete) {
- mPaused = false;
-
- if (notifyComplete) {
- mResumePending = true;
- }
-
- if (mCodec == NULL) {
- ALOGE("[%s] onResume without a valid codec", mComponentName.c_str());
- handleError(NO_INIT);
- return;
- }
- mCodec->start();
-}
-
-void NuPlayer2::Decoder::doFlush(bool notifyComplete) {
- if (mCCDecoder != NULL) {
- mCCDecoder->flush();
- }
-
- if (mRenderer != NULL) {
- mRenderer->flush(mIsAudio, notifyComplete);
- mRenderer->signalTimeDiscontinuity();
- }
-
- status_t err = OK;
- if (mCodec != NULL) {
- err = mCodec->flush();
- mCSDsToSubmit = mCSDsForCurrentFormat; // copy operator
- ++mBufferGeneration;
- }
-
- if (err != OK) {
- ALOGE("failed to flush [%s] (err=%d)", mComponentName.c_str(), err);
- handleError(err);
- // finish with posting kWhatFlushCompleted.
- // we attempt to release the buffers even if flush fails.
- }
- releaseAndResetMediaBuffers();
- mPaused = true;
-}
-
-
-void NuPlayer2::Decoder::onFlush() {
- doFlush(true);
-
- if (isDiscontinuityPending()) {
- // This could happen if the client starts seeking/shutdown
- // after we queued an EOS for discontinuities.
- // We can consider discontinuity handled.
- finishHandleDiscontinuity(false /* flushOnTimeChange */);
- }
-
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatFlushCompleted);
- notify->post();
-}
-
-void NuPlayer2::Decoder::onShutdown(bool notifyComplete) {
- status_t err = OK;
-
- // if there is a pending resume request, notify complete now
- notifyResumeCompleteIfNecessary();
-
- if (mCodec != NULL) {
- err = mCodec->release();
- mCodec = NULL;
- ++mBufferGeneration;
-
- if (mNativeWindow != NULL && mNativeWindow->getANativeWindow() != NULL) {
- // reconnect to surface as MediaCodec disconnected from it
- status_t error = native_window_api_connect(mNativeWindow->getANativeWindow(),
- NATIVE_WINDOW_API_MEDIA);
- ALOGW_IF(error != NO_ERROR,
- "[%s] failed to connect to native window, error=%d",
- mComponentName.c_str(), error);
- }
- mComponentName = "decoder";
- }
-
- releaseAndResetMediaBuffers();
-
- if (err != OK) {
- ALOGE("failed to release [%s] (err=%d)", mComponentName.c_str(), err);
- handleError(err);
- // finish with posting kWhatShutdownCompleted.
- }
-
- if (notifyComplete) {
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatShutdownCompleted);
- notify->post();
- mPaused = true;
- }
-}
-
-/*
- * returns true if we should request more data
- */
-bool NuPlayer2::Decoder::doRequestBuffers() {
- if (isDiscontinuityPending()) {
- return false;
- }
- status_t err = OK;
- while (err == OK && !mDequeuedInputBuffers.empty()) {
- size_t bufferIx = *mDequeuedInputBuffers.begin();
- sp<AMessage> msg = new AMessage();
- msg->setSize("buffer-ix", bufferIx);
- err = fetchInputData(msg);
- if (err != OK && err != ERROR_END_OF_STREAM) {
- // if EOS, need to queue EOS buffer
- break;
- }
- mDequeuedInputBuffers.erase(mDequeuedInputBuffers.begin());
-
- if (!mPendingInputMessages.empty()
- || !onInputBufferFetched(msg)) {
- mPendingInputMessages.push_back(msg);
- }
- }
-
- return err == -EWOULDBLOCK
- && mSource->feedMoreTSData() == OK;
-}
-
-void NuPlayer2::Decoder::handleError(int32_t err)
-{
- // We cannot immediately release the codec due to buffers still outstanding
- // in the renderer. We signal to the player the error so it can shutdown/release the
- // decoder after flushing and increment the generation to discard unnecessary messages.
-
- ++mBufferGeneration;
-
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatError);
- notify->setInt32("err", err);
- notify->post();
-}
-
-status_t NuPlayer2::Decoder::releaseCrypto()
-{
- ALOGV("releaseCrypto");
-
- sp<AMessage> msg = new AMessage(kWhatDrmReleaseCrypto, this);
-
- sp<AMessage> response;
- status_t status = msg->postAndAwaitResponse(&response);
- if (status == OK && response != NULL) {
- CHECK(response->findInt32("status", &status));
- ALOGV("releaseCrypto ret: %d ", status);
- } else {
- ALOGE("releaseCrypto err: %d", status);
- }
-
- return status;
-}
-
-void NuPlayer2::Decoder::onReleaseCrypto(const sp<AMessage>& msg)
-{
- status_t status = INVALID_OPERATION;
- if (mCodec != NULL) {
- status = mCodec->releaseCrypto();
- } else {
- // returning OK if the codec has been already released
- status = OK;
- ALOGE("onReleaseCrypto No mCodec. err: %d", status);
- }
-
- sp<AMessage> response = new AMessage;
- response->setInt32("status", status);
- // Clearing the state as it's tied to crypto. mIsEncryptedObservedEarlier is sticky though
- // and lasts for the lifetime of this codec. See its use in fetchInputData.
- mIsEncrypted = false;
-
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
-}
-
-bool NuPlayer2::Decoder::handleAnInputBuffer(size_t index) {
- if (isDiscontinuityPending()) {
- return false;
- }
-
- if (mCodec == NULL) {
- ALOGE("[%s] handleAnInputBuffer without a valid codec", mComponentName.c_str());
- handleError(NO_INIT);
- return false;
- }
-
- size_t bufferSize = 0;
- uint8_t *bufferBase = mCodec->getInputBuffer(index, &bufferSize);
-
- if (bufferBase == NULL) {
- ALOGE("[%s] handleAnInputBuffer, failed to get input buffer", mComponentName.c_str());
- handleError(UNKNOWN_ERROR);
- return false;
- }
-
- sp<MediaCodecBuffer> buffer =
- new MediaCodecBuffer(NULL /* format */, new ABuffer(bufferBase, bufferSize));
-
- if (index >= mInputBuffers.size()) {
- for (size_t i = mInputBuffers.size(); i <= index; ++i) {
- mInputBuffers.add();
- mMediaBuffers.add();
- mInputBufferIsDequeued.add();
- mMediaBuffers.editItemAt(i) = NULL;
- mInputBufferIsDequeued.editItemAt(i) = false;
- }
- }
- mInputBuffers.editItemAt(index) = buffer;
-
- //CHECK_LT(bufferIx, mInputBuffers.size());
-
- if (mMediaBuffers[index] != NULL) {
- mMediaBuffers[index]->release();
- mMediaBuffers.editItemAt(index) = NULL;
- }
- mInputBufferIsDequeued.editItemAt(index) = true;
-
- if (!mCSDsToSubmit.isEmpty()) {
- sp<AMessage> msg = new AMessage();
- msg->setSize("buffer-ix", index);
-
- sp<ABuffer> buffer = mCSDsToSubmit.itemAt(0);
- ALOGI("[%s] resubmitting CSD", mComponentName.c_str());
- msg->setBuffer("buffer", buffer);
- mCSDsToSubmit.removeAt(0);
- if (!onInputBufferFetched(msg)) {
- handleError(UNKNOWN_ERROR);
- return false;
- }
- return true;
- }
-
- while (!mPendingInputMessages.empty()) {
- sp<AMessage> msg = *mPendingInputMessages.begin();
- if (!onInputBufferFetched(msg)) {
- break;
- }
- mPendingInputMessages.erase(mPendingInputMessages.begin());
- }
-
- if (!mInputBufferIsDequeued.editItemAt(index)) {
- return true;
- }
-
- mDequeuedInputBuffers.push_back(index);
-
- onRequestInputBuffers();
- return true;
-}
-
-bool NuPlayer2::Decoder::handleAnOutputBuffer(
- size_t index,
- size_t offset,
- size_t size,
- int64_t timeUs,
- int32_t flags) {
- if (mCodec == NULL) {
- ALOGE("[%s] handleAnOutputBuffer without a valid codec", mComponentName.c_str());
- handleError(NO_INIT);
- return false;
- }
-
-// CHECK_LT(bufferIx, mOutputBuffers.size());
-
- size_t bufferSize = 0;
- uint8_t *bufferBase = mCodec->getOutputBuffer(index, &bufferSize);
-
- if (bufferBase == NULL) {
- ALOGE("[%s] handleAnOutputBuffer, failed to get output buffer", mComponentName.c_str());
- handleError(UNKNOWN_ERROR);
- return false;
- }
-
- sp<MediaCodecBuffer> buffer =
- new MediaCodecBuffer(NULL /* format */, new ABuffer(bufferBase, bufferSize));
-
- if (index >= mOutputBuffers.size()) {
- for (size_t i = mOutputBuffers.size(); i <= index; ++i) {
- mOutputBuffers.add();
- }
- }
-
- mOutputBuffers.editItemAt(index) = buffer;
-
- buffer->setRange(offset, size);
- buffer->meta()->clear();
- buffer->meta()->setInt64("timeUs", timeUs);
-
- bool eos = flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM;
- // we do not expect CODECCONFIG or SYNCFRAME for decoder
-
- sp<AMessage> reply = new AMessage(kWhatRenderBuffer, this);
- reply->setSize("buffer-ix", index);
- reply->setInt32("generation", mBufferGeneration);
-
- if (eos) {
- ALOGI("[%s] saw output EOS", mIsAudio ? "audio" : "video");
-
- buffer->meta()->setInt32("eos", true);
- reply->setInt32("eos", true);
- }
-
- mNumFramesTotal += !mIsAudio;
-
- if (mSkipRenderingUntilMediaTimeUs >= 0) {
- if (timeUs < mSkipRenderingUntilMediaTimeUs) {
- ALOGV("[%s] dropping buffer at time %lld as requested.",
- mComponentName.c_str(), (long long)timeUs);
-
- reply->post();
- if (eos) {
- notifyResumeCompleteIfNecessary();
- if (mRenderer != NULL && !isDiscontinuityPending()) {
- mRenderer->queueEOS(mIsAudio, ERROR_END_OF_STREAM);
- }
- }
- return true;
- }
-
- mSkipRenderingUntilMediaTimeUs = -1;
- }
-
- // wait until 1st frame comes out to signal resume complete
- notifyResumeCompleteIfNecessary();
-
- if (mRenderer != NULL) {
- // send the buffer to renderer.
- mRenderer->queueBuffer(mIsAudio, buffer, reply);
- if (eos && !isDiscontinuityPending()) {
- mRenderer->queueEOS(mIsAudio, ERROR_END_OF_STREAM);
- }
- }
-
- return true;
-}
-
-void NuPlayer2::Decoder::handleOutputFormatChange(const sp<AMessage> &format) {
- if (!mIsAudio) {
- int32_t width, height;
- if (format->findInt32("width", &width)
- && format->findInt32("height", &height)) {
- mStats->setInt32("width", width);
- mStats->setInt32("height", height);
- }
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatVideoSizeChanged);
- notify->setMessage("format", format);
- notify->post();
- } else if (mRenderer != NULL) {
- uint32_t flags;
- int64_t durationUs;
- bool hasVideo = (mSource->getFormat(false /* audio */) != NULL);
- if (getAudioDeepBufferSetting() // override regardless of source duration
- || (mSource->getDuration(&durationUs) == OK
- && durationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US)) {
- flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
- } else {
- flags = AUDIO_OUTPUT_FLAG_NONE;
- }
-
- sp<AMessage> reply = new AMessage(kWhatAudioOutputFormatChanged, this);
- reply->setInt32("generation", mBufferGeneration);
- mRenderer->changeAudioFormat(
- format, false /* offloadOnly */, hasVideo,
- flags, mSource->isStreaming(), reply);
- }
-}
-
-void NuPlayer2::Decoder::releaseAndResetMediaBuffers() {
- for (size_t i = 0; i < mMediaBuffers.size(); i++) {
- if (mMediaBuffers[i] != NULL) {
- mMediaBuffers[i]->release();
- mMediaBuffers.editItemAt(i) = NULL;
- }
- }
- mMediaBuffers.resize(mInputBuffers.size());
- for (size_t i = 0; i < mMediaBuffers.size(); i++) {
- mMediaBuffers.editItemAt(i) = NULL;
- }
- mInputBufferIsDequeued.clear();
- mInputBufferIsDequeued.resize(mInputBuffers.size());
- for (size_t i = 0; i < mInputBufferIsDequeued.size(); i++) {
- mInputBufferIsDequeued.editItemAt(i) = false;
- }
-
- mPendingInputMessages.clear();
- mDequeuedInputBuffers.clear();
- mSkipRenderingUntilMediaTimeUs = -1;
-}
-
-bool NuPlayer2::Decoder::isStaleReply(const sp<AMessage> &msg) {
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
- return generation != mBufferGeneration;
-}
-
-status_t NuPlayer2::Decoder::fetchInputData(sp<AMessage> &reply) {
- sp<ABuffer> accessUnit;
- bool dropAccessUnit = true;
- do {
- status_t err = mSource->dequeueAccessUnit(mIsAudio, &accessUnit);
-
- if (err == -EWOULDBLOCK) {
- return err;
- } else if (err != OK) {
- if (err == INFO_DISCONTINUITY) {
- int32_t type;
- CHECK(accessUnit->meta()->findInt32("discontinuity", &type));
-
- bool formatChange =
- (mIsAudio &&
- (type & ATSParser::DISCONTINUITY_AUDIO_FORMAT))
- || (!mIsAudio &&
- (type & ATSParser::DISCONTINUITY_VIDEO_FORMAT));
-
- bool timeChange = (type & ATSParser::DISCONTINUITY_TIME) != 0;
-
- ALOGI("%s discontinuity (format=%d, time=%d)",
- mIsAudio ? "audio" : "video", formatChange, timeChange);
-
- bool seamlessFormatChange = false;
- sp<AMessage> newFormat = mSource->getFormat(mIsAudio);
- if (formatChange) {
- seamlessFormatChange =
- supportsSeamlessFormatChange(newFormat);
- // treat seamless format change separately
- formatChange = !seamlessFormatChange;
- }
-
- // For format or time change, return EOS to queue EOS input,
- // then wait for EOS on output.
- if (formatChange /* not seamless */) {
- mFormatChangePending = true;
- err = ERROR_END_OF_STREAM;
- } else if (timeChange) {
- rememberCodecSpecificData(newFormat);
- mTimeChangePending = true;
- err = ERROR_END_OF_STREAM;
- } else if (seamlessFormatChange) {
- // reuse existing decoder and don't flush
- rememberCodecSpecificData(newFormat);
- continue;
- } else {
- // This stream is unaffected by the discontinuity
- return -EWOULDBLOCK;
- }
- }
-
- // reply should only be returned without a buffer set
- // when there is an error (including EOS)
- CHECK(err != OK);
-
- reply->setInt32("err", err);
- return ERROR_END_OF_STREAM;
- }
-
- dropAccessUnit = false;
- if (!mIsAudio && !mIsEncrypted) {
- // Extra safeguard if higher-level behavior changes. Otherwise, not required now.
- // Preventing the buffer from being processed (and sent to codec) if this is a later
- // round of playback but this time without prepareDrm. Or if there is a race between
- // stop (which is not blocking) and releaseDrm allowing buffers being processed after
- // Crypto has been released (GenericSource currently prevents this race though).
- // Particularly doing this check before IsAVCReferenceFrame call to prevent parsing
- // of encrypted data.
- if (mIsEncryptedObservedEarlier) {
- ALOGE("fetchInputData: mismatched mIsEncrypted/mIsEncryptedObservedEarlier (0/1)");
-
- return INVALID_OPERATION;
- }
-
- int32_t layerId = 0;
- bool haveLayerId = accessUnit->meta()->findInt32("temporal-layer-id", &layerId);
- if (mRenderer->getVideoLateByUs() > 100000LL
- && mIsVideoAVC
- && !IsAVCReferenceFrame(accessUnit)) {
- dropAccessUnit = true;
- } else if (haveLayerId && mNumVideoTemporalLayerTotal > 1) {
- // Add only one layer each time.
- if (layerId > mCurrentMaxVideoTemporalLayerId + 1
- || layerId >= mNumVideoTemporalLayerAllowed) {
- dropAccessUnit = true;
- ALOGV("dropping layer(%d), speed=%g, allowed layer count=%d, max layerId=%d",
- layerId, mPlaybackSpeed, mNumVideoTemporalLayerAllowed,
- mCurrentMaxVideoTemporalLayerId);
- } else if (layerId > mCurrentMaxVideoTemporalLayerId) {
- mCurrentMaxVideoTemporalLayerId = layerId;
- } else if (layerId == 0 && mNumVideoTemporalLayerTotal > 1
- && IsIDR(accessUnit->data(), accessUnit->size())) {
- mCurrentMaxVideoTemporalLayerId = mNumVideoTemporalLayerTotal - 1;
- }
- }
- if (dropAccessUnit) {
- if (layerId <= mCurrentMaxVideoTemporalLayerId && layerId > 0) {
- mCurrentMaxVideoTemporalLayerId = layerId - 1;
- }
- ++mNumInputFramesDropped;
- }
- }
- } while (dropAccessUnit);
-
- // ALOGV("returned a valid buffer of %s data", mIsAudio ? "mIsAudio" : "video");
-#if 0
- int64_t mediaTimeUs;
- CHECK(accessUnit->meta()->findInt64("timeUs", &mediaTimeUs));
- ALOGV("[%s] feeding input buffer at media time %.3f",
- mIsAudio ? "audio" : "video",
- mediaTimeUs / 1E6);
-#endif
-
- if (mCCDecoder != NULL) {
- mCCDecoder->decode(accessUnit);
- }
-
- reply->setBuffer("buffer", accessUnit);
-
- return OK;
-}
-
-bool NuPlayer2::Decoder::onInputBufferFetched(const sp<AMessage> &msg) {
- if (mCodec == NULL) {
- ALOGE("[%s] onInputBufferFetched without a valid codec", mComponentName.c_str());
- handleError(NO_INIT);
- return false;
- }
-
- size_t bufferIx;
- CHECK(msg->findSize("buffer-ix", &bufferIx));
- CHECK_LT(bufferIx, mInputBuffers.size());
- sp<MediaCodecBuffer> codecBuffer = mInputBuffers[bufferIx];
-
- sp<ABuffer> buffer;
- bool hasBuffer = msg->findBuffer("buffer", &buffer);
- bool needsCopy = true;
-
- if (buffer == NULL /* includes !hasBuffer */) {
- int32_t streamErr = ERROR_END_OF_STREAM;
- CHECK(msg->findInt32("err", &streamErr) || !hasBuffer);
-
- CHECK(streamErr != OK);
-
- // attempt to queue EOS
- status_t err = mCodec->queueInputBuffer(
- bufferIx,
- 0,
- 0,
- 0,
- AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM);
- if (err == OK) {
- mInputBufferIsDequeued.editItemAt(bufferIx) = false;
- } else if (streamErr == ERROR_END_OF_STREAM) {
- streamErr = err;
- // err will not be ERROR_END_OF_STREAM
- }
-
- if (streamErr != ERROR_END_OF_STREAM) {
- ALOGE("Stream error for [%s] (err=%d), EOS %s queued",
- mComponentName.c_str(),
- streamErr,
- err == OK ? "successfully" : "unsuccessfully");
- handleError(streamErr);
- }
- } else {
- sp<AMessage> extra;
- if (buffer->meta()->findMessage("extra", &extra) && extra != NULL) {
- int64_t resumeAtMediaTimeUs;
- if (extra->findInt64(
- "resume-at-mediaTimeUs", &resumeAtMediaTimeUs)) {
- ALOGI("[%s] suppressing rendering until %lld us",
- mComponentName.c_str(), (long long)resumeAtMediaTimeUs);
- mSkipRenderingUntilMediaTimeUs = resumeAtMediaTimeUs;
- }
- }
-
- int64_t timeUs = 0;
- uint32_t flags = 0;
- CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
-
- int32_t eos, csd;
- // we do not expect SYNCFRAME for decoder
- if (buffer->meta()->findInt32("eos", &eos) && eos) {
- flags |= AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM;
- } else if (buffer->meta()->findInt32("csd", &csd) && csd) {
- flags |= AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG;
- }
-
- // Modular DRM
- MediaBufferBase *mediaBuf = NULL;
- sp<AMediaCodecCryptoInfoWrapper> cryptInfo;
-
- // copy into codec buffer
- if (needsCopy) {
- if (buffer->size() > codecBuffer->capacity()) {
- handleError(ERROR_BUFFER_TOO_SMALL);
- mDequeuedInputBuffers.push_back(bufferIx);
- return false;
- }
-
- if (buffer->data() != NULL) {
- codecBuffer->setRange(0, buffer->size());
- memcpy(codecBuffer->data(), buffer->data(), buffer->size());
- } else { // No buffer->data()
- //Modular DRM
- sp<RefBase> holder;
- if (buffer->meta()->findObject("mediaBufferHolder", &holder)) {
- mediaBuf = (holder != nullptr) ?
- static_cast<MediaBufferHolder*>(holder.get())->mediaBuffer() : nullptr;
- }
- if (mediaBuf != NULL) {
- if (mediaBuf->size() > codecBuffer->capacity()) {
- handleError(ERROR_BUFFER_TOO_SMALL);
- mDequeuedInputBuffers.push_back(bufferIx);
- return false;
- }
-
- codecBuffer->setRange(0, mediaBuf->size());
- memcpy(codecBuffer->data(), mediaBuf->data(), mediaBuf->size());
-
- MetaDataBase &meta_data = mediaBuf->meta_data();
- cryptInfo = AMediaCodecCryptoInfoWrapper::Create(meta_data);
- } else { // No mediaBuf
- ALOGE("onInputBufferFetched: buffer->data()/mediaBuf are NULL for %p",
- buffer.get());
- handleError(UNKNOWN_ERROR);
- return false;
- }
- } // buffer->data()
- } // needsCopy
-
- sp<RefBase> cryptInfoObj;
- if (buffer->meta()->findObject("cryptInfo", &cryptInfoObj)) {
- cryptInfo = static_cast<AMediaCodecCryptoInfoWrapper *>(cryptInfoObj.get());
- }
-
- status_t err;
- if (cryptInfo != NULL) {
- err = mCodec->queueSecureInputBuffer(
- bufferIx,
- codecBuffer->offset(),
- cryptInfo,
- timeUs,
- flags);
- // synchronous call so done with cryptInfo here
- } else {
- err = mCodec->queueInputBuffer(
- bufferIx,
- codecBuffer->offset(),
- codecBuffer->size(),
- timeUs,
- flags);
- } // no cryptInfo
-
- if (err != OK) {
- ALOGE("onInputBufferFetched: queue%sInputBuffer failed for [%s] (err=%d)",
- (cryptInfo != NULL ? "Secure" : ""),
- mComponentName.c_str(), err);
- handleError(err);
- } else {
- mInputBufferIsDequeued.editItemAt(bufferIx) = false;
- }
-
- } // buffer != NULL
- return true;
-}
-
-void NuPlayer2::Decoder::onRenderBuffer(const sp<AMessage> &msg) {
- status_t err;
- int32_t render;
- size_t bufferIx;
- int32_t eos;
- CHECK(msg->findSize("buffer-ix", &bufferIx));
-
- if (!mIsAudio) {
- int64_t timeUs;
- sp<MediaCodecBuffer> buffer = mOutputBuffers[bufferIx];
- buffer->meta()->findInt64("timeUs", &timeUs);
-
- if (mCCDecoder != NULL && mCCDecoder->isSelected()) {
- mCCDecoder->display(timeUs);
- }
- }
-
- if (mCodec == NULL) {
- err = NO_INIT;
- } else if (msg->findInt32("render", &render) && render) {
- int64_t timestampNs;
- CHECK(msg->findInt64("timestampNs", ×tampNs));
- err = mCodec->releaseOutputBufferAtTime(bufferIx, timestampNs);
- } else {
- mNumOutputFramesDropped += !mIsAudio;
- err = mCodec->releaseOutputBuffer(bufferIx, false /* render */);
- }
- if (err != OK) {
- ALOGE("failed to release output buffer for [%s] (err=%d)",
- mComponentName.c_str(), err);
- handleError(err);
- }
- if (msg->findInt32("eos", &eos) && eos
- && isDiscontinuityPending()) {
- finishHandleDiscontinuity(true /* flushOnTimeChange */);
- }
-}
-
-bool NuPlayer2::Decoder::isDiscontinuityPending() const {
- return mFormatChangePending || mTimeChangePending;
-}
-
-void NuPlayer2::Decoder::finishHandleDiscontinuity(bool flushOnTimeChange) {
- ALOGV("finishHandleDiscontinuity: format %d, time %d, flush %d",
- mFormatChangePending, mTimeChangePending, flushOnTimeChange);
-
- // If we have format change, pause and wait to be killed;
- // If we have time change only, flush and restart fetching.
-
- if (mFormatChangePending) {
- mPaused = true;
- } else if (mTimeChangePending) {
- if (flushOnTimeChange) {
- doFlush(false /* notifyComplete */);
- signalResume(false /* notifyComplete */);
- }
- }
-
- // Notify NuPlayer2 to either shutdown decoder, or rescan sources
- sp<AMessage> msg = mNotify->dup();
- msg->setInt32("what", kWhatInputDiscontinuity);
- msg->setInt32("formatChange", mFormatChangePending);
- msg->post();
-
- mFormatChangePending = false;
- mTimeChangePending = false;
-}
-
-bool NuPlayer2::Decoder::supportsSeamlessAudioFormatChange(
- const sp<AMessage> &targetFormat) const {
- if (targetFormat == NULL) {
- return true;
- }
-
- AString mime;
- if (!targetFormat->findString("mime", &mime)) {
- return false;
- }
-
- if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_AUDIO_AAC)) {
- // field-by-field comparison
- const char * keys[] = { "channel-count", "sample-rate", "is-adts" };
- for (unsigned int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) {
- int32_t oldVal, newVal;
- if (!mInputFormat->getInt32(keys[i], &oldVal) ||
- !targetFormat->findInt32(keys[i], &newVal) ||
- oldVal != newVal) {
- return false;
- }
- }
-
- sp<ABuffer> newBuf;
- uint8_t *oldBufData = NULL;
- size_t oldBufSize = 0;
- if (mInputFormat->getBuffer("csd-0", (void**)&oldBufData, &oldBufSize) &&
- targetFormat->findBuffer("csd-0", &newBuf)) {
- if (oldBufSize != newBuf->size()) {
- return false;
- }
- return !memcmp(oldBufData, newBuf->data(), oldBufSize);
- }
- }
- return false;
-}
-
-bool NuPlayer2::Decoder::supportsSeamlessFormatChange(const sp<AMessage> &targetFormat) const {
- if (mInputFormat == NULL) {
- return false;
- }
-
- if (targetFormat == NULL) {
- return true;
- }
-
- AString oldMime, newMime;
- if (!mInputFormat->getString("mime", &oldMime)
- || !targetFormat->findString("mime", &newMime)
- || !(oldMime == newMime)) {
- return false;
- }
-
- bool audio = !strncasecmp(oldMime.c_str(), "audio/", strlen("audio/"));
- bool seamless;
- if (audio) {
- seamless = supportsSeamlessAudioFormatChange(targetFormat);
- } else {
- int32_t isAdaptive;
- seamless = (mCodec != NULL &&
- mInputFormat->getInt32("adaptive-playback", &isAdaptive) &&
- isAdaptive);
- }
-
- ALOGV("%s seamless support for %s", seamless ? "yes" : "no", oldMime.c_str());
- return seamless;
-}
-
-void NuPlayer2::Decoder::rememberCodecSpecificData(const sp<AMessage> &format) {
- if (format == NULL) {
- return;
- }
- mCSDsForCurrentFormat.clear();
- for (int32_t i = 0; ; ++i) {
- AString tag = "csd-";
- tag.append(i);
- sp<ABuffer> buffer;
- if (!format->findBuffer(tag.c_str(), &buffer)) {
- break;
- }
- mCSDsForCurrentFormat.push(buffer);
- }
-}
-
-void NuPlayer2::Decoder::notifyResumeCompleteIfNecessary() {
- if (mResumePending) {
- mResumePending = false;
-
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatResumeCompleted);
- notify->post();
- }
-}
-
-} // namespace android
-
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.h
deleted file mode 100644
index fdfb10e..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NUPLAYER2_DECODER_H_
-#define NUPLAYER2_DECODER_H_
-
-#include "NuPlayer2.h"
-
-#include "NuPlayer2DecoderBase.h"
-
-namespace android {
-
-class MediaCodecBuffer;
-
-struct AMediaCodecWrapper;
-struct AMediaFormatWrapper;
-
-struct NuPlayer2::Decoder : public DecoderBase {
- Decoder(const sp<AMessage> ¬ify,
- const sp<Source> &source,
- pid_t pid,
- uid_t uid,
- const sp<Renderer> &renderer = NULL,
- const sp<ANativeWindowWrapper> &nww = NULL,
- const sp<CCDecoder> &ccDecoder = NULL);
-
- virtual sp<AMessage> getStats() const;
-
- // sets the output surface of video decoders.
- virtual status_t setVideoSurface(const sp<ANativeWindowWrapper> &nww);
-
- virtual status_t releaseCrypto();
-
-protected:
- virtual ~Decoder();
-
- virtual void onMessageReceived(const sp<AMessage> &msg);
-
- virtual void onConfigure(const sp<AMessage> &format);
- virtual void onSetParameters(const sp<AMessage> ¶ms);
- virtual void onSetRenderer(const sp<Renderer> &renderer);
- virtual void onResume(bool notifyComplete);
- virtual void onFlush();
- virtual void onShutdown(bool notifyComplete);
- virtual bool doRequestBuffers();
-
-private:
- enum {
- kWhatCodecNotify = 'cdcN',
- kWhatRenderBuffer = 'rndr',
- kWhatSetVideoSurface = 'sSur',
- kWhatAudioOutputFormatChanged = 'aofc',
- kWhatDrmReleaseCrypto = 'rDrm',
- };
-
- enum {
- kMaxNumVideoTemporalLayers = 32,
- };
-
- sp<ANativeWindowWrapper> mNativeWindow;
-
- sp<Source> mSource;
- sp<Renderer> mRenderer;
- sp<CCDecoder> mCCDecoder;
-
- sp<AMediaFormatWrapper> mInputFormat;
- sp<AMediaCodecWrapper> mCodec;
-
- List<sp<AMessage> > mPendingInputMessages;
-
- Vector<sp<MediaCodecBuffer> > mInputBuffers;
- Vector<sp<MediaCodecBuffer> > mOutputBuffers;
- Vector<sp<ABuffer> > mCSDsForCurrentFormat;
- Vector<sp<ABuffer> > mCSDsToSubmit;
- Vector<bool> mInputBufferIsDequeued;
- Vector<MediaBuffer *> mMediaBuffers;
- Vector<size_t> mDequeuedInputBuffers;
-
- const pid_t mPid;
- const uid_t mUid;
- int64_t mSkipRenderingUntilMediaTimeUs;
- int64_t mNumFramesTotal;
- int64_t mNumInputFramesDropped;
- int64_t mNumOutputFramesDropped;
- int32_t mVideoWidth;
- int32_t mVideoHeight;
- bool mIsAudio;
- bool mIsVideoAVC;
- bool mIsSecure;
- bool mIsEncrypted;
- bool mIsEncryptedObservedEarlier;
- bool mFormatChangePending;
- bool mTimeChangePending;
- float mFrameRateTotal;
- float mPlaybackSpeed;
- int32_t mNumVideoTemporalLayerTotal;
- int32_t mNumVideoTemporalLayerAllowed;
- int32_t mCurrentMaxVideoTemporalLayerId;
- float mVideoTemporalLayerAggregateFps[kMaxNumVideoTemporalLayers];
-
- bool mResumePending;
- AString mComponentName;
-
- void handleError(int32_t err);
- bool handleAnInputBuffer(size_t index);
- bool handleAnOutputBuffer(
- size_t index,
- size_t offset,
- size_t size,
- int64_t timeUs,
- int32_t flags);
- void handleOutputFormatChange(const sp<AMessage> &format);
-
- void releaseAndResetMediaBuffers();
- bool isStaleReply(const sp<AMessage> &msg);
-
- void doFlush(bool notifyComplete);
- status_t fetchInputData(sp<AMessage> &reply);
- bool onInputBufferFetched(const sp<AMessage> &msg);
- void onRenderBuffer(const sp<AMessage> &msg);
-
- bool supportsSeamlessFormatChange(const sp<AMessage> &to) const;
- bool supportsSeamlessAudioFormatChange(const sp<AMessage> &targetFormat) const;
- void rememberCodecSpecificData(const sp<AMessage> &format);
- bool isDiscontinuityPending() const;
- void finishHandleDiscontinuity(bool flushOnTimeChange);
-
- void notifyResumeCompleteIfNecessary();
-
- void onReleaseCrypto(const sp<AMessage>& msg);
-
- DISALLOW_EVIL_CONSTRUCTORS(Decoder);
-};
-
-} // namespace android
-
-#endif // NUPLAYER2_DECODER_H_
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderBase.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderBase.cpp
deleted file mode 100644
index 914f29f..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderBase.cpp
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NuPlayer2DecoderBase"
-#include <utils/Log.h>
-#include <inttypes.h>
-
-#include "NuPlayer2DecoderBase.h"
-
-#include "NuPlayer2Renderer.h"
-
-#include <media/MediaCodecBuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-
-namespace android {
-
-NuPlayer2::DecoderBase::DecoderBase(const sp<AMessage> ¬ify)
- : mNotify(notify),
- mBufferGeneration(0),
- mPaused(false),
- mStats(new AMessage),
- mRequestInputBuffersPending(false) {
- // Every decoder has its own looper because MediaCodec operations
- // are blocking, but NuPlayer2 needs asynchronous operations.
- mDecoderLooper = new ALooper;
- mDecoderLooper->setName("NP2Decoder");
- mDecoderLooper->start(false, /* runOnCallingThread */
- true, /* canCallJava */
- ANDROID_PRIORITY_AUDIO);
-}
-
-NuPlayer2::DecoderBase::~DecoderBase() {
- stopLooper();
-}
-
-static
-status_t PostAndAwaitResponse(
- const sp<AMessage> &msg, sp<AMessage> *response) {
- status_t err = msg->postAndAwaitResponse(response);
-
- if (err != OK) {
- return err;
- }
-
- if (!(*response)->findInt32("err", &err)) {
- err = OK;
- }
-
- return err;
-}
-
-void NuPlayer2::DecoderBase::configure(const sp<AMessage> &format) {
- sp<AMessage> msg = new AMessage(kWhatConfigure, this);
- msg->setMessage("format", format);
- msg->post();
-}
-
-void NuPlayer2::DecoderBase::init() {
- mDecoderLooper->registerHandler(this);
-}
-
-void NuPlayer2::DecoderBase::stopLooper() {
- mDecoderLooper->unregisterHandler(id());
- mDecoderLooper->stop();
-}
-
-void NuPlayer2::DecoderBase::setParameters(const sp<AMessage> ¶ms) {
- sp<AMessage> msg = new AMessage(kWhatSetParameters, this);
- msg->setMessage("params", params);
- msg->post();
-}
-
-void NuPlayer2::DecoderBase::setRenderer(const sp<Renderer> &renderer) {
- sp<AMessage> msg = new AMessage(kWhatSetRenderer, this);
- msg->setObject("renderer", renderer);
- msg->post();
-}
-
-void NuPlayer2::DecoderBase::pause() {
- sp<AMessage> msg = new AMessage(kWhatPause, this);
-
- sp<AMessage> response;
- PostAndAwaitResponse(msg, &response);
-}
-
-void NuPlayer2::DecoderBase::signalFlush() {
- (new AMessage(kWhatFlush, this))->post();
-}
-
-void NuPlayer2::DecoderBase::signalResume(bool notifyComplete) {
- sp<AMessage> msg = new AMessage(kWhatResume, this);
- msg->setInt32("notifyComplete", notifyComplete);
- msg->post();
-}
-
-void NuPlayer2::DecoderBase::initiateShutdown() {
- (new AMessage(kWhatShutdown, this))->post();
-}
-
-void NuPlayer2::DecoderBase::onRequestInputBuffers() {
- if (mRequestInputBuffersPending) {
- return;
- }
-
- // doRequestBuffers() return true if we should request more data
- if (doRequestBuffers()) {
- mRequestInputBuffersPending = true;
-
- sp<AMessage> msg = new AMessage(kWhatRequestInputBuffers, this);
- msg->post(10 * 1000LL);
- }
-}
-
-void NuPlayer2::DecoderBase::onMessageReceived(const sp<AMessage> &msg) {
-
- switch (msg->what()) {
- case kWhatConfigure:
- {
- sp<AMessage> format;
- CHECK(msg->findMessage("format", &format));
- onConfigure(format);
- break;
- }
-
- case kWhatSetParameters:
- {
- sp<AMessage> params;
- CHECK(msg->findMessage("params", ¶ms));
- onSetParameters(params);
- break;
- }
-
- case kWhatSetRenderer:
- {
- sp<RefBase> obj;
- CHECK(msg->findObject("renderer", &obj));
- onSetRenderer(static_cast<Renderer *>(obj.get()));
- break;
- }
-
- case kWhatPause:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
- mPaused = true;
-
- (new AMessage)->postReply(replyID);
- break;
- }
-
- case kWhatRequestInputBuffers:
- {
- mRequestInputBuffersPending = false;
- onRequestInputBuffers();
- break;
- }
-
- case kWhatFlush:
- {
- onFlush();
- break;
- }
-
- case kWhatResume:
- {
- int32_t notifyComplete;
- CHECK(msg->findInt32("notifyComplete", ¬ifyComplete));
-
- onResume(notifyComplete);
- break;
- }
-
- case kWhatShutdown:
- {
- onShutdown(true);
- break;
- }
-
- default:
- TRESPASS();
- break;
- }
-}
-
-void NuPlayer2::DecoderBase::handleError(int32_t err)
-{
- // We cannot immediately release the codec due to buffers still outstanding
- // in the renderer. We signal to the player the error so it can shutdown/release the
- // decoder after flushing and increment the generation to discard unnecessary messages.
-
- ++mBufferGeneration;
-
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatError);
- notify->setInt32("err", err);
- notify->post();
-}
-
-} // namespace android
-
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderBase.h b/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderBase.h
deleted file mode 100644
index 1e57f0d..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderBase.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NUPLAYER2_DECODER_BASE_H_
-
-#define NUPLAYER2_DECODER_BASE_H_
-
-#include "NuPlayer2.h"
-
-#include <media/stagefright/foundation/AHandler.h>
-
-namespace android {
-
-struct ABuffer;
-struct ANativeWindowWrapper;
-struct MediaCodec;
-class MediaBuffer;
-class MediaCodecBuffer;
-
-struct NuPlayer2::DecoderBase : public AHandler {
- explicit DecoderBase(const sp<AMessage> ¬ify);
-
- void configure(const sp<AMessage> &format);
- void init();
- void setParameters(const sp<AMessage> ¶ms);
-
- // Synchronous call to ensure decoder will not request or send out data.
- void pause();
-
- void setRenderer(const sp<Renderer> &renderer);
- virtual status_t setVideoSurface(const sp<ANativeWindowWrapper> &) { return INVALID_OPERATION; }
-
- void signalFlush();
- void signalResume(bool notifyComplete);
- void initiateShutdown();
-
- virtual sp<AMessage> getStats() const {
- return mStats;
- }
-
- virtual status_t releaseCrypto() {
- return INVALID_OPERATION;
- }
-
- enum {
- kWhatInputDiscontinuity = 'inDi',
- kWhatVideoSizeChanged = 'viSC',
- kWhatFlushCompleted = 'flsC',
- kWhatShutdownCompleted = 'shDC',
- kWhatResumeCompleted = 'resC',
- kWhatEOS = 'eos ',
- kWhatError = 'err ',
- };
-
-protected:
-
- virtual ~DecoderBase();
-
- void stopLooper();
-
- virtual void onMessageReceived(const sp<AMessage> &msg);
-
- virtual void onConfigure(const sp<AMessage> &format) = 0;
- virtual void onSetParameters(const sp<AMessage> ¶ms) = 0;
- virtual void onSetRenderer(const sp<Renderer> &renderer) = 0;
- virtual void onResume(bool notifyComplete) = 0;
- virtual void onFlush() = 0;
- virtual void onShutdown(bool notifyComplete) = 0;
-
- void onRequestInputBuffers();
- virtual bool doRequestBuffers() = 0;
- virtual void handleError(int32_t err);
-
- sp<AMessage> mNotify;
- int32_t mBufferGeneration;
- bool mPaused;
- sp<AMessage> mStats;
-
-private:
- enum {
- kWhatConfigure = 'conf',
- kWhatSetParameters = 'setP',
- kWhatSetRenderer = 'setR',
- kWhatPause = 'paus',
- kWhatRequestInputBuffers = 'reqB',
- kWhatFlush = 'flus',
- kWhatShutdown = 'shuD',
- };
-
- sp<ALooper> mDecoderLooper;
- bool mRequestInputBuffersPending;
-
- DISALLOW_EVIL_CONSTRUCTORS(DecoderBase);
-};
-
-} // namespace android
-
-#endif // NUPLAYER2_DECODER_BASE_H_
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderPassThrough.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderPassThrough.cpp
deleted file mode 100644
index 0514e88..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderPassThrough.cpp
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NuPlayer2DecoderPassThrough"
-#include <utils/Log.h>
-#include <inttypes.h>
-
-#include "NuPlayer2DecoderPassThrough.h"
-
-#include "NuPlayer2Renderer.h"
-#include "NuPlayer2Source.h"
-
-#include <media/MediaCodecBuffer.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaErrors.h>
-
-#include "ATSParser.h"
-
-namespace android {
-
-// TODO optimize buffer size for power consumption
-// The offload read buffer size is 32 KB but 24 KB uses less power.
-static const size_t kAggregateBufferSizeBytes = 24 * 1024;
-static const size_t kMaxCachedBytes = 200000;
-
-NuPlayer2::DecoderPassThrough::DecoderPassThrough(
- const sp<AMessage> ¬ify,
- const sp<Source> &source,
- const sp<Renderer> &renderer)
- : DecoderBase(notify),
- mSource(source),
- mRenderer(renderer),
- mSkipRenderingUntilMediaTimeUs(-1LL),
- mReachedEOS(true),
- mPendingAudioErr(OK),
- mPendingBuffersToDrain(0),
- mCachedBytes(0),
- mComponentName("pass through decoder") {
- ALOGW_IF(renderer == NULL, "expect a non-NULL renderer");
-}
-
-NuPlayer2::DecoderPassThrough::~DecoderPassThrough() {
-}
-
-void NuPlayer2::DecoderPassThrough::onConfigure(const sp<AMessage> &format) {
- ALOGV("[%s] onConfigure", mComponentName.c_str());
- mCachedBytes = 0;
- mPendingBuffersToDrain = 0;
- mReachedEOS = false;
- ++mBufferGeneration;
-
- onRequestInputBuffers();
-
- int32_t hasVideo = 0;
- format->findInt32("has-video", &hasVideo);
-
- // The audio sink is already opened before the PassThrough decoder is created.
- // Opening again might be relevant if decoder is instantiated after shutdown and
- // format is different.
- status_t err = mRenderer->openAudioSink(
- format, true /* offloadOnly */, hasVideo,
- AUDIO_OUTPUT_FLAG_NONE /* flags */, NULL /* isOffloaded */, mSource->isStreaming());
- if (err != OK) {
- handleError(err);
- }
-}
-
-void NuPlayer2::DecoderPassThrough::onSetParameters(const sp<AMessage> &/*params*/) {
- ALOGW("onSetParameters() called unexpectedly");
-}
-
-void NuPlayer2::DecoderPassThrough::onSetRenderer(
- const sp<Renderer> &renderer) {
- // renderer can't be changed during offloading
- ALOGW_IF(renderer != mRenderer,
- "ignoring request to change renderer");
-}
-
-bool NuPlayer2::DecoderPassThrough::isStaleReply(const sp<AMessage> &msg) {
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
- return generation != mBufferGeneration;
-}
-
-bool NuPlayer2::DecoderPassThrough::isDoneFetching() const {
- ALOGV("[%s] mCachedBytes = %zu, mReachedEOS = %d mPaused = %d",
- mComponentName.c_str(), mCachedBytes, mReachedEOS, mPaused);
-
- return mCachedBytes >= kMaxCachedBytes || mReachedEOS || mPaused;
-}
-
-/*
- * returns true if we should request more data
- */
-bool NuPlayer2::DecoderPassThrough::doRequestBuffers() {
- status_t err = OK;
- while (!isDoneFetching()) {
- sp<AMessage> msg = new AMessage();
-
- err = fetchInputData(msg);
- if (err != OK) {
- break;
- }
-
- onInputBufferFetched(msg);
- }
-
- return err == -EWOULDBLOCK
- && mSource->feedMoreTSData() == OK;
-}
-
-status_t NuPlayer2::DecoderPassThrough::dequeueAccessUnit(sp<ABuffer> *accessUnit) {
- status_t err;
-
- // Did we save an accessUnit earlier because of a discontinuity?
- if (mPendingAudioAccessUnit != NULL) {
- *accessUnit = mPendingAudioAccessUnit;
- mPendingAudioAccessUnit.clear();
- err = mPendingAudioErr;
- ALOGV("feedDecoderInputData() use mPendingAudioAccessUnit");
- } else {
- err = mSource->dequeueAccessUnit(true /* audio */, accessUnit);
- }
-
- if (err == INFO_DISCONTINUITY || err == ERROR_END_OF_STREAM) {
- if (mAggregateBuffer != NULL) {
- // We already have some data so save this for later.
- mPendingAudioErr = err;
- mPendingAudioAccessUnit = *accessUnit;
- (*accessUnit).clear();
- ALOGD("return aggregated buffer and save err(=%d) for later", err);
- err = OK;
- }
- }
-
- return err;
-}
-
-sp<ABuffer> NuPlayer2::DecoderPassThrough::aggregateBuffer(
- const sp<ABuffer> &accessUnit) {
- sp<ABuffer> aggregate;
-
- if (accessUnit == NULL) {
- // accessUnit is saved to mPendingAudioAccessUnit
- // return current mAggregateBuffer
- aggregate = mAggregateBuffer;
- mAggregateBuffer.clear();
- return aggregate;
- }
-
- size_t smallSize = accessUnit->size();
- if ((mAggregateBuffer == NULL)
- // Don't bother if only room for a few small buffers.
- && (smallSize < (kAggregateBufferSizeBytes / 3))) {
- // Create a larger buffer for combining smaller buffers from the extractor.
- mAggregateBuffer = new ABuffer(kAggregateBufferSizeBytes);
- mAggregateBuffer->setRange(0, 0); // start empty
- }
-
- if (mAggregateBuffer != NULL) {
- int64_t timeUs;
- int64_t dummy;
- bool smallTimestampValid = accessUnit->meta()->findInt64("timeUs", &timeUs);
- bool bigTimestampValid = mAggregateBuffer->meta()->findInt64("timeUs", &dummy);
- // Will the smaller buffer fit?
- size_t bigSize = mAggregateBuffer->size();
- size_t roomLeft = mAggregateBuffer->capacity() - bigSize;
- // Should we save this small buffer for the next big buffer?
- // If the first small buffer did not have a timestamp then save
- // any buffer that does have a timestamp until the next big buffer.
- if ((smallSize > roomLeft)
- || (!bigTimestampValid && (bigSize > 0) && smallTimestampValid)) {
- mPendingAudioErr = OK;
- mPendingAudioAccessUnit = accessUnit;
- aggregate = mAggregateBuffer;
- mAggregateBuffer.clear();
- } else {
- // Grab time from first small buffer if available.
- if ((bigSize == 0) && smallTimestampValid) {
- mAggregateBuffer->meta()->setInt64("timeUs", timeUs);
- }
- // Append small buffer to the bigger buffer.
- memcpy(mAggregateBuffer->base() + bigSize, accessUnit->data(), smallSize);
- bigSize += smallSize;
- mAggregateBuffer->setRange(0, bigSize);
-
- ALOGV("feedDecoderInputData() smallSize = %zu, bigSize = %zu, capacity = %zu",
- smallSize, bigSize, mAggregateBuffer->capacity());
- }
- } else {
- // decided not to aggregate
- aggregate = accessUnit;
- }
-
- return aggregate;
-}
-
-status_t NuPlayer2::DecoderPassThrough::fetchInputData(sp<AMessage> &reply) {
- sp<ABuffer> accessUnit;
-
- do {
- status_t err = dequeueAccessUnit(&accessUnit);
-
- if (err == -EWOULDBLOCK) {
- // Flush out the aggregate buffer to try to avoid underrun.
- accessUnit = aggregateBuffer(NULL /* accessUnit */);
- if (accessUnit != NULL) {
- break;
- }
- return err;
- } else if (err != OK) {
- if (err == INFO_DISCONTINUITY) {
- int32_t type;
- CHECK(accessUnit->meta()->findInt32("discontinuity", &type));
-
- bool formatChange =
- (type & ATSParser::DISCONTINUITY_AUDIO_FORMAT) != 0;
-
- bool timeChange =
- (type & ATSParser::DISCONTINUITY_TIME) != 0;
-
- ALOGI("audio discontinuity (formatChange=%d, time=%d)",
- formatChange, timeChange);
-
- if (formatChange || timeChange) {
- sp<AMessage> msg = mNotify->dup();
- msg->setInt32("what", kWhatInputDiscontinuity);
- // will perform seamless format change,
- // only notify NuPlayer2 to scan sources
- msg->setInt32("formatChange", false);
- msg->post();
- }
-
- if (timeChange) {
- doFlush(false /* notifyComplete */);
- err = OK;
- } else if (formatChange) {
- // do seamless format change
- err = OK;
- } else {
- // This stream is unaffected by the discontinuity
- return -EWOULDBLOCK;
- }
- }
-
- reply->setInt32("err", err);
- return OK;
- }
-
- accessUnit = aggregateBuffer(accessUnit);
- } while (accessUnit == NULL);
-
-#if 0
- int64_t mediaTimeUs;
- CHECK(accessUnit->meta()->findInt64("timeUs", &mediaTimeUs));
- ALOGV("feeding audio input buffer at media time %.2f secs",
- mediaTimeUs / 1E6);
-#endif
-
- reply->setBuffer("buffer", accessUnit);
-
- return OK;
-}
-
-void NuPlayer2::DecoderPassThrough::onInputBufferFetched(
- const sp<AMessage> &msg) {
- if (mReachedEOS) {
- return;
- }
-
- sp<ABuffer> buffer;
- bool hasBuffer = msg->findBuffer("buffer", &buffer);
- if (buffer == NULL) {
- int32_t streamErr = ERROR_END_OF_STREAM;
- CHECK(msg->findInt32("err", &streamErr) || !hasBuffer);
- if (streamErr == OK) {
- return;
- }
-
- if (streamErr != ERROR_END_OF_STREAM) {
- handleError(streamErr);
- }
- mReachedEOS = true;
- if (mRenderer != NULL) {
- mRenderer->queueEOS(true /* audio */, ERROR_END_OF_STREAM);
- }
- return;
- }
-
- sp<AMessage> extra;
- if (buffer->meta()->findMessage("extra", &extra) && extra != NULL) {
- int64_t resumeAtMediaTimeUs;
- if (extra->findInt64(
- "resume-at-mediatimeUs", &resumeAtMediaTimeUs)) {
- ALOGI("[%s] suppressing rendering until %lld us",
- mComponentName.c_str(), (long long)resumeAtMediaTimeUs);
- mSkipRenderingUntilMediaTimeUs = resumeAtMediaTimeUs;
- }
- }
-
- int32_t bufferSize = buffer->size();
- mCachedBytes += bufferSize;
-
- int64_t timeUs = 0;
- CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
- if (mSkipRenderingUntilMediaTimeUs >= 0) {
- if (timeUs < mSkipRenderingUntilMediaTimeUs) {
- ALOGV("[%s] dropping buffer at time %lld as requested.",
- mComponentName.c_str(), (long long)timeUs);
-
- onBufferConsumed(bufferSize);
- return;
- }
-
- mSkipRenderingUntilMediaTimeUs = -1;
- }
-
- if (mRenderer == NULL) {
- onBufferConsumed(bufferSize);
- return;
- }
-
- sp<AMessage> reply = new AMessage(kWhatBufferConsumed, this);
- reply->setInt32("generation", mBufferGeneration);
- reply->setInt32("size", bufferSize);
-
- sp<MediaCodecBuffer> mcBuffer = new MediaCodecBuffer(nullptr, buffer);
- mcBuffer->meta()->setInt64("timeUs", timeUs);
-
- mRenderer->queueBuffer(true /* audio */, mcBuffer, reply);
-
- ++mPendingBuffersToDrain;
- ALOGV("onInputBufferFilled: #ToDrain = %zu, cachedBytes = %zu",
- mPendingBuffersToDrain, mCachedBytes);
-}
-
-void NuPlayer2::DecoderPassThrough::onBufferConsumed(int32_t size) {
- --mPendingBuffersToDrain;
- mCachedBytes -= size;
- ALOGV("onBufferConsumed: #ToDrain = %zu, cachedBytes = %zu",
- mPendingBuffersToDrain, mCachedBytes);
- onRequestInputBuffers();
-}
-
-void NuPlayer2::DecoderPassThrough::onResume(bool notifyComplete) {
- mPaused = false;
-
- onRequestInputBuffers();
-
- if (notifyComplete) {
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatResumeCompleted);
- notify->post();
- }
-}
-
-void NuPlayer2::DecoderPassThrough::doFlush(bool notifyComplete) {
- ++mBufferGeneration;
- mSkipRenderingUntilMediaTimeUs = -1;
- mPendingAudioAccessUnit.clear();
- mPendingAudioErr = OK;
- mAggregateBuffer.clear();
-
- if (mRenderer != NULL) {
- mRenderer->flush(true /* audio */, notifyComplete);
- mRenderer->signalTimeDiscontinuity();
- }
-
- mPendingBuffersToDrain = 0;
- mCachedBytes = 0;
- mReachedEOS = false;
-}
-
-void NuPlayer2::DecoderPassThrough::onFlush() {
- doFlush(true /* notifyComplete */);
-
- mPaused = true;
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatFlushCompleted);
- notify->post();
-
-}
-
-void NuPlayer2::DecoderPassThrough::onShutdown(bool notifyComplete) {
- ++mBufferGeneration;
- mSkipRenderingUntilMediaTimeUs = -1;
-
- if (notifyComplete) {
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatShutdownCompleted);
- notify->post();
- }
-
- mReachedEOS = true;
-}
-
-void NuPlayer2::DecoderPassThrough::onMessageReceived(const sp<AMessage> &msg) {
- ALOGV("[%s] onMessage: %s", mComponentName.c_str(),
- msg->debugString().c_str());
-
- switch (msg->what()) {
- case kWhatBufferConsumed:
- {
- if (!isStaleReply(msg)) {
- int32_t size;
- CHECK(msg->findInt32("size", &size));
- onBufferConsumed(size);
- }
- break;
- }
-
- default:
- DecoderBase::onMessageReceived(msg);
- break;
- }
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderPassThrough.h b/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderPassThrough.h
deleted file mode 100644
index 838c60a..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderPassThrough.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NUPLAYER2_DECODER_PASS_THROUGH_H_
-
-#define NUPLAYER2_DECODER_PASS_THROUGH_H_
-
-#include "NuPlayer2.h"
-
-#include "NuPlayer2DecoderBase.h"
-
-namespace android {
-
-struct NuPlayer2::DecoderPassThrough : public DecoderBase {
- DecoderPassThrough(const sp<AMessage> ¬ify,
- const sp<Source> &source,
- const sp<Renderer> &renderer);
-
-protected:
-
- virtual ~DecoderPassThrough();
-
- virtual void onMessageReceived(const sp<AMessage> &msg);
-
- virtual void onConfigure(const sp<AMessage> &format);
- virtual void onSetParameters(const sp<AMessage> ¶ms);
- virtual void onSetRenderer(const sp<Renderer> &renderer);
- virtual void onResume(bool notifyComplete);
- virtual void onFlush();
- virtual void onShutdown(bool notifyComplete);
- virtual bool doRequestBuffers();
-
-private:
- enum {
- kWhatBufferConsumed = 'bufC',
- };
-
- sp<Source> mSource;
- sp<Renderer> mRenderer;
- int64_t mSkipRenderingUntilMediaTimeUs;
-
- bool mReachedEOS;
-
- // Used by feedDecoderInputData to aggregate small buffers into
- // one large buffer.
- sp<ABuffer> mPendingAudioAccessUnit;
- status_t mPendingAudioErr;
- sp<ABuffer> mAggregateBuffer;
-
- // mPendingBuffersToDrain are only for debugging. It can be removed
- // when the power investigation is done.
- size_t mPendingBuffersToDrain;
- size_t mCachedBytes;
- AString mComponentName;
-
- bool isStaleReply(const sp<AMessage> &msg);
- bool isDoneFetching() const;
-
- status_t dequeueAccessUnit(sp<ABuffer> *accessUnit);
- sp<ABuffer> aggregateBuffer(const sp<ABuffer> &accessUnit);
- status_t fetchInputData(sp<AMessage> &reply);
- void doFlush(bool notifyComplete);
-
- void onInputBufferFetched(const sp<AMessage> &msg);
- void onBufferConsumed(int32_t size);
-
- DISALLOW_EVIL_CONSTRUCTORS(DecoderPassThrough);
-};
-
-} // namespace android
-
-#endif // NUPLAYER2_DECODER_PASS_THROUGH_H_
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
deleted file mode 100644
index 1876496..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
+++ /dev/null
@@ -1,1010 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NuPlayer2Driver"
-#include <inttypes.h>
-#include <android-base/macros.h>
-#include <utils/Log.h>
-#include <cutils/properties.h>
-
-#include "NuPlayer2Driver.h"
-
-#include "NuPlayer2.h"
-#include "NuPlayer2Source.h"
-
-#include <media/DataSourceDesc.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/foundation/AUtils.h>
-#include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/MediaClock.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
-
-#include <media/IMediaAnalyticsService.h>
-
-using google::protobuf::RepeatedPtrField;
-using android::media::MediaPlayer2Proto::Value;
-
-static const int kDumpLockRetries = 50;
-static const int kDumpLockSleepUs = 20000;
-
-namespace android {
-
-struct PlayerMessageWrapper : public RefBase {
- static sp<PlayerMessageWrapper> Create(const PlayerMessage *p) {
- if (p != NULL) {
- sp<PlayerMessageWrapper> pw = new PlayerMessageWrapper();
- pw->copyFrom(p);
- return pw;
- }
- return NULL;
- }
-
- const PlayerMessage *getPlayerMessage() {
- return mPlayerMessage;
- }
-
-protected:
- virtual ~PlayerMessageWrapper() {
- if (mPlayerMessage != NULL) {
- delete mPlayerMessage;
- }
- }
-
-private:
- PlayerMessageWrapper()
- : mPlayerMessage(NULL) { }
-
- void copyFrom(const PlayerMessage *p) {
- if (mPlayerMessage == NULL) {
- mPlayerMessage = new PlayerMessage;
- }
- mPlayerMessage->CopyFrom(*p);
- }
-
- PlayerMessage *mPlayerMessage;
-};
-
-// key for media statistics
-static const char *kKeyPlayer = "nuplayer2";
-// attrs for media statistics
- // NB: these are matched with public Java API constants defined
- // in frameworks/base/media/java/android/media/MediaPlayer2.java
- // These must be kept synchronized with the constants there.
-static const char *kPlayerVMime = "android.media.mediaplayer.video.mime";
-static const char *kPlayerVCodec = "android.media.mediaplayer.video.codec";
-static const char *kPlayerWidth = "android.media.mediaplayer.width";
-static const char *kPlayerHeight = "android.media.mediaplayer.height";
-static const char *kPlayerFrames = "android.media.mediaplayer.frames";
-static const char *kPlayerFramesDropped = "android.media.mediaplayer.dropped";
-static const char *kPlayerFrameRate = "android.media.mediaplayer.fps";
-static const char *kPlayerAMime = "android.media.mediaplayer.audio.mime";
-static const char *kPlayerACodec = "android.media.mediaplayer.audio.codec";
-static const char *kPlayerDuration = "android.media.mediaplayer.durationMs";
-static const char *kPlayerPlaying = "android.media.mediaplayer.playingMs";
-static const char *kPlayerError = "android.media.mediaplayer.err";
-static const char *kPlayerErrorCode = "android.media.mediaplayer.errcode";
-
-// NB: These are not yet exposed as public Java API constants.
-static const char *kPlayerErrorState = "android.media.mediaplayer.errstate";
-static const char *kPlayerDataSourceType = "android.media.mediaplayer.dataSource";
-//
-static const char *kPlayerRebuffering = "android.media.mediaplayer.rebufferingMs";
-static const char *kPlayerRebufferingCount = "android.media.mediaplayer.rebuffers";
-static const char *kPlayerRebufferingAtExit = "android.media.mediaplayer.rebufferExit";
-
-static const char *kPlayerVersion = "android.media.mediaplayer.version";
-
-
-NuPlayer2Driver::NuPlayer2Driver(pid_t pid, uid_t uid, const sp<JObjectHolder> &context)
- : mState(STATE_IDLE),
- mAsyncResult(UNKNOWN_ERROR),
- mSrcId(0),
- mSetSurfaceInProgress(false),
- mDurationUs(-1),
- mPositionUs(-1),
- mSeekInProgress(false),
- mPlayingTimeUs(0),
- mRebufferingTimeUs(0),
- mRebufferingEvents(0),
- mRebufferingAtExit(false),
- mLooper(new ALooper),
- mNuPlayer2Looper(new ALooper),
- mMediaClock(new MediaClock),
- mPlayer(new NuPlayer2(pid, uid, mMediaClock, context)),
- mPlayerFlags(0),
- mMetricsHandle(0),
- mPlayerVersion(0),
- mClientUid(uid),
- mAtEOS(false),
- mLooping(false),
- mAutoLoop(false) {
- ALOGD("NuPlayer2Driver(%p) created, clientPid(%d)", this, pid);
- mLooper->setName("NuPlayer2Driver Looper");
- mNuPlayer2Looper->setName("NuPlayer2 Looper");
-
- mMediaClock->init();
-
- // XXX: what version are we?
- // Ideally, this ticks with the apk version info for the APEX packaging
-
- // set up media metrics record
- mMetricsHandle = mediametrics_create(kKeyPlayer);
- mediametrics_setUid(mMetricsHandle, mClientUid);
- mediametrics_setInt64(mMetricsHandle, kPlayerVersion, mPlayerVersion);
-
- mNuPlayer2Looper->start(
- false, /* runOnCallingThread */
- true, /* canCallJava */
- PRIORITY_AUDIO);
-
- mNuPlayer2Looper->registerHandler(mPlayer);
-
- mPlayer->setDriver(this);
-}
-
-NuPlayer2Driver::~NuPlayer2Driver() {
- ALOGV("~NuPlayer2Driver(%p)", this);
- mNuPlayer2Looper->stop();
- mLooper->stop();
-
- // finalize any pending metrics, usually a no-op.
- updateMetrics("destructor");
- logMetrics("destructor");
-
- mediametrics_delete(mMetricsHandle);
-}
-
-status_t NuPlayer2Driver::initCheck() {
- mLooper->start(
- false, /* runOnCallingThread */
- true, /* canCallJava */
- PRIORITY_AUDIO);
-
- mLooper->registerHandler(this);
- return OK;
-}
-
-status_t NuPlayer2Driver::setDataSource(const sp<DataSourceDesc> &dsd) {
- ALOGV("setDataSource(%p)", this);
- Mutex::Autolock autoLock(mLock);
-
- if (mState != STATE_IDLE) {
- return INVALID_OPERATION;
- }
-
- mSrcId = dsd->mId;
- mState = STATE_SET_DATASOURCE_PENDING;
-
- mPlayer->setDataSourceAsync(dsd);
-
- while (mState == STATE_SET_DATASOURCE_PENDING) {
- mCondition.wait(mLock);
- }
-
- return mAsyncResult;
-}
-
-status_t NuPlayer2Driver::prepareNextDataSource(const sp<DataSourceDesc> &dsd) {
- ALOGV("prepareNextDataSource(%p)", this);
- Mutex::Autolock autoLock(mLock);
-
- mPlayer->prepareNextDataSourceAsync(dsd);
-
- return OK;
-}
-
-status_t NuPlayer2Driver::playNextDataSource(int64_t srcId) {
- ALOGV("playNextDataSource(%p)", this);
- Mutex::Autolock autoLock(mLock);
-
- mSrcId = srcId;
- mPlayer->playNextDataSource(srcId);
-
- return OK;
-}
-
-status_t NuPlayer2Driver::setVideoSurfaceTexture(const sp<ANativeWindowWrapper> &nww) {
- ALOGV("setVideoSurfaceTexture(%p)", this);
- Mutex::Autolock autoLock(mLock);
-
- if (mSetSurfaceInProgress) {
- return INVALID_OPERATION;
- }
-
- switch (mState) {
- case STATE_SET_DATASOURCE_PENDING:
- case STATE_RESET_IN_PROGRESS:
- return INVALID_OPERATION;
-
- default:
- break;
- }
-
- mSetSurfaceInProgress = true;
-
- mPlayer->setVideoSurfaceTextureAsync(nww);
-
- while (mSetSurfaceInProgress) {
- mCondition.wait(mLock);
- }
-
- return OK;
-}
-
-status_t NuPlayer2Driver::getBufferingSettings(BufferingSettings* buffering) {
- ALOGV("getBufferingSettings(%p)", this);
- {
- Mutex::Autolock autoLock(mLock);
- if (mState == STATE_IDLE) {
- return INVALID_OPERATION;
- }
- }
-
- return mPlayer->getBufferingSettings(buffering);
-}
-
-status_t NuPlayer2Driver::setBufferingSettings(const BufferingSettings& buffering) {
- ALOGV("setBufferingSettings(%p)", this);
- {
- Mutex::Autolock autoLock(mLock);
- if (mState == STATE_IDLE) {
- return INVALID_OPERATION;
- }
- }
-
- return mPlayer->setBufferingSettings(buffering);
-}
-
-status_t NuPlayer2Driver::prepareAsync() {
- ALOGV("prepareAsync(%p)", this);
- Mutex::Autolock autoLock(mLock);
-
- switch (mState) {
- case STATE_UNPREPARED:
- mState = STATE_PREPARING;
- mPlayer->prepareAsync();
- return OK;
- default:
- return INVALID_OPERATION;
- };
-}
-
-status_t NuPlayer2Driver::start() {
- ALOGD("start(%p), state is %d, eos is %d", this, mState, mAtEOS);
- Mutex::Autolock autoLock(mLock);
- return start_l();
-}
-
-status_t NuPlayer2Driver::start_l() {
- switch (mState) {
- case STATE_PAUSED:
- case STATE_PREPARED:
- {
- mPlayer->start();
- FALLTHROUGH_INTENDED;
- }
-
- case STATE_RUNNING:
- {
- if (mAtEOS) {
- mPlayer->rewind();
- mAtEOS = false;
- mPositionUs = -1;
- }
- break;
- }
-
- default:
- return INVALID_OPERATION;
- }
-
- mState = STATE_RUNNING;
-
- return OK;
-}
-
-status_t NuPlayer2Driver::pause() {
- ALOGD("pause(%p)", this);
- // The NuPlayerRenderer may get flushed if pause for long enough, e.g. the pause timeout tear
- // down for audio offload mode. If that happens, the NuPlayerRenderer will no longer know the
- // current position. So similar to seekTo, update |mPositionUs| to the pause position by calling
- // getCurrentPosition here.
- int64_t unused;
- getCurrentPosition(&unused);
-
- Mutex::Autolock autoLock(mLock);
-
- switch (mState) {
- case STATE_PAUSED:
- return OK;
-
- case STATE_PREPARED:
- case STATE_RUNNING:
- mState = STATE_PAUSED;
- mPlayer->pause();
- break;
-
- default:
- return INVALID_OPERATION;
- }
-
- return OK;
-}
-
-bool NuPlayer2Driver::isPlaying() {
- return mState == STATE_RUNNING && !mAtEOS;
-}
-
-status_t NuPlayer2Driver::setPlaybackSettings(const AudioPlaybackRate &rate) {
- status_t err = mPlayer->setPlaybackSettings(rate);
- if (err == OK) {
- // try to update position
- int64_t unused;
- getCurrentPosition(&unused);
- }
- return err;
-}
-
-status_t NuPlayer2Driver::getPlaybackSettings(AudioPlaybackRate *rate) {
- return mPlayer->getPlaybackSettings(rate);
-}
-
-status_t NuPlayer2Driver::setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) {
- return mPlayer->setSyncSettings(sync, videoFpsHint);
-}
-
-status_t NuPlayer2Driver::getSyncSettings(AVSyncSettings *sync, float *videoFps) {
- return mPlayer->getSyncSettings(sync, videoFps);
-}
-
-status_t NuPlayer2Driver::seekTo(int64_t msec, MediaPlayer2SeekMode mode) {
- ALOGD("seekTo(%p) (%lld ms, %d) at state %d", this, (long long)msec, mode, mState);
- Mutex::Autolock autoLock(mLock);
-
- int64_t seekTimeUs = msec * 1000LL;
-
- switch (mState) {
- case STATE_PREPARED:
- case STATE_PAUSED:
- case STATE_RUNNING:
- {
- mAtEOS = false;
- mSeekInProgress = true;
- mPlayer->seekToAsync(seekTimeUs, mode, true /* needNotify */);
- break;
- }
-
- default:
- return INVALID_OPERATION;
- }
-
- mPositionUs = seekTimeUs;
- return OK;
-}
-
-status_t NuPlayer2Driver::getCurrentPosition(int64_t *msec) {
- int64_t tempUs = 0;
- {
- Mutex::Autolock autoLock(mLock);
- if (mSeekInProgress || (mState == STATE_PAUSED && !mAtEOS)) {
- tempUs = (mPositionUs <= 0) ? 0 : mPositionUs;
- *msec = divRound(tempUs, (int64_t)(1000));
- return OK;
- }
- }
-
- status_t ret = mPlayer->getCurrentPosition(&tempUs);
-
- Mutex::Autolock autoLock(mLock);
- // We need to check mSeekInProgress here because mPlayer->seekToAsync is an async call, which
- // means getCurrentPosition can be called before seek is completed. Iow, renderer may return a
- // position value that's different the seek to position.
- if (ret != OK) {
- tempUs = (mPositionUs <= 0) ? 0 : mPositionUs;
- } else {
- mPositionUs = tempUs;
- }
- *msec = divRound(tempUs, (int64_t)(1000));
- return OK;
-}
-
-status_t NuPlayer2Driver::getDuration(int64_t *msec) {
- Mutex::Autolock autoLock(mLock);
-
- if (mDurationUs < 0) {
- return UNKNOWN_ERROR;
- }
-
- *msec = (mDurationUs + 500LL) / 1000;
-
- return OK;
-}
-
-void NuPlayer2Driver::updateMetrics(const char *where) {
- if (where == NULL) {
- where = "unknown";
- }
- ALOGV("updateMetrics(%p) from %s at state %d", this, where, mState);
-
- // gather the final stats for this record
- Vector<sp<AMessage>> trackStats;
- mPlayer->getStats(&trackStats);
-
- if (trackStats.size() > 0) {
- for (size_t i = 0; i < trackStats.size(); ++i) {
- const sp<AMessage> &stats = trackStats.itemAt(i);
-
- AString mime;
- stats->findString("mime", &mime);
-
- AString name;
- stats->findString("component-name", &name);
-
- if (mime.startsWith("video/")) {
- int32_t width, height;
- mediametrics_setCString(mMetricsHandle, kPlayerVMime, mime.c_str());
- if (!name.empty()) {
- mediametrics_setCString(mMetricsHandle, kPlayerVCodec, name.c_str());
- }
-
- if (stats->findInt32("width", &width)
- && stats->findInt32("height", &height)) {
- mediametrics_setInt32(mMetricsHandle, kPlayerWidth, width);
- mediametrics_setInt32(mMetricsHandle, kPlayerHeight, height);
- }
-
- int64_t numFramesTotal = 0;
- int64_t numFramesDropped = 0;
- stats->findInt64("frames-total", &numFramesTotal);
- stats->findInt64("frames-dropped-output", &numFramesDropped);
-
- mediametrics_setInt64(mMetricsHandle, kPlayerFrames, numFramesTotal);
- mediametrics_setInt64(mMetricsHandle, kPlayerFramesDropped, numFramesDropped);
-
- float frameRate = 0;
- if (stats->findFloat("frame-rate-output", &frameRate)) {
- mediametrics_setInt64(mMetricsHandle, kPlayerFrameRate, frameRate);
- }
-
- } else if (mime.startsWith("audio/")) {
- mediametrics_setCString(mMetricsHandle, kPlayerAMime, mime.c_str());
- if (!name.empty()) {
- mediametrics_setCString(mMetricsHandle, kPlayerACodec, name.c_str());
- }
- }
- }
- }
-
- // always provide duration and playing time, even if they have 0/unknown values.
-
- // getDuration() uses mLock for mutex -- careful where we use it.
- int64_t duration_ms = -1;
- getDuration(&duration_ms);
- mediametrics_setInt64(mMetricsHandle, kPlayerDuration, duration_ms);
-
- mediametrics_setInt64(mMetricsHandle, kPlayerPlaying, (mPlayingTimeUs+500)/1000 );
-
- if (mRebufferingEvents != 0) {
- mediametrics_setInt64(mMetricsHandle, kPlayerRebuffering, (mRebufferingTimeUs+500)/1000 );
- mediametrics_setInt32(mMetricsHandle, kPlayerRebufferingCount, mRebufferingEvents);
- mediametrics_setInt32(mMetricsHandle, kPlayerRebufferingAtExit, mRebufferingAtExit);
- }
-
- mediametrics_setCString(mMetricsHandle, kPlayerDataSourceType, mPlayer->getDataSourceType());
-}
-
-
-void NuPlayer2Driver::logMetrics(const char *where) {
- if (where == NULL) {
- where = "unknown";
- }
- ALOGV("logMetrics(%p) from %s at state %d", this, where, mState);
-
- if (mMetricsHandle == 0 || mediametrics_isEnabled() == false) {
- return;
- }
-
- // log only non-empty records
- // we always updateMetrics() before we get here
- // and that always injects 3 fields (duration, playing time, and
- // datasource) into the record.
- // So the canonical "empty" record has 3 elements in it.
- if (mediametrics_count(mMetricsHandle) > 3) {
- mediametrics_selfRecord(mMetricsHandle);
- // re-init in case we prepare() and start() again.
- mediametrics_delete(mMetricsHandle);
- mMetricsHandle = mediametrics_create(kKeyPlayer);
- mediametrics_setUid(mMetricsHandle, mClientUid);
- mediametrics_setInt64(mMetricsHandle, kPlayerVersion, mPlayerVersion);
- } else {
- ALOGV("did not have anything to record");
- }
-}
-
-status_t NuPlayer2Driver::reset() {
- ALOGD("reset(%p) at state %d", this, mState);
-
- updateMetrics("reset");
- logMetrics("reset");
-
- Mutex::Autolock autoLock(mLock);
-
- switch (mState) {
- case STATE_IDLE:
- return OK;
-
- case STATE_SET_DATASOURCE_PENDING:
- case STATE_RESET_IN_PROGRESS:
- return INVALID_OPERATION;
-
- case STATE_PREPARING:
- {
- notifyListener_l(mSrcId, MEDIA2_PREPARED);
- break;
- }
-
- default:
- break;
- }
-
- mState = STATE_RESET_IN_PROGRESS;
- mPlayer->resetAsync();
-
- while (mState == STATE_RESET_IN_PROGRESS) {
- mCondition.wait(mLock);
- }
-
- mDurationUs = -1;
- mPositionUs = -1;
- mLooping = false;
- mPlayingTimeUs = 0;
- mRebufferingTimeUs = 0;
- mRebufferingEvents = 0;
- mRebufferingAtExit = false;
-
- return OK;
-}
-
-status_t NuPlayer2Driver::notifyAt(int64_t mediaTimeUs) {
- ALOGV("notifyAt(%p), time:%lld", this, (long long)mediaTimeUs);
- return mPlayer->notifyAt(mediaTimeUs);
-}
-
-status_t NuPlayer2Driver::setLooping(int loop) {
- mLooping = loop != 0;
- return OK;
-}
-
-status_t NuPlayer2Driver::invoke(const PlayerMessage &request, PlayerMessage *response) {
- if (response == NULL) {
- ALOGE("reply is a NULL pointer");
- return BAD_VALUE;
- }
-
- RepeatedPtrField<const Value>::const_iterator it = request.values().cbegin();
- int32_t methodId = (it++)->int32_value();
-
- switch (methodId) {
- case MEDIA_PLAYER2_INVOKE_ID_SET_VIDEO_SCALING_MODE:
- {
- int mode = (it++)->int32_value();
- return mPlayer->setVideoScalingMode(mode);
- }
-
- case MEDIA_PLAYER2_INVOKE_ID_GET_TRACK_INFO:
- {
- int64_t srcId = (it++)->int64_value();
- return mPlayer->getTrackInfo(srcId, response);
- }
-
- case MEDIA_PLAYER2_INVOKE_ID_SELECT_TRACK:
- {
- int64_t srcId = (it++)->int64_value();
- int trackIndex = (it++)->int32_value();
- int64_t msec = 0;
- // getCurrentPosition should always return OK
- getCurrentPosition(&msec);
- return mPlayer->selectTrack(srcId, trackIndex, true /* select */, msec * 1000LL);
- }
-
- case MEDIA_PLAYER2_INVOKE_ID_UNSELECT_TRACK:
- {
- int64_t srcId = (it++)->int64_value();
- int trackIndex = (it++)->int32_value();
- return mPlayer->selectTrack(
- srcId, trackIndex, false /* select */, 0xdeadbeef /* not used */);
- }
-
- case MEDIA_PLAYER2_INVOKE_ID_GET_SELECTED_TRACK:
- {
- int64_t srcId = (it++)->int64_value();
- int32_t type = (it++)->int32_value();
- return mPlayer->getSelectedTrack(srcId, type, response);
- }
-
- default:
- {
- return INVALID_OPERATION;
- }
- }
-}
-
-void NuPlayer2Driver::setAudioSink(const sp<AudioSink> &audioSink) {
- mPlayer->setAudioSink(audioSink);
- mAudioSink = audioSink;
-}
-
-status_t NuPlayer2Driver::setParameter(
- int /* key */, const Parcel & /* request */) {
- return INVALID_OPERATION;
-}
-
-status_t NuPlayer2Driver::getParameter(int key __unused, Parcel *reply __unused) {
- return INVALID_OPERATION;
-}
-
-status_t NuPlayer2Driver::getMetrics(char **buffer, size_t *length) {
- updateMetrics("api");
- if (mediametrics_getAttributes(mMetricsHandle, buffer, length))
- return OK;
- else
- return FAILED_TRANSACTION;
-}
-
-void NuPlayer2Driver::notifyResetComplete(int64_t /* srcId */) {
- ALOGD("notifyResetComplete(%p)", this);
- Mutex::Autolock autoLock(mLock);
-
- CHECK_EQ(mState, STATE_RESET_IN_PROGRESS);
- mState = STATE_IDLE;
- mCondition.broadcast();
-}
-
-void NuPlayer2Driver::notifySetSurfaceComplete(int64_t /* srcId */) {
- ALOGV("notifySetSurfaceComplete(%p)", this);
- Mutex::Autolock autoLock(mLock);
-
- CHECK(mSetSurfaceInProgress);
- mSetSurfaceInProgress = false;
-
- mCondition.broadcast();
-}
-
-void NuPlayer2Driver::notifyDuration(int64_t /* srcId */, int64_t durationUs) {
- Mutex::Autolock autoLock(mLock);
- mDurationUs = durationUs;
-}
-
-void NuPlayer2Driver::notifyMorePlayingTimeUs(int64_t /* srcId */, int64_t playingUs) {
- Mutex::Autolock autoLock(mLock);
- mPlayingTimeUs += playingUs;
-}
-
-void NuPlayer2Driver::notifyMoreRebufferingTimeUs(int64_t /* srcId */, int64_t rebufferingUs) {
- Mutex::Autolock autoLock(mLock);
- mRebufferingTimeUs += rebufferingUs;
- mRebufferingEvents++;
-}
-
-void NuPlayer2Driver::notifyRebufferingWhenExit(int64_t /* srcId */, bool status) {
- Mutex::Autolock autoLock(mLock);
- mRebufferingAtExit = status;
-}
-
-void NuPlayer2Driver::notifySeekComplete(int64_t srcId) {
- ALOGV("notifySeekComplete(%p)", this);
- Mutex::Autolock autoLock(mLock);
- mSeekInProgress = false;
- notifyListener_l(srcId, MEDIA2_SEEK_COMPLETE);
-}
-
-status_t NuPlayer2Driver::dump(
- int fd, const Vector<String16> & /* args */) const {
-
- Vector<sp<AMessage> > trackStats;
- mPlayer->getStats(&trackStats);
-
- AString logString(" NuPlayer2\n");
- char buf[256] = {0};
-
- bool locked = false;
- for (int i = 0; i < kDumpLockRetries; ++i) {
- if (mLock.tryLock() == NO_ERROR) {
- locked = true;
- break;
- }
- usleep(kDumpLockSleepUs);
- }
-
- if (locked) {
- snprintf(buf, sizeof(buf), " state(%d), atEOS(%d), looping(%d), autoLoop(%d)\n",
- mState, mAtEOS, mLooping, mAutoLoop);
- mLock.unlock();
- } else {
- snprintf(buf, sizeof(buf), " NPD(%p) lock is taken\n", this);
- }
- logString.append(buf);
-
- for (size_t i = 0; i < trackStats.size(); ++i) {
- const sp<AMessage> &stats = trackStats.itemAt(i);
-
- AString mime;
- if (stats->findString("mime", &mime)) {
- snprintf(buf, sizeof(buf), " mime(%s)\n", mime.c_str());
- logString.append(buf);
- }
-
- AString name;
- if (stats->findString("component-name", &name)) {
- snprintf(buf, sizeof(buf), " decoder(%s)\n", name.c_str());
- logString.append(buf);
- }
-
- if (mime.startsWith("video/")) {
- int32_t width, height;
- if (stats->findInt32("width", &width)
- && stats->findInt32("height", &height)) {
- snprintf(buf, sizeof(buf), " resolution(%d x %d)\n", width, height);
- logString.append(buf);
- }
-
- int64_t numFramesTotal = 0;
- int64_t numFramesDropped = 0;
-
- stats->findInt64("frames-total", &numFramesTotal);
- stats->findInt64("frames-dropped-output", &numFramesDropped);
- snprintf(buf, sizeof(buf), " numFramesTotal(%lld), numFramesDropped(%lld), "
- "percentageDropped(%.2f%%)\n",
- (long long)numFramesTotal,
- (long long)numFramesDropped,
- numFramesTotal == 0
- ? 0.0 : (double)(numFramesDropped * 100) / numFramesTotal);
- logString.append(buf);
- }
- }
-
- ALOGI("%s", logString.c_str());
-
- if (fd >= 0) {
- FILE *out = fdopen(dup(fd), "w");
- fprintf(out, "%s", logString.c_str());
- fclose(out);
- out = NULL;
- }
-
- return OK;
-}
-
-void NuPlayer2Driver::onMessageReceived(const sp<AMessage> &msg) {
- switch (msg->what()) {
- case kWhatNotifyListener: {
- int64_t srcId;
- int32_t msgId;
- int32_t ext1 = 0;
- int32_t ext2 = 0;
- CHECK(msg->findInt64("srcId", &srcId));
- CHECK(msg->findInt32("messageId", &msgId));
- msg->findInt32("ext1", &ext1);
- msg->findInt32("ext2", &ext2);
- sp<PlayerMessageWrapper> in;
- sp<RefBase> obj;
- if (msg->findObject("obj", &obj) && obj != NULL) {
- in = static_cast<PlayerMessageWrapper *>(obj.get());
- }
- sendEvent(srcId, msgId, ext1, ext2, (in == NULL ? NULL : in->getPlayerMessage()));
- break;
- }
- default:
- break;
- }
-}
-
-void NuPlayer2Driver::notifyListener(
- int64_t srcId, int msg, int ext1, int ext2, const PlayerMessage *in) {
- Mutex::Autolock autoLock(mLock);
- notifyListener_l(srcId, msg, ext1, ext2, in);
-}
-
-void NuPlayer2Driver::notifyListener_l(
- int64_t srcId, int msg, int ext1, int ext2, const PlayerMessage *in) {
- ALOGD("notifyListener_l(%p), (%lld, %d, %d, %d, %d), loop setting(%d, %d)",
- this, (long long)srcId, msg, ext1, ext2,
- (in == NULL ? -1 : (int)in->ByteSize()), mAutoLoop, mLooping);
- if (srcId == mSrcId) {
- switch (msg) {
- case MEDIA2_PLAYBACK_COMPLETE:
- {
- if (mState != STATE_RESET_IN_PROGRESS) {
- if (mAutoLoop) {
- audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
- if (mAudioSink != NULL) {
- streamType = mAudioSink->getAudioStreamType();
- }
- if (streamType == AUDIO_STREAM_NOTIFICATION) {
- ALOGW("disabling auto-loop for notification");
- mAutoLoop = false;
- }
- }
- if (mLooping || mAutoLoop) {
- mPlayer->rewind();
- if (mAudioSink != NULL) {
- // The renderer has stopped the sink at the end in order to play out
- // the last little bit of audio. In looping mode, we need to restart it.
- mAudioSink->start();
- }
-
- sp<AMessage> notify = new AMessage(kWhatNotifyListener, this);
- notify->setInt64("srcId", srcId);
- notify->setInt32("messageId", MEDIA2_INFO);
- notify->setInt32("ext1", MEDIA2_INFO_DATA_SOURCE_REPEAT);
- notify->post();
- return;
- }
- if (property_get_bool("persist.debug.sf.stats", false)) {
- Vector<String16> args;
- dump(-1, args);
- }
- mPlayer->pause();
- mState = STATE_PAUSED;
- }
- FALLTHROUGH_INTENDED;
- }
-
- case MEDIA2_ERROR:
- {
- // when we have an error, add it to the analytics for this playback.
- // ext1 is our primary 'error type' value. Only add ext2 when non-zero.
- // [test against msg is due to fall through from previous switch value]
- if (msg == MEDIA2_ERROR) {
- mediametrics_setInt32(mMetricsHandle, kPlayerError, ext1);
- if (ext2 != 0) {
- mediametrics_setInt32(mMetricsHandle, kPlayerErrorCode, ext2);
- }
- mediametrics_setCString(mMetricsHandle, kPlayerErrorState, stateString(mState).c_str());
- }
- mAtEOS = true;
- break;
- }
-
- default:
- break;
- }
- }
-
- sp<AMessage> notify = new AMessage(kWhatNotifyListener, this);
- notify->setInt64("srcId", srcId);
- notify->setInt32("messageId", msg);
- notify->setInt32("ext1", ext1);
- notify->setInt32("ext2", ext2);
- notify->setObject("obj", PlayerMessageWrapper::Create((PlayerMessage*)in));
- notify->post();
-}
-
-void NuPlayer2Driver::notifySetDataSourceCompleted(int64_t /* srcId */, status_t err) {
- Mutex::Autolock autoLock(mLock);
-
- CHECK_EQ(mState, STATE_SET_DATASOURCE_PENDING);
-
- mAsyncResult = err;
- mState = (err == OK) ? STATE_UNPREPARED : STATE_IDLE;
- mCondition.broadcast();
-}
-
-void NuPlayer2Driver::notifyPrepareCompleted(int64_t srcId, status_t err) {
- ALOGV("notifyPrepareCompleted %d", err);
-
- Mutex::Autolock autoLock(mLock);
-
- if (srcId != mSrcId) {
- if (err == OK) {
- notifyListener_l(srcId, MEDIA2_PREPARED);
- } else {
- notifyListener_l(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
- }
- return;
- }
-
- if (mState != STATE_PREPARING) {
- // We were preparing asynchronously when the client called
- // reset(), we sent a premature "prepared" notification and
- // then initiated the reset. This notification is stale.
- CHECK(mState == STATE_RESET_IN_PROGRESS || mState == STATE_IDLE);
- return;
- }
-
- CHECK_EQ(mState, STATE_PREPARING);
-
- mAsyncResult = err;
-
- if (err == OK) {
- // update state before notifying client, so that if client calls back into NuPlayer2Driver
- // in response, NuPlayer2Driver has the right state
- mState = STATE_PREPARED;
- notifyListener_l(srcId, MEDIA2_PREPARED);
- } else {
- mState = STATE_UNPREPARED;
- notifyListener_l(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
- }
-
- sp<MetaData> meta = mPlayer->getFileMeta();
- int32_t loop;
- if (meta != NULL
- && meta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
- mAutoLoop = true;
- }
-
- mCondition.broadcast();
-}
-
-void NuPlayer2Driver::notifyFlagsChanged(int64_t /* srcId */, uint32_t flags) {
- Mutex::Autolock autoLock(mLock);
-
- mPlayerFlags = flags;
-}
-
-// Modular DRM
-status_t NuPlayer2Driver::prepareDrm(
- int64_t srcId, const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId)
-{
- ALOGV("prepareDrm(%p) state: %d", this, mState);
-
- // leaving the state verification for mediaplayer.cpp
- status_t ret = mPlayer->prepareDrm(srcId, uuid, drmSessionId);
-
- ALOGV("prepareDrm ret: %d", ret);
-
- return ret;
-}
-
-status_t NuPlayer2Driver::releaseDrm(int64_t srcId)
-{
- ALOGV("releaseDrm(%p) state: %d", this, mState);
-
- // leaving the state verification for mediaplayer.cpp
- status_t ret = mPlayer->releaseDrm(srcId);
-
- ALOGV("releaseDrm ret: %d", ret);
-
- return ret;
-}
-
-std::string NuPlayer2Driver::stateString(State state) {
- const char *rval = NULL;
- char rawbuffer[16]; // allows "%d"
-
- switch (state) {
- case STATE_IDLE: rval = "IDLE"; break;
- case STATE_SET_DATASOURCE_PENDING: rval = "SET_DATASOURCE_PENDING"; break;
- case STATE_UNPREPARED: rval = "UNPREPARED"; break;
- case STATE_PREPARING: rval = "PREPARING"; break;
- case STATE_PREPARED: rval = "PREPARED"; break;
- case STATE_RUNNING: rval = "RUNNING"; break;
- case STATE_PAUSED: rval = "PAUSED"; break;
- case STATE_RESET_IN_PROGRESS: rval = "RESET_IN_PROGRESS"; break;
- default:
- // yes, this buffer is shared and vulnerable to races
- snprintf(rawbuffer, sizeof(rawbuffer), "%d", state);
- rval = rawbuffer;
- break;
- }
-
- return rval;
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h
deleted file mode 100644
index c97e247..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <mediaplayer2/MediaPlayer2Interface.h>
-
-#include <media/MediaMetrics.h>
-#include <media/stagefright/foundation/ABase.h>
-#include <mediaplayer2/JObjectHolder.h>
-
-namespace android {
-
-struct ALooper;
-struct MediaClock;
-struct NuPlayer2;
-
-struct NuPlayer2Driver : public MediaPlayer2Interface {
- explicit NuPlayer2Driver(pid_t pid, uid_t uid, const sp<JObjectHolder> &context);
-
- virtual status_t initCheck() override;
-
- virtual status_t setDataSource(const sp<DataSourceDesc> &dsd) override;
- virtual status_t prepareNextDataSource(const sp<DataSourceDesc> &dsd) override;
- virtual status_t playNextDataSource(int64_t srcId) override;
-
- virtual status_t setVideoSurfaceTexture(const sp<ANativeWindowWrapper> &nww) override;
-
- virtual status_t getBufferingSettings(
- BufferingSettings* buffering /* nonnull */) override;
- virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
-
- virtual status_t prepareAsync() override;
- virtual status_t start() override;
- virtual status_t pause() override;
- virtual bool isPlaying() override;
- virtual status_t setPlaybackSettings(const AudioPlaybackRate &rate) override;
- virtual status_t getPlaybackSettings(AudioPlaybackRate *rate) override;
- virtual status_t setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) override;
- virtual status_t getSyncSettings(AVSyncSettings *sync, float *videoFps) override;
- virtual status_t seekTo(
- int64_t msec,
- MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC) override;
- virtual status_t getCurrentPosition(int64_t *msec) override;
- virtual status_t getDuration(int64_t *msec) override;
- virtual status_t reset() override;
- virtual status_t notifyAt(int64_t mediaTimeUs) override;
- virtual status_t setLooping(int loop) override;
- virtual status_t invoke(const PlayerMessage &request, PlayerMessage *response) override;
- virtual void setAudioSink(const sp<AudioSink> &audioSink) override;
- virtual status_t setParameter(int key, const Parcel &request) override;
- virtual status_t getParameter(int key, Parcel *reply) override;
- virtual status_t getMetrics(char **buf, size_t *length) override;
-
- virtual status_t dump(int fd, const Vector<String16> &args) const override;
-
- virtual void onMessageReceived(const sp<AMessage> &msg) override;
-
- void notifySetDataSourceCompleted(int64_t srcId, status_t err);
- void notifyPrepareCompleted(int64_t srcId, status_t err);
- void notifyResetComplete(int64_t srcId);
- void notifySetSurfaceComplete(int64_t srcId);
- void notifyDuration(int64_t srcId, int64_t durationUs);
- void notifyMorePlayingTimeUs(int64_t srcId, int64_t timeUs);
- void notifyMoreRebufferingTimeUs(int64_t srcId, int64_t timeUs);
- void notifyRebufferingWhenExit(int64_t srcId, bool status);
- void notifySeekComplete(int64_t srcId);
- void notifyListener(int64_t srcId, int msg, int ext1 = 0, int ext2 = 0,
- const PlayerMessage *in = NULL);
- void notifyFlagsChanged(int64_t srcId, uint32_t flags);
-
- // Modular DRM
- virtual status_t prepareDrm(
- int64_t srcId, const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId);
- virtual status_t releaseDrm(int64_t srcId);
-
-protected:
- virtual ~NuPlayer2Driver();
-
-private:
- enum State {
- STATE_IDLE,
- STATE_SET_DATASOURCE_PENDING,
- STATE_UNPREPARED,
- STATE_PREPARING,
- STATE_PREPARED,
- STATE_RUNNING,
- STATE_PAUSED,
- STATE_RESET_IN_PROGRESS,
- };
-
- std::string stateString(State state);
-
- enum {
- kWhatNotifyListener,
- };
-
- mutable Mutex mLock;
- Condition mCondition;
-
- State mState;
-
- status_t mAsyncResult;
-
- // The following are protected through "mLock"
- // >>>
- int64_t mSrcId;
- bool mSetSurfaceInProgress;
- int64_t mDurationUs;
- int64_t mPositionUs;
- bool mSeekInProgress;
- int64_t mPlayingTimeUs;
- int64_t mRebufferingTimeUs;
- int32_t mRebufferingEvents;
- bool mRebufferingAtExit;
- // <<<
-
- sp<ALooper> mLooper;
- sp<ALooper> mNuPlayer2Looper;
- const sp<MediaClock> mMediaClock;
- const sp<NuPlayer2> mPlayer;
- sp<AudioSink> mAudioSink;
- uint32_t mPlayerFlags;
-
- mediametrics_handle_t mMetricsHandle;
- int64_t mPlayerVersion;
- uid_t mClientUid;
-
- bool mAtEOS;
- bool mLooping;
- bool mAutoLoop;
-
- void updateMetrics(const char *where);
- void logMetrics(const char *where);
-
- status_t start_l();
- void notifyListener_l(int64_t srcId, int msg, int ext1 = 0, int ext2 = 0,
- const PlayerMessage *in = NULL);
-
- DISALLOW_EVIL_CONSTRUCTORS(NuPlayer2Driver);
-};
-
-} // namespace android
-
-
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.cpp
deleted file mode 100644
index f41a431..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.cpp
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NuPlayer2Drm"
-
-#include "NuPlayer2Drm.h"
-
-#include <media/NdkWrapper.h>
-#include <utils/Log.h>
-#include <sstream>
-
-namespace android {
-
-Vector<DrmUUID> NuPlayer2Drm::parsePSSH(const void *pssh, size_t psshsize)
-{
- Vector<DrmUUID> drmSchemes, empty;
- const int DATALEN_SIZE = 4;
-
- // the format of the buffer is 1 or more of:
- // {
- // 16 byte uuid
- // 4 byte data length N
- // N bytes of data
- // }
- // Determine the number of entries in the source data.
- // Since we got the data from stagefright, we trust it is valid and properly formatted.
-
- const uint8_t *data = (const uint8_t*)pssh;
- size_t len = psshsize;
- size_t numentries = 0;
- while (len > 0) {
- if (len < DrmUUID::UUID_SIZE) {
- ALOGE("ParsePSSH: invalid PSSH data");
- return empty;
- }
-
- const uint8_t *uuidPtr = data;
-
- // skip uuid
- data += DrmUUID::UUID_SIZE;
- len -= DrmUUID::UUID_SIZE;
-
- // get data length
- if (len < DATALEN_SIZE) {
- ALOGE("ParsePSSH: invalid PSSH data");
- return empty;
- }
-
- uint32_t datalen = *((uint32_t*)data);
- data += DATALEN_SIZE;
- len -= DATALEN_SIZE;
-
- if (len < datalen) {
- ALOGE("ParsePSSH: invalid PSSH data");
- return empty;
- }
-
- // skip the data
- data += datalen;
- len -= datalen;
-
- DrmUUID _uuid(uuidPtr);
- drmSchemes.add(_uuid);
-
- ALOGV("ParsePSSH[%zu]: %s: %s", numentries,
- _uuid.toHexString().string(),
- DrmUUID::arrayToHex(data, datalen).string()
- );
-
- numentries++;
- }
-
- return drmSchemes;
-}
-
-Vector<DrmUUID> NuPlayer2Drm::getSupportedDrmSchemes(const void *pssh, size_t psshsize)
-{
- Vector<DrmUUID> psshDRMs = parsePSSH(pssh, psshsize);
-
- Vector<DrmUUID> supportedDRMs;
- for (size_t i = 0; i < psshDRMs.size(); i++) {
- DrmUUID uuid = psshDRMs[i];
- if (AMediaDrmWrapper::isCryptoSchemeSupported(uuid.ptr(), NULL)) {
- supportedDRMs.add(uuid);
- }
- }
-
- ALOGV("getSupportedDrmSchemes: psshDRMs: %zu supportedDRMs: %zu",
- psshDRMs.size(), supportedDRMs.size());
-
- return supportedDRMs;
-}
-
-sp<ABuffer> NuPlayer2Drm::retrieveDrmInfo(const void *pssh, uint32_t psshsize)
-{
- std::ostringstream buf;
-
- // 1) PSSH bytes
- buf.write(reinterpret_cast<const char *>(&psshsize), sizeof(psshsize));
- buf.write(reinterpret_cast<const char *>(pssh), psshsize);
-
- ALOGV("retrieveDrmInfo: MEDIA2_DRM_INFO PSSH: size: %u %s", psshsize,
- DrmUUID::arrayToHex((uint8_t*)pssh, psshsize).string());
-
- // 2) supportedDRMs
- Vector<DrmUUID> supportedDRMs = getSupportedDrmSchemes(pssh, psshsize);
- uint32_t n = supportedDRMs.size();
- buf.write(reinterpret_cast<char *>(&n), sizeof(n));
- for (size_t i = 0; i < n; i++) {
- DrmUUID uuid = supportedDRMs[i];
- buf.write(reinterpret_cast<const char *>(&n), sizeof(n));
- buf.write(reinterpret_cast<const char *>(uuid.ptr()), DrmUUID::UUID_SIZE);
-
- ALOGV("retrieveDrmInfo: MEDIA2_DRM_INFO supportedScheme[%zu] %s", i,
- uuid.toHexString().string());
- }
-
- sp<ABuffer> drmInfoBuffer = ABuffer::CreateAsCopy(buf.str().c_str(), buf.tellp());
- return drmInfoBuffer;
-}
-
-status_t NuPlayer2Drm::retrieveDrmInfo(PsshInfo *psshInfo, PlayerMessage *playerMsg)
-{
- std::ostringstream pssh, drmInfo;
-
- // 0) Generate PSSH bytes
- for (size_t i = 0; i < psshInfo->numentries; i++) {
- PsshEntry *entry = &psshInfo->entries[i];
- uint32_t datalen = entry->datalen;
- pssh.write(reinterpret_cast<const char *>(&entry->uuid), sizeof(entry->uuid));
- pssh.write(reinterpret_cast<const char *>(&datalen), sizeof(datalen));
- pssh.write(reinterpret_cast<const char *>(entry->data), datalen);
- }
-
- uint32_t psshSize = pssh.tellp();
- std::string psshBase = pssh.str();
- const auto* psshPtr = reinterpret_cast<const uint8_t*>(psshBase.c_str());
- ALOGV("retrieveDrmInfo: MEDIA_DRM_INFO PSSH: size: %u %s", psshSize,
- DrmUUID::arrayToHex(psshPtr, psshSize).string());
-
- // 1) Write PSSH bytes
- playerMsg->add_values()->set_bytes_value(
- reinterpret_cast<const char *>(pssh.str().c_str()), psshSize);
-
- // 2) Write supportedDRMs
- uint32_t numentries = psshInfo->numentries;
- playerMsg->add_values()->set_int32_value(numentries);
- for (size_t i = 0; i < numentries; i++) {
- PsshEntry *entry = &psshInfo->entries[i];
- playerMsg->add_values()->set_bytes_value(
- reinterpret_cast<const char *>(&entry->uuid), sizeof(entry->uuid));
- ALOGV("retrieveDrmInfo: MEDIA_DRM_INFO supportedScheme[%zu] %s", i,
- DrmUUID::arrayToHex((const uint8_t*)&entry->uuid, sizeof(AMediaUUID)).string());
- }
- return OK;
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.h
deleted file mode 100644
index 968d1be..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NUPLAYER2_DRM_H_
-#define NUPLAYER2_DRM_H_
-
-#include <media/NdkMediaExtractor.h>
-#include <media/stagefright/foundation/ABuffer.h>
-
-#include <utils/String8.h>
-#include <utils/Vector.h>
-
-#include "mediaplayer2.pb.h"
-
-using android::media::MediaPlayer2Proto::PlayerMessage;
-
-namespace android {
-
- struct DrmUUID {
- static const int UUID_SIZE = 16;
-
- DrmUUID() {
- memset(this->uuid, 0, sizeof(uuid));
- }
-
- // to allow defining Vector/KeyedVector of UUID type
- DrmUUID(const DrmUUID &a) {
- memcpy(this->uuid, a.uuid, sizeof(uuid));
- }
-
- // to allow defining Vector/KeyedVector of UUID type
- DrmUUID(const uint8_t uuid_in[UUID_SIZE]) {
- memcpy(this->uuid, uuid_in, sizeof(uuid));
- }
-
- const uint8_t *ptr() const {
- return uuid;
- }
-
- String8 toHexString() const {
- return arrayToHex(uuid, UUID_SIZE);
- }
-
- static String8 toHexString(const uint8_t uuid_in[UUID_SIZE]) {
- return arrayToHex(uuid_in, UUID_SIZE);
- }
-
- static String8 arrayToHex(const uint8_t *array, int bytes) {
- String8 result;
- for (int i = 0; i < bytes; i++) {
- result.appendFormat("%02x", array[i]);
- }
-
- return result;
- }
-
- protected:
- uint8_t uuid[UUID_SIZE];
- };
-
-
- struct NuPlayer2Drm {
-
- // static helpers - internal
-
- protected:
- static Vector<DrmUUID> parsePSSH(const void *pssh, size_t psshsize);
- static Vector<DrmUUID> getSupportedDrmSchemes(const void *pssh, size_t psshsize);
-
- // static helpers - public
-
- public:
- static sp<ABuffer> retrieveDrmInfo(const void *pssh, uint32_t psshsize);
- static status_t retrieveDrmInfo(PsshInfo *, PlayerMessage *);
-
- }; // NuPlayer2Drm
-
-} // android
-
-#endif //NUPLAYER2_DRM_H_
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
deleted file mode 100644
index fd459df..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
+++ /dev/null
@@ -1,2096 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NuPlayer2Renderer"
-#include <utils/Log.h>
-
-#include "JWakeLock.h"
-#include "NuPlayer2Renderer.h"
-#include <algorithm>
-#include <cutils/properties.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/foundation/AUtils.h>
-#include <media/stagefright/MediaClock.h>
-#include <media/stagefright/MediaCodecConstants.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/Utils.h>
-#include <media/stagefright/VideoFrameScheduler2.h>
-#include <media/MediaCodecBuffer.h>
-
-#include <inttypes.h>
-
-namespace android {
-
-/*
- * Example of common configuration settings in shell script form
-
- #Turn offload audio off (use PCM for Play Music) -- AudioPolicyManager
- adb shell setprop audio.offload.disable 1
-
- #Allow offload audio with video (requires offloading to be enabled) -- AudioPolicyManager
- adb shell setprop audio.offload.video 1
-
- #Use audio callbacks for PCM data
- adb shell setprop media.stagefright.audio.cbk 1
-
- #Use deep buffer for PCM data with video (it is generally enabled for audio-only)
- adb shell setprop media.stagefright.audio.deep 1
-
- #Set size of buffers for pcm audio sink in msec (example: 1000 msec)
- adb shell setprop media.stagefright.audio.sink 1000
-
- * These configurations take effect for the next track played (not the current track).
- */
-
-static inline bool getUseAudioCallbackSetting() {
- return property_get_bool("media.stagefright.audio.cbk", false /* default_value */);
-}
-
-static inline int32_t getAudioSinkPcmMsSetting() {
- return property_get_int32(
- "media.stagefright.audio.sink", 500 /* default_value */);
-}
-
-// Maximum time in paused state when offloading audio decompression. When elapsed, the AudioSink
-// is closed to allow the audio DSP to power down.
-static const int64_t kOffloadPauseMaxUs = 10000000LL;
-
-// Maximum allowed delay from AudioSink, 1.5 seconds.
-static const int64_t kMaxAllowedAudioSinkDelayUs = 1500000LL;
-
-static const int64_t kMinimumAudioClockUpdatePeriodUs = 20 /* msec */ * 1000;
-
-// Default video frame display duration when only video exists.
-// Used to set max media time in MediaClock.
-static const int64_t kDefaultVideoFrameIntervalUs = 100000LL;
-
-// static
-const NuPlayer2::Renderer::PcmInfo NuPlayer2::Renderer::AUDIO_PCMINFO_INITIALIZER = {
- AUDIO_CHANNEL_NONE,
- AUDIO_OUTPUT_FLAG_NONE,
- AUDIO_FORMAT_INVALID,
- 0, // mNumChannels
- 0 // mSampleRate
-};
-
-// static
-const int64_t NuPlayer2::Renderer::kMinPositionUpdateDelayUs = 100000LL;
-
-static audio_format_t constexpr audioFormatFromEncoding(int32_t pcmEncoding) {
- switch (pcmEncoding) {
- case kAudioEncodingPcmFloat:
- return AUDIO_FORMAT_PCM_FLOAT;
- case kAudioEncodingPcm16bit:
- return AUDIO_FORMAT_PCM_16_BIT;
- case kAudioEncodingPcm8bit:
- return AUDIO_FORMAT_PCM_8_BIT; // TODO: do we want to support this?
- default:
- ALOGE("%s: Invalid encoding: %d", __func__, pcmEncoding);
- return AUDIO_FORMAT_INVALID;
- }
-}
-
-NuPlayer2::Renderer::Renderer(
- const sp<MediaPlayer2Interface::AudioSink> &sink,
- const sp<MediaClock> &mediaClock,
- const sp<AMessage> ¬ify,
- const sp<JObjectHolder> &context,
- uint32_t flags)
- : mAudioSink(sink),
- mUseVirtualAudioSink(false),
- mNotify(notify),
- mFlags(flags),
- mNumFramesWritten(0),
- mDrainAudioQueuePending(false),
- mDrainVideoQueuePending(false),
- mAudioQueueGeneration(0),
- mVideoQueueGeneration(0),
- mAudioDrainGeneration(0),
- mVideoDrainGeneration(0),
- mAudioEOSGeneration(0),
- mMediaClock(mediaClock),
- mPlaybackSettings(AUDIO_PLAYBACK_RATE_DEFAULT),
- mAudioFirstAnchorTimeMediaUs(-1),
- mAnchorTimeMediaUs(-1),
- mAnchorNumFramesWritten(-1),
- mVideoLateByUs(0LL),
- mNextVideoTimeMediaUs(-1),
- mHasAudio(false),
- mHasVideo(false),
- mNotifyCompleteAudio(false),
- mNotifyCompleteVideo(false),
- mSyncQueues(false),
- mPaused(true),
- mPauseDrainAudioAllowedUs(0),
- mVideoSampleReceived(false),
- mVideoRenderingStarted(false),
- mVideoRenderingStartGeneration(0),
- mAudioRenderingStartGeneration(0),
- mRenderingDataDelivered(false),
- mNextAudioClockUpdateTimeUs(-1),
- mLastAudioMediaTimeUs(-1),
- mAudioOffloadPauseTimeoutGeneration(0),
- mAudioTornDown(false),
- mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER),
- mCurrentPcmInfo(AUDIO_PCMINFO_INITIALIZER),
- mTotalBuffersQueued(0),
- mLastAudioBufferDrained(0),
- mUseAudioCallback(false),
- mWakeLock(new JWakeLock(context)) {
- CHECK(mediaClock != NULL);
- mMediaClock->setPlaybackRate(mPlaybackSettings.mSpeed);
-}
-
-NuPlayer2::Renderer::~Renderer() {
- if (offloadingAudio()) {
- mAudioSink->stop();
- mAudioSink->flush();
- mAudioSink->close();
- }
-
- // Try to avoid racing condition in case callback is still on.
- Mutex::Autolock autoLock(mLock);
- if (mUseAudioCallback) {
- flushQueue(&mAudioQueue);
- flushQueue(&mVideoQueue);
- }
- mWakeLock.clear();
- mVideoScheduler.clear();
- mNotify.clear();
- mAudioSink.clear();
-}
-
-void NuPlayer2::Renderer::queueBuffer(
- bool audio,
- const sp<MediaCodecBuffer> &buffer,
- const sp<AMessage> ¬ifyConsumed) {
- sp<AMessage> msg = new AMessage(kWhatQueueBuffer, this);
- msg->setInt32("queueGeneration", getQueueGeneration(audio));
- msg->setInt32("audio", static_cast<int32_t>(audio));
- msg->setObject("buffer", buffer);
- msg->setMessage("notifyConsumed", notifyConsumed);
- msg->post();
-}
-
-void NuPlayer2::Renderer::queueEOS(bool audio, status_t finalResult) {
- CHECK_NE(finalResult, (status_t)OK);
-
- sp<AMessage> msg = new AMessage(kWhatQueueEOS, this);
- msg->setInt32("queueGeneration", getQueueGeneration(audio));
- msg->setInt32("audio", static_cast<int32_t>(audio));
- msg->setInt32("finalResult", finalResult);
- msg->post();
-}
-
-status_t NuPlayer2::Renderer::setPlaybackSettings(const AudioPlaybackRate &rate) {
- sp<AMessage> msg = new AMessage(kWhatConfigPlayback, this);
- writeToAMessage(msg, rate);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- }
- return err;
-}
-
-status_t NuPlayer2::Renderer::onConfigPlayback(const AudioPlaybackRate &rate /* sanitized */) {
- if (rate.mSpeed <= 0.f) {
- ALOGW("playback rate cannot be %f", rate.mSpeed);
- return BAD_VALUE;
- }
-
- if (mAudioSink != NULL && mAudioSink->ready()) {
- status_t err = mAudioSink->setPlaybackRate(rate);
- if (err != OK) {
- ALOGW("failed to get playback rate from audio sink, err(%d)", err);
- return err;
- }
- }
- mPlaybackSettings = rate;
- mMediaClock->setPlaybackRate(mPlaybackSettings.mSpeed);
- return OK;
-}
-
-status_t NuPlayer2::Renderer::getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) {
- sp<AMessage> msg = new AMessage(kWhatGetPlaybackSettings, this);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- if (err == OK) {
- readFromAMessage(response, rate);
- }
- }
- return err;
-}
-
-status_t NuPlayer2::Renderer::onGetPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) {
- if (mAudioSink != NULL && mAudioSink->ready()) {
- status_t err = mAudioSink->getPlaybackRate(rate);
- if (err == OK) {
- if (!isAudioPlaybackRateEqual(*rate, mPlaybackSettings)) {
- ALOGW("correcting mismatch in internal/external playback rate, %f vs %f",
- rate->mSpeed, mPlaybackSettings.mSpeed);
- }
- // get playback settings used by audiosink, as it may be
- // slightly off due to audiosink not taking small changes.
- mPlaybackSettings = *rate;
- }
- return err;
- }
- *rate = mPlaybackSettings;
- return OK;
-}
-
-status_t NuPlayer2::Renderer::setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) {
- sp<AMessage> msg = new AMessage(kWhatConfigSync, this);
- writeToAMessage(msg, sync, videoFpsHint);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- }
- return err;
-}
-
-status_t NuPlayer2::Renderer::onConfigSync(const AVSyncSettings &sync, float videoFpsHint __unused) {
- if (sync.mSource != AVSYNC_SOURCE_DEFAULT) {
- return BAD_VALUE;
- }
- // TODO: support sync sources
- return INVALID_OPERATION;
-}
-
-status_t NuPlayer2::Renderer::getSyncSettings(AVSyncSettings *sync, float *videoFps) {
- sp<AMessage> msg = new AMessage(kWhatGetSyncSettings, this);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- if (err == OK) {
- readFromAMessage(response, sync, videoFps);
- }
- }
- return err;
-}
-
-status_t NuPlayer2::Renderer::onGetSyncSettings(
- AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */) {
- *sync = mSyncSettings;
- *videoFps = -1.f;
- return OK;
-}
-
-void NuPlayer2::Renderer::flush(bool audio, bool notifyComplete) {
- {
- Mutex::Autolock autoLock(mLock);
- if (audio) {
- mNotifyCompleteAudio |= notifyComplete;
- clearAudioFirstAnchorTime_l();
- ++mAudioQueueGeneration;
- ++mAudioDrainGeneration;
- } else {
- mNotifyCompleteVideo |= notifyComplete;
- ++mVideoQueueGeneration;
- ++mVideoDrainGeneration;
- mNextVideoTimeMediaUs = -1;
- }
-
- mMediaClock->clearAnchor();
- mVideoLateByUs = 0;
- mSyncQueues = false;
- }
-
- sp<AMessage> msg = new AMessage(kWhatFlush, this);
- msg->setInt32("audio", static_cast<int32_t>(audio));
- msg->post();
-}
-
-void NuPlayer2::Renderer::signalTimeDiscontinuity() {
-}
-
-void NuPlayer2::Renderer::signalDisableOffloadAudio() {
- (new AMessage(kWhatDisableOffloadAudio, this))->post();
-}
-
-void NuPlayer2::Renderer::signalEnableOffloadAudio() {
- (new AMessage(kWhatEnableOffloadAudio, this))->post();
-}
-
-void NuPlayer2::Renderer::pause() {
- (new AMessage(kWhatPause, this))->post();
-}
-
-void NuPlayer2::Renderer::resume() {
- (new AMessage(kWhatResume, this))->post();
-}
-
-void NuPlayer2::Renderer::setVideoFrameRate(float fps) {
- sp<AMessage> msg = new AMessage(kWhatSetVideoFrameRate, this);
- msg->setFloat("frame-rate", fps);
- msg->post();
-}
-
-// Called on any threads without mLock acquired.
-status_t NuPlayer2::Renderer::getCurrentPosition(int64_t *mediaUs) {
- status_t result = mMediaClock->getMediaTime(ALooper::GetNowUs(), mediaUs);
- if (result == OK) {
- return result;
- }
-
- // MediaClock has not started yet. Try to start it if possible.
- {
- Mutex::Autolock autoLock(mLock);
- if (mAudioFirstAnchorTimeMediaUs == -1) {
- return result;
- }
-
- AudioTimestamp ts;
- status_t res = mAudioSink->getTimestamp(ts);
- if (res != OK) {
- return result;
- }
-
- // AudioSink has rendered some frames.
- int64_t nowUs = ALooper::GetNowUs();
- int64_t nowMediaUs = mAudioSink->getPlayedOutDurationUs(nowUs)
- + mAudioFirstAnchorTimeMediaUs;
- mMediaClock->updateAnchor(nowMediaUs, nowUs, -1);
- }
-
- return mMediaClock->getMediaTime(ALooper::GetNowUs(), mediaUs);
-}
-
-void NuPlayer2::Renderer::clearAudioFirstAnchorTime_l() {
- mAudioFirstAnchorTimeMediaUs = -1;
- mMediaClock->setStartingTimeMedia(-1);
-}
-
-void NuPlayer2::Renderer::setAudioFirstAnchorTimeIfNeeded_l(int64_t mediaUs) {
- if (mAudioFirstAnchorTimeMediaUs == -1) {
- mAudioFirstAnchorTimeMediaUs = mediaUs;
- mMediaClock->setStartingTimeMedia(mediaUs);
- }
-}
-
-// Called on renderer looper.
-void NuPlayer2::Renderer::clearAnchorTime() {
- mMediaClock->clearAnchor();
- mAnchorTimeMediaUs = -1;
- mAnchorNumFramesWritten = -1;
-}
-
-void NuPlayer2::Renderer::setVideoLateByUs(int64_t lateUs) {
- Mutex::Autolock autoLock(mLock);
- mVideoLateByUs = lateUs;
-}
-
-int64_t NuPlayer2::Renderer::getVideoLateByUs() {
- Mutex::Autolock autoLock(mLock);
- return mVideoLateByUs;
-}
-
-status_t NuPlayer2::Renderer::openAudioSink(
- const sp<AMessage> &format,
- bool offloadOnly,
- bool hasVideo,
- uint32_t flags,
- bool *isOffloaded,
- bool isStreaming) {
- sp<AMessage> msg = new AMessage(kWhatOpenAudioSink, this);
- msg->setMessage("format", format);
- msg->setInt32("offload-only", offloadOnly);
- msg->setInt32("has-video", hasVideo);
- msg->setInt32("flags", flags);
- msg->setInt32("isStreaming", isStreaming);
-
- sp<AMessage> response;
- status_t postStatus = msg->postAndAwaitResponse(&response);
-
- int32_t err;
- if (postStatus != OK || response.get() == nullptr || !response->findInt32("err", &err)) {
- err = INVALID_OPERATION;
- } else if (err == OK && isOffloaded != NULL) {
- int32_t offload;
- CHECK(response->findInt32("offload", &offload));
- *isOffloaded = (offload != 0);
- }
- return err;
-}
-
-void NuPlayer2::Renderer::closeAudioSink() {
- sp<AMessage> msg = new AMessage(kWhatCloseAudioSink, this);
-
- sp<AMessage> response;
- msg->postAndAwaitResponse(&response);
-}
-
-void NuPlayer2::Renderer::changeAudioFormat(
- const sp<AMessage> &format,
- bool offloadOnly,
- bool hasVideo,
- uint32_t flags,
- bool isStreaming,
- const sp<AMessage> ¬ify) {
- sp<AMessage> meta = new AMessage;
- meta->setMessage("format", format);
- meta->setInt32("offload-only", offloadOnly);
- meta->setInt32("has-video", hasVideo);
- meta->setInt32("flags", flags);
- meta->setInt32("isStreaming", isStreaming);
-
- sp<AMessage> msg = new AMessage(kWhatChangeAudioFormat, this);
- msg->setInt32("queueGeneration", getQueueGeneration(true /* audio */));
- msg->setMessage("notify", notify);
- msg->setMessage("meta", meta);
- msg->post();
-}
-
-void NuPlayer2::Renderer::onMessageReceived(const sp<AMessage> &msg) {
- switch (msg->what()) {
- case kWhatOpenAudioSink:
- {
- sp<AMessage> format;
- CHECK(msg->findMessage("format", &format));
-
- int32_t offloadOnly;
- CHECK(msg->findInt32("offload-only", &offloadOnly));
-
- int32_t hasVideo;
- CHECK(msg->findInt32("has-video", &hasVideo));
-
- uint32_t flags;
- CHECK(msg->findInt32("flags", (int32_t *)&flags));
-
- uint32_t isStreaming;
- CHECK(msg->findInt32("isStreaming", (int32_t *)&isStreaming));
-
- status_t err = onOpenAudioSink(format, offloadOnly, hasVideo, flags, isStreaming);
-
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
- response->setInt32("offload", offloadingAudio());
-
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
-
- break;
- }
-
- case kWhatCloseAudioSink:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
- onCloseAudioSink();
-
- sp<AMessage> response = new AMessage;
- response->postReply(replyID);
- break;
- }
-
- case kWhatStopAudioSink:
- {
- mAudioSink->stop();
- break;
- }
-
- case kWhatChangeAudioFormat:
- {
- int32_t queueGeneration;
- CHECK(msg->findInt32("queueGeneration", &queueGeneration));
-
- sp<AMessage> notify;
- CHECK(msg->findMessage("notify", ¬ify));
-
- if (offloadingAudio()) {
- ALOGW("changeAudioFormat should NOT be called in offload mode");
- notify->setInt32("err", INVALID_OPERATION);
- notify->post();
- break;
- }
-
- sp<AMessage> meta;
- CHECK(msg->findMessage("meta", &meta));
-
- if (queueGeneration != getQueueGeneration(true /* audio */)
- || mAudioQueue.empty()) {
- onChangeAudioFormat(meta, notify);
- break;
- }
-
- QueueEntry entry;
- entry.mNotifyConsumed = notify;
- entry.mMeta = meta;
-
- Mutex::Autolock autoLock(mLock);
- mAudioQueue.push_back(entry);
- postDrainAudioQueue_l();
-
- break;
- }
-
- case kWhatDrainAudioQueue:
- {
- mDrainAudioQueuePending = false;
-
- int32_t generation;
- CHECK(msg->findInt32("drainGeneration", &generation));
- if (generation != getDrainGeneration(true /* audio */)) {
- break;
- }
-
- if (onDrainAudioQueue()) {
- uint32_t numFramesPlayed;
- CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed),
- (status_t)OK);
-
- // Handle AudioTrack race when start is immediately called after flush.
- uint32_t numFramesPendingPlayout =
- (mNumFramesWritten > numFramesPlayed ?
- mNumFramesWritten - numFramesPlayed : 0);
-
- // This is how long the audio sink will have data to
- // play back.
- int64_t delayUs =
- mAudioSink->msecsPerFrame()
- * numFramesPendingPlayout * 1000ll;
- if (mPlaybackSettings.mSpeed > 1.0f) {
- delayUs /= mPlaybackSettings.mSpeed;
- }
-
- // Let's give it more data after about half that time
- // has elapsed.
- delayUs /= 2;
- // check the buffer size to estimate maximum delay permitted.
- const int64_t maxDrainDelayUs = std::max(
- mAudioSink->getBufferDurationInUs(), (int64_t)500000 /* half second */);
- ALOGD_IF(delayUs > maxDrainDelayUs, "postDrainAudioQueue long delay: %lld > %lld",
- (long long)delayUs, (long long)maxDrainDelayUs);
- Mutex::Autolock autoLock(mLock);
- postDrainAudioQueue_l(delayUs);
- }
- break;
- }
-
- case kWhatDrainVideoQueue:
- {
- int32_t generation;
- CHECK(msg->findInt32("drainGeneration", &generation));
- if (generation != getDrainGeneration(false /* audio */)) {
- break;
- }
-
- mDrainVideoQueuePending = false;
-
- onDrainVideoQueue();
-
- postDrainVideoQueue();
- break;
- }
-
- case kWhatPostDrainVideoQueue:
- {
- int32_t generation;
- CHECK(msg->findInt32("drainGeneration", &generation));
- if (generation != getDrainGeneration(false /* audio */)) {
- break;
- }
-
- mDrainVideoQueuePending = false;
- postDrainVideoQueue();
- break;
- }
-
- case kWhatQueueBuffer:
- {
- onQueueBuffer(msg);
- break;
- }
-
- case kWhatQueueEOS:
- {
- onQueueEOS(msg);
- break;
- }
-
- case kWhatEOS:
- {
- int32_t generation;
- CHECK(msg->findInt32("audioEOSGeneration", &generation));
- if (generation != mAudioEOSGeneration) {
- break;
- }
- status_t finalResult;
- CHECK(msg->findInt32("finalResult", &finalResult));
- notifyEOS(true /* audio */, finalResult);
- break;
- }
-
- case kWhatConfigPlayback:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- AudioPlaybackRate rate;
- readFromAMessage(msg, &rate);
- status_t err = onConfigPlayback(rate);
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatGetPlaybackSettings:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- AudioPlaybackRate rate = AUDIO_PLAYBACK_RATE_DEFAULT;
- status_t err = onGetPlaybackSettings(&rate);
- sp<AMessage> response = new AMessage;
- if (err == OK) {
- writeToAMessage(response, rate);
- }
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatConfigSync:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- AVSyncSettings sync;
- float videoFpsHint;
- readFromAMessage(msg, &sync, &videoFpsHint);
- status_t err = onConfigSync(sync, videoFpsHint);
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatGetSyncSettings:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
- ALOGV("kWhatGetSyncSettings");
- AVSyncSettings sync;
- float videoFps = -1.f;
- status_t err = onGetSyncSettings(&sync, &videoFps);
- sp<AMessage> response = new AMessage;
- if (err == OK) {
- writeToAMessage(response, sync, videoFps);
- }
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatFlush:
- {
- onFlush(msg);
- break;
- }
-
- case kWhatDisableOffloadAudio:
- {
- onDisableOffloadAudio();
- break;
- }
-
- case kWhatEnableOffloadAudio:
- {
- onEnableOffloadAudio();
- break;
- }
-
- case kWhatPause:
- {
- onPause();
- break;
- }
-
- case kWhatResume:
- {
- onResume();
- break;
- }
-
- case kWhatSetVideoFrameRate:
- {
- float fps;
- CHECK(msg->findFloat("frame-rate", &fps));
- onSetVideoFrameRate(fps);
- break;
- }
-
- case kWhatAudioTearDown:
- {
- int32_t reason;
- CHECK(msg->findInt32("reason", &reason));
-
- onAudioTearDown((AudioTearDownReason)reason);
- break;
- }
-
- case kWhatAudioOffloadPauseTimeout:
- {
- int32_t generation;
- CHECK(msg->findInt32("drainGeneration", &generation));
- if (generation != mAudioOffloadPauseTimeoutGeneration) {
- break;
- }
- ALOGV("Audio Offload tear down due to pause timeout.");
- onAudioTearDown(kDueToTimeout);
- mWakeLock->release();
- break;
- }
-
- default:
- TRESPASS();
- break;
- }
-}
-
-void NuPlayer2::Renderer::postDrainAudioQueue_l(int64_t delayUs) {
- if (mDrainAudioQueuePending || mSyncQueues || mUseAudioCallback) {
- return;
- }
-
- if (mAudioQueue.empty()) {
- return;
- }
-
- // FIXME: if paused, wait until AudioTrack stop() is complete before delivering data.
- if (mPaused) {
- const int64_t diffUs = mPauseDrainAudioAllowedUs - ALooper::GetNowUs();
- if (diffUs > delayUs) {
- delayUs = diffUs;
- }
- }
-
- mDrainAudioQueuePending = true;
- sp<AMessage> msg = new AMessage(kWhatDrainAudioQueue, this);
- msg->setInt32("drainGeneration", mAudioDrainGeneration);
- msg->post(delayUs);
-}
-
-void NuPlayer2::Renderer::prepareForMediaRenderingStart_l() {
- mAudioRenderingStartGeneration = mAudioDrainGeneration;
- mVideoRenderingStartGeneration = mVideoDrainGeneration;
- mRenderingDataDelivered = false;
-}
-
-void NuPlayer2::Renderer::notifyIfMediaRenderingStarted_l() {
- if (mVideoRenderingStartGeneration == mVideoDrainGeneration &&
- mAudioRenderingStartGeneration == mAudioDrainGeneration) {
- mRenderingDataDelivered = true;
- if (mPaused) {
- return;
- }
- mVideoRenderingStartGeneration = -1;
- mAudioRenderingStartGeneration = -1;
-
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatMediaRenderingStart);
- notify->post();
- }
-}
-
-// static
-size_t NuPlayer2::Renderer::AudioSinkCallback(
- MediaPlayer2Interface::AudioSink * /* audioSink */,
- void *buffer,
- size_t size,
- void *cookie,
- MediaPlayer2Interface::AudioSink::cb_event_t event) {
- NuPlayer2::Renderer *me = (NuPlayer2::Renderer *)cookie;
-
- switch (event) {
- case MediaPlayer2Interface::AudioSink::CB_EVENT_FILL_BUFFER:
- {
- return me->fillAudioBuffer(buffer, size);
- break;
- }
-
- case MediaPlayer2Interface::AudioSink::CB_EVENT_STREAM_END:
- {
- ALOGV("AudioSink::CB_EVENT_STREAM_END");
- me->notifyEOSCallback();
- break;
- }
-
- case MediaPlayer2Interface::AudioSink::CB_EVENT_TEAR_DOWN:
- {
- ALOGV("AudioSink::CB_EVENT_TEAR_DOWN");
- me->notifyAudioTearDown(kDueToError);
- break;
- }
- }
-
- return 0;
-}
-
-void NuPlayer2::Renderer::notifyEOSCallback() {
- Mutex::Autolock autoLock(mLock);
-
- if (!mUseAudioCallback) {
- return;
- }
-
- notifyEOS_l(true /* audio */, ERROR_END_OF_STREAM);
-}
-
-size_t NuPlayer2::Renderer::fillAudioBuffer(void *buffer, size_t size) {
- Mutex::Autolock autoLock(mLock);
-
- if (!mUseAudioCallback) {
- return 0;
- }
-
- bool hasEOS = false;
-
- size_t sizeCopied = 0;
- bool firstEntry = true;
- QueueEntry *entry; // will be valid after while loop if hasEOS is set.
- while (sizeCopied < size && !mAudioQueue.empty()) {
- entry = &*mAudioQueue.begin();
-
- if (entry->mBuffer == NULL) { // EOS
- hasEOS = true;
- mAudioQueue.erase(mAudioQueue.begin());
- break;
- }
-
- if (firstEntry && entry->mOffset == 0) {
- firstEntry = false;
- int64_t mediaTimeUs;
- CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
- ALOGV("fillAudioBuffer: rendering audio at media time %.2f secs", mediaTimeUs / 1E6);
- setAudioFirstAnchorTimeIfNeeded_l(mediaTimeUs);
- }
-
- size_t copy = entry->mBuffer->size() - entry->mOffset;
- size_t sizeRemaining = size - sizeCopied;
- if (copy > sizeRemaining) {
- copy = sizeRemaining;
- }
-
- memcpy((char *)buffer + sizeCopied,
- entry->mBuffer->data() + entry->mOffset,
- copy);
-
- entry->mOffset += copy;
- if (entry->mOffset == entry->mBuffer->size()) {
- entry->mNotifyConsumed->post();
- mAudioQueue.erase(mAudioQueue.begin());
- entry = NULL;
- }
- sizeCopied += copy;
-
- notifyIfMediaRenderingStarted_l();
- }
-
- if (mAudioFirstAnchorTimeMediaUs >= 0) {
- int64_t nowUs = ALooper::GetNowUs();
- int64_t nowMediaUs =
- mAudioFirstAnchorTimeMediaUs + mAudioSink->getPlayedOutDurationUs(nowUs);
- // we don't know how much data we are queueing for offloaded tracks.
- mMediaClock->updateAnchor(nowMediaUs, nowUs, INT64_MAX);
- }
-
- // for non-offloaded audio, we need to compute the frames written because
- // there is no EVENT_STREAM_END notification. The frames written gives
- // an estimate on the pending played out duration.
- if (!offloadingAudio()) {
- mNumFramesWritten += sizeCopied / mAudioSink->frameSize();
- }
-
- if (hasEOS) {
- (new AMessage(kWhatStopAudioSink, this))->post();
- // As there is currently no EVENT_STREAM_END callback notification for
- // non-offloaded audio tracks, we need to post the EOS ourselves.
- if (!offloadingAudio()) {
- int64_t postEOSDelayUs = 0;
- if (mAudioSink->needsTrailingPadding()) {
- postEOSDelayUs = getPendingAudioPlayoutDurationUs(ALooper::GetNowUs());
- }
- ALOGV("fillAudioBuffer: notifyEOS_l "
- "mNumFramesWritten:%u finalResult:%d postEOSDelay:%lld",
- mNumFramesWritten, entry->mFinalResult, (long long)postEOSDelayUs);
- notifyEOS_l(true /* audio */, entry->mFinalResult, postEOSDelayUs);
- }
- }
- return sizeCopied;
-}
-
-void NuPlayer2::Renderer::drainAudioQueueUntilLastEOS() {
- List<QueueEntry>::iterator it = mAudioQueue.begin(), itEOS = it;
- bool foundEOS = false;
- while (it != mAudioQueue.end()) {
- int32_t eos;
- QueueEntry *entry = &*it++;
- if ((entry->mBuffer == nullptr && entry->mNotifyConsumed == nullptr)
- || (entry->mNotifyConsumed->findInt32("eos", &eos) && eos != 0)) {
- itEOS = it;
- foundEOS = true;
- }
- }
-
- if (foundEOS) {
- // post all replies before EOS and drop the samples
- for (it = mAudioQueue.begin(); it != itEOS; it++) {
- if (it->mBuffer == nullptr) {
- if (it->mNotifyConsumed == nullptr) {
- // delay doesn't matter as we don't even have an AudioTrack
- notifyEOS(true /* audio */, it->mFinalResult);
- } else {
- // TAG for re-opening audio sink.
- onChangeAudioFormat(it->mMeta, it->mNotifyConsumed);
- }
- } else {
- it->mNotifyConsumed->post();
- }
- }
- mAudioQueue.erase(mAudioQueue.begin(), itEOS);
- }
-}
-
-bool NuPlayer2::Renderer::onDrainAudioQueue() {
- // do not drain audio during teardown as queued buffers may be invalid.
- if (mAudioTornDown) {
- return false;
- }
- // TODO: This call to getPosition checks if AudioTrack has been created
- // in AudioSink before draining audio. If AudioTrack doesn't exist, then
- // CHECKs on getPosition will fail.
- // We still need to figure out why AudioTrack is not created when
- // this function is called. One possible reason could be leftover
- // audio. Another possible place is to check whether decoder
- // has received INFO_FORMAT_CHANGED as the first buffer since
- // AudioSink is opened there, and possible interactions with flush
- // immediately after start. Investigate error message
- // "vorbis_dsp_synthesis returned -135", along with RTSP.
- uint32_t numFramesPlayed;
- if (mAudioSink->getPosition(&numFramesPlayed) != OK) {
- // When getPosition fails, renderer will not reschedule the draining
- // unless new samples are queued.
- // If we have pending EOS (or "eos" marker for discontinuities), we need
- // to post these now as NuPlayer2Decoder might be waiting for it.
- drainAudioQueueUntilLastEOS();
-
- ALOGW("onDrainAudioQueue(): audio sink is not ready");
- return false;
- }
-
-#if 0
- ssize_t numFramesAvailableToWrite =
- mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed);
-
- if (numFramesAvailableToWrite == mAudioSink->frameCount()) {
- ALOGI("audio sink underrun");
- } else {
- ALOGV("audio queue has %d frames left to play",
- mAudioSink->frameCount() - numFramesAvailableToWrite);
- }
-#endif
-
- uint32_t prevFramesWritten = mNumFramesWritten;
- while (!mAudioQueue.empty()) {
- QueueEntry *entry = &*mAudioQueue.begin();
-
- if (entry->mBuffer == NULL) {
- if (entry->mNotifyConsumed != nullptr) {
- // TAG for re-open audio sink.
- onChangeAudioFormat(entry->mMeta, entry->mNotifyConsumed);
- mAudioQueue.erase(mAudioQueue.begin());
- continue;
- }
-
- // EOS
- if (mPaused) {
- // Do not notify EOS when paused.
- // This is needed to avoid switch to next clip while in pause.
- ALOGV("onDrainAudioQueue(): Do not notify EOS when paused");
- return false;
- }
-
- int64_t postEOSDelayUs = 0;
- if (mAudioSink->needsTrailingPadding()) {
- postEOSDelayUs = getPendingAudioPlayoutDurationUs(ALooper::GetNowUs());
- }
- notifyEOS(true /* audio */, entry->mFinalResult, postEOSDelayUs);
- mLastAudioMediaTimeUs = getDurationUsIfPlayedAtSampleRate(mNumFramesWritten);
-
- mAudioQueue.erase(mAudioQueue.begin());
- entry = NULL;
- if (mAudioSink->needsTrailingPadding()) {
- // If we're not in gapless playback (i.e. through setNextPlayer), we
- // need to stop the track here, because that will play out the last
- // little bit at the end of the file. Otherwise short files won't play.
- mAudioSink->stop();
- mNumFramesWritten = 0;
- }
- return false;
- }
-
- mLastAudioBufferDrained = entry->mBufferOrdinal;
-
- // ignore 0-sized buffer which could be EOS marker with no data
- if (entry->mOffset == 0 && entry->mBuffer->size() > 0) {
- int64_t mediaTimeUs;
- CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
- ALOGV("onDrainAudioQueue: rendering audio at media time %.2f secs",
- mediaTimeUs / 1E6);
- onNewAudioMediaTime(mediaTimeUs);
- }
-
- size_t copy = entry->mBuffer->size() - entry->mOffset;
-
- ssize_t written = mAudioSink->write(entry->mBuffer->data() + entry->mOffset,
- copy, false /* blocking */);
- if (written < 0) {
- // An error in AudioSink write. Perhaps the AudioSink was not properly opened.
- if (written == WOULD_BLOCK) {
- ALOGV("AudioSink write would block when writing %zu bytes", copy);
- } else {
- ALOGE("AudioSink write error(%zd) when writing %zu bytes", written, copy);
- // This can only happen when AudioSink was opened with doNotReconnect flag set to
- // true, in which case the NuPlayer2 will handle the reconnect.
- notifyAudioTearDown(kDueToError);
- }
- break;
- }
-
- entry->mOffset += written;
- size_t remainder = entry->mBuffer->size() - entry->mOffset;
- if ((ssize_t)remainder < mAudioSink->frameSize()) {
- if (remainder > 0) {
- ALOGW("Corrupted audio buffer has fractional frames, discarding %zu bytes.",
- remainder);
- entry->mOffset += remainder;
- copy -= remainder;
- }
-
- entry->mNotifyConsumed->post();
- mAudioQueue.erase(mAudioQueue.begin());
-
- entry = NULL;
- }
-
- size_t copiedFrames = written / mAudioSink->frameSize();
- mNumFramesWritten += copiedFrames;
-
- {
- Mutex::Autolock autoLock(mLock);
- int64_t maxTimeMedia;
- maxTimeMedia =
- mAnchorTimeMediaUs +
- (int64_t)(max((long long)mNumFramesWritten - mAnchorNumFramesWritten, 0LL)
- * 1000LL * mAudioSink->msecsPerFrame());
- mMediaClock->updateMaxTimeMedia(maxTimeMedia);
-
- notifyIfMediaRenderingStarted_l();
- }
-
- if (written != (ssize_t)copy) {
- // A short count was received from AudioSink::write()
- //
- // AudioSink write is called in non-blocking mode.
- // It may return with a short count when:
- //
- // 1) Size to be copied is not a multiple of the frame size. Fractional frames are
- // discarded.
- // 2) The data to be copied exceeds the available buffer in AudioSink.
- // 3) An error occurs and data has been partially copied to the buffer in AudioSink.
- // 4) AudioSink is an AudioCache for data retrieval, and the AudioCache is exceeded.
-
- // (Case 1)
- // Must be a multiple of the frame size. If it is not a multiple of a frame size, it
- // needs to fail, as we should not carry over fractional frames between calls.
- CHECK_EQ(copy % mAudioSink->frameSize(), 0u);
-
- // (Case 2, 3, 4)
- // Return early to the caller.
- // Beware of calling immediately again as this may busy-loop if you are not careful.
- ALOGV("AudioSink write short frame count %zd < %zu", written, copy);
- break;
- }
- }
-
- // calculate whether we need to reschedule another write.
- bool reschedule = !mAudioQueue.empty()
- && (!mPaused
- || prevFramesWritten != mNumFramesWritten); // permit pause to fill buffers
- //ALOGD("reschedule:%d empty:%d mPaused:%d prevFramesWritten:%u mNumFramesWritten:%u",
- // reschedule, mAudioQueue.empty(), mPaused, prevFramesWritten, mNumFramesWritten);
- return reschedule;
-}
-
-int64_t NuPlayer2::Renderer::getDurationUsIfPlayedAtSampleRate(uint32_t numFrames) {
- int32_t sampleRate = offloadingAudio() ?
- mCurrentOffloadInfo.sample_rate : mCurrentPcmInfo.mSampleRate;
- if (sampleRate == 0) {
- ALOGE("sampleRate is 0 in %s mode", offloadingAudio() ? "offload" : "non-offload");
- return 0;
- }
- return (int64_t)(numFrames * 1000000LL / sampleRate);
-}
-
-// Calculate duration of pending samples if played at normal rate (i.e., 1.0).
-int64_t NuPlayer2::Renderer::getPendingAudioPlayoutDurationUs(int64_t nowUs) {
- int64_t writtenAudioDurationUs = getDurationUsIfPlayedAtSampleRate(mNumFramesWritten);
- if (mUseVirtualAudioSink) {
- int64_t nowUs = ALooper::GetNowUs();
- int64_t mediaUs;
- if (mMediaClock->getMediaTime(nowUs, &mediaUs) != OK) {
- return 0LL;
- } else {
- return writtenAudioDurationUs - (mediaUs - mAudioFirstAnchorTimeMediaUs);
- }
- }
-
- const int64_t audioSinkPlayedUs = mAudioSink->getPlayedOutDurationUs(nowUs);
- int64_t pendingUs = writtenAudioDurationUs - audioSinkPlayedUs;
- if (pendingUs < 0) {
- // This shouldn't happen unless the timestamp is stale.
- ALOGW("%s: pendingUs %lld < 0, clamping to zero, potential resume after pause "
- "writtenAudioDurationUs: %lld, audioSinkPlayedUs: %lld",
- __func__, (long long)pendingUs,
- (long long)writtenAudioDurationUs, (long long)audioSinkPlayedUs);
- pendingUs = 0;
- }
- return pendingUs;
-}
-
-int64_t NuPlayer2::Renderer::getRealTimeUs(int64_t mediaTimeUs, int64_t nowUs) {
- int64_t realUs;
- if (mMediaClock->getRealTimeFor(mediaTimeUs, &realUs) != OK) {
- // If failed to get current position, e.g. due to audio clock is
- // not ready, then just play out video immediately without delay.
- return nowUs;
- }
- return realUs;
-}
-
-void NuPlayer2::Renderer::onNewAudioMediaTime(int64_t mediaTimeUs) {
- Mutex::Autolock autoLock(mLock);
- // TRICKY: vorbis decoder generates multiple frames with the same
- // timestamp, so only update on the first frame with a given timestamp
- if (mediaTimeUs == mAnchorTimeMediaUs) {
- return;
- }
- setAudioFirstAnchorTimeIfNeeded_l(mediaTimeUs);
-
- // mNextAudioClockUpdateTimeUs is -1 if we're waiting for audio sink to start
- if (mNextAudioClockUpdateTimeUs == -1) {
- AudioTimestamp ts;
- if (mAudioSink->getTimestamp(ts) == OK && ts.mPosition > 0) {
- mNextAudioClockUpdateTimeUs = 0; // start our clock updates
- }
- }
- int64_t nowUs = ALooper::GetNowUs();
- if (mNextAudioClockUpdateTimeUs >= 0) {
- if (nowUs >= mNextAudioClockUpdateTimeUs) {
- int64_t nowMediaUs = mediaTimeUs - getPendingAudioPlayoutDurationUs(nowUs);
- mMediaClock->updateAnchor(nowMediaUs, nowUs, mediaTimeUs);
- mUseVirtualAudioSink = false;
- mNextAudioClockUpdateTimeUs = nowUs + kMinimumAudioClockUpdatePeriodUs;
- }
- } else {
- int64_t unused;
- if ((mMediaClock->getMediaTime(nowUs, &unused) != OK)
- && (getDurationUsIfPlayedAtSampleRate(mNumFramesWritten)
- > kMaxAllowedAudioSinkDelayUs)) {
- // Enough data has been sent to AudioSink, but AudioSink has not rendered
- // any data yet. Something is wrong with AudioSink, e.g., the device is not
- // connected to audio out.
- // Switch to system clock. This essentially creates a virtual AudioSink with
- // initial latenty of getDurationUsIfPlayedAtSampleRate(mNumFramesWritten).
- // This virtual AudioSink renders audio data starting from the very first sample
- // and it's paced by system clock.
- ALOGW("AudioSink stuck. ARE YOU CONNECTED TO AUDIO OUT? Switching to system clock.");
- mMediaClock->updateAnchor(mAudioFirstAnchorTimeMediaUs, nowUs, mediaTimeUs);
- mUseVirtualAudioSink = true;
- }
- }
- mAnchorNumFramesWritten = mNumFramesWritten;
- mAnchorTimeMediaUs = mediaTimeUs;
-}
-
-// Called without mLock acquired.
-void NuPlayer2::Renderer::postDrainVideoQueue() {
- if (mDrainVideoQueuePending
- || getSyncQueues()
- || (mPaused && mVideoSampleReceived)) {
- return;
- }
-
- if (mVideoQueue.empty()) {
- return;
- }
-
- QueueEntry &entry = *mVideoQueue.begin();
-
- sp<AMessage> msg = new AMessage(kWhatDrainVideoQueue, this);
- msg->setInt32("drainGeneration", getDrainGeneration(false /* audio */));
-
- if (entry.mBuffer == NULL) {
- // EOS doesn't carry a timestamp.
- msg->post();
- mDrainVideoQueuePending = true;
- return;
- }
-
- int64_t nowUs = ALooper::GetNowUs();
- if (mFlags & FLAG_REAL_TIME) {
- int64_t realTimeUs;
- CHECK(entry.mBuffer->meta()->findInt64("timeUs", &realTimeUs));
-
- realTimeUs = mVideoScheduler->schedule(realTimeUs * 1000) / 1000;
-
- int64_t twoVsyncsUs = 2 * (mVideoScheduler->getVsyncPeriod() / 1000);
-
- int64_t delayUs = realTimeUs - nowUs;
-
- ALOGW_IF(delayUs > 500000, "unusually high delayUs: %lld", (long long)delayUs);
- // post 2 display refreshes before rendering is due
- msg->post(delayUs > twoVsyncsUs ? delayUs - twoVsyncsUs : 0);
-
- mDrainVideoQueuePending = true;
- return;
- }
-
- int64_t mediaTimeUs;
- CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
-
- {
- Mutex::Autolock autoLock(mLock);
- if (mAnchorTimeMediaUs < 0) {
- mMediaClock->updateAnchor(mediaTimeUs, nowUs, mediaTimeUs);
- mAnchorTimeMediaUs = mediaTimeUs;
- }
- }
- mNextVideoTimeMediaUs = mediaTimeUs;
- if (!mHasAudio) {
- // smooth out videos >= 10fps
- mMediaClock->updateMaxTimeMedia(mediaTimeUs + kDefaultVideoFrameIntervalUs);
- }
-
- if (!mVideoSampleReceived || mediaTimeUs < mAudioFirstAnchorTimeMediaUs) {
- msg->post();
- } else {
- int64_t twoVsyncsUs = 2 * (mVideoScheduler->getVsyncPeriod() / 1000);
-
- // post 2 display refreshes before rendering is due
- mMediaClock->addTimer(msg, mediaTimeUs, -twoVsyncsUs);
- }
-
- mDrainVideoQueuePending = true;
-}
-
-void NuPlayer2::Renderer::onDrainVideoQueue() {
- if (mVideoQueue.empty()) {
- return;
- }
-
- QueueEntry *entry = &*mVideoQueue.begin();
-
- if (entry->mBuffer == NULL) {
- // EOS
-
- notifyEOS(false /* audio */, entry->mFinalResult);
-
- mVideoQueue.erase(mVideoQueue.begin());
- entry = NULL;
-
- setVideoLateByUs(0);
- return;
- }
-
- int64_t nowUs = ALooper::GetNowUs();
- int64_t realTimeUs;
- int64_t mediaTimeUs = -1;
- if (mFlags & FLAG_REAL_TIME) {
- CHECK(entry->mBuffer->meta()->findInt64("timeUs", &realTimeUs));
- } else {
- CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
-
- realTimeUs = getRealTimeUs(mediaTimeUs, nowUs);
- }
- realTimeUs = mVideoScheduler->schedule(realTimeUs * 1000) / 1000;
-
- bool tooLate = false;
-
- if (!mPaused) {
- setVideoLateByUs(nowUs - realTimeUs);
- tooLate = (mVideoLateByUs > 40000);
-
- if (tooLate) {
- ALOGV("video late by %lld us (%.2f secs)",
- (long long)mVideoLateByUs, mVideoLateByUs / 1E6);
- } else {
- int64_t mediaUs = 0;
- mMediaClock->getMediaTime(realTimeUs, &mediaUs);
- ALOGV("rendering video at media time %.2f secs",
- (mFlags & FLAG_REAL_TIME ? realTimeUs :
- mediaUs) / 1E6);
-
- if (!(mFlags & FLAG_REAL_TIME)
- && mLastAudioMediaTimeUs != -1
- && mediaTimeUs > mLastAudioMediaTimeUs) {
- // If audio ends before video, video continues to drive media clock.
- // Also smooth out videos >= 10fps.
- mMediaClock->updateMaxTimeMedia(mediaTimeUs + kDefaultVideoFrameIntervalUs);
- }
- }
- } else {
- setVideoLateByUs(0);
- if (!mVideoSampleReceived && !mHasAudio) {
- // This will ensure that the first frame after a flush won't be used as anchor
- // when renderer is in paused state, because resume can happen any time after seek.
- clearAnchorTime();
- }
- }
-
- // Always render the first video frame while keeping stats on A/V sync.
- if (!mVideoSampleReceived) {
- realTimeUs = nowUs;
- tooLate = false;
- }
-
- entry->mNotifyConsumed->setInt64("timestampNs", realTimeUs * 1000LL);
- entry->mNotifyConsumed->setInt32("render", !tooLate);
- entry->mNotifyConsumed->post();
- mVideoQueue.erase(mVideoQueue.begin());
- entry = NULL;
-
- mVideoSampleReceived = true;
-
- if (!mPaused) {
- if (!mVideoRenderingStarted) {
- mVideoRenderingStarted = true;
- notifyVideoRenderingStart();
- }
- Mutex::Autolock autoLock(mLock);
- notifyIfMediaRenderingStarted_l();
- }
-}
-
-void NuPlayer2::Renderer::notifyVideoRenderingStart() {
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatVideoRenderingStart);
- notify->post();
-}
-
-void NuPlayer2::Renderer::notifyEOS(bool audio, status_t finalResult, int64_t delayUs) {
- Mutex::Autolock autoLock(mLock);
- notifyEOS_l(audio, finalResult, delayUs);
-}
-
-void NuPlayer2::Renderer::notifyEOS_l(bool audio, status_t finalResult, int64_t delayUs) {
- if (audio && delayUs > 0) {
- sp<AMessage> msg = new AMessage(kWhatEOS, this);
- msg->setInt32("audioEOSGeneration", mAudioEOSGeneration);
- msg->setInt32("finalResult", finalResult);
- msg->post(delayUs);
- return;
- }
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatEOS);
- notify->setInt32("audio", static_cast<int32_t>(audio));
- notify->setInt32("finalResult", finalResult);
- notify->post(delayUs);
-
- if (audio) {
- // Video might outlive audio. Clear anchor to enable video only case.
- mAnchorTimeMediaUs = -1;
- mHasAudio = false;
- if (mNextVideoTimeMediaUs >= 0) {
- int64_t mediaUs = 0;
- int64_t nowUs = ALooper::GetNowUs();
- status_t result = mMediaClock->getMediaTime(nowUs, &mediaUs);
- if (result == OK) {
- if (mNextVideoTimeMediaUs > mediaUs) {
- mMediaClock->updateMaxTimeMedia(mNextVideoTimeMediaUs);
- }
- } else {
- mMediaClock->updateAnchor(
- mNextVideoTimeMediaUs, nowUs,
- mNextVideoTimeMediaUs + kDefaultVideoFrameIntervalUs);
- }
- }
- }
-}
-
-void NuPlayer2::Renderer::notifyAudioTearDown(AudioTearDownReason reason) {
- sp<AMessage> msg = new AMessage(kWhatAudioTearDown, this);
- msg->setInt32("reason", reason);
- msg->post();
-}
-
-void NuPlayer2::Renderer::onQueueBuffer(const sp<AMessage> &msg) {
- int32_t audio;
- CHECK(msg->findInt32("audio", &audio));
-
- if (dropBufferIfStale(audio, msg)) {
- return;
- }
-
- if (audio) {
- mHasAudio = true;
- } else {
- mHasVideo = true;
- }
-
- if (mHasVideo) {
- if (mVideoScheduler == NULL) {
- mVideoScheduler = new VideoFrameScheduler2();
- mVideoScheduler->init();
- }
- }
-
- sp<RefBase> obj;
- CHECK(msg->findObject("buffer", &obj));
- sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
-
- sp<AMessage> notifyConsumed;
- CHECK(msg->findMessage("notifyConsumed", ¬ifyConsumed));
-
- QueueEntry entry;
- entry.mBuffer = buffer;
- entry.mNotifyConsumed = notifyConsumed;
- entry.mOffset = 0;
- entry.mFinalResult = OK;
- entry.mBufferOrdinal = ++mTotalBuffersQueued;
-
- if (audio) {
- Mutex::Autolock autoLock(mLock);
- mAudioQueue.push_back(entry);
- postDrainAudioQueue_l();
- } else {
- mVideoQueue.push_back(entry);
- postDrainVideoQueue();
- }
-
- Mutex::Autolock autoLock(mLock);
- if (!mSyncQueues || mAudioQueue.empty() || mVideoQueue.empty()) {
- return;
- }
-
- sp<MediaCodecBuffer> firstAudioBuffer = (*mAudioQueue.begin()).mBuffer;
- sp<MediaCodecBuffer> firstVideoBuffer = (*mVideoQueue.begin()).mBuffer;
-
- if (firstAudioBuffer == NULL || firstVideoBuffer == NULL) {
- // EOS signalled on either queue.
- syncQueuesDone_l();
- return;
- }
-
- int64_t firstAudioTimeUs;
- int64_t firstVideoTimeUs;
- CHECK(firstAudioBuffer->meta()
- ->findInt64("timeUs", &firstAudioTimeUs));
- CHECK(firstVideoBuffer->meta()
- ->findInt64("timeUs", &firstVideoTimeUs));
-
- int64_t diff = firstVideoTimeUs - firstAudioTimeUs;
-
- ALOGV("queueDiff = %.2f secs", diff / 1E6);
-
- if (diff > 100000LL) {
- // Audio data starts More than 0.1 secs before video.
- // Drop some audio.
-
- (*mAudioQueue.begin()).mNotifyConsumed->post();
- mAudioQueue.erase(mAudioQueue.begin());
- return;
- }
-
- syncQueuesDone_l();
-}
-
-void NuPlayer2::Renderer::syncQueuesDone_l() {
- if (!mSyncQueues) {
- return;
- }
-
- mSyncQueues = false;
-
- if (!mAudioQueue.empty()) {
- postDrainAudioQueue_l();
- }
-
- if (!mVideoQueue.empty()) {
- mLock.unlock();
- postDrainVideoQueue();
- mLock.lock();
- }
-}
-
-void NuPlayer2::Renderer::onQueueEOS(const sp<AMessage> &msg) {
- int32_t audio;
- CHECK(msg->findInt32("audio", &audio));
-
- if (dropBufferIfStale(audio, msg)) {
- return;
- }
-
- int32_t finalResult;
- CHECK(msg->findInt32("finalResult", &finalResult));
-
- QueueEntry entry;
- entry.mOffset = 0;
- entry.mFinalResult = finalResult;
-
- if (audio) {
- Mutex::Autolock autoLock(mLock);
- if (mAudioQueue.empty() && mSyncQueues) {
- syncQueuesDone_l();
- }
- mAudioQueue.push_back(entry);
- postDrainAudioQueue_l();
- } else {
- if (mVideoQueue.empty() && getSyncQueues()) {
- Mutex::Autolock autoLock(mLock);
- syncQueuesDone_l();
- }
- mVideoQueue.push_back(entry);
- postDrainVideoQueue();
- }
-}
-
-void NuPlayer2::Renderer::onFlush(const sp<AMessage> &msg) {
- int32_t audio, notifyComplete;
- CHECK(msg->findInt32("audio", &audio));
-
- {
- Mutex::Autolock autoLock(mLock);
- if (audio) {
- notifyComplete = mNotifyCompleteAudio;
- mNotifyCompleteAudio = false;
- mLastAudioMediaTimeUs = -1;
-
- mHasAudio = false;
- if (mNextVideoTimeMediaUs >= 0) {
- int64_t nowUs = ALooper::GetNowUs();
- mMediaClock->updateAnchor(
- mNextVideoTimeMediaUs, nowUs,
- mNextVideoTimeMediaUs + kDefaultVideoFrameIntervalUs);
- }
- } else {
- notifyComplete = mNotifyCompleteVideo;
- mNotifyCompleteVideo = false;
- mVideoRenderingStarted = false;
- }
-
- // If we're currently syncing the queues, i.e. dropping audio while
- // aligning the first audio/video buffer times and only one of the
- // two queues has data, we may starve that queue by not requesting
- // more buffers from the decoder. If the other source then encounters
- // a discontinuity that leads to flushing, we'll never find the
- // corresponding discontinuity on the other queue.
- // Therefore we'll stop syncing the queues if at least one of them
- // is flushed.
- syncQueuesDone_l();
- }
- clearAnchorTime();
-
- ALOGV("flushing %s", audio ? "audio" : "video");
- if (audio) {
- {
- Mutex::Autolock autoLock(mLock);
- flushQueue(&mAudioQueue);
-
- ++mAudioDrainGeneration;
- ++mAudioEOSGeneration;
- prepareForMediaRenderingStart_l();
-
- // the frame count will be reset after flush.
- clearAudioFirstAnchorTime_l();
- }
-
- mDrainAudioQueuePending = false;
-
- if (offloadingAudio()) {
- mAudioSink->pause();
- mAudioSink->flush();
- if (!mPaused) {
- mAudioSink->start();
- }
- } else {
- mAudioSink->pause();
- mAudioSink->flush();
- // Call stop() to signal to the AudioSink to completely fill the
- // internal buffer before resuming playback.
- // FIXME: this is ignored after flush().
- mAudioSink->stop();
- if (mPaused) {
- // Race condition: if renderer is paused and audio sink is stopped,
- // we need to make sure that the audio track buffer fully drains
- // before delivering data.
- // FIXME: remove this if we can detect if stop() is complete.
- const int delayUs = 2 * 50 * 1000; // (2 full mixer thread cycles at 50ms)
- mPauseDrainAudioAllowedUs = ALooper::GetNowUs() + delayUs;
- } else {
- mAudioSink->start();
- }
- mNumFramesWritten = 0;
- }
- mNextAudioClockUpdateTimeUs = -1;
- } else {
- flushQueue(&mVideoQueue);
-
- mDrainVideoQueuePending = false;
-
- if (mVideoScheduler != NULL) {
- mVideoScheduler->restart();
- }
-
- Mutex::Autolock autoLock(mLock);
- ++mVideoDrainGeneration;
- prepareForMediaRenderingStart_l();
- }
-
- mVideoSampleReceived = false;
-
- if (notifyComplete) {
- notifyFlushComplete(audio);
- }
-}
-
-void NuPlayer2::Renderer::flushQueue(List<QueueEntry> *queue) {
- while (!queue->empty()) {
- QueueEntry *entry = &*queue->begin();
-
- if (entry->mBuffer != NULL) {
- entry->mNotifyConsumed->post();
- } else if (entry->mNotifyConsumed != nullptr) {
- // Is it needed to open audio sink now?
- onChangeAudioFormat(entry->mMeta, entry->mNotifyConsumed);
- }
-
- queue->erase(queue->begin());
- entry = NULL;
- }
-}
-
-void NuPlayer2::Renderer::notifyFlushComplete(bool audio) {
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatFlushComplete);
- notify->setInt32("audio", static_cast<int32_t>(audio));
- notify->post();
-}
-
-bool NuPlayer2::Renderer::dropBufferIfStale(
- bool audio, const sp<AMessage> &msg) {
- int32_t queueGeneration;
- CHECK(msg->findInt32("queueGeneration", &queueGeneration));
-
- if (queueGeneration == getQueueGeneration(audio)) {
- return false;
- }
-
- sp<AMessage> notifyConsumed;
- if (msg->findMessage("notifyConsumed", ¬ifyConsumed)) {
- notifyConsumed->post();
- }
-
- return true;
-}
-
-void NuPlayer2::Renderer::onAudioSinkChanged() {
- if (offloadingAudio()) {
- return;
- }
- CHECK(!mDrainAudioQueuePending);
- mNumFramesWritten = 0;
- mAnchorNumFramesWritten = -1;
- uint32_t written;
- if (mAudioSink->getFramesWritten(&written) == OK) {
- mNumFramesWritten = written;
- }
-}
-
-void NuPlayer2::Renderer::onDisableOffloadAudio() {
- Mutex::Autolock autoLock(mLock);
- mFlags &= ~FLAG_OFFLOAD_AUDIO;
- ++mAudioDrainGeneration;
- if (mAudioRenderingStartGeneration != -1) {
- prepareForMediaRenderingStart_l();
- }
-}
-
-void NuPlayer2::Renderer::onEnableOffloadAudio() {
- Mutex::Autolock autoLock(mLock);
- mFlags |= FLAG_OFFLOAD_AUDIO;
- ++mAudioDrainGeneration;
- if (mAudioRenderingStartGeneration != -1) {
- prepareForMediaRenderingStart_l();
- }
-}
-
-void NuPlayer2::Renderer::onPause() {
- if (mPaused) {
- return;
- }
-
- {
- Mutex::Autolock autoLock(mLock);
- // we do not increment audio drain generation so that we fill audio buffer during pause.
- ++mVideoDrainGeneration;
- prepareForMediaRenderingStart_l();
- mPaused = true;
- mMediaClock->setPlaybackRate(0.0);
- }
-
- mDrainAudioQueuePending = false;
- mDrainVideoQueuePending = false;
-
- // Note: audio data may not have been decoded, and the AudioSink may not be opened.
- mAudioSink->pause();
- startAudioOffloadPauseTimeout();
-
- ALOGV("now paused audio queue has %zu entries, video has %zu entries",
- mAudioQueue.size(), mVideoQueue.size());
-}
-
-void NuPlayer2::Renderer::onResume() {
- if (!mPaused) {
- return;
- }
-
- // Note: audio data may not have been decoded, and the AudioSink may not be opened.
- cancelAudioOffloadPauseTimeout();
- if (mAudioSink->ready()) {
- status_t err = mAudioSink->start();
- if (err != OK) {
- ALOGE("cannot start AudioSink err %d", err);
- notifyAudioTearDown(kDueToError);
- }
- }
-
- {
- Mutex::Autolock autoLock(mLock);
- mPaused = false;
- // rendering started message may have been delayed if we were paused.
- if (mRenderingDataDelivered) {
- notifyIfMediaRenderingStarted_l();
- }
- // configure audiosink as we did not do it when pausing
- if (mAudioSink != NULL && mAudioSink->ready()) {
- mAudioSink->setPlaybackRate(mPlaybackSettings);
- }
-
- mMediaClock->setPlaybackRate(mPlaybackSettings.mSpeed);
-
- if (!mAudioQueue.empty()) {
- postDrainAudioQueue_l();
- }
- }
-
- if (!mVideoQueue.empty()) {
- postDrainVideoQueue();
- }
-}
-
-void NuPlayer2::Renderer::onSetVideoFrameRate(float fps) {
- if (mVideoScheduler == NULL) {
- mVideoScheduler = new VideoFrameScheduler2();
- }
- mVideoScheduler->init(fps);
-}
-
-int32_t NuPlayer2::Renderer::getQueueGeneration(bool audio) {
- Mutex::Autolock autoLock(mLock);
- return (audio ? mAudioQueueGeneration : mVideoQueueGeneration);
-}
-
-int32_t NuPlayer2::Renderer::getDrainGeneration(bool audio) {
- Mutex::Autolock autoLock(mLock);
- return (audio ? mAudioDrainGeneration : mVideoDrainGeneration);
-}
-
-bool NuPlayer2::Renderer::getSyncQueues() {
- Mutex::Autolock autoLock(mLock);
- return mSyncQueues;
-}
-
-void NuPlayer2::Renderer::onAudioTearDown(AudioTearDownReason reason) {
- if (mAudioTornDown) {
- return;
- }
- mAudioTornDown = true;
-
- int64_t currentPositionUs;
- sp<AMessage> notify = mNotify->dup();
- if (getCurrentPosition(¤tPositionUs) == OK) {
- notify->setInt64("positionUs", currentPositionUs);
- }
-
- mAudioSink->stop();
- mAudioSink->flush();
-
- notify->setInt32("what", kWhatAudioTearDown);
- notify->setInt32("reason", reason);
- notify->post();
-}
-
-void NuPlayer2::Renderer::startAudioOffloadPauseTimeout() {
- if (offloadingAudio()) {
- mWakeLock->acquire();
- sp<AMessage> msg = new AMessage(kWhatAudioOffloadPauseTimeout, this);
- msg->setInt32("drainGeneration", mAudioOffloadPauseTimeoutGeneration);
- msg->post(kOffloadPauseMaxUs);
- }
-}
-
-void NuPlayer2::Renderer::cancelAudioOffloadPauseTimeout() {
- // We may have called startAudioOffloadPauseTimeout() without
- // the AudioSink open and with offloadingAudio enabled.
- //
- // When we cancel, it may be that offloadingAudio is subsequently disabled, so regardless
- // we always release the wakelock and increment the pause timeout generation.
- //
- // Note: The acquired wakelock prevents the device from suspending
- // immediately after offload pause (in case a resume happens shortly thereafter).
- mWakeLock->release(true);
- ++mAudioOffloadPauseTimeoutGeneration;
-}
-
-status_t NuPlayer2::Renderer::onOpenAudioSink(
- const sp<AMessage> &format,
- bool offloadOnly,
- bool hasVideo,
- uint32_t flags,
- bool isStreaming) {
- ALOGV("openAudioSink: offloadOnly(%d) offloadingAudio(%d)",
- offloadOnly, offloadingAudio());
-
- bool audioSinkChanged = false;
-
- int32_t numChannels;
- CHECK(format->findInt32("channel-count", &numChannels));
-
- int32_t channelMask;
- if (!format->findInt32("channel-mask", &channelMask)) {
- // signal to the AudioSink to derive the mask from count.
- channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER;
- }
-
- int32_t sampleRate;
- CHECK(format->findInt32("sample-rate", &sampleRate));
-
- // read pcm encoding from MediaCodec output format, if available
- int32_t pcmEncoding;
- audio_format_t audioFormat =
- format->findInt32(KEY_PCM_ENCODING, &pcmEncoding) ?
- audioFormatFromEncoding(pcmEncoding) : AUDIO_FORMAT_PCM_16_BIT;
-
- if (offloadingAudio()) {
- AString mime;
- CHECK(format->findString("mime", &mime));
- status_t err = mapMimeToAudioFormat(audioFormat, mime.c_str());
-
- if (err != OK) {
- ALOGE("Couldn't map mime \"%s\" to a valid "
- "audio_format", mime.c_str());
- onDisableOffloadAudio();
- } else {
- ALOGV("Mime \"%s\" mapped to audio_format 0x%x",
- mime.c_str(), audioFormat);
-
- int avgBitRate = -1;
- format->findInt32("bitrate", &avgBitRate);
-
- int32_t aacProfile = -1;
- if (audioFormat == AUDIO_FORMAT_AAC
- && format->findInt32("aac-profile", &aacProfile)) {
- // Redefine AAC format as per aac profile
- mapAACProfileToAudioFormat(
- audioFormat,
- aacProfile);
- }
-
- audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER;
- offloadInfo.duration_us = -1;
- format->findInt64(
- "durationUs", &offloadInfo.duration_us);
- offloadInfo.sample_rate = sampleRate;
- offloadInfo.channel_mask = channelMask;
- offloadInfo.format = audioFormat;
- offloadInfo.stream_type = AUDIO_STREAM_MUSIC;
- offloadInfo.bit_rate = avgBitRate;
- offloadInfo.has_video = hasVideo;
- offloadInfo.is_streaming = isStreaming;
-
- if (memcmp(&mCurrentOffloadInfo, &offloadInfo, sizeof(offloadInfo)) == 0) {
- ALOGV("openAudioSink: no change in offload mode");
- // no change from previous configuration, everything ok.
- return OK;
- }
- mCurrentPcmInfo = AUDIO_PCMINFO_INITIALIZER;
-
- ALOGV("openAudioSink: try to open AudioSink in offload mode");
- uint32_t offloadFlags = flags;
- offloadFlags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
- offloadFlags &= ~AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
- audioSinkChanged = true;
- mAudioSink->close();
-
- err = mAudioSink->open(
- sampleRate,
- numChannels,
- (audio_channel_mask_t)channelMask,
- audioFormat,
- &NuPlayer2::Renderer::AudioSinkCallback,
- this,
- (audio_output_flags_t)offloadFlags,
- &offloadInfo);
-
- if (err == OK) {
- err = mAudioSink->setPlaybackRate(mPlaybackSettings);
- }
-
- if (err == OK) {
- // If the playback is offloaded to h/w, we pass
- // the HAL some metadata information.
- // We don't want to do this for PCM because it
- // will be going through the AudioFlinger mixer
- // before reaching the hardware.
- // TODO
- mCurrentOffloadInfo = offloadInfo;
- if (!mPaused) { // for preview mode, don't start if paused
- err = mAudioSink->start();
- }
- ALOGV_IF(err == OK, "openAudioSink: offload succeeded");
- }
- if (err != OK) {
- // Clean up, fall back to non offload mode.
- mAudioSink->close();
- onDisableOffloadAudio();
- mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER;
- ALOGV("openAudioSink: offload failed");
- if (offloadOnly) {
- notifyAudioTearDown(kForceNonOffload);
- }
- } else {
- mUseAudioCallback = true; // offload mode transfers data through callback
- ++mAudioDrainGeneration; // discard pending kWhatDrainAudioQueue message.
- }
- }
- }
- if (!offloadOnly && !offloadingAudio()) {
- ALOGV("openAudioSink: open AudioSink in NON-offload mode");
- uint32_t pcmFlags = flags;
- pcmFlags &= ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
-
- const PcmInfo info = {
- (audio_channel_mask_t)channelMask,
- (audio_output_flags_t)pcmFlags,
- audioFormat,
- numChannels,
- sampleRate
- };
- if (memcmp(&mCurrentPcmInfo, &info, sizeof(info)) == 0) {
- ALOGV("openAudioSink: no change in pcm mode");
- // no change from previous configuration, everything ok.
- return OK;
- }
-
- audioSinkChanged = true;
- mAudioSink->close();
- mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER;
- // Note: It is possible to set up the callback, but not use it to send audio data.
- // This requires a fix in AudioSink to explicitly specify the transfer mode.
- mUseAudioCallback = getUseAudioCallbackSetting();
- if (mUseAudioCallback) {
- ++mAudioDrainGeneration; // discard pending kWhatDrainAudioQueue message.
- }
-
- // Compute the desired buffer size.
- // For callback mode, the amount of time before wakeup is about half the buffer size.
- const uint32_t frameCount =
- (unsigned long long)sampleRate * getAudioSinkPcmMsSetting() / 1000;
-
- // We should always be able to set our playback settings if the sink is closed.
- LOG_ALWAYS_FATAL_IF(mAudioSink->setPlaybackRate(mPlaybackSettings) != OK,
- "onOpenAudioSink: can't set playback rate on closed sink");
- status_t err = mAudioSink->open(
- sampleRate,
- numChannels,
- (audio_channel_mask_t)channelMask,
- audioFormat,
- mUseAudioCallback ? &NuPlayer2::Renderer::AudioSinkCallback : NULL,
- mUseAudioCallback ? this : NULL,
- (audio_output_flags_t)pcmFlags,
- NULL,
- frameCount);
- if (err != OK) {
- ALOGW("openAudioSink: non offloaded open failed status: %d", err);
- mAudioSink->close();
- mCurrentPcmInfo = AUDIO_PCMINFO_INITIALIZER;
- return err;
- }
- mCurrentPcmInfo = info;
- if (!mPaused) { // for preview mode, don't start if paused
- mAudioSink->start();
- }
- }
- if (audioSinkChanged) {
- onAudioSinkChanged();
- }
- mAudioTornDown = false;
- return OK;
-}
-
-void NuPlayer2::Renderer::onCloseAudioSink() {
- mAudioSink->close();
- mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER;
- mCurrentPcmInfo = AUDIO_PCMINFO_INITIALIZER;
-}
-
-void NuPlayer2::Renderer::onChangeAudioFormat(
- const sp<AMessage> &meta, const sp<AMessage> ¬ify) {
- sp<AMessage> format;
- CHECK(meta->findMessage("format", &format));
-
- int32_t offloadOnly;
- CHECK(meta->findInt32("offload-only", &offloadOnly));
-
- int32_t hasVideo;
- CHECK(meta->findInt32("has-video", &hasVideo));
-
- uint32_t flags;
- CHECK(meta->findInt32("flags", (int32_t *)&flags));
-
- uint32_t isStreaming;
- CHECK(meta->findInt32("isStreaming", (int32_t *)&isStreaming));
-
- status_t err = onOpenAudioSink(format, offloadOnly, hasVideo, flags, isStreaming);
-
- if (err != OK) {
- notify->setInt32("err", err);
- }
- notify->post();
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.h
deleted file mode 100644
index d065dee..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.h
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NUPLAYER2_RENDERER_H_
-
-#define NUPLAYER2_RENDERER_H_
-
-#include <media/AudioResamplerPublic.h>
-#include <media/AVSyncSettings.h>
-#include <mediaplayer2/JObjectHolder.h>
-
-#include "NuPlayer2.h"
-
-namespace android {
-
-class JWakeLock;
-struct MediaClock;
-class MediaCodecBuffer;
-struct VideoFrameSchedulerBase;
-
-struct NuPlayer2::Renderer : public AHandler {
- enum Flags {
- FLAG_REAL_TIME = 1,
- FLAG_OFFLOAD_AUDIO = 2,
- };
- Renderer(const sp<MediaPlayer2Interface::AudioSink> &sink,
- const sp<MediaClock> &mediaClock,
- const sp<AMessage> ¬ify,
- const sp<JObjectHolder> &context,
- uint32_t flags = 0);
-
- static size_t AudioSinkCallback(
- MediaPlayer2Interface::AudioSink *audioSink,
- void *data, size_t size, void *me,
- MediaPlayer2Interface::AudioSink::cb_event_t event);
-
- void queueBuffer(
- bool audio,
- const sp<MediaCodecBuffer> &buffer,
- const sp<AMessage> ¬ifyConsumed);
-
- void queueEOS(bool audio, status_t finalResult);
-
- status_t setPlaybackSettings(const AudioPlaybackRate &rate /* sanitized */);
- status_t getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */);
- status_t setSyncSettings(const AVSyncSettings &sync, float videoFpsHint);
- status_t getSyncSettings(AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */);
-
- void flush(bool audio, bool notifyComplete);
-
- void signalTimeDiscontinuity();
-
- void signalDisableOffloadAudio();
- void signalEnableOffloadAudio();
-
- void pause();
- void resume();
-
- void setVideoFrameRate(float fps);
-
- status_t getCurrentPosition(int64_t *mediaUs);
- int64_t getVideoLateByUs();
-
- status_t openAudioSink(
- const sp<AMessage> &format,
- bool offloadOnly,
- bool hasVideo,
- uint32_t flags,
- bool *isOffloaded,
- bool isStreaming);
- void closeAudioSink();
-
- // re-open audio sink after all pending audio buffers played.
- void changeAudioFormat(
- const sp<AMessage> &format,
- bool offloadOnly,
- bool hasVideo,
- uint32_t flags,
- bool isStreaming,
- const sp<AMessage> ¬ify);
-
- enum {
- kWhatEOS = 'eos ',
- kWhatFlushComplete = 'fluC',
- kWhatPosition = 'posi',
- kWhatVideoRenderingStart = 'vdrd',
- kWhatMediaRenderingStart = 'mdrd',
- kWhatAudioTearDown = 'adTD',
- kWhatAudioOffloadPauseTimeout = 'aOPT',
- };
-
- enum AudioTearDownReason {
- kDueToError = 0, // Could restart with either offload or non-offload.
- kDueToTimeout,
- kForceNonOffload, // Restart only with non-offload.
- };
-
-protected:
- virtual ~Renderer();
-
- virtual void onMessageReceived(const sp<AMessage> &msg);
-
-private:
- enum {
- kWhatDrainAudioQueue = 'draA',
- kWhatDrainVideoQueue = 'draV',
- kWhatPostDrainVideoQueue = 'pDVQ',
- kWhatQueueBuffer = 'queB',
- kWhatQueueEOS = 'qEOS',
- kWhatConfigPlayback = 'cfPB',
- kWhatConfigSync = 'cfSy',
- kWhatGetPlaybackSettings = 'gPbS',
- kWhatGetSyncSettings = 'gSyS',
- kWhatFlush = 'flus',
- kWhatPause = 'paus',
- kWhatResume = 'resm',
- kWhatOpenAudioSink = 'opnA',
- kWhatCloseAudioSink = 'clsA',
- kWhatChangeAudioFormat = 'chgA',
- kWhatStopAudioSink = 'stpA',
- kWhatDisableOffloadAudio = 'noOA',
- kWhatEnableOffloadAudio = 'enOA',
- kWhatSetVideoFrameRate = 'sVFR',
- };
-
- // if mBuffer != nullptr, it's a buffer containing real data.
- // else if mNotifyConsumed == nullptr, it's EOS.
- // else it's a tag for re-opening audio sink in different format.
- struct QueueEntry {
- sp<MediaCodecBuffer> mBuffer;
- sp<AMessage> mMeta;
- sp<AMessage> mNotifyConsumed;
- size_t mOffset;
- status_t mFinalResult;
- int32_t mBufferOrdinal;
- };
-
- static const int64_t kMinPositionUpdateDelayUs;
-
- sp<MediaPlayer2Interface::AudioSink> mAudioSink;
- bool mUseVirtualAudioSink;
- sp<AMessage> mNotify;
- Mutex mLock;
- uint32_t mFlags;
- List<QueueEntry> mAudioQueue;
- List<QueueEntry> mVideoQueue;
- uint32_t mNumFramesWritten;
- sp<VideoFrameSchedulerBase> mVideoScheduler;
-
- bool mDrainAudioQueuePending;
- bool mDrainVideoQueuePending;
- int32_t mAudioQueueGeneration;
- int32_t mVideoQueueGeneration;
- int32_t mAudioDrainGeneration;
- int32_t mVideoDrainGeneration;
- int32_t mAudioEOSGeneration;
-
- const sp<MediaClock> mMediaClock;
-
- AudioPlaybackRate mPlaybackSettings;
- AVSyncSettings mSyncSettings;
- float mVideoFpsHint;
-
- int64_t mAudioFirstAnchorTimeMediaUs;
- int64_t mAnchorTimeMediaUs;
- int64_t mAnchorNumFramesWritten;
- int64_t mVideoLateByUs;
- int64_t mNextVideoTimeMediaUs;
- bool mHasAudio;
- bool mHasVideo;
-
- bool mNotifyCompleteAudio;
- bool mNotifyCompleteVideo;
-
- bool mSyncQueues;
-
- // modified on only renderer's thread.
- bool mPaused;
- int64_t mPauseDrainAudioAllowedUs; // time when we can drain/deliver audio in pause mode.
-
- bool mVideoSampleReceived;
- bool mVideoRenderingStarted;
- int32_t mVideoRenderingStartGeneration;
- int32_t mAudioRenderingStartGeneration;
- bool mRenderingDataDelivered;
-
- int64_t mNextAudioClockUpdateTimeUs;
- // the media timestamp of last audio sample right before EOS.
- int64_t mLastAudioMediaTimeUs;
-
- int32_t mAudioOffloadPauseTimeoutGeneration;
- bool mAudioTornDown;
- audio_offload_info_t mCurrentOffloadInfo;
-
- struct PcmInfo {
- audio_channel_mask_t mChannelMask;
- audio_output_flags_t mFlags;
- audio_format_t mFormat;
- int32_t mNumChannels;
- int32_t mSampleRate;
- };
- PcmInfo mCurrentPcmInfo;
- static const PcmInfo AUDIO_PCMINFO_INITIALIZER;
-
- int32_t mTotalBuffersQueued;
- int32_t mLastAudioBufferDrained;
- bool mUseAudioCallback;
-
- sp<JWakeLock> mWakeLock;
-
- status_t getCurrentPositionOnLooper(int64_t *mediaUs);
- status_t getCurrentPositionOnLooper(
- int64_t *mediaUs, int64_t nowUs, bool allowPastQueuedVideo = false);
- bool getCurrentPositionIfPaused_l(int64_t *mediaUs);
- status_t getCurrentPositionFromAnchor(
- int64_t *mediaUs, int64_t nowUs, bool allowPastQueuedVideo = false);
-
- void notifyEOSCallback();
- size_t fillAudioBuffer(void *buffer, size_t size);
-
- bool onDrainAudioQueue();
- void drainAudioQueueUntilLastEOS();
- int64_t getPendingAudioPlayoutDurationUs(int64_t nowUs);
- void postDrainAudioQueue_l(int64_t delayUs = 0);
-
- void clearAnchorTime();
- void clearAudioFirstAnchorTime_l();
- void setAudioFirstAnchorTimeIfNeeded_l(int64_t mediaUs);
- void setVideoLateByUs(int64_t lateUs);
-
- void onNewAudioMediaTime(int64_t mediaTimeUs);
- int64_t getRealTimeUs(int64_t mediaTimeUs, int64_t nowUs);
-
- void onDrainVideoQueue();
- void postDrainVideoQueue();
-
- void prepareForMediaRenderingStart_l();
- void notifyIfMediaRenderingStarted_l();
-
- void onQueueBuffer(const sp<AMessage> &msg);
- void onQueueEOS(const sp<AMessage> &msg);
- void onFlush(const sp<AMessage> &msg);
- void onAudioSinkChanged();
- void onDisableOffloadAudio();
- void onEnableOffloadAudio();
- status_t onConfigPlayback(const AudioPlaybackRate &rate /* sanitized */);
- status_t onGetPlaybackSettings(AudioPlaybackRate *rate /* nonnull */);
- status_t onConfigSync(const AVSyncSettings &sync, float videoFpsHint);
- status_t onGetSyncSettings(AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */);
-
- void onPause();
- void onResume();
- void onSetVideoFrameRate(float fps);
- int32_t getQueueGeneration(bool audio);
- int32_t getDrainGeneration(bool audio);
- bool getSyncQueues();
- void onAudioTearDown(AudioTearDownReason reason);
- status_t onOpenAudioSink(
- const sp<AMessage> &format,
- bool offloadOnly,
- bool hasVideo,
- uint32_t flags,
- bool isStreaming);
- void onCloseAudioSink();
- void onChangeAudioFormat(const sp<AMessage> &meta, const sp<AMessage> ¬ify);
-
- void notifyEOS(bool audio, status_t finalResult, int64_t delayUs = 0);
- void notifyEOS_l(bool audio, status_t finalResult, int64_t delayUs = 0);
- void notifyFlushComplete(bool audio);
- void notifyPosition();
- void notifyVideoLateBy(int64_t lateByUs);
- void notifyVideoRenderingStart();
- void notifyAudioTearDown(AudioTearDownReason reason);
-
- void flushQueue(List<QueueEntry> *queue);
- bool dropBufferIfStale(bool audio, const sp<AMessage> &msg);
- void syncQueuesDone_l();
-
- bool offloadingAudio() const { return (mFlags & FLAG_OFFLOAD_AUDIO) != 0; }
-
- void startAudioOffloadPauseTimeout();
- void cancelAudioOffloadPauseTimeout();
-
- int64_t getDurationUsIfPlayedAtSampleRate(uint32_t numFrames);
-
- DISALLOW_EVIL_CONSTRUCTORS(Renderer);
-};
-
-} // namespace android
-
-#endif // NUPLAYER2_RENDERER_H_
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h
deleted file mode 100644
index 9298a99..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NUPLAYER2_SOURCE_H_
-
-#define NUPLAYER2_SOURCE_H_
-
-#include "NuPlayer2.h"
-
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MetaData.h>
-#include <mediaplayer2/mediaplayer2.h>
-#include <utils/Vector.h>
-
-namespace android {
-
-struct ABuffer;
-struct AMediaCryptoWrapper;
-class MediaBuffer;
-
-struct NuPlayer2::Source : public AHandler {
- enum Flags {
- FLAG_CAN_PAUSE = 1,
- FLAG_CAN_SEEK_BACKWARD = 2, // the "10 sec back button"
- FLAG_CAN_SEEK_FORWARD = 4, // the "10 sec forward button"
- FLAG_CAN_SEEK = 8, // the "seek bar"
- FLAG_DYNAMIC_DURATION = 16,
- FLAG_SECURE = 32, // Secure codec is required.
- FLAG_PROTECTED = 64, // The screen needs to be protected (screenshot is disabled).
- };
-
- enum {
- kWhatPrepared,
- kWhatFlagsChanged,
- kWhatVideoSizeChanged,
- kWhatBufferingUpdate,
- kWhatPauseOnBufferingStart,
- kWhatResumeOnBufferingEnd,
- kWhatCacheStats,
- kWhatSubtitleData,
- kWhatTimedTextData,
- kWhatTimedMetaData,
- kWhatQueueDecoderShutdown,
- kWhatDrmNoLicense,
- // Modular DRM
- kWhatDrmInfo,
- };
-
- // The provides message is used to notify the player about various
- // events.
- explicit Source(const sp<AMessage> ¬ify)
- : mNotify(notify) {
- }
-
- virtual status_t getBufferingSettings(
- BufferingSettings* buffering /* nonnull */) = 0;
- virtual status_t setBufferingSettings(const BufferingSettings& buffering) = 0;
-
- virtual void prepareAsync(int64_t startTimeUs) = 0;
-
- virtual void start() = 0;
- virtual void stop() {}
- virtual void pause() {}
- virtual void resume() {}
-
- // Explicitly disconnect the underling data source
- virtual void disconnect() {}
-
- // Returns OK iff more data was available,
- // an error or ERROR_END_OF_STREAM if not.
- virtual status_t feedMoreTSData() = 0;
-
- // Returns non-NULL format when the specified track exists.
- // When the format has "err" set to -EWOULDBLOCK, source needs more time to get valid meta data.
- // Returns NULL if the specified track doesn't exist or is invalid;
- virtual sp<AMessage> getFormat(bool audio);
-
- virtual sp<MetaData> getFormatMeta(bool /* audio */) { return NULL; }
- virtual sp<MetaData> getFileFormatMeta() const { return NULL; }
-
- virtual status_t dequeueAccessUnit(
- bool audio, sp<ABuffer> *accessUnit) = 0;
-
- virtual status_t getDuration(int64_t * /* durationUs */) {
- return INVALID_OPERATION;
- }
-
- virtual size_t getTrackCount() const {
- return 0;
- }
-
- virtual sp<AMessage> getTrackInfo(size_t /* trackIndex */) const {
- return NULL;
- }
-
- virtual ssize_t getSelectedTrack(media_track_type /* type */) const {
- return INVALID_OPERATION;
- }
-
- virtual status_t selectTrack(size_t /* trackIndex */, bool /* select */, int64_t /* timeUs*/) {
- return INVALID_OPERATION;
- }
-
- virtual status_t seekTo(
- int64_t /* seekTimeUs */,
- MediaPlayer2SeekMode /* mode */ = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC) {
- return INVALID_OPERATION;
- }
-
- virtual bool isRealTime() const {
- return false;
- }
-
- virtual bool isStreaming() const {
- return true;
- }
-
- virtual void setOffloadAudio(bool /* offload */) {}
-
- // Modular DRM
- virtual status_t prepareDrm(
- const uint8_t /* uuid */[16], const Vector<uint8_t> & /* drmSessionId */,
- sp<AMediaCryptoWrapper> * /* crypto */) {
- return INVALID_OPERATION;
- }
-
- virtual status_t releaseDrm() {
- return INVALID_OPERATION;
- }
-
-protected:
- virtual ~Source() {}
-
- virtual void onMessageReceived(const sp<AMessage> &msg);
-
- sp<AMessage> dupNotify() const { return mNotify->dup(); }
-
- void notifyFlagsChanged(uint32_t flags);
- void notifyVideoSizeChanged(const sp<AMessage> &format = NULL);
- void notifyPrepared(status_t err = OK);
- // Modular DRM
- void notifyDrmInfo(const sp<ABuffer> &buffer);
-
-private:
- sp<AMessage> mNotify;
-
- DISALLOW_EVIL_CONSTRUCTORS(Source);
-};
-
-} // namespace android
-
-#endif // NUPLAYER2_SOURCE_H_
-
diff --git a/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp b/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp
deleted file mode 100644
index a70269e..0000000
--- a/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp
+++ /dev/null
@@ -1,903 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "RTSPSource2"
-#include <utils/Log.h>
-
-#include "RTSPSource2.h"
-
-#include "AnotherPacketSource.h"
-#include "MyHandler.h"
-#include "SDPLoader.h"
-
-#include <media/MediaHTTPService.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MetaData.h>
-
-namespace android {
-
-const int64_t kNearEOSTimeoutUs = 2000000LL; // 2 secs
-
-// Default Buffer Underflow/Prepare/StartServer/Overflow Marks
-static const int kUnderflowMarkMs = 1000; // 1 second
-static const int kPrepareMarkMs = 3000; // 3 seconds
-//static const int kStartServerMarkMs = 5000;
-static const int kOverflowMarkMs = 10000; // 10 seconds
-
-NuPlayer2::RTSPSource2::RTSPSource2(
- const sp<AMessage> ¬ify,
- const sp<MediaHTTPService> &httpService,
- const char *url,
- const KeyedVector<String8, String8> *headers,
- uid_t uid,
- bool isSDP)
- : Source(notify),
- mHTTPService(httpService),
- mURL(url),
- mUID(uid),
- mFlags(0),
- mIsSDP(isSDP),
- mState(DISCONNECTED),
- mFinalResult(OK),
- mDisconnectReplyID(0),
- mBuffering(false),
- mInPreparationPhase(true),
- mEOSPending(false),
- mSeekGeneration(0),
- mEOSTimeoutAudio(0),
- mEOSTimeoutVideo(0) {
- mBufferingSettings.mInitialMarkMs = kPrepareMarkMs;
- mBufferingSettings.mResumePlaybackMarkMs = kOverflowMarkMs;
- if (headers) {
- mExtraHeaders = *headers;
-
- ssize_t index =
- mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log"));
-
- if (index >= 0) {
- mFlags |= kFlagIncognito;
-
- mExtraHeaders.removeItemsAt(index);
- }
- }
-}
-
-NuPlayer2::RTSPSource2::~RTSPSource2() {
- if (mLooper != NULL) {
- mLooper->unregisterHandler(id());
- mLooper->stop();
- }
-}
-
-status_t NuPlayer2::RTSPSource2::getBufferingSettings(
- BufferingSettings* buffering /* nonnull */) {
- Mutex::Autolock _l(mBufferingSettingsLock);
- *buffering = mBufferingSettings;
- return OK;
-}
-
-status_t NuPlayer2::RTSPSource2::setBufferingSettings(const BufferingSettings& buffering) {
- Mutex::Autolock _l(mBufferingSettingsLock);
- mBufferingSettings = buffering;
- return OK;
-}
-
-// TODO: fetch data starting from |startTimeUs|
-void NuPlayer2::RTSPSource2::prepareAsync(int64_t /* startTimeUs */) {
- if (mIsSDP && mHTTPService == NULL) {
- notifyPrepared(BAD_VALUE);
- return;
- }
-
- if (mLooper == NULL) {
- mLooper = new ALooper;
- mLooper->setName("rtsp2");
- mLooper->start();
-
- mLooper->registerHandler(this);
- }
-
- CHECK(mHandler == NULL);
- CHECK(mSDPLoader == NULL);
-
- sp<AMessage> notify = new AMessage(kWhatNotify, this);
-
- CHECK_EQ(mState, (int)DISCONNECTED);
- mState = CONNECTING;
-
- if (mIsSDP) {
- mSDPLoader = new SDPLoader(notify,
- (mFlags & kFlagIncognito) ? SDPLoader::kFlagIncognito : 0,
- mHTTPService);
-
- mSDPLoader->load(
- mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
- } else {
- mHandler = new MyHandler(mURL.c_str(), notify, true /* uidValid */, mUID);
- mLooper->registerHandler(mHandler);
-
- mHandler->connect();
- }
-
- startBufferingIfNecessary();
-}
-
-void NuPlayer2::RTSPSource2::start() {
-}
-
-void NuPlayer2::RTSPSource2::stop() {
- if (mLooper == NULL) {
- return;
- }
- sp<AMessage> msg = new AMessage(kWhatDisconnect, this);
-
- sp<AMessage> dummy;
- msg->postAndAwaitResponse(&dummy);
-}
-
-status_t NuPlayer2::RTSPSource2::feedMoreTSData() {
- Mutex::Autolock _l(mBufferingLock);
- return mFinalResult;
-}
-
-sp<MetaData> NuPlayer2::RTSPSource2::getFormatMeta(bool audio) {
- sp<AnotherPacketSource> source = getSource(audio);
-
- if (source == NULL) {
- return NULL;
- }
-
- return source->getFormat();
-}
-
-bool NuPlayer2::RTSPSource2::haveSufficientDataOnAllTracks() {
- // We're going to buffer at least 2 secs worth data on all tracks before
- // starting playback (both at startup and after a seek).
-
- static const int64_t kMinDurationUs = 2000000LL;
-
- int64_t mediaDurationUs = 0;
- getDuration(&mediaDurationUs);
- if ((mAudioTrack != NULL && mAudioTrack->isFinished(mediaDurationUs))
- || (mVideoTrack != NULL && mVideoTrack->isFinished(mediaDurationUs))) {
- return true;
- }
-
- status_t err;
- int64_t durationUs;
- if (mAudioTrack != NULL
- && (durationUs = mAudioTrack->getBufferedDurationUs(&err))
- < kMinDurationUs
- && err == OK) {
- ALOGV("audio track doesn't have enough data yet. (%.2f secs buffered)",
- durationUs / 1E6);
- return false;
- }
-
- if (mVideoTrack != NULL
- && (durationUs = mVideoTrack->getBufferedDurationUs(&err))
- < kMinDurationUs
- && err == OK) {
- ALOGV("video track doesn't have enough data yet. (%.2f secs buffered)",
- durationUs / 1E6);
- return false;
- }
-
- return true;
-}
-
-status_t NuPlayer2::RTSPSource2::dequeueAccessUnit(
- bool audio, sp<ABuffer> *accessUnit) {
- if (!stopBufferingIfNecessary()) {
- return -EWOULDBLOCK;
- }
-
- sp<AnotherPacketSource> source = getSource(audio);
-
- if (source == NULL) {
- return -EWOULDBLOCK;
- }
-
- status_t finalResult;
- if (!source->hasBufferAvailable(&finalResult)) {
- if (finalResult == OK) {
-
- // If other source already signaled EOS, this source should also return EOS
- if (sourceReachedEOS(!audio)) {
- return ERROR_END_OF_STREAM;
- }
-
- // If this source has detected near end, give it some time to retrieve more
- // data before returning EOS
- int64_t mediaDurationUs = 0;
- getDuration(&mediaDurationUs);
- if (source->isFinished(mediaDurationUs)) {
- int64_t eosTimeout = audio ? mEOSTimeoutAudio : mEOSTimeoutVideo;
- if (eosTimeout == 0) {
- setEOSTimeout(audio, ALooper::GetNowUs());
- } else if ((ALooper::GetNowUs() - eosTimeout) > kNearEOSTimeoutUs) {
- setEOSTimeout(audio, 0);
- return ERROR_END_OF_STREAM;
- }
- return -EWOULDBLOCK;
- }
-
- if (!sourceNearEOS(!audio)) {
- // We should not enter buffering mode
- // if any of the sources already have detected EOS.
- startBufferingIfNecessary();
- }
-
- return -EWOULDBLOCK;
- }
- return finalResult;
- }
-
- setEOSTimeout(audio, 0);
-
- return source->dequeueAccessUnit(accessUnit);
-}
-
-sp<AnotherPacketSource> NuPlayer2::RTSPSource2::getSource(bool audio) {
- if (mTSParser != NULL) {
- sp<MediaSource> source = mTSParser->getSource(
- audio ? ATSParser::AUDIO : ATSParser::VIDEO);
-
- return static_cast<AnotherPacketSource *>(source.get());
- }
-
- return audio ? mAudioTrack : mVideoTrack;
-}
-
-void NuPlayer2::RTSPSource2::setEOSTimeout(bool audio, int64_t timeout) {
- if (audio) {
- mEOSTimeoutAudio = timeout;
- } else {
- mEOSTimeoutVideo = timeout;
- }
-}
-
-status_t NuPlayer2::RTSPSource2::getDuration(int64_t *durationUs) {
- *durationUs = -1LL;
-
- int64_t audioDurationUs;
- if (mAudioTrack != NULL
- && mAudioTrack->getFormat()->findInt64(
- kKeyDuration, &audioDurationUs)
- && audioDurationUs > *durationUs) {
- *durationUs = audioDurationUs;
- }
-
- int64_t videoDurationUs;
- if (mVideoTrack != NULL
- && mVideoTrack->getFormat()->findInt64(
- kKeyDuration, &videoDurationUs)
- && videoDurationUs > *durationUs) {
- *durationUs = videoDurationUs;
- }
-
- return OK;
-}
-
-status_t NuPlayer2::RTSPSource2::seekTo(int64_t seekTimeUs, MediaPlayer2SeekMode mode) {
- sp<AMessage> msg = new AMessage(kWhatPerformSeek, this);
- msg->setInt32("generation", ++mSeekGeneration);
- msg->setInt64("timeUs", seekTimeUs);
- msg->setInt32("mode", mode);
-
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- }
-
- return err;
-}
-
-void NuPlayer2::RTSPSource2::performSeek(int64_t seekTimeUs) {
- if (mState != CONNECTED) {
- finishSeek(INVALID_OPERATION);
- return;
- }
-
- mState = SEEKING;
- mHandler->seek(seekTimeUs);
- mEOSPending = false;
-}
-
-void NuPlayer2::RTSPSource2::schedulePollBuffering() {
- sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
- msg->post(1000000LL); // 1 second intervals
-}
-
-void NuPlayer2::RTSPSource2::checkBuffering(
- bool *prepared, bool *underflow, bool *overflow, bool *startServer, bool *finished) {
- size_t numTracks = mTracks.size();
- size_t preparedCount, underflowCount, overflowCount, startCount, finishedCount;
- preparedCount = underflowCount = overflowCount = startCount = finishedCount = 0;
-
- size_t count = numTracks;
- for (size_t i = 0; i < count; ++i) {
- status_t finalResult;
- TrackInfo *info = &mTracks.editItemAt(i);
- sp<AnotherPacketSource> src = info->mSource;
- if (src == NULL) {
- --numTracks;
- continue;
- }
- int64_t bufferedDurationUs = src->getBufferedDurationUs(&finalResult);
-
- int64_t initialMarkUs;
- int64_t maxRebufferingMarkUs;
- {
- Mutex::Autolock _l(mBufferingSettingsLock);
- initialMarkUs = mBufferingSettings.mInitialMarkMs * 1000LL;
- // TODO: maxRebufferingMarkUs could be larger than
- // mBufferingSettings.mResumePlaybackMarkMs * 1000ll.
- maxRebufferingMarkUs = mBufferingSettings.mResumePlaybackMarkMs * 1000LL;
- }
- // isFinished when duration is 0 checks for EOS result only
- if (bufferedDurationUs > initialMarkUs
- || src->isFinished(/* duration */ 0)) {
- ++preparedCount;
- }
-
- if (src->isFinished(/* duration */ 0)) {
- ++overflowCount;
- ++finishedCount;
- } else {
- // TODO: redefine kUnderflowMarkMs to a fair value,
- if (bufferedDurationUs < kUnderflowMarkMs * 1000) {
- ++underflowCount;
- }
- if (bufferedDurationUs > maxRebufferingMarkUs) {
- ++overflowCount;
- }
- int64_t startServerMarkUs =
- (kUnderflowMarkMs * 1000LL + maxRebufferingMarkUs) / 2;
- if (bufferedDurationUs < startServerMarkUs) {
- ++startCount;
- }
- }
- }
-
- *prepared = (preparedCount == numTracks);
- *underflow = (underflowCount > 0);
- *overflow = (overflowCount == numTracks);
- *startServer = (startCount > 0);
- *finished = (finishedCount > 0);
-}
-
-void NuPlayer2::RTSPSource2::onPollBuffering() {
- bool prepared, underflow, overflow, startServer, finished;
- checkBuffering(&prepared, &underflow, &overflow, &startServer, &finished);
-
- if (prepared && mInPreparationPhase) {
- mInPreparationPhase = false;
- notifyPrepared();
- }
-
- if (!mInPreparationPhase && underflow) {
- startBufferingIfNecessary();
- }
-
- if (haveSufficientDataOnAllTracks()) {
- stopBufferingIfNecessary();
- }
-
- if (overflow && mHandler != NULL) {
- mHandler->pause();
- }
-
- if (startServer && mHandler != NULL) {
- mHandler->resume();
- }
-
- if (finished && mHandler != NULL) {
- mHandler->cancelAccessUnitTimeoutCheck();
- }
-
- schedulePollBuffering();
-}
-
-void NuPlayer2::RTSPSource2::signalSourceEOS(status_t result) {
- const bool audio = true;
- const bool video = false;
-
- sp<AnotherPacketSource> source = getSource(audio);
- if (source != NULL) {
- source->signalEOS(result);
- }
-
- source = getSource(video);
- if (source != NULL) {
- source->signalEOS(result);
- }
-}
-
-bool NuPlayer2::RTSPSource2::sourceReachedEOS(bool audio) {
- sp<AnotherPacketSource> source = getSource(audio);
- status_t finalResult;
- return (source != NULL &&
- !source->hasBufferAvailable(&finalResult) &&
- finalResult == ERROR_END_OF_STREAM);
-}
-
-bool NuPlayer2::RTSPSource2::sourceNearEOS(bool audio) {
- sp<AnotherPacketSource> source = getSource(audio);
- int64_t mediaDurationUs = 0;
- getDuration(&mediaDurationUs);
- return (source != NULL && source->isFinished(mediaDurationUs));
-}
-
-void NuPlayer2::RTSPSource2::onSignalEOS(const sp<AMessage> &msg) {
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
-
- if (generation != mSeekGeneration) {
- return;
- }
-
- if (mEOSPending) {
- signalSourceEOS(ERROR_END_OF_STREAM);
- mEOSPending = false;
- }
-}
-
-void NuPlayer2::RTSPSource2::postSourceEOSIfNecessary() {
- const bool audio = true;
- const bool video = false;
- // If a source has detected near end, give it some time to retrieve more
- // data before signaling EOS
- if (sourceNearEOS(audio) || sourceNearEOS(video)) {
- if (!mEOSPending) {
- sp<AMessage> msg = new AMessage(kWhatSignalEOS, this);
- msg->setInt32("generation", mSeekGeneration);
- msg->post(kNearEOSTimeoutUs);
- mEOSPending = true;
- }
- }
-}
-
-void NuPlayer2::RTSPSource2::onMessageReceived(const sp<AMessage> &msg) {
- if (msg->what() == kWhatDisconnect) {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
- mDisconnectReplyID = replyID;
- finishDisconnectIfPossible();
- return;
- } else if (msg->what() == kWhatPerformSeek) {
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
- CHECK(msg->senderAwaitsResponse(&mSeekReplyID));
-
- if (generation != mSeekGeneration) {
- // obsolete.
- finishSeek(OK);
- return;
- }
-
- int64_t seekTimeUs;
- int32_t mode;
- CHECK(msg->findInt64("timeUs", &seekTimeUs));
- CHECK(msg->findInt32("mode", &mode));
-
- // TODO: add "mode" to performSeek.
- performSeek(seekTimeUs/*, (MediaPlayer2SeekMode)mode */);
- return;
- } else if (msg->what() == kWhatPollBuffering) {
- onPollBuffering();
- return;
- } else if (msg->what() == kWhatSignalEOS) {
- onSignalEOS(msg);
- return;
- }
-
- CHECK_EQ(msg->what(), kWhatNotify);
-
- int32_t what;
- CHECK(msg->findInt32("what", &what));
-
- switch (what) {
- case MyHandler::kWhatConnected:
- {
- onConnected();
-
- notifyVideoSizeChanged();
-
- uint32_t flags = 0;
-
- if (mHandler->isSeekable()) {
- flags = FLAG_CAN_PAUSE
- | FLAG_CAN_SEEK
- | FLAG_CAN_SEEK_BACKWARD
- | FLAG_CAN_SEEK_FORWARD;
- }
-
- notifyFlagsChanged(flags);
- schedulePollBuffering();
- break;
- }
-
- case MyHandler::kWhatDisconnected:
- {
- onDisconnected(msg);
- break;
- }
-
- case MyHandler::kWhatSeekDone:
- {
- mState = CONNECTED;
- // Unblock seekTo here in case we attempted to seek in a live stream
- finishSeek(OK);
- break;
- }
-
- case MyHandler::kWhatSeekPaused:
- {
- sp<AnotherPacketSource> source = getSource(true /* audio */);
- if (source != NULL) {
- source->queueDiscontinuity(ATSParser::DISCONTINUITY_NONE,
- /* extra */ NULL,
- /* discard */ true);
- }
- source = getSource(false /* video */);
- if (source != NULL) {
- source->queueDiscontinuity(ATSParser::DISCONTINUITY_NONE,
- /* extra */ NULL,
- /* discard */ true);
- };
-
- status_t err = OK;
- msg->findInt32("err", &err);
-
- if (err == OK) {
- int64_t timeUs;
- CHECK(msg->findInt64("time", &timeUs));
- mHandler->continueSeekAfterPause(timeUs);
- } else {
- finishSeek(err);
- }
- break;
- }
-
- case MyHandler::kWhatAccessUnit:
- {
- size_t trackIndex;
- CHECK(msg->findSize("trackIndex", &trackIndex));
-
- if (mTSParser == NULL) {
- CHECK_LT(trackIndex, mTracks.size());
- } else {
- CHECK_EQ(trackIndex, 0u);
- }
-
- sp<ABuffer> accessUnit;
- CHECK(msg->findBuffer("accessUnit", &accessUnit));
-
- int32_t damaged;
- if (accessUnit->meta()->findInt32("damaged", &damaged)
- && damaged) {
- ALOGI("dropping damaged access unit.");
- break;
- }
-
- if (mTSParser != NULL) {
- size_t offset = 0;
- status_t err = OK;
- while (offset + 188 <= accessUnit->size()) {
- err = mTSParser->feedTSPacket(
- accessUnit->data() + offset, 188);
- if (err != OK) {
- break;
- }
-
- offset += 188;
- }
-
- if (offset < accessUnit->size()) {
- err = ERROR_MALFORMED;
- }
-
- if (err != OK) {
- signalSourceEOS(err);
- }
-
- postSourceEOSIfNecessary();
- break;
- }
-
- TrackInfo *info = &mTracks.editItemAt(trackIndex);
-
- sp<AnotherPacketSource> source = info->mSource;
- if (source != NULL) {
- uint32_t rtpTime;
- CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
-
- if (!info->mNPTMappingValid) {
- // This is a live stream, we didn't receive any normal
- // playtime mapping. We won't map to npt time.
- source->queueAccessUnit(accessUnit);
- break;
- }
-
- int64_t nptUs =
- ((double)rtpTime - (double)info->mRTPTime)
- / info->mTimeScale
- * 1000000LL
- + info->mNormalPlaytimeUs;
-
- accessUnit->meta()->setInt64("timeUs", nptUs);
-
- source->queueAccessUnit(accessUnit);
- }
- postSourceEOSIfNecessary();
- break;
- }
-
- case MyHandler::kWhatEOS:
- {
- int32_t finalResult;
- CHECK(msg->findInt32("finalResult", &finalResult));
- CHECK_NE(finalResult, (status_t)OK);
-
- if (mTSParser != NULL) {
- signalSourceEOS(finalResult);
- }
-
- size_t trackIndex;
- CHECK(msg->findSize("trackIndex", &trackIndex));
- CHECK_LT(trackIndex, mTracks.size());
-
- TrackInfo *info = &mTracks.editItemAt(trackIndex);
- sp<AnotherPacketSource> source = info->mSource;
- if (source != NULL) {
- source->signalEOS(finalResult);
- }
-
- break;
- }
-
- case MyHandler::kWhatSeekDiscontinuity:
- {
- size_t trackIndex;
- CHECK(msg->findSize("trackIndex", &trackIndex));
- CHECK_LT(trackIndex, mTracks.size());
-
- TrackInfo *info = &mTracks.editItemAt(trackIndex);
- sp<AnotherPacketSource> source = info->mSource;
- if (source != NULL) {
- source->queueDiscontinuity(
- ATSParser::DISCONTINUITY_TIME,
- NULL,
- true /* discard */);
- }
-
- break;
- }
-
- case MyHandler::kWhatNormalPlayTimeMapping:
- {
- size_t trackIndex;
- CHECK(msg->findSize("trackIndex", &trackIndex));
- CHECK_LT(trackIndex, mTracks.size());
-
- uint32_t rtpTime;
- CHECK(msg->findInt32("rtpTime", (int32_t *)&rtpTime));
-
- int64_t nptUs;
- CHECK(msg->findInt64("nptUs", &nptUs));
-
- TrackInfo *info = &mTracks.editItemAt(trackIndex);
- info->mRTPTime = rtpTime;
- info->mNormalPlaytimeUs = nptUs;
- info->mNPTMappingValid = true;
- break;
- }
-
- case SDPLoader::kWhatSDPLoaded:
- {
- onSDPLoaded(msg);
- break;
- }
-
- default:
- TRESPASS();
- }
-}
-
-void NuPlayer2::RTSPSource2::onConnected() {
- CHECK(mAudioTrack == NULL);
- CHECK(mVideoTrack == NULL);
-
- size_t numTracks = mHandler->countTracks();
- for (size_t i = 0; i < numTracks; ++i) {
- int32_t timeScale;
- sp<MetaData> format = mHandler->getTrackFormat(i, &timeScale);
-
- const char *mime;
- CHECK(format->findCString(kKeyMIMEType, &mime));
-
- if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
- // Very special case for MPEG2 Transport Streams.
- CHECK_EQ(numTracks, 1u);
-
- mTSParser = new ATSParser;
- return;
- }
-
- bool isAudio = !strncasecmp(mime, "audio/", 6);
- bool isVideo = !strncasecmp(mime, "video/", 6);
-
- TrackInfo info;
- info.mTimeScale = timeScale;
- info.mRTPTime = 0;
- info.mNormalPlaytimeUs = 0LL;
- info.mNPTMappingValid = false;
-
- if ((isAudio && mAudioTrack == NULL)
- || (isVideo && mVideoTrack == NULL)) {
- sp<AnotherPacketSource> source = new AnotherPacketSource(format);
-
- if (isAudio) {
- mAudioTrack = source;
- } else {
- mVideoTrack = source;
- }
-
- info.mSource = source;
- }
-
- mTracks.push(info);
- }
-
- mState = CONNECTED;
-}
-
-void NuPlayer2::RTSPSource2::onSDPLoaded(const sp<AMessage> &msg) {
- status_t err;
- CHECK(msg->findInt32("result", &err));
-
- mSDPLoader.clear();
-
- if (mDisconnectReplyID != 0) {
- err = UNKNOWN_ERROR;
- }
-
- if (err == OK) {
- sp<ASessionDescription> desc;
- sp<RefBase> obj;
- CHECK(msg->findObject("description", &obj));
- desc = static_cast<ASessionDescription *>(obj.get());
-
- AString rtspUri;
- if (!desc->findAttribute(0, "a=control", &rtspUri)) {
- ALOGE("Unable to find url in SDP");
- err = UNKNOWN_ERROR;
- } else {
- sp<AMessage> notify = new AMessage(kWhatNotify, this);
-
- mHandler = new MyHandler(rtspUri.c_str(), notify, true /* uidValid */, mUID);
- mLooper->registerHandler(mHandler);
-
- mHandler->loadSDP(desc);
- }
- }
-
- if (err != OK) {
- if (mState == CONNECTING) {
- // We're still in the preparation phase, signal that it
- // failed.
- notifyPrepared(err);
- }
-
- mState = DISCONNECTED;
- setError(err);
-
- if (mDisconnectReplyID != 0) {
- finishDisconnectIfPossible();
- }
- }
-}
-
-void NuPlayer2::RTSPSource2::onDisconnected(const sp<AMessage> &msg) {
- if (mState == DISCONNECTED) {
- return;
- }
-
- status_t err;
- CHECK(msg->findInt32("result", &err));
- CHECK_NE(err, (status_t)OK);
-
- mLooper->unregisterHandler(mHandler->id());
- mHandler.clear();
-
- if (mState == CONNECTING) {
- // We're still in the preparation phase, signal that it
- // failed.
- notifyPrepared(err);
- }
-
- mState = DISCONNECTED;
- setError(err);
-
- if (mDisconnectReplyID != 0) {
- finishDisconnectIfPossible();
- }
-}
-
-void NuPlayer2::RTSPSource2::finishDisconnectIfPossible() {
- if (mState != DISCONNECTED) {
- if (mHandler != NULL) {
- mHandler->disconnect();
- } else if (mSDPLoader != NULL) {
- mSDPLoader->cancel();
- }
- return;
- }
-
- (new AMessage)->postReply(mDisconnectReplyID);
- mDisconnectReplyID = 0;
-}
-
-void NuPlayer2::RTSPSource2::setError(status_t err) {
- Mutex::Autolock _l(mBufferingLock);
- mFinalResult = err;
-}
-
-void NuPlayer2::RTSPSource2::startBufferingIfNecessary() {
- Mutex::Autolock _l(mBufferingLock);
-
- if (!mBuffering) {
- mBuffering = true;
-
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatPauseOnBufferingStart);
- notify->post();
- }
-}
-
-bool NuPlayer2::RTSPSource2::stopBufferingIfNecessary() {
- Mutex::Autolock _l(mBufferingLock);
-
- if (mBuffering) {
- if (!haveSufficientDataOnAllTracks()) {
- return false;
- }
-
- mBuffering = false;
-
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatResumeOnBufferingEnd);
- notify->post();
- }
-
- return true;
-}
-
-void NuPlayer2::RTSPSource2::finishSeek(status_t err) {
- if (mSeekReplyID == NULL) {
- return;
- }
- sp<AMessage> seekReply = new AMessage;
- seekReply->setInt32("err", err);
- seekReply->postReply(mSeekReplyID);
- mSeekReplyID = NULL;
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/RTSPSource2.h b/media/libmediaplayer2/nuplayer2/RTSPSource2.h
deleted file mode 100644
index e5f1716..0000000
--- a/media/libmediaplayer2/nuplayer2/RTSPSource2.h
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef RTSP_SOURCE2_H_
-
-#define RTSP_SOURCE2_H_
-
-#include "NuPlayer2Source.h"
-
-#include "ATSParser.h"
-
-namespace android {
-
-struct ALooper;
-struct AReplyToken;
-struct AnotherPacketSource;
-struct MyHandler;
-struct SDPLoader;
-
-struct NuPlayer2::RTSPSource2 : public NuPlayer2::Source {
- RTSPSource2(
- const sp<AMessage> ¬ify,
- const sp<MediaHTTPService> &httpService,
- const char *url,
- const KeyedVector<String8, String8> *headers,
- uid_t uid = 0,
- bool isSDP = false);
-
- virtual status_t getBufferingSettings(
- BufferingSettings* buffering /* nonnull */) override;
- virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
-
- virtual void prepareAsync(int64_t startTimeUs);
- virtual void start();
- virtual void stop();
-
- virtual status_t feedMoreTSData();
-
- virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
-
- virtual status_t getDuration(int64_t *durationUs);
- virtual status_t seekTo(
- int64_t seekTimeUs,
- MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC) override;
-
- void onMessageReceived(const sp<AMessage> &msg);
-
-protected:
- virtual ~RTSPSource2();
-
- virtual sp<MetaData> getFormatMeta(bool audio);
-
-private:
- enum {
- kWhatNotify = 'noti',
- kWhatDisconnect = 'disc',
- kWhatPerformSeek = 'seek',
- kWhatPollBuffering = 'poll',
- kWhatSignalEOS = 'eos ',
- };
-
- enum State {
- DISCONNECTED,
- CONNECTING,
- CONNECTED,
- SEEKING,
- };
-
- enum Flags {
- // Don't log any URLs.
- kFlagIncognito = 1,
- };
-
- struct TrackInfo {
- sp<AnotherPacketSource> mSource;
-
- int32_t mTimeScale;
- uint32_t mRTPTime;
- int64_t mNormalPlaytimeUs;
- bool mNPTMappingValid;
- };
-
- sp<MediaHTTPService> mHTTPService;
- AString mURL;
- KeyedVector<String8, String8> mExtraHeaders;
- uid_t mUID;
- uint32_t mFlags;
- bool mIsSDP;
- State mState;
- status_t mFinalResult;
- sp<AReplyToken> mDisconnectReplyID;
- Mutex mBufferingLock;
- bool mBuffering;
- bool mInPreparationPhase;
- bool mEOSPending;
-
- Mutex mBufferingSettingsLock;
- BufferingSettings mBufferingSettings;
-
- sp<ALooper> mLooper;
- sp<MyHandler> mHandler;
- sp<SDPLoader> mSDPLoader;
-
- Vector<TrackInfo> mTracks;
- sp<AnotherPacketSource> mAudioTrack;
- sp<AnotherPacketSource> mVideoTrack;
-
- sp<ATSParser> mTSParser;
-
- int32_t mSeekGeneration;
-
- int64_t mEOSTimeoutAudio;
- int64_t mEOSTimeoutVideo;
-
- sp<AReplyToken> mSeekReplyID;
-
- sp<AnotherPacketSource> getSource(bool audio);
-
- void onConnected();
- void onSDPLoaded(const sp<AMessage> &msg);
- void onDisconnected(const sp<AMessage> &msg);
- void finishDisconnectIfPossible();
-
- void performSeek(int64_t seekTimeUs);
- void schedulePollBuffering();
- void checkBuffering(
- bool *prepared,
- bool *underflow,
- bool *overflow,
- bool *startServer,
- bool *finished);
- void onPollBuffering();
-
- bool haveSufficientDataOnAllTracks();
-
- void setEOSTimeout(bool audio, int64_t timeout);
- void setError(status_t err);
- void startBufferingIfNecessary();
- bool stopBufferingIfNecessary();
- void finishSeek(status_t err);
-
- void postSourceEOSIfNecessary();
- void signalSourceEOS(status_t result);
- void onSignalEOS(const sp<AMessage> &msg);
-
- bool sourceNearEOS(bool audio);
- bool sourceReachedEOS(bool audio);
-
- DISALLOW_EVIL_CONSTRUCTORS(RTSPSource2);
-};
-
-} // namespace android
-
-#endif // RTSP_SOURCE2_H_
diff --git a/media/libmediaplayerservice/Android.bp b/media/libmediaplayerservice/Android.bp
index 6709585..5301f5c 100644
--- a/media/libmediaplayerservice/Android.bp
+++ b/media/libmediaplayerservice/Android.bp
@@ -7,6 +7,7 @@
"MediaPlayerService.cpp",
"MediaRecorderClient.cpp",
"MetadataRetrieverClient.cpp",
+ "StagefrightMetadataRetriever.cpp",
"StagefrightRecorder.cpp",
"TestPlayerStub.cpp",
],
@@ -21,11 +22,14 @@
"libcodec2_client",
"libcrypto",
"libcutils",
+ "libdatasource",
"libdl",
+ "libdrmframework",
"libgui",
"libhidlbase",
"liblog",
"libmedia",
+ "libmedia_codeclist",
"libmedia_omx",
"libmediadrm",
"libmediametrics",
@@ -44,6 +48,7 @@
],
static_libs: [
+ "libplayerservice_datasource",
"libstagefright_nuplayer",
"libstagefright_rtsp",
"libstagefright_timedtext",
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index 1376ccc..05f7365 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -20,9 +20,9 @@
#include <utils/Log.h>
#include <cutils/properties.h>
+#include <datasource/FileSource.h>
#include <media/DataSource.h>
#include <media/IMediaPlayer.h>
-#include <media/stagefright/FileSource.h>
#include <media/stagefright/foundation/ADebug.h>
#include <utils/Errors.h>
#include <utils/misc.h>
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index dfd3933..81ffcbc 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -48,6 +48,7 @@
#include <utils/Vector.h>
#include <codec2/hidl/client.h>
+#include <datasource/HTTPBase.h>
#include <media/IMediaHTTPService.h>
#include <media/IRemoteDisplay.h>
#include <media/IRemoteDisplayClient.h>
@@ -58,9 +59,11 @@
#include <media/AudioTrack.h>
#include <media/MemoryLeakTrackUtil.h>
#include <media/stagefright/InterfaceUtils.h>
+#include <media/stagefright/MediaCodecConstants.h>
#include <media/stagefright/MediaCodecList.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooperRoster.h>
#include <media/stagefright/SurfaceUtils.h>
@@ -80,7 +83,6 @@
#include "TestPlayerStub.h"
#include "nuplayer/NuPlayerDriver.h"
-#include "HTTPBase.h"
static const int kDumpLockRetries = 50;
static const int kDumpLockSleepUs = 20000;
@@ -264,6 +266,172 @@
return ok;
}
+static void dumpCodecDetails(int fd, const sp<IMediaCodecList> &codecList, bool queryDecoders) {
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ const char *codecType = queryDecoders? "Decoder" : "Encoder";
+ snprintf(buffer, SIZE - 1, "\n%s infos by media types:\n"
+ "=============================\n", codecType);
+ result.append(buffer);
+
+ size_t numCodecs = codecList->countCodecs();
+
+ // gather all media types supported by codec class, and link to codecs that support them
+ KeyedVector<AString, Vector<sp<MediaCodecInfo>>> allMediaTypes;
+ for (size_t codec_ix = 0; codec_ix < numCodecs; ++codec_ix) {
+ sp<MediaCodecInfo> info = codecList->getCodecInfo(codec_ix);
+ if (info->isEncoder() == !queryDecoders) {
+ Vector<AString> supportedMediaTypes;
+ info->getSupportedMediaTypes(&supportedMediaTypes);
+ if (!supportedMediaTypes.size()) {
+ snprintf(buffer, SIZE - 1, "warning: %s does not support any media types\n",
+ info->getCodecName());
+ result.append(buffer);
+ } else {
+ for (const AString &mediaType : supportedMediaTypes) {
+ if (allMediaTypes.indexOfKey(mediaType) < 0) {
+ allMediaTypes.add(mediaType, Vector<sp<MediaCodecInfo>>());
+ }
+ allMediaTypes.editValueFor(mediaType).add(info);
+ }
+ }
+ }
+ }
+
+ KeyedVector<AString, bool> visitedCodecs;
+ for (size_t type_ix = 0; type_ix < allMediaTypes.size(); ++type_ix) {
+ const AString &mediaType = allMediaTypes.keyAt(type_ix);
+ snprintf(buffer, SIZE - 1, "\nMedia type '%s':\n", mediaType.c_str());
+ result.append(buffer);
+
+ for (const sp<MediaCodecInfo> &info : allMediaTypes.valueAt(type_ix)) {
+ sp<MediaCodecInfo::Capabilities> caps = info->getCapabilitiesFor(mediaType.c_str());
+ if (caps == NULL) {
+ snprintf(buffer, SIZE - 1, "warning: %s does not have capabilities for type %s\n",
+ info->getCodecName(), mediaType.c_str());
+ result.append(buffer);
+ continue;
+ }
+ snprintf(buffer, SIZE - 1, " %s \"%s\" supports\n",
+ codecType, info->getCodecName());
+ result.append(buffer);
+
+ auto printList = [&](const char *type, const Vector<AString> &values){
+ snprintf(buffer, SIZE - 1, " %s: [", type);
+ result.append(buffer);
+ for (size_t j = 0; j < values.size(); ++j) {
+ snprintf(buffer, SIZE - 1, "\n %s%s", values[j].c_str(),
+ j == values.size() - 1 ? " " : ",");
+ result.append(buffer);
+ }
+ result.append("]\n");
+ };
+
+ if (visitedCodecs.indexOfKey(info->getCodecName()) < 0) {
+ visitedCodecs.add(info->getCodecName(), true);
+ {
+ Vector<AString> aliases;
+ info->getAliases(&aliases);
+ // quote alias
+ for (AString &alias : aliases) {
+ alias.insert("\"", 1, 0);
+ alias.append('"');
+ }
+ printList("aliases", aliases);
+ }
+ {
+ uint32_t attrs = info->getAttributes();
+ Vector<AString> list;
+ list.add(AStringPrintf("encoder: %d",
+ !!(attrs & MediaCodecInfo::kFlagIsEncoder)));
+ list.add(AStringPrintf("vendor: %d",
+ !!(attrs & MediaCodecInfo::kFlagIsVendor)));
+ list.add(AStringPrintf("software-only: %d",
+ !!(attrs & MediaCodecInfo::kFlagIsSoftwareOnly)));
+ list.add(AStringPrintf("hw-accelerated: %d",
+ !!(attrs & MediaCodecInfo::kFlagIsHardwareAccelerated)));
+ printList(AStringPrintf("attributes: %#x", attrs).c_str(), list);
+ }
+
+ snprintf(buffer, SIZE - 1, " owner: \"%s\"\n", info->getOwnerName());
+ result.append(buffer);
+ snprintf(buffer, SIZE - 1, " rank: %u\n", info->getRank());
+ result.append(buffer);
+ } else {
+ result.append(" aliases, attributes, owner, rank: see above\n");
+ }
+
+ {
+ Vector<AString> list;
+ Vector<MediaCodecInfo::ProfileLevel> profileLevels;
+ caps->getSupportedProfileLevels(&profileLevels);
+ for (const MediaCodecInfo::ProfileLevel &pl : profileLevels) {
+ const char *niceProfile =
+ mediaType.equalsIgnoreCase(MIMETYPE_AUDIO_AAC)
+ ? asString_AACObject(pl.mProfile) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_MPEG2)
+ ? asString_MPEG2Profile(pl.mProfile) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_H263)
+ ? asString_H263Profile(pl.mProfile) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_MPEG4)
+ ? asString_MPEG4Profile(pl.mProfile) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_AVC)
+ ? asString_AVCProfile(pl.mProfile) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_VP8)
+ ? asString_VP8Profile(pl.mProfile) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_HEVC)
+ ? asString_HEVCProfile(pl.mProfile) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_VP9)
+ ? asString_VP9Profile(pl.mProfile) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_AV1)
+ ? asString_AV1Profile(pl.mProfile) : "??";
+ const char *niceLevel =
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_MPEG2)
+ ? asString_MPEG2Level(pl.mLevel) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_H263)
+ ? asString_H263Level(pl.mLevel) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_MPEG4)
+ ? asString_MPEG4Level(pl.mLevel) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_AVC)
+ ? asString_AVCLevel(pl.mLevel) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_VP8)
+ ? asString_VP8Level(pl.mLevel) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_HEVC)
+ ? asString_HEVCTierLevel(pl.mLevel) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_VP9)
+ ? asString_VP9Level(pl.mLevel) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_AV1)
+ ? asString_AV1Level(pl.mLevel) : "??";
+
+ list.add(AStringPrintf("% 5u/% 5u (%s/%s)",
+ pl.mProfile, pl.mLevel, niceProfile, niceLevel));
+ }
+ printList("profile/levels", list);
+ }
+
+ {
+ Vector<AString> list;
+ Vector<uint32_t> colors;
+ caps->getSupportedColorFormats(&colors);
+ for (uint32_t color : colors) {
+ list.add(AStringPrintf("%#x (%s)", color,
+ asString_ColorFormat((int32_t)color)));
+ }
+ printList("colors", list);
+ }
+
+ result.append(" details: ");
+ result.append(caps->getDetails()->debugString(6).c_str());
+ result.append("\n");
+ }
+ }
+ result.append("\n");
+ ::write(fd, result.string(), result.size());
+}
+
+
// TODO: Find real cause of Audio/Video delay in PV framework and remove this workaround
/* static */ int MediaPlayerService::AudioOutput::mMinBufferCount = 4;
/* static */ bool MediaPlayerService::AudioOutput::mIsOnEmulator = false;
@@ -423,7 +591,7 @@
SortedVector< sp<MediaRecorderClient> > mediaRecorderClients;
if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
- snprintf(buffer, SIZE, "Permission Denial: "
+ snprintf(buffer, SIZE - 1, "Permission Denial: "
"can't dump MediaPlayerService from pid=%d, uid=%d\n",
IPCThreadState::self()->getCallingPid(),
IPCThreadState::self()->getCallingUid());
@@ -452,11 +620,11 @@
}
result.append(" Files opened and/or mapped:\n");
- snprintf(buffer, SIZE, "/proc/%d/maps", getpid());
+ snprintf(buffer, SIZE - 1, "/proc/%d/maps", getpid());
FILE *f = fopen(buffer, "r");
if (f) {
while (!feof(f)) {
- fgets(buffer, SIZE, f);
+ fgets(buffer, SIZE - 1, f);
if (strstr(buffer, " /storage/") ||
strstr(buffer, " /system/sounds/") ||
strstr(buffer, " /data/") ||
@@ -472,13 +640,13 @@
result.append("\n");
}
- snprintf(buffer, SIZE, "/proc/%d/fd", getpid());
+ snprintf(buffer, SIZE - 1, "/proc/%d/fd", getpid());
DIR *d = opendir(buffer);
if (d) {
struct dirent *ent;
while((ent = readdir(d)) != NULL) {
if (strcmp(ent->d_name,".") && strcmp(ent->d_name,"..")) {
- snprintf(buffer, SIZE, "/proc/%d/fd/%s", getpid(), ent->d_name);
+ snprintf(buffer, SIZE - 1, "/proc/%d/fd/%s", getpid(), ent->d_name);
struct stat s;
if (lstat(buffer, &s) == 0) {
if ((s.st_mode & S_IFMT) == S_IFLNK) {
@@ -521,6 +689,10 @@
gLooperRoster.dump(fd, args);
+ sp<IMediaCodecList> codecList = getCodecList();
+ dumpCodecDetails(fd, codecList, true /* decoders */);
+ dumpCodecDetails(fd, codecList, false /* !decoders */);
+
bool dumpMem = false;
bool unreachableMemory = false;
for (size_t i = 0; i < args.size(); i++) {
@@ -543,6 +715,7 @@
}
}
write(fd, result.string(), result.size());
+
return NO_ERROR;
}
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 49688ce..6431ca1 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -26,15 +26,17 @@
#include <utils/String8.h>
#include <utils/Vector.h>
+#include <media/AudioResamplerPublic.h>
+#include <media/AudioSystem.h>
#include <media/MediaPlayerInterface.h>
#include <media/Metadata.h>
#include <media/stagefright/foundation/ABase.h>
+
#include <system/audio.h>
namespace android {
-struct AudioPlaybackRate;
class AudioTrack;
struct AVSyncSettings;
class DeathNotifier;
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index 703da4b..9b1974b 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -32,6 +32,7 @@
#include <cutils/atomic.h>
#include <cutils/properties.h> // for property_get
#include <gui/IGraphicBufferProducer.h>
+#include <mediautils/ServiceUtilities.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <system/audio.h>
@@ -44,7 +45,6 @@
namespace android {
const char* cameraPermission = "android.permission.CAMERA";
-const char* recordAudioPermission = "android.permission.RECORD_AUDIO";
static bool checkPermission(const char* permissionString) {
if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
@@ -118,7 +118,16 @@
status_t MediaRecorderClient::setAudioSource(int as)
{
ALOGV("setAudioSource(%d)", as);
- if (!checkPermission(recordAudioPermission)) {
+ if (as < AUDIO_SOURCE_DEFAULT
+ || (as >= AUDIO_SOURCE_CNT && as != AUDIO_SOURCE_FM_TUNER)) {
+ ALOGE("Invalid audio source: %d", as);
+ return BAD_VALUE;
+ }
+ pid_t pid = IPCThreadState::self()->getCallingPid();
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+
+ if ((as == AUDIO_SOURCE_FM_TUNER && !captureAudioOutputAllowed(pid, uid))
+ || !recordingAllowed(String16(""), pid, uid)) {
return PERMISSION_DENIED;
}
Mutex::Autolock lock(mLock);
@@ -129,6 +138,29 @@
return mRecorder->setAudioSource((audio_source_t)as);
}
+status_t MediaRecorderClient::setPrivacySensitive(bool privacySensitive)
+{
+ ALOGV("%s(%s)", __func__, privacySensitive ? "true" : "false");
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ ALOGE("%s: recorder is not initialized", __func__);
+ return NO_INIT;
+ }
+ return mRecorder->setPrivacySensitive(privacySensitive);
+}
+
+status_t MediaRecorderClient::isPrivacySensitive(bool *privacySensitive) const
+{
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ ALOGE("%s: recorder is not initialized", __func__);
+ return NO_INIT;
+ }
+ status_t status = mRecorder->isPrivacySensitive(privacySensitive);
+ ALOGV("%s: status: %d enabled: %s", __func__, status, *privacySensitive ? "true" : "false");
+ return status;
+}
+
status_t MediaRecorderClient::setOutputFormat(int of)
{
ALOGV("setOutputFormat(%d)", of);
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index 9e0f877..12257e5 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -51,6 +51,8 @@
virtual status_t setPreviewSurface(const sp<IGraphicBufferProducer>& surface);
virtual status_t setVideoSource(int vs);
virtual status_t setAudioSource(int as);
+ status_t setPrivacySensitive(bool privacySensitive) override;
+ status_t isPrivacySensitive(bool *privacySensitive) const override;
virtual status_t setOutputFormat(int of);
virtual status_t setVideoEncoder(int ve);
virtual status_t setAudioEncoder(int ae);
@@ -98,7 +100,7 @@
sp<AudioDeviceUpdatedNotifier> mAudioDeviceUpdatedNotifier;
pid_t mPid;
- Mutex mLock;
+ mutable Mutex mLock;
MediaRecorderBase *mRecorder;
sp<MediaPlayerService> mMediaPlayerService;
};
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index 40b17bf..fb228ca 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -37,6 +37,7 @@
#include <media/MediaPlayerInterface.h>
#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <private/media/VideoFrame.h>
#include "MetadataRetrieverClient.h"
#include "StagefrightMetadataRetriever.h"
@@ -242,31 +243,27 @@
sp<IMemory> frame = mRetriever->getImageRectAtIndex(
index, colorFormat, left, top, right, bottom);
if (frame == NULL) {
- ALOGE("failed to extract image");
- return NULL;
+ ALOGE("failed to extract image at index %d", index);
}
return frame;
}
-status_t MetadataRetrieverClient::getFrameAtIndex(
- std::vector<sp<IMemory> > *frames,
- int frameIndex, int numFrames, int colorFormat, bool metaOnly) {
- ALOGV("getFrameAtIndex: frameIndex(%d), numFrames(%d), colorFormat(%d), metaOnly(%d)",
- frameIndex, numFrames, colorFormat, metaOnly);
+sp<IMemory> MetadataRetrieverClient::getFrameAtIndex(
+ int index, int colorFormat, bool metaOnly) {
+ ALOGV("getFrameAtIndex: index(%d), colorFormat(%d), metaOnly(%d)",
+ index, colorFormat, metaOnly);
Mutex::Autolock lock(mLock);
Mutex::Autolock glock(sLock);
if (mRetriever == NULL) {
ALOGE("retriever is not initialized");
- return INVALID_OPERATION;
+ return NULL;
}
- status_t err = mRetriever->getFrameAtIndex(
- frames, frameIndex, numFrames, colorFormat, metaOnly);
- if (err != OK) {
- frames->clear();
- return err;
+ sp<IMemory> frame = mRetriever->getFrameAtIndex(index, colorFormat, metaOnly);
+ if (frame == NULL) {
+ ALOGE("failed to extract frame at index %d", index);
}
- return OK;
+ return frame;
}
sp<IMemory> MetadataRetrieverClient::extractAlbumArt()
@@ -296,7 +293,7 @@
delete albumArt;
return NULL;
}
- MediaAlbumArt::init((MediaAlbumArt *) mAlbumArt->pointer(),
+ MediaAlbumArt::init((MediaAlbumArt *) mAlbumArt->unsecurePointer(),
albumArt->size(), albumArt->data());
delete albumArt; // We've taken our copy.
return mAlbumArt;
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.h b/media/libmediaplayerservice/MetadataRetrieverClient.h
index 272d093..8020441 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.h
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.h
@@ -56,9 +56,8 @@
int index, int colorFormat, bool metaOnly, bool thumbnail);
virtual sp<IMemory> getImageRectAtIndex(
int index, int colorFormat, int left, int top, int right, int bottom);
- virtual status_t getFrameAtIndex(
- std::vector<sp<IMemory> > *frames,
- int frameIndex, int numFrames, int colorFormat, bool metaOnly);
+ virtual sp<IMemory> getFrameAtIndex(
+ int index, int colorFormat, bool metaOnly);
virtual sp<IMemory> extractAlbumArt();
virtual const char* extractMetadata(int keyCode);
diff --git a/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
new file mode 100644
index 0000000..41b6f72
--- /dev/null
+++ b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
@@ -0,0 +1,705 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "StagefrightMetadataRetriever"
+
+#include <inttypes.h>
+
+#include <utils/Log.h>
+#include <cutils/properties.h>
+
+#include "StagefrightMetadataRetriever.h"
+#include "FrameDecoder.h"
+
+#include <datasource/PlayerServiceDataSourceFactory.h>
+#include <datasource/PlayerServiceFileSource.h>
+#include <media/IMediaHTTPService.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaCodecList.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaExtractorFactory.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+#include <media/CharacterEncodingDetector.h>
+
+namespace android {
+
+StagefrightMetadataRetriever::StagefrightMetadataRetriever()
+ : mParsedMetaData(false),
+ mAlbumArt(NULL),
+ mLastDecodedIndex(-1) {
+ ALOGV("StagefrightMetadataRetriever()");
+}
+
+StagefrightMetadataRetriever::~StagefrightMetadataRetriever() {
+ ALOGV("~StagefrightMetadataRetriever()");
+ clearMetadata();
+ if (mSource != NULL) {
+ mSource->close();
+ }
+}
+
+status_t StagefrightMetadataRetriever::setDataSource(
+ const sp<IMediaHTTPService> &httpService,
+ const char *uri,
+ const KeyedVector<String8, String8> *headers) {
+ ALOGV("setDataSource(%s)", uri);
+
+ clearMetadata();
+ mSource = PlayerServiceDataSourceFactory::getInstance()->CreateFromURI(
+ httpService, uri, headers);
+
+ if (mSource == NULL) {
+ ALOGE("Unable to create data source for '%s'.", uri);
+ return UNKNOWN_ERROR;
+ }
+
+ mExtractor = MediaExtractorFactory::Create(mSource);
+
+ if (mExtractor == NULL) {
+ ALOGE("Unable to instantiate an extractor for '%s'.", uri);
+
+ mSource.clear();
+
+ return UNKNOWN_ERROR;
+ }
+
+ return OK;
+}
+
+// Warning caller retains ownership of the filedescriptor! Dup it if necessary.
+status_t StagefrightMetadataRetriever::setDataSource(
+ int fd, int64_t offset, int64_t length) {
+ fd = dup(fd);
+
+ ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
+
+ clearMetadata();
+ mSource = new PlayerServiceFileSource(fd, offset, length);
+
+ status_t err;
+ if ((err = mSource->initCheck()) != OK) {
+ mSource.clear();
+
+ return err;
+ }
+
+ mExtractor = MediaExtractorFactory::Create(mSource);
+
+ if (mExtractor == NULL) {
+ mSource.clear();
+
+ return UNKNOWN_ERROR;
+ }
+
+ return OK;
+}
+
+status_t StagefrightMetadataRetriever::setDataSource(
+ const sp<DataSource>& source, const char *mime) {
+ ALOGV("setDataSource(DataSource)");
+
+ clearMetadata();
+ mSource = source;
+ mExtractor = MediaExtractorFactory::Create(mSource, mime);
+
+ if (mExtractor == NULL) {
+ ALOGE("Failed to instantiate a MediaExtractor.");
+ mSource.clear();
+ return UNKNOWN_ERROR;
+ }
+
+ return OK;
+}
+
+sp<IMemory> StagefrightMetadataRetriever::getImageAtIndex(
+ int index, int colorFormat, bool metaOnly, bool thumbnail) {
+ ALOGV("getImageAtIndex: index(%d) colorFormat(%d) metaOnly(%d) thumbnail(%d)",
+ index, colorFormat, metaOnly, thumbnail);
+
+ return getImageInternal(index, colorFormat, metaOnly, thumbnail, NULL);
+}
+
+sp<IMemory> StagefrightMetadataRetriever::getImageRectAtIndex(
+ int index, int colorFormat, int left, int top, int right, int bottom) {
+ ALOGV("getImageRectAtIndex: index(%d) colorFormat(%d) rect {%d, %d, %d, %d}",
+ index, colorFormat, left, top, right, bottom);
+
+ FrameRect rect = {left, top, right, bottom};
+
+ if (mDecoder != NULL && index == mLastDecodedIndex) {
+ return mDecoder->extractFrame(&rect);
+ }
+
+ return getImageInternal(
+ index, colorFormat, false /*metaOnly*/, false /*thumbnail*/, &rect);
+}
+
+sp<IMemory> StagefrightMetadataRetriever::getImageInternal(
+ int index, int colorFormat, bool metaOnly, bool thumbnail, FrameRect* rect) {
+ mDecoder.clear();
+ mLastDecodedIndex = -1;
+
+ if (mExtractor.get() == NULL) {
+ ALOGE("no extractor.");
+ return NULL;
+ }
+
+ size_t n = mExtractor->countTracks();
+ size_t i;
+ int imageCount = 0;
+
+ for (i = 0; i < n; ++i) {
+ sp<MetaData> meta = mExtractor->getTrackMetaData(i);
+ if (!meta) {
+ continue;
+ }
+ ALOGV("getting track %zu of %zu, meta=%s", i, n, meta->toString().c_str());
+
+ const char *mime;
+ CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+ if (!strncasecmp(mime, "image/", 6)) {
+ int32_t isPrimary;
+ if ((index < 0 && meta->findInt32(
+ kKeyTrackIsDefault, &isPrimary) && isPrimary)
+ || (index == imageCount++)) {
+ break;
+ }
+ }
+ }
+
+ if (i == n) {
+ ALOGE("image track not found.");
+ return NULL;
+ }
+
+ sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i);
+ if (!trackMeta) {
+ return NULL;
+ }
+
+ if (metaOnly) {
+ return FrameDecoder::getMetadataOnly(trackMeta, colorFormat, thumbnail);
+ }
+
+ sp<IMediaSource> source = mExtractor->getTrack(i);
+
+ if (source.get() == NULL) {
+ ALOGE("unable to instantiate image track.");
+ return NULL;
+ }
+
+ const char *mime;
+ CHECK(trackMeta->findCString(kKeyMIMEType, &mime));
+ ALOGV("extracting from %s track", mime);
+ if (!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC)) {
+ mime = MEDIA_MIMETYPE_VIDEO_HEVC;
+ trackMeta = new MetaData(*trackMeta);
+ trackMeta->setCString(kKeyMIMEType, mime);
+ }
+
+ bool preferhw = property_get_bool(
+ "media.stagefright.thumbnail.prefer_hw_codecs", false);
+ uint32_t flags = preferhw ? 0 : MediaCodecList::kPreferSoftwareCodecs;
+ Vector<AString> matchingCodecs;
+ MediaCodecList::findMatchingCodecs(
+ mime,
+ false, /* encoder */
+ flags,
+ &matchingCodecs);
+
+ for (size_t i = 0; i < matchingCodecs.size(); ++i) {
+ const AString &componentName = matchingCodecs[i];
+ sp<ImageDecoder> decoder = new ImageDecoder(componentName, trackMeta, source);
+ int64_t frameTimeUs = thumbnail ? -1 : 0;
+ if (decoder->init(frameTimeUs, 0 /*option*/, colorFormat) == OK) {
+ sp<IMemory> frame = decoder->extractFrame(rect);
+
+ if (frame != NULL) {
+ if (rect != NULL) {
+ // keep the decoder if slice decoding
+ mDecoder = decoder;
+ mLastDecodedIndex = index;
+ }
+ return frame;
+ }
+ }
+ ALOGV("%s failed to extract thumbnail, trying next decoder.", componentName.c_str());
+ }
+
+ ALOGE("all codecs failed to extract frame.");
+ return NULL;
+}
+
+sp<IMemory> StagefrightMetadataRetriever::getFrameAtTime(
+ int64_t timeUs, int option, int colorFormat, bool metaOnly) {
+ ALOGV("getFrameAtTime: %" PRId64 " us option: %d colorFormat: %d, metaOnly: %d",
+ timeUs, option, colorFormat, metaOnly);
+
+ return getFrameInternal(timeUs, option, colorFormat, metaOnly);
+}
+
+sp<IMemory> StagefrightMetadataRetriever::getFrameAtIndex(
+ int frameIndex, int colorFormat, bool metaOnly) {
+ ALOGV("getFrameAtIndex: frameIndex %d, colorFormat: %d, metaOnly: %d",
+ frameIndex, colorFormat, metaOnly);
+ if (mDecoder != NULL && frameIndex == mLastDecodedIndex + 1) {
+ sp<IMemory> frame = mDecoder->extractFrame();
+ if (frame != nullptr) {
+ mLastDecodedIndex = frameIndex;
+ }
+ return frame;
+ }
+
+ return getFrameInternal(frameIndex,
+ MediaSource::ReadOptions::SEEK_FRAME_INDEX, colorFormat, metaOnly);
+}
+
+sp<IMemory> StagefrightMetadataRetriever::getFrameInternal(
+ int64_t timeUs, int option, int colorFormat, bool metaOnly) {
+ mDecoder.clear();
+ mLastDecodedIndex = -1;
+
+ if (mExtractor.get() == NULL) {
+ ALOGE("no extractor.");
+ return NULL;
+ }
+
+ sp<MetaData> fileMeta = mExtractor->getMetaData();
+
+ if (fileMeta == NULL) {
+ ALOGE("extractor doesn't publish metadata, failed to initialize?");
+ return NULL;
+ }
+
+ size_t n = mExtractor->countTracks();
+ size_t i;
+ for (i = 0; i < n; ++i) {
+ sp<MetaData> meta = mExtractor->getTrackMetaData(i);
+ if (!meta) {
+ continue;
+ }
+
+ const char *mime;
+ CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+ if (!strncasecmp(mime, "video/", 6)) {
+ break;
+ }
+ }
+
+ if (i == n) {
+ ALOGE("no video track found.");
+ return NULL;
+ }
+
+ sp<MetaData> trackMeta = mExtractor->getTrackMetaData(
+ i, MediaExtractor::kIncludeExtensiveMetaData);
+ if (!trackMeta) {
+ return NULL;
+ }
+
+ if (metaOnly) {
+ return FrameDecoder::getMetadataOnly(trackMeta, colorFormat);
+ }
+
+ sp<IMediaSource> source = mExtractor->getTrack(i);
+
+ if (source.get() == NULL) {
+ ALOGV("unable to instantiate video track.");
+ return NULL;
+ }
+
+ const void *data;
+ uint32_t type;
+ size_t dataSize;
+ if (fileMeta->findData(kKeyAlbumArt, &type, &data, &dataSize)
+ && mAlbumArt == NULL) {
+ mAlbumArt = MediaAlbumArt::fromData(dataSize, data);
+ }
+
+ const char *mime;
+ CHECK(trackMeta->findCString(kKeyMIMEType, &mime));
+
+ bool preferhw = property_get_bool(
+ "media.stagefright.thumbnail.prefer_hw_codecs", false);
+ uint32_t flags = preferhw ? 0 : MediaCodecList::kPreferSoftwareCodecs;
+ Vector<AString> matchingCodecs;
+ MediaCodecList::findMatchingCodecs(
+ mime,
+ false, /* encoder */
+ flags,
+ &matchingCodecs);
+
+ for (size_t i = 0; i < matchingCodecs.size(); ++i) {
+ const AString &componentName = matchingCodecs[i];
+ sp<VideoFrameDecoder> decoder = new VideoFrameDecoder(componentName, trackMeta, source);
+ if (decoder->init(timeUs, option, colorFormat) == OK) {
+ sp<IMemory> frame = decoder->extractFrame();
+ if (frame != nullptr) {
+ // keep the decoder if seeking by frame index
+ if (option == MediaSource::ReadOptions::SEEK_FRAME_INDEX) {
+ mDecoder = decoder;
+ mLastDecodedIndex = timeUs;
+ }
+ return frame;
+ }
+ }
+ ALOGV("%s failed to extract frame, trying next decoder.", componentName.c_str());
+ }
+
+ ALOGE("all codecs failed to extract frame.");
+ return NULL;
+}
+
+MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() {
+ ALOGV("extractAlbumArt (extractor: %s)", mExtractor.get() != NULL ? "YES" : "NO");
+
+ if (mExtractor == NULL) {
+ return NULL;
+ }
+
+ if (!mParsedMetaData) {
+ parseMetaData();
+
+ mParsedMetaData = true;
+ }
+
+ if (mAlbumArt) {
+ return mAlbumArt->clone();
+ }
+
+ return NULL;
+}
+
+const char *StagefrightMetadataRetriever::extractMetadata(int keyCode) {
+ if (mExtractor == NULL) {
+ return NULL;
+ }
+
+ if (!mParsedMetaData) {
+ parseMetaData();
+
+ mParsedMetaData = true;
+ }
+
+ ssize_t index = mMetaData.indexOfKey(keyCode);
+
+ if (index < 0) {
+ return NULL;
+ }
+
+ return mMetaData.valueAt(index).string();
+}
+
+void StagefrightMetadataRetriever::parseColorAspects(const sp<MetaData>& meta) {
+ sp<AMessage> format = new AMessage();
+ if (convertMetaDataToMessage(meta, &format) != OK) {
+ return;
+ }
+
+ int32_t standard, transfer, range;
+ if (format->findInt32("color-standard", &standard)
+ && format->findInt32("color-transfer", &transfer)
+ && format->findInt32("color-range", &range)) {
+ ALOGV("found color aspects : standard=%d, transfer=%d, range=%d",
+ standard, transfer, range);
+
+ mMetaData.add(METADATA_KEY_COLOR_STANDARD, String8::format("%d", standard));
+ mMetaData.add(METADATA_KEY_COLOR_TRANSFER, String8::format("%d", transfer));
+ mMetaData.add(METADATA_KEY_COLOR_RANGE, String8::format("%d", range));
+ }
+}
+
+void StagefrightMetadataRetriever::parseMetaData() {
+ sp<MetaData> meta = mExtractor->getMetaData();
+
+ if (meta == NULL) {
+ ALOGV("extractor doesn't publish metadata, failed to initialize?");
+ return;
+ }
+
+ struct Map {
+ int from;
+ int to;
+ const char *name;
+ };
+ static const Map kMap[] = {
+ { kKeyMIMEType, METADATA_KEY_MIMETYPE, NULL },
+ { kKeyCDTrackNumber, METADATA_KEY_CD_TRACK_NUMBER, "tracknumber" },
+ { kKeyDiscNumber, METADATA_KEY_DISC_NUMBER, "discnumber" },
+ { kKeyAlbum, METADATA_KEY_ALBUM, "album" },
+ { kKeyArtist, METADATA_KEY_ARTIST, "artist" },
+ { kKeyAlbumArtist, METADATA_KEY_ALBUMARTIST, "albumartist" },
+ { kKeyAuthor, METADATA_KEY_AUTHOR, NULL },
+ { kKeyComposer, METADATA_KEY_COMPOSER, "composer" },
+ { kKeyDate, METADATA_KEY_DATE, NULL },
+ { kKeyGenre, METADATA_KEY_GENRE, "genre" },
+ { kKeyTitle, METADATA_KEY_TITLE, "title" },
+ { kKeyYear, METADATA_KEY_YEAR, "year" },
+ { kKeyWriter, METADATA_KEY_WRITER, "writer" },
+ { kKeyCompilation, METADATA_KEY_COMPILATION, "compilation" },
+ { kKeyLocation, METADATA_KEY_LOCATION, NULL },
+ };
+
+ static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]);
+
+ CharacterEncodingDetector *detector = new CharacterEncodingDetector();
+
+ for (size_t i = 0; i < kNumMapEntries; ++i) {
+ const char *value;
+ if (meta->findCString(kMap[i].from, &value)) {
+ if (kMap[i].name) {
+ // add to charset detector
+ detector->addTag(kMap[i].name, value);
+ } else {
+ // directly add to output list
+ mMetaData.add(kMap[i].to, String8(value));
+ }
+ }
+ }
+
+ detector->detectAndConvert();
+ int size = detector->size();
+ if (size) {
+ for (int i = 0; i < size; i++) {
+ const char *name;
+ const char *value;
+ detector->getTag(i, &name, &value);
+ for (size_t j = 0; j < kNumMapEntries; ++j) {
+ if (kMap[j].name && !strcmp(kMap[j].name, name)) {
+ mMetaData.add(kMap[j].to, String8(value));
+ }
+ }
+ }
+ }
+ delete detector;
+
+ const void *data;
+ uint32_t type;
+ size_t dataSize;
+ if (meta->findData(kKeyAlbumArt, &type, &data, &dataSize)
+ && mAlbumArt == NULL) {
+ mAlbumArt = MediaAlbumArt::fromData(dataSize, data);
+ }
+
+ size_t numTracks = mExtractor->countTracks();
+
+ char tmp[32];
+ sprintf(tmp, "%zu", numTracks);
+
+ mMetaData.add(METADATA_KEY_NUM_TRACKS, String8(tmp));
+
+ float captureFps;
+ if (meta->findFloat(kKeyCaptureFramerate, &captureFps)) {
+ sprintf(tmp, "%f", captureFps);
+ mMetaData.add(METADATA_KEY_CAPTURE_FRAMERATE, String8(tmp));
+ }
+
+ int64_t exifOffset, exifSize;
+ if (meta->findInt64(kKeyExifOffset, &exifOffset)
+ && meta->findInt64(kKeyExifSize, &exifSize)) {
+ sprintf(tmp, "%lld", (long long)exifOffset);
+ mMetaData.add(METADATA_KEY_EXIF_OFFSET, String8(tmp));
+ sprintf(tmp, "%lld", (long long)exifSize);
+ mMetaData.add(METADATA_KEY_EXIF_LENGTH, String8(tmp));
+ }
+
+ bool hasAudio = false;
+ bool hasVideo = false;
+ int32_t videoWidth = -1;
+ int32_t videoHeight = -1;
+ int32_t videoFrameCount = 0;
+ int32_t audioBitrate = -1;
+ int32_t rotationAngle = -1;
+ int32_t imageCount = 0;
+ int32_t imagePrimary = 0;
+ int32_t imageWidth = -1;
+ int32_t imageHeight = -1;
+ int32_t imageRotation = -1;
+
+ // The overall duration is the duration of the longest track.
+ int64_t maxDurationUs = 0;
+ String8 timedTextLang;
+ for (size_t i = 0; i < numTracks; ++i) {
+ sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i);
+ if (!trackMeta) {
+ continue;
+ }
+
+ int64_t durationUs;
+ if (trackMeta->findInt64(kKeyDuration, &durationUs)) {
+ if (durationUs > maxDurationUs) {
+ maxDurationUs = durationUs;
+ }
+ }
+
+ const char *mime;
+ if (trackMeta->findCString(kKeyMIMEType, &mime)) {
+ if (!hasAudio && !strncasecmp("audio/", mime, 6)) {
+ hasAudio = true;
+
+ if (!trackMeta->findInt32(kKeyBitRate, &audioBitrate)) {
+ audioBitrate = -1;
+ }
+
+ int32_t bitsPerSample = -1;
+ int32_t sampleRate = -1;
+ trackMeta->findInt32(kKeyBitsPerSample, &bitsPerSample);
+ trackMeta->findInt32(kKeySampleRate, &sampleRate);
+ if (bitsPerSample >= 0) {
+ sprintf(tmp, "%d", bitsPerSample);
+ mMetaData.add(METADATA_KEY_BITS_PER_SAMPLE, String8(tmp));
+ }
+ if (sampleRate >= 0) {
+ sprintf(tmp, "%d", sampleRate);
+ mMetaData.add(METADATA_KEY_SAMPLERATE, String8(tmp));
+ }
+ } else if (!hasVideo && !strncasecmp("video/", mime, 6)) {
+ hasVideo = true;
+
+ CHECK(trackMeta->findInt32(kKeyWidth, &videoWidth));
+ CHECK(trackMeta->findInt32(kKeyHeight, &videoHeight));
+ if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
+ rotationAngle = 0;
+ }
+ if (!trackMeta->findInt32(kKeyFrameCount, &videoFrameCount)) {
+ videoFrameCount = 0;
+ }
+
+ parseColorAspects(trackMeta);
+ } else if (!strncasecmp("image/", mime, 6)) {
+ int32_t isPrimary;
+ if (trackMeta->findInt32(
+ kKeyTrackIsDefault, &isPrimary) && isPrimary) {
+ imagePrimary = imageCount;
+ CHECK(trackMeta->findInt32(kKeyWidth, &imageWidth));
+ CHECK(trackMeta->findInt32(kKeyHeight, &imageHeight));
+ if (!trackMeta->findInt32(kKeyRotation, &imageRotation)) {
+ imageRotation = 0;
+ }
+ }
+ imageCount++;
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
+ const char *lang;
+ if (trackMeta->findCString(kKeyMediaLanguage, &lang)) {
+ timedTextLang.append(String8(lang));
+ timedTextLang.append(String8(":"));
+ } else {
+ ALOGE("No language found for timed text");
+ }
+ }
+ }
+ }
+
+ // To save the language codes for all timed text tracks
+ // If multiple text tracks present, the format will look
+ // like "eng:chi"
+ if (!timedTextLang.isEmpty()) {
+ mMetaData.add(METADATA_KEY_TIMED_TEXT_LANGUAGES, timedTextLang);
+ }
+
+ // The duration value is a string representing the duration in ms.
+ sprintf(tmp, "%" PRId64, (maxDurationUs + 500) / 1000);
+ mMetaData.add(METADATA_KEY_DURATION, String8(tmp));
+
+ if (hasAudio) {
+ mMetaData.add(METADATA_KEY_HAS_AUDIO, String8("yes"));
+ }
+
+ if (hasVideo) {
+ mMetaData.add(METADATA_KEY_HAS_VIDEO, String8("yes"));
+
+ sprintf(tmp, "%d", videoWidth);
+ mMetaData.add(METADATA_KEY_VIDEO_WIDTH, String8(tmp));
+
+ sprintf(tmp, "%d", videoHeight);
+ mMetaData.add(METADATA_KEY_VIDEO_HEIGHT, String8(tmp));
+
+ sprintf(tmp, "%d", rotationAngle);
+ mMetaData.add(METADATA_KEY_VIDEO_ROTATION, String8(tmp));
+
+ if (videoFrameCount > 0) {
+ sprintf(tmp, "%d", videoFrameCount);
+ mMetaData.add(METADATA_KEY_VIDEO_FRAME_COUNT, String8(tmp));
+ }
+ }
+
+ if (imageCount > 0) {
+ mMetaData.add(METADATA_KEY_HAS_IMAGE, String8("yes"));
+
+ sprintf(tmp, "%d", imageCount);
+ mMetaData.add(METADATA_KEY_IMAGE_COUNT, String8(tmp));
+
+ sprintf(tmp, "%d", imagePrimary);
+ mMetaData.add(METADATA_KEY_IMAGE_PRIMARY, String8(tmp));
+
+ sprintf(tmp, "%d", imageWidth);
+ mMetaData.add(METADATA_KEY_IMAGE_WIDTH, String8(tmp));
+
+ sprintf(tmp, "%d", imageHeight);
+ mMetaData.add(METADATA_KEY_IMAGE_HEIGHT, String8(tmp));
+
+ sprintf(tmp, "%d", imageRotation);
+ mMetaData.add(METADATA_KEY_IMAGE_ROTATION, String8(tmp));
+ }
+
+ if (numTracks == 1 && hasAudio && audioBitrate >= 0) {
+ sprintf(tmp, "%d", audioBitrate);
+ mMetaData.add(METADATA_KEY_BITRATE, String8(tmp));
+ } else {
+ off64_t sourceSize;
+ if (mSource != NULL && mSource->getSize(&sourceSize) == OK) {
+ int64_t avgBitRate = (int64_t)(sourceSize * 8E6 / maxDurationUs);
+
+ sprintf(tmp, "%" PRId64, avgBitRate);
+ mMetaData.add(METADATA_KEY_BITRATE, String8(tmp));
+ }
+ }
+
+ if (numTracks == 1) {
+ const char *fileMIME;
+
+ if (meta->findCString(kKeyMIMEType, &fileMIME) &&
+ !strcasecmp(fileMIME, "video/x-matroska")) {
+ sp<MetaData> trackMeta = mExtractor->getTrackMetaData(0);
+ const char *trackMIME;
+ if (trackMeta != nullptr) {
+ CHECK(trackMeta->findCString(kKeyMIMEType, &trackMIME));
+ }
+ if (!strncasecmp("audio/", trackMIME, 6)) {
+ // The matroska file only contains a single audio track,
+ // rewrite its mime type.
+ mMetaData.add(
+ METADATA_KEY_MIMETYPE, String8("audio/x-matroska"));
+ }
+ }
+ }
+}
+
+void StagefrightMetadataRetriever::clearMetadata() {
+ mParsedMetaData = false;
+ mMetaData.clear();
+ delete mAlbumArt;
+ mAlbumArt = NULL;
+}
+
+} // namespace android
diff --git a/media/libmediaplayerservice/StagefrightMetadataRetriever.h b/media/libmediaplayerservice/StagefrightMetadataRetriever.h
new file mode 100644
index 0000000..c09a501
--- /dev/null
+++ b/media/libmediaplayerservice/StagefrightMetadataRetriever.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STAGEFRIGHT_METADATA_RETRIEVER_H_
+
+#define STAGEFRIGHT_METADATA_RETRIEVER_H_
+
+#include <android/IMediaExtractor.h>
+#include <media/MediaMetadataRetrieverInterface.h>
+
+#include <utils/KeyedVector.h>
+
+namespace android {
+
+class DataSource;
+struct FrameDecoder;
+struct FrameRect;
+
+struct StagefrightMetadataRetriever : public MediaMetadataRetrieverBase {
+ StagefrightMetadataRetriever();
+ virtual ~StagefrightMetadataRetriever();
+
+ virtual status_t setDataSource(
+ const sp<IMediaHTTPService> &httpService,
+ const char *url,
+ const KeyedVector<String8, String8> *headers);
+
+ virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
+ virtual status_t setDataSource(const sp<DataSource>& source, const char *mime);
+
+ virtual sp<IMemory> getFrameAtTime(
+ int64_t timeUs, int option, int colorFormat, bool metaOnly);
+ virtual sp<IMemory> getImageAtIndex(
+ int index, int colorFormat, bool metaOnly, bool thumbnail);
+ virtual sp<IMemory> getImageRectAtIndex(
+ int index, int colorFormat, int left, int top, int right, int bottom);
+ virtual sp<IMemory> getFrameAtIndex(
+ int index, int colorFormat, bool metaOnly);
+
+ virtual MediaAlbumArt *extractAlbumArt();
+ virtual const char *extractMetadata(int keyCode);
+
+private:
+ sp<DataSource> mSource;
+ sp<IMediaExtractor> mExtractor;
+
+ bool mParsedMetaData;
+ KeyedVector<int, String8> mMetaData;
+ MediaAlbumArt *mAlbumArt;
+
+ sp<FrameDecoder> mDecoder;
+ int mLastDecodedIndex;
+ void parseMetaData();
+ void parseColorAspects(const sp<MetaData>& meta);
+ // Delete album art and clear metadata.
+ void clearMetadata();
+
+ sp<IMemory> getFrameInternal(
+ int64_t timeUs, int option, int colorFormat, bool metaOnly);
+
+ sp<IMemory> getImageInternal(
+ int index, int colorFormat, bool metaOnly, bool thumbnail, FrameRect* rect);
+
+ StagefrightMetadataRetriever(const StagefrightMetadataRetriever &);
+
+ StagefrightMetadataRetriever &operator=(
+ const StagefrightMetadataRetriever &);
+};
+
+} // namespace android
+
+#endif // STAGEFRIGHT_METADATA_RETRIEVER_H_
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 63681fa..cf7f423 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -31,7 +31,7 @@
#include <binder/IServiceManager.h>
#include <media/IMediaPlayerService.h>
-#include <media/MediaAnalyticsItem.h>
+#include <media/MediaMetricsItem.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
@@ -115,6 +115,7 @@
mWriter(NULL),
mOutputFd(-1),
mAudioSource((audio_source_t)AUDIO_SOURCE_CNT), // initialize with invalid value
+ mPrivacySensitive(PRIVACY_SENSITIVE_DEFAULT),
mVideoSource(VIDEO_SOURCE_LIST_END),
mStarted(false),
mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
@@ -137,7 +138,7 @@
}
// log the current record, provided it has some information worth recording
- // NB: this also reclaims & clears mAnalyticsItem.
+ // NB: this also reclaims & clears mMetricsItem.
flushAndResetMetrics(false);
}
@@ -146,69 +147,69 @@
// we run as part of the media player service; what we really want to
// know is the app which requested the recording.
- mAnalyticsItem->setUid(mClientUid);
+ mMetricsItem->setUid(mClientUid);
// populate the values from the raw fields.
// TBD mOutputFormat = OUTPUT_FORMAT_THREE_GPP;
// TBD mAudioEncoder = AUDIO_ENCODER_AMR_NB;
// TBD mVideoEncoder = VIDEO_ENCODER_DEFAULT;
- mAnalyticsItem->setInt32(kRecorderHeight, mVideoHeight);
- mAnalyticsItem->setInt32(kRecorderWidth, mVideoWidth);
- mAnalyticsItem->setInt32(kRecorderFrameRate, mFrameRate);
- mAnalyticsItem->setInt32(kRecorderVideoBitrate, mVideoBitRate);
- mAnalyticsItem->setInt32(kRecorderAudioSampleRate, mSampleRate);
- mAnalyticsItem->setInt32(kRecorderAudioChannels, mAudioChannels);
- mAnalyticsItem->setInt32(kRecorderAudioBitrate, mAudioBitRate);
+ mMetricsItem->setInt32(kRecorderHeight, mVideoHeight);
+ mMetricsItem->setInt32(kRecorderWidth, mVideoWidth);
+ mMetricsItem->setInt32(kRecorderFrameRate, mFrameRate);
+ mMetricsItem->setInt32(kRecorderVideoBitrate, mVideoBitRate);
+ mMetricsItem->setInt32(kRecorderAudioSampleRate, mSampleRate);
+ mMetricsItem->setInt32(kRecorderAudioChannels, mAudioChannels);
+ mMetricsItem->setInt32(kRecorderAudioBitrate, mAudioBitRate);
// TBD mInterleaveDurationUs = 0;
- mAnalyticsItem->setInt32(kRecorderVideoIframeInterval, mIFramesIntervalSec);
+ mMetricsItem->setInt32(kRecorderVideoIframeInterval, mIFramesIntervalSec);
// TBD mAudioSourceNode = 0;
// TBD mUse64BitFileOffset = false;
if (mMovieTimeScale != -1)
- mAnalyticsItem->setInt32(kRecorderMovieTimescale, mMovieTimeScale);
+ mMetricsItem->setInt32(kRecorderMovieTimescale, mMovieTimeScale);
if (mAudioTimeScale != -1)
- mAnalyticsItem->setInt32(kRecorderAudioTimescale, mAudioTimeScale);
+ mMetricsItem->setInt32(kRecorderAudioTimescale, mAudioTimeScale);
if (mVideoTimeScale != -1)
- mAnalyticsItem->setInt32(kRecorderVideoTimescale, mVideoTimeScale);
+ mMetricsItem->setInt32(kRecorderVideoTimescale, mVideoTimeScale);
// TBD mCameraId = 0;
// TBD mStartTimeOffsetMs = -1;
- mAnalyticsItem->setInt32(kRecorderVideoProfile, mVideoEncoderProfile);
- mAnalyticsItem->setInt32(kRecorderVideoLevel, mVideoEncoderLevel);
+ mMetricsItem->setInt32(kRecorderVideoProfile, mVideoEncoderProfile);
+ mMetricsItem->setInt32(kRecorderVideoLevel, mVideoEncoderLevel);
// TBD mMaxFileDurationUs = 0;
// TBD mMaxFileSizeBytes = 0;
// TBD mTrackEveryTimeDurationUs = 0;
- mAnalyticsItem->setInt32(kRecorderCaptureFpsEnable, mCaptureFpsEnable);
- mAnalyticsItem->setDouble(kRecorderCaptureFps, mCaptureFps);
+ mMetricsItem->setInt32(kRecorderCaptureFpsEnable, mCaptureFpsEnable);
+ mMetricsItem->setDouble(kRecorderCaptureFps, mCaptureFps);
// TBD mCameraSourceTimeLapse = NULL;
// TBD mMetaDataStoredInVideoBuffers = kMetadataBufferTypeInvalid;
// TBD mEncoderProfiles = MediaProfiles::getInstance();
- mAnalyticsItem->setInt32(kRecorderRotation, mRotationDegrees);
+ mMetricsItem->setInt32(kRecorderRotation, mRotationDegrees);
// PII mLatitudex10000 = -3600000;
// PII mLongitudex10000 = -3600000;
// TBD mTotalBitRate = 0;
// duration information (recorded, paused, # of pauses)
- mAnalyticsItem->setInt64(kRecorderDurationMs, (mDurationRecordedUs+500)/1000 );
+ mMetricsItem->setInt64(kRecorderDurationMs, (mDurationRecordedUs+500)/1000 );
if (mNPauses != 0) {
- mAnalyticsItem->setInt64(kRecorderPaused, (mDurationPausedUs+500)/1000 );
- mAnalyticsItem->setInt32(kRecorderNumPauses, mNPauses);
+ mMetricsItem->setInt64(kRecorderPaused, (mDurationPausedUs+500)/1000 );
+ mMetricsItem->setInt32(kRecorderNumPauses, mNPauses);
}
}
void StagefrightRecorder::flushAndResetMetrics(bool reinitialize) {
ALOGV("flushAndResetMetrics");
// flush anything we have, maybe setup a new record
- if (mAnalyticsDirty && mAnalyticsItem != NULL) {
+ if (mAnalyticsDirty && mMetricsItem != NULL) {
updateMetrics();
- if (mAnalyticsItem->count() > 0) {
- mAnalyticsItem->selfrecord();
+ if (mMetricsItem->count() > 0) {
+ mMetricsItem->selfrecord();
}
- delete mAnalyticsItem;
- mAnalyticsItem = NULL;
+ delete mMetricsItem;
+ mMetricsItem = NULL;
}
mAnalyticsDirty = false;
if (reinitialize) {
- mAnalyticsItem = MediaAnalyticsItem::create(kKeyRecorder);
+ mMetricsItem = mediametrics::Item::create(kKeyRecorder);
}
}
@@ -232,18 +233,37 @@
status_t StagefrightRecorder::setAudioSource(audio_source_t as) {
ALOGV("setAudioSource: %d", as);
- if (as < AUDIO_SOURCE_DEFAULT ||
- (as >= AUDIO_SOURCE_CNT && as != AUDIO_SOURCE_FM_TUNER)) {
- ALOGE("Invalid audio source: %d", as);
- return BAD_VALUE;
- }
if (as == AUDIO_SOURCE_DEFAULT) {
mAudioSource = AUDIO_SOURCE_MIC;
} else {
mAudioSource = as;
}
+ // Reset privacy sensitive in case this is the second time audio source is set
+ mPrivacySensitive = PRIVACY_SENSITIVE_DEFAULT;
+ return OK;
+}
+status_t StagefrightRecorder::setPrivacySensitive(bool privacySensitive) {
+ // privacy sensitive cannot be set before audio source is set
+ if (mAudioSource == AUDIO_SOURCE_CNT) {
+ return INVALID_OPERATION;
+ }
+ mPrivacySensitive = privacySensitive ? PRIVACY_SENSITIVE_ENABLED : PRIVACY_SENSITIVE_DISABLED;
+ return OK;
+}
+
+status_t StagefrightRecorder::isPrivacySensitive(bool *privacySensitive) const {
+ *privacySensitive = false;
+ if (mAudioSource == AUDIO_SOURCE_CNT) {
+ return INVALID_OPERATION;
+ }
+ if (mPrivacySensitive == PRIVACY_SENSITIVE_DEFAULT) {
+ *privacySensitive = mAudioSource == AUDIO_SOURCE_VOICE_COMMUNICATION
+ || mAudioSource == AUDIO_SOURCE_CAMCORDER;
+ } else {
+ *privacySensitive = mPrivacySensitive == PRIVACY_SENSITIVE_ENABLED;
+ }
return OK;
}
@@ -1087,9 +1107,35 @@
}
}
+ audio_attributes_t attr = AUDIO_ATTRIBUTES_INITIALIZER;
+ attr.source = mAudioSource;
+ // attr.flags AUDIO_FLAG_CAPTURE_PRIVATE is cleared by default
+ if (mPrivacySensitive == PRIVACY_SENSITIVE_DEFAULT) {
+ if (attr.source == AUDIO_SOURCE_VOICE_COMMUNICATION
+ || attr.source == AUDIO_SOURCE_CAMCORDER) {
+ attr.flags |= AUDIO_FLAG_CAPTURE_PRIVATE;
+ mPrivacySensitive = PRIVACY_SENSITIVE_ENABLED;
+ } else {
+ mPrivacySensitive = PRIVACY_SENSITIVE_DISABLED;
+ }
+ } else {
+ if (mAudioSource == AUDIO_SOURCE_REMOTE_SUBMIX
+ || mAudioSource == AUDIO_SOURCE_FM_TUNER
+ || mAudioSource == AUDIO_SOURCE_VOICE_DOWNLINK
+ || mAudioSource == AUDIO_SOURCE_VOICE_UPLINK
+ || mAudioSource == AUDIO_SOURCE_VOICE_CALL
+ || mAudioSource == AUDIO_SOURCE_ECHO_REFERENCE) {
+ ALOGE("Cannot request private capture with source: %d", mAudioSource);
+ return NULL;
+ }
+ if (mPrivacySensitive == PRIVACY_SENSITIVE_ENABLED) {
+ attr.flags |= AUDIO_FLAG_CAPTURE_PRIVATE;
+ }
+ }
+
sp<AudioSource> audioSource =
new AudioSource(
- mAudioSource,
+ &attr,
mOpPackageName,
sourceSampleRate,
mAudioChannels,
@@ -1138,10 +1184,10 @@
}
// log audio mime type for media metrics
- if (mAnalyticsItem != NULL) {
+ if (mMetricsItem != NULL) {
AString audiomime;
if (format->findString("mime", &audiomime)) {
- mAnalyticsItem->setCString(kRecorderAudioMime, audiomime.c_str());
+ mMetricsItem->setCString(kRecorderAudioMime, audiomime.c_str());
}
}
@@ -1699,10 +1745,10 @@
}
// log video mime type for media metrics
- if (mAnalyticsItem != NULL) {
+ if (mMetricsItem != NULL) {
AString videomime;
if (format->findString("mime", &videomime)) {
- mAnalyticsItem->setCString(kRecorderVideoMime, videomime.c_str());
+ mMetricsItem->setCString(kRecorderVideoMime, videomime.c_str());
}
}
@@ -1956,7 +2002,6 @@
(*meta)->setInt32(kKeyTimeScale, mMovieTimeScale);
}
if (mOutputFormat != OUTPUT_FORMAT_WEBM) {
- (*meta)->setInt32(kKey64BitFileOffset, mUse64BitFileOffset);
if (mTrackEveryTimeDurationUs > 0) {
(*meta)->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs);
}
@@ -1964,6 +2009,9 @@
(*meta)->setInt32(kKeyRotation, mRotationDegrees);
}
}
+ if (mOutputFormat == OUTPUT_FORMAT_MPEG_4 || mOutputFormat == OUTPUT_FORMAT_THREE_GPP) {
+ (*meta)->setInt32(kKeyEmptyTrackMalFormed, true);
+ }
}
status_t StagefrightRecorder::pause() {
@@ -2220,12 +2268,12 @@
return BAD_VALUE;
}
- if (mAnalyticsItem == NULL) {
+ if (mMetricsItem == NULL) {
return UNKNOWN_ERROR;
}
updateMetrics();
- mAnalyticsItem->writeToParcel(reply);
+ mMetricsItem->writeToParcel(reply);
return OK;
}
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index 8bf083a..a725bee 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -18,7 +18,7 @@
#define STAGEFRIGHT_RECORDER_H_
-#include <media/MediaAnalyticsItem.h>
+#include <media/MediaMetricsItem.h>
#include <media/MediaRecorderBase.h>
#include <camera/CameraParameters.h>
#include <utils/String8.h>
@@ -46,6 +46,8 @@
virtual ~StagefrightRecorder();
virtual status_t init();
virtual status_t setAudioSource(audio_source_t as);
+ status_t setPrivacySensitive(bool privacySensitive) override;
+ status_t isPrivacySensitive(bool *privacySensitive) const override;
virtual status_t setVideoSource(video_source vs);
virtual status_t setOutputFormat(output_format of);
virtual status_t setAudioEncoder(audio_encoder ae);
@@ -82,6 +84,13 @@
status_t getPortId(audio_port_handle_t *portId) const override;
private:
+
+ enum privacy_sensitive_t {
+ PRIVACY_SENSITIVE_DEFAULT = -1,
+ PRIVACY_SENSITIVE_DISABLED = 0,
+ PRIVACY_SENSITIVE_ENABLED = 1,
+ };
+
mutable Mutex mLock;
sp<hardware::ICamera> mCamera;
sp<ICameraRecordingProxy> mCameraProxy;
@@ -95,12 +104,13 @@
int mOutputFd;
sp<AudioSource> mAudioSourceNode;
- MediaAnalyticsItem *mAnalyticsItem;
+ mediametrics::Item *mMetricsItem;
bool mAnalyticsDirty;
void flushAndResetMetrics(bool reinitialize);
void updateMetrics();
audio_source_t mAudioSource;
+ privacy_sensitive_t mPrivacySensitive;
video_source mVideoSource;
output_format mOutputFormat;
audio_encoder mAudioEncoder;
diff --git a/media/libmediaplayerservice/datasource/Android.bp b/media/libmediaplayerservice/datasource/Android.bp
new file mode 100644
index 0000000..71fa50b
--- /dev/null
+++ b/media/libmediaplayerservice/datasource/Android.bp
@@ -0,0 +1,43 @@
+cc_library_static {
+ name: "libplayerservice_datasource",
+
+ srcs: [
+ "PlayerServiceDataSourceFactory.cpp",
+ "PlayerServiceFileSource.cpp",
+ "PlayerServiceMediaHTTP.cpp",
+ ],
+
+ header_libs: [
+ "media_ndk_headers",
+ "libmedia_headers",
+ ],
+
+ shared_libs: [
+ "libdatasource",
+ "libdrmframework",
+ "liblog",
+ "libutils",
+ ],
+
+ local_include_dirs: [
+ "include",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wno-error=deprecated-declarations",
+ "-Wall",
+ ],
+
+ sanitize: {
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ cfi: true,
+ },
+}
diff --git a/media/libmediaplayerservice/datasource/PlayerServiceDataSourceFactory.cpp b/media/libmediaplayerservice/datasource/PlayerServiceDataSourceFactory.cpp
new file mode 100644
index 0000000..ef946e9
--- /dev/null
+++ b/media/libmediaplayerservice/datasource/PlayerServiceDataSourceFactory.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+//#define LOG_NDEBUG 0
+#define LOG_TAG "PlayerServuceDataSourceFactory"
+
+
+#include <datasource/PlayerServiceDataSourceFactory.h>
+#include <datasource/PlayerServiceFileSource.h>
+#include <datasource/PlayerServiceMediaHTTP.h>
+#include <media/MediaHTTPConnection.h>
+#include <media/MediaHTTPService.h>
+
+namespace android {
+
+// static
+sp<PlayerServiceDataSourceFactory> PlayerServiceDataSourceFactory::sInstance;
+// static
+Mutex PlayerServiceDataSourceFactory::sInstanceLock;
+
+// static
+sp<PlayerServiceDataSourceFactory> PlayerServiceDataSourceFactory::getInstance() {
+ Mutex::Autolock l(sInstanceLock);
+ if (!sInstance) {
+ sInstance = new PlayerServiceDataSourceFactory();
+ }
+ return sInstance;
+}
+
+sp<DataSource> PlayerServiceDataSourceFactory::CreateMediaHTTP(
+ const sp<MediaHTTPService> &httpService) {
+ if (httpService == NULL) {
+ return NULL;
+ }
+
+ sp<MediaHTTPConnection> conn = httpService->makeHTTPConnection();
+ if (conn == NULL) {
+ ALOGE("Failed to make http connection from http service!");
+ return NULL;
+ } else {
+ return new PlayerServiceMediaHTTP(conn);
+ }
+}
+
+sp<DataSource> PlayerServiceDataSourceFactory::CreateFileSource(const char *uri) {
+ return new PlayerServiceFileSource(uri);
+}
+
+} // namespace android
diff --git a/media/libmediaplayerservice/datasource/PlayerServiceFileSource.cpp b/media/libmediaplayerservice/datasource/PlayerServiceFileSource.cpp
new file mode 100644
index 0000000..4d95de5
--- /dev/null
+++ b/media/libmediaplayerservice/datasource/PlayerServiceFileSource.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "PlayerServiceFileSource"
+#include <utils/Log.h>
+
+#include <datasource/PlayerServiceFileSource.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <private/android_filesystem_config.h>
+
+namespace android {
+
+PlayerServiceFileSource::PlayerServiceFileSource(const char *filename)
+ : FileSource(filename),
+ mDecryptHandle(NULL),
+ mDrmManagerClient(NULL),
+ mDrmBufOffset(0),
+ mDrmBufSize(0),
+ mDrmBuf(NULL){
+ (void) DrmInitialization(nullptr);
+}
+
+PlayerServiceFileSource::PlayerServiceFileSource(int fd, int64_t offset, int64_t length)
+ : FileSource(fd, offset, length),
+ mDecryptHandle(NULL),
+ mDrmManagerClient(NULL),
+ mDrmBufOffset(0),
+ mDrmBufSize(0),
+ mDrmBuf(NULL) {
+ (void) DrmInitialization(nullptr);
+}
+
+PlayerServiceFileSource::~PlayerServiceFileSource() {
+ if (mDrmBuf != NULL) {
+ delete[] mDrmBuf;
+ mDrmBuf = NULL;
+ }
+
+ if (mDecryptHandle != NULL) {
+ // To release mDecryptHandle
+ CHECK(mDrmManagerClient);
+ mDrmManagerClient->closeDecryptSession(mDecryptHandle);
+ mDecryptHandle = NULL;
+ }
+
+ if (mDrmManagerClient != NULL) {
+ delete mDrmManagerClient;
+ mDrmManagerClient = NULL;
+ }
+}
+
+ssize_t PlayerServiceFileSource::readAt(off64_t offset, void *data, size_t size) {
+ if (mFd < 0) {
+ return NO_INIT;
+ }
+
+ Mutex::Autolock autoLock(mLock);
+
+ if (mLength >= 0) {
+ if (offset < 0) {
+ return UNKNOWN_ERROR;
+ }
+ if (offset >= mLength) {
+ return 0; // read beyond EOF.
+ }
+ uint64_t numAvailable = mLength - offset;
+ if ((uint64_t)size > numAvailable) {
+ size = numAvailable;
+ }
+ }
+
+ if (mDecryptHandle != NULL && DecryptApiType::CONTAINER_BASED
+ == mDecryptHandle->decryptApiType) {
+ return readAtDRM_l(offset, data, size);
+ } else {
+ return readAt_l(offset, data, size);
+ }
+}
+
+sp<DecryptHandle> PlayerServiceFileSource::DrmInitialization(const char *mime) {
+ if (getuid() == AID_MEDIA_EX) {
+ return NULL; // no DRM in media extractor
+ }
+ if (mDrmManagerClient == NULL) {
+ mDrmManagerClient = new DrmManagerClient();
+ }
+
+ if (mDrmManagerClient == NULL) {
+ return NULL;
+ }
+
+ if (mDecryptHandle == NULL) {
+ mDecryptHandle = mDrmManagerClient->openDecryptSession(
+ mFd, mOffset, mLength, mime);
+ }
+
+ if (mDecryptHandle == NULL) {
+ delete mDrmManagerClient;
+ mDrmManagerClient = NULL;
+ }
+
+ return mDecryptHandle;
+}
+
+ssize_t PlayerServiceFileSource::readAtDRM_l(off64_t offset, void *data, size_t size) {
+ size_t DRM_CACHE_SIZE = 1024;
+ if (mDrmBuf == NULL) {
+ mDrmBuf = new unsigned char[DRM_CACHE_SIZE];
+ }
+
+ if (mDrmBuf != NULL && mDrmBufSize > 0 && (offset + mOffset) >= mDrmBufOffset
+ && (offset + mOffset + size) <= static_cast<size_t>(mDrmBufOffset + mDrmBufSize)) {
+ /* Use buffered data */
+ memcpy(data, (void*)(mDrmBuf+(offset+mOffset-mDrmBufOffset)), size);
+ return size;
+ } else if (size <= DRM_CACHE_SIZE) {
+ /* Buffer new data */
+ mDrmBufOffset = offset + mOffset;
+ mDrmBufSize = mDrmManagerClient->pread(mDecryptHandle, mDrmBuf,
+ DRM_CACHE_SIZE, offset + mOffset);
+ if (mDrmBufSize > 0) {
+ int64_t dataRead = 0;
+ dataRead = size > static_cast<size_t>(mDrmBufSize) ? mDrmBufSize : size;
+ memcpy(data, (void*)mDrmBuf, dataRead);
+ return dataRead;
+ } else {
+ return mDrmBufSize;
+ }
+ } else {
+ /* Too big chunk to cache. Call DRM directly */
+ return mDrmManagerClient->pread(mDecryptHandle, data, size, offset + mOffset);
+ }
+}
+
+/* static */
+bool PlayerServiceFileSource::requiresDrm(int fd, int64_t offset, int64_t length, const char *mime) {
+ std::unique_ptr<DrmManagerClient> drmClient(new DrmManagerClient());
+ sp<DecryptHandle> decryptHandle =
+ drmClient->openDecryptSession(fd, offset, length, mime);
+ bool requiresDrm = false;
+ if (decryptHandle != nullptr) {
+ requiresDrm = decryptHandle->decryptApiType == DecryptApiType::CONTAINER_BASED;
+ drmClient->closeDecryptSession(decryptHandle);
+ }
+ return requiresDrm;
+}
+
+} // namespace android
diff --git a/media/libmediaplayerservice/datasource/PlayerServiceMediaHTTP.cpp b/media/libmediaplayerservice/datasource/PlayerServiceMediaHTTP.cpp
new file mode 100644
index 0000000..f99a861
--- /dev/null
+++ b/media/libmediaplayerservice/datasource/PlayerServiceMediaHTTP.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "PlayerServiceMediaHTTP"
+#include <utils/Log.h>
+
+#include <datasource/PlayerServiceMediaHTTP.h>
+
+#include <binder/IServiceManager.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/FoundationUtils.h>
+
+#include <media/MediaHTTPConnection.h>
+
+namespace android {
+
+PlayerServiceMediaHTTP::PlayerServiceMediaHTTP(const sp<MediaHTTPConnection> &conn)
+ : MediaHTTP(conn),
+ mDrmManagerClient(NULL) {
+ (void) DrmInitialization(nullptr);
+}
+
+PlayerServiceMediaHTTP::~PlayerServiceMediaHTTP() {
+ clearDRMState_l();
+}
+
+// DRM...
+
+sp<DecryptHandle> PlayerServiceMediaHTTP::DrmInitialization(const char *mime) {
+ if (mDrmManagerClient == NULL) {
+ mDrmManagerClient = new DrmManagerClient();
+ }
+
+ if (mDrmManagerClient == NULL) {
+ return NULL;
+ }
+
+ if (mDecryptHandle == NULL) {
+ mDecryptHandle = mDrmManagerClient->openDecryptSession(
+ String8(mLastURI.c_str()), mime);
+ }
+
+ if (mDecryptHandle == NULL) {
+ delete mDrmManagerClient;
+ mDrmManagerClient = NULL;
+ }
+
+ return mDecryptHandle;
+}
+
+void PlayerServiceMediaHTTP::clearDRMState_l() {
+ if (mDecryptHandle != NULL) {
+ // To release mDecryptHandle
+ CHECK(mDrmManagerClient);
+ mDrmManagerClient->closeDecryptSession(mDecryptHandle);
+ mDecryptHandle = NULL;
+ }
+}
+
+} // namespace android
diff --git a/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceDataSourceFactory.h b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceDataSourceFactory.h
new file mode 100644
index 0000000..7d58c5c
--- /dev/null
+++ b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceDataSourceFactory.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef PLAYER_SERVICE_DATA_SOURCE_FACTORY_H_
+
+#define PLAYER_SERVICE_DATA_SOURCE_FACTORY_H_
+
+#include <datasource/DataSourceFactory.h>
+#include <media/DataSource.h>
+#include <sys/types.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+struct MediaHTTPService;
+class String8;
+struct HTTPBase;
+
+class PlayerServiceDataSourceFactory : public DataSourceFactory {
+public:
+ static sp<PlayerServiceDataSourceFactory> getInstance();
+ virtual sp<DataSource> CreateMediaHTTP(const sp<MediaHTTPService> &httpService);
+
+protected:
+ virtual sp<DataSource> CreateFileSource(const char *uri);
+
+private:
+ static sp<PlayerServiceDataSourceFactory> sInstance;
+ static Mutex sInstanceLock;
+ PlayerServiceDataSourceFactory() {};
+};
+
+} // namespace android
+
+#endif // PLAYER_SERVICE_DATA_SOURCE_FACTORY_H_
diff --git a/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceFileSource.h b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceFileSource.h
new file mode 100644
index 0000000..7ae8dda
--- /dev/null
+++ b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceFileSource.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef PLAYER_SERVICE_FILE_SOURCE_H_
+
+#define PLAYER_SERVICE_FILE_SOURCE_H_
+
+#include <stdio.h>
+
+#include <datasource/FileSource.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/threads.h>
+#include <drm/DrmManagerClient.h>
+
+namespace android {
+
+// FileSource implementation which works on MediaPlayerService.
+// Supports OMA(forword-lock) files.
+class PlayerServiceFileSource : public FileSource {
+public:
+ PlayerServiceFileSource(const char *filename);
+ // PlayerServiceFileSource takes ownership and will close the fd
+ PlayerServiceFileSource(int fd, int64_t offset, int64_t length);
+
+ virtual ssize_t readAt(off64_t offset, void *data, size_t size);
+
+ static bool requiresDrm(int fd, int64_t offset, int64_t length, const char *mime);
+
+protected:
+ virtual ~PlayerServiceFileSource();
+
+private:
+ /*for DRM*/
+ sp<DecryptHandle> mDecryptHandle;
+ DrmManagerClient *mDrmManagerClient;
+ int64_t mDrmBufOffset;
+ ssize_t mDrmBufSize;
+ unsigned char *mDrmBuf;
+
+ sp<DecryptHandle> DrmInitialization(const char *mime);
+ ssize_t readAtDRM_l(off64_t offset, void *data, size_t size);
+
+ PlayerServiceFileSource(const PlayerServiceFileSource &);
+ PlayerServiceFileSource &operator=(const PlayerServiceFileSource &);
+};
+
+} // namespace android
+
+#endif // PLAYER_SERVICE_FILE_SOURCE_H_
+
diff --git a/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceMediaHTTP.h b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceMediaHTTP.h
new file mode 100644
index 0000000..2f94ada
--- /dev/null
+++ b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceMediaHTTP.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef PLAYER_SERVICE_MEDIA_HTTP_H_
+
+#define PLAYER_SERVICE_MEDIA_HTTP_H_
+
+#include <datasource/MediaHTTP.h>
+#include <drm/DrmManagerClient.h>
+#include <media/stagefright/foundation/AString.h>
+
+namespace android {
+
+struct MediaHTTPConnection;
+
+// MediaHTTP implementation which works on MediaPlayerService.
+// Supports OMA(forword-lock) stream.
+struct PlayerServiceMediaHTTP : public MediaHTTP {
+ PlayerServiceMediaHTTP(const sp<MediaHTTPConnection> &conn);
+
+protected:
+ virtual ~PlayerServiceMediaHTTP();
+
+private:
+ sp<DecryptHandle> mDecryptHandle;
+ DrmManagerClient *mDrmManagerClient;
+
+ sp<DecryptHandle> DrmInitialization(const char *mime);
+ void clearDRMState_l();
+
+ DISALLOW_EVIL_CONSTRUCTORS(PlayerServiceMediaHTTP);
+};
+
+} // namespace android
+
+#endif // PLAYER_SERVICE_MEDIA_HTTP_H_
diff --git a/media/libmediaplayerservice/include/MediaPlayerInterface.h b/media/libmediaplayerservice/include/MediaPlayerInterface.h
index 0ad4d04..436cb31 100644
--- a/media/libmediaplayerservice/include/MediaPlayerInterface.h
+++ b/media/libmediaplayerservice/include/MediaPlayerInterface.h
@@ -27,7 +27,6 @@
#include <media/mediaplayer.h>
#include <media/AudioResamplerPublic.h>
-#include <media/AudioSystem.h>
#include <media/AudioTimestamp.h>
#include <media/AVSyncSettings.h>
#include <media/BufferingSettings.h>
diff --git a/media/libmediaplayerservice/nuplayer/Android.bp b/media/libmediaplayerservice/nuplayer/Android.bp
index 23a19e7..32c97cf 100644
--- a/media/libmediaplayerservice/nuplayer/Android.bp
+++ b/media/libmediaplayerservice/nuplayer/Android.bp
@@ -18,6 +18,8 @@
],
header_libs: [
+ "libmediadrm_headers",
+ "libmediametrics_headers",
"media_plugin_headers",
],
@@ -45,6 +47,7 @@
shared_libs: [
"libbinder",
+ "libdatasource",
"libui",
"libgui",
"libmedia",
@@ -52,6 +55,10 @@
"libpowermanager",
],
+ static_libs: [
+ "libplayerservice_datasource",
+ ],
+
name: "libstagefright_nuplayer",
sanitize: {
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 4653711..0eaa503 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -23,17 +23,20 @@
#include "AnotherPacketSource.h"
#include <binder/IServiceManager.h>
#include <cutils/properties.h>
+#include <datasource/PlayerServiceDataSourceFactory.h>
+#include <datasource/PlayerServiceFileSource.h>
+#include <datasource/HTTPBase.h>
+#include <datasource/NuCachedSource2.h>
#include <media/DataSource.h>
#include <media/MediaBufferHolder.h>
-#include <media/MediaSource.h>
-#include <media/IMediaExtractorService.h>
+#include <media/stagefright/MediaSource.h>
+#include <android/IMediaExtractorService.h>
#include <media/IMediaHTTPService.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSourceFactory.h>
-#include <media/stagefright/FileSource.h>
#include <media/stagefright/InterfaceUtils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaClock.h>
#include <media/stagefright/MediaDefs.h>
@@ -41,8 +44,6 @@
#include <media/stagefright/MediaExtractorFactory.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
-#include "../../libstagefright/include/NuCachedSource2.h"
-#include "../../libstagefright/include/HTTPBase.h"
namespace android {
@@ -75,7 +76,6 @@
mUIDValid(uidValid),
mUID(uid),
mMediaClock(mediaClock),
- mFd(-1),
mBitrate(-1LL),
mPendingReadBufferTypes(0) {
ALOGV("GenericSource");
@@ -98,10 +98,7 @@
mUri.clear();
mUriHeaders.clear();
mSources.clear();
- if (mFd >= 0) {
- close(mFd);
- mFd = -1;
- }
+ mFd.reset();
mOffset = 0;
mLength = 0;
mStarted = false;
@@ -137,11 +134,11 @@
status_t NuPlayer::GenericSource::setDataSource(
int fd, int64_t offset, int64_t length) {
Mutex::Autolock _l(mLock);
- ALOGV("setDataSource %d/%lld/%lld", fd, (long long)offset, (long long)length);
+ ALOGV("setDataSource %d/%lld/%lld (%s)", fd, (long long)offset, (long long)length, nameForFd(fd).c_str());
resetDataSource();
- mFd = dup(fd);
+ mFd.reset(dup(fd));
mOffset = offset;
mLength = length;
@@ -385,7 +382,8 @@
if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
sp<DataSource> httpSource;
mDisconnectLock.unlock();
- httpSource = DataSourceFactory::CreateMediaHTTP(mHTTPService);
+ httpSource = PlayerServiceDataSourceFactory::getInstance()
+ ->CreateMediaHTTP(mHTTPService);
if (httpSource == NULL) {
ALOGE("Failed to create http source!");
notifyPreparedAndCleanup(UNKNOWN_ERROR);
@@ -401,9 +399,9 @@
mLock.unlock();
mDisconnectLock.unlock();
// This might take long time if connection has some issue.
- sp<DataSource> dataSource = DataSourceFactory::CreateFromURI(
- mHTTPService, uri, &mUriHeaders, &contentType,
- static_cast<HTTPBase *>(mHttpSource.get()));
+ sp<DataSource> dataSource = PlayerServiceDataSourceFactory::getInstance()
+ ->CreateFromURI(mHTTPService, uri, &mUriHeaders, &contentType,
+ static_cast<HTTPBase *>(mHttpSource.get()));
mDisconnectLock.lock();
mLock.lock();
if (!mDisconnected) {
@@ -411,24 +409,20 @@
}
} else {
if (property_get_bool("media.stagefright.extractremote", true) &&
- !FileSource::requiresDrm(mFd, mOffset, mLength, nullptr /* mime */)) {
+ !PlayerServiceFileSource::requiresDrm(
+ mFd.get(), mOffset, mLength, nullptr /* mime */)) {
sp<IBinder> binder =
defaultServiceManager()->getService(String16("media.extractor"));
if (binder != nullptr) {
ALOGD("FileSource remote");
sp<IMediaExtractorService> mediaExService(
interface_cast<IMediaExtractorService>(binder));
- sp<IDataSource> source =
- mediaExService->makeIDataSource(mFd, mOffset, mLength);
+ sp<IDataSource> source;
+ mediaExService->makeIDataSource(base::unique_fd(dup(mFd.get())), mOffset, mLength, &source);
ALOGV("IDataSource(FileSource): %p %d %lld %lld",
- source.get(), mFd, (long long)mOffset, (long long)mLength);
+ source.get(), mFd.get(), (long long)mOffset, (long long)mLength);
if (source.get() != nullptr) {
mDataSource = CreateDataSourceFromIDataSource(source);
- if (mDataSource != nullptr) {
- // Close the local file descriptor as it is not needed anymore.
- close(mFd);
- mFd = -1;
- }
} else {
ALOGW("extractor service cannot make data source");
}
@@ -438,12 +432,8 @@
}
if (mDataSource == nullptr) {
ALOGD("FileSource local");
- mDataSource = new FileSource(mFd, mOffset, mLength);
+ mDataSource = new PlayerServiceFileSource(mFd.get(), mOffset, mLength);
}
- // TODO: close should always be done on mFd, see the lines following
- // CreateDataSourceFromIDataSource above,
- // and the FileSource constructor should dup the mFd argument as needed.
- mFd = -1;
}
if (mDataSource == NULL) {
@@ -782,7 +772,7 @@
return;
}
- int64_t nextSubTimeUs;
+ int64_t nextSubTimeUs = 0;
readBuffer(type, -1, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */, &nextSubTimeUs);
sp<ABuffer> buffer;
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 4d1905d..7a2ab8f 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -23,6 +23,7 @@
#include "ATSParser.h"
+#include <android-base/unique_fd.h>
#include <media/mediaplayer.h>
#include <media/stagefright/MediaBuffer.h>
@@ -154,7 +155,7 @@
sp<IMediaHTTPService> mHTTPService;
AString mUri;
KeyedVector<String8, String8> mUriHeaders;
- int mFd;
+ base::unique_fd mFd;
int64_t mOffset;
int64_t mLength;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 3388097..c1c4b55 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -1798,7 +1798,9 @@
}
void NuPlayer::closeAudioSink() {
- mRenderer->closeAudioSink();
+ if (mRenderer != NULL) {
+ mRenderer->closeAudioSink();
+ }
}
void NuPlayer::restartAudio(
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 9f5be06..ef4354c 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -19,7 +19,7 @@
#define NU_PLAYER_H_
#include <media/AudioResamplerPublic.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/MediaPlayerInterface.h>
#include <media/stagefright/foundation/AHandler.h>
@@ -27,7 +27,6 @@
struct ABuffer;
struct AMessage;
-struct AudioPlaybackRate;
struct AVSyncSettings;
class IDataSource;
struct MediaClock;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 2f0da2d..f734439 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -28,7 +28,7 @@
#include "NuPlayerSource.h"
#include <cutils/properties.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/MediaBufferHolder.h>
#include <media/MediaCodecBuffer.h>
#include <media/stagefright/foundation/ABuffer.h>
@@ -106,16 +106,17 @@
releaseAndResetMediaBuffers();
}
-sp<AMessage> NuPlayer::Decoder::getStats() const {
+sp<AMessage> NuPlayer::Decoder::getStats() {
+ Mutex::Autolock autolock(mStatsLock);
mStats->setInt64("frames-total", mNumFramesTotal);
mStats->setInt64("frames-dropped-input", mNumInputFramesDropped);
mStats->setInt64("frames-dropped-output", mNumOutputFramesDropped);
mStats->setFloat("frame-rate-total", mFrameRateTotal);
- // i'm mutexed right now.
// make our own copy, so we aren't victim to any later changes.
sp<AMessage> copiedStats = mStats->dup();
+
return copiedStats;
}
@@ -362,13 +363,17 @@
CHECK_EQ((status_t)OK, mCodec->getOutputFormat(&mOutputFormat));
CHECK_EQ((status_t)OK, mCodec->getInputFormat(&mInputFormat));
- mStats->setString("mime", mime.c_str());
- mStats->setString("component-name", mComponentName.c_str());
+ {
+ Mutex::Autolock autolock(mStatsLock);
+ mStats->setString("mime", mime.c_str());
+ mStats->setString("component-name", mComponentName.c_str());
+ }
if (!mIsAudio) {
int32_t width, height;
if (mOutputFormat->findInt32("width", &width)
&& mOutputFormat->findInt32("height", &height)) {
+ Mutex::Autolock autolock(mStatsLock);
mStats->setInt32("width", width);
mStats->setInt32("height", height);
}
@@ -799,6 +804,7 @@
int32_t width, height;
if (format->findInt32("width", &width)
&& format->findInt32("height", &height)) {
+ Mutex::Autolock autolock(mStatsLock);
mStats->setInt32("width", width);
mStats->setInt32("height", height);
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
index 3da2f0b..4a52b0c 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
@@ -34,7 +34,7 @@
const sp<Surface> &surface = NULL,
const sp<CCDecoder> &ccDecoder = NULL);
- virtual sp<AMessage> getStats() const;
+ virtual sp<AMessage> getStats();
// sets the output surface of video decoders.
virtual status_t setVideoSurface(const sp<Surface> &surface);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
index d44c396..a3e0046 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
@@ -47,7 +47,7 @@
void signalResume(bool notifyComplete);
void initiateShutdown();
- virtual sp<AMessage> getStats() const {
+ virtual sp<AMessage> getStats() {
return mStats;
}
@@ -88,6 +88,7 @@
int32_t mBufferGeneration;
bool mPaused;
sp<AMessage> mStats;
+ Mutex mStatsLock;
private:
enum {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
index 0997e7d..793014e 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
@@ -24,7 +24,7 @@
#include "NuPlayerRenderer.h"
#include "NuPlayerSource.h"
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/MediaCodecBuffer.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 865cb2a..24afd43 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -33,8 +33,7 @@
#include <media/stagefright/MediaClock.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
-
-#include <media/IMediaAnalyticsService.h>
+#include <media/stagefright/FoundationUtils.h>
static const int kDumpLockRetries = 50;
static const int kDumpLockSleepUs = 20000;
@@ -86,7 +85,7 @@
mMediaClock(new MediaClock),
mPlayer(new NuPlayer(pid, mMediaClock)),
mPlayerFlags(0),
- mAnalyticsItem(NULL),
+ mMetricsItem(NULL),
mClientUid(-1),
mAtEOS(false),
mLooping(false),
@@ -97,7 +96,7 @@
mMediaClock->init();
// set up an analytics record
- mAnalyticsItem = MediaAnalyticsItem::create(kKeyPlayer);
+ mMetricsItem = mediametrics::Item::create(kKeyPlayer);
mLooper->start(
false, /* runOnCallingThread */
@@ -117,9 +116,9 @@
updateMetrics("destructor");
logMetrics("destructor");
- if (mAnalyticsItem != NULL) {
- delete mAnalyticsItem;
- mAnalyticsItem = NULL;
+ if (mMetricsItem != NULL) {
+ delete mMetricsItem;
+ mMetricsItem = NULL;
}
}
@@ -130,8 +129,8 @@
status_t NuPlayerDriver::setUID(uid_t uid) {
mPlayer->setUID(uid);
mClientUid = uid;
- if (mAnalyticsItem) {
- mAnalyticsItem->setUid(mClientUid);
+ if (mMetricsItem) {
+ mMetricsItem->setUid(mClientUid);
}
return OK;
@@ -559,15 +558,15 @@
if (mime.startsWith("video/")) {
int32_t width, height;
- mAnalyticsItem->setCString(kPlayerVMime, mime.c_str());
+ mMetricsItem->setCString(kPlayerVMime, mime.c_str());
if (!name.empty()) {
- mAnalyticsItem->setCString(kPlayerVCodec, name.c_str());
+ mMetricsItem->setCString(kPlayerVCodec, name.c_str());
}
if (stats->findInt32("width", &width)
&& stats->findInt32("height", &height)) {
- mAnalyticsItem->setInt32(kPlayerWidth, width);
- mAnalyticsItem->setInt32(kPlayerHeight, height);
+ mMetricsItem->setInt32(kPlayerWidth, width);
+ mMetricsItem->setInt32(kPlayerHeight, height);
}
int64_t numFramesTotal = 0;
@@ -575,18 +574,18 @@
stats->findInt64("frames-total", &numFramesTotal);
stats->findInt64("frames-dropped-output", &numFramesDropped);
- mAnalyticsItem->setInt64(kPlayerFrames, numFramesTotal);
- mAnalyticsItem->setInt64(kPlayerFramesDropped, numFramesDropped);
+ mMetricsItem->setInt64(kPlayerFrames, numFramesTotal);
+ mMetricsItem->setInt64(kPlayerFramesDropped, numFramesDropped);
float frameRate = 0;
if (stats->findFloat("frame-rate-total", &frameRate)) {
- mAnalyticsItem->setDouble(kPlayerFrameRate, (double) frameRate);
+ mMetricsItem->setDouble(kPlayerFrameRate, (double) frameRate);
}
} else if (mime.startsWith("audio/")) {
- mAnalyticsItem->setCString(kPlayerAMime, mime.c_str());
+ mMetricsItem->setCString(kPlayerAMime, mime.c_str());
if (!name.empty()) {
- mAnalyticsItem->setCString(kPlayerACodec, name.c_str());
+ mMetricsItem->setCString(kPlayerACodec, name.c_str());
}
}
}
@@ -597,20 +596,20 @@
// getDuration() uses mLock for mutex -- careful where we use it.
int duration_ms = -1;
getDuration(&duration_ms);
- mAnalyticsItem->setInt64(kPlayerDuration, duration_ms);
+ mMetricsItem->setInt64(kPlayerDuration, duration_ms);
mPlayer->updateInternalTimers();
- mAnalyticsItem->setInt64(kPlayerPlaying, (mPlayingTimeUs+500)/1000 );
+ mMetricsItem->setInt64(kPlayerPlaying, (mPlayingTimeUs+500)/1000 );
if (mRebufferingEvents != 0) {
- mAnalyticsItem->setInt64(kPlayerRebuffering, (mRebufferingTimeUs+500)/1000 );
- mAnalyticsItem->setInt32(kPlayerRebufferingCount, mRebufferingEvents);
- mAnalyticsItem->setInt32(kPlayerRebufferingAtExit, mRebufferingAtExit);
+ mMetricsItem->setInt64(kPlayerRebuffering, (mRebufferingTimeUs+500)/1000 );
+ mMetricsItem->setInt32(kPlayerRebufferingCount, mRebufferingEvents);
+ mMetricsItem->setInt32(kPlayerRebufferingAtExit, mRebufferingAtExit);
}
- mAnalyticsItem->setCString(kPlayerDataSourceType, mPlayer->getDataSourceType());
+ mMetricsItem->setCString(kPlayerDataSourceType, mPlayer->getDataSourceType());
}
@@ -620,7 +619,7 @@
}
ALOGV("logMetrics(%p) from %s at state %d", this, where, mState);
- if (mAnalyticsItem == NULL || mAnalyticsItem->isEnabled() == false) {
+ if (mMetricsItem == NULL || mMetricsItem->isEnabled() == false) {
return;
}
@@ -629,18 +628,18 @@
// and that always injects 3 fields (duration, playing time, and
// datasource) into the record.
// So the canonical "empty" record has 3 elements in it.
- if (mAnalyticsItem->count() > 3) {
+ if (mMetricsItem->count() > 3) {
- mAnalyticsItem->selfrecord();
+ mMetricsItem->selfrecord();
// re-init in case we prepare() and start() again.
- delete mAnalyticsItem ;
- mAnalyticsItem = MediaAnalyticsItem::create(kKeyPlayer);
- if (mAnalyticsItem) {
- mAnalyticsItem->setUid(mClientUid);
+ delete mMetricsItem ;
+ mMetricsItem = mediametrics::Item::create(kKeyPlayer);
+ if (mMetricsItem) {
+ mMetricsItem->setUid(mClientUid);
}
} else {
- ALOGV("nothing to record (only %d fields)", mAnalyticsItem->count());
+ ALOGV("nothing to record (only %zu fields)", mMetricsItem->count());
}
}
@@ -778,11 +777,11 @@
status_t NuPlayerDriver::getParameter(int key, Parcel *reply) {
- if (key == FOURCC('m','t','r','X') && mAnalyticsItem != NULL) {
+ if (key == FOURCC('m','t','r','X') && mMetricsItem != NULL) {
// mtrX -- a play on 'metrics' (not matrix)
// gather current info all together, parcel it, and send it back
updateMetrics("api");
- mAnalyticsItem->writeToParcel(reply);
+ mMetricsItem->writeToParcel(reply);
return OK;
}
@@ -1006,12 +1005,12 @@
// when we have an error, add it to the analytics for this playback.
// ext1 is our primary 'error type' value. Only add ext2 when non-zero.
// [test against msg is due to fall through from previous switch value]
- if (msg == MEDIA_ERROR && mAnalyticsItem != NULL) {
- mAnalyticsItem->setInt32(kPlayerError, ext1);
+ if (msg == MEDIA_ERROR && mMetricsItem != NULL) {
+ mMetricsItem->setInt32(kPlayerError, ext1);
if (ext2 != 0) {
- mAnalyticsItem->setInt32(kPlayerErrorCode, ext2);
+ mMetricsItem->setInt32(kPlayerErrorCode, ext2);
}
- mAnalyticsItem->setCString(kPlayerErrorState, stateString(mState).c_str());
+ mMetricsItem->setCString(kPlayerErrorState, stateString(mState).c_str());
}
mAtEOS = true;
break;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index ad878f8..7001f4a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -16,7 +16,7 @@
#include <media/MediaPlayerInterface.h>
-#include <media/MediaAnalyticsItem.h>
+#include <media/MediaMetricsItem.h>
#include <media/stagefright/foundation/ABase.h>
namespace android {
@@ -141,7 +141,7 @@
sp<AudioSink> mAudioSink;
uint32_t mPlayerFlags;
- MediaAnalyticsItem *mAnalyticsItem;
+ mediametrics::Item *mMetricsItem;
uid_t mClientUid;
bool mAtEOS;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
index 2d0c9e0..6788b56 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
@@ -19,8 +19,7 @@
#include "NuPlayerDrm.h"
-#include <binder/IServiceManager.h>
-#include <mediadrm/IMediaDrmService.h>
+#include <mediadrm/DrmUtils.h>
#include <utils/Log.h>
@@ -30,60 +29,13 @@
sp<IDrm> NuPlayerDrm::CreateDrm(status_t *pstatus)
{
- status_t &status = *pstatus;
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder = sm->getService(String16("media.drm"));
- ALOGV("CreateDrm binder %p", (binder != NULL ? binder.get() : 0));
-
- sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
- if (service == NULL) {
- ALOGE("CreateDrm failed at IMediaDrmService");
- return NULL;
- }
-
- sp<IDrm> drm = service->makeDrm();
- if (drm == NULL) {
- ALOGE("CreateDrm failed at makeDrm");
- return NULL;
- }
-
- // this is before plugin creation so NO_INIT is fine
- status = drm->initCheck();
- if (status != OK && status != NO_INIT) {
- ALOGE("CreateDrm failed drm->initCheck(): %d", status);
- return NULL;
- }
- return drm;
+ return DrmUtils::MakeDrm(pstatus);
}
sp<ICrypto> NuPlayerDrm::createCrypto(status_t *pstatus)
{
- status_t &status = *pstatus;
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder = sm->getService(String16("media.drm"));
- sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
- if (service == NULL) {
- status = UNKNOWN_ERROR;
- ALOGE("CreateCrypto failed at IMediaDrmService");
- return NULL;
- }
-
- sp<ICrypto> crypto = service->makeCrypto();
- if (crypto == NULL) {
- status = UNKNOWN_ERROR;
- ALOGE("createCrypto failed");
- return NULL;
- }
-
- // this is before plugin creation so NO_INIT is fine
- status = crypto->initCheck();
- if (status != OK && status != NO_INIT) {
- ALOGE("createCrypto failed crypto->initCheck(): %d", status);
- return NULL;
- }
-
- return crypto;
+ return DrmUtils::MakeCrypto(pstatus);
}
Vector<DrmUUID> NuPlayerDrm::parsePSSH(const void *pssh, size_t psshsize)
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.h b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.h
index 50f69ff..4360656 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.h
@@ -18,8 +18,8 @@
#define NUPLAYER_DRM_H_
#include <binder/Parcel.h>
-#include <media/ICrypto.h>
-#include <media/IDrm.h>
+#include <mediadrm/ICrypto.h>
+#include <mediadrm/IDrm.h>
#include <media/stagefright/MetaData.h> // for CryptInfo
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 39be40d..c30f048 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -33,6 +33,7 @@
#include <media/stagefright/Utils.h>
#include <media/stagefright/VideoFrameScheduler.h>
#include <media/MediaCodecBuffer.h>
+#include <utils/SystemClock.h>
#include <inttypes.h>
@@ -156,6 +157,7 @@
CHECK(mediaClock != NULL);
mPlaybackRate = mPlaybackSettings.mSpeed;
mMediaClock->setPlaybackRate(mPlaybackRate);
+ (void)mSyncFlag.test_and_set();
}
NuPlayer::Renderer::~Renderer() {
@@ -326,9 +328,27 @@
mSyncQueues = false;
}
+ // Wait until the current job in the message queue is done, to make sure
+ // buffer processing from the old generation is finished. After the current
+ // job is finished, access to buffers are protected by generation.
+ Mutex::Autolock syncLock(mSyncLock);
+ int64_t syncCount = mSyncCount;
+ mSyncFlag.clear();
+
+ // Make sure message queue is not empty after mSyncFlag is cleared.
sp<AMessage> msg = new AMessage(kWhatFlush, this);
msg->setInt32("audio", static_cast<int32_t>(audio));
msg->post();
+
+ int64_t uptimeMs = uptimeMillis();
+ while (mSyncCount == syncCount) {
+ (void)mSyncCondition.waitRelative(mSyncLock, ms2ns(1000));
+ if (uptimeMillis() - uptimeMs > 1000) {
+ ALOGW("flush(): no wake-up from sync point for 1s; stop waiting to "
+ "prevent being stuck indefinitely.");
+ break;
+ }
+ }
}
void NuPlayer::Renderer::signalTimeDiscontinuity() {
@@ -781,6 +801,11 @@
TRESPASS();
break;
}
+ if (!mSyncFlag.test_and_set()) {
+ Mutex::Autolock syncLock(mSyncLock);
+ ++mSyncCount;
+ mSyncCondition.broadcast();
+ }
}
void NuPlayer::Renderer::postDrainAudioQueue_l(int64_t delayUs) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index a521f62..3d2b033 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -18,6 +18,8 @@
#define NUPLAYER_RENDERER_H_
+#include <atomic>
+
#include <media/AudioResamplerPublic.h>
#include <media/AVSyncSettings.h>
@@ -220,6 +222,11 @@
sp<AWakeLock> mWakeLock;
+ std::atomic_flag mSyncFlag = ATOMIC_FLAG_INIT;
+ Mutex mSyncLock;
+ Condition mSyncCondition;
+ int64_t mSyncCount{0};
+
status_t getCurrentPositionOnLooper(int64_t *mediaUs);
status_t getCurrentPositionOnLooper(
int64_t *mediaUs, int64_t nowUs, bool allowPastQueuedVideo = false);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index 9f5ef78..f137c52 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -20,7 +20,7 @@
#include "NuPlayer.h"
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/mediaplayer.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MetaData.h>
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.cpp
index ee70306..b5142ed 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.cpp
@@ -154,7 +154,7 @@
}
memcpy(data,
- (const uint8_t *)mem->pointer()
+ (const uint8_t *)mem->unsecurePointer()
+ entry->mOffset,
copy);
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index bf14ec2..83da092 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -144,6 +144,10 @@
if (mLooper == NULL) {
return;
}
+
+ // Close socket before posting message to RTSPSource message handler.
+ close(mHandler->getARTSPConnection()->getSocket());
+
sp<AMessage> msg = new AMessage(kWhatDisconnect, this);
sp<AMessage> dummy;
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
index f21d2b3..14f1323 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
@@ -24,7 +24,7 @@
#include "AnotherPacketSource.h"
#include "NuPlayerStreamListener.h"
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
diff --git a/media/libmediaplayerservice/tests/Android.bp b/media/libmediaplayerservice/tests/Android.bp
index f8c89e5..e845c33 100644
--- a/media/libmediaplayerservice/tests/Android.bp
+++ b/media/libmediaplayerservice/tests/Android.bp
@@ -6,14 +6,27 @@
shared_libs: [
"liblog",
+ "libbinder",
+ "libbinder_ndk",
+ "libmedia",
"libmediaplayerservice",
"libmediadrm",
+ "libresourcemanagerservice",
"libutils",
"android.hardware.drm@1.0",
"android.hardware.drm@1.1",
"android.hardware.drm@1.2",
],
+ static_libs: [
+ "resourcemanager_aidl_interface-ndk_platform",
+ ],
+
+ include_dirs: [
+ "frameworks/av/include",
+ "frameworks/av/services/mediaresourcemanager",
+ ],
+
cflags: [
"-Werror",
"-Wall",
diff --git a/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp b/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
index d81ee05..f114046 100644
--- a/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
+++ b/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
@@ -16,18 +16,40 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "DrmSessionManager_test"
+#include <android/binder_auto_utils.h>
#include <utils/Log.h>
#include <gtest/gtest.h>
+#include <aidl/android/media/BnResourceManagerClient.h>
+#include <aidl/android/media/BnResourceManagerService.h>
+
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/ProcessInfoInterface.h>
-#include <mediadrm/DrmHal.h>
-#include <mediadrm/DrmSessionClientInterface.h>
#include <mediadrm/DrmSessionManager.h>
+#include <algorithm>
+#include <iostream>
+#include <vector>
+
+#include "ResourceManagerService.h"
+
namespace android {
+using Status = ::ndk::ScopedAStatus;
+using ::aidl::android::media::BnResourceManagerClient;
+using ::aidl::android::media::BnResourceManagerService;
+using ::aidl::android::media::MediaResourceParcel;
+using ::aidl::android::media::IResourceManagerClient;
+
+static Vector<uint8_t> toAndroidVector(const std::vector<uint8_t> &vec) {
+ Vector<uint8_t> aVec;
+ for (auto b : vec) {
+ aVec.push_back(b);
+ }
+ return aVec;
+}
+
struct FakeProcessInfo : public ProcessInfoInterface {
FakeProcessInfo() {}
virtual ~FakeProcessInfo() {}
@@ -47,173 +69,128 @@
DISALLOW_EVIL_CONSTRUCTORS(FakeProcessInfo);
};
-struct FakeDrm : public DrmSessionClientInterface {
- FakeDrm() {}
- virtual ~FakeDrm() {}
+struct FakeDrm : public BnResourceManagerClient {
+ FakeDrm(const std::vector<uint8_t>& sessionId, const sp<DrmSessionManager>& manager)
+ : mSessionId(toAndroidVector(sessionId)),
+ mReclaimed(false),
+ mDrmSessionManager(manager) {}
- virtual bool reclaimSession(const Vector<uint8_t>& sessionId) {
- mReclaimedSessions.push_back(sessionId);
- return true;
+ Status reclaimResource(bool* _aidl_return) {
+ mReclaimed = true;
+ mDrmSessionManager->removeSession(mSessionId);
+ *_aidl_return = true;
+ return Status::ok();
}
- const Vector<Vector<uint8_t> >& reclaimedSessions() const {
- return mReclaimedSessions;
+ Status getName(::std::string* _aidl_return) {
+ String8 name("FakeDrm[");
+ for (size_t i = 0; i < mSessionId.size(); ++i) {
+ name.appendFormat("%02x", mSessionId[i]);
+ }
+ name.append("]");
+ *_aidl_return = name;
+ return Status::ok();
}
+ bool isReclaimed() const {
+ return mReclaimed;
+ }
+
+ const Vector<uint8_t> mSessionId;
+
private:
- Vector<Vector<uint8_t> > mReclaimedSessions;
+ bool mReclaimed;
+ const sp<DrmSessionManager> mDrmSessionManager;
DISALLOW_EVIL_CONSTRUCTORS(FakeDrm);
};
+struct FakeSystemCallback :
+ public ResourceManagerService::SystemCallbackInterface {
+ FakeSystemCallback() {}
+
+ virtual void noteStartVideo(int /*uid*/) override {}
+
+ virtual void noteStopVideo(int /*uid*/) override {}
+
+ virtual void noteResetVideo() override {}
+
+ virtual bool requestCpusetBoost(bool /*enable*/) override {
+ return true;
+ }
+
+protected:
+ virtual ~FakeSystemCallback() {}
+
+private:
+
+ DISALLOW_EVIL_CONSTRUCTORS(FakeSystemCallback);
+};
+
static const int kTestPid1 = 30;
static const int kTestPid2 = 20;
-static const uint8_t kTestSessionId1[] = {1, 2, 3};
-static const uint8_t kTestSessionId2[] = {4, 5, 6, 7, 8};
-static const uint8_t kTestSessionId3[] = {9, 0};
+static const std::vector<uint8_t> kTestSessionId1{1, 2, 3};
+static const std::vector<uint8_t> kTestSessionId2{4, 5, 6, 7, 8};
+static const std::vector<uint8_t> kTestSessionId3{9, 0};
class DrmSessionManagerTest : public ::testing::Test {
public:
DrmSessionManagerTest()
- : mDrmSessionManager(new DrmSessionManager(new FakeProcessInfo())),
- mTestDrm1(new FakeDrm()),
- mTestDrm2(new FakeDrm()) {
- GetSessionId(kTestSessionId1, ARRAY_SIZE(kTestSessionId1), &mSessionId1);
- GetSessionId(kTestSessionId2, ARRAY_SIZE(kTestSessionId2), &mSessionId2);
- GetSessionId(kTestSessionId3, ARRAY_SIZE(kTestSessionId3), &mSessionId3);
+ : mService(::ndk::SharedRefBase::make<ResourceManagerService>
+ (new FakeProcessInfo(), new FakeSystemCallback())),
+ mDrmSessionManager(new DrmSessionManager(mService)),
+ mTestDrm1(::ndk::SharedRefBase::make<FakeDrm>(
+ kTestSessionId1, mDrmSessionManager)),
+ mTestDrm2(::ndk::SharedRefBase::make<FakeDrm>(
+ kTestSessionId2, mDrmSessionManager)),
+ mTestDrm3(::ndk::SharedRefBase::make<FakeDrm>(
+ kTestSessionId3, mDrmSessionManager)) {
}
protected:
- static void GetSessionId(const uint8_t* ids, size_t num, Vector<uint8_t>* sessionId) {
- for (size_t i = 0; i < num; ++i) {
- sessionId->push_back(ids[i]);
- }
- }
-
- static void ExpectEqSessionInfo(const SessionInfo& info, sp<DrmSessionClientInterface> drm,
- const Vector<uint8_t>& sessionId, int64_t timeStamp) {
- EXPECT_EQ(drm, info.drm);
- EXPECT_TRUE(isEqualSessionId(sessionId, info.sessionId));
- EXPECT_EQ(timeStamp, info.timeStamp);
- }
-
void addSession() {
- mDrmSessionManager->addSession(kTestPid1, mTestDrm1, mSessionId1);
- mDrmSessionManager->addSession(kTestPid2, mTestDrm2, mSessionId2);
- mDrmSessionManager->addSession(kTestPid2, mTestDrm2, mSessionId3);
- const PidSessionInfosMap& map = sessionMap();
- EXPECT_EQ(2u, map.size());
- ssize_t index1 = map.indexOfKey(kTestPid1);
- ASSERT_GE(index1, 0);
- const SessionInfos& infos1 = map[index1];
- EXPECT_EQ(1u, infos1.size());
- ExpectEqSessionInfo(infos1[0], mTestDrm1, mSessionId1, 0);
-
- ssize_t index2 = map.indexOfKey(kTestPid2);
- ASSERT_GE(index2, 0);
- const SessionInfos& infos2 = map[index2];
- EXPECT_EQ(2u, infos2.size());
- ExpectEqSessionInfo(infos2[0], mTestDrm2, mSessionId2, 1);
- ExpectEqSessionInfo(infos2[1], mTestDrm2, mSessionId3, 2);
+ mDrmSessionManager->addSession(kTestPid1, mTestDrm1, mTestDrm1->mSessionId);
+ mDrmSessionManager->addSession(kTestPid2, mTestDrm2, mTestDrm2->mSessionId);
+ mDrmSessionManager->addSession(kTestPid2, mTestDrm3, mTestDrm3->mSessionId);
}
- const PidSessionInfosMap& sessionMap() {
- return mDrmSessionManager->mSessionMap;
- }
-
- void testGetLowestPriority() {
- int pid;
- int priority;
- EXPECT_FALSE(mDrmSessionManager->getLowestPriority_l(&pid, &priority));
-
- addSession();
- EXPECT_TRUE(mDrmSessionManager->getLowestPriority_l(&pid, &priority));
-
- EXPECT_EQ(kTestPid1, pid);
- FakeProcessInfo processInfo;
- int priority1;
- processInfo.getPriority(kTestPid1, &priority1);
- EXPECT_EQ(priority1, priority);
- }
-
- void testGetLeastUsedSession() {
- sp<DrmSessionClientInterface> drm;
- Vector<uint8_t> sessionId;
- EXPECT_FALSE(mDrmSessionManager->getLeastUsedSession_l(kTestPid1, &drm, &sessionId));
-
- addSession();
-
- EXPECT_TRUE(mDrmSessionManager->getLeastUsedSession_l(kTestPid1, &drm, &sessionId));
- EXPECT_EQ(mTestDrm1, drm);
- EXPECT_TRUE(isEqualSessionId(mSessionId1, sessionId));
-
- EXPECT_TRUE(mDrmSessionManager->getLeastUsedSession_l(kTestPid2, &drm, &sessionId));
- EXPECT_EQ(mTestDrm2, drm);
- EXPECT_TRUE(isEqualSessionId(mSessionId2, sessionId));
-
- // mSessionId2 is no longer the least used session.
- mDrmSessionManager->useSession(mSessionId2);
- EXPECT_TRUE(mDrmSessionManager->getLeastUsedSession_l(kTestPid2, &drm, &sessionId));
- EXPECT_EQ(mTestDrm2, drm);
- EXPECT_TRUE(isEqualSessionId(mSessionId3, sessionId));
- }
-
+ std::shared_ptr<ResourceManagerService> mService;
sp<DrmSessionManager> mDrmSessionManager;
- sp<FakeDrm> mTestDrm1;
- sp<FakeDrm> mTestDrm2;
- Vector<uint8_t> mSessionId1;
- Vector<uint8_t> mSessionId2;
- Vector<uint8_t> mSessionId3;
+ std::shared_ptr<FakeDrm> mTestDrm1;
+ std::shared_ptr<FakeDrm> mTestDrm2;
+ std::shared_ptr<FakeDrm> mTestDrm3;
};
TEST_F(DrmSessionManagerTest, addSession) {
addSession();
+
+ EXPECT_EQ(3u, mDrmSessionManager->getSessionCount());
+ EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm1->mSessionId));
+ EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm2->mSessionId));
+ EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm3->mSessionId));
}
TEST_F(DrmSessionManagerTest, useSession) {
addSession();
- mDrmSessionManager->useSession(mSessionId1);
- mDrmSessionManager->useSession(mSessionId3);
+ mDrmSessionManager->useSession(mTestDrm1->mSessionId);
+ mDrmSessionManager->useSession(mTestDrm3->mSessionId);
- const PidSessionInfosMap& map = sessionMap();
- const SessionInfos& infos1 = map.valueFor(kTestPid1);
- const SessionInfos& infos2 = map.valueFor(kTestPid2);
- ExpectEqSessionInfo(infos1[0], mTestDrm1, mSessionId1, 3);
- ExpectEqSessionInfo(infos2[1], mTestDrm2, mSessionId3, 4);
+ EXPECT_EQ(3u, mDrmSessionManager->getSessionCount());
+ EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm1->mSessionId));
+ EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm2->mSessionId));
+ EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm3->mSessionId));
}
TEST_F(DrmSessionManagerTest, removeSession) {
addSession();
- mDrmSessionManager->removeSession(mSessionId2);
+ mDrmSessionManager->removeSession(mTestDrm2->mSessionId);
- const PidSessionInfosMap& map = sessionMap();
- EXPECT_EQ(2u, map.size());
- const SessionInfos& infos1 = map.valueFor(kTestPid1);
- const SessionInfos& infos2 = map.valueFor(kTestPid2);
- EXPECT_EQ(1u, infos1.size());
- EXPECT_EQ(1u, infos2.size());
- // mSessionId2 has been removed.
- ExpectEqSessionInfo(infos2[0], mTestDrm2, mSessionId3, 2);
-}
-
-TEST_F(DrmSessionManagerTest, removeDrm) {
- addSession();
-
- sp<FakeDrm> drm = new FakeDrm;
- const uint8_t ids[] = {123};
- Vector<uint8_t> sessionId;
- GetSessionId(ids, ARRAY_SIZE(ids), &sessionId);
- mDrmSessionManager->addSession(kTestPid2, drm, sessionId);
-
- mDrmSessionManager->removeDrm(mTestDrm2);
-
- const PidSessionInfosMap& map = sessionMap();
- const SessionInfos& infos2 = map.valueFor(kTestPid2);
- EXPECT_EQ(1u, infos2.size());
- // mTestDrm2 has been removed.
- ExpectEqSessionInfo(infos2[0], drm, sessionId, 3);
+ EXPECT_EQ(2u, mDrmSessionManager->getSessionCount());
+ EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm1->mSessionId));
+ EXPECT_FALSE(mDrmSessionManager->containsSession(mTestDrm2->mSessionId));
+ EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm3->mSessionId));
}
TEST_F(DrmSessionManagerTest, reclaimSession) {
@@ -224,30 +201,64 @@
EXPECT_FALSE(mDrmSessionManager->reclaimSession(50));
EXPECT_TRUE(mDrmSessionManager->reclaimSession(10));
- EXPECT_EQ(1u, mTestDrm1->reclaimedSessions().size());
- EXPECT_TRUE(isEqualSessionId(mSessionId1, mTestDrm1->reclaimedSessions()[0]));
-
- mDrmSessionManager->removeSession(mSessionId1);
+ EXPECT_TRUE(mTestDrm1->isReclaimed());
// add a session from a higher priority process.
- sp<FakeDrm> drm = new FakeDrm;
- const uint8_t ids[] = {1, 3, 5};
- Vector<uint8_t> sessionId;
- GetSessionId(ids, ARRAY_SIZE(ids), &sessionId);
- mDrmSessionManager->addSession(15, drm, sessionId);
+ const std::vector<uint8_t> sid{1, 3, 5};
+ std::shared_ptr<FakeDrm> drm =
+ ::ndk::SharedRefBase::make<FakeDrm>(sid, mDrmSessionManager);
+ mDrmSessionManager->addSession(15, drm, drm->mSessionId);
+ // make sure mTestDrm2 is reclaimed next instead of mTestDrm3
+ mDrmSessionManager->useSession(mTestDrm3->mSessionId);
EXPECT_TRUE(mDrmSessionManager->reclaimSession(18));
- EXPECT_EQ(1u, mTestDrm2->reclaimedSessions().size());
- // mSessionId2 is reclaimed.
- EXPECT_TRUE(isEqualSessionId(mSessionId2, mTestDrm2->reclaimedSessions()[0]));
+ EXPECT_TRUE(mTestDrm2->isReclaimed());
+
+ EXPECT_EQ(2u, mDrmSessionManager->getSessionCount());
+ EXPECT_FALSE(mDrmSessionManager->containsSession(mTestDrm1->mSessionId));
+ EXPECT_FALSE(mDrmSessionManager->containsSession(mTestDrm2->mSessionId));
+ EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm3->mSessionId));
+ EXPECT_TRUE(mDrmSessionManager->containsSession(drm->mSessionId));
}
-TEST_F(DrmSessionManagerTest, getLowestPriority) {
- testGetLowestPriority();
-}
+TEST_F(DrmSessionManagerTest, reclaimAfterUse) {
+ // nothing to reclaim yet
+ EXPECT_FALSE(mDrmSessionManager->reclaimSession(kTestPid1));
+ EXPECT_FALSE(mDrmSessionManager->reclaimSession(kTestPid2));
-TEST_F(DrmSessionManagerTest, getLeastUsedSession_l) {
- testGetLeastUsedSession();
+ // add sessions from same pid
+ mDrmSessionManager->addSession(kTestPid2, mTestDrm1, mTestDrm1->mSessionId);
+ mDrmSessionManager->addSession(kTestPid2, mTestDrm2, mTestDrm2->mSessionId);
+ mDrmSessionManager->addSession(kTestPid2, mTestDrm3, mTestDrm3->mSessionId);
+
+ // use some but not all sessions
+ mDrmSessionManager->useSession(mTestDrm1->mSessionId);
+ mDrmSessionManager->useSession(mTestDrm1->mSessionId);
+ mDrmSessionManager->useSession(mTestDrm2->mSessionId);
+
+ // calling pid priority is too low
+ int lowPriorityPid = kTestPid2 + 1;
+ EXPECT_FALSE(mDrmSessionManager->reclaimSession(lowPriorityPid));
+
+ // unused session is reclaimed first
+ int highPriorityPid = kTestPid2 - 1;
+ EXPECT_TRUE(mDrmSessionManager->reclaimSession(highPriorityPid));
+ EXPECT_FALSE(mTestDrm1->isReclaimed());
+ EXPECT_FALSE(mTestDrm2->isReclaimed());
+ EXPECT_TRUE(mTestDrm3->isReclaimed());
+ mDrmSessionManager->removeSession(mTestDrm3->mSessionId);
+
+ // less-used session is reclaimed next
+ EXPECT_TRUE(mDrmSessionManager->reclaimSession(highPriorityPid));
+ EXPECT_FALSE(mTestDrm1->isReclaimed());
+ EXPECT_TRUE(mTestDrm2->isReclaimed());
+ EXPECT_TRUE(mTestDrm3->isReclaimed());
+
+ // most-used session still open
+ EXPECT_EQ(1u, mDrmSessionManager->getSessionCount());
+ EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm1->mSessionId));
+ EXPECT_FALSE(mDrmSessionManager->containsSession(mTestDrm2->mSessionId));
+ EXPECT_FALSE(mDrmSessionManager->containsSession(mTestDrm3->mSessionId));
}
} // namespace android
diff --git a/media/libmediatranscoding/.clang-format b/media/libmediatranscoding/.clang-format
new file mode 100644
index 0000000..3198d00
--- /dev/null
+++ b/media/libmediatranscoding/.clang-format
@@ -0,0 +1,29 @@
+#
+# Copyright (C) 2020 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+BasedOnStyle: Google
+AllowShortFunctionsOnASingleLine: Inline
+AllowShortIfStatementsOnASingleLine: true
+AllowShortLoopsOnASingleLine: true
+BinPackArguments: true
+BinPackParameters: true
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+ContinuationIndentWidth: 8
+DerivePointerAlignment: false
+IndentWidth: 4
+PointerAlignment: Left
+TabWidth: 4
\ No newline at end of file
diff --git a/media/libmediatranscoding/Android.bp b/media/libmediatranscoding/Android.bp
new file mode 100644
index 0000000..7468426
--- /dev/null
+++ b/media/libmediatranscoding/Android.bp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// AIDL interfaces of MediaTranscoding.
+aidl_interface {
+ name: "mediatranscoding_aidl_interface",
+ local_include_dir: "aidl",
+ srcs: [
+ "aidl/android/media/IMediaTranscodingService.aidl",
+ "aidl/android/media/ITranscodingServiceClient.aidl",
+ "aidl/android/media/TranscodingErrorCode.aidl",
+ "aidl/android/media/TranscodingJobPriority.aidl",
+ "aidl/android/media/TranscodingType.aidl",
+ "aidl/android/media/TranscodingVideoCodecType.aidl",
+ "aidl/android/media/TranscodingJobParcel.aidl",
+ "aidl/android/media/TranscodingRequestParcel.aidl",
+ "aidl/android/media/TranscodingResultParcel.aidl",
+ ],
+}
+
+cc_library_shared {
+ name: "libmediatranscoding",
+
+ srcs: [
+ "TranscodingClientManager.cpp"
+ ],
+
+ shared_libs: [
+ "libbinder_ndk",
+ "libcutils",
+ "liblog",
+ "libutils",
+ ],
+
+ export_include_dirs: ["include"],
+
+ static_libs: [
+ "mediatranscoding_aidl_interface-ndk_platform",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wno-error=deprecated-declarations",
+ "-Wall",
+ ],
+
+ sanitize: {
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ cfi: true,
+ },
+}
diff --git a/media/libmediatranscoding/OWNERS b/media/libmediatranscoding/OWNERS
new file mode 100644
index 0000000..02287cb
--- /dev/null
+++ b/media/libmediatranscoding/OWNERS
@@ -0,0 +1,3 @@
+akersten@google.com
+hkuang@google.com
+lnilsson@google.com
diff --git a/media/libmediatranscoding/TranscodingClientManager.cpp b/media/libmediatranscoding/TranscodingClientManager.cpp
new file mode 100644
index 0000000..7252437
--- /dev/null
+++ b/media/libmediatranscoding/TranscodingClientManager.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "TranscodingClientManager"
+
+#include <inttypes.h>
+#include <media/TranscodingClientManager.h>
+#include <utils/Log.h>
+
+namespace android {
+
+using Status = ::ndk::ScopedAStatus;
+
+// static
+TranscodingClientManager& TranscodingClientManager::getInstance() {
+ static TranscodingClientManager gInstance{};
+ return gInstance;
+}
+
+// static
+void TranscodingClientManager::BinderDiedCallback(void* cookie) {
+ int32_t clientId = static_cast<int32_t>(reinterpret_cast<intptr_t>(cookie));
+ ALOGD("Client %" PRId32 " is dead", clientId);
+ // Don't check for pid validity since we know it's already dead.
+ TranscodingClientManager& manager = TranscodingClientManager::getInstance();
+ manager.removeClient(clientId);
+}
+
+TranscodingClientManager::TranscodingClientManager()
+ : mDeathRecipient(AIBinder_DeathRecipient_new(BinderDiedCallback)) {
+ ALOGD("TranscodingClientManager started");
+}
+
+TranscodingClientManager::~TranscodingClientManager() {
+ ALOGD("TranscodingClientManager exited");
+}
+
+bool TranscodingClientManager::isClientIdRegistered(int32_t clientId) const {
+ std::scoped_lock lock{mLock};
+ return mClientIdToClientInfoMap.find(clientId) != mClientIdToClientInfoMap.end();
+}
+
+void TranscodingClientManager::dumpAllClients(int fd, const Vector<String16>& args __unused) {
+ String8 result;
+
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, " Total num of Clients: %zu\n", mClientIdToClientInfoMap.size());
+ result.append(buffer);
+
+ if (mClientIdToClientInfoMap.size() > 0) {
+ snprintf(buffer, SIZE, "========== Dumping all clients =========\n");
+ result.append(buffer);
+ }
+
+ for (const auto& iter : mClientIdToClientInfoMap) {
+ const std::shared_ptr<ITranscodingServiceClient> client = iter.second->mClient;
+ std::string clientName;
+ Status status = client->getName(&clientName);
+ if (!status.isOk()) {
+ ALOGE("Failed to get client: %d information", iter.first);
+ continue;
+ }
+ snprintf(buffer, SIZE, " -- Clients: %d name: %s\n", iter.first, clientName.c_str());
+ result.append(buffer);
+ }
+
+ write(fd, result.string(), result.size());
+}
+
+status_t TranscodingClientManager::addClient(std::unique_ptr<ClientInfo> client) {
+ // Validate the client.
+ if (client == nullptr || client->mClientId < 0 || client->mClientPid < 0 ||
+ client->mClientUid < 0 || client->mClientOpPackageName.empty() ||
+ client->mClientOpPackageName == "") {
+ ALOGE("Invalid client");
+ return BAD_VALUE;
+ }
+
+ std::scoped_lock lock{mLock};
+
+ // Check if the client already exists.
+ if (mClientIdToClientInfoMap.count(client->mClientId) != 0) {
+ ALOGW("Client already exists.");
+ return ALREADY_EXISTS;
+ }
+
+ ALOGD("Adding client id %d pid: %d uid: %d %s", client->mClientId, client->mClientPid,
+ client->mClientUid, client->mClientOpPackageName.c_str());
+
+ AIBinder_linkToDeath(client->mClient->asBinder().get(), mDeathRecipient.get(),
+ reinterpret_cast<void*>(client->mClientId));
+
+ // Adds the new client to the map.
+ mClientIdToClientInfoMap[client->mClientId] = std::move(client);
+
+ return OK;
+}
+
+status_t TranscodingClientManager::removeClient(int32_t clientId) {
+ ALOGD("Removing client id %d", clientId);
+ std::scoped_lock lock{mLock};
+
+ // Checks if the client is valid.
+ auto it = mClientIdToClientInfoMap.find(clientId);
+ if (it == mClientIdToClientInfoMap.end()) {
+ ALOGE("Client id %d does not exist", clientId);
+ return INVALID_OPERATION;
+ }
+
+ std::shared_ptr<ITranscodingServiceClient> client = it->second->mClient;
+
+ // Check if the client still live. If alive, unlink the death.
+ if (client) {
+ AIBinder_unlinkToDeath(client->asBinder().get(), mDeathRecipient.get(),
+ reinterpret_cast<void*>(clientId));
+ }
+
+ // Erase the entry.
+ mClientIdToClientInfoMap.erase(it);
+
+ return OK;
+}
+
+size_t TranscodingClientManager::getNumOfClients() const {
+ std::scoped_lock lock{mLock};
+ return mClientIdToClientInfoMap.size();
+}
+
+} // namespace android
diff --git a/media/libmediatranscoding/aidl/android/media/IMediaTranscodingService.aidl b/media/libmediatranscoding/aidl/android/media/IMediaTranscodingService.aidl
new file mode 100644
index 0000000..07b6c1a
--- /dev/null
+++ b/media/libmediatranscoding/aidl/android/media/IMediaTranscodingService.aidl
@@ -0,0 +1,111 @@
+/**
+ * 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.
+ */
+
+package android.media;
+
+import android.media.TranscodingJobParcel;
+import android.media.TranscodingRequestParcel;
+import android.media.ITranscodingServiceClient;
+
+/**
+ * Binder interface for MediaTranscodingService.
+ *
+ * {@hide}
+ */
+interface IMediaTranscodingService {
+ /**
+ * All MediaTranscoding service and device Binder calls may return a
+ * ServiceSpecificException with the following error codes
+ */
+ const int ERROR_PERMISSION_DENIED = 1;
+ const int ERROR_ALREADY_EXISTS = 2;
+ const int ERROR_ILLEGAL_ARGUMENT = 3;
+ const int ERROR_DISCONNECTED = 4;
+ const int ERROR_TIMED_OUT = 5;
+ const int ERROR_DISABLED = 6;
+ const int ERROR_INVALID_OPERATION = 7;
+
+ /**
+ * Default UID/PID values for non-privileged callers of
+ * registerClient().
+ */
+ const int USE_CALLING_UID = -1;
+ const int USE_CALLING_PID = -1;
+
+ /**
+ * Register the client with the MediaTranscodingService.
+ *
+ * Client must call this function to register itself with the service in order to perform
+ * transcoding. This function will return a unique positive Id assigned by the service.
+ * Client should save this Id and use it for all the transaction with the service.
+ *
+ * @param client interface for the MediaTranscodingService to call the client.
+ * @param opPackageName op package name of the client.
+ * @param clientUid user id of the client.
+ * @param clientPid process id of the client.
+ * @return a unique positive Id assigned to the client by the service, -1 means failed to
+ * register.
+ */
+ int registerClient(in ITranscodingServiceClient client,
+ in String opPackageName,
+ in int clientUid,
+ in int clientPid);
+
+ /**
+ * Unregister the client with the MediaTranscodingService.
+ *
+ * Client will not be able to perform any more transcoding after unregister.
+ *
+ * @param clientId assigned Id of the client.
+ * @return true if succeeds, false otherwise.
+ */
+ boolean unregisterClient(in int clientId);
+
+ /**
+ * Returns the number of clients. This is used for debugging.
+ */
+ int getNumOfClients();
+
+ /**
+ * Submits a transcoding request to MediaTranscodingService.
+ *
+ * @param clientId assigned Id of the client.
+ * @param request a TranscodingRequest contains transcoding configuration.
+ * @param job(output variable) a TranscodingJob generated by the MediaTranscodingService.
+ * @return a unique positive jobId generated by the MediaTranscodingService, -1 means failure.
+ */
+ int submitRequest(in int clientId,
+ in TranscodingRequestParcel request,
+ out TranscodingJobParcel job);
+
+ /**
+ * Cancels a transcoding job.
+ *
+ * @param clientId assigned id of the client.
+ * @param jobId a TranscodingJob generated by the MediaTranscodingService.
+ * @return true if succeeds, false otherwise.
+ */
+ boolean cancelJob(in int clientId, in int jobId);
+
+ /**
+ * Queries the job detail associated with a jobId.
+ *
+ * @param jobId a TranscodingJob generated by the MediaTranscodingService.
+ * @param job(output variable) the TranscodingJob associated with the jobId.
+ * @return true if succeeds, false otherwise.
+ */
+ boolean getJobWithId(in int jobId, out TranscodingJobParcel job);
+}
diff --git a/media/libmediatranscoding/aidl/android/media/ITranscodingServiceClient.aidl b/media/libmediatranscoding/aidl/android/media/ITranscodingServiceClient.aidl
new file mode 100644
index 0000000..e23c833
--- /dev/null
+++ b/media/libmediatranscoding/aidl/android/media/ITranscodingServiceClient.aidl
@@ -0,0 +1,77 @@
+/**
+ * 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.
+ */
+
+package android.media;
+
+import android.media.TranscodingErrorCode;
+import android.media.TranscodingJobParcel;
+import android.media.TranscodingResultParcel;
+
+/**
+ * ITranscodingServiceClient interface for the MediaTranscodingervice to communicate with the
+ * client.
+ *
+ * {@hide}
+ */
+//TODO(hkuang): Implement the interface.
+interface ITranscodingServiceClient {
+ /**
+ * Retrieves the name of the client.
+ */
+ @utf8InCpp String getName();
+
+ /**
+ * Called when the transcoding associated with the jobId finished.
+ *
+ * @param jobId jobId assigned by the MediaTranscodingService upon receiving request.
+ * @param result contains the transcoded file stats and other transcoding metrics if requested.
+ */
+ oneway void onTranscodingFinished(in int jobId, in TranscodingResultParcel result);
+
+ /**
+ * Called when the transcoding associated with the jobId failed.
+ *
+ * @param jobId jobId assigned by the MediaTranscodingService upon receiving request.
+ * @param errorCode error code that indicates the error.
+ */
+ oneway void onTranscodingFailed(in int jobId, in TranscodingErrorCode errorCode);
+
+ /**
+ * Called when the transcoding configuration associated with the jobId gets updated, i.e. wait
+ * number in the job queue.
+ *
+ * <p> This will only be called if client set requestUpdate to be true in the TranscodingRequest
+ * submitted to the MediaTranscodingService.
+ *
+ * @param jobId jobId assigned by the MediaTranscodingService upon receiving request.
+ * @param oldAwaitNumber previous number of jobs ahead of current job.
+ * @param newAwaitNumber updated number of jobs ahead of current job.
+ */
+ oneway void onAwaitNumberOfJobsChanged(in int jobId,
+ in int oldAwaitNumber,
+ in int newAwaitNumber);
+
+ /**
+ * Called when there is an update on the progress of the TranscodingJob.
+ *
+ * <p> This will only be called if client set requestUpdate to be true in the TranscodingRequest
+ * submitted to the MediaTranscodingService.
+ *
+ * @param jobId jobId assigned by the MediaTranscodingService upon receiving request.
+ * @param progress an integer number ranging from 0 ~ 100 inclusive.
+ */
+ oneway void onProgressUpdate(in int jobId, in int progress);
+}
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingErrorCode.aidl b/media/libmediatranscoding/aidl/android/media/TranscodingErrorCode.aidl
new file mode 100644
index 0000000..7f47fdc
--- /dev/null
+++ b/media/libmediatranscoding/aidl/android/media/TranscodingErrorCode.aidl
@@ -0,0 +1,33 @@
+/**
+ * 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.
+ */
+
+package android.media;
+
+/**
+ * Type enums of video transcoding errors.
+ *
+ * {@hide}
+ */
+@Backing(type = "int")
+enum TranscodingErrorCode {
+ kUnknown = 0,
+ kUnsupported = 1,
+ kDecoderError = 2,
+ kEncoderError = 3,
+ kExtractorError = 4,
+ kMuxerError = 5,
+ kInvalidBitstream = 6
+}
\ No newline at end of file
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingJobParcel.aidl b/media/libmediatranscoding/aidl/android/media/TranscodingJobParcel.aidl
new file mode 100644
index 0000000..d912c38
--- /dev/null
+++ b/media/libmediatranscoding/aidl/android/media/TranscodingJobParcel.aidl
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+package android.media;
+
+import android.media.TranscodingRequestParcel;
+
+/**
+ * TranscodingJob is generated by the MediaTranscodingService upon receiving a TranscodingRequest.
+ * It contains all the necessary configuration generated by the MediaTranscodingService for the
+ * TranscodingRequest.
+ *
+ * {@hide}
+ */
+//TODO(hkuang): Implement the parcelable.
+parcelable TranscodingJobParcel {
+ /**
+ * A unique positive Id generated by the MediaTranscodingService.
+ */
+ int jobId;
+
+ /**
+ * The request associated with the TranscodingJob.
+ */
+ TranscodingRequestParcel request;
+
+ /**
+ * Current number of jobs ahead of this job. The service schedules the job based on the priority
+ * passed from the client. Client could specify whether to receive updates when the
+ * awaitNumberOfJobs changes through setting requestProgressUpdate in the TranscodingRequest.
+ */
+ int awaitNumberOfJobs;
+}
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl b/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
new file mode 100644
index 0000000..1a5d81a
--- /dev/null
+++ b/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+/**
+ * Priority of a transcoding job.
+ *
+ * {@hide}
+ */
+@Backing(type="int")
+enum TranscodingJobPriority {
+ // TODO(hkuang): define what each priority level actually mean.
+ kUnspecified = 0,
+ kLow = 1,
+ /**
+ * 2 ~ 20 is reserved for future use.
+ */
+ kNormal = 21,
+ /**
+ * 22 ~ 30 is reserved for future use.
+ */
+ kHigh = 31,
+}
\ No newline at end of file
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingRequestParcel.aidl b/media/libmediatranscoding/aidl/android/media/TranscodingRequestParcel.aidl
new file mode 100644
index 0000000..7b7986d
--- /dev/null
+++ b/media/libmediatranscoding/aidl/android/media/TranscodingRequestParcel.aidl
@@ -0,0 +1,58 @@
+/**
+ * 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.
+ */
+
+package android.media;
+
+import android.media.TranscodingJobPriority;
+import android.media.TranscodingType;
+
+/**
+ * TranscodingRequest contains the desired configuration for the transcoding.
+ *
+ * {@hide}
+ */
+//TODO(hkuang): Implement the parcelable.
+parcelable TranscodingRequestParcel {
+ /**
+ * Name of file to be transcoded.
+ */
+ @utf8InCpp String fileName;
+
+ /**
+ * Type of the transcoding.
+ */
+ TranscodingType transcodingType;
+
+ /**
+ * Input source file descriptor.
+ */
+ ParcelFileDescriptor inFd;
+
+ /**
+ * Output transcoded file descriptor.
+ */
+ ParcelFileDescriptor outFd;
+
+ /**
+ * Priority of this transcoding. Service will schedule the transcoding based on the priority.
+ */
+ TranscodingJobPriority priority;
+
+ /**
+ * Whether to receive update on progress and change of awaitNumJobs.
+ */
+ boolean requestUpdate;
+}
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingResultParcel.aidl b/media/libmediatranscoding/aidl/android/media/TranscodingResultParcel.aidl
new file mode 100644
index 0000000..65c49e7
--- /dev/null
+++ b/media/libmediatranscoding/aidl/android/media/TranscodingResultParcel.aidl
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+package android.media;
+
+/**
+ * Result of the transcoding.
+ *
+ * {@hide}
+ */
+//TODO(hkuang): Implement the parcelable.
+parcelable TranscodingResultParcel {
+ /**
+ * The jobId associated with the TranscodingResult.
+ */
+ int jobId;
+
+ /**
+ * Actual bitrate of the transcoded video in bits per second. This will only present for video
+ * transcoding. -1 means not available.
+ */
+ int actualBitrateBps;
+
+ // TODO(hkuang): Add more fields.
+}
\ No newline at end of file
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingType.aidl b/media/libmediatranscoding/aidl/android/media/TranscodingType.aidl
new file mode 100644
index 0000000..9184c87
--- /dev/null
+++ b/media/libmediatranscoding/aidl/android/media/TranscodingType.aidl
@@ -0,0 +1,29 @@
+/**
+ * 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.
+ */
+
+package android.media;
+
+/**
+ * Type of transcoding.
+ *
+ * {@hide}
+ */
+@Backing(type = "int")
+enum TranscodingType {
+ kUnknown = 0,
+ kVideoTranscoding = 1,
+ kImageTranscoding = 2,
+}
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingVideoCodecType.aidl b/media/libmediatranscoding/aidl/android/media/TranscodingVideoCodecType.aidl
new file mode 100644
index 0000000..5dab4f2
--- /dev/null
+++ b/media/libmediatranscoding/aidl/android/media/TranscodingVideoCodecType.aidl
@@ -0,0 +1,29 @@
+/**
+ * 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.
+ */
+
+package android.media;
+
+/**
+ * Type enums of video codec type.
+ *
+ * {@hide}
+ */
+@Backing(type = "int")
+enum TranscodingVideoCodecType {
+ kUnspecified = 0,
+ kAvc = 1,
+ kHevc = 2,
+}
\ No newline at end of file
diff --git a/media/libmediatranscoding/include/media/AdjustableMaxPriorityQueue.h b/media/libmediatranscoding/include/media/AdjustableMaxPriorityQueue.h
new file mode 100644
index 0000000..0e8dcfd
--- /dev/null
+++ b/media/libmediatranscoding/include/media/AdjustableMaxPriorityQueue.h
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_ADJUSTABLE_MAX_PRIORITY_QUEUE_H
+#define ANDROID_MEDIA_ADJUSTABLE_MAX_PRIORITY_QUEUE_H
+
+#include <utils/Log.h>
+
+#include <functional>
+#include <iostream>
+#include <vector>
+
+namespace android {
+
+/*
+ * AdjustableMaxPriorityQueue is a custom max priority queue that helps managing jobs for
+ * MediaTranscodingService.
+ *
+ * AdjustableMaxPriorityQueue is a wrapper template around the STL's *_heap() functions.
+ * - Internally, it uses a std::vector<T> to store elements in a heap order.
+ * - Support adjusting item's priority while maintaining the heap property.
+ * - Support removing any item in the heap while maintaining the heap property. Note that the
+ * removal complexity will be O(n) in worst case.
+ * - AdjustableMaxPriorityQueue needs T::operator<() at instantiation time
+ */
+template <class T, class Comparator = std::less<T>>
+class AdjustableMaxPriorityQueue {
+ public:
+ typedef typename std::vector<T>::iterator iterator;
+ typedef typename std::vector<T>::const_iterator const_iterator;
+
+ AdjustableMaxPriorityQueue();
+
+ /* Whether the queue is empty. */
+ bool empty() const;
+
+ /* Number of items in the queue. */
+ int size() const;
+
+ /* Return the top element in the queue. The queue still owns the element. */
+ const T& top() const;
+
+ /* Discards the element with highest value based on the given comparator. */
+ void pop();
+
+ /* Erases all the elements in the queue. */
+ void clear();
+
+ /*
+ * Returns the element with the highest value based on the given comparator. Queue transfer the
+ * ownership of the item to the caller. Client MUST call empty() to check whether there is
+ * element at the top before calling this.
+ */
+ T consume_top();
+
+ /* Adds an element to the heap. The queue will make a deep copy of the element. */
+ bool push(const T& item) { return pushInternal(item); }
+
+ /* Adds an element to the heap. The queue will take ownership of the element. */
+ bool push(T&& item) { return pushInternal(std::move(item)); }
+
+ /* Adds a new element to the AdjustableMaxPriorityQueue. This new element is constructed in
+ * place passing args as the arguments for its constructor. */
+ template <class... Args>
+ bool emplace(Args&&... args);
+
+ /* Remove an element from a AdjustableMaxPriorityQueue. */
+ void erase(iterator pos);
+
+ /*
+ * Rebuild a heap based on the given comparator. This MUST be called after changing the value
+ * of items.
+ */
+ void rebuild();
+
+ /*
+ * Iterators used for accessing and changing the priority.
+ * If you change the value of items through these access iterators BE SURE to call rebuild() to
+ * ensure the integrity of the heap is maintained.
+ * NOTE: The iterator pos will change after calling rebuild().
+ */
+ const iterator begin();
+ const iterator end();
+
+ /*
+ * Iterators used for accessing the priority.
+ */
+ const const_iterator begin() const;
+ const const_iterator end() const;
+
+ /* Return the backbone storage of this PriorityQueue. Mainly used for debugging. */
+ const std::vector<T>& getStorage() const { return mHeap; };
+
+ private:
+ std::vector<T> mHeap;
+
+ /* Implementation shared by both public push() methods. */
+ template <class Arg>
+ bool pushInternal(Arg&& item);
+};
+
+template <class T, class Comparator>
+AdjustableMaxPriorityQueue<T, Comparator>::AdjustableMaxPriorityQueue() {}
+
+template <class T, class Comparator>
+bool AdjustableMaxPriorityQueue<T, Comparator>::empty() const {
+ return mHeap.empty();
+}
+
+template <class T, class Comparator>
+int AdjustableMaxPriorityQueue<T, Comparator>::size() const {
+ return mHeap.size();
+}
+
+template <class T, class Comparator>
+const T& AdjustableMaxPriorityQueue<T, Comparator>::top() const {
+ DCHECK(!mHeap.empty());
+ return mHeap.front();
+}
+
+// Compares elements and potentially swaps (or moves) them until rearranged as a longer heap.
+// Complexity of this: Up to logarithmic in the distance between first and last.
+template <class T, class Comparator>
+template <class Arg>
+bool AdjustableMaxPriorityQueue<T, Comparator>::pushInternal(Arg&& item) {
+ mHeap.push_back(std::forward<Arg>(item));
+ std::push_heap(mHeap.begin(), mHeap.end(), Comparator());
+ return true;
+}
+
+template <class T, class Comparator>
+template <class... Args>
+bool AdjustableMaxPriorityQueue<T, Comparator>::emplace(Args&&... args) {
+ mHeap.emplace_back(std::forward<Args>(args)...);
+ std::push_heap(mHeap.begin(), mHeap.end(), Comparator());
+ return true;
+}
+
+// Compares elements and potentially swaps (or moves) them until rearranged as a shorter heap.
+// Complexity of this: Up to twice logarithmic in the distance between first and last.
+template <class T, class Comparator>
+void AdjustableMaxPriorityQueue<T, Comparator>::pop() {
+ DCHECK(!mHeap.empty());
+ std::pop_heap(mHeap.begin(), mHeap.end(), Comparator());
+ mHeap.pop_back();
+}
+
+// Compares elements and potentially swaps (or moves) them until rearranged as a shorter heap.
+// Complexity of this: Up to twice logarithmic in the distance between first and last.
+template <class T, class Comparator>
+T AdjustableMaxPriorityQueue<T, Comparator>::consume_top() {
+ DCHECK(!mHeap.empty());
+ std::pop_heap(mHeap.begin(), mHeap.end(), Comparator());
+ T to_return = std::move(mHeap.back());
+ mHeap.pop_back();
+ return to_return;
+}
+
+template <class T, class Comparator>
+const typename AdjustableMaxPriorityQueue<T, Comparator>::iterator
+AdjustableMaxPriorityQueue<T, Comparator>::begin() {
+ return mHeap.begin();
+}
+
+template <class T, class Comparator>
+const typename AdjustableMaxPriorityQueue<T, Comparator>::iterator
+AdjustableMaxPriorityQueue<T, Comparator>::end() {
+ return mHeap.end();
+}
+
+template <class T, class Comparator>
+const typename AdjustableMaxPriorityQueue<T, Comparator>::const_iterator
+AdjustableMaxPriorityQueue<T, Comparator>::begin() const {
+ return mHeap.begin();
+}
+
+template <class T, class Comparator>
+const typename AdjustableMaxPriorityQueue<T, Comparator>::const_iterator
+AdjustableMaxPriorityQueue<T, Comparator>::end() const {
+ return mHeap.end();
+}
+
+template <class T, class Comparator>
+void AdjustableMaxPriorityQueue<T, Comparator>::clear() {
+ mHeap.erase(mHeap.begin(), mHeap.end());
+}
+
+// Complexity of this: At most 3*std::distance(first, last) comparisons.
+template <class T, class Comparator>
+void AdjustableMaxPriorityQueue<T, Comparator>::rebuild() {
+ std::make_heap(mHeap.begin(), mHeap.end(), Comparator());
+}
+
+// Remove a random element from a AdjustableMaxPriorityQueue.
+template <class T, class Comparator>
+void AdjustableMaxPriorityQueue<T, Comparator>::erase(iterator pos) {
+ DCHECK(!mHeap.empty());
+ mHeap.erase(pos);
+ rebuild();
+}
+
+} // namespace android
+#endif // ANDROID_MEDIA_ADJUSTABLE_MAX_PRIORITY_QUEUE_H
\ No newline at end of file
diff --git a/media/libmediatranscoding/include/media/TranscodingClientManager.h b/media/libmediatranscoding/include/media/TranscodingClientManager.h
new file mode 100644
index 0000000..eec120a
--- /dev/null
+++ b/media/libmediatranscoding/include/media/TranscodingClientManager.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_TRANSCODING_CLIENT_MANAGER_H
+#define ANDROID_MEDIA_TRANSCODING_CLIENT_MANAGER_H
+
+#include <aidl/android/media/BnTranscodingServiceClient.h>
+#include <android/binder_ibinder.h>
+#include <sys/types.h>
+#include <utils/Condition.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+#include <mutex>
+#include <unordered_map>
+
+namespace android {
+
+using ::aidl::android::media::ITranscodingServiceClient;
+
+class MediaTranscodingService;
+
+/*
+ * TranscodingClientManager manages all the transcoding clients across different processes.
+ *
+ * TranscodingClientManager is a global singleton that could only acquired by
+ * MediaTranscodingService. It manages all the clients's registration/unregistration and clients'
+ * information. It also bookkeeps all the clients' information. It also monitors to the death of the
+ * clients. Upon client's death, it will remove the client from it.
+ *
+ * TODO(hkuang): Hook up with ResourceManager for resource management.
+ * TODO(hkuang): Hook up with MediaMetrics to log all the transactions.
+ */
+class TranscodingClientManager {
+ public:
+ virtual ~TranscodingClientManager();
+
+ /**
+ * ClientInfo contains a single client's information.
+ */
+ struct ClientInfo {
+ /* The remote client that this ClientInfo is associated with. */
+ std::shared_ptr<ITranscodingServiceClient> mClient;
+ /* A unique positive Id assigned to the client by the service. */
+ int32_t mClientId;
+ /* Process id of the client */
+ int32_t mClientPid;
+ /* User id of the client. */
+ int32_t mClientUid;
+ /* Package name of the client. */
+ std::string mClientOpPackageName;
+
+ ClientInfo(const std::shared_ptr<ITranscodingServiceClient>& client, int64_t clientId,
+ int32_t pid, int32_t uid, const std::string& opPackageName)
+ : mClient(client),
+ mClientId(clientId),
+ mClientPid(pid),
+ mClientUid(uid),
+ mClientOpPackageName(opPackageName) {}
+ };
+
+ /**
+ * Adds a new client to the manager.
+ *
+ * The client must have valid clientId, pid, uid and opPackageName, otherwise, this will return
+ * a non-zero errorcode. If the client has already been added, it will also return non-zero
+ * errorcode.
+ *
+ * @param client to be added to the manager.
+ * @return 0 if client is added successfully, non-zero errorcode otherwise.
+ */
+ status_t addClient(std::unique_ptr<ClientInfo> client);
+
+ /**
+ * Removes an existing client from the manager.
+ *
+ * If the client does not exist, this will return non-zero errorcode.
+ *
+ * @param clientId id of the client to be removed..
+ * @return 0 if client is removed successfully, non-zero errorcode otherwise.
+ */
+ status_t removeClient(int32_t clientId);
+
+ /**
+ * Gets the number of clients.
+ */
+ size_t getNumOfClients() const;
+
+ /**
+ * Checks if a client with clientId is already registered.
+ */
+ bool isClientIdRegistered(int32_t clientId) const;
+
+ /**
+ * Dump all the client information to the fd.
+ */
+ void dumpAllClients(int fd, const Vector<String16>& args);
+
+ private:
+ friend class MediaTranscodingService;
+ friend class TranscodingClientManagerTest;
+
+ /** Get the singleton instance of the TranscodingClientManager. */
+ static TranscodingClientManager& getInstance();
+
+ TranscodingClientManager();
+
+ static void BinderDiedCallback(void* cookie);
+
+ mutable std::mutex mLock;
+ std::unordered_map<int32_t, std::unique_ptr<ClientInfo>> mClientIdToClientInfoMap
+ GUARDED_BY(mLock);
+
+ ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+};
+
+} // namespace android
+#endif // ANDROID_MEDIA_TRANSCODING_SERVICE_H
diff --git a/media/libmediatranscoding/tests/AdjustableMaxPriorityQueue_tests.cpp b/media/libmediatranscoding/tests/AdjustableMaxPriorityQueue_tests.cpp
new file mode 100644
index 0000000..d58af4e
--- /dev/null
+++ b/media/libmediatranscoding/tests/AdjustableMaxPriorityQueue_tests.cpp
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Unit Test for AdjustableMaxPriorityQueue
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "AdjustableMaxPriorityQueueTest"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <gtest/gtest.h>
+#include <media/AdjustableMaxPriorityQueue.h>
+#include <utils/Log.h>
+
+#include <algorithm>
+#include <functional>
+#include <iterator>
+#include <list>
+#include <queue>
+#include <unordered_map>
+
+namespace android {
+
+class IntUniquePtrComp {
+ public:
+ bool operator()(const std::unique_ptr<int>& lhs, const std::unique_ptr<int>& rhs) const {
+ return *lhs < *rhs;
+ }
+};
+
+// Test the heap property and make sure it is the same as std::priority_queue.
+TEST(AdjustableMaxPriorityQueueTest, BasicAPIS) {
+ AdjustableMaxPriorityQueue<std::pair<float, char*>> heap;
+ std::priority_queue<std::pair<float, char*>> pq;
+ AdjustableMaxPriorityQueue<std::pair<float, char*>> remove_queue;
+
+ // Push a set of values onto both AdjustableMaxPriorityQueue and priority_queue
+ // Also compute the sum of those values
+ double sum = 0;
+ for (int i = 0; i < 10; ++i) {
+ float value = 2.1 * i;
+ sum += value;
+ heap.push(std::pair<float, char*>(value, nullptr));
+ pq.push(std::pair<float, char*>(value, nullptr));
+ remove_queue.push(std::pair<float, char*>(value, nullptr));
+ }
+
+ // Test the iterator by using it to subtract all values from earlier sum
+ AdjustableMaxPriorityQueue<std::pair<float, char*>>::iterator it;
+ for (it = heap.begin(); it != heap.end(); ++it) {
+ sum -= it->first;
+ }
+ EXPECT_EQ(0, sum);
+
+ // Test the size();
+ EXPECT_EQ(10, heap.size());
+
+ // Testing pop() by popping values from both queues and compare if they are the same.
+ // Also check each pop is smaller than the previous pop max value.
+ float max = 1000;
+ while (!heap.empty()) {
+ float value = heap.top().first;
+ ALOGD("Value is %f ", value);
+ EXPECT_EQ(value, pq.top().first);
+ EXPECT_LE(value, max);
+ max = value;
+ heap.pop();
+ pq.pop();
+ }
+
+ // Test erase() by removing values and ensuring the heap
+ // condition is still met as miscellaneous elements are
+ // removed from the heap.
+ int iteration_mixer = 0;
+ float previous_value = remove_queue.top().first;
+
+ while (!remove_queue.empty()) {
+ int iteration_count = iteration_mixer % remove_queue.size();
+
+ AdjustableMaxPriorityQueue<std::pair<float, char*>>::iterator iterator =
+ remove_queue.begin();
+
+ // Empty loop as we just want to advance the iterator.
+ for (int i = 0; i < iteration_count; ++i, ++iterator) {
+ }
+
+ remove_queue.erase(iterator);
+ float value = remove_queue.top().first;
+ remove_queue.pop();
+
+ EXPECT_GE(previous_value, value);
+
+ ++iteration_mixer;
+ previous_value = value;
+ }
+}
+
+TEST(AdjustableMaxPriorityQueueTest, BasicWithMoveOnly) {
+ AdjustableMaxPriorityQueue<std::unique_ptr<int>, IntUniquePtrComp> heap;
+
+ auto smaller = std::make_unique<int>(1);
+ EXPECT_TRUE(heap.push(std::move(smaller)));
+ EXPECT_EQ(1, *heap.top());
+ EXPECT_EQ(1, heap.size());
+
+ auto bigger = std::make_unique<int>(2);
+ heap.push(std::move(bigger));
+ EXPECT_EQ(2, *heap.top());
+
+ auto biggest = std::make_unique<int>(3);
+ EXPECT_TRUE(heap.push(std::move(biggest)));
+
+ EXPECT_EQ(3, heap.size());
+ // Biggest should be on top.
+ EXPECT_EQ(3, *heap.top());
+
+ biggest = heap.consume_top();
+ EXPECT_EQ(3, *biggest);
+
+ bigger = heap.consume_top();
+ EXPECT_EQ(2, *bigger);
+
+ smaller = heap.consume_top();
+ EXPECT_EQ(1, *smaller);
+
+ EXPECT_TRUE(heap.empty());
+}
+
+TEST(AdjustableMaxPriorityQueueTest, TestChangingItem) {
+ AdjustableMaxPriorityQueue<std::unique_ptr<int>, IntUniquePtrComp> heap;
+ using HeapIterator =
+ AdjustableMaxPriorityQueue<std::unique_ptr<int>, IntUniquePtrComp>::iterator;
+
+ int testValues[] = {1, 2, 3};
+ // Map to save each value's position in the heap.
+ std::unordered_map<int, HeapIterator> itemToIterratorMap;
+
+ // Insert the test values into the heap.
+ for (auto value : testValues) {
+ auto item = std::make_unique<int>(value);
+ EXPECT_TRUE(heap.push(std::move(item)));
+ }
+
+ // Save each value and its pos in the heap into the map.
+ for (HeapIterator iter = heap.begin(); iter != heap.end(); iter++) {
+ itemToIterratorMap[*iter->get()] = iter;
+ }
+
+ // Change the item with value 1 -> 4. And expects the 4 to be the top of the HEAP after that.
+ // After changing, the heap should contain [2,3,4].
+ auto newValue = std::make_unique<int>(4);
+ itemToIterratorMap[1]->swap(newValue);
+ heap.rebuild();
+ EXPECT_EQ(4, *heap.top());
+
+ // Change the item with value 2 -> 5. And expects the 5 to be the top of the HEAP after that.
+ auto newValue2 = std::make_unique<int>(5);
+ itemToIterratorMap[2]->swap(newValue2);
+ heap.rebuild();
+ EXPECT_EQ(5, *heap.top());
+}
+
+TEST(AdjustableMaxPriorityQueueTest, TestErasingItem) {
+ AdjustableMaxPriorityQueue<std::unique_ptr<int>, IntUniquePtrComp> heap;
+ using HeapIterator =
+ AdjustableMaxPriorityQueue<std::unique_ptr<int>, IntUniquePtrComp>::iterator;
+
+ int testValues[] = {1, 2, 3};
+ // Map to save each value's position in the heap.
+ std::unordered_map<int, HeapIterator> itemToIterratorMap;
+
+ // Insert the test values into the heap.
+ for (auto value : testValues) {
+ auto item = std::make_unique<int>(value);
+ EXPECT_TRUE(heap.push(std::move(item)));
+ }
+
+ // Save each value and its pos in the heap into the map.
+ for (HeapIterator iter = heap.begin(); iter != heap.end(); iter++) {
+ itemToIterratorMap[*iter->get()] = iter;
+ }
+
+ // The top of the heap must be 3.
+ EXPECT_EQ(3, *heap.top());
+
+ // Remove 3 and the top of the heap should be 2.
+ heap.erase(itemToIterratorMap[3]);
+ EXPECT_EQ(2, *heap.top());
+
+ // Reset the iter pos in the heap.
+ itemToIterratorMap.clear();
+ for (HeapIterator iter = heap.begin(); iter != heap.end(); iter++) {
+ itemToIterratorMap[*iter->get()] = iter;
+ }
+
+ // Remove 2 and the top of the heap should be 1.
+ heap.erase(itemToIterratorMap[2]);
+ EXPECT_EQ(1, *heap.top());
+
+ // Reset the iter pos in the heap as iterator pos changed after
+ itemToIterratorMap.clear();
+ for (HeapIterator iter = heap.begin(); iter != heap.end(); iter++) {
+ itemToIterratorMap[*iter->get()] = iter;
+ }
+
+ // Remove 1 and the heap should be empty.
+ heap.erase(itemToIterratorMap[1]);
+ EXPECT_TRUE(heap.empty());
+}
+
+// Test the heap property and make sure it is the same as std::priority_queue.
+TEST(AdjustableMaxPriorityQueueTest, TranscodingJobTest) {
+ // Test data structure that mimics the Transcoding job.
+ struct TranscodingJob {
+ int32_t priority;
+ int64_t createTimeUs;
+ };
+
+ // The job is arranging according to priority with highest priority comes first.
+ // For the job with the same priority, the job with early createTime will come first.
+ class TranscodingJobComp {
+ public:
+ bool operator()(const std::unique_ptr<TranscodingJob>& lhs,
+ const std::unique_ptr<TranscodingJob>& rhs) const {
+ if (lhs->priority != rhs->priority) {
+ return lhs->priority < rhs->priority;
+ }
+ return lhs->createTimeUs > rhs->createTimeUs;
+ }
+ };
+
+ // Map to save each value's position in the heap.
+ std::unordered_map<int, TranscodingJob*> jobIdToJobMap;
+
+ TranscodingJob testJobs[] = {
+ {1 /*priority*/, 66 /*createTimeUs*/}, // First job,
+ {2 /*priority*/, 67 /*createTimeUs*/}, // Second job,
+ {2 /*priority*/, 66 /*createTimeUs*/}, // Third job,
+ {3 /*priority*/, 68 /*createTimeUs*/}, // Fourth job.
+ };
+
+ AdjustableMaxPriorityQueue<std::unique_ptr<TranscodingJob>, TranscodingJobComp> jobQueue;
+
+ // Pushes all the jobs into the heap.
+ for (int jobId = 0; jobId < 4; ++jobId) {
+ auto newJob = std::make_unique<TranscodingJob>(testJobs[jobId]);
+ jobIdToJobMap[jobId] = newJob.get();
+ EXPECT_TRUE(jobQueue.push(std::move(newJob)));
+ }
+
+ // Check the job queue size.
+ EXPECT_EQ(4, jobQueue.size());
+
+ // Check the top and it should be Forth job: (3, 68)
+ const std::unique_ptr<TranscodingJob>& topJob = jobQueue.top();
+ EXPECT_EQ(3, topJob->priority);
+ EXPECT_EQ(68, topJob->createTimeUs);
+
+ // Consume the top.
+ std::unique_ptr<TranscodingJob> consumeJob = jobQueue.consume_top();
+
+ // Check the top and it should be Third Job (2, 66)
+ const std::unique_ptr<TranscodingJob>& topJob2 = jobQueue.top();
+ EXPECT_EQ(2, topJob2->priority);
+ EXPECT_EQ(66, topJob2->createTimeUs);
+
+ // Change the Second job's priority to 4 from (2, 67) -> (4, 67). It should becomes top of the
+ // queue.
+ jobIdToJobMap[1]->priority = 4;
+ jobQueue.rebuild();
+ const std::unique_ptr<TranscodingJob>& topJob3 = jobQueue.top();
+ EXPECT_EQ(4, topJob3->priority);
+ EXPECT_EQ(67, topJob3->createTimeUs);
+}
+} // namespace android
\ No newline at end of file
diff --git a/media/libmediatranscoding/tests/Android.bp b/media/libmediatranscoding/tests/Android.bp
new file mode 100644
index 0000000..8191b00
--- /dev/null
+++ b/media/libmediatranscoding/tests/Android.bp
@@ -0,0 +1,48 @@
+// Build the unit tests for libmediatranscoding.
+cc_defaults {
+ name: "libmediatranscoding_test_defaults",
+
+ header_libs: [
+ "libbase_headers",
+ "libmedia_headers",
+ ],
+
+ shared_libs: [
+ "libbinder_ndk",
+ "libcutils",
+ "liblog",
+ "libutils",
+ "libmediatranscoding"
+ ],
+
+ static_libs: [
+ "mediatranscoding_aidl_interface-ndk_platform",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ test_suites: ["device-tests"],
+}
+
+//
+// TranscodingClientManager unit test
+//
+cc_test {
+ name: "TranscodingClientManager_tests",
+ defaults: ["libmediatranscoding_test_defaults"],
+
+ srcs: ["TranscodingClientManager_tests.cpp"],
+}
+
+//
+// AdjustableMaxPriorityQueue unit test
+//
+cc_test {
+ name: "AdjustableMaxPriorityQueue_tests",
+ defaults: ["libmediatranscoding_test_defaults"],
+
+ srcs: ["AdjustableMaxPriorityQueue_tests.cpp"],
+}
\ No newline at end of file
diff --git a/media/libmediatranscoding/tests/TranscodingClientManager_tests.cpp b/media/libmediatranscoding/tests/TranscodingClientManager_tests.cpp
new file mode 100644
index 0000000..5d2419d
--- /dev/null
+++ b/media/libmediatranscoding/tests/TranscodingClientManager_tests.cpp
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Unit Test for TranscodingClientManager
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "TranscodingClientManagerTest"
+
+#include <aidl/android/media/BnTranscodingServiceClient.h>
+#include <aidl/android/media/IMediaTranscodingService.h>
+#include <aidl/android/media/ITranscodingServiceClient.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <gtest/gtest.h>
+#include <media/TranscodingClientManager.h>
+#include <utils/Log.h>
+
+namespace android {
+
+using Status = ::ndk::ScopedAStatus;
+using aidl::android::media::BnTranscodingServiceClient;
+using aidl::android::media::IMediaTranscodingService;
+using aidl::android::media::ITranscodingServiceClient;
+
+constexpr int32_t kInvalidClientId = -1;
+constexpr int32_t kInvalidClientPid = -1;
+constexpr int32_t kInvalidClientUid = -1;
+constexpr const char* kInvalidClientOpPackageName = "";
+
+constexpr int32_t kClientId = 1;
+constexpr int32_t kClientPid = 2;
+constexpr int32_t kClientUid = 3;
+constexpr const char* kClientOpPackageName = "TestClient";
+
+struct TestClient : public BnTranscodingServiceClient {
+ TestClient(const std::shared_ptr<IMediaTranscodingService>& service) : mService(service) {
+ ALOGD("TestClient Created");
+ }
+
+ Status getName(std::string* _aidl_return) override {
+ *_aidl_return = "test_client";
+ return Status::ok();
+ }
+
+ Status onTranscodingFinished(
+ int32_t /* in_jobId */,
+ const ::aidl::android::media::TranscodingResultParcel& /* in_result */) override {
+ return Status::ok();
+ }
+
+ Status onTranscodingFailed(
+ int32_t /* in_jobId */,
+ ::aidl::android::media::TranscodingErrorCode /*in_errorCode */) override {
+ return Status::ok();
+ }
+
+ Status onAwaitNumberOfJobsChanged(int32_t /* in_jobId */, int32_t /* in_oldAwaitNumber */,
+ int32_t /* in_newAwaitNumber */) override {
+ return Status::ok();
+ }
+
+ Status onProgressUpdate(int32_t /* in_jobId */, int32_t /* in_progress */) override {
+ return Status::ok();
+ }
+
+ virtual ~TestClient() { ALOGI("TestClient destroyed"); };
+
+ private:
+ std::shared_ptr<IMediaTranscodingService> mService;
+ TestClient(const TestClient&) = delete;
+ TestClient& operator=(const TestClient&) = delete;
+};
+
+class TranscodingClientManagerTest : public ::testing::Test {
+ public:
+ TranscodingClientManagerTest() : mClientManager(TranscodingClientManager::getInstance()) {
+ ALOGD("TranscodingClientManagerTest created");
+ }
+
+ void SetUp() override {
+ ::ndk::SpAIBinder binder(AServiceManager_getService("media.transcoding"));
+ mService = IMediaTranscodingService::fromBinder(binder);
+ if (mService == nullptr) {
+ ALOGE("Failed to connect to the media.trascoding service.");
+ return;
+ }
+
+ mTestClient = ::ndk::SharedRefBase::make<TestClient>(mService);
+ }
+
+ void TearDown() override {
+ ALOGI("TranscodingClientManagerTest tear down");
+ mService = nullptr;
+ }
+
+ ~TranscodingClientManagerTest() { ALOGD("TranscodingClientManagerTest destroyed"); }
+
+ TranscodingClientManager& mClientManager;
+ std::shared_ptr<ITranscodingServiceClient> mTestClient = nullptr;
+ std::shared_ptr<IMediaTranscodingService> mService = nullptr;
+};
+
+TEST_F(TranscodingClientManagerTest, TestAddingWithInvalidClientId) {
+ std::shared_ptr<ITranscodingServiceClient> client =
+ ::ndk::SharedRefBase::make<TestClient>(mService);
+
+ // Create a client with invalid client id.
+ std::unique_ptr<TranscodingClientManager::ClientInfo> clientInfo =
+ std::make_unique<TranscodingClientManager::ClientInfo>(
+ client, kInvalidClientId, kClientPid, kClientUid, kClientOpPackageName);
+
+ // Add the client to the manager and expect failure.
+ status_t err = mClientManager.addClient(std::move(clientInfo));
+ EXPECT_TRUE(err != OK);
+}
+
+TEST_F(TranscodingClientManagerTest, TestAddingWithInvalidClientPid) {
+ std::shared_ptr<ITranscodingServiceClient> client =
+ ::ndk::SharedRefBase::make<TestClient>(mService);
+
+ // Create a client with invalid Pid.
+ std::unique_ptr<TranscodingClientManager::ClientInfo> clientInfo =
+ std::make_unique<TranscodingClientManager::ClientInfo>(
+ client, kClientId, kInvalidClientPid, kClientUid, kClientOpPackageName);
+
+ // Add the client to the manager and expect failure.
+ status_t err = mClientManager.addClient(std::move(clientInfo));
+ EXPECT_TRUE(err != OK);
+}
+
+TEST_F(TranscodingClientManagerTest, TestAddingWithInvalidClientUid) {
+ std::shared_ptr<ITranscodingServiceClient> client =
+ ::ndk::SharedRefBase::make<TestClient>(mService);
+
+ // Create a client with invalid Uid.
+ std::unique_ptr<TranscodingClientManager::ClientInfo> clientInfo =
+ std::make_unique<TranscodingClientManager::ClientInfo>(
+ client, kClientId, kClientPid, kInvalidClientUid, kClientOpPackageName);
+
+ // Add the client to the manager and expect failure.
+ status_t err = mClientManager.addClient(std::move(clientInfo));
+ EXPECT_TRUE(err != OK);
+}
+
+TEST_F(TranscodingClientManagerTest, TestAddingWithInvalidClientPackageName) {
+ std::shared_ptr<ITranscodingServiceClient> client =
+ ::ndk::SharedRefBase::make<TestClient>(mService);
+
+ // Create a client with invalid packagename.
+ std::unique_ptr<TranscodingClientManager::ClientInfo> clientInfo =
+ std::make_unique<TranscodingClientManager::ClientInfo>(
+ client, kClientId, kClientPid, kClientUid, kInvalidClientOpPackageName);
+
+ // Add the client to the manager and expect failure.
+ status_t err = mClientManager.addClient(std::move(clientInfo));
+ EXPECT_TRUE(err != OK);
+}
+
+TEST_F(TranscodingClientManagerTest, TestAddingValidClient) {
+ std::shared_ptr<ITranscodingServiceClient> client1 =
+ ::ndk::SharedRefBase::make<TestClient>(mService);
+
+ std::unique_ptr<TranscodingClientManager::ClientInfo> clientInfo =
+ std::make_unique<TranscodingClientManager::ClientInfo>(
+ client1, kClientId, kClientPid, kClientUid, kClientOpPackageName);
+
+ status_t err = mClientManager.addClient(std::move(clientInfo));
+ EXPECT_TRUE(err == OK);
+
+ size_t numOfClients = mClientManager.getNumOfClients();
+ EXPECT_EQ(numOfClients, 1);
+
+ err = mClientManager.removeClient(kClientId);
+ EXPECT_TRUE(err == OK);
+}
+
+TEST_F(TranscodingClientManagerTest, TestAddingDupliacteClient) {
+ std::shared_ptr<ITranscodingServiceClient> client1 =
+ ::ndk::SharedRefBase::make<TestClient>(mService);
+
+ std::unique_ptr<TranscodingClientManager::ClientInfo> clientInfo =
+ std::make_unique<TranscodingClientManager::ClientInfo>(
+ client1, kClientId, kClientPid, kClientUid, kClientOpPackageName);
+
+ status_t err = mClientManager.addClient(std::move(clientInfo));
+ EXPECT_TRUE(err == OK);
+
+ err = mClientManager.addClient(std::move(clientInfo));
+ EXPECT_TRUE(err != OK);
+
+ err = mClientManager.removeClient(kClientId);
+ EXPECT_TRUE(err == OK);
+}
+
+TEST_F(TranscodingClientManagerTest, TestAddingMultipleClient) {
+ std::shared_ptr<ITranscodingServiceClient> client1 =
+ ::ndk::SharedRefBase::make<TestClient>(mService);
+
+ std::unique_ptr<TranscodingClientManager::ClientInfo> clientInfo1 =
+ std::make_unique<TranscodingClientManager::ClientInfo>(
+ client1, kClientId, kClientPid, kClientUid, kClientOpPackageName);
+
+ status_t err = mClientManager.addClient(std::move(clientInfo1));
+ EXPECT_TRUE(err == OK);
+
+ std::shared_ptr<ITranscodingServiceClient> client2 =
+ ::ndk::SharedRefBase::make<TestClient>(mService);
+
+ std::unique_ptr<TranscodingClientManager::ClientInfo> clientInfo2 =
+ std::make_unique<TranscodingClientManager::ClientInfo>(
+ client2, kClientId + 1, kClientPid, kClientUid, kClientOpPackageName);
+
+ err = mClientManager.addClient(std::move(clientInfo2));
+ EXPECT_TRUE(err == OK);
+
+ std::shared_ptr<ITranscodingServiceClient> client3 =
+ ::ndk::SharedRefBase::make<TestClient>(mService);
+
+ // Create a client with invalid packagename.
+ std::unique_ptr<TranscodingClientManager::ClientInfo> clientInfo3 =
+ std::make_unique<TranscodingClientManager::ClientInfo>(
+ client3, kClientId + 2, kClientPid, kClientUid, kClientOpPackageName);
+
+ err = mClientManager.addClient(std::move(clientInfo3));
+ EXPECT_TRUE(err == OK);
+
+ size_t numOfClients = mClientManager.getNumOfClients();
+ EXPECT_EQ(numOfClients, 3);
+
+ err = mClientManager.removeClient(kClientId);
+ EXPECT_TRUE(err == OK);
+
+ err = mClientManager.removeClient(kClientId + 1);
+ EXPECT_TRUE(err == OK);
+
+ err = mClientManager.removeClient(kClientId + 2);
+ EXPECT_TRUE(err == OK);
+}
+
+TEST_F(TranscodingClientManagerTest, TestRemovingNonExistClient) {
+ status_t err = mClientManager.removeClient(kInvalidClientId);
+ EXPECT_TRUE(err != OK);
+
+ err = mClientManager.removeClient(1000 /* clientId */);
+ EXPECT_TRUE(err != OK);
+}
+
+TEST_F(TranscodingClientManagerTest, TestCheckClientWithClientId) {
+ std::shared_ptr<ITranscodingServiceClient> client =
+ ::ndk::SharedRefBase::make<TestClient>(mService);
+
+ std::unique_ptr<TranscodingClientManager::ClientInfo> clientInfo =
+ std::make_unique<TranscodingClientManager::ClientInfo>(
+ client, kClientId, kClientPid, kClientUid, kClientOpPackageName);
+
+ status_t err = mClientManager.addClient(std::move(clientInfo));
+ EXPECT_TRUE(err == OK);
+
+ bool res = mClientManager.isClientIdRegistered(kClientId);
+ EXPECT_TRUE(res);
+
+ res = mClientManager.isClientIdRegistered(kInvalidClientId);
+ EXPECT_FALSE(res);
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/media/libmediatranscoding/tests/build_and_run_all_unit_tests.sh b/media/libmediatranscoding/tests/build_and_run_all_unit_tests.sh
new file mode 100644
index 0000000..d8e4830
--- /dev/null
+++ b/media/libmediatranscoding/tests/build_and_run_all_unit_tests.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+#
+# Run tests in this directory.
+#
+
+if [ -z "$ANDROID_BUILD_TOP" ]; then
+ echo "Android build environment not set"
+ exit -1
+fi
+
+# ensure we have mm
+. $ANDROID_BUILD_TOP/build/envsetup.sh
+
+mm
+
+echo "waiting for device"
+
+adb root && adb wait-for-device remount && adb sync
+
+echo "========================================"
+
+echo "testing TranscodingClientManager"
+adb shell /data/nativetest64/TranscodingClientManager_tests/TranscodingClientManager_tests
+
+echo "testing AdjustableMaxPriorityQueue"
+adb shell /data/nativetest64/AdjustableMaxPriorityQueue_tests/AdjustableMaxPriorityQueue_tests
diff --git a/media/libnbaio/Android.bp b/media/libnbaio/Android.bp
index a4df38d..04ddcfff 100644
--- a/media/libnbaio/Android.bp
+++ b/media/libnbaio/Android.bp
@@ -1,4 +1,3 @@
-
cc_defaults {
name: "libnbaio_mono_defaults",
srcs: [
@@ -9,20 +8,27 @@
header_libs: [
"libaudioclient_headers",
"libaudio_system_headers",
- "libmedia_headers",
],
export_header_lib_headers: [
"libaudioclient_headers",
- "libmedia_headers",
],
shared_libs: [
"libaudioutils",
+ "libcutils",
"liblog",
"libutils",
],
+ export_shared_lib_headers: [
+ "libaudioutils",
+ ],
export_include_dirs: ["include_mono"],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
}
// libnbaio_mono is the part of libnbaio that is available for vendors to use. Vendor modules can't
@@ -53,20 +59,7 @@
// ],
// static_libs: ["libsndfile"],
- shared_libs: [
- "libaudioutils",
- "libbinder",
- "libcutils",
- "liblog",
- "libutils",
- ],
-
- cflags: [
- "-Werror",
- "-Wall",
- ],
-
- include_dirs: ["system/media/audio_utils/include"],
+ header_libs: ["libaudiohal_headers"],
export_include_dirs: ["include"],
}
diff --git a/media/libnbaio/include_mono/media/nbaio/MonoPipe.h b/media/libnbaio/include_mono/media/nbaio/MonoPipe.h
index c51d0fe..926d84a 100644
--- a/media/libnbaio/include_mono/media/nbaio/MonoPipe.h
+++ b/media/libnbaio/include_mono/media/nbaio/MonoPipe.h
@@ -19,7 +19,7 @@
#include <time.h>
#include <audio_utils/fifo.h>
-#include <media/SingleStateQueue.h>
+#include <media/nbaio/SingleStateQueue.h>
#include <media/nbaio/NBAIO.h>
namespace android {
diff --git a/media/libmedia/include/media/SingleStateQueue.h b/media/libnbaio/include_mono/media/nbaio/SingleStateQueue.h
similarity index 100%
rename from media/libmedia/include/media/SingleStateQueue.h
rename to media/libnbaio/include_mono/media/nbaio/SingleStateQueue.h
diff --git a/media/libnblog/Reader.cpp b/media/libnblog/Reader.cpp
index f556e37..67d028d 100644
--- a/media/libnblog/Reader.cpp
+++ b/media/libnblog/Reader.cpp
@@ -45,7 +45,12 @@
}
Reader::Reader(const sp<IMemory>& iMemory, size_t size, const std::string &name)
- : Reader(iMemory != 0 ? (Shared *) iMemory->pointer() : NULL, size, name)
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
+ : Reader(iMemory != 0 ? (Shared *) iMemory->unsecurePointer() : NULL, size,
+ name)
{
mIMemory = iMemory;
}
@@ -156,7 +161,8 @@
bool Reader::isIMemory(const sp<IMemory>& iMemory) const
{
- return iMemory != 0 && mIMemory != 0 && iMemory->pointer() == mIMemory->pointer();
+ return iMemory != 0 && mIMemory != 0 &&
+ iMemory->unsecurePointer() == mIMemory->unsecurePointer();
}
// We make a set of the invalid types rather than the valid types when aligning
diff --git a/media/libnblog/ReportPerformance.cpp b/media/libnblog/ReportPerformance.cpp
index b050b83..aa678ba 100644
--- a/media/libnblog/ReportPerformance.cpp
+++ b/media/libnblog/ReportPerformance.cpp
@@ -30,7 +30,7 @@
#include <sys/time.h>
#include <utility>
#include <json/json.h>
-#include <media/MediaAnalyticsItem.h>
+#include <media/MediaMetricsItem.h>
#include <media/nblog/Events.h>
#include <media/nblog/PerformanceAnalysis.h>
#include <media/nblog/ReportPerformance.h>
@@ -168,7 +168,7 @@
return false;
}
- std::unique_ptr<MediaAnalyticsItem> item(MediaAnalyticsItem::create("audiothread"));
+ std::unique_ptr<mediametrics::Item> item(mediametrics::Item::create("audiothread"));
const Histogram &workHist = data.workHist;
if (workHist.totalCount() > 0) {
diff --git a/media/libnblog/Writer.cpp b/media/libnblog/Writer.cpp
index da3bd52..86d3b98 100644
--- a/media/libnblog/Writer.cpp
+++ b/media/libnblog/Writer.cpp
@@ -56,7 +56,11 @@
}
Writer::Writer(const sp<IMemory>& iMemory, size_t size)
- : Writer(iMemory != 0 ? (Shared *) iMemory->pointer() : NULL, size)
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
+ : Writer(iMemory != 0 ? (Shared *) iMemory->unsecurePointer() : NULL, size)
{
mIMemory = iMemory;
}
diff --git a/media/libstagefright/AACWriter.cpp b/media/libstagefright/AACWriter.cpp
index e173974..9c0a7a5 100644
--- a/media/libstagefright/AACWriter.cpp
+++ b/media/libstagefright/AACWriter.cpp
@@ -31,7 +31,7 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/mediarecorder.h>
namespace android {
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 44f246d..73d3a0b 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -24,6 +24,8 @@
#include <inttypes.h>
#include <utils/Trace.h>
+#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
+
#include <gui/Surface.h>
#include <media/stagefright/ACodec.h>
@@ -45,6 +47,7 @@
#include <media/hardware/HardwareAPI.h>
#include <media/MediaBufferHolder.h>
#include <media/OMXBuffer.h>
+#include <media/omx/1.0/Conversion.h>
#include <media/omx/1.0/WOmxNode.h>
#include <hidlmemory/mapping.h>
@@ -63,7 +66,9 @@
namespace android {
-using binder::Status;
+typedef hardware::media::omx::V1_0::IGraphicBufferSource HGraphicBufferSource;
+
+using hardware::media::omx::V1_0::Status;
enum {
kMaxIndicesToCheck = 32, // used when enumerating supported formats and profiles
@@ -98,16 +103,11 @@
}
}
-static inline status_t statusFromBinderStatus(const Status &status) {
+static inline status_t statusFromBinderStatus(hardware::Return<Status> &&status) {
if (status.isOk()) {
- return OK;
- }
- status_t err;
- if ((err = status.serviceSpecificErrorCode()) != OK) {
- return err;
- }
- if ((err = status.transactionError()) != OK) {
- return err;
+ return static_cast<status_t>(status.withDefault(Status::UNKNOWN_ERROR));
+ } else if (status.isDeadObject()) {
+ return DEAD_OBJECT;
}
// Other exception
return UNKNOWN_ERROR;
@@ -1310,7 +1310,7 @@
OMX_U32 bufferCount, bufferSize, minUndequeuedBuffers;
status_t err = configureOutputBuffersFromNativeWindow(
&bufferCount, &bufferSize, &minUndequeuedBuffers,
- false /* preregister */);
+ mFlags & kFlagPreregisterMetadataBuffers /* preregister */);
if (err != OK)
return err;
mNumUndequeuedBuffers = minUndequeuedBuffers;
@@ -1780,6 +1780,14 @@
}
}
+ int32_t lowLatency = 0;
+ if (msg->findInt32("low-latency", &lowLatency)) {
+ err = setLowLatency(lowLatency);
+ if (err != OK) {
+ return err;
+ }
+ }
+
int32_t prependSPSPPS = 0;
if (encoder && mIsVideo
&& msg->findInt32("prepend-sps-pps-to-idr-frames", &prependSPSPPS)
@@ -1888,6 +1896,19 @@
setPortMode(kPortIndexInput, IOMX::kPortModePresetByteBuffer);
err = OK; // ignore error for now
}
+
+ OMX_INDEXTYPE index;
+ if (mOMXNode->getExtensionIndex(
+ "OMX.google.android.index.preregisterMetadataBuffers", &index) == OK) {
+ OMX_CONFIG_BOOLEANTYPE param;
+ InitOMXParams(¶m);
+ param.bEnabled = OMX_FALSE;
+ if (mOMXNode->getParameter(index, ¶m, sizeof(param)) == OK) {
+ if (param.bEnabled == OMX_TRUE) {
+ mFlags |= kFlagPreregisterMetadataBuffers;
+ }
+ }
+ }
}
if (haveNativeWindow) {
sp<ANativeWindow> nativeWindow =
@@ -2160,12 +2181,20 @@
}
if (!msg->findInt32("aac-target-ref-level", &drc.targetRefLevel)) {
// value is unknown
- drc.targetRefLevel = -1;
+ drc.targetRefLevel = -2;
}
if (!msg->findInt32("aac-drc-effect-type", &drc.effectType)) {
// value is unknown
drc.effectType = -2; // valid values are -1 and over
}
+ if (!msg->findInt32("aac-drc-album-mode", &drc.albumMode)) {
+ // value is unknown
+ drc.albumMode = -1; // valid values are 0 and 1
+ }
+ if (!msg->findInt32("aac-drc-output-loudness", &drc.outputLoudness)) {
+ // value is unknown
+ drc.outputLoudness = -1;
+ }
err = setupAACCodec(
encoder, numChannels, sampleRate, bitrate, aacProfile,
@@ -2348,6 +2377,24 @@
return err;
}
+status_t ACodec::setLowLatency(int32_t lowLatency) {
+ if (mIsEncoder) {
+ ALOGE("encoder does not support low-latency");
+ return BAD_VALUE;
+ }
+
+ OMX_CONFIG_BOOLEANTYPE config;
+ InitOMXParams(&config);
+ config.bEnabled = (OMX_BOOL)(lowLatency != 0);
+ status_t err = mOMXNode->setConfig(
+ (OMX_INDEXTYPE)OMX_IndexConfigLowLatency,
+ &config, sizeof(config));
+ if (err != OK) {
+ ALOGE("decoder can not set low-latency to %d (err %d)", lowLatency, err);
+ }
+ return err;
+}
+
status_t ACodec::setLatency(uint32_t latency) {
OMX_PARAM_U32TYPE config;
InitOMXParams(&config);
@@ -2410,7 +2457,7 @@
}
rate = (OMX_U32)(rateFloat * 65536.0f + 0.5f);
} else {
- if (rateFloat > UINT_MAX) {
+ if (rateFloat > (float)UINT_MAX) {
return BAD_VALUE;
}
rate = (OMX_U32)(rateFloat);
@@ -2837,6 +2884,8 @@
presentation.nEncodedTargetLevel = drc.encodedTargetLevel;
presentation.nPCMLimiterEnable = pcmLimiterEnable;
presentation.nDrcEffectType = drc.effectType;
+ presentation.nDrcAlbumMode = drc.albumMode;
+ presentation.nDrcOutputLoudness = drc.outputLoudness;
status_t res = mOMXNode->setParameter(
OMX_IndexParamAudioAac, &profile, sizeof(profile));
@@ -3316,6 +3365,7 @@
{ MEDIA_MIMETYPE_VIDEO_VP9, OMX_VIDEO_CodingVP9 },
{ MEDIA_MIMETYPE_VIDEO_DOLBY_VISION, OMX_VIDEO_CodingDolbyVision },
{ MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC, OMX_VIDEO_CodingImageHEIC },
+ { MEDIA_MIMETYPE_VIDEO_AV1, OMX_VIDEO_CodingAV1 },
};
static status_t GetVideoCodingTypeFromMime(
@@ -6880,8 +6930,11 @@
return err;
}
+ using hardware::media::omx::V1_0::utils::TWOmxNode;
err = statusFromBinderStatus(
- mCodec->mGraphicBufferSource->configure(mCodec->mOMXNode, dataSpace));
+ mCodec->mGraphicBufferSource->configure(
+ new TWOmxNode(mCodec->mOMXNode),
+ static_cast<hardware::graphics::common::V1_0::Dataspace>(dataSpace)));
if (err != OK) {
ALOGE("[%s] Unable to configure for node (err %d)",
mCodec->mComponentName.c_str(), err);
@@ -6967,8 +7020,9 @@
}
err = statusFromBinderStatus(
- mCodec->mGraphicBufferSource->setColorAspects(ColorUtils::packToU32(
- *(ColorAspects *)colorAspectsBuffer->base())));
+ mCodec->mGraphicBufferSource->setColorAspects(
+ hardware::media::omx::V1_0::utils::toHardwareColorAspects(
+ *(ColorAspects *)colorAspectsBuffer->base())));
if (err != OK) {
ALOGE("[%s] Unable to configure color aspects (err %d)",
@@ -6984,8 +7038,10 @@
ALOGV("onCreateInputSurface");
sp<IGraphicBufferProducer> bufferProducer;
+ sp<HGraphicBufferSource> bufferSource;
status_t err = mCodec->mOMX->createInputSurface(
- &bufferProducer, &mCodec->mGraphicBufferSource);
+ &bufferProducer, &bufferSource);
+ mCodec->mGraphicBufferSource = bufferSource;
if (err == OK) {
err = setupInputSurface();
@@ -7018,8 +7074,12 @@
}
sp<PersistentSurface> surface = static_cast<PersistentSurface *>(obj.get());
- mCodec->mGraphicBufferSource = surface->getBufferSource();
- status_t err = setupInputSurface();
+ sp<HGraphicBufferSource> hgbs = HGraphicBufferSource::castFrom(surface->getHidlTarget());
+ status_t err = BAD_VALUE;
+ if (hgbs) {
+ mCodec->mGraphicBufferSource = hgbs;
+ err = setupInputSurface();
+ }
if (err == OK) {
mCodec->mCallback->onInputSurfaceAccepted(
@@ -7538,8 +7598,14 @@
}
int64_t stopTimeOffsetUs;
- err = statusFromBinderStatus(
- mGraphicBufferSource->getStopTimeOffsetUs(&stopTimeOffsetUs));
+ hardware::Return<void> trans = mGraphicBufferSource->getStopTimeOffsetUs(
+ [&err, &stopTimeOffsetUs](auto status, auto result) {
+ err = static_cast<status_t>(status);
+ stopTimeOffsetUs = result;
+ });
+ if (!trans.isOk()) {
+ err = trans.isDeadObject() ? DEAD_OBJECT : UNKNOWN_ERROR;
+ }
if (err != OK) {
ALOGE("Failed to get stop time offset (err %d)", err);
@@ -7582,6 +7648,14 @@
}
}
+ int32_t lowLatency = 0;
+ if (params->findInt32("low-latency", &lowLatency)) {
+ status_t err = setLowLatency(lowLatency);
+ if (err != OK) {
+ return err;
+ }
+ }
+
int32_t latency = 0;
if (params->findInt32("latency", &latency) && latency > 0) {
status_t err = setLatency(latency);
diff --git a/media/libstagefright/ACodecBufferChannel.cpp b/media/libstagefright/ACodecBufferChannel.cpp
index 266a240..e5115d9 100644
--- a/media/libstagefright/ACodecBufferChannel.cpp
+++ b/media/libstagefright/ACodecBufferChannel.cpp
@@ -20,7 +20,10 @@
#include <numeric>
+#include <C2Buffer.h>
+
#include <android/hardware/cas/native/1.0/IDescrambler.h>
+#include <android/hardware/drm/1.0/types.h>
#include <binder/MemoryDealer.h>
#include <hidlmemory/FrameworkUtils.h>
#include <media/openmax/OMX_Core.h>
@@ -41,6 +44,7 @@
using hardware::hidl_vec;
using namespace hardware::cas::V1_0;
using namespace hardware::cas::native::V1_0;
+using DrmBufferType = hardware::drm::V1_0::BufferType;
using BufferInfo = ACodecBufferChannel::BufferInfo;
using BufferInfoIterator = std::vector<const BufferInfo>::const_iterator;
@@ -131,18 +135,18 @@
ssize_t result = -1;
ssize_t codecDataOffset = 0;
if (mCrypto != NULL) {
- ICrypto::DestinationBuffer destination;
+ hardware::drm::V1_0::DestinationBuffer destination;
if (secure) {
- destination.mType = ICrypto::kDestinationTypeNativeHandle;
- destination.mHandle = secureHandle;
+ destination.type = DrmBufferType::NATIVE_HANDLE;
+ destination.secureMemory = hidl_handle(secureHandle);
} else {
- destination.mType = ICrypto::kDestinationTypeSharedMemory;
- destination.mSharedMemory = mDecryptDestination;
+ destination.type = DrmBufferType::SHARED_MEMORY;
+ IMemoryToSharedBuffer(
+ mDecryptDestination, mHeapSeqNum, &destination.nonsecureMemory);
}
- ICrypto::SourceBuffer source;
- source.mSharedMemory = it->mSharedEncryptedBuffer;
- source.mHeapSeqNum = mHeapSeqNum;
+ hardware::drm::V1_0::SharedBuffer source;
+ IMemoryToSharedBuffer(it->mSharedEncryptedBuffer, mHeapSeqNum, &source);
result = mCrypto->decrypt(key, iv, mode, pattern,
source, it->mClientBuffer->offset(),
@@ -152,8 +156,8 @@
return result;
}
- if (destination.mType == ICrypto::kDestinationTypeSharedMemory) {
- memcpy(it->mCodecBuffer->base(), destination.mSharedMemory->pointer(), result);
+ if (destination.type == DrmBufferType::SHARED_MEMORY) {
+ memcpy(it->mCodecBuffer->base(), mDecryptDestination->unsecurePointer(), result);
}
} else {
// Here we cast CryptoPlugin::SubSample to hardware::cas::native::V1_0::SubSample
@@ -219,7 +223,8 @@
if (dstBuffer.type == BufferType::SHARED_MEMORY) {
memcpy(it->mCodecBuffer->base(),
- (uint8_t*)it->mSharedEncryptedBuffer->pointer(), result);
+ (uint8_t*)it->mSharedEncryptedBuffer->unsecurePointer(),
+ result);
}
}
@@ -247,6 +252,178 @@
return OK;
}
+status_t ACodecBufferChannel::attachBuffer(
+ const std::shared_ptr<C2Buffer> &c2Buffer,
+ const sp<MediaCodecBuffer> &buffer) {
+ switch (c2Buffer->data().type()) {
+ case C2BufferData::LINEAR: {
+ if (c2Buffer->data().linearBlocks().size() != 1u) {
+ return -ENOSYS;
+ }
+ C2ConstLinearBlock block{c2Buffer->data().linearBlocks().front()};
+ C2ReadView view{block.map().get()};
+ if (view.capacity() > buffer->capacity()) {
+ return -ENOSYS;
+ }
+ memcpy(buffer->base(), view.data(), view.capacity());
+ buffer->setRange(0, view.capacity());
+ break;
+ }
+ case C2BufferData::GRAPHIC: {
+ // TODO
+ return -ENOSYS;
+ }
+ case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
+ case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
+ default:
+ return -ENOSYS;
+ }
+
+ return OK;
+}
+
+int32_t ACodecBufferChannel::getHeapSeqNum(const sp<HidlMemory> &memory) {
+ CHECK(mCrypto);
+ auto it = mHeapSeqNumMap.find(memory);
+ int32_t heapSeqNum = -1;
+ if (it == mHeapSeqNumMap.end()) {
+ heapSeqNum = mCrypto->setHeap(memory);
+ mHeapSeqNumMap.emplace(memory, heapSeqNum);
+ } else {
+ heapSeqNum = it->second;
+ }
+ return heapSeqNum;
+}
+
+status_t ACodecBufferChannel::attachEncryptedBuffer(
+ const sp<hardware::HidlMemory> &memory,
+ bool secure,
+ const uint8_t *key,
+ const uint8_t *iv,
+ CryptoPlugin::Mode mode,
+ CryptoPlugin::Pattern pattern,
+ size_t offset,
+ const CryptoPlugin::SubSample *subSamples,
+ size_t numSubSamples,
+ const sp<MediaCodecBuffer> &buffer) {
+ std::shared_ptr<const std::vector<const BufferInfo>> array(
+ std::atomic_load(&mInputBuffers));
+ BufferInfoIterator it = findClientBuffer(array, buffer);
+ if (it == array->end()) {
+ return -ENOENT;
+ }
+
+ native_handle_t *secureHandle = NULL;
+ if (secure) {
+ sp<SecureBuffer> secureData =
+ static_cast<SecureBuffer *>(it->mCodecBuffer.get());
+ if (secureData->getDestinationType() != ICrypto::kDestinationTypeNativeHandle) {
+ return BAD_VALUE;
+ }
+ secureHandle = static_cast<native_handle_t *>(secureData->getDestinationPointer());
+ }
+ size_t size = 0;
+ for (size_t i = 0; i < numSubSamples; ++i) {
+ size += subSamples[i].mNumBytesOfClearData + subSamples[i].mNumBytesOfEncryptedData;
+ }
+ ssize_t result = -1;
+ ssize_t codecDataOffset = 0;
+ if (mCrypto != NULL) {
+ AString errorDetailMsg;
+ hardware::drm::V1_0::DestinationBuffer destination;
+ if (secure) {
+ destination.type = DrmBufferType::NATIVE_HANDLE;
+ destination.secureMemory = hidl_handle(secureHandle);
+ } else {
+ destination.type = DrmBufferType::SHARED_MEMORY;
+ IMemoryToSharedBuffer(
+ mDecryptDestination, mHeapSeqNum, &destination.nonsecureMemory);
+ }
+
+ int32_t heapSeqNum = getHeapSeqNum(memory);
+ hardware::drm::V1_0::SharedBuffer source{(uint32_t)heapSeqNum, offset, size};
+
+ result = mCrypto->decrypt(key, iv, mode, pattern,
+ source, it->mClientBuffer->offset(),
+ subSamples, numSubSamples, destination, &errorDetailMsg);
+
+ if (result < 0) {
+ return result;
+ }
+
+ if (destination.type == DrmBufferType::SHARED_MEMORY) {
+ memcpy(it->mCodecBuffer->base(), mDecryptDestination->unsecurePointer(), result);
+ }
+ } else {
+ // Here we cast CryptoPlugin::SubSample to hardware::cas::native::V1_0::SubSample
+ // directly, the structure definitions should match as checked in DescramblerImpl.cpp.
+ hidl_vec<SubSample> hidlSubSamples;
+ hidlSubSamples.setToExternal((SubSample *)subSamples, numSubSamples, false /*own*/);
+
+ hardware::cas::native::V1_0::SharedBuffer srcBuffer = {
+ .heapBase = *memory,
+ .offset = (uint64_t) offset,
+ .size = size
+ };
+
+ DestinationBuffer dstBuffer;
+ if (secure) {
+ dstBuffer.type = BufferType::NATIVE_HANDLE;
+ dstBuffer.secureMemory = hidl_handle(secureHandle);
+ } else {
+ dstBuffer.type = BufferType::SHARED_MEMORY;
+ dstBuffer.nonsecureMemory = srcBuffer;
+ }
+
+ Status status = Status::OK;
+ hidl_string detailedError;
+ ScramblingControl sctrl = ScramblingControl::UNSCRAMBLED;
+
+ if (key != NULL) {
+ sctrl = (ScramblingControl)key[0];
+ // Adjust for the PES offset
+ codecDataOffset = key[2] | (key[3] << 8);
+ }
+
+ auto returnVoid = mDescrambler->descramble(
+ sctrl,
+ hidlSubSamples,
+ srcBuffer,
+ 0,
+ dstBuffer,
+ 0,
+ [&status, &result, &detailedError] (
+ Status _status, uint32_t _bytesWritten,
+ const hidl_string& _detailedError) {
+ status = _status;
+ result = (ssize_t)_bytesWritten;
+ detailedError = _detailedError;
+ });
+
+ if (!returnVoid.isOk() || status != Status::OK || result < 0) {
+ ALOGE("descramble failed, trans=%s, status=%d, result=%zd",
+ returnVoid.description().c_str(), status, result);
+ return UNKNOWN_ERROR;
+ }
+
+ if (result < codecDataOffset) {
+ ALOGD("invalid codec data offset: %zd, result %zd", codecDataOffset, result);
+ return BAD_VALUE;
+ }
+
+ ALOGV("descramble succeeded, %zd bytes", result);
+
+ if (dstBuffer.type == BufferType::SHARED_MEMORY) {
+ memcpy(it->mCodecBuffer->base(),
+ (uint8_t*)it->mSharedEncryptedBuffer->unsecurePointer(),
+ result);
+ }
+ }
+
+ it->mCodecBuffer->setRange(codecDataOffset, result - codecDataOffset);
+ return OK;
+}
+
status_t ACodecBufferChannel::renderOutputBuffer(
const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) {
std::shared_ptr<const std::vector<const BufferInfo>> array(
@@ -313,7 +490,8 @@
}
dealer = new MemoryDealer(heapSize, "ACodecBufferChannel");
if (mCrypto != nullptr) {
- int32_t seqNum = mCrypto->setHeap(dealer->getMemoryHeap());
+ sp<HidlMemory> hHeap = fromHeap(dealer->getMemoryHeap());
+ int32_t seqNum = mCrypto->setHeap(hHeap);
if (seqNum >= 0) {
mHeapSeqNum = seqNum;
ALOGV("setHeap returned mHeapSeqNum=%d", mHeapSeqNum);
@@ -429,4 +607,22 @@
it->mClientBuffer);
}
+void ACodecBufferChannel::setCrypto(const sp<ICrypto> &crypto) {
+ if (mCrypto != nullptr) {
+ for (std::pair<wp<HidlMemory>, int32_t> entry : mHeapSeqNumMap) {
+ mCrypto->unsetHeap(entry.second);
+ }
+ mHeapSeqNumMap.clear();
+ if (mHeapSeqNum >= 0) {
+ mCrypto->unsetHeap(mHeapSeqNum);
+ mHeapSeqNum = -1;
+ }
+ }
+ mCrypto = crypto;
+}
+
+void ACodecBufferChannel::setDescrambler(const sp<IDescrambler> &descrambler) {
+ mDescrambler = descrambler;
+}
+
} // namespace android
diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp
index 24f6f0b..a1aa5dd 100644
--- a/media/libstagefright/AMRWriter.cpp
+++ b/media/libstagefright/AMRWriter.cpp
@@ -26,7 +26,7 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/mediarecorder.h>
namespace android {
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 7eab230..a8fea90 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -19,8 +19,10 @@
],
cfi: true,
},
-
- shared_libs: ["libmedia"],
+ shared_libs: [
+ "libstagefright_foundation",
+ "libutils"
+ ],
}
cc_library_static {
@@ -39,7 +41,11 @@
cfi: true,
},
- shared_libs: ["libmedia", "libmediandk"],
+ header_libs: [
+ "libstagefright_foundation_headers",
+ ],
+ shared_libs: ["libmediandk"],
+ export_include_dirs: ["include"],
}
cc_library_shared {
@@ -51,6 +57,7 @@
"CodecBase.cpp",
"FrameRenderTracker.cpp",
"MediaCodecListWriter.cpp",
+ "SkipCutBuffer.cpp",
],
cflags: [
@@ -58,14 +65,22 @@
"-Wall",
],
+ header_libs: [
+ "libmediadrm_headers",
+ "media_ndk_headers",
+ ],
+
shared_libs: [
"libgui",
+ "libhidlallocatorutils",
"liblog",
+ "libmedia_codeclist",
"libmedia_omx",
"libstagefright_foundation",
"libui",
"libutils",
"android.hardware.cas.native@1.0",
+ "android.hardware.drm@1.0",
],
sanitize: {
@@ -88,14 +103,18 @@
shared_libs: [
"liblog",
- "libmedia",
- "libmedia_omx",
],
export_include_dirs: [
"include",
],
+ header_libs: [
+ "libaudioclient_headers",
+ "libmedia_headers",
+ "media_ndk_headers",
+ ],
+
cflags: [
"-Wno-multichar",
"-Werror",
@@ -112,6 +131,53 @@
},
}
+cc_library_shared {
+ name: "libstagefright_framecapture_utils",
+
+ srcs: [
+ "FrameCaptureLayer.cpp",
+ "FrameCaptureProcessor.cpp",
+ ],
+
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libEGL",
+ "libGLESv1_CM",
+ "libGLESv2",
+ "libgui",
+ "liblog",
+ "libprocessgroup",
+ "libstagefright_foundation",
+ "libsync",
+ "libui",
+ "libutils",
+ ],
+
+ static_libs: [
+ "librenderengine",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+
+ cflags: [
+ "-Wno-multichar",
+ "-Werror",
+ "-Wno-error=deprecated-declarations",
+ "-Wall",
+ ],
+
+ sanitize: {
+ // TODO: re-enabled cfi for this lib after b/139945549 fixed
+ cfi: false,
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ },
+}
cc_library {
name: "libstagefright",
@@ -121,7 +187,6 @@
"ACodecBufferChannel.cpp",
"AHierarchicalStateMachine.cpp",
"AMRWriter.cpp",
- "AudioPlayer.cpp",
"AudioSource.cpp",
"BufferImpl.cpp",
"CallbackDataSource.cpp",
@@ -129,12 +194,7 @@
"CameraSource.cpp",
"CameraSourceTimeLapse.cpp",
"DataConverter.cpp",
- "DataSourceFactory.cpp",
- "DataURISource.cpp",
- "ClearFileSource.cpp",
- "FileSource.cpp",
"FrameDecoder.cpp",
- "HTTPBase.cpp",
"HevcUtils.cpp",
"InterfaceUtils.cpp",
"JPEGSource.cpp",
@@ -151,10 +211,7 @@
"MediaSource.cpp",
"MediaSync.cpp",
"MediaTrack.cpp",
- "http/ClearMediaHTTP.cpp",
- "http/MediaHTTP.cpp",
"MediaMuxer.cpp",
- "NuCachedSource2.cpp",
"NuMediaExtractor.cpp",
"OggWriter.cpp",
"OMXClient.cpp",
@@ -162,37 +219,39 @@
"RemoteMediaExtractor.cpp",
"RemoteMediaSource.cpp",
"SimpleDecodingSource.cpp",
- "SkipCutBuffer.cpp",
"StagefrightMediaScanner.cpp",
- "StagefrightMetadataRetriever.cpp",
- "StagefrightPluginLoader.cpp",
"SurfaceUtils.cpp",
- "Utils.cpp",
"ThrottledSource.cpp",
+ "Utils.cpp",
"VideoFrameSchedulerBase.cpp",
"VideoFrameScheduler.cpp",
],
shared_libs: [
+ "libstagefright_framecapture_utils",
"libaudioutils",
"libbase",
"libbinder",
+ "libbinder_ndk",
"libcamera_client",
+ "libcodec2",
+ "libcodec2_vndk",
"libcutils",
+ "libdatasource",
"libdl",
"libdl_android",
- "libdrmframework",
"libgui",
"liblog",
"libmedia",
+ "libmedia_codeclist",
"libmedia_omx",
"libmedia_omx_client",
"libaudioclient",
"libmediametrics",
- "libmediautils",
"libui",
"libutils",
"libmedia_helper",
+ "libsfplugin_ccodec",
"libstagefright_codecbase",
"libstagefright_foundation",
"libstagefright_omx_utils",
@@ -202,10 +261,12 @@
"libhidlmemory",
"android.hidl.allocator@1.0",
"android.hardware.cas.native@1.0",
+ "android.hardware.drm@1.0",
"android.hardware.media.omx@1.0",
],
static_libs: [
+ "libstagefright_esds",
"libstagefright_color_conversion",
"libyuv_static",
"libstagefright_mediafilter",
@@ -213,13 +274,12 @@
"libstagefright_timedtext",
"libogg",
"libwebm",
- "libstagefright_esds",
"libstagefright_id3",
- "libFLAC",
],
header_libs:[
- "libnativeloader-dummy-headers",
+ "libmediadrm_headers",
+ "libnativeloader-headers",
"libstagefright_xmlparser_headers",
"media_ndk_headers",
],
@@ -259,62 +319,3 @@
],
},
}
-
-cc_library_static {
- name: "libstagefright_player2",
-
- srcs: [
- "ClearFileSource.cpp",
- "DataURISource.cpp",
- "HTTPBase.cpp",
- "HevcUtils.cpp",
- "MediaClock.cpp",
- "MediaSource.cpp",
- "NdkUtils.cpp",
- "Utils.cpp",
- "VideoFrameSchedulerBase.cpp",
- "VideoFrameScheduler2.cpp",
- "http/ClearMediaHTTP.cpp",
- ],
-
- shared_libs: [
- "libgui",
- "liblog",
- "libnetd_client",
- "libutils",
- "libstagefright_foundation",
- "libandroid",
- ],
-
- static_libs: [
- "libmedia_player2_util",
- "libmedia2_jni_core",
- ],
-
- export_include_dirs: [
- "include",
- ],
-
- cflags: [
- "-Wno-multichar",
- "-Werror",
- "-Wno-error=deprecated-declarations",
- "-Wall",
- ],
-
- product_variables: {
- debuggable: {
- // enable experiments only in userdebug and eng builds
- cflags: ["-DENABLE_STAGEFRIGHT_EXPERIMENTS"],
- },
- },
-
- sanitize: {
- cfi: true,
- misc_undefined: [
- "unsigned-integer-overflow",
- "signed-integer-overflow",
- ],
- },
-}
-
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
deleted file mode 100644
index 199b57b..0000000
--- a/media/libstagefright/AudioPlayer.cpp
+++ /dev/null
@@ -1,688 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <inttypes.h>
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "AudioPlayer"
-#include <utils/Log.h>
-#include <cutils/compiler.h>
-
-#include <binder/IPCThreadState.h>
-#include <media/AudioTrack.h>
-#include <media/MediaSource.h>
-#include <media/openmax/OMX_Audio.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/ALookup.h>
-#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/AudioPlayer.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
-
-namespace android {
-
-AudioPlayer::AudioPlayer(
- const sp<MediaPlayerBase::AudioSink> &audioSink,
- uint32_t flags)
- : mInputBuffer(NULL),
- mSampleRate(0),
- mLatencyUs(0),
- mFrameSize(0),
- mNumFramesPlayed(0),
- mNumFramesPlayedSysTimeUs(ALooper::GetNowUs()),
- mPositionTimeMediaUs(-1),
- mPositionTimeRealUs(-1),
- mSeeking(false),
- mReachedEOS(false),
- mFinalStatus(OK),
- mSeekTimeUs(0),
- mStarted(false),
- mIsFirstBuffer(false),
- mFirstBufferResult(OK),
- mFirstBuffer(NULL),
- mAudioSink(audioSink),
- mPlaying(false),
- mStartPosUs(0),
- mCreateFlags(flags) {
-}
-
-AudioPlayer::~AudioPlayer() {
- if (mStarted) {
- reset();
- }
-}
-
-void AudioPlayer::setSource(const sp<MediaSource> &source) {
- CHECK(mSource == NULL);
- mSource = source;
-}
-
-ALookup<audio_format_t, int32_t> sAudioFormatToPcmEncoding {
- {
- { AUDIO_FORMAT_PCM_16_BIT, kAudioEncodingPcm16bit },
- { AUDIO_FORMAT_PCM_8_BIT, kAudioEncodingPcm8bit },
- { AUDIO_FORMAT_PCM_FLOAT, kAudioEncodingPcmFloat },
- }
-};
-
-status_t AudioPlayer::start(bool sourceAlreadyStarted) {
- CHECK(!mStarted);
- CHECK(mSource != NULL);
-
- status_t err;
- if (!sourceAlreadyStarted) {
- err = mSource->start();
-
- if (err != OK) {
- return err;
- }
- }
-
- // We allow an optional INFO_FORMAT_CHANGED at the very beginning
- // of playback, if there is one, getFormat below will retrieve the
- // updated format, if there isn't, we'll stash away the valid buffer
- // of data to be used on the first audio callback.
-
- CHECK(mFirstBuffer == NULL);
-
- MediaSource::ReadOptions options;
- if (mSeeking) {
- options.setSeekTo(mSeekTimeUs);
- mSeeking = false;
- }
-
- mFirstBufferResult = mSource->read(&mFirstBuffer, &options);
- if (mFirstBufferResult == INFO_FORMAT_CHANGED) {
- ALOGV("INFO_FORMAT_CHANGED!!!");
-
- CHECK(mFirstBuffer == NULL);
- mFirstBufferResult = OK;
- mIsFirstBuffer = false;
- } else {
- mIsFirstBuffer = true;
- }
-
- sp<MetaData> format = mSource->getFormat();
-
- if (format == NULL) {
- ALOGE("No metadata b/118620871");
- android_errorWriteLog(0x534e4554, "118620871");
- return BAD_VALUE;
- }
-
- const char *mime;
- bool success = format->findCString(kKeyMIMEType, &mime);
- CHECK(success);
- CHECK(useOffload() || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW));
-
- success = format->findInt32(kKeySampleRate, &mSampleRate);
- CHECK(success);
-
- int32_t numChannels, channelMask;
- success = format->findInt32(kKeyChannelCount, &numChannels);
- CHECK(success);
-
- if(!format->findInt32(kKeyChannelMask, &channelMask)) {
- // log only when there's a risk of ambiguity of channel mask selection
- ALOGI_IF(numChannels > 2,
- "source format didn't specify channel mask, using (%d) channel order", numChannels);
- channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER;
- }
-
- audio_format_t audioFormat = AUDIO_FORMAT_PCM_16_BIT;
- int32_t pcmEncoding;
- if (format->findInt32(kKeyPcmEncoding, &pcmEncoding)) {
- sAudioFormatToPcmEncoding.map(pcmEncoding, &audioFormat);
- }
-
- if (useOffload()) {
- if (mapMimeToAudioFormat(audioFormat, mime) != OK) {
- ALOGE("Couldn't map mime type \"%s\" to a valid AudioSystem::audio_format", mime);
- audioFormat = AUDIO_FORMAT_INVALID;
- } else {
- ALOGV("Mime type \"%s\" mapped to audio_format 0x%x", mime, audioFormat);
- }
-
- int32_t aacaot = -1;
- if ((audioFormat == AUDIO_FORMAT_AAC) && format->findInt32(kKeyAACAOT, &aacaot)) {
- // Redefine AAC format corrosponding to aac profile
- mapAACProfileToAudioFormat(audioFormat,(OMX_AUDIO_AACPROFILETYPE) aacaot);
- }
- }
-
- int avgBitRate = -1;
- format->findInt32(kKeyBitRate, &avgBitRate);
-
- if (mAudioSink.get() != NULL) {
-
- uint32_t flags = AUDIO_OUTPUT_FLAG_NONE;
- audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER;
-
- if (allowDeepBuffering()) {
- flags |= AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
- }
- if (useOffload()) {
- flags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
-
- int64_t durationUs;
- if (format->findInt64(kKeyDuration, &durationUs)) {
- offloadInfo.duration_us = durationUs;
- } else {
- offloadInfo.duration_us = -1;
- }
-
- offloadInfo.sample_rate = mSampleRate;
- offloadInfo.channel_mask = channelMask;
- offloadInfo.format = audioFormat;
- offloadInfo.stream_type = AUDIO_STREAM_MUSIC;
- offloadInfo.bit_rate = avgBitRate;
- offloadInfo.has_video = ((mCreateFlags & HAS_VIDEO) != 0);
- offloadInfo.is_streaming = ((mCreateFlags & IS_STREAMING) != 0);
- }
-
- status_t err = mAudioSink->open(
- mSampleRate, numChannels, channelMask, audioFormat,
- DEFAULT_AUDIOSINK_BUFFERCOUNT,
- &AudioPlayer::AudioSinkCallback,
- this,
- (audio_output_flags_t)flags,
- useOffload() ? &offloadInfo : NULL);
-
- if (err == OK) {
- mLatencyUs = (int64_t)mAudioSink->latency() * 1000;
- mFrameSize = mAudioSink->frameSize();
-
- if (useOffload()) {
- // If the playback is offloaded to h/w we pass the
- // HAL some metadata information
- // We don't want to do this for PCM because it will be going
- // through the AudioFlinger mixer before reaching the hardware
- sendMetaDataToHal(mAudioSink, format);
- }
-
- err = mAudioSink->start();
- // do not alter behavior for non offloaded tracks: ignore start status.
- if (!useOffload()) {
- err = OK;
- }
- }
-
- if (err != OK) {
- if (mFirstBuffer != NULL) {
- mFirstBuffer->release();
- mFirstBuffer = NULL;
- }
-
- if (!sourceAlreadyStarted) {
- mSource->stop();
- }
-
- return err;
- }
-
- } else {
- // playing to an AudioTrack, set up mask if necessary
- audio_channel_mask_t audioMask = channelMask == CHANNEL_MASK_USE_CHANNEL_ORDER ?
- audio_channel_out_mask_from_count(numChannels) : channelMask;
- if (0 == audioMask) {
- return BAD_VALUE;
- }
-
- mAudioTrack = new AudioTrack(
- AUDIO_STREAM_MUSIC, mSampleRate, AUDIO_FORMAT_PCM_16_BIT, audioMask,
- 0 /*frameCount*/, AUDIO_OUTPUT_FLAG_NONE, &AudioCallback, this,
- 0 /*notificationFrames*/);
-
- if ((err = mAudioTrack->initCheck()) != OK) {
- mAudioTrack.clear();
-
- if (mFirstBuffer != NULL) {
- mFirstBuffer->release();
- mFirstBuffer = NULL;
- }
-
- if (!sourceAlreadyStarted) {
- mSource->stop();
- }
-
- return err;
- }
-
- mLatencyUs = (int64_t)mAudioTrack->latency() * 1000;
- mFrameSize = mAudioTrack->frameSize();
-
- mAudioTrack->start();
- }
-
- mStarted = true;
- mPlaying = true;
-
- return OK;
-}
-
-void AudioPlayer::pause(bool playPendingSamples) {
- CHECK(mStarted);
-
- if (playPendingSamples) {
- if (mAudioSink.get() != NULL) {
- mAudioSink->stop();
- } else {
- mAudioTrack->stop();
- }
-
- mNumFramesPlayed = 0;
- mNumFramesPlayedSysTimeUs = ALooper::GetNowUs();
- } else {
- if (mAudioSink.get() != NULL) {
- mAudioSink->pause();
- } else {
- mAudioTrack->pause();
- }
- }
-
- mPlaying = false;
-}
-
-status_t AudioPlayer::resume() {
- CHECK(mStarted);
- status_t err;
-
- if (mAudioSink.get() != NULL) {
- err = mAudioSink->start();
- } else {
- err = mAudioTrack->start();
- }
-
- if (err == OK) {
- mPlaying = true;
- }
-
- return err;
-}
-
-void AudioPlayer::reset() {
- CHECK(mStarted);
-
- ALOGV("reset: mPlaying=%d mReachedEOS=%d useOffload=%d",
- mPlaying, mReachedEOS, useOffload() );
-
- if (mAudioSink.get() != NULL) {
- mAudioSink->stop();
- // If we're closing and have reached EOS, we don't want to flush
- // the track because if it is offloaded there could be a small
- // amount of residual data in the hardware buffer which we must
- // play to give gapless playback.
- // But if we're resetting when paused or before we've reached EOS
- // we can't be doing a gapless playback and there could be a large
- // amount of data queued in the hardware if the track is offloaded,
- // so we must flush to prevent a track switch being delayed playing
- // the buffered data that we don't want now
- if (!mPlaying || !mReachedEOS) {
- mAudioSink->flush();
- }
-
- mAudioSink->close();
- } else {
- mAudioTrack->stop();
-
- if (!mPlaying || !mReachedEOS) {
- mAudioTrack->flush();
- }
-
- mAudioTrack.clear();
- }
-
- // Make sure to release any buffer we hold onto so that the
- // source is able to stop().
-
- if (mFirstBuffer != NULL) {
- mFirstBuffer->release();
- mFirstBuffer = NULL;
- }
-
- if (mInputBuffer != NULL) {
- ALOGV("AudioPlayer releasing input buffer.");
-
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
-
- mSource->stop();
-
- // The following hack is necessary to ensure that the OMX
- // component is completely released by the time we may try
- // to instantiate it again.
- // When offloading, the OMX component is not used so this hack
- // is not needed
- if (!useOffload()) {
- wp<MediaSource> tmp = mSource;
- mSource.clear();
- while (tmp.promote() != NULL) {
- usleep(1000);
- }
- } else {
- mSource.clear();
- }
- IPCThreadState::self()->flushCommands();
-
- mNumFramesPlayed = 0;
- mNumFramesPlayedSysTimeUs = ALooper::GetNowUs();
- mPositionTimeMediaUs = -1;
- mPositionTimeRealUs = -1;
- mSeeking = false;
- mSeekTimeUs = 0;
- mReachedEOS = false;
- mFinalStatus = OK;
- mStarted = false;
- mPlaying = false;
- mStartPosUs = 0;
-}
-
-// static
-void AudioPlayer::AudioCallback(int event, void *user, void *info) {
- static_cast<AudioPlayer *>(user)->AudioCallback(event, info);
-}
-
-bool AudioPlayer::reachedEOS(status_t *finalStatus) {
- *finalStatus = OK;
-
- Mutex::Autolock autoLock(mLock);
- *finalStatus = mFinalStatus;
- return mReachedEOS;
-}
-
-status_t AudioPlayer::setPlaybackRate(const AudioPlaybackRate &rate) {
- if (mAudioSink.get() != NULL) {
- return mAudioSink->setPlaybackRate(rate);
- } else if (mAudioTrack != 0){
- return mAudioTrack->setPlaybackRate(rate);
- } else {
- return NO_INIT;
- }
-}
-
-status_t AudioPlayer::getPlaybackRate(AudioPlaybackRate *rate /* nonnull */) {
- if (mAudioSink.get() != NULL) {
- return mAudioSink->getPlaybackRate(rate);
- } else if (mAudioTrack != 0) {
- *rate = mAudioTrack->getPlaybackRate();
- return OK;
- } else {
- return NO_INIT;
- }
-}
-
-// static
-size_t AudioPlayer::AudioSinkCallback(
- MediaPlayerBase::AudioSink * /* audioSink */,
- void *buffer, size_t size, void *cookie,
- MediaPlayerBase::AudioSink::cb_event_t event) {
- AudioPlayer *me = (AudioPlayer *)cookie;
-
- switch(event) {
- case MediaPlayerBase::AudioSink::CB_EVENT_FILL_BUFFER:
- return me->fillBuffer(buffer, size);
-
- case MediaPlayerBase::AudioSink::CB_EVENT_STREAM_END:
- ALOGV("AudioSinkCallback: stream end");
- me->mReachedEOS = true;
- break;
-
- case MediaPlayerBase::AudioSink::CB_EVENT_TEAR_DOWN:
- ALOGV("AudioSinkCallback: Tear down event");
- break;
- }
-
- return 0;
-}
-
-void AudioPlayer::AudioCallback(int event, void *info) {
- switch (event) {
- case AudioTrack::EVENT_MORE_DATA:
- {
- AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
- size_t numBytesWritten = fillBuffer(buffer->raw, buffer->size);
- buffer->size = numBytesWritten;
- }
- break;
-
- case AudioTrack::EVENT_STREAM_END:
- mReachedEOS = true;
- break;
- }
-}
-
-size_t AudioPlayer::fillBuffer(void *data, size_t size) {
- if (mNumFramesPlayed == 0) {
- ALOGV("AudioCallback");
- }
-
- if (mReachedEOS) {
- return 0;
- }
-
- size_t size_done = 0;
- size_t size_remaining = size;
- while (size_remaining > 0) {
- MediaSource::ReadOptions options;
- bool refreshSeekTime = false;
-
- {
- Mutex::Autolock autoLock(mLock);
-
- if (mSeeking) {
- if (mIsFirstBuffer) {
- if (mFirstBuffer != NULL) {
- mFirstBuffer->release();
- mFirstBuffer = NULL;
- }
- mIsFirstBuffer = false;
- }
-
- options.setSeekTo(mSeekTimeUs);
- refreshSeekTime = true;
-
- if (mInputBuffer != NULL) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
-
- mSeeking = false;
- }
- }
-
- if (mInputBuffer == NULL) {
- status_t err;
-
- if (mIsFirstBuffer) {
- mInputBuffer = mFirstBuffer;
- mFirstBuffer = NULL;
- err = mFirstBufferResult;
-
- mIsFirstBuffer = false;
- } else {
- err = mSource->read(&mInputBuffer, &options);
- }
-
- CHECK((err == OK && mInputBuffer != NULL)
- || (err != OK && mInputBuffer == NULL));
-
- Mutex::Autolock autoLock(mLock);
-
- if (err != OK) {
- if (!mReachedEOS) {
- if (useOffload()) {
- // no more buffers to push - stop() and wait for STREAM_END
- // don't set mReachedEOS until stream end received
- if (mAudioSink != NULL) {
- mAudioSink->stop();
- } else {
- mAudioTrack->stop();
- }
- } else {
- mReachedEOS = true;
- }
- }
-
- mFinalStatus = err;
- break;
- }
-
- if (mAudioSink != NULL) {
- mLatencyUs = (int64_t)mAudioSink->latency() * 1000;
- } else {
- mLatencyUs = (int64_t)mAudioTrack->latency() * 1000;
- }
-
- if(mInputBuffer->range_length() != 0) {
- CHECK(mInputBuffer->meta_data().findInt64(
- kKeyTime, &mPositionTimeMediaUs));
- }
-
- // need to adjust the mStartPosUs for offload decoding since parser
- // might not be able to get the exact seek time requested.
- if (refreshSeekTime) {
- if (useOffload()) {
- mStartPosUs = mPositionTimeMediaUs;
- ALOGV("adjust seek time to: %.2f", mStartPosUs/ 1E6);
- }
- // clear seek time with mLock locked and once we have valid mPositionTimeMediaUs
- // and mPositionTimeRealUs
- // before clearing mSeekTimeUs check if a new seek request has been received while
- // we were reading from the source with mLock released.
- if (!mSeeking) {
- mSeekTimeUs = 0;
- }
- }
-
- if (!useOffload()) {
- mPositionTimeRealUs =
- ((mNumFramesPlayed + size_done / mFrameSize) * 1000000)
- / mSampleRate;
- ALOGV("buffer->size() = %zu, "
- "mPositionTimeMediaUs=%.2f mPositionTimeRealUs=%.2f",
- mInputBuffer->range_length(),
- mPositionTimeMediaUs / 1E6, mPositionTimeRealUs / 1E6);
- }
-
- }
-
- if (mInputBuffer->range_length() == 0) {
- mInputBuffer->release();
- mInputBuffer = NULL;
-
- continue;
- }
-
- size_t copy = size_remaining;
- if (copy > mInputBuffer->range_length()) {
- copy = mInputBuffer->range_length();
- }
-
- memcpy((char *)data + size_done,
- (const char *)mInputBuffer->data() + mInputBuffer->range_offset(),
- copy);
-
- mInputBuffer->set_range(mInputBuffer->range_offset() + copy,
- mInputBuffer->range_length() - copy);
-
- size_done += copy;
- size_remaining -= copy;
- }
-
- if (useOffload()) {
- // We must ask the hardware what it has played
- mPositionTimeRealUs = getOutputPlayPositionUs_l();
- ALOGV("mPositionTimeMediaUs=%.2f mPositionTimeRealUs=%.2f",
- mPositionTimeMediaUs / 1E6, mPositionTimeRealUs / 1E6);
- }
-
- {
- Mutex::Autolock autoLock(mLock);
- mNumFramesPlayed += size_done / mFrameSize;
- mNumFramesPlayedSysTimeUs = ALooper::GetNowUs();
- }
-
- return size_done;
-}
-
-int64_t AudioPlayer::getOutputPlayPositionUs_l()
-{
- uint32_t playedSamples = 0;
- uint32_t sampleRate;
- if (mAudioSink != NULL) {
- mAudioSink->getPosition(&playedSamples);
- sampleRate = mAudioSink->getSampleRate();
- } else {
- mAudioTrack->getPosition(&playedSamples);
- sampleRate = mAudioTrack->getSampleRate();
- }
- if (sampleRate != 0) {
- mSampleRate = sampleRate;
- }
-
- int64_t playedUs;
- if (mSampleRate != 0) {
- playedUs = (static_cast<int64_t>(playedSamples) * 1000000 ) / mSampleRate;
- } else {
- playedUs = 0;
- }
-
- // HAL position is relative to the first buffer we sent at mStartPosUs
- const int64_t renderedDuration = mStartPosUs + playedUs;
- ALOGV("getOutputPlayPositionUs_l %" PRId64, renderedDuration);
- return renderedDuration;
-}
-
-status_t AudioPlayer::seekTo(int64_t time_us) {
- Mutex::Autolock autoLock(mLock);
-
- ALOGV("seekTo( %" PRId64 " )", time_us);
-
- mSeeking = true;
- mPositionTimeRealUs = mPositionTimeMediaUs = -1;
- mReachedEOS = false;
- mSeekTimeUs = time_us;
- mStartPosUs = time_us;
-
- // Flush resets the number of played frames
- mNumFramesPlayed = 0;
- mNumFramesPlayedSysTimeUs = ALooper::GetNowUs();
-
- if (mAudioSink != NULL) {
- if (mPlaying) {
- mAudioSink->pause();
- }
- mAudioSink->flush();
- if (mPlaying) {
- mAudioSink->start();
- }
- } else {
- if (mPlaying) {
- mAudioTrack->pause();
- }
- mAudioTrack->flush();
- if (mPlaying) {
- mAudioTrack->start();
- }
- }
-
- return OK;
-}
-
-}
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index d78d729..00c5b40 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -50,7 +50,7 @@
}
AudioSource::AudioSource(
- audio_source_t inputSource, const String16 &opPackageName,
+ const audio_attributes_t *attr, const String16 &opPackageName,
uint32_t sampleRate, uint32_t channelCount, uint32_t outSampleRate,
uid_t uid, pid_t pid, audio_port_handle_t selectedDeviceId,
audio_microphone_direction_t selectedMicDirection,
@@ -92,7 +92,7 @@
}
mRecord = new AudioRecord(
- inputSource, sampleRate, AUDIO_FORMAT_PCM_16_BIT,
+ AUDIO_SOURCE_DEFAULT, sampleRate, AUDIO_FORMAT_PCM_16_BIT,
audio_channel_in_mask_from_count(channelCount),
opPackageName,
(size_t) (bufCount * frameCount),
@@ -104,7 +104,7 @@
AUDIO_INPUT_FLAG_NONE,
uid,
pid,
- NULL /*pAttributes*/,
+ attr,
selectedDeviceId,
selectedMicDirection,
selectedMicFieldDimension);
diff --git a/media/libstagefright/BufferImpl.cpp b/media/libstagefright/BufferImpl.cpp
index b760273..b097324 100644
--- a/media/libstagefright/BufferImpl.cpp
+++ b/media/libstagefright/BufferImpl.cpp
@@ -21,7 +21,7 @@
#include <binder/IMemory.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <utils/NativeHandle.h>
#include "include/SecureBuffer.h"
@@ -32,7 +32,11 @@
// SharedMemoryBuffer
SharedMemoryBuffer::SharedMemoryBuffer(const sp<AMessage> &format, const sp<IMemory> &mem)
- : MediaCodecBuffer(format, new ABuffer(mem->pointer(), mem->size())),
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
+ : MediaCodecBuffer(format, new ABuffer(mem->unsecurePointer(), mem->size())),
mMemory(mem) {
}
diff --git a/media/libstagefright/CallbackDataSource.cpp b/media/libstagefright/CallbackDataSource.cpp
index 92e6eb9..eb3cb45 100644
--- a/media/libstagefright/CallbackDataSource.cpp
+++ b/media/libstagefright/CallbackDataSource.cpp
@@ -20,9 +20,9 @@
#include "include/CallbackDataSource.h"
+#include <android/IDataSource.h>
#include <binder/IMemory.h>
#include <binder/IPCThreadState.h>
-#include <media/IDataSource.h>
#include <media/stagefright/foundation/ADebug.h>
#include <algorithm>
@@ -81,7 +81,8 @@
return ERROR_OUT_OF_RANGE;
}
CHECK(numRead >= 0 && (size_t)numRead <= bufferSize);
- memcpy(((uint8_t*)data) + totalNumRead, mMemory->pointer(), numRead);
+ memcpy(((uint8_t*)data) + totalNumRead, mMemory->unsecurePointer(),
+ numRead);
numLeft -= numRead;
totalNumRead += numRead;
}
@@ -113,10 +114,6 @@
}
}
-sp<DecryptHandle> CallbackDataSource::DrmInitialization(const char *mime) {
- return mIDataSource->DrmInitialization(mime);
-}
-
sp<IDataSource> CallbackDataSource::getIDataSource() const {
return mIDataSource;
}
@@ -190,14 +187,6 @@
return mSource->flags();
}
-sp<DecryptHandle> TinyCacheSource::DrmInitialization(const char *mime) {
- // flush cache when DrmInitialization occurs since decrypted
- // data may differ from what is in cache.
- mCachedOffset = 0;
- mCachedSize = 0;
- return mSource->DrmInitialization(mime);
-}
-
sp<IDataSource> TinyCacheSource::getIDataSource() const {
return mSource->getIDataSource();
}
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 41f5db0..9b3f420 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -89,7 +89,7 @@
void CameraSourceListener::postData(int32_t msgType, const sp<IMemory> &dataPtr,
camera_frame_metadata_t * /* metadata */) {
ALOGV("postData(%d, ptr:%p, size:%zu)",
- msgType, dataPtr->pointer(), dataPtr->size());
+ msgType, dataPtr->unsecurePointer(), dataPtr->size());
sp<CameraSource> source = mSource.promote();
if (source.get() != NULL) {
@@ -966,8 +966,12 @@
// Check if frame contains a VideoNativeHandleMetadata.
if (frame->size() == sizeof(VideoNativeHandleMetadata)) {
- VideoNativeHandleMetadata *metadata =
- (VideoNativeHandleMetadata*)(frame->pointer());
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
+ VideoNativeHandleMetadata *metadata =
+ (VideoNativeHandleMetadata*)(frame->unsecurePointer());
if (metadata->eType == kMetadataBufferTypeNativeHandleSource) {
handle = metadata->pHandle;
}
@@ -1047,7 +1051,7 @@
Mutex::Autolock autoLock(mLock);
for (List<sp<IMemory> >::iterator it = mFramesBeingEncoded.begin();
it != mFramesBeingEncoded.end(); ++it) {
- if ((*it)->pointer() == buffer->data()) {
+ if ((*it)->unsecurePointer() == buffer->data()) {
releaseOneRecordingFrame((*it));
mFramesBeingEncoded.erase(it);
++mNumFramesEncoded;
@@ -1102,7 +1106,11 @@
frameTime = *mFrameTimes.begin();
mFrameTimes.erase(mFrameTimes.begin());
mFramesBeingEncoded.push_back(frame);
- *buffer = new MediaBuffer(frame->pointer(), frame->size());
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
+ *buffer = new MediaBuffer(frame->unsecurePointer(), frame->size());
(*buffer)->setObserver(this);
(*buffer)->add_ref();
(*buffer)->meta_data().setInt64(kKeyTime, frameTime);
@@ -1248,7 +1256,7 @@
mMemoryBases.erase(mMemoryBases.begin());
// Wrap native handle in sp<IMemory> so it can be pushed to mFramesReceived.
- VideoNativeHandleMetadata *metadata = (VideoNativeHandleMetadata*)(data->pointer());
+ VideoNativeHandleMetadata *metadata = (VideoNativeHandleMetadata*)(data->unsecurePointer());
metadata->eType = kMetadataBufferTypeNativeHandleSource;
metadata->pHandle = handle;
@@ -1296,7 +1304,11 @@
mMemoryBases.erase(mMemoryBases.begin());
// Wrap native handle in sp<IMemory> so it can be pushed to mFramesReceived.
- VideoNativeHandleMetadata *metadata = (VideoNativeHandleMetadata*)(data->pointer());
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
+ VideoNativeHandleMetadata *metadata = (VideoNativeHandleMetadata*)(data->unsecurePointer());
metadata->eType = kMetadataBufferTypeNativeHandleSource;
metadata->pHandle = handle;
diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp
index 2a819ad..e0a6eb3 100644
--- a/media/libstagefright/CameraSourceTimeLapse.cpp
+++ b/media/libstagefright/CameraSourceTimeLapse.cpp
@@ -245,11 +245,11 @@
ALOGV("createIMemoryCopy");
size_t source_size = source_data->size();
- void* source_pointer = source_data->pointer();
+ void* source_pointer = source_data->unsecurePointer();
sp<MemoryHeapBase> newMemoryHeap = new MemoryHeapBase(source_size);
sp<MemoryBase> newMemory = new MemoryBase(newMemoryHeap, 0, source_size);
- memcpy(newMemory->pointer(), source_pointer, source_size);
+ memcpy(newMemory->unsecurePointer(), source_pointer, source_size);
return newMemory;
}
diff --git a/media/libstagefright/ClearFileSource.cpp b/media/libstagefright/ClearFileSource.cpp
deleted file mode 100644
index e3a2cb7..0000000
--- a/media/libstagefright/ClearFileSource.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "ClearFileSource"
-#include <utils/Log.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/ClearFileSource.h>
-#include <media/stagefright/Utils.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-namespace android {
-
-ClearFileSource::ClearFileSource(const char *filename)
- : mFd(-1),
- mOffset(0),
- mLength(-1),
- mName("<null>") {
-
- if (filename) {
- mName = String8::format("FileSource(%s)", filename);
- }
- ALOGV("%s", filename);
- mFd = open(filename, O_LARGEFILE | O_RDONLY);
-
- if (mFd >= 0) {
- mLength = lseek64(mFd, 0, SEEK_END);
- } else {
- ALOGE("Failed to open file '%s'. (%s)", filename, strerror(errno));
- }
-}
-
-ClearFileSource::ClearFileSource(int fd, int64_t offset, int64_t length)
- : mFd(fd),
- mOffset(offset),
- mLength(length),
- mName("<null>") {
- ALOGV("fd=%d (%s), offset=%lld, length=%lld",
- fd, nameForFd(fd).c_str(), (long long) offset, (long long) length);
-
- if (mOffset < 0) {
- mOffset = 0;
- }
- if (mLength < 0) {
- mLength = 0;
- }
- if (mLength > INT64_MAX - mOffset) {
- mLength = INT64_MAX - mOffset;
- }
- struct stat s;
- if (fstat(fd, &s) == 0) {
- if (mOffset > s.st_size) {
- mOffset = s.st_size;
- mLength = 0;
- }
- if (mOffset + mLength > s.st_size) {
- mLength = s.st_size - mOffset;
- }
- }
- if (mOffset != offset || mLength != length) {
- ALOGW("offset/length adjusted from %lld/%lld to %lld/%lld",
- (long long) offset, (long long) length,
- (long long) mOffset, (long long) mLength);
- }
-
- mName = String8::format(
- "FileSource(fd(%s), %lld, %lld)",
- nameForFd(fd).c_str(),
- (long long) mOffset,
- (long long) mLength);
-
-}
-
-ClearFileSource::~ClearFileSource() {
- if (mFd >= 0) {
- ::close(mFd);
- mFd = -1;
- }
-}
-
-status_t ClearFileSource::initCheck() const {
- return mFd >= 0 ? OK : NO_INIT;
-}
-
-ssize_t ClearFileSource::readAt(off64_t offset, void *data, size_t size) {
- if (mFd < 0) {
- return NO_INIT;
- }
-
- Mutex::Autolock autoLock(mLock);
- if (mLength >= 0) {
- if (offset >= mLength) {
- return 0; // read beyond EOF.
- }
- uint64_t numAvailable = mLength - offset;
- if ((uint64_t)size > numAvailable) {
- size = numAvailable;
- }
- }
- return readAt_l(offset, data, size);
-}
-
-ssize_t ClearFileSource::readAt_l(off64_t offset, void *data, size_t size) {
- off64_t result = lseek64(mFd, offset + mOffset, SEEK_SET);
- if (result == -1) {
- ALOGE("seek to %lld failed", (long long)(offset + mOffset));
- return UNKNOWN_ERROR;
- }
-
- return ::read(mFd, data, size);
-}
-
-status_t ClearFileSource::getSize(off64_t *size) {
- Mutex::Autolock autoLock(mLock);
-
- if (mFd < 0) {
- return NO_INIT;
- }
-
- *size = mLength;
-
- return OK;
-}
-
-} // namespace android
diff --git a/media/libstagefright/CodecBase.cpp b/media/libstagefright/CodecBase.cpp
index d0610b2..5b724aa 100644
--- a/media/libstagefright/CodecBase.cpp
+++ b/media/libstagefright/CodecBase.cpp
@@ -18,18 +18,26 @@
#define LOG_TAG "CodecBase"
#include <android/hardware/cas/native/1.0/IDescrambler.h>
-#include <media/ICrypto.h>
+#include <android/hardware/drm/1.0/types.h>
+#include <hidlmemory/FrameworkUtils.h>
+#include <mediadrm/ICrypto.h>
#include <media/stagefright/CodecBase.h>
#include <utils/Log.h>
namespace android {
-void BufferChannelBase::setCrypto(const sp<ICrypto> &crypto) {
- mCrypto = crypto;
-}
+void BufferChannelBase::IMemoryToSharedBuffer(
+ const sp<IMemory> &memory,
+ int32_t heapSeqNum,
+ hardware::drm::V1_0::SharedBuffer *buf) {
+ ssize_t offset;
+ size_t size;
-void BufferChannelBase::setDescrambler(const sp<IDescrambler> &descrambler) {
- mDescrambler = descrambler;
+ sp<hardware::HidlMemory> hidlMemory;
+ hidlMemory = hardware::fromHeap(memory->getMemory(&offset, &size));
+ buf->bufferId = static_cast<uint32_t>(heapSeqNum);
+ buf->offset = offset >= 0 ? offset : 0;
+ buf->size = size;
}
} // namespace android
diff --git a/media/libstagefright/DataSourceFactory.cpp b/media/libstagefright/DataSourceFactory.cpp
deleted file mode 100644
index 54bf0cc..0000000
--- a/media/libstagefright/DataSourceFactory.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-//#define LOG_NDEBUG 0
-#define LOG_TAG "DataSource"
-
-#include "include/HTTPBase.h"
-#include "include/NuCachedSource2.h"
-
-#include <media/MediaHTTPConnection.h>
-#include <media/MediaHTTPService.h>
-#include <media/stagefright/DataSourceFactory.h>
-#include <media/stagefright/DataURISource.h>
-#include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaHTTP.h>
-#include <utils/String8.h>
-
-namespace android {
-
-// static
-sp<DataSource> DataSourceFactory::CreateFromURI(
- const sp<MediaHTTPService> &httpService,
- const char *uri,
- const KeyedVector<String8, String8> *headers,
- String8 *contentType,
- HTTPBase *httpSource) {
- if (contentType != NULL) {
- *contentType = "";
- }
-
- sp<DataSource> source;
- if (!strncasecmp("file://", uri, 7)) {
- source = new FileSource(uri + 7);
- } else if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
- if (httpService == NULL) {
- ALOGE("Invalid http service!");
- return NULL;
- }
-
- if (httpSource == NULL) {
- sp<MediaHTTPConnection> conn = httpService->makeHTTPConnection();
- if (conn == NULL) {
- ALOGE("Failed to make http connection from http service!");
- return NULL;
- }
- httpSource = new MediaHTTP(conn);
- }
-
- String8 cacheConfig;
- bool disconnectAtHighwatermark = false;
- KeyedVector<String8, String8> nonCacheSpecificHeaders;
- if (headers != NULL) {
- nonCacheSpecificHeaders = *headers;
- NuCachedSource2::RemoveCacheSpecificHeaders(
- &nonCacheSpecificHeaders,
- &cacheConfig,
- &disconnectAtHighwatermark);
- }
-
- if (httpSource->connect(uri, &nonCacheSpecificHeaders) != OK) {
- ALOGE("Failed to connect http source!");
- return NULL;
- }
-
- if (contentType != NULL) {
- *contentType = httpSource->getMIMEType();
- }
-
- source = NuCachedSource2::Create(
- httpSource,
- cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
- disconnectAtHighwatermark);
- } else if (!strncasecmp("data:", uri, 5)) {
- source = DataURISource::Create(uri);
- } else {
- // Assume it's a filename.
- source = new FileSource(uri);
- }
-
- if (source == NULL || source->initCheck() != OK) {
- return NULL;
- }
-
- return source;
-}
-
-sp<DataSource> DataSourceFactory::CreateFromFd(int fd, int64_t offset, int64_t length) {
- sp<FileSource> source = new FileSource(fd, offset, length);
- return source->initCheck() != OK ? nullptr : source;
-}
-
-sp<DataSource> DataSourceFactory::CreateMediaHTTP(const sp<MediaHTTPService> &httpService) {
- if (httpService == NULL) {
- return NULL;
- }
-
- sp<MediaHTTPConnection> conn = httpService->makeHTTPConnection();
- if (conn == NULL) {
- return NULL;
- } else {
- return new MediaHTTP(conn);
- }
-}
-
-} // namespace android
diff --git a/media/libstagefright/DataURISource.cpp b/media/libstagefright/DataURISource.cpp
deleted file mode 100644
index b975b38..0000000
--- a/media/libstagefright/DataURISource.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <media/stagefright/DataURISource.h>
-
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/AString.h>
-#include <media/stagefright/foundation/base64.h>
-
-namespace android {
-
-// static
-sp<DataURISource> DataURISource::Create(const char *uri) {
- if (strncasecmp("data:", uri, 5)) {
- return NULL;
- }
-
- const char *commaPos = strrchr(uri, ',');
-
- if (commaPos == NULL) {
- return NULL;
- }
-
- sp<ABuffer> buffer;
-
- AString tmp(&uri[5], commaPos - &uri[5]);
-
- if (tmp.endsWith(";base64")) {
-
- // strip all CR and LF characters.
- const char *src = commaPos+1;
- int len = strlen(src) + 1;
- char *cleansed = (char *) malloc(len);
- if (cleansed == NULL) return NULL;
- char *keeping = cleansed;
- int left = len;
- for (int i = 0; i < len ; i++)
- {
- const char c = *src++;
- if (c == '\r' || c == '\n') {
- continue;
- }
- *keeping++ = c;
- left--;
- }
- memset(keeping, 0, left);
-
- AString encoded(cleansed);
- free(cleansed);
-
- buffer = decodeBase64(encoded);
-
- if (buffer == NULL) {
- ALOGE("Malformed base64 encoded content found.");
- return NULL;
- }
- } else {
-#if 0
- size_t dataLen = strlen(uri) - tmp.size() - 6;
- buffer = new ABuffer(dataLen);
- memcpy(buffer->data(), commaPos + 1, dataLen);
-
- // unescape
-#else
- // MediaPlayer doesn't care for this right now as we don't
- // play any text-based media.
- return NULL;
-#endif
- }
-
- // We don't really care about charset or mime type.
-
- return new DataURISource(buffer);
-}
-
-DataURISource::DataURISource(const sp<ABuffer> &buffer)
- : mBuffer(buffer) {
-}
-
-DataURISource::~DataURISource() {
-}
-
-status_t DataURISource::initCheck() const {
- return OK;
-}
-
-ssize_t DataURISource::readAt(off64_t offset, void *data, size_t size) {
- if ((offset < 0) || (offset >= (off64_t)mBuffer->size())) {
- return 0;
- }
-
- size_t copy = mBuffer->size() - offset;
- if (copy > size) {
- copy = size;
- }
-
- memcpy(data, mBuffer->data() + offset, copy);
-
- return copy;
-}
-
-status_t DataURISource::getSize(off64_t *size) {
- *size = mBuffer->size();
-
- return OK;
-}
-
-} // namespace android
-
diff --git a/media/libstagefright/FileSource.cpp b/media/libstagefright/FileSource.cpp
deleted file mode 100644
index aee7fd8..0000000
--- a/media/libstagefright/FileSource.cpp
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "FileSource"
-#include <utils/Log.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/FileSource.h>
-#include <media/stagefright/Utils.h>
-#include <private/android_filesystem_config.h>
-
-namespace android {
-
-FileSource::FileSource(const char *filename)
- : ClearFileSource(filename),
- mDecryptHandle(NULL),
- mDrmManagerClient(NULL),
- mDrmBufOffset(0),
- mDrmBufSize(0),
- mDrmBuf(NULL){
-}
-
-FileSource::FileSource(int fd, int64_t offset, int64_t length)
- : ClearFileSource(fd, offset, length),
- mDecryptHandle(NULL),
- mDrmManagerClient(NULL),
- mDrmBufOffset(0),
- mDrmBufSize(0),
- mDrmBuf(NULL) {
-}
-
-FileSource::~FileSource() {
- if (mDrmBuf != NULL) {
- delete[] mDrmBuf;
- mDrmBuf = NULL;
- }
-
- if (mDecryptHandle != NULL) {
- // To release mDecryptHandle
- CHECK(mDrmManagerClient);
- mDrmManagerClient->closeDecryptSession(mDecryptHandle);
- mDecryptHandle = NULL;
- }
-
- if (mDrmManagerClient != NULL) {
- delete mDrmManagerClient;
- mDrmManagerClient = NULL;
- }
-}
-
-ssize_t FileSource::readAt(off64_t offset, void *data, size_t size) {
- if (mFd < 0) {
- return NO_INIT;
- }
-
- Mutex::Autolock autoLock(mLock);
-
- if (mLength >= 0) {
- if (offset >= mLength) {
- return 0; // read beyond EOF.
- }
- uint64_t numAvailable = mLength - offset;
- if ((uint64_t)size > numAvailable) {
- size = numAvailable;
- }
- }
-
- if (mDecryptHandle != NULL && DecryptApiType::CONTAINER_BASED
- == mDecryptHandle->decryptApiType) {
- return readAtDRM_l(offset, data, size);
- } else {
- return readAt_l(offset, data, size);
- }
-}
-
-sp<DecryptHandle> FileSource::DrmInitialization(const char *mime) {
- if (getuid() == AID_MEDIA_EX) return nullptr; // no DRM in media extractor
- if (mDrmManagerClient == NULL) {
- mDrmManagerClient = new DrmManagerClient();
- }
-
- if (mDrmManagerClient == NULL) {
- return NULL;
- }
-
- if (mDecryptHandle == NULL) {
- mDecryptHandle = mDrmManagerClient->openDecryptSession(
- mFd, mOffset, mLength, mime);
- }
-
- if (mDecryptHandle == NULL) {
- delete mDrmManagerClient;
- mDrmManagerClient = NULL;
- }
-
- return mDecryptHandle;
-}
-
-ssize_t FileSource::readAtDRM_l(off64_t offset, void *data, size_t size) {
- size_t DRM_CACHE_SIZE = 1024;
- if (mDrmBuf == NULL) {
- mDrmBuf = new unsigned char[DRM_CACHE_SIZE];
- }
-
- if (mDrmBuf != NULL && mDrmBufSize > 0 && (offset + mOffset) >= mDrmBufOffset
- && (offset + mOffset + size) <= static_cast<size_t>(mDrmBufOffset + mDrmBufSize)) {
- /* Use buffered data */
- memcpy(data, (void*)(mDrmBuf+(offset+mOffset-mDrmBufOffset)), size);
- return size;
- } else if (size <= DRM_CACHE_SIZE) {
- /* Buffer new data */
- mDrmBufOffset = offset + mOffset;
- mDrmBufSize = mDrmManagerClient->pread(mDecryptHandle, mDrmBuf,
- DRM_CACHE_SIZE, offset + mOffset);
- if (mDrmBufSize > 0) {
- int64_t dataRead = 0;
- dataRead = size > static_cast<size_t>(mDrmBufSize) ? mDrmBufSize : size;
- memcpy(data, (void*)mDrmBuf, dataRead);
- return dataRead;
- } else {
- return mDrmBufSize;
- }
- } else {
- /* Too big chunk to cache. Call DRM directly */
- return mDrmManagerClient->pread(mDecryptHandle, data, size, offset + mOffset);
- }
-}
-
-/* static */
-bool FileSource::requiresDrm(int fd, int64_t offset, int64_t length, const char *mime) {
- std::unique_ptr<DrmManagerClient> drmClient(new DrmManagerClient());
- sp<DecryptHandle> decryptHandle =
- drmClient->openDecryptSession(fd, offset, length, mime);
- bool requiresDrm = false;
- if (decryptHandle != nullptr) {
- requiresDrm = decryptHandle->decryptApiType == DecryptApiType::CONTAINER_BASED;
- drmClient->closeDecryptSession(decryptHandle);
- }
- return requiresDrm;
-}
-
-} // namespace android
diff --git a/media/libstagefright/FrameCaptureLayer.cpp b/media/libstagefright/FrameCaptureLayer.cpp
new file mode 100644
index 0000000..d2cfd41
--- /dev/null
+++ b/media/libstagefright/FrameCaptureLayer.cpp
@@ -0,0 +1,258 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "FrameCaptureLayer"
+
+#include <include/FrameCaptureLayer.h>
+#include <media/stagefright/FrameCaptureProcessor.h>
+#include <gui/BufferQueue.h>
+#include <gui/GLConsumer.h>
+#include <gui/IGraphicBufferConsumer.h>
+#include <gui/Surface.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaErrors.h>
+#include <renderengine/RenderEngine.h>
+#include <utils/Log.h>
+
+namespace android {
+
+static const int64_t kAcquireBufferTimeoutNs = 100000000LL;
+static constexpr float kDefaultMaxMasteringLuminance = 1000.0;
+static constexpr float kDefaultMaxContentLuminance = 1000.0;
+
+ui::Dataspace translateDataspace(ui::Dataspace dataspace) {
+ ui::Dataspace updatedDataspace = dataspace;
+ // translate legacy dataspaces to modern dataspaces
+ switch (dataspace) {
+ case ui::Dataspace::SRGB:
+ updatedDataspace = ui::Dataspace::V0_SRGB;
+ break;
+ case ui::Dataspace::SRGB_LINEAR:
+ updatedDataspace = ui::Dataspace::V0_SRGB_LINEAR;
+ break;
+ case ui::Dataspace::JFIF:
+ updatedDataspace = ui::Dataspace::V0_JFIF;
+ break;
+ case ui::Dataspace::BT601_625:
+ updatedDataspace = ui::Dataspace::V0_BT601_625;
+ break;
+ case ui::Dataspace::BT601_525:
+ updatedDataspace = ui::Dataspace::V0_BT601_525;
+ break;
+ case ui::Dataspace::BT709:
+ updatedDataspace = ui::Dataspace::V0_BT709;
+ break;
+ default:
+ break;
+ }
+
+ return updatedDataspace;
+}
+
+bool isHdrY410(const BufferItem &bi) {
+ ui::Dataspace dataspace = translateDataspace(static_cast<ui::Dataspace>(bi.mDataSpace));
+ // pixel format is HDR Y410 masquerading as RGBA_1010102
+ return ((dataspace == ui::Dataspace::BT2020_ITU_PQ ||
+ dataspace == ui::Dataspace::BT2020_ITU_HLG) &&
+ bi.mGraphicBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102);
+}
+
+struct FrameCaptureLayer::BufferLayer : public FrameCaptureProcessor::Layer {
+ BufferLayer(const BufferItem &bi) : mBufferItem(bi) {}
+ void getLayerSettings(
+ const Rect &sourceCrop, uint32_t textureName,
+ renderengine::LayerSettings *layerSettings) override;
+ BufferItem mBufferItem;
+};
+
+void FrameCaptureLayer::BufferLayer::getLayerSettings(
+ const Rect &sourceCrop, uint32_t textureName,
+ renderengine::LayerSettings *layerSettings) {
+ layerSettings->geometry.boundaries = sourceCrop.toFloatRect();
+ layerSettings->alpha = 1.0f;
+
+ layerSettings->sourceDataspace = translateDataspace(
+ static_cast<ui::Dataspace>(mBufferItem.mDataSpace));
+
+ // from BufferLayer
+ layerSettings->source.buffer.buffer = mBufferItem.mGraphicBuffer;
+ layerSettings->source.buffer.isOpaque = true;
+ layerSettings->source.buffer.fence = mBufferItem.mFence;
+ layerSettings->source.buffer.textureName = textureName;
+ layerSettings->source.buffer.usePremultipliedAlpha = false;
+ layerSettings->source.buffer.isY410BT2020 = isHdrY410(mBufferItem);
+ bool hasSmpte2086 = mBufferItem.mHdrMetadata.validTypes & HdrMetadata::SMPTE2086;
+ bool hasCta861_3 = mBufferItem.mHdrMetadata.validTypes & HdrMetadata::CTA861_3;
+ layerSettings->source.buffer.maxMasteringLuminance = hasSmpte2086
+ ? mBufferItem.mHdrMetadata.smpte2086.maxLuminance
+ : kDefaultMaxMasteringLuminance;
+ layerSettings->source.buffer.maxContentLuminance = hasCta861_3
+ ? mBufferItem.mHdrMetadata.cta8613.maxContentLightLevel
+ : kDefaultMaxContentLuminance;
+
+ // Set filtering to false since the capture itself doesn't involve
+ // any scaling, metadata retriever JNI is scaling the bitmap if
+ // display size is different from decoded size. If that scaling
+ // needs to be handled by server side, consider enable this based
+ // display size vs decoded size.
+ const bool useFiltering = false;
+ layerSettings->source.buffer.useTextureFiltering = useFiltering;
+
+ float textureMatrix[16];
+ GLConsumer::computeTransformMatrix(
+ textureMatrix, mBufferItem.mGraphicBuffer,
+ mBufferItem.mCrop, mBufferItem.mTransform, useFiltering);
+
+ // Flip y-coordinates because GLConsumer expects OpenGL convention.
+ mat4 tr = mat4::translate(vec4(.5, .5, 0, 1)) * mat4::scale(vec4(1, -1, 1, 1)) *
+ mat4::translate(vec4(-.5, -.5, 0, 1));
+
+ layerSettings->source.buffer.textureTransform =
+ mat4(static_cast<const float*>(textureMatrix)) * tr;
+}
+
+status_t FrameCaptureLayer::init() {
+ if (FrameCaptureProcessor::getInstance() == nullptr) {
+ ALOGE("failed to get capture processor");
+ return ERROR_UNSUPPORTED;
+ }
+
+ // Mimic surfaceflinger's BufferQueueLayer::onFirstRef() to create a
+ // BufferQueue for encoder output
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ // We don't need HW_COMPOSER usage since we're not using hwc to compose.
+ // The buffer is only used as a GL texture.
+ consumer->setConsumerUsageBits(GraphicBuffer::USAGE_HW_TEXTURE);
+ consumer->setConsumerName(String8("FrameDecoder"));
+
+ status_t err = consumer->consumerConnect(
+ new BufferQueue::ProxyConsumerListener(this), false);
+ if (NO_ERROR != err) {
+ ALOGE("Error connecting to BufferQueue: %s (%d)", strerror(-err), err);
+ return err;
+ }
+
+ mConsumer = consumer;
+ mSurface = new Surface(producer);
+
+ return OK;
+}
+
+status_t FrameCaptureLayer::capture(const ui::PixelFormat reqPixelFormat,
+ const Rect &sourceCrop, sp<GraphicBuffer> *outBuffer) {
+ ALOGV("capture: reqPixelFormat %d, crop {%d, %d, %d, %d}", reqPixelFormat,
+ sourceCrop.left, sourceCrop.top, sourceCrop.right, sourceCrop.bottom);
+
+ BufferItem bi;
+ status_t err = acquireBuffer(&bi);
+ if (err != OK) {
+ return err;
+ }
+
+ // create out buffer
+ const uint32_t usage =
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
+ GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
+ sp<GraphicBuffer> buffer = new GraphicBuffer(
+ sourceCrop.getWidth(), sourceCrop.getHeight(),
+ static_cast<android_pixel_format>(reqPixelFormat),
+ 1, usage, std::string("thumbnail"));
+
+ err = FrameCaptureProcessor::getInstance()->capture(
+ new BufferLayer(bi), sourceCrop, buffer);
+ if (err == OK) {
+ *outBuffer = buffer;
+ }
+
+ (void)releaseBuffer(bi);
+ return err;
+}
+
+FrameCaptureLayer::FrameCaptureLayer() : mFrameAvailable(false) {}
+
+void FrameCaptureLayer::onFrameAvailable(const BufferItem& /*item*/) {
+ ALOGV("onFrameAvailable");
+ Mutex::Autolock _lock(mLock);
+
+ mFrameAvailable = true;
+ mCondition.signal();
+}
+
+void FrameCaptureLayer::onBuffersReleased() {
+ ALOGV("onBuffersReleased");
+ Mutex::Autolock _lock(mLock);
+
+ uint64_t mask = 0;
+ mConsumer->getReleasedBuffers(&mask);
+ for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+ if (mask & (1ULL << i)) {
+ mSlotToBufferMap[i] = nullptr;
+ }
+ }
+}
+
+void FrameCaptureLayer::onSidebandStreamChanged() {
+ ALOGV("onSidebandStreamChanged");
+}
+
+status_t FrameCaptureLayer::acquireBuffer(BufferItem *bi) {
+ ALOGV("acquireBuffer");
+ Mutex::Autolock _lock(mLock);
+
+ if (!mFrameAvailable) {
+ // The output buffer is already released to the codec at this point.
+ // Use a small timeout of 100ms in case the buffer hasn't arrived
+ // at the consumer end of the output surface yet.
+ if (mCondition.waitRelative(mLock, kAcquireBufferTimeoutNs) != OK) {
+ ALOGE("wait for buffer timed out");
+ return TIMED_OUT;
+ }
+ }
+ mFrameAvailable = false;
+
+ status_t err = mConsumer->acquireBuffer(bi, 0);
+ if (err != OK) {
+ ALOGE("failed to acquire buffer!");
+ return err;
+ }
+
+ if (bi->mGraphicBuffer != nullptr) {
+ mSlotToBufferMap[bi->mSlot] = bi->mGraphicBuffer;
+ } else {
+ bi->mGraphicBuffer = mSlotToBufferMap[bi->mSlot];
+ }
+
+ if (bi->mGraphicBuffer == nullptr) {
+ ALOGE("acquired null buffer!");
+ return BAD_VALUE;
+ }
+ return OK;
+}
+
+status_t FrameCaptureLayer::releaseBuffer(const BufferItem &bi) {
+ ALOGV("releaseBuffer");
+ Mutex::Autolock _lock(mLock);
+
+ return mConsumer->releaseBuffer(bi.mSlot, bi.mFrameNumber,
+ EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, bi.mFence);
+}
+
+} // namespace android
diff --git a/media/libstagefright/FrameCaptureProcessor.cpp b/media/libstagefright/FrameCaptureProcessor.cpp
new file mode 100644
index 0000000..96c1195
--- /dev/null
+++ b/media/libstagefright/FrameCaptureProcessor.cpp
@@ -0,0 +1,213 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "FrameCaptureProcessor"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/FrameCaptureProcessor.h>
+#include <media/stagefright/MediaErrors.h>
+#include <renderengine/RenderEngine.h>
+#include <ui/Fence.h>
+#include <ui/PixelFormat.h>
+#include <utils/Log.h>
+
+namespace android {
+
+//static
+Mutex FrameCaptureProcessor::sLock;
+//static
+sp<FrameCaptureProcessor> FrameCaptureProcessor::sInstance;
+
+//static
+sp<FrameCaptureProcessor> FrameCaptureProcessor::getInstance() {
+ Mutex::Autolock _l(sLock);
+ if (sInstance == nullptr) {
+ sInstance = new FrameCaptureProcessor();
+ sInstance->createRenderEngine();
+ }
+ // init only once, if failed nullptr will be returned afterwards.
+ return (sInstance->initCheck() == OK) ? sInstance : nullptr;
+}
+
+//static
+status_t FrameCaptureProcessor::PostAndAwaitResponse(
+ const sp<AMessage> &msg, sp<AMessage> *response) {
+ status_t err = msg->postAndAwaitResponse(response);
+
+ if (err != OK) {
+ return err;
+ }
+
+ if (!(*response)->findInt32("err", &err)) {
+ err = OK;
+ }
+
+ return err;
+}
+
+//static
+void FrameCaptureProcessor::PostReplyWithError(
+ const sp<AReplyToken> &replyID, status_t err) {
+ sp<AMessage> response = new AMessage;
+ if (err != OK) {
+ response->setInt32("err", err);
+ }
+ response->postReply(replyID);
+}
+
+FrameCaptureProcessor::FrameCaptureProcessor()
+ : mInitStatus(NO_INIT), mTextureName(0) {}
+
+FrameCaptureProcessor::~FrameCaptureProcessor() {
+ if (mLooper != nullptr) {
+ mLooper->unregisterHandler(id());
+ mLooper->stop();
+ }
+}
+
+void FrameCaptureProcessor::createRenderEngine() {
+ // this method should only be called once, immediately after ctor
+ CHECK(mInitStatus == NO_INIT);
+
+ mLooper = new ALooper();
+ mLooper->setName("capture_looper");
+ mLooper->start(); // default priority
+ mLooper->registerHandler(this);
+
+ sp<AMessage> response;
+ status_t err = PostAndAwaitResponse(new AMessage(kWhatCreate, this), &response);
+ if (err != OK) {
+ mInitStatus = ERROR_UNSUPPORTED;
+
+ mLooper->unregisterHandler(id());
+ mLooper->stop();
+ mLooper.clear();
+ return;
+ }
+
+ // only need one texture name
+ mRE->genTextures(1, &mTextureName);
+
+ mInitStatus = OK;
+}
+
+status_t FrameCaptureProcessor::capture(
+ const sp<Layer> &layer, const Rect &sourceCrop, const sp<GraphicBuffer> &buffer) {
+ sp<AMessage> msg = new AMessage(kWhatCapture, this);
+ msg->setObject("layer", layer);
+ msg->setRect("crop", sourceCrop.left, sourceCrop.top, sourceCrop.right, sourceCrop.bottom);
+ msg->setObject("buffer", buffer);
+ sp<AMessage> response;
+ return PostAndAwaitResponse(msg, &response);
+}
+
+status_t FrameCaptureProcessor::onCreate() {
+ mRE = renderengine::RenderEngine::create(
+ renderengine::RenderEngineCreationArgs::Builder()
+ .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
+ .setImageCacheSize(2 /*maxFrameBufferAcquiredBuffers*/)
+ .setUseColorManagerment(true)
+ .setEnableProtectedContext(false)
+ .setPrecacheToneMapperShaderOnly(true)
+ .setContextPriority(renderengine::RenderEngine::ContextPriority::LOW)
+ .build());
+
+ if (mRE == nullptr) {
+ return ERROR_UNSUPPORTED;
+ }
+ return OK;
+}
+
+status_t FrameCaptureProcessor::onCapture(const sp<Layer> &layer,
+ const Rect &sourceCrop, const sp<GraphicBuffer> &buffer) {
+ renderengine::DisplaySettings clientCompositionDisplay;
+ std::vector<const renderengine::LayerSettings*> clientCompositionLayers;
+
+ clientCompositionDisplay.physicalDisplay = sourceCrop;
+ clientCompositionDisplay.clip = sourceCrop;
+
+ clientCompositionDisplay.outputDataspace = ui::Dataspace::V0_SRGB;
+ clientCompositionDisplay.maxLuminance = sDefaultMaxLumiance;
+ clientCompositionDisplay.clearRegion = Region::INVALID_REGION;
+
+ // from Layer && BufferLayer
+ renderengine::LayerSettings layerSettings;
+
+ layer->getLayerSettings(sourceCrop, mTextureName, &layerSettings);
+
+ clientCompositionLayers.push_back(&layerSettings);
+
+ // Use an empty fence for the buffer fence, since we just created the buffer so
+ // there is no need for synchronization with the GPU.
+ base::unique_fd bufferFence;
+ base::unique_fd drawFence;
+ mRE->useProtectedContext(false);
+ status_t err = mRE->drawLayers(clientCompositionDisplay, clientCompositionLayers, buffer.get(),
+ /*useFramebufferCache=*/false, std::move(bufferFence), &drawFence);
+
+ sp<Fence> fence = new Fence(std::move(drawFence));
+
+ if (err != OK) {
+ ALOGE("drawLayers returned err %d", err);
+ return err;
+ }
+
+ err = fence->wait(500);
+ if (err != OK) {
+ ALOGW("wait for fence returned err %d", err);
+ }
+ return OK;
+}
+
+void FrameCaptureProcessor::onMessageReceived(const sp<AMessage> &msg) {
+ switch (msg->what()) {
+ case kWhatCreate:
+ {
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
+ status_t err = onCreate();
+
+ PostReplyWithError(replyID, err);
+ break;
+ }
+ case kWhatCapture:
+ {
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
+ sp<RefBase> layerObj, bufferObj;
+ int32_t left, top, right, bottom;
+ CHECK(msg->findObject("layer", &layerObj));
+ CHECK(msg->findRect("crop", &left, &top, &right, &bottom));
+ CHECK(msg->findObject("buffer", &bufferObj));
+
+ sp<GraphicBuffer> buffer = static_cast<GraphicBuffer*>(bufferObj.get());
+ sp<Layer> layer = static_cast<Layer*>(layerObj.get());
+
+ PostReplyWithError(replyID,
+ onCapture(layer, Rect(left, top, right, bottom), buffer));
+
+ break;
+ }
+ default:
+ TRESPASS();
+ }
+}
+
+} // namespace android
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index 18a6bd8..734f5bb 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -18,17 +18,20 @@
#define LOG_TAG "FrameDecoder"
#include "include/FrameDecoder.h"
+#include "include/FrameCaptureLayer.h"
#include <binder/MemoryBase.h>
#include <binder/MemoryHeapBase.h>
#include <gui/Surface.h>
#include <inttypes.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/IMediaSource.h>
#include <media/MediaCodecBuffer.h>
#include <media/stagefright/foundation/avc_utils.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ColorUtils.h>
#include <media/stagefright/ColorConverter.h>
+#include <media/stagefright/FrameCaptureProcessor.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaCodec.h>
#include <media/stagefright/MediaDefs.h>
@@ -41,10 +44,11 @@
static const int64_t kBufferTimeOutUs = 10000LL; // 10 msec
static const size_t kRetryCount = 50; // must be >0
+static const int64_t kDefaultSampleDurationUs = 33333LL; // 33ms
sp<IMemory> allocVideoFrame(const sp<MetaData>& trackMeta,
int32_t width, int32_t height, int32_t tileWidth, int32_t tileHeight,
- int32_t dstBpp, bool metaOnly = false) {
+ int32_t dstBpp, bool allocRotated, bool metaOnly) {
int32_t rotationAngle;
if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
rotationAngle = 0; // By default, no rotation
@@ -74,6 +78,14 @@
displayHeight = height;
}
+ if (allocRotated && (rotationAngle == 90 || rotationAngle == 270)) {
+ int32_t tmp;
+ tmp = width; width = height; height = tmp;
+ tmp = displayWidth; displayWidth = displayHeight; displayHeight = tmp;
+ tmp = tileWidth; tileWidth = tileHeight; tileHeight = tmp;
+ rotationAngle = 0;
+ }
+
VideoFrame frame(width, height, displayWidth, displayHeight,
tileWidth, tileHeight, rotationAngle, dstBpp, !metaOnly, iccSize);
@@ -88,12 +100,26 @@
ALOGE("not enough memory for VideoFrame size=%zu", size);
return NULL;
}
- VideoFrame* frameCopy = static_cast<VideoFrame*>(frameMem->pointer());
+ VideoFrame* frameCopy = static_cast<VideoFrame*>(frameMem->unsecurePointer());
frameCopy->init(frame, iccData, iccSize);
return frameMem;
}
+sp<IMemory> allocVideoFrame(const sp<MetaData>& trackMeta,
+ int32_t width, int32_t height, int32_t tileWidth, int32_t tileHeight,
+ int32_t dstBpp, bool allocRotated = false) {
+ return allocVideoFrame(trackMeta, width, height, tileWidth, tileHeight, dstBpp,
+ allocRotated, false /*metaOnly*/);
+}
+
+sp<IMemory> allocMetaFrame(const sp<MetaData>& trackMeta,
+ int32_t width, int32_t height, int32_t tileWidth, int32_t tileHeight,
+ int32_t dstBpp) {
+ return allocVideoFrame(trackMeta, width, height, tileWidth, tileHeight, dstBpp,
+ false /*allocRotated*/, true /*metaOnly*/);
+}
+
bool findThumbnailInfo(
const sp<MetaData> &trackMeta, int32_t *width, int32_t *height,
uint32_t *type = NULL, const void **data = NULL, size_t *size = NULL) {
@@ -117,23 +143,27 @@
bool getDstColorFormat(
android_pixel_format_t colorFormat,
OMX_COLOR_FORMATTYPE *dstFormat,
+ ui::PixelFormat *captureFormat,
int32_t *dstBpp) {
switch (colorFormat) {
case HAL_PIXEL_FORMAT_RGB_565:
{
*dstFormat = OMX_COLOR_Format16bitRGB565;
+ *captureFormat = ui::PixelFormat::RGB_565;
*dstBpp = 2;
return true;
}
case HAL_PIXEL_FORMAT_RGBA_8888:
{
*dstFormat = OMX_COLOR_Format32BitRGBA8888;
+ *captureFormat = ui::PixelFormat::RGBA_8888;
*dstBpp = 4;
return true;
}
case HAL_PIXEL_FORMAT_BGRA_8888:
{
*dstFormat = OMX_COLOR_Format32bitBGRA8888;
+ *captureFormat = ui::PixelFormat::BGRA_8888;
*dstBpp = 4;
return true;
}
@@ -150,9 +180,10 @@
sp<IMemory> FrameDecoder::getMetadataOnly(
const sp<MetaData> &trackMeta, int colorFormat, bool thumbnail) {
OMX_COLOR_FORMATTYPE dstFormat;
+ ui::PixelFormat captureFormat;
int32_t dstBpp;
- if (!getDstColorFormat(
- (android_pixel_format_t)colorFormat, &dstFormat, &dstBpp)) {
+ if (!getDstColorFormat((android_pixel_format_t)colorFormat,
+ &dstFormat, &captureFormat, &dstBpp)) {
return NULL;
}
@@ -170,8 +201,19 @@
tileWidth = tileHeight = 0;
}
}
- return allocVideoFrame(trackMeta,
- width, height, tileWidth, tileHeight, dstBpp, true /*metaOnly*/);
+
+ sp<IMemory> metaMem = allocMetaFrame(trackMeta, width, height, tileWidth, tileHeight, dstBpp);
+
+ // try to fill sequence meta's duration based on average frame rate,
+ // default to 33ms if frame rate is unavailable.
+ int32_t frameRate;
+ VideoFrame* meta = static_cast<VideoFrame*>(metaMem->unsecurePointer());
+ if (trackMeta->findInt32(kKeyFrameRate, &frameRate) && frameRate > 0) {
+ meta->mDurationUs = 1000000LL / frameRate;
+ } else {
+ meta->mDurationUs = kDefaultSampleDurationUs;
+ }
+ return metaMem;
}
FrameDecoder::FrameDecoder(
@@ -194,15 +236,31 @@
}
}
+bool isHDR(const sp<AMessage> &format) {
+ uint32_t standard, range, transfer;
+ if (!format->findInt32("color-standard", (int32_t*)&standard)) {
+ standard = 0;
+ }
+ if (!format->findInt32("color-range", (int32_t*)&range)) {
+ range = 0;
+ }
+ if (!format->findInt32("color-transfer", (int32_t*)&transfer)) {
+ transfer = 0;
+ }
+ return standard == ColorUtils::kColorStandardBT2020 &&
+ (transfer == ColorUtils::kColorTransferST2084 ||
+ transfer == ColorUtils::kColorTransferHLG);
+}
+
status_t FrameDecoder::init(
- int64_t frameTimeUs, size_t numFrames, int option, int colorFormat) {
- if (!getDstColorFormat(
- (android_pixel_format_t)colorFormat, &mDstFormat, &mDstBpp)) {
+ int64_t frameTimeUs, int option, int colorFormat) {
+ if (!getDstColorFormat((android_pixel_format_t)colorFormat,
+ &mDstFormat, &mCaptureFormat, &mDstBpp)) {
return ERROR_UNSUPPORTED;
}
sp<AMessage> videoFormat = onGetFormatAndSeekOptions(
- frameTimeUs, numFrames, option, &mReadOptions);
+ frameTimeUs, option, &mReadOptions, &mSurface);
if (videoFormat == NULL) {
ALOGE("video format or seek mode not supported");
return ERROR_UNSUPPORTED;
@@ -219,7 +277,7 @@
}
err = decoder->configure(
- videoFormat, NULL /* surface */, NULL /* crypto */, 0 /* flags */);
+ videoFormat, mSurface, NULL /* crypto */, 0 /* flags */);
if (err != OK) {
ALOGW("configure returned error %d (%s)", err, asString(err));
decoder->release();
@@ -253,19 +311,7 @@
return NULL;
}
- return mFrames.size() > 0 ? mFrames[0] : NULL;
-}
-
-status_t FrameDecoder::extractFrames(std::vector<sp<IMemory> >* frames) {
- status_t err = extractInternal();
- if (err != OK) {
- return err;
- }
-
- for (size_t i = 0; i < mFrames.size(); i++) {
- frames->push_back(mFrames[i]);
- }
- return OK;
+ return mFrameMemory;
}
status_t FrameDecoder::extractInternal() {
@@ -379,8 +425,13 @@
ALOGE("failed to get output buffer %zu", index);
break;
}
- err = onOutputReceived(videoFrameBuffer, mOutputFormat, ptsUs, &done);
- mDecoder->releaseOutputBuffer(index);
+ if (mSurface != nullptr) {
+ mDecoder->renderOutputBufferAndRelease(index);
+ err = onOutputReceived(videoFrameBuffer, mOutputFormat, ptsUs, &done);
+ } else {
+ err = onOutputReceived(videoFrameBuffer, mOutputFormat, ptsUs, &done);
+ mDecoder->releaseOutputBuffer(index);
+ }
} else {
ALOGW("Received error %d (%s) instead of output", err, asString(err));
done = true;
@@ -404,22 +455,23 @@
const sp<MetaData> &trackMeta,
const sp<IMediaSource> &source)
: FrameDecoder(componentName, trackMeta, source),
+ mFrame(NULL),
mIsAvcOrHevc(false),
mSeekMode(MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC),
mTargetTimeUs(-1LL),
- mNumFrames(0),
- mNumFramesDecoded(0) {
+ mDefaultSampleDurationUs(0) {
}
sp<AMessage> VideoFrameDecoder::onGetFormatAndSeekOptions(
- int64_t frameTimeUs, size_t numFrames, int seekMode, MediaSource::ReadOptions *options) {
+ int64_t frameTimeUs, int seekMode,
+ MediaSource::ReadOptions *options,
+ sp<Surface> *window) {
mSeekMode = static_cast<MediaSource::ReadOptions::SeekMode>(seekMode);
if (mSeekMode < MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC ||
mSeekMode > MediaSource::ReadOptions::SEEK_FRAME_INDEX) {
ALOGE("Unknown seek mode: %d", mSeekMode);
return NULL;
}
- mNumFrames = numFrames;
const char *mime;
if (!trackMeta()->findCString(kKeyMIMEType, &mime)) {
@@ -460,6 +512,23 @@
videoFormat->setInt32("android._num-input-buffers", 1);
videoFormat->setInt32("android._num-output-buffers", 1);
}
+
+ if (isHDR(videoFormat)) {
+ *window = initSurface();
+ if (*window == NULL) {
+ ALOGE("Failed to init surface control for HDR, fallback to non-hdr");
+ } else {
+ videoFormat->setInt32("color-format", OMX_COLOR_FormatAndroidOpaque);
+ }
+ }
+
+ int32_t frameRate;
+ if (trackMeta()->findInt32(kKeyFrameRate, &frameRate) && frameRate > 0) {
+ mDefaultSampleDurationUs = 1000000LL / frameRate;
+ } else {
+ mDefaultSampleDurationUs = kDefaultSampleDurationUs;
+ }
+
return videoFormat;
}
@@ -480,6 +549,12 @@
// option, in which case we need to actually decode to targetTimeUs.
*flags |= MediaCodec::BUFFER_FLAG_EOS;
}
+ int64_t durationUs;
+ if (sampleMeta.findInt64(kKeyDuration, &durationUs)) {
+ mSampleDurations.push_back(durationUs);
+ } else {
+ mSampleDurations.push_back(mDefaultSampleDurationUs);
+ }
return OK;
}
@@ -487,6 +562,11 @@
const sp<MediaCodecBuffer> &videoFrameBuffer,
const sp<AMessage> &outputFormat,
int64_t timeUs, bool *done) {
+ int64_t durationUs = mDefaultSampleDurationUs;
+ if (!mSampleDurations.empty()) {
+ durationUs = *mSampleDurations.begin();
+ mSampleDurations.erase(mSampleDurations.begin());
+ }
bool shouldOutput = (mTargetTimeUs < 0LL) || (timeUs >= mTargetTimeUs);
// If this is not the target frame, skip color convert.
@@ -495,7 +575,7 @@
return OK;
}
- *done = (++mNumFramesDecoded >= mNumFrames);
+ *done = true;
if (outputFormat == NULL) {
return ERROR_MALFORMED;
@@ -504,13 +584,22 @@
int32_t width, height, stride, srcFormat;
if (!outputFormat->findInt32("width", &width) ||
!outputFormat->findInt32("height", &height) ||
- !outputFormat->findInt32("stride", &stride) ||
!outputFormat->findInt32("color-format", &srcFormat)) {
ALOGE("format missing dimension or color: %s",
outputFormat->debugString().c_str());
return ERROR_MALFORMED;
}
+ if (!outputFormat->findInt32("stride", &stride)) {
+ if (mCaptureLayer == NULL) {
+ ALOGE("format must have stride for byte buffer mode: %s",
+ outputFormat->debugString().c_str());
+ return ERROR_MALFORMED;
+ }
+ // for surface output, set stride to width, we don't actually need it.
+ stride = width;
+ }
+
int32_t crop_left, crop_top, crop_right, crop_bottom;
if (!outputFormat->findRect("crop", &crop_left, &crop_top, &crop_right, &crop_bottom)) {
crop_left = crop_top = 0;
@@ -518,15 +607,25 @@
crop_bottom = height - 1;
}
- sp<IMemory> frameMem = allocVideoFrame(
- trackMeta(),
- (crop_right - crop_left + 1),
- (crop_bottom - crop_top + 1),
- 0,
- 0,
- dstBpp());
- addFrame(frameMem);
- VideoFrame* frame = static_cast<VideoFrame*>(frameMem->pointer());
+ if (mFrame == NULL) {
+ sp<IMemory> frameMem = allocVideoFrame(
+ trackMeta(),
+ (crop_right - crop_left + 1),
+ (crop_bottom - crop_top + 1),
+ 0,
+ 0,
+ dstBpp(),
+ mCaptureLayer != nullptr /*allocRotated*/);
+ mFrame = static_cast<VideoFrame*>(frameMem->unsecurePointer());
+
+ setFrame(frameMem);
+ }
+
+ mFrame->mDurationUs = durationUs;
+
+ if (mCaptureLayer != nullptr) {
+ return captureSurface();
+ }
ColorConverter converter((OMX_COLOR_FORMATTYPE)srcFormat, dstFormat());
@@ -547,9 +646,11 @@
(const uint8_t *)videoFrameBuffer->data(),
width, height, stride,
crop_left, crop_top, crop_right, crop_bottom,
- frame->getFlattenedData(),
- frame->mWidth, frame->mHeight, frame->mRowBytes,
- crop_left, crop_top, crop_right, crop_bottom);
+ mFrame->getFlattenedData(),
+ mFrame->mWidth, mFrame->mHeight, mFrame->mRowBytes,
+ // since the frame is allocated with top-left adjusted,
+ // the dst rect should start at {0,0} as well.
+ 0, 0, mFrame->mWidth - 1, mFrame->mHeight - 1);
return OK;
}
@@ -558,6 +659,57 @@
return ERROR_UNSUPPORTED;
}
+sp<Surface> VideoFrameDecoder::initSurface() {
+ // create the consumer listener interface, and hold sp so that this
+ // interface lives as long as the GraphicBufferSource.
+ sp<FrameCaptureLayer> captureLayer = new FrameCaptureLayer();
+ if (captureLayer->init() != OK) {
+ ALOGE("failed to init capture layer");
+ return nullptr;
+ }
+ mCaptureLayer = captureLayer;
+
+ return captureLayer->getSurface();
+}
+
+status_t VideoFrameDecoder::captureSurface() {
+ sp<GraphicBuffer> outBuffer;
+ status_t err = mCaptureLayer->capture(
+ captureFormat(), Rect(0, 0, mFrame->mWidth, mFrame->mHeight), &outBuffer);
+
+ if (err != OK) {
+ ALOGE("failed to capture layer (err %d)", err);
+ return err;
+ }
+
+ ALOGV("capture: %dx%d, format %d, stride %d",
+ outBuffer->getWidth(),
+ outBuffer->getHeight(),
+ outBuffer->getPixelFormat(),
+ outBuffer->getStride());
+
+ uint8_t *base;
+ int32_t outBytesPerPixel, outBytesPerStride;
+ err = outBuffer->lock(
+ GraphicBuffer::USAGE_SW_READ_OFTEN,
+ reinterpret_cast<void**>(&base),
+ &outBytesPerPixel,
+ &outBytesPerStride);
+ if (err != OK) {
+ ALOGE("failed to lock graphic buffer: err %d", err);
+ return err;
+ }
+
+ uint8_t *dst = mFrame->getFlattenedData();
+ for (size_t y = 0 ; y < fmin(mFrame->mHeight, outBuffer->getHeight()) ; y++) {
+ memcpy(dst, base, fmin(mFrame->mWidth, outBuffer->getWidth()) * mFrame->mBytesPerPixel);
+ dst += mFrame->mRowBytes;
+ base += outBuffer->getStride() * mFrame->mBytesPerPixel;
+ }
+ outBuffer->unlock();
+ return OK;
+}
+
////////////////////////////////////////////////////////////////////////
ImageDecoder::ImageDecoder(
@@ -577,8 +729,8 @@
}
sp<AMessage> ImageDecoder::onGetFormatAndSeekOptions(
- int64_t frameTimeUs, size_t /*numFrames*/,
- int /*seekMode*/, MediaSource::ReadOptions *options) {
+ int64_t frameTimeUs, int /*seekMode*/,
+ MediaSource::ReadOptions *options, sp<Surface> * /*window*/) {
sp<MetaData> overrideMeta;
if (frameTimeUs < 0) {
uint32_t type;
@@ -703,9 +855,9 @@
if (mFrame == NULL) {
sp<IMemory> frameMem = allocVideoFrame(
trackMeta(), mWidth, mHeight, mTileWidth, mTileHeight, dstBpp());
- mFrame = static_cast<VideoFrame*>(frameMem->pointer());
+ mFrame = static_cast<VideoFrame*>(frameMem->unsecurePointer());
- addFrame(frameMem);
+ setFrame(frameMem);
}
int32_t srcFormat;
@@ -725,12 +877,6 @@
}
converter.setSrcColorSpace(standard, range, transfer);
- int32_t dstLeft, dstTop, dstRight, dstBottom;
- dstLeft = mTilesDecoded % mGridCols * width;
- dstTop = mTilesDecoded / mGridCols * height;
- dstRight = dstLeft + width - 1;
- dstBottom = dstTop + height - 1;
-
int32_t crop_left, crop_top, crop_right, crop_bottom;
if (!outputFormat->findRect("crop", &crop_left, &crop_top, &crop_right, &crop_bottom)) {
crop_left = crop_top = 0;
@@ -738,15 +884,25 @@
crop_bottom = height - 1;
}
+ int32_t crop_width, crop_height;
+ crop_width = crop_right - crop_left + 1;
+ crop_height = crop_bottom - crop_top + 1;
+
+ int32_t dstLeft, dstTop, dstRight, dstBottom;
+ dstLeft = mTilesDecoded % mGridCols * crop_width;
+ dstTop = mTilesDecoded / mGridCols * crop_height;
+ dstRight = dstLeft + crop_width - 1;
+ dstBottom = dstTop + crop_height - 1;
+
// apply crop on bottom-right
// TODO: need to move this into the color converter itself.
if (dstRight >= mWidth) {
- crop_right = mWidth - dstLeft - 1;
- dstRight = dstLeft + crop_right;
+ crop_right = crop_left + mWidth - dstLeft - 1;
+ dstRight = mWidth - 1;
}
if (dstBottom >= mHeight) {
- crop_bottom = mHeight - dstTop - 1;
- dstBottom = dstTop + crop_bottom;
+ crop_bottom = crop_top + mHeight - dstTop - 1;
+ dstBottom = mHeight - 1;
}
*done = (++mTilesDecoded >= mTargetTiles);
diff --git a/media/libstagefright/HTTPBase.cpp b/media/libstagefright/HTTPBase.cpp
deleted file mode 100644
index d118e8c..0000000
--- a/media/libstagefright/HTTPBase.cpp
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "HTTPBase"
-#include <utils/Log.h>
-
-#include "include/HTTPBase.h"
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/ALooper.h>
-
-#include <cutils/properties.h>
-#include <cutils/qtaguid.h>
-
-namespace android {
-
-HTTPBase::HTTPBase()
- : mNumBandwidthHistoryItems(0),
- mTotalTransferTimeUs(0),
- mTotalTransferBytes(0),
- mMaxBandwidthHistoryItems(100),
- mPrevBandwidthMeasureTimeUs(0),
- mPrevEstimatedBandWidthKbps(0),
- mBandWidthCollectFreqMs(5000) {
- mName = String8("HTTPBase(<disconnected>)");
-}
-
-void HTTPBase::addBandwidthMeasurement(
- size_t numBytes, int64_t delayUs) {
- Mutex::Autolock autoLock(mLock);
-
- BandwidthEntry entry;
- entry.mDelayUs = delayUs;
- entry.mNumBytes = numBytes;
- mTotalTransferTimeUs += delayUs;
- mTotalTransferBytes += numBytes;
-
- mBandwidthHistory.push_back(entry);
- if (++mNumBandwidthHistoryItems > mMaxBandwidthHistoryItems) {
- BandwidthEntry *entry = &*mBandwidthHistory.begin();
- mTotalTransferTimeUs -= entry->mDelayUs;
- mTotalTransferBytes -= entry->mNumBytes;
- mBandwidthHistory.erase(mBandwidthHistory.begin());
- --mNumBandwidthHistoryItems;
-
- int64_t timeNowUs = ALooper::GetNowUs();
- if (timeNowUs - mPrevBandwidthMeasureTimeUs >=
- mBandWidthCollectFreqMs * 1000LL) {
-
- if (mPrevBandwidthMeasureTimeUs != 0) {
- mPrevEstimatedBandWidthKbps =
- (mTotalTransferBytes * 8E3 / mTotalTransferTimeUs);
- }
- mPrevBandwidthMeasureTimeUs = timeNowUs;
- }
- }
-
-}
-
-bool HTTPBase::estimateBandwidth(int32_t *bandwidth_bps) {
- Mutex::Autolock autoLock(mLock);
-
- // Do not do bandwidth estimation if we don't have enough samples, or
- // total bytes download are too small (<64K).
- // Bandwidth estimation from these samples can often shoot up and cause
- // unwanted bw adaption behaviors.
- if (mNumBandwidthHistoryItems < 2 || mTotalTransferBytes < 65536) {
- return false;
- }
-
- *bandwidth_bps = ((double)mTotalTransferBytes * 8E6 / mTotalTransferTimeUs);
-
- return true;
-}
-
-status_t HTTPBase::getEstimatedBandwidthKbps(int32_t *kbps) {
- Mutex::Autolock autoLock(mLock);
- *kbps = mPrevEstimatedBandWidthKbps;
- return OK;
-}
-
-status_t HTTPBase::setBandwidthStatCollectFreq(int32_t freqMs) {
- Mutex::Autolock autoLock(mLock);
-
- if (freqMs < kMinBandwidthCollectFreqMs
- || freqMs > kMaxBandwidthCollectFreqMs) {
-
- ALOGE("frequency (%d ms) is out of range [1000, 60000]", freqMs);
- return BAD_VALUE;
- }
-
- ALOGI("frequency set to %d ms", freqMs);
- mBandWidthCollectFreqMs = freqMs;
- return OK;
-}
-
-void HTTPBase::setBandwidthHistorySize(size_t numHistoryItems) {
- mMaxBandwidthHistoryItems = numHistoryItems;
-}
-
-} // namespace android
diff --git a/media/libstagefright/MPEG2TSWriter.cpp b/media/libstagefright/MPEG2TSWriter.cpp
index a9715c9..34b840e 100644
--- a/media/libstagefright/MPEG2TSWriter.cpp
+++ b/media/libstagefright/MPEG2TSWriter.cpp
@@ -17,7 +17,7 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "MPEG2TSWriter"
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/foundation/ABuffer.h>
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index f130c9b..af8096d 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -31,8 +31,9 @@
#include <utils/Log.h>
#include <functional>
+#include <fcntl.h>
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AUtils.h>
@@ -64,9 +65,6 @@
namespace android {
static const int64_t kMinStreamableFileSizeInBytes = 5 * 1024 * 1024;
-static const int64_t kMax32BitFileSize = 0x00ffffffffLL; // 2^32-1 : max FAT32
- // filesystem file size
- // used by most SD cards
static const uint8_t kNalUnitTypeSeqParamSet = 0x07;
static const uint8_t kNalUnitTypePicParamSet = 0x08;
static const int64_t kInitialDelayTimeUs = 700000LL;
@@ -118,7 +116,7 @@
int64_t getDurationUs() const;
int64_t getEstimatedTrackSizeBytes() const;
int32_t getMetaSizeIncrease(int32_t angle, int32_t trackCount) const;
- void writeTrackHeader(bool use32BitOffset = true);
+ void writeTrackHeader();
int64_t getMinCttsOffsetTimeUs();
void bufferChunk(int64_t timestampUs);
bool isAvc() const { return mIsAvc; }
@@ -136,6 +134,7 @@
static const char *getFourCCForMime(const char *mime);
const char *getTrackType() const;
void resetInternal();
+ int64_t trackMetaDataSize();
private:
// A helper class to handle faster write box with table entries
@@ -295,20 +294,16 @@
int64_t mTrackDurationUs;
int64_t mMaxChunkDurationUs;
int64_t mLastDecodingTimeUs;
-
int64_t mEstimatedTrackSizeBytes;
int64_t mMdatSizeBytes;
int32_t mTimeScale;
pthread_t mThread;
-
List<MediaBuffer *> mChunkSamples;
- bool mSamplesHaveSameSize;
+ bool mSamplesHaveSameSize;
ListTableEntries<uint32_t, 1> *mStszTableEntries;
-
- ListTableEntries<uint32_t, 1> *mStcoTableEntries;
ListTableEntries<off64_t, 1> *mCo64TableEntries;
ListTableEntries<uint32_t, 3> *mStscTableEntries;
ListTableEntries<uint32_t, 1> *mStssTableEntries;
@@ -352,6 +347,8 @@
int64_t mStartTimestampUs;
int64_t mStartTimeRealUs;
int64_t mFirstSampleTimeRealUs;
+ // Captures negative start offset of a track(track starttime < 0).
+ int64_t mFirstSampleStartOffsetUs;
int64_t mPreviousTrackTimeUs;
int64_t mTrackEveryTimeDurationUs;
@@ -361,6 +358,7 @@
ItemRefs mDimgRefs;
Vector<uint16_t> mExifList;
uint16_t mImageItemId;
+ uint16_t mItemIdBase;
int32_t mIsPrimary;
int32_t mWidth, mHeight;
int32_t mTileWidth, mTileHeight;
@@ -410,10 +408,8 @@
void updateTrackSizeEstimate();
void addOneStscTableEntry(size_t chunkId, size_t sampleId);
void addOneStssTableEntry(size_t sampleId);
-
- // Duration is time scale based
- void addOneSttsTableEntry(size_t sampleCount, int32_t timescaledDur);
- void addOneCttsTableEntry(size_t sampleCount, int32_t timescaledDur);
+ void addOneSttsTableEntry(size_t sampleCount, int32_t delta /* media time scale based */);
+ void addOneCttsTableEntry(size_t sampleCount, int32_t sampleOffset);
void addOneElstTableEntry(uint32_t segmentDuration, int32_t mediaTime,
int16_t mediaRate, int16_t mediaRateFraction);
@@ -421,7 +417,7 @@
void sendTrackSummary(bool hasMultipleTracks);
// Write the boxes
- void writeStcoBox(bool use32BitOffset);
+ void writeCo64Box();
void writeStscBox();
void writeStszBox();
void writeStssBox();
@@ -447,7 +443,7 @@
void writeAudioFourCCBox();
void writeVideoFourCCBox();
void writeMetadataFourCCBox();
- void writeStblBox(bool use32BitOffset);
+ void writeStblBox();
void writeEdtsBox();
Track(const Track &);
@@ -489,14 +485,17 @@
mStarted = false;
mWriterThreadStarted = false;
mSendNotify = false;
+ mWriteSeekErr = false;
+ mFallocateErr = false;
// Reset following variables for all the sessions and they will be
// initialized in start(MetaData *param).
mIsRealTimeRecording = true;
mUse4ByteNalLength = true;
- mUse32BitOffset = true;
mOffset = 0;
+ mPreAllocateFileEndOffset = 0;
mMdatOffset = 0;
+ mMdatEndOffset = 0;
mInMemoryCache = NULL;
mInMemoryCacheOffset = 0;
mInMemoryCacheSize = 0;
@@ -505,10 +504,14 @@
mStreamableFile = false;
mTimeScale = -1;
mHasFileLevelMeta = false;
+ mFileLevelMetaDataSize = 0;
mPrimaryItemId = 0;
mAssociationEntryCount = 0;
mNumGrids = 0;
+ mNextItemId = kItemIdBase;
mHasRefs = false;
+ mPreAllocFirstTime = true;
+ mPrevAllTracksTotalMetaDataSizeEstimate = 0;
// Following variables only need to be set for the first recording session.
// And they will stay the same for all the recording sessions.
@@ -530,6 +533,15 @@
ALOGE("cannot seek mFd: %s (%d) %lld", strerror(errno), errno, (long long)mFd);
release();
}
+
+ if (fallocate(mFd, 0, 0, 1) == 0) {
+ ALOGD("PreAllocation enabled");
+ mPreAllocationEnabled = true;
+ } else {
+ ALOGD("PreAllocation disabled. fallocate : %s, %d", strerror(errno), errno);
+ mPreAllocationEnabled = false;
+ }
+
for (List<Track *>::iterator it = mTracks.begin();
it != mTracks.end(); ++it) {
(*it)->resetInternal();
@@ -613,8 +625,9 @@
CHECK(source.get() != NULL);
- const char *mime;
- source->getFormat()->findCString(kKeyMIMEType, &mime);
+ const char *mime = NULL;
+ sp<MetaData> meta = source->getFormat();
+ meta->findCString(kKeyMIMEType, &mime);
if (Track::getFourCCForMime(mime) == NULL) {
ALOGE("Unsupported mime '%s'", mime);
@@ -736,9 +749,8 @@
// If the estimation is wrong, we will pay the price of wasting
// some reserved space. This should not happen so often statistically.
- static const int32_t factor = mUse32BitOffset? 1: 2;
- static const int64_t MIN_MOOV_BOX_SIZE = 3 * 1024; // 3 KB
- static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000);
+ static const int64_t MIN_MOOV_BOX_SIZE = 3 * 1024; // 3 KibiBytes
+ static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000); // 395.5 KibiBytes
int64_t size = MIN_MOOV_BOX_SIZE;
// Max file size limit is set
@@ -781,10 +793,7 @@
" estimated moov size %" PRId64 " bytes",
mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size);
- int64_t estimatedSize = factor * size;
- CHECK_GE(estimatedSize, 8);
-
- return estimatedSize;
+ return size;
}
status_t MPEG4Writer::start(MetaData *param) {
@@ -794,36 +803,24 @@
mStartMeta = param;
/*
- * Check mMaxFileSizeLimitBytes at the beginning
- * since mMaxFileSizeLimitBytes may be implicitly
- * changed later for 32-bit file offset even if
- * user does not ask to set it explicitly.
+ * Check mMaxFileSizeLimitBytes at the beginning since mMaxFileSizeLimitBytes may be implicitly
+ * changed later as per filesizebits of filesystem even if user does not set it explicitly.
*/
if (mMaxFileSizeLimitBytes != 0) {
mIsFileSizeLimitExplicitlyRequested = true;
}
- int32_t use64BitOffset;
- if (param &&
- param->findInt32(kKey64BitFileOffset, &use64BitOffset) &&
- use64BitOffset) {
- mUse32BitOffset = false;
- }
-
- if (mUse32BitOffset) {
- // Implicit 32 bit file size limit
- if (mMaxFileSizeLimitBytes == 0) {
- mMaxFileSizeLimitBytes = kMax32BitFileSize;
- }
-
- // If file size is set to be larger than the 32 bit file
- // size limit, treat it as an error.
- if (mMaxFileSizeLimitBytes > kMax32BitFileSize) {
- ALOGW("32-bit file size limit (%" PRId64 " bytes) too big. "
- "It is changed to %" PRId64 " bytes",
- mMaxFileSizeLimitBytes, kMax32BitFileSize);
- mMaxFileSizeLimitBytes = kMax32BitFileSize;
- }
+ int32_t fileSizeBits = fpathconf(mFd, _PC_FILESIZEBITS);
+ ALOGD("fpathconf _PC_FILESIZEBITS:%" PRId32, fileSizeBits);
+ fileSizeBits = std::min(fileSizeBits, 52 /* cap it below 4 peta bytes */);
+ int64_t maxFileSizeBytes = ((int64_t)1 << fileSizeBits) - 1;
+ if (mMaxFileSizeLimitBytes > maxFileSizeBytes) {
+ mMaxFileSizeLimitBytes = maxFileSizeBytes;
+ ALOGD("File size limit (%" PRId64 " bytes) too big. It is changed to %" PRId64 " bytes",
+ mMaxFileSizeLimitBytes, maxFileSizeBytes);
+ } else if (mMaxFileSizeLimitBytes == 0) {
+ mMaxFileSizeLimitBytes = maxFileSizeBytes;
+ ALOGD("File size limit set to %" PRId64 " bytes implicitly", maxFileSizeBytes);
}
int32_t use2ByteNalLength;
@@ -850,7 +847,8 @@
if (!param ||
!param->findInt32(kKeyTimeScale, &mTimeScale)) {
- mTimeScale = 1000;
+ // Increased by a factor of 10 to improve precision of segment duration in edit list entry.
+ mTimeScale = 10000;
}
CHECK_GT(mTimeScale, 0);
ALOGV("movie time scale: %d", mTimeScale);
@@ -915,7 +913,8 @@
if (mInMemoryCacheSize == 0) {
int32_t bitRate = -1;
if (mHasFileLevelMeta) {
- mInMemoryCacheSize += estimateFileLevelMetaSize(param);
+ mFileLevelMetaDataSize = estimateFileLevelMetaSize(param);
+ mInMemoryCacheSize += mFileLevelMetaDataSize;
}
if (mHasMoovBox) {
if (param) {
@@ -926,7 +925,7 @@
}
if (mStreamableFile) {
// Reserve a 'free' box only for streamable file
- lseek64(mFd, mFreeBoxOffset, SEEK_SET);
+ seekOrPostError(mFd, mFreeBoxOffset, SEEK_SET);
writeInt32(mInMemoryCacheSize);
write("free", 4);
mMdatOffset = mFreeBoxOffset + mInMemoryCacheSize;
@@ -935,18 +934,16 @@
}
mOffset = mMdatOffset;
- lseek64(mFd, mMdatOffset, SEEK_SET);
- if (mUse32BitOffset) {
- write("????mdat", 8);
- } else {
- write("\x00\x00\x00\x01mdat????????", 16);
- }
+ seekOrPostError(mFd, mMdatOffset, SEEK_SET);
+ write("\x00\x00\x00\x01mdat????????", 16);
status_t err = startWriterThread();
if (err != OK) {
return err;
}
+ setupAndStartLooper();
+
err = startTracks(param);
if (err != OK) {
return err;
@@ -956,32 +953,30 @@
return OK;
}
-bool MPEG4Writer::use32BitFileOffset() const {
- return mUse32BitOffset;
-}
-
status_t MPEG4Writer::pause() {
ALOGW("MPEG4Writer: pause is not supported");
return ERROR_UNSUPPORTED;
}
-void MPEG4Writer::stopWriterThread() {
- ALOGD("Stopping writer thread");
+status_t MPEG4Writer::stopWriterThread() {
+ ALOGV("Stopping writer thread");
if (!mWriterThreadStarted) {
- return;
+ return OK;
}
-
{
Mutex::Autolock autolock(mLock);
-
mDone = true;
mChunkReadyCondition.signal();
}
void *dummy;
- pthread_join(mThread, &dummy);
+ status_t err = pthread_join(mThread, &dummy);
+ WARN_UNLESS(err == 0, "stopWriterThread pthread_join err: %d", err);
+
+ err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy));
mWriterThreadStarted = false;
- ALOGD("Writer thread stopped");
+ WARN_UNLESS(err == 0, "stopWriterThread pthread_join retVal: %d, writer thread stopped", err);
+ return err;
}
/*
@@ -1037,12 +1032,21 @@
}
void MPEG4Writer::release() {
- close(mFd);
+ ALOGD("release()");
+ if (mPreAllocationEnabled) {
+ truncatePreAllocation();
+ }
+ int retVal = fsync(mFd);
+ WARN_UNLESS(retVal == 0, "fsync retVal:%d", retVal);
+ retVal = close(mFd);
+ WARN_UNLESS(retVal == 0, "close mFd retVal :%d", retVal);
mFd = -1;
if (mNextFd != -1) {
- close(mNextFd);
+ retVal = close(mNextFd);
mNextFd = -1;
+ WARN_UNLESS(retVal == 0, "close mNextFd retVal :%d", retVal);
}
+ stopAndReleaseLooper();
mInitCheck = NO_INIT;
mStarted = false;
free(mInMemoryCache);
@@ -1073,16 +1077,19 @@
}
status_t MPEG4Writer::reset(bool stopSource) {
+ ALOGD("reset()");
+ std::lock_guard<std::mutex> l(mResetMutex);
if (mInitCheck != OK) {
return OK;
} else {
if (!mWriterThreadStarted ||
!mStarted) {
+ status_t err = OK;
if (mWriterThreadStarted) {
- stopWriterThread();
+ err = stopWriterThread();
}
release();
- return OK;
+ return err;
}
}
@@ -1092,9 +1099,10 @@
int32_t nonImageTrackCount = 0;
for (List<Track *>::iterator it = mTracks.begin();
it != mTracks.end(); ++it) {
- status_t status = (*it)->stop(stopSource);
- if (err == OK && status != OK) {
- err = status;
+ status_t trackErr = (*it)->stop(stopSource);
+ if (err == OK && trackErr != OK) {
+ ALOGW("%s track stopped with an error", (*it)->getTrackType());
+ err = trackErr;
}
// skip image tracks
@@ -1110,31 +1118,32 @@
}
}
+
if (nonImageTrackCount > 1) {
ALOGD("Duration from tracks range is [%" PRId64 ", %" PRId64 "] us",
minDurationUs, maxDurationUs);
}
- stopWriterThread();
+ status_t writerErr = stopWriterThread();
- // Do not write out movie header on error.
- if (err != OK) {
+ // TODO: which error to propagage, writerErr or trackErr?
+ if (err == OK && writerErr != OK) {
+ err = writerErr;
+ }
+
+ // Do not write out movie header on error except malformed track.
+ if (err != OK && err != ERROR_MALFORMED) {
release();
return err;
}
// Fix up the size of the 'mdat' chunk.
- if (mUse32BitOffset) {
- lseek64(mFd, mMdatOffset, SEEK_SET);
- uint32_t size = htonl(static_cast<uint32_t>(mOffset - mMdatOffset));
- ::write(mFd, &size, 4);
- } else {
- lseek64(mFd, mMdatOffset + 8, SEEK_SET);
- uint64_t size = mOffset - mMdatOffset;
- size = hton64(size);
- ::write(mFd, &size, 8);
- }
- lseek64(mFd, mOffset, SEEK_SET);
+ seekOrPostError(mFd, mMdatOffset + 8, SEEK_SET);
+ uint64_t size = mOffset - mMdatOffset;
+ size = hton64(size);
+ writeOrPostError(mFd, &size, 8);
+ seekOrPostError(mFd, mOffset, SEEK_SET);
+ mMdatEndOffset = mOffset;
// Construct file-level meta and moov box now
mInMemoryCacheOffset = 0;
@@ -1198,12 +1207,12 @@
CHECK_LE(mInMemoryCacheOffset + 8, mInMemoryCacheSize);
// Cached box
- lseek64(mFd, mFreeBoxOffset, SEEK_SET);
+ seekOrPostError(mFd, mFreeBoxOffset, SEEK_SET);
mOffset = mFreeBoxOffset;
write(mInMemoryCache, 1, mInMemoryCacheOffset);
// Free box
- lseek64(mFd, mOffset, SEEK_SET);
+ seekOrPostError(mFd, mOffset, SEEK_SET);
mFreeBoxOffset = mOffset;
writeInt32(mInMemoryCacheSize - mInMemoryCacheOffset);
write("free", 4);
@@ -1272,20 +1281,19 @@
std::min(minCttsOffsetTimeUs, (*it)->getMinCttsOffsetTimeUs());
}
}
- ALOGI("Ajust the moov start time from %lld us -> %lld us",
- (long long)mStartTimestampUs,
- (long long)(mStartTimestampUs + minCttsOffsetTimeUs - kMaxCttsOffsetTimeUs));
- // Adjust the global start time.
+ ALOGI("Adjust the moov start time from %lld us -> %lld us", (long long)mStartTimestampUs,
+ (long long)(mStartTimestampUs + minCttsOffsetTimeUs - kMaxCttsOffsetTimeUs));
+ // Adjust movie start time.
mStartTimestampUs += minCttsOffsetTimeUs - kMaxCttsOffsetTimeUs;
- // Add mStartTimeOffsetBFramesUs(-ve or zero) to the duration of first entry in STTS.
+ // Add mStartTimeOffsetBFramesUs(-ve or zero) to the start offset of tracks.
mStartTimeOffsetBFramesUs = minCttsOffsetTimeUs - kMaxCttsOffsetTimeUs;
ALOGV("mStartTimeOffsetBFramesUs :%" PRId32, mStartTimeOffsetBFramesUs);
for (List<Track *>::iterator it = mTracks.begin();
it != mTracks.end(); ++it) {
if (!(*it)->isHeic()) {
- (*it)->writeTrackHeader(mUse32BitOffset);
+ (*it)->writeTrackHeader();
}
}
endBox(); // moov
@@ -1376,17 +1384,15 @@
} else {
if (tiffHdrOffset > 0) {
tiffHdrOffset = htonl(tiffHdrOffset);
- ::write(mFd, &tiffHdrOffset, 4); // exif_tiff_header_offset field
+ writeOrPostError(mFd, &tiffHdrOffset, 4); // exif_tiff_header_offset field
mOffset += 4;
}
- ::write(mFd,
- (const uint8_t *)buffer->data() + buffer->range_offset(),
- buffer->range_length());
+ writeOrPostError(mFd, (const uint8_t*)buffer->data() + buffer->range_offset(),
+ buffer->range_length());
mOffset += buffer->range_length();
}
-
*bytesWritten = mOffset - old_offset;
return old_offset;
}
@@ -1431,30 +1437,27 @@
void MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) {
size_t length = buffer->range_length();
-
if (mUse4ByteNalLength) {
uint8_t x = length >> 24;
- ::write(mFd, &x, 1);
+ writeOrPostError(mFd, &x, 1);
x = (length >> 16) & 0xff;
- ::write(mFd, &x, 1);
+ writeOrPostError(mFd, &x, 1);
x = (length >> 8) & 0xff;
- ::write(mFd, &x, 1);
+ writeOrPostError(mFd, &x, 1);
x = length & 0xff;
- ::write(mFd, &x, 1);
+ writeOrPostError(mFd, &x, 1);
- ::write(mFd,
- (const uint8_t *)buffer->data() + buffer->range_offset(),
- length);
+ writeOrPostError(mFd, (const uint8_t*)buffer->data() + buffer->range_offset(), length);
mOffset += length + 4;
} else {
CHECK_LT(length, 65536u);
uint8_t x = length >> 8;
- ::write(mFd, &x, 1);
+ writeOrPostError(mFd, &x, 1);
x = length & 0xff;
- ::write(mFd, &x, 1);
- ::write(mFd, (const uint8_t *)buffer->data() + buffer->range_offset(), length);
+ writeOrPostError(mFd, &x, 1);
+ writeOrPostError(mFd, (const uint8_t*)buffer->data() + buffer->range_offset(), length);
mOffset += length + 2;
}
}
@@ -1476,9 +1479,9 @@
it != mBoxes.end(); ++it) {
(*it) += mOffset;
}
- lseek64(mFd, mOffset, SEEK_SET);
- ::write(mFd, mInMemoryCache, mInMemoryCacheOffset);
- ::write(mFd, ptr, bytes);
+ seekOrPostError(mFd, mOffset, SEEK_SET);
+ writeOrPostError(mFd, mInMemoryCache, mInMemoryCacheOffset);
+ writeOrPostError(mFd, ptr, bytes);
mOffset += (bytes + mInMemoryCacheOffset);
// All subsequent boxes will be written to the end of the file.
@@ -1488,13 +1491,54 @@
mInMemoryCacheOffset += bytes;
}
} else {
- ::write(mFd, ptr, size * nmemb);
+ writeOrPostError(mFd, ptr, bytes);
mOffset += bytes;
}
return bytes;
}
+void MPEG4Writer::writeOrPostError(int fd, const void* buf, size_t count) {
+ if (mWriteSeekErr == true)
+ return;
+ ssize_t bytesWritten = ::write(fd, buf, count);
+ /* Write as much as possible during stop() execution when there was an error
+ * (mWriteSeekErr == true) in the previous call to write() or lseek64().
+ */
+ if (bytesWritten == count)
+ return;
+ mWriteSeekErr = true;
+ // Note that errno is not changed even when bytesWritten < count.
+ ALOGE("writeOrPostError bytesWritten:%zd, count:%zu, error:%s(%d)", bytesWritten, count,
+ std::strerror(errno), errno);
+
+ // Can't guarantee that file is usable or write would succeed anymore, hence signal to stop.
+ sp<AMessage> msg = new AMessage(kWhatHandleIOError, mReflector);
+ status_t err = msg->post();
+ ALOGE("writeOrPostError post:%d", err);
+}
+
+void MPEG4Writer::seekOrPostError(int fd, off64_t offset, int whence) {
+ if (mWriteSeekErr == true)
+ return;
+ off64_t resOffset = lseek64(fd, offset, whence);
+ /* Allow to seek during stop() execution even when there was an error
+ * (mWriteSeekErr == true) in the previous call to write() or lseek64().
+ */
+ if (resOffset == offset)
+ return;
+ mWriteSeekErr = true;
+ ALOGE("seekOrPostError resOffset:%" PRIu64 ", offset:%" PRIu64 ", error:%s(%d)", resOffset,
+ offset, std::strerror(errno), errno);
+
+ // Can't guarantee that file is usable or seek would succeed anymore, hence signal to stop.
+ sp<AMessage> msg = new AMessage(kWhatHandleIOError, mReflector);
+ status_t err = msg->post();
+ ALOGE("seekOrPostError post:%d", err);
+}
+
void MPEG4Writer::beginBox(uint32_t id) {
+ ALOGV("beginBox:%" PRIu32, id);
+
mBoxes.push_back(mWriteBoxToMemory?
mInMemoryCacheOffset: mOffset);
@@ -1503,6 +1547,7 @@
}
void MPEG4Writer::beginBox(const char *fourcc) {
+ ALOGV("beginBox:%s", fourcc);
CHECK_EQ(strlen(fourcc), 4u);
mBoxes.push_back(mWriteBoxToMemory?
@@ -1522,10 +1567,11 @@
int32_t x = htonl(mInMemoryCacheOffset - offset);
memcpy(mInMemoryCache + offset, &x, 4);
} else {
- lseek64(mFd, offset, SEEK_SET);
+ seekOrPostError(mFd, offset, SEEK_SET);
writeInt32(mOffset - offset);
+ ALOGV("box size:%" PRIu64, mOffset - offset);
mOffset -= 4;
- lseek64(mFd, mOffset, SEEK_SET);
+ seekOrPostError(mFd, mOffset, SEEK_SET);
}
}
@@ -1679,6 +1725,79 @@
return mStreamableFile;
}
+bool MPEG4Writer::preAllocate(uint64_t wantSize) {
+ if (!mPreAllocationEnabled)
+ return true;
+
+ std::lock_guard<std::mutex> l(mFallocMutex);
+
+ if (mFallocateErr == true)
+ return false;
+
+ // approxMOOVHeadersSize has to be changed whenever its needed in the future.
+ uint64_t approxMOOVHeadersSize = 500;
+ // approxTrackHeadersSize has to be changed whenever its needed in the future.
+ const uint64_t approxTrackHeadersSize = 800;
+
+ uint64_t approxMOOVBoxSize = 0;
+ if (mPreAllocFirstTime) {
+ mPreAllocFirstTime = false;
+ approxMOOVBoxSize = approxMOOVHeadersSize + mFileLevelMetaDataSize + mMoovExtraSize +
+ (approxTrackHeadersSize * numTracks());
+ ALOGV("firstTimeAllocation approxMOOVBoxSize:%" PRIu64, approxMOOVBoxSize);
+ }
+
+ uint64_t allTracksTotalMetaDataSizeEstimate = 0;
+ for (List<Track *>::iterator it = mTracks.begin(); it != mTracks.end(); ++it) {
+ allTracksTotalMetaDataSizeEstimate += ((*it)->trackMetaDataSize());
+ }
+ ALOGV(" allTracksTotalMetaDataSizeEstimate:%" PRIu64, allTracksTotalMetaDataSizeEstimate);
+
+ /* MOOVBoxSize will increase whenever a sample gets written to the file. Enough to allocate
+ * the delta increase for each sample after the very first allocation.
+ */
+ uint64_t approxMetaDataSizeIncrease =
+ allTracksTotalMetaDataSizeEstimate - mPrevAllTracksTotalMetaDataSizeEstimate;
+ ALOGV("approxMetaDataSizeIncrease:%" PRIu64 " wantSize:%" PRIu64, approxMetaDataSizeIncrease,
+ wantSize);
+ mPrevAllTracksTotalMetaDataSizeEstimate = allTracksTotalMetaDataSizeEstimate;
+ ALOGV("mPreAllocateFileEndOffset:%" PRIu64 " mOffset:%" PRIu64, mPreAllocateFileEndOffset,
+ mOffset);
+ off64_t lastFileEndOffset = std::max(mPreAllocateFileEndOffset, mOffset);
+ uint64_t preAllocateSize = wantSize + approxMOOVBoxSize + approxMetaDataSizeIncrease;
+ ALOGV("preAllocateSize :%" PRIu64 " lastFileEndOffset:%" PRIu64, preAllocateSize,
+ lastFileEndOffset);
+
+ int res = fallocate(mFd, 0, lastFileEndOffset, preAllocateSize);
+ if (res == -1) {
+ ALOGE("fallocate err:%s, %d, fd:%d", strerror(errno), errno, mFd);
+ sp<AMessage> msg = new AMessage(kWhatHandleFallocateError, mReflector);
+ status_t err = msg->post();
+ mFallocateErr = true;
+ ALOGD("preAllocation post:%d", err);
+ } else {
+ mPreAllocateFileEndOffset = lastFileEndOffset + preAllocateSize;
+ ALOGV("mPreAllocateFileEndOffset:%" PRIu64, mPreAllocateFileEndOffset);
+ }
+ return (res == -1) ? false : true;
+}
+
+bool MPEG4Writer::truncatePreAllocation() {
+ bool status = true;
+ off64_t endOffset = std::max(mMdatEndOffset, mOffset);
+ /* if mPreAllocateFileEndOffset >= endOffset, then preallocation logic works good. (diff >= 0).
+ * Otherwise, the logic needs to be modified.
+ */
+ ALOGD("ftruncate mPreAllocateFileEndOffset:%" PRId64 " mOffset:%" PRIu64
+ " mMdatEndOffset:%" PRIu64 " diff:%" PRId64, mPreAllocateFileEndOffset, mOffset,
+ mMdatEndOffset, mPreAllocateFileEndOffset - endOffset);
+ if(ftruncate(mFd, endOffset) == -1) {
+ ALOGE("ftruncate err:%s, %d, fd:%d", strerror(errno), errno, mFd);
+ status = false;
+ }
+ return status;
+}
+
bool MPEG4Writer::exceedsFileSizeLimit() {
// No limit
if (mMaxFileSizeLimitBytes == 0) {
@@ -1764,6 +1883,9 @@
return mStartTimestampUs;
}
+/* Returns negative when reordering is needed because of BFrames or zero otherwise.
+ * CTTS values for tracks with BFrames offsets this negative value.
+ */
int32_t MPEG4Writer::getStartTimeOffsetBFramesUs() {
Mutex::Autolock autoLock(mLock);
return mStartTimeOffsetBFramesUs;
@@ -1792,7 +1914,6 @@
mEstimatedTrackSizeBytes(0),
mSamplesHaveSameSize(true),
mStszTableEntries(new ListTableEntries<uint32_t, 1>(1000)),
- mStcoTableEntries(new ListTableEntries<uint32_t, 1>(1000)),
mCo64TableEntries(new ListTableEntries<off64_t, 1>(1000)),
mStscTableEntries(new ListTableEntries<uint32_t, 3>(1000)),
mStssTableEntries(new ListTableEntries<uint32_t, 1>(1000)),
@@ -1807,9 +1928,12 @@
mGotAllCodecSpecificData(false),
mReachedEOS(false),
mStartTimestampUs(-1),
+ mFirstSampleTimeRealUs(0),
+ mFirstSampleStartOffsetUs(0),
mRotation(0),
mDimgRefs("dimg"),
mImageItemId(0),
+ mItemIdBase(0),
mIsPrimary(0),
mWidth(0),
mHeight(0),
@@ -1872,15 +1996,11 @@
mIsMalformed = false;
mTrackDurationUs = 0;
mEstimatedTrackSizeBytes = 0;
- mSamplesHaveSameSize = 0;
+ mSamplesHaveSameSize = false;
if (mStszTableEntries != NULL) {
delete mStszTableEntries;
mStszTableEntries = new ListTableEntries<uint32_t, 1>(1000);
}
- if (mStcoTableEntries != NULL) {
- delete mStcoTableEntries;
- mStcoTableEntries = new ListTableEntries<uint32_t, 1>(1000);
- }
if (mCo64TableEntries != NULL) {
delete mCo64TableEntries;
mCo64TableEntries = new ListTableEntries<off64_t, 1>(1000);
@@ -1908,25 +2028,24 @@
mReachedEOS = false;
}
+int64_t MPEG4Writer::Track::trackMetaDataSize() {
+ int64_t co64BoxSizeBytes = mCo64TableEntries->count() * 8;
+ int64_t stszBoxSizeBytes = mStszTableEntries->count() * 4;
+ int64_t trackMetaDataSize = mStscTableEntries->count() * 12 + // stsc box size
+ mStssTableEntries->count() * 4 + // stss box size
+ mSttsTableEntries->count() * 8 + // stts box size
+ mCttsTableEntries->count() * 8 + // ctts box size
+ mElstTableEntries->count() * 12 + // elst box size
+ co64BoxSizeBytes + // stco box size
+ stszBoxSizeBytes; // stsz box size
+ return trackMetaDataSize;
+}
+
+
void MPEG4Writer::Track::updateTrackSizeEstimate() {
mEstimatedTrackSizeBytes = mMdatSizeBytes; // media data size
-
if (!isHeic() && !mOwner->isFileStreamable()) {
- uint32_t stcoBoxCount = (mOwner->use32BitFileOffset()
- ? mStcoTableEntries->count()
- : mCo64TableEntries->count());
- int64_t stcoBoxSizeBytes = stcoBoxCount * 4;
- int64_t stszBoxSizeBytes = mSamplesHaveSameSize? 4: (mStszTableEntries->count() * 4);
-
- // Reserved free space is not large enough to hold
- // all meta data and thus wasted.
- mEstimatedTrackSizeBytes += mStscTableEntries->count() * 12 + // stsc box size
- mStssTableEntries->count() * 4 + // stss box size
- mSttsTableEntries->count() * 8 + // stts box size
- mCttsTableEntries->count() * 8 + // ctts box size
- mElstTableEntries->count() * 12 + // elst box size
- stcoBoxSizeBytes + // stco box size
- stszBoxSizeBytes; // stsz box size
+ mEstimatedTrackSizeBytes += trackMetaDataSize();
}
}
@@ -1941,24 +2060,20 @@
mStssTableEntries->add(htonl(sampleId));
}
-void MPEG4Writer::Track::addOneSttsTableEntry(
- size_t sampleCount, int32_t duration) {
-
- if (duration == 0) {
+void MPEG4Writer::Track::addOneSttsTableEntry(size_t sampleCount, int32_t delta) {
+ if (delta == 0) {
ALOGW("0-duration samples found: %zu", sampleCount);
}
mSttsTableEntries->add(htonl(sampleCount));
- mSttsTableEntries->add(htonl(duration));
+ mSttsTableEntries->add(htonl(delta));
}
-void MPEG4Writer::Track::addOneCttsTableEntry(
- size_t sampleCount, int32_t duration) {
-
+void MPEG4Writer::Track::addOneCttsTableEntry(size_t sampleCount, int32_t sampleOffset) {
if (!mIsVideo) {
return;
}
mCttsTableEntries->add(htonl(sampleCount));
- mCttsTableEntries->add(htonl(duration));
+ mCttsTableEntries->add(htonl(sampleOffset));
}
void MPEG4Writer::Track::addOneElstTableEntry(
@@ -1971,16 +2086,30 @@
mElstTableEntries->add(htonl((((uint32_t)mediaRate) << 16) | (uint32_t)mediaRateFraction));
}
-status_t MPEG4Writer::setNextFd(int fd) {
- ALOGV("addNextFd");
- Mutex::Autolock l(mLock);
- if (mLooper == NULL) {
- mReflector = new AHandlerReflector<MPEG4Writer>(this);
+void MPEG4Writer::setupAndStartLooper() {
+ if (mLooper == nullptr) {
mLooper = new ALooper;
- mLooper->registerHandler(mReflector);
+ mLooper->setName("MP4WriterLooper");
mLooper->start();
+ mReflector = new AHandlerReflector<MPEG4Writer>(this);
+ mLooper->registerHandler(mReflector);
}
+}
+void MPEG4Writer::stopAndReleaseLooper() {
+ if (mLooper != nullptr) {
+ if (mReflector != nullptr) {
+ ALOGD("unregisterHandler");
+ mLooper->unregisterHandler(mReflector->id());
+ mReflector.clear();
+ }
+ mLooper->stop();
+ mLooper.clear();
+ }
+}
+
+status_t MPEG4Writer::setNextFd(int fd) {
+ Mutex::Autolock l(mLock);
if (mNextFd != -1) {
// No need to set a new FD yet.
return INVALID_OPERATION;
@@ -2021,12 +2150,7 @@
void MPEG4Writer::Track::addChunkOffset(off64_t offset) {
CHECK(!mIsHeic);
- if (mOwner->use32BitFileOffset()) {
- uint32_t value = offset;
- mStcoTableEntries->add(htonl(value));
- } else {
- mCo64TableEntries->add(hton64(offset));
- }
+ mCo64TableEntries->add(hton64(offset));
}
void MPEG4Writer::Track::addItemOffsetAndSize(off64_t offset, size_t size, bool isExif) {
@@ -2042,8 +2166,14 @@
}
if (isExif) {
- mExifList.push_back(mOwner->addItem_l({
+ uint16_t exifItemId;
+ if (mOwner->reserveItemId_l(1, &exifItemId) != OK) {
+ return;
+ }
+
+ mExifList.push_back(mOwner->addItem_l({
.itemType = "Exif",
+ .itemId = exifItemId,
.isPrimary = false,
.isHidden = false,
.offset = (uint32_t)offset,
@@ -2092,6 +2222,7 @@
if (hasGrid) {
mDimgRefs.value.push_back(mOwner->addItem_l({
.itemType = "hvc1",
+ .itemId = mItemIdBase++,
.isPrimary = false,
.isHidden = true,
.offset = (uint32_t)offset,
@@ -2114,6 +2245,7 @@
}
mImageItemId = mOwner->addItem_l({
.itemType = "grid",
+ .itemId = mItemIdBase++,
.isPrimary = (mIsPrimary != 0),
.isHidden = false,
.rows = (uint32_t)mGridRows,
@@ -2126,6 +2258,7 @@
} else {
mImageItemId = mOwner->addItem_l({
.itemType = "hvc1",
+ .itemId = mItemIdBase++,
.isPrimary = (mIsPrimary != 0),
.isHidden = false,
.offset = (uint32_t)offset,
@@ -2195,6 +2328,22 @@
notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_NEXT_OUTPUT_FILE_STARTED, 0);
break;
}
+ // ::write() or lseek64() wasn't a success, file could be malformed
+ case kWhatHandleIOError: {
+ ALOGE("kWhatHandleIOError");
+ // Stop tracks' threads and main writer thread.
+ notify(MEDIA_RECORDER_EVENT_ERROR, MEDIA_RECORDER_ERROR_UNKNOWN, ERROR_MALFORMED);
+ stop();
+ break;
+ }
+ // fallocate() failed, hence notify app about it and stop().
+ case kWhatHandleFallocateError: {
+ ALOGE("kWhatHandleFallocateError");
+ //TODO: introduce new MEDIA_RECORDER_INFO_STOPPED instead MEDIA_RECORDER_INFO_UNKNOWN?
+ notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_UNKNOWN, ERROR_IO);
+ stop();
+ break;
+ }
default:
TRESPASS();
}
@@ -2213,8 +2362,10 @@
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC) ||
!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC)) {
mMeta->findData(kKeyHVCC, &type, &data, &size);
- } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)
- || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION)) {
+ mMeta->findData(kKeyDVCC, &type, &data, &size);
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
+ !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
if (mMeta->findData(kKeyESDS, &type, &data, &size)) {
ESDS esds(data, size);
if (esds.getCodecSpecificInfo(&data, &size) == OK &&
@@ -2234,7 +2385,6 @@
stop();
delete mStszTableEntries;
- delete mStcoTableEntries;
delete mCo64TableEntries;
delete mStscTableEntries;
delete mSttsTableEntries;
@@ -2243,7 +2393,6 @@
delete mElstTableEntries;
mStszTableEntries = NULL;
- mStcoTableEntries = NULL;
mCo64TableEntries = NULL;
mStscTableEntries = NULL;
mSttsTableEntries = NULL;
@@ -2383,7 +2532,6 @@
if (interChunkTimeUs > it->mPrevChunkTimestampUs) {
it->mMaxInterChunkDurUs = interChunkTimeUs;
}
-
return true;
}
}
@@ -2466,6 +2614,22 @@
params->findInt32(kKeyRotation, &rotationDegrees)) {
mRotation = rotationDegrees;
}
+ if (mIsHeic) {
+ // Reserve the item ids, so that the item ids are ordered in the same
+ // order that the image tracks are added.
+ // If we leave the item ids to be assigned when the sample is written out,
+ // the original track order may not be preserved, if two image tracks
+ // have data around the same time. (This could happen especially when
+ // we're encoding with single tile.) The reordering may be undesirable,
+ // even if the file is well-formed and the primary picture is correct.
+
+ // Reserve item ids for samples + grid
+ size_t numItemsToReserve = mNumTiles + (mNumTiles > 1);
+ status_t err = mOwner->reserveItemId_l(numItemsToReserve, &mItemIdBase);
+ if (err != OK) {
+ return err;
+ }
+ }
initTrackingProgressStatus(params);
@@ -2523,7 +2687,7 @@
status_t MPEG4Writer::Track::stop(bool stopSource) {
ALOGD("%s track stopping. %s source", getTrackType(), stopSource ? "Stop" : "Not Stop");
if (!mStarted) {
- ALOGE("Stop() called but track is not started");
+ ALOGE("Stop() called but track is not started or stopped");
return ERROR_END_OF_STREAM;
}
@@ -2542,10 +2706,12 @@
mDone = true;
void *dummy;
- pthread_join(mThread, &dummy);
- status_t err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy));
-
- ALOGD("%s track stopped. %s source", getTrackType(), stopSource ? "Stop" : "Not Stop");
+ status_t err = pthread_join(mThread, &dummy);
+ WARN_UNLESS(err == 0, "track::stop: pthread_join status:%d", err);
+ err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy));
+ WARN_UNLESS(err == 0, "%s track stopped. Status :%d. %s source", getTrackType(), err,
+ stopSource ? "Stop" : "Not Stop");
+ mStarted = false;
return err;
}
@@ -2943,6 +3109,7 @@
int32_t nActualFrames = 0; // frames containing non-CSD data (non-0 length)
int32_t nZeroLengthFrames = 0;
int64_t lastTimestampUs = 0; // Previous sample time stamp
+ int64_t previousSampleTimestampWithoutFudgeUs = 0; // Timestamp received/without fudge for STTS
int64_t lastDurationUs = 0; // Between the previous two samples
int64_t currDurationTicks = 0; // Timescale based ticks
int64_t lastDurationTicks = 0; // Timescale based ticks
@@ -2955,13 +3122,15 @@
int64_t lastCttsOffsetTimeTicks = -1; // Timescale based ticks
int32_t cttsSampleCount = 0; // Sample count in the current ctts table entry
uint32_t lastSamplesPerChunk = 0;
+ int64_t lastSampleDurationUs = -1; // Duration calculated from EOS buffer and its timestamp
+ int64_t lastSampleDurationTicks = -1; // Timescale based ticks
if (mIsAudio) {
- prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0);
+ prctl(PR_SET_NAME, (unsigned long)"AudioTrackWriterThread", 0, 0, 0);
} else if (mIsVideo) {
- prctl(PR_SET_NAME, (unsigned long)"VideoTrackEncoding", 0, 0, 0);
+ prctl(PR_SET_NAME, (unsigned long)"VideoTrackWriterThread", 0, 0, 0);
} else {
- prctl(PR_SET_NAME, (unsigned long)"MetadataTrackEncoding", 0, 0, 0);
+ prctl(PR_SET_NAME, (unsigned long)"MetadataTrackWriterThread", 0, 0, 0);
}
if (mOwner->isRealTimeRecording()) {
@@ -2974,11 +3143,32 @@
MediaBufferBase *buffer;
const char *trackName = getTrackType();
while (!mDone && (err = mSource->read(&buffer)) == OK) {
+ int32_t isEOS = false;
if (buffer->range_length() == 0) {
- buffer->release();
- buffer = NULL;
- ++nZeroLengthFrames;
- continue;
+ if (buffer->meta_data().findInt32(kKeyIsEndOfStream, &isEOS) && isEOS) {
+ int64_t eosSampleTimestampUs = -1;
+ CHECK(buffer->meta_data().findInt64(kKeyTime, &eosSampleTimestampUs));
+ if (eosSampleTimestampUs > 0) {
+ lastSampleDurationUs = eosSampleTimestampUs -
+ previousSampleTimestampWithoutFudgeUs -
+ previousPausedDurationUs;
+ if (lastSampleDurationUs >= 0) {
+ lastSampleDurationTicks = (lastSampleDurationUs * mTimeScale + 500000LL) /
+ 1000000LL;
+ } else {
+ ALOGW("lastSampleDurationUs %" PRId64 " is negative", lastSampleDurationUs);
+ }
+ }
+ buffer->release();
+ buffer = nullptr;
+ mSource->stop();
+ break;
+ } else {
+ buffer->release();
+ buffer = nullptr;
+ ++nZeroLengthFrames;
+ continue;
+ }
}
// If the codec specific data has not been received yet, delay pause.
@@ -2991,7 +3181,6 @@
}
++count;
-
int32_t isCodecConfig;
if (buffer->meta_data().findInt32(kKeyIsCodecConfig, &isCodecConfig)
&& isCodecConfig) {
@@ -3058,6 +3247,18 @@
}
}
+ /*
+ * Reserve space in the file for the current sample + to be written MOOV box. If reservation
+ * for a new sample fails, preAllocate(...) stops muxing session completely. Stop() could
+ * write MOOV box successfully as space for the same was reserved in the prior call.
+ * Release the current buffer/sample only here.
+ */
+ if (!mOwner->preAllocate(buffer->range_length())) {
+ buffer->release();
+ buffer = nullptr;
+ break;
+ }
+
++nActualFrames;
// Make a deep copy of the MediaBuffer and Metadata and release
@@ -3069,7 +3270,6 @@
meta_data = new MetaData(buffer->meta_data());
buffer->release();
buffer = NULL;
-
if (isExif) {
copy->meta_data().setInt32(kKeyExifTiffOffset, tiffHdrOffset);
}
@@ -3117,10 +3317,10 @@
if (mOwner->approachingFileSizeLimit()) {
mOwner->notifyApproachingLimit();
}
-
int32_t isSync = false;
meta_data->findInt32(kKeyIsSyncFrame, &isSync);
CHECK(meta_data->findInt64(kKeyTime, ×tampUs));
+ timestampUs += mFirstSampleStartOffsetUs;
// For video, skip the first several non-key frames until getting the first key frame.
if (mIsVideo && !mGotStartKeyFrame && !isSync) {
@@ -3132,10 +3332,13 @@
mGotStartKeyFrame = true;
}
////////////////////////////////////////////////////////////////////////////////
-
if (!mIsHeic) {
if (mStszTableEntries->count() == 0) {
mFirstSampleTimeRealUs = systemTime() / 1000;
+ if (timestampUs < 0 && mFirstSampleStartOffsetUs == 0) {
+ mFirstSampleStartOffsetUs = -timestampUs;
+ timestampUs = 0;
+ }
mOwner->setStartTimestampUs(timestampUs);
mStartTimestampUs = timestampUs;
previousPausedDurationUs = mStartTimestampUs;
@@ -3291,6 +3494,8 @@
break;
}
+ previousSampleTimestampWithoutFudgeUs = timestampUs;
+
// if the duration is different for this sample, see if it is close enough to the previous
// duration that we can fudge it and use the same value, to avoid filling the stts table
// with lots of near-identical entries.
@@ -3307,17 +3512,17 @@
}
}
mStszTableEntries->add(htonl(sampleSize));
+
if (mStszTableEntries->count() > 2) {
// Force the first sample to have its own stts entry so that
// we can adjust its value later to maintain the A/V sync.
- if (mStszTableEntries->count() == 3 || currDurationTicks != lastDurationTicks) {
+ if (lastDurationTicks && currDurationTicks != lastDurationTicks) {
addOneSttsTableEntry(sampleCount, lastDurationTicks);
sampleCount = 1;
} else {
++sampleCount;
}
-
}
if (mSamplesHaveSameSize) {
if (mStszTableEntries->count() >= 2 && previousSampleSize != sampleSize) {
@@ -3350,11 +3555,7 @@
if (mIsHeic) {
addItemOffsetAndSize(offset, bytesWritten, isExif);
} else {
- uint32_t count = (mOwner->use32BitFileOffset()
- ? mStcoTableEntries->count()
- : mCo64TableEntries->count());
-
- if (count == 0) {
+ if (mCo64TableEntries->count() == 0) {
addChunkOffset(offset);
}
}
@@ -3390,58 +3591,63 @@
}
}
}
-
}
-
if (isTrackMalFormed()) {
+ mIsMalformed = true;
dumpTimeStamps();
err = ERROR_MALFORMED;
}
mOwner->trackProgressStatus(mTrackId, -1, err);
- if (mIsHeic) {
- if (!mChunkSamples.empty()) {
- bufferChunk(0);
- ++nChunks;
- }
- } else {
- // Last chunk
- if (!hasMultipleTracks) {
- addOneStscTableEntry(1, mStszTableEntries->count());
- } else if (!mChunkSamples.empty()) {
- addOneStscTableEntry(++nChunks, mChunkSamples.size());
- bufferChunk(timestampUs);
- }
-
- // We don't really know how long the last frame lasts, since
- // there is no frame time after it, just repeat the previous
- // frame's duration.
- if (mStszTableEntries->count() == 1) {
- lastDurationUs = 0; // A single sample's duration
- lastDurationTicks = 0;
- } else {
- ++sampleCount; // Count for the last sample
- }
-
- if (mStszTableEntries->count() <= 2) {
- addOneSttsTableEntry(1, lastDurationTicks);
- if (sampleCount - 1 > 0) {
- addOneSttsTableEntry(sampleCount - 1, lastDurationTicks);
+ // Add final entries only for non-empty tracks.
+ if (mStszTableEntries->count() > 0) {
+ if (mIsHeic) {
+ if (!mChunkSamples.empty()) {
+ bufferChunk(0);
+ ++nChunks;
}
} else {
- addOneSttsTableEntry(sampleCount, lastDurationTicks);
- }
+ // Last chunk
+ if (!hasMultipleTracks) {
+ addOneStscTableEntry(1, mStszTableEntries->count());
+ } else if (!mChunkSamples.empty()) {
+ addOneStscTableEntry(++nChunks, mChunkSamples.size());
+ bufferChunk(timestampUs);
+ }
- // The last ctts box may not have been written yet, and this
- // is to make sure that we write out the last ctts box.
- if (currCttsOffsetTimeTicks == lastCttsOffsetTimeTicks) {
- if (cttsSampleCount > 0) {
- addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks);
+ // We don't really know how long the last frame lasts, since
+ // there is no frame time after it, just repeat the previous
+ // frame's duration.
+ if (mStszTableEntries->count() == 1) {
+ if (lastSampleDurationUs >= 0) {
+ addOneSttsTableEntry(sampleCount, lastSampleDurationTicks);
+ } else {
+ lastDurationUs = 0; // A single sample's duration
+ lastDurationTicks = 0;
+ addOneSttsTableEntry(sampleCount, lastDurationTicks);
+ }
+ } else if (lastSampleDurationUs >= 0) {
+ addOneSttsTableEntry(sampleCount, lastDurationTicks);
+ addOneSttsTableEntry(1, lastSampleDurationTicks);
+ } else {
+ ++sampleCount; // Count for the last sample
+ addOneSttsTableEntry(sampleCount, lastDurationTicks);
+ }
+
+ // The last ctts box entry may not have been written yet, and this
+ // is to make sure that we write out the last ctts box entry.
+ if (currCttsOffsetTimeTicks == lastCttsOffsetTimeTicks) {
+ if (cttsSampleCount > 0) {
+ addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks);
+ }
+ }
+ if (lastSampleDurationUs >= 0) {
+ mTrackDurationUs += lastSampleDurationUs;
+ } else {
+ mTrackDurationUs += lastDurationUs;
}
}
-
- mTrackDurationUs += lastDurationUs;
}
mReachedEOS = true;
@@ -3464,14 +3670,24 @@
return true;
}
- if (!mIsHeic && mStszTableEntries->count() == 0) { // no samples written
- ALOGE("The number of recorded samples is 0");
- return true;
- }
-
- if (mIsVideo && mStssTableEntries->count() == 0) { // no sync frames for video
- ALOGE("There are no sync frames for video track");
- return true;
+ int32_t emptyTrackMalformed = false;
+ if (mOwner->mStartMeta &&
+ mOwner->mStartMeta->findInt32(kKeyEmptyTrackMalFormed, &emptyTrackMalformed) &&
+ emptyTrackMalformed) {
+ if (!mIsHeic && mStszTableEntries->count() == 0) { // no samples written
+ ALOGE("The number of recorded samples is 0");
+ return true;
+ }
+ if (mIsVideo && mStssTableEntries->count() == 0) { // no sync frames for video
+ ALOGE("There are no sync frames for video track");
+ return true;
+ }
+ } else {
+ // No sync frames for video.
+ if (mIsVideo && mStszTableEntries->count() > 0 && mStssTableEntries->count() == 0) {
+ ALOGE("There are no sync frames for video track");
+ return true;
+ }
}
if (OK != checkCodecSpecificData()) { // no codec specific data
@@ -3685,7 +3901,7 @@
"Metadata";
}
-void MPEG4Writer::Track::writeTrackHeader(bool use32BitOffset) {
+void MPEG4Writer::Track::writeTrackHeader() {
uint32_t now = getMpeg4Time();
mOwner->beginBox("trak");
writeTkhdBox(now);
@@ -3702,7 +3918,7 @@
writeNmhdBox();
}
writeDinfBox();
- writeStblBox(use32BitOffset);
+ writeStblBox();
mOwner->endBox(); // minf
mOwner->endBox(); // mdia
mOwner->endBox(); // trak
@@ -3718,27 +3934,30 @@
return mMinCttsOffsetTimeUs;
}
-void MPEG4Writer::Track::writeStblBox(bool use32BitOffset) {
+void MPEG4Writer::Track::writeStblBox() {
mOwner->beginBox("stbl");
- mOwner->beginBox("stsd");
- mOwner->writeInt32(0); // version=0, flags=0
- mOwner->writeInt32(1); // entry count
- if (mIsAudio) {
- writeAudioFourCCBox();
- } else if (mIsVideo) {
- writeVideoFourCCBox();
- } else {
- writeMetadataFourCCBox();
+ // Add subboxes only for non-empty tracks.
+ if (mStszTableEntries->count() > 0) {
+ mOwner->beginBox("stsd");
+ mOwner->writeInt32(0); // version=0, flags=0
+ mOwner->writeInt32(1); // entry count
+ if (mIsAudio) {
+ writeAudioFourCCBox();
+ } else if (mIsVideo) {
+ writeVideoFourCCBox();
+ } else {
+ writeMetadataFourCCBox();
+ }
+ mOwner->endBox(); // stsd
+ writeSttsBox();
+ if (mIsVideo) {
+ writeCttsBox();
+ writeStssBox();
+ }
+ writeStszBox();
+ writeStscBox();
+ writeCo64Box();
}
- mOwner->endBox(); // stsd
- writeSttsBox();
- if (mIsVideo) {
- writeCttsBox();
- writeStssBox();
- }
- writeStszBox();
- writeStscBox();
- writeStcoBox(use32BitOffset);
mOwner->endBox(); // stbl
}
@@ -4097,19 +4316,122 @@
mOwner->endBox();
}
-void MPEG4Writer::Track::writeEdtsBox(){
+void MPEG4Writer::Track::writeEdtsBox() {
ALOGV("%s : getStartTimeOffsetTimeUs of track:%" PRId64 " us", getTrackType(),
getStartTimeOffsetTimeUs());
- // Prepone video playback.
- if (mMinCttsOffsetTicks != mMaxCttsOffsetTicks) {
- int32_t mvhdTimeScale = mOwner->getTimeScale();
- uint32_t tkhdDuration = (getDurationUs() * mvhdTimeScale + 5E5) / 1E6;
- int64_t mediaTime = ((kMaxCttsOffsetTimeUs - getMinCttsOffsetTimeUs())
- * mTimeScale + 5E5) / 1E6;
- if (tkhdDuration > 0 && mediaTime > 0) {
- addOneElstTableEntry(tkhdDuration, mediaTime, 1, 0);
+ int32_t mvhdTimeScale = mOwner->getTimeScale();
+ ALOGV("mvhdTimeScale:%" PRId32, mvhdTimeScale);
+ /* trackStartOffsetUs of this track is the sum of longest offset needed by a track among all
+ * tracks with B frames in this movie and the start offset of this track.
+ */
+ int64_t trackStartOffsetUs = getStartTimeOffsetTimeUs();
+ ALOGV("trackStartOffsetUs:%" PRIu64, trackStartOffsetUs);
+
+ // Longest offset needed by a track among all tracks with B frames.
+ int32_t movieStartOffsetBFramesUs = mOwner->getStartTimeOffsetBFramesUs();
+ ALOGV("movieStartOffsetBFramesUs:%" PRId32, movieStartOffsetBFramesUs);
+
+ // This media/track's real duration (sum of duration of all samples in this track).
+ uint32_t tkhdDurationTicks = (mTrackDurationUs * mvhdTimeScale + 5E5) / 1E6;
+ ALOGV("mTrackDurationUs:%" PRId64 "us", mTrackDurationUs);
+
+ int64_t movieStartTimeUs = mOwner->getStartTimestampUs();
+ ALOGV("movieStartTimeUs:%" PRId64, movieStartTimeUs);
+
+ int64_t trackStartTimeUs = movieStartTimeUs + trackStartOffsetUs;
+ ALOGV("trackStartTimeUs:%" PRId64, trackStartTimeUs);
+
+ if (movieStartOffsetBFramesUs == 0) {
+ // No B frames in any tracks.
+ if (trackStartOffsetUs > 0) {
+ // Track with positive start offset.
+ uint32_t segDuration = (trackStartOffsetUs * mvhdTimeScale + 5E5) / 1E6;
+ ALOGV("segDuration:%" PRIu64 "us", trackStartOffsetUs);
+ /* The first entry is an empty edit (indicated by media_time equal to -1), and its
+ * duration (segment_duration) is equal to the difference of the presentation times of
+ * the earliest media sample among all tracks and the earliest media sample of the track.
+ */
+ ALOGV("Empty edit list entry");
+ addOneElstTableEntry(segDuration, -1, 1, 0);
+ addOneElstTableEntry(tkhdDurationTicks, 0, 1, 0);
+ } else if (mFirstSampleStartOffsetUs > 0) {
+ // Track with start time < 0 / negative start offset.
+ ALOGV("Normal edit list entry");
+ int32_t mediaTime = (mFirstSampleStartOffsetUs * mTimeScale + 5E5) / 1E6;
+ int32_t firstSampleOffsetTicks =
+ (mFirstSampleStartOffsetUs * mvhdTimeScale + 5E5) / 1E6;
+ // samples before 0 don't count in for duration, hence subtract firstSampleOffsetTicks.
+ addOneElstTableEntry(tkhdDurationTicks - firstSampleOffsetTicks, mediaTime, 1, 0);
+ } else {
+ // Track starting at zero.
+ ALOGV("No edit list entry required for this track");
}
+ } else if (movieStartOffsetBFramesUs < 0) {
+ // B frames present in at least one of the tracks.
+ ALOGV("writeEdtsBox - Reordered frames(B frames) present");
+ if (trackStartOffsetUs == std::abs(movieStartOffsetBFramesUs)) {
+ // Track starting at 0, no start offset.
+ // TODO : need to take care of mFirstSampleStartOffsetUs > 0 and trackStartOffsetUs > 0
+ // separately
+ if (mMinCttsOffsetTicks == mMaxCttsOffsetTicks) {
+ // Video with no B frame or non-video track.
+ if (mFirstSampleStartOffsetUs > 0) {
+ // Track with start time < 0 / negative start offset.
+ ALOGV("Normal edit list entry");
+ ALOGV("mFirstSampleStartOffsetUs:%" PRId64 "us", mFirstSampleStartOffsetUs);
+ int32_t mediaTimeTicks = (mFirstSampleStartOffsetUs * mTimeScale + 5E5) / 1E6;
+ int32_t firstSampleOffsetTicks =
+ (mFirstSampleStartOffsetUs * mvhdTimeScale + 5E5) / 1E6;
+ // Samples before 0 don't count for duration, subtract firstSampleOffsetTicks.
+ addOneElstTableEntry(tkhdDurationTicks - firstSampleOffsetTicks, mediaTimeTicks,
+ 1, 0);
+ }
+ } else {
+ // Track with B Frames.
+ int32_t mediaTimeTicks = (trackStartOffsetUs * mTimeScale + 5E5) / 1E6;
+ ALOGV("mediaTime:%" PRId64 "us", trackStartOffsetUs);
+ ALOGV("Normal edit list entry to negate start offset by B Frames in others tracks");
+ addOneElstTableEntry(tkhdDurationTicks, mediaTimeTicks, 1, 0);
+ }
+ } else if (trackStartOffsetUs > std::abs(movieStartOffsetBFramesUs)) {
+ // Track with start offset.
+ ALOGV("Tracks starting > 0");
+ int32_t editDurationTicks = 0;
+ if (mMinCttsOffsetTicks == mMaxCttsOffsetTicks) {
+ // Video with no B frame or non-video track.
+ editDurationTicks =
+ ((trackStartOffsetUs + movieStartOffsetBFramesUs) * mvhdTimeScale + 5E5) /
+ 1E6;
+ ALOGV("editDuration:%" PRId64 "us", (trackStartOffsetUs + movieStartOffsetBFramesUs));
+ } else {
+ // Track with B frame.
+ int32_t trackStartOffsetBFramesUs = getMinCttsOffsetTimeUs() - kMaxCttsOffsetTimeUs;
+ ALOGV("trackStartOffsetBFramesUs:%" PRId32, trackStartOffsetBFramesUs);
+ editDurationTicks =
+ ((trackStartOffsetUs + movieStartOffsetBFramesUs +
+ trackStartOffsetBFramesUs) * mvhdTimeScale + 5E5) / 1E6;
+ ALOGV("editDuration:%" PRId64 "us", (trackStartOffsetUs + movieStartOffsetBFramesUs + trackStartOffsetBFramesUs));
+ }
+ ALOGV("editDurationTicks:%" PRIu32, editDurationTicks);
+ if (editDurationTicks > 0) {
+ ALOGV("Empty edit list entry");
+ addOneElstTableEntry(editDurationTicks, -1, 1, 0);
+ addOneElstTableEntry(tkhdDurationTicks, 0, 1, 0);
+ } else if (editDurationTicks < 0) {
+ // Only video tracks with B Frames would hit this case.
+ ALOGV("Edit list entry to negate start offset by B frames in other tracks");
+ addOneElstTableEntry(tkhdDurationTicks, std::abs(editDurationTicks), 1, 0);
+ } else {
+ ALOGV("No edit list entry needed for this track");
+ }
+ } else {
+ // Not expecting this case as we adjust negative start timestamps to zero.
+ ALOGW("trackStartOffsetUs < std::abs(movieStartOffsetBFramesUs)");
+ }
+ } else {
+ // Neither B frames present nor absent! or any other case?.
+ ALOGW("movieStartOffsetBFramesUs > 0");
}
if (mElstTableEntries->count() == 0) {
@@ -4251,19 +4573,6 @@
void MPEG4Writer::Track::writeSttsBox() {
mOwner->beginBox("stts");
mOwner->writeInt32(0); // version=0, flags=0
- if (mMinCttsOffsetTicks == mMaxCttsOffsetTicks) {
- // For non-vdeio tracks or video tracks without ctts table,
- // adjust duration of first sample for tracks to account for
- // first sample not starting at the media start time.
- // TODO: consider signaling this using some offset
- // as this is not quite correct.
- uint32_t duration;
- CHECK(mSttsTableEntries->get(duration, 1));
- duration = htonl(duration); // Back to host byte order
- int32_t startTimeOffsetScaled = (((getStartTimeOffsetTimeUs() +
- mOwner->getStartTimeOffsetBFramesUs()) * mTimeScale) + 500000LL) / 1000000LL;
- mSttsTableEntries->set(htonl((int32_t)duration + startTimeOffsetScaled), 1);
- }
mSttsTableEntries->write(mOwner);
mOwner->endBox(); // stts
}
@@ -4284,7 +4593,9 @@
mOwner->beginBox("ctts");
mOwner->writeInt32(0); // version=0, flags=0
- int64_t deltaTimeUs = kMaxCttsOffsetTimeUs - getStartTimeOffsetTimeUs();
+ // Adjust ctts entries to have only offset needed for reordering frames.
+ int64_t deltaTimeUs = mMinCttsOffsetTimeUs;
+ ALOGV("ctts deltaTimeUs:%" PRId64, deltaTimeUs);
int64_t delta = (deltaTimeUs * mTimeScale + 500000LL) / 1000000LL;
mCttsTableEntries->adjustEntries([delta](size_t /* ix */, uint32_t (&value)[2]) {
// entries are <count, ctts> pairs; adjust only ctts
@@ -4325,14 +4636,10 @@
mOwner->endBox(); // stsc
}
-void MPEG4Writer::Track::writeStcoBox(bool use32BitOffset) {
- mOwner->beginBox(use32BitOffset? "stco": "co64");
+void MPEG4Writer::Track::writeCo64Box() {
+ mOwner->beginBox("co64");
mOwner->writeInt32(0); // version=0, flags=0
- if (use32BitOffset) {
- mStcoTableEntries->write(mOwner);
- } else {
- mCo64TableEntries->write(mOwner);
- }
+ mCo64TableEntries->write(mOwner);
mOwner->endBox(); // stco or co64
}
@@ -4455,9 +4762,11 @@
}
writeInt16((uint16_t)itemCount);
- for (size_t i = 0; i < itemCount; i++) {
- writeInt16(mItems[i].itemId);
- bool isGrid = mItems[i].isGrid();
+ for (auto it = mItems.begin(); it != mItems.end(); it++) {
+ ItemInfo &item = it->second;
+
+ writeInt16(item.itemId);
+ bool isGrid = item.isGrid();
writeInt16(isGrid ? 1 : 0); // construction_method
writeInt16(0); // data_reference_index = 0
@@ -4468,8 +4777,8 @@
writeInt32(mNumGrids++ * 8);
writeInt32(8);
} else {
- writeInt32(mItems[i].offset);
- writeInt32(mItems[i].size);
+ writeInt32(item.offset);
+ writeInt32(item.size);
}
}
endBox();
@@ -4498,9 +4807,11 @@
}
writeInt16((uint16_t)itemCount);
- for (size_t i = 0; i < itemCount; i++) {
- writeInfeBox(mItems[i].itemId, mItems[i].itemType,
- (mItems[i].isImage() && mItems[i].isHidden) ? 1 : 0);
+ for (auto it = mItems.begin(); it != mItems.end(); it++) {
+ ItemInfo &item = it->second;
+
+ writeInfeBox(item.itemId, item.itemType,
+ (item.isImage() && item.isHidden) ? 1 : 0);
}
endBox();
@@ -4509,20 +4820,22 @@
void MPEG4Writer::writeIdatBox() {
beginBox("idat");
- for (size_t i = 0; i < mItems.size(); i++) {
- if (mItems[i].isGrid()) {
+ for (auto it = mItems.begin(); it != mItems.end(); it++) {
+ ItemInfo &item = it->second;
+
+ if (item.isGrid()) {
writeInt8(0); // version
// flags == 1 means 32-bit width,height
- int8_t flags = (mItems[i].width > 65535 || mItems[i].height > 65535);
+ int8_t flags = (item.width > 65535 || item.height > 65535);
writeInt8(flags);
- writeInt8(mItems[i].rows - 1);
- writeInt8(mItems[i].cols - 1);
+ writeInt8(item.rows - 1);
+ writeInt8(item.cols - 1);
if (flags) {
- writeInt32(mItems[i].width);
- writeInt32(mItems[i].height);
+ writeInt32(item.width);
+ writeInt32(item.height);
} else {
- writeInt16((uint16_t)mItems[i].width);
- writeInt16((uint16_t)mItems[i].height);
+ writeInt16((uint16_t)item.width);
+ writeInt16((uint16_t)item.height);
}
}
}
@@ -4534,11 +4847,13 @@
beginBox("iref");
writeInt32(0); // Version = 0, Flags = 0
{
- for (size_t i = 0; i < mItems.size(); i++) {
- for (size_t r = 0; r < mItems[i].refsList.size(); r++) {
- const ItemRefs &refs = mItems[i].refsList[r];
+ for (auto it = mItems.begin(); it != mItems.end(); it++) {
+ ItemInfo &item = it->second;
+
+ for (size_t r = 0; r < item.refsList.size(); r++) {
+ const ItemRefs &refs = item.refsList[r];
beginBox(refs.key);
- writeInt16(mItems[i].itemId);
+ writeInt16(item.itemId);
size_t refCount = refs.value.size();
if (refCount > 65535) {
ALOGW("too many entries in %s", refs.key);
@@ -4613,12 +4928,14 @@
writeInt32(flags); // Version = 0
writeInt32(mAssociationEntryCount);
- for (size_t itemIndex = 0; itemIndex < mItems.size(); itemIndex++) {
- const Vector<uint16_t> &properties = mItems[itemIndex].properties;
+ for (auto it = mItems.begin(); it != mItems.end(); it++) {
+ ItemInfo &item = it->second;
+
+ const Vector<uint16_t> &properties = item.properties;
if (properties.empty()) {
continue;
}
- writeInt16(mItems[itemIndex].itemId);
+ writeInt16(item.itemId);
size_t entryCount = properties.size();
if (entryCount > 255) {
@@ -4648,19 +4965,21 @@
// patch up the mPrimaryItemId and count items with prop associations
uint16_t firstVisibleItemId = 0;
uint16_t firstImageItemId = 0;
- for (size_t index = 0; index < mItems.size(); index++) {
- if (!mItems[index].isImage()) continue;
+ for (auto it = mItems.begin(); it != mItems.end(); it++) {
+ ItemInfo &item = it->second;
- if (mItems[index].isPrimary) {
- mPrimaryItemId = mItems[index].itemId;
+ if (!item.isImage()) continue;
+
+ if (item.isPrimary) {
+ mPrimaryItemId = item.itemId;
}
if (!firstImageItemId) {
- firstImageItemId = mItems[index].itemId;
+ firstImageItemId = item.itemId;
}
- if (!firstVisibleItemId && !mItems[index].isHidden) {
- firstVisibleItemId = mItems[index].itemId;
+ if (!firstVisibleItemId && !item.isHidden) {
+ firstVisibleItemId = item.itemId;
}
- if (!mItems[index].properties.empty()) {
+ if (!item.properties.empty()) {
mAssociationEntryCount++;
}
}
@@ -4714,15 +5033,25 @@
return mProperties.size();
}
+status_t MPEG4Writer::reserveItemId_l(size_t numItems, uint16_t *itemIdBase) {
+ if (numItems > UINT16_MAX - mNextItemId) {
+ ALOGE("couldn't reserve item ids for %zu items", numItems);
+ return ERROR_OUT_OF_RANGE;
+ }
+ *itemIdBase = mNextItemId;
+ mNextItemId += numItems;
+ return OK;
+}
+
uint16_t MPEG4Writer::addItem_l(const ItemInfo &info) {
ALOGV("addItem_l: type %s, offset %u, size %u",
info.itemType, info.offset, info.size);
- size_t index = mItems.size();
- mItems.push_back(info);
+ if (info.itemId < kItemIdBase || info.itemId >= mNextItemId) {
+ ALOGW("Item id %u is used without reservation!", info.itemId);
+ }
- // make the item id start at kItemIdBase
- mItems.editItemAt(index).itemId = index + kItemIdBase;
+ mItems[info.itemId] = info;
#if (LOG_NDEBUG==0)
if (!info.properties.empty()) {
@@ -4733,24 +5062,28 @@
}
str.append(info.properties[i]);
}
- ALOGV("addItem_l: id %d, properties: %s", mItems[index].itemId, str.c_str());
+ ALOGV("addItem_l: id %d, properties: %s", info.itemId, str.c_str());
}
#endif // (LOG_NDEBUG==0)
- return mItems[index].itemId;
+ return info.itemId;
}
void MPEG4Writer::addRefs_l(uint16_t itemId, const ItemRefs &refs) {
if (refs.value.empty()) {
return;
}
- if (itemId < kItemIdBase) {
- ALOGW("itemId shouldn't be smaller than kItemIdBase");
+ if (itemId < kItemIdBase || itemId >= mNextItemId) {
+ ALOGW("itemId %u for ref is invalid!", itemId);
return;
}
- size_t index = itemId - kItemIdBase;
- mItems.editItemAt(index).refsList.push_back(refs);
+ auto it = mItems.find(itemId);
+ if (it == mItems.end()) {
+ ALOGW("itemId %u was not added yet", itemId);
+ return;
+ }
+ it->second.refsList.push_back(refs);
mHasRefs = true;
}
diff --git a/media/libstagefright/MediaClock.cpp b/media/libstagefright/MediaClock.cpp
index 4f9bc6d..24608a7 100644
--- a/media/libstagefright/MediaClock.cpp
+++ b/media/libstagefright/MediaClock.cpp
@@ -281,7 +281,7 @@
it = mTimers.erase(it);
} else {
if (mPlaybackRate != 0.0
- && (double)diffMediaUs < INT64_MAX * (double)mPlaybackRate) {
+ && (double)diffMediaUs < (double)INT64_MAX * (double)mPlaybackRate) {
int64_t targetRealUs = diffMediaUs / (double)mPlaybackRate;
if (targetRealUs < nextLapseRealUs) {
nextLapseRealUs = targetRealUs;
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index eceb84e..b597583 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -21,25 +21,28 @@
#include <inttypes.h>
#include <stdlib.h>
-#include "include/SecureBuffer.h"
-#include "include/SharedMemoryBuffer.h"
+#include <C2Buffer.h>
+
#include "include/SoftwareRenderer.h"
-#include "StagefrightPluginLoader.h"
#include <android/hardware/cas/native/1.0/IDescrambler.h>
+#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
+#include <aidl/android/media/BnResourceManagerClient.h>
+#include <aidl/android/media/IResourceManagerService.h>
+#include <android/binder_ibinder.h>
+#include <android/binder_manager.h>
#include <binder/IMemory.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
#include <binder/MemoryDealer.h>
#include <cutils/properties.h>
#include <gui/BufferQueue.h>
#include <gui/Surface.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/IOMX.h>
-#include <media/IResourceManagerService.h>
#include <media/MediaCodecBuffer.h>
-#include <media/MediaAnalyticsItem.h>
+#include <media/MediaCodecInfo.h>
+#include <media/MediaMetricsItem.h>
+#include <media/MediaResource.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
@@ -50,6 +53,7 @@
#include <media/stagefright/ACodec.h>
#include <media/stagefright/BatteryChecker.h>
#include <media/stagefright/BufferProducerWrapper.h>
+#include <media/stagefright/CCodec.h>
#include <media/stagefright/MediaCodec.h>
#include <media/stagefright/MediaCodecList.h>
#include <media/stagefright/MediaDefs.h>
@@ -63,6 +67,11 @@
namespace android {
+using Status = ::ndk::ScopedAStatus;
+using aidl::android::media::BnResourceManagerClient;
+using aidl::android::media::IResourceManagerClient;
+using aidl::android::media::IResourceManagerService;
+
// key for media statistics
static const char *kCodecKeyName = "codec";
// attrs for media statistics
@@ -94,6 +103,12 @@
static const char *kCodecLatencyCount = "android.media.mediacodec.latency.n";
static const char *kCodecLatencyHist = "android.media.mediacodec.latency.hist"; /* in us */
static const char *kCodecLatencyUnknown = "android.media.mediacodec.latency.unknown";
+static const char *kCodecQueueSecureInputBufferError = "android.media.mediacodec.queueSecureInputBufferError";
+static const char *kCodecQueueInputBufferError = "android.media.mediacodec.queueInputBufferError";
+
+static const char *kCodecNumLowLatencyModeOn = "android.media.mediacodec.low-latency.on"; /* 0..n */
+static const char *kCodecNumLowLatencyModeOff = "android.media.mediacodec.low-latency.off"; /* 0..n */
+static const char *kCodecFirstFrameIndexLowLatencyModeOn = "android.media.mediacodec.low-latency.first-frame"; /* 0..n */
// the kCodecRecent* fields appear only in getMetrics() results
static const char *kCodecRecentLatencyMax = "android.media.mediacodec.recent.max"; /* in us */
@@ -106,7 +121,7 @@
static bool kEmitHistogram = false;
-static int64_t getId(const sp<IResourceManagerClient> &client) {
+static int64_t getId(const std::shared_ptr<IResourceManagerClient> &client) {
return (int64_t) client.get();
}
@@ -118,16 +133,20 @@
static const int kMaxReclaimWaitTimeInUs = 500000; // 0.5s
static const int kNumBuffersAlign = 16;
+static const C2MemoryUsage kDefaultReadWriteUsage{
+ C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
+
////////////////////////////////////////////////////////////////////////////////
struct ResourceManagerClient : public BnResourceManagerClient {
explicit ResourceManagerClient(MediaCodec* codec) : mMediaCodec(codec) {}
- virtual bool reclaimResource() {
+ Status reclaimResource(bool* _aidl_return) override {
sp<MediaCodec> codec = mMediaCodec.promote();
if (codec == NULL) {
// codec is already gone.
- return true;
+ *_aidl_return = true;
+ return Status::ok();
}
status_t err = codec->reclaim();
if (err == WOULD_BLOCK) {
@@ -139,25 +158,25 @@
if (err != OK) {
ALOGW("ResourceManagerClient failed to release codec with err %d", err);
}
- return (err == OK);
+ *_aidl_return = (err == OK);
+ return Status::ok();
}
- virtual String8 getName() {
- String8 ret;
+ Status getName(::std::string* _aidl_return) override {
+ _aidl_return->clear();
sp<MediaCodec> codec = mMediaCodec.promote();
if (codec == NULL) {
// codec is already gone.
- return ret;
+ return Status::ok();
}
AString name;
if (codec->getName(&name) == OK) {
- ret.setTo(name.c_str());
+ *_aidl_return = name.c_str();
}
- return ret;
+ return Status::ok();
}
-protected:
virtual ~ResourceManagerClient() {}
private:
@@ -166,73 +185,110 @@
DISALLOW_EVIL_CONSTRUCTORS(ResourceManagerClient);
};
+struct MediaCodec::ResourceManagerServiceProxy : public RefBase {
+ ResourceManagerServiceProxy(pid_t pid, uid_t uid,
+ const std::shared_ptr<IResourceManagerClient> &client);
+ virtual ~ResourceManagerServiceProxy();
+
+ void init();
+
+ // implements DeathRecipient
+ static void BinderDiedCallback(void* cookie);
+ void binderDied();
+
+ void addResource(const MediaResourceParcel &resource);
+ void removeResource(const MediaResourceParcel &resource);
+ void removeClient();
+ bool reclaimResource(const std::vector<MediaResourceParcel> &resources);
+
+private:
+ Mutex mLock;
+ pid_t mPid;
+ uid_t mUid;
+ std::shared_ptr<IResourceManagerService> mService;
+ std::shared_ptr<IResourceManagerClient> mClient;
+ ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+};
+
MediaCodec::ResourceManagerServiceProxy::ResourceManagerServiceProxy(
- pid_t pid, uid_t uid)
- : mPid(pid), mUid(uid) {
+ pid_t pid, uid_t uid, const std::shared_ptr<IResourceManagerClient> &client)
+ : mPid(pid), mUid(uid), mClient(client),
+ mDeathRecipient(AIBinder_DeathRecipient_new(BinderDiedCallback)) {
if (mPid == MediaCodec::kNoPid) {
- mPid = IPCThreadState::self()->getCallingPid();
+ mPid = AIBinder_getCallingPid();
}
}
MediaCodec::ResourceManagerServiceProxy::~ResourceManagerServiceProxy() {
- if (mService != NULL) {
- IInterface::asBinder(mService)->unlinkToDeath(this);
+ if (mService != nullptr) {
+ AIBinder_unlinkToDeath(mService->asBinder().get(), mDeathRecipient.get(), this);
}
}
void MediaCodec::ResourceManagerServiceProxy::init() {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder = sm->getService(String16("media.resource_manager"));
- mService = interface_cast<IResourceManagerService>(binder);
- if (mService == NULL) {
+ ::ndk::SpAIBinder binder(AServiceManager_getService("media.resource_manager"));
+ mService = IResourceManagerService::fromBinder(binder);
+ if (mService == nullptr) {
ALOGE("Failed to get ResourceManagerService");
return;
}
- IInterface::asBinder(mService)->linkToDeath(this);
+
+ AIBinder_linkToDeath(mService->asBinder().get(), mDeathRecipient.get(), this);
}
-void MediaCodec::ResourceManagerServiceProxy::binderDied(const wp<IBinder>& /*who*/) {
+//static
+void MediaCodec::ResourceManagerServiceProxy::BinderDiedCallback(void* cookie) {
+ auto thiz = static_cast<ResourceManagerServiceProxy*>(cookie);
+ thiz->binderDied();
+}
+
+void MediaCodec::ResourceManagerServiceProxy::binderDied() {
ALOGW("ResourceManagerService died.");
Mutex::Autolock _l(mLock);
- mService.clear();
+ mService = nullptr;
}
void MediaCodec::ResourceManagerServiceProxy::addResource(
- int64_t clientId,
- const sp<IResourceManagerClient> &client,
- const Vector<MediaResource> &resources) {
+ const MediaResourceParcel &resource) {
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(resource);
+
Mutex::Autolock _l(mLock);
- if (mService == NULL) {
+ if (mService == nullptr) {
return;
}
- mService->addResource(mPid, mUid, clientId, client, resources);
+ mService->addResource(mPid, mUid, getId(mClient), mClient, resources);
}
void MediaCodec::ResourceManagerServiceProxy::removeResource(
- int64_t clientId,
- const Vector<MediaResource> &resources) {
+ const MediaResourceParcel &resource) {
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(resource);
+
Mutex::Autolock _l(mLock);
- if (mService == NULL) {
+ if (mService == nullptr) {
return;
}
- mService->removeResource(mPid, clientId, resources);
+ mService->removeResource(mPid, getId(mClient), resources);
}
-void MediaCodec::ResourceManagerServiceProxy::removeClient(int64_t clientId) {
+void MediaCodec::ResourceManagerServiceProxy::removeClient() {
Mutex::Autolock _l(mLock);
- if (mService == NULL) {
+ if (mService == nullptr) {
return;
}
- mService->removeClient(mPid, clientId);
+ mService->removeClient(mPid, getId(mClient));
}
bool MediaCodec::ResourceManagerServiceProxy::reclaimResource(
- const Vector<MediaResource> &resources) {
+ const std::vector<MediaResourceParcel> &resources) {
Mutex::Autolock _l(mLock);
if (mService == NULL) {
return false;
}
- return mService->reclaimResource(mPid, resources);
+ bool success;
+ Status status = mService->reclaimResource(mPid, resources, &success);
+ return status.isOk() && success;
}
////////////////////////////////////////////////////////////////////////////////
@@ -490,9 +546,7 @@
// static
sp<PersistentSurface> MediaCodec::CreatePersistentInputSurface() {
- // allow plugin to create surface
- sp<PersistentSurface> pluginSurface =
- StagefrightPluginLoader::GetCCodecInstance()->createInputSurface();
+ sp<PersistentSurface> pluginSurface = CCodec::CreateInputSurface();
if (pluginSurface != nullptr) {
return pluginSurface;
}
@@ -506,7 +560,7 @@
sp<IOMX> omx = client.interface();
sp<IGraphicBufferProducer> bufferProducer;
- sp<IGraphicBufferSource> bufferSource;
+ sp<hardware::media::omx::V1_0::IGraphicBufferSource> bufferSource;
status_t err = omx->createInputSurface(&bufferProducer, &bufferSource);
@@ -527,7 +581,7 @@
mFlags(0),
mStickyError(OK),
mSoftRenderer(NULL),
- mAnalyticsItem(NULL),
+ mMetricsHandle(0),
mIsVideo(false),
mVideoWidth(0),
mVideoHeight(0),
@@ -539,28 +593,33 @@
mHaveInputSurface(false),
mHavePendingInputBuffers(false),
mCpuBoostRequested(false),
- mLatencyUnknown(0) {
+ mLatencyUnknown(0),
+ mNumLowLatencyEnables(0),
+ mNumLowLatencyDisables(0),
+ mIsLowLatencyModeOn(false),
+ mIndexOfFirstFrameWhenLowLatencyOn(-1),
+ mInputBufferCounter(0) {
if (uid == kNoUid) {
- mUid = IPCThreadState::self()->getCallingUid();
+ mUid = AIBinder_getCallingUid();
} else {
mUid = uid;
}
- mResourceManagerClient = new ResourceManagerClient(this);
- mResourceManagerService = new ResourceManagerServiceProxy(pid, mUid);
+ mResourceManagerProxy = new ResourceManagerServiceProxy(pid, mUid,
+ ::ndk::SharedRefBase::make<ResourceManagerClient>(this));
- initAnalyticsItem();
+ initMediametrics();
}
MediaCodec::~MediaCodec() {
CHECK_EQ(mState, UNINITIALIZED);
- mResourceManagerService->removeClient(getId(mResourceManagerClient));
+ mResourceManagerProxy->removeClient();
- flushAnalyticsItem();
+ flushMediametrics();
}
-void MediaCodec::initAnalyticsItem() {
- if (mAnalyticsItem == NULL) {
- mAnalyticsItem = MediaAnalyticsItem::create(kCodecKeyName);
+void MediaCodec::initMediametrics() {
+ if (mMetricsHandle == 0) {
+ mMetricsHandle = mediametrics_create(kCodecKeyName);
}
mLatencyHist.setup(kLatencyHistBuckets, kLatencyHistWidth, kLatencyHistFloor);
@@ -572,40 +631,58 @@
}
mRecentHead = 0;
}
+
+ {
+ Mutex::Autolock al(mLatencyLock);
+ mBuffersInFlight.clear();
+ mNumLowLatencyEnables = 0;
+ mNumLowLatencyDisables = 0;
+ mIsLowLatencyModeOn = false;
+ mIndexOfFirstFrameWhenLowLatencyOn = -1;
+ mInputBufferCounter = 0;
+ }
}
-void MediaCodec::updateAnalyticsItem() {
- ALOGV("MediaCodec::updateAnalyticsItem");
- if (mAnalyticsItem == NULL) {
+void MediaCodec::updateMediametrics() {
+ ALOGV("MediaCodec::updateMediametrics");
+ if (mMetricsHandle == 0) {
return;
}
+
if (mLatencyHist.getCount() != 0 ) {
- mAnalyticsItem->setInt64(kCodecLatencyMax, mLatencyHist.getMax());
- mAnalyticsItem->setInt64(kCodecLatencyMin, mLatencyHist.getMin());
- mAnalyticsItem->setInt64(kCodecLatencyAvg, mLatencyHist.getAvg());
- mAnalyticsItem->setInt64(kCodecLatencyCount, mLatencyHist.getCount());
+ mediametrics_setInt64(mMetricsHandle, kCodecLatencyMax, mLatencyHist.getMax());
+ mediametrics_setInt64(mMetricsHandle, kCodecLatencyMin, mLatencyHist.getMin());
+ mediametrics_setInt64(mMetricsHandle, kCodecLatencyAvg, mLatencyHist.getAvg());
+ mediametrics_setInt64(mMetricsHandle, kCodecLatencyCount, mLatencyHist.getCount());
if (kEmitHistogram) {
// and the histogram itself
std::string hist = mLatencyHist.emit();
- mAnalyticsItem->setCString(kCodecLatencyHist, hist.c_str());
+ mediametrics_setCString(mMetricsHandle, kCodecLatencyHist, hist.c_str());
}
}
if (mLatencyUnknown > 0) {
- mAnalyticsItem->setInt64(kCodecLatencyUnknown, mLatencyUnknown);
+ mediametrics_setInt64(mMetricsHandle, kCodecLatencyUnknown, mLatencyUnknown);
}
+ {
+ Mutex::Autolock al(mLatencyLock);
+ mediametrics_setInt64(mMetricsHandle, kCodecNumLowLatencyModeOn, mNumLowLatencyEnables);
+ mediametrics_setInt64(mMetricsHandle, kCodecNumLowLatencyModeOff, mNumLowLatencyDisables);
+ mediametrics_setInt64(mMetricsHandle, kCodecFirstFrameIndexLowLatencyModeOn,
+ mIndexOfFirstFrameWhenLowLatencyOn);
+ }
#if 0
// enable for short term, only while debugging
- updateEphemeralAnalytics(mAnalyticsItem);
+ updateEphemeralMediametrics(mMetricsHandle);
#endif
}
-void MediaCodec::updateEphemeralAnalytics(MediaAnalyticsItem *item) {
- ALOGD("MediaCodec::updateEphemeralAnalytics()");
+void MediaCodec::updateEphemeralMediametrics(mediametrics_handle_t item) {
+ ALOGD("MediaCodec::updateEphemeralMediametrics()");
- if (item == NULL) {
+ if (item == 0) {
return;
}
@@ -628,28 +705,43 @@
// spit the data (if any) into the supplied analytics record
if (recentHist.getCount()!= 0 ) {
- item->setInt64(kCodecRecentLatencyMax, recentHist.getMax());
- item->setInt64(kCodecRecentLatencyMin, recentHist.getMin());
- item->setInt64(kCodecRecentLatencyAvg, recentHist.getAvg());
- item->setInt64(kCodecRecentLatencyCount, recentHist.getCount());
+ mediametrics_setInt64(item, kCodecRecentLatencyMax, recentHist.getMax());
+ mediametrics_setInt64(item, kCodecRecentLatencyMin, recentHist.getMin());
+ mediametrics_setInt64(item, kCodecRecentLatencyAvg, recentHist.getAvg());
+ mediametrics_setInt64(item, kCodecRecentLatencyCount, recentHist.getCount());
if (kEmitHistogram) {
// and the histogram itself
std::string hist = recentHist.emit();
- item->setCString(kCodecRecentLatencyHist, hist.c_str());
+ mediametrics_setCString(item, kCodecRecentLatencyHist, hist.c_str());
}
}
}
-void MediaCodec::flushAnalyticsItem() {
- updateAnalyticsItem();
- if (mAnalyticsItem != NULL) {
- // don't log empty records
- if (mAnalyticsItem->count() > 0) {
- mAnalyticsItem->selfrecord();
+void MediaCodec::flushMediametrics() {
+ updateMediametrics();
+ if (mMetricsHandle != 0) {
+ if (mediametrics_count(mMetricsHandle) > 0) {
+ mediametrics_selfRecord(mMetricsHandle);
}
- delete mAnalyticsItem;
- mAnalyticsItem = NULL;
+ mediametrics_delete(mMetricsHandle);
+ mMetricsHandle = 0;
+ }
+}
+
+void MediaCodec::updateLowLatency(const sp<AMessage> &msg) {
+ int32_t lowLatency = 0;
+ if (msg->findInt32("low-latency", &lowLatency)) {
+ Mutex::Autolock al(mLatencyLock);
+ if (lowLatency > 0) {
+ ++mNumLowLatencyEnables;
+ // This is just an estimate since low latency mode change happens ONLY at key frame
+ mIsLowLatencyModeOn = true;
+ } else if (lowLatency == 0) {
+ ++mNumLowLatencyDisables;
+ // This is just an estimate since low latency mode change happens ONLY at key frame
+ mIsLowLatencyModeOn = false;
+ }
}
}
@@ -754,7 +846,7 @@
if (mBatteryChecker != nullptr) {
mBatteryChecker->onCodecActivity([this] () {
- addResource(MediaResource::kBattery, MediaResource::kVideoCodec, 1);
+ mResourceManagerProxy->addResource(MediaResource::VideoBatteryResource());
});
}
@@ -769,6 +861,11 @@
// XXX: we *could* make sure that the time is later than the end of queue
// as part of a consistency check...
mBuffersInFlight.push_back(startdata);
+
+ if (mIsLowLatencyModeOn && mIndexOfFirstFrameWhenLowLatencyOn < 0) {
+ mIndexOfFirstFrameWhenLowLatencyOn = mInputBufferCounter;
+ }
+ ++mInputBufferCounter;
}
}
@@ -794,7 +891,7 @@
if (mBatteryChecker != nullptr) {
mBatteryChecker->onCodecActivity([this] () {
- addResource(MediaResource::kBattery, MediaResource::kVideoCodec, 1);
+ mResourceManagerProxy->addResource(MediaResource::VideoBatteryResource());
});
}
@@ -878,7 +975,7 @@
}
static CodecBase *CreateCCodec() {
- return StagefrightPluginLoader::GetCCodecInstance()->createCodec();
+ return new CCodec;
}
//static
@@ -903,8 +1000,30 @@
}
}
+struct CodecListCache {
+ CodecListCache()
+ : mCodecInfoMap{[] {
+ const sp<IMediaCodecList> mcl = MediaCodecList::getInstance();
+ size_t count = mcl->countCodecs();
+ std::map<std::string, sp<MediaCodecInfo>> codecInfoMap;
+ for (size_t i = 0; i < count; ++i) {
+ sp<MediaCodecInfo> info = mcl->getCodecInfo(i);
+ codecInfoMap.emplace(info->getCodecName(), info);
+ }
+ return codecInfoMap;
+ }()} {
+ }
+
+ const std::map<std::string, sp<MediaCodecInfo>> mCodecInfoMap;
+};
+
+static const CodecListCache &GetCodecListCache() {
+ static CodecListCache sCache{};
+ return sCache;
+}
+
status_t MediaCodec::init(const AString &name) {
- mResourceManagerService->init();
+ mResourceManagerProxy->init();
// save init parameters for reset
mInitName = name;
@@ -917,37 +1036,41 @@
mCodecInfo.clear();
bool secureCodec = false;
- AString tmp = name;
- if (tmp.endsWith(".secure")) {
- secureCodec = true;
- tmp.erase(tmp.size() - 7, 7);
- }
- const sp<IMediaCodecList> mcl = MediaCodecList::getInstance();
- if (mcl == NULL) {
- mCodec = NULL; // remove the codec.
- return NO_INIT; // if called from Java should raise IOException
- }
- for (const AString &codecName : { name, tmp }) {
- ssize_t codecIdx = mcl->findCodecByName(codecName.c_str());
- if (codecIdx < 0) {
- continue;
+ const char *owner = "";
+ if (!name.startsWith("android.filter.")) {
+ AString tmp = name;
+ if (tmp.endsWith(".secure")) {
+ secureCodec = true;
+ tmp.erase(tmp.size() - 7, 7);
}
- mCodecInfo = mcl->getCodecInfo(codecIdx);
- Vector<AString> mediaTypes;
- mCodecInfo->getSupportedMediaTypes(&mediaTypes);
- for (size_t i = 0; i < mediaTypes.size(); i++) {
- if (mediaTypes[i].startsWith("video/")) {
- mIsVideo = true;
- break;
+ const sp<IMediaCodecList> mcl = MediaCodecList::getInstance();
+ if (mcl == NULL) {
+ mCodec = NULL; // remove the codec.
+ return NO_INIT; // if called from Java should raise IOException
+ }
+ for (const AString &codecName : { name, tmp }) {
+ ssize_t codecIdx = mcl->findCodecByName(codecName.c_str());
+ if (codecIdx < 0) {
+ continue;
}
+ mCodecInfo = mcl->getCodecInfo(codecIdx);
+ Vector<AString> mediaTypes;
+ mCodecInfo->getSupportedMediaTypes(&mediaTypes);
+ for (size_t i = 0; i < mediaTypes.size(); i++) {
+ if (mediaTypes[i].startsWith("video/")) {
+ mIsVideo = true;
+ break;
+ }
+ }
+ break;
}
- break;
- }
- if (mCodecInfo == nullptr) {
- return NAME_NOT_FOUND;
+ if (mCodecInfo == nullptr) {
+ return NAME_NOT_FOUND;
+ }
+ owner = mCodecInfo->getOwnerName();
}
- mCodec = GetCodecBase(name, mCodecInfo->getOwnerName());
+ mCodec = GetCodecBase(name, owner);
if (mCodec == NULL) {
return NAME_NOT_FOUND;
}
@@ -976,14 +1099,17 @@
new BufferCallback(new AMessage(kWhatCodecNotify, this))));
sp<AMessage> msg = new AMessage(kWhatInit, this);
- msg->setObject("codecInfo", mCodecInfo);
- // name may be different from mCodecInfo->getCodecName() if we stripped
- // ".secure"
+ if (mCodecInfo) {
+ msg->setObject("codecInfo", mCodecInfo);
+ // name may be different from mCodecInfo->getCodecName() if we stripped
+ // ".secure"
+ }
msg->setString("name", name);
- if (mAnalyticsItem != NULL) {
- mAnalyticsItem->setCString(kCodecCodec, name.c_str());
- mAnalyticsItem->setCString(kCodecMode, mIsVideo ? kCodecModeVideo : kCodecModeAudio);
+ if (mMetricsHandle != 0) {
+ mediametrics_setCString(mMetricsHandle, kCodecCodec, name.c_str());
+ mediametrics_setCString(mMetricsHandle, kCodecMode,
+ mIsVideo ? kCodecModeVideo : kCodecModeAudio);
}
if (mIsVideo) {
@@ -991,16 +1117,12 @@
}
status_t err;
- Vector<MediaResource> resources;
- MediaResource::Type type =
- secureCodec ? MediaResource::kSecureCodec : MediaResource::kNonSecureCodec;
- MediaResource::SubType subtype =
- mIsVideo ? MediaResource::kVideoCodec : MediaResource::kAudioCodec;
- resources.push_back(MediaResource(type, subtype, 1));
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(MediaResource::CodecResource(secureCodec, mIsVideo));
for (int i = 0; i <= kMaxRetry; ++i) {
if (i > 0) {
// Don't try to reclaim resource for the first time.
- if (!mResourceManagerService->reclaimResource(resources)) {
+ if (!mResourceManagerProxy->reclaimResource(resources)) {
break;
}
}
@@ -1044,16 +1166,17 @@
uint32_t flags) {
sp<AMessage> msg = new AMessage(kWhatConfigure, this);
- if (mAnalyticsItem != NULL) {
+ if (mMetricsHandle != 0) {
int32_t profile = 0;
if (format->findInt32("profile", &profile)) {
- mAnalyticsItem->setInt32(kCodecProfile, profile);
+ mediametrics_setInt32(mMetricsHandle, kCodecProfile, profile);
}
int32_t level = 0;
if (format->findInt32("level", &level)) {
- mAnalyticsItem->setInt32(kCodecLevel, level);
+ mediametrics_setInt32(mMetricsHandle, kCodecLevel, level);
}
- mAnalyticsItem->setInt32(kCodecEncoder, (flags & CONFIGURE_FLAG_ENCODE) ? 1 : 0);
+ mediametrics_setInt32(mMetricsHandle, kCodecEncoder,
+ (flags & CONFIGURE_FLAG_ENCODE) ? 1 : 0);
}
if (mIsVideo) {
@@ -1063,17 +1186,17 @@
mRotationDegrees = 0;
}
- if (mAnalyticsItem != NULL) {
- mAnalyticsItem->setInt32(kCodecWidth, mVideoWidth);
- mAnalyticsItem->setInt32(kCodecHeight, mVideoHeight);
- mAnalyticsItem->setInt32(kCodecRotation, mRotationDegrees);
+ if (mMetricsHandle != 0) {
+ mediametrics_setInt32(mMetricsHandle, kCodecWidth, mVideoWidth);
+ mediametrics_setInt32(mMetricsHandle, kCodecHeight, mVideoHeight);
+ mediametrics_setInt32(mMetricsHandle, kCodecRotation, mRotationDegrees);
int32_t maxWidth = 0;
if (format->findInt32("max-width", &maxWidth)) {
- mAnalyticsItem->setInt32(kCodecMaxWidth, maxWidth);
+ mediametrics_setInt32(mMetricsHandle, kCodecMaxWidth, maxWidth);
}
int32_t maxHeight = 0;
if (format->findInt32("max-height", &maxHeight)) {
- mAnalyticsItem->setInt32(kCodecMaxHeight, maxHeight);
+ mediametrics_setInt32(mMetricsHandle, kCodecMaxHeight, maxHeight);
}
}
@@ -1085,6 +1208,8 @@
}
}
+ updateLowLatency(format);
+
msg->setMessage("format", format);
msg->setInt32("flags", flags);
msg->setObject("surface", surface);
@@ -1095,8 +1220,8 @@
} else {
msg->setPointer("descrambler", descrambler.get());
}
- if (mAnalyticsItem != NULL) {
- mAnalyticsItem->setInt32(kCodecCrypto, 1);
+ if (mMetricsHandle != 0) {
+ mediametrics_setInt32(mMetricsHandle, kCodecCrypto, 1);
}
} else if (mFlags & kFlagIsSecure) {
ALOGW("Crypto or descrambler should be given for secure codec");
@@ -1106,19 +1231,15 @@
mConfigureMsg = msg;
status_t err;
- Vector<MediaResource> resources;
- MediaResource::Type type = (mFlags & kFlagIsSecure) ?
- MediaResource::kSecureCodec : MediaResource::kNonSecureCodec;
- MediaResource::SubType subtype =
- mIsVideo ? MediaResource::kVideoCodec : MediaResource::kAudioCodec;
- resources.push_back(MediaResource(type, subtype, 1));
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(MediaResource::CodecResource(mFlags & kFlagIsSecure, mIsVideo));
// Don't know the buffer size at this point, but it's fine to use 1 because
// the reclaimResource call doesn't consider the requester's buffer size for now.
- resources.push_back(MediaResource(MediaResource::kGraphicMemory, 1));
+ resources.push_back(MediaResource::GraphicMemoryResource(1));
for (int i = 0; i <= kMaxRetry; ++i) {
if (i > 0) {
// Don't try to reclaim resource for the first time.
- if (!mResourceManagerService->reclaimResource(resources)) {
+ if (!mResourceManagerProxy->reclaimResource(resources)) {
break;
}
}
@@ -1239,38 +1360,19 @@
return size;
}
-void MediaCodec::addResource(
- MediaResource::Type type, MediaResource::SubType subtype, uint64_t value) {
- Vector<MediaResource> resources;
- resources.push_back(MediaResource(type, subtype, value));
- mResourceManagerService->addResource(
- getId(mResourceManagerClient), mResourceManagerClient, resources);
-}
-
-void MediaCodec::removeResource(
- MediaResource::Type type, MediaResource::SubType subtype, uint64_t value) {
- Vector<MediaResource> resources;
- resources.push_back(MediaResource(type, subtype, value));
- mResourceManagerService->removeResource(getId(mResourceManagerClient), resources);
-}
-
status_t MediaCodec::start() {
sp<AMessage> msg = new AMessage(kWhatStart, this);
status_t err;
- Vector<MediaResource> resources;
- MediaResource::Type type = (mFlags & kFlagIsSecure) ?
- MediaResource::kSecureCodec : MediaResource::kNonSecureCodec;
- MediaResource::SubType subtype =
- mIsVideo ? MediaResource::kVideoCodec : MediaResource::kAudioCodec;
- resources.push_back(MediaResource(type, subtype, 1));
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(MediaResource::CodecResource(mFlags & kFlagIsSecure, mIsVideo));
// Don't know the buffer size at this point, but it's fine to use 1 because
// the reclaimResource call doesn't consider the requester's buffer size for now.
- resources.push_back(MediaResource(MediaResource::kGraphicMemory, 1));
+ resources.push_back(MediaResource::GraphicMemoryResource(1));
for (int i = 0; i <= kMaxRetry; ++i) {
if (i > 0) {
// Don't try to reclaim resource for the first time.
- if (!mResourceManagerService->reclaimResource(resources)) {
+ if (!mResourceManagerProxy->reclaimResource(resources)) {
break;
}
// Recover codec from previous error before retry start.
@@ -1429,6 +1531,75 @@
return err;
}
+status_t MediaCodec::queueBuffer(
+ size_t index,
+ const std::shared_ptr<C2Buffer> &buffer,
+ int64_t presentationTimeUs,
+ uint32_t flags,
+ const sp<AMessage> &tunings,
+ AString *errorDetailMsg) {
+ if (errorDetailMsg != NULL) {
+ errorDetailMsg->clear();
+ }
+
+ sp<AMessage> msg = new AMessage(kWhatQueueInputBuffer, this);
+ msg->setSize("index", index);
+ sp<WrapperObject<std::shared_ptr<C2Buffer>>> obj{
+ new WrapperObject<std::shared_ptr<C2Buffer>>{buffer}};
+ msg->setObject("c2buffer", obj);
+ msg->setInt64("timeUs", presentationTimeUs);
+ msg->setInt32("flags", flags);
+ msg->setMessage("tunings", tunings);
+ msg->setPointer("errorDetailMsg", errorDetailMsg);
+
+ sp<AMessage> response;
+ status_t err = PostAndAwaitResponse(msg, &response);
+
+ return err;
+}
+
+status_t MediaCodec::queueEncryptedBuffer(
+ size_t index,
+ const sp<hardware::HidlMemory> &buffer,
+ size_t offset,
+ const CryptoPlugin::SubSample *subSamples,
+ size_t numSubSamples,
+ const uint8_t key[16],
+ const uint8_t iv[16],
+ CryptoPlugin::Mode mode,
+ const CryptoPlugin::Pattern &pattern,
+ int64_t presentationTimeUs,
+ uint32_t flags,
+ const sp<AMessage> &tunings,
+ AString *errorDetailMsg) {
+ if (errorDetailMsg != NULL) {
+ errorDetailMsg->clear();
+ }
+
+ sp<AMessage> msg = new AMessage(kWhatQueueInputBuffer, this);
+ msg->setSize("index", index);
+ sp<WrapperObject<sp<hardware::HidlMemory>>> memory{
+ new WrapperObject<sp<hardware::HidlMemory>>{buffer}};
+ msg->setObject("memory", memory);
+ msg->setSize("offset", offset);
+ msg->setPointer("subSamples", (void *)subSamples);
+ msg->setSize("numSubSamples", numSubSamples);
+ msg->setPointer("key", (void *)key);
+ msg->setPointer("iv", (void *)iv);
+ msg->setInt32("mode", mode);
+ msg->setInt32("encryptBlocks", pattern.mEncryptBlocks);
+ msg->setInt32("skipBlocks", pattern.mSkipBlocks);
+ msg->setInt64("timeUs", presentationTimeUs);
+ msg->setInt32("flags", flags);
+ msg->setMessage("tunings", tunings);
+ msg->setPointer("errorDetailMsg", errorDetailMsg);
+
+ sp<AMessage> response;
+ status_t err = PostAndAwaitResponse(msg, &response);
+
+ return err;
+}
+
status_t MediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
sp<AMessage> msg = new AMessage(kWhatDequeueInputBuffer, this);
msg->setInt64("timeoutUs", timeoutUs);
@@ -1561,22 +1732,22 @@
return OK;
}
-status_t MediaCodec::getMetrics(MediaAnalyticsItem * &reply) {
+status_t MediaCodec::getMetrics(mediametrics_handle_t &reply) {
- reply = NULL;
+ reply = 0;
// shouldn't happen, but be safe
- if (mAnalyticsItem == NULL) {
+ if (mMetricsHandle == 0) {
return UNKNOWN_ERROR;
}
// update any in-flight data that's not carried within the record
- updateAnalyticsItem();
+ updateMediametrics();
// send it back to the caller.
- reply = mAnalyticsItem->dup();
+ reply = mediametrics_dup(mMetricsHandle);
- updateEphemeralAnalytics(reply);
+ updateEphemeralMediametrics(reply);
return OK;
}
@@ -1708,8 +1879,7 @@
totalPixel = width * height;
}
if (totalPixel >= 1920 * 1080) {
- addResource(MediaResource::kCpuBoost,
- MediaResource::kUnspecifiedSubType, 1);
+ mResourceManagerProxy->addResource(MediaResource::CpuBoostResource());
mCpuBoostRequested = true;
}
}
@@ -1890,10 +2060,11 @@
case CONFIGURING:
{
if (actionCode == ACTION_CODE_FATAL) {
- mAnalyticsItem->setInt32(kCodecError, err);
- mAnalyticsItem->setCString(kCodecErrorState, stateString(mState).c_str());
- flushAnalyticsItem();
- initAnalyticsItem();
+ mediametrics_setInt32(mMetricsHandle, kCodecError, err);
+ mediametrics_setCString(mMetricsHandle, kCodecErrorState,
+ stateString(mState).c_str());
+ flushMediametrics();
+ initMediametrics();
}
setState(actionCode == ACTION_CODE_FATAL ?
UNINITIALIZED : INITIALIZED);
@@ -1903,10 +2074,11 @@
case STARTING:
{
if (actionCode == ACTION_CODE_FATAL) {
- mAnalyticsItem->setInt32(kCodecError, err);
- mAnalyticsItem->setCString(kCodecErrorState, stateString(mState).c_str());
- flushAnalyticsItem();
- initAnalyticsItem();
+ mediametrics_setInt32(mMetricsHandle, kCodecError, err);
+ mediametrics_setCString(mMetricsHandle, kCodecErrorState,
+ stateString(mState).c_str());
+ flushMediametrics();
+ initMediametrics();
}
setState(actionCode == ACTION_CODE_FATAL ?
UNINITIALIZED : CONFIGURED);
@@ -1944,10 +2116,11 @@
case FLUSHING:
{
if (actionCode == ACTION_CODE_FATAL) {
- mAnalyticsItem->setInt32(kCodecError, err);
- mAnalyticsItem->setCString(kCodecErrorState, stateString(mState).c_str());
- flushAnalyticsItem();
- initAnalyticsItem();
+ mediametrics_setInt32(mMetricsHandle, kCodecError, err);
+ mediametrics_setCString(mMetricsHandle, kCodecErrorState,
+ stateString(mState).c_str());
+ flushMediametrics();
+ initMediametrics();
setState(UNINITIALIZED);
} else {
@@ -1977,10 +2150,11 @@
setState(INITIALIZED);
break;
default:
- mAnalyticsItem->setInt32(kCodecError, err);
- mAnalyticsItem->setCString(kCodecErrorState, stateString(mState).c_str());
- flushAnalyticsItem();
- initAnalyticsItem();
+ mediametrics_setInt32(mMetricsHandle, kCodecError, err);
+ mediametrics_setCString(mMetricsHandle, kCodecErrorState,
+ stateString(mState).c_str());
+ flushMediametrics();
+ initMediametrics();
setState(UNINITIALIZED);
break;
}
@@ -2037,32 +2211,31 @@
CHECK(msg->findString("componentName", &mComponentName));
if (mComponentName.c_str()) {
- mAnalyticsItem->setCString(kCodecCodec, mComponentName.c_str());
+ mediametrics_setCString(mMetricsHandle, kCodecCodec,
+ mComponentName.c_str());
}
- const char *owner = mCodecInfo->getOwnerName();
+ const char *owner = mCodecInfo ? mCodecInfo->getOwnerName() : "";
if (mComponentName.startsWith("OMX.google.")
- && (owner == nullptr || strncmp(owner, "default", 8) == 0)) {
+ && strncmp(owner, "default", 8) == 0) {
mFlags |= kFlagUsesSoftwareRenderer;
} else {
mFlags &= ~kFlagUsesSoftwareRenderer;
}
mOwnerName = owner;
- MediaResource::Type resourceType;
if (mComponentName.endsWith(".secure")) {
mFlags |= kFlagIsSecure;
- resourceType = MediaResource::kSecureCodec;
- mAnalyticsItem->setInt32(kCodecSecure, 1);
+ mediametrics_setInt32(mMetricsHandle, kCodecSecure, 1);
} else {
mFlags &= ~kFlagIsSecure;
- resourceType = MediaResource::kNonSecureCodec;
- mAnalyticsItem->setInt32(kCodecSecure, 0);
+ mediametrics_setInt32(mMetricsHandle, kCodecSecure, 0);
}
if (mIsVideo) {
// audio codec is currently ignored.
- addResource(resourceType, MediaResource::kVideoCodec, 1);
+ mResourceManagerProxy->addResource(
+ MediaResource::CodecResource(mFlags & kFlagIsSecure, mIsVideo));
}
(new AMessage)->postReply(mReplyID);
@@ -2105,14 +2278,15 @@
(new AMessage)->postReply(mReplyID);
// augment our media metrics info, now that we know more things
- if (mAnalyticsItem != NULL) {
+ if (mMetricsHandle != 0) {
sp<AMessage> format;
if (mConfigureMsg != NULL &&
mConfigureMsg->findMessage("format", &format)) {
// format includes: mime
AString mime;
if (format->findString("mime", &mime)) {
- mAnalyticsItem->setCString(kCodecMime, mime.c_str());
+ mediametrics_setCString(mMetricsHandle, kCodecMime,
+ mime.c_str());
}
}
}
@@ -2182,10 +2356,8 @@
CHECK_EQ(mState, STARTING);
if (mIsVideo) {
- addResource(
- MediaResource::kGraphicMemory,
- MediaResource::kUnspecifiedSubType,
- getGraphicBufferSize());
+ mResourceManagerProxy->addResource(
+ MediaResource::GraphicMemoryResource(getGraphicBufferSize()));
}
setState(STARTED);
(new AMessage)->postReply(mReplyID);
@@ -2282,6 +2454,23 @@
sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
if (mOutputFormat != buffer->format()) {
+ if (mFlags & kFlagUseBlockModel) {
+ sp<AMessage> diff1 = mOutputFormat->changesFrom(buffer->format());
+ sp<AMessage> diff2 = buffer->format()->changesFrom(mOutputFormat);
+ std::set<std::string> keys;
+ size_t numEntries = diff1->countEntries();
+ AMessage::Type type;
+ for (size_t i = 0; i < numEntries; ++i) {
+ keys.emplace(diff1->getEntryNameAt(i, &type));
+ }
+ numEntries = diff2->countEntries();
+ for (size_t i = 0; i < numEntries; ++i) {
+ keys.emplace(diff2->getEntryNameAt(i, &type));
+ }
+ sp<WrapperObject<std::set<std::string>>> changedKeys{
+ new WrapperObject<std::set<std::string>>{std::move(keys)}};
+ buffer->meta()->setObject("changedKeys", changedKeys);
+ }
mOutputFormat = buffer->format();
ALOGV("[%s] output format changed to: %s",
mComponentName.c_str(), mOutputFormat->debugString(4).c_str());
@@ -2331,7 +2520,7 @@
// format as necessary.
int32_t flags = 0;
(void) buffer->meta()->findInt32("flags", &flags);
- if (flags & BUFFER_FLAG_CODECCONFIG) {
+ if ((flags & BUFFER_FLAG_CODECCONFIG) && !(mFlags & kFlagIsSecure)) {
status_t err =
amendOutputFormatWithCodecSpecificData(buffer);
@@ -2409,7 +2598,7 @@
mBatteryChecker->onClientRemoved();
}
- mResourceManagerService->removeClient(getId(mResourceManagerClient));
+ mResourceManagerProxy->removeClient();
(new AMessage)->postReply(mReplyID);
break;
@@ -2454,12 +2643,14 @@
setState(INITIALIZING);
sp<RefBase> codecInfo;
- CHECK(msg->findObject("codecInfo", &codecInfo));
+ (void)msg->findObject("codecInfo", &codecInfo);
AString name;
CHECK(msg->findString("name", &name));
sp<AMessage> format = new AMessage;
- format->setObject("codecInfo", codecInfo);
+ if (codecInfo) {
+ format->setObject("codecInfo", codecInfo);
+ }
format->setString("componentName", name);
mCodec->initiateAllocateComponent(format);
@@ -2547,6 +2738,15 @@
handleSetSurface(NULL);
}
+ uint32_t flags;
+ CHECK(msg->findInt32("flags", (int32_t *)&flags));
+ if (flags & CONFIGURE_FLAG_USE_BLOCK_MODEL) {
+ if (!(mFlags & kFlagIsAsync)) {
+ PostReplyWithError(replyID, INVALID_OPERATION);
+ break;
+ }
+ mFlags |= kFlagUseBlockModel;
+ }
mReplyID = replyID;
setState(CONFIGURING);
@@ -2572,9 +2772,7 @@
mDescrambler = static_cast<IDescrambler *>(descrambler);
mBufferChannel->setDescrambler(mDescrambler);
- uint32_t flags;
- CHECK(msg->findInt32("flags", (int32_t *)&flags));
-
+ format->setInt32("flags", flags);
if (flags & CONFIGURE_FLAG_ENCODE) {
format->setInt32("encoder", true);
mFlags |= kFlagIsEncoder;
@@ -3124,7 +3322,8 @@
{
if (mBatteryChecker != nullptr) {
mBatteryChecker->onCheckBatteryTimer(msg, [this] () {
- removeResource(MediaResource::kBattery, MediaResource::kVideoCodec, 1);
+ mResourceManagerProxy->removeResource(
+ MediaResource::VideoBatteryResource());
});
}
break;
@@ -3158,22 +3357,36 @@
status_t MediaCodec::queueCSDInputBuffer(size_t bufferIndex) {
CHECK(!mCSD.empty());
- const BufferInfo &info = mPortBuffers[kPortIndexInput][bufferIndex];
-
sp<ABuffer> csd = *mCSD.begin();
mCSD.erase(mCSD.begin());
+ std::shared_ptr<C2Buffer> c2Buffer;
- const sp<MediaCodecBuffer> &codecInputData = info.mData;
+ if ((mFlags & kFlagUseBlockModel) && mOwnerName.startsWith("codec2::")) {
+ std::shared_ptr<C2LinearBlock> block =
+ FetchLinearBlock(csd->size(), {std::string{mComponentName.c_str()}});
+ C2WriteView view{block->map().get()};
+ if (view.error() != C2_OK) {
+ return -EINVAL;
+ }
+ if (csd->size() > view.capacity()) {
+ return -EINVAL;
+ }
+ memcpy(view.base(), csd->data(), csd->size());
+ c2Buffer = C2Buffer::CreateLinearBuffer(block->share(0, csd->size(), C2Fence{}));
+ } else {
+ const BufferInfo &info = mPortBuffers[kPortIndexInput][bufferIndex];
+ const sp<MediaCodecBuffer> &codecInputData = info.mData;
- if (csd->size() > codecInputData->capacity()) {
- return -EINVAL;
+ if (csd->size() > codecInputData->capacity()) {
+ return -EINVAL;
+ }
+ if (codecInputData->data() == NULL) {
+ ALOGV("Input buffer %zu is not properly allocated", bufferIndex);
+ return -EINVAL;
+ }
+
+ memcpy(codecInputData->data(), csd->data(), csd->size());
}
- if (codecInputData->data() == NULL) {
- ALOGV("Input buffer %zu is not properly allocated", bufferIndex);
- return -EINVAL;
- }
-
- memcpy(codecInputData->data(), csd->data(), csd->size());
AString errorDetailMsg;
@@ -3184,6 +3397,12 @@
msg->setInt64("timeUs", 0LL);
msg->setInt32("flags", BUFFER_FLAG_CODECCONFIG);
msg->setPointer("errorDetailMsg", &errorDetailMsg);
+ if (c2Buffer) {
+ sp<WrapperObject<std::shared_ptr<C2Buffer>>> obj{
+ new WrapperObject<std::shared_ptr<C2Buffer>>{c2Buffer}};
+ msg->setObject("c2buffer", obj);
+ msg->setMessage("tunings", new AMessage);
+ }
return onQueueInputBuffer(msg);
}
@@ -3289,10 +3508,20 @@
int64_t timeUs;
uint32_t flags;
CHECK(msg->findSize("index", &index));
- CHECK(msg->findSize("offset", &offset));
CHECK(msg->findInt64("timeUs", &timeUs));
CHECK(msg->findInt32("flags", (int32_t *)&flags));
-
+ std::shared_ptr<C2Buffer> c2Buffer;
+ sp<hardware::HidlMemory> memory;
+ sp<RefBase> obj;
+ if (msg->findObject("c2buffer", &obj)) {
+ CHECK(obj);
+ c2Buffer = static_cast<WrapperObject<std::shared_ptr<C2Buffer>> *>(obj.get())->value;
+ } else if (msg->findObject("memory", &obj)) {
+ CHECK(obj);
+ memory = static_cast<WrapperObject<sp<hardware::HidlMemory>> *>(obj.get())->value;
+ } else {
+ CHECK(msg->findSize("offset", &offset));
+ }
const CryptoPlugin::SubSample *subSamples;
size_t numSubSamples;
const uint8_t *key;
@@ -3316,7 +3545,7 @@
pattern.mEncryptBlocks = 0;
pattern.mSkipBlocks = 0;
}
- } else {
+ } else if (!c2Buffer) {
if (!hasCryptoOrDescrambler()) {
ALOGE("[%s] queuing secure buffer without mCrypto or mDescrambler!",
mComponentName.c_str());
@@ -3347,26 +3576,46 @@
}
BufferInfo *info = &mPortBuffers[kPortIndexInput][index];
+ sp<MediaCodecBuffer> buffer = info->mData;
- if (info->mData == nullptr || !info->mOwnedByClient) {
+ if (c2Buffer || memory) {
+ sp<AMessage> tunings;
+ CHECK(msg->findMessage("tunings", &tunings));
+ onSetParameters(tunings);
+
+ status_t err = OK;
+ if (c2Buffer) {
+ err = mBufferChannel->attachBuffer(c2Buffer, buffer);
+ } else if (memory) {
+ err = mBufferChannel->attachEncryptedBuffer(
+ memory, (mFlags & kFlagIsSecure), key, iv, mode, pattern,
+ offset, subSamples, numSubSamples, buffer);
+ }
+ offset = buffer->offset();
+ size = buffer->size();
+ if (err != OK) {
+ return err;
+ }
+ }
+
+ if (buffer == nullptr || !info->mOwnedByClient) {
return -EACCES;
}
- if (offset + size > info->mData->capacity()) {
+ if (offset + size > buffer->capacity()) {
return -EINVAL;
}
- info->mData->setRange(offset, size);
- info->mData->meta()->setInt64("timeUs", timeUs);
+ buffer->setRange(offset, size);
+ buffer->meta()->setInt64("timeUs", timeUs);
if (flags & BUFFER_FLAG_EOS) {
- info->mData->meta()->setInt32("eos", true);
+ buffer->meta()->setInt32("eos", true);
}
if (flags & BUFFER_FLAG_CODECCONFIG) {
- info->mData->meta()->setInt32("csd", true);
+ buffer->meta()->setInt32("csd", true);
}
- sp<MediaCodecBuffer> buffer = info->mData;
status_t err = OK;
if (hasCryptoOrDescrambler()) {
AString *errorDetailMsg;
@@ -3382,8 +3631,16 @@
subSamples,
numSubSamples,
errorDetailMsg);
+ if (err != OK) {
+ mediametrics_setInt32(mMetricsHandle, kCodecQueueSecureInputBufferError, err);
+ ALOGW("Log queueSecureInputBuffer error: %d", err);
+ }
} else {
err = mBufferChannel->queueInputBuffer(buffer);
+ if (err != OK) {
+ mediametrics_setInt32(mMetricsHandle, kCodecQueueInputBufferError, err);
+ ALOGW("Log queueInputBuffer error: %d", err);
+ }
}
if (err == OK) {
@@ -3685,6 +3942,7 @@
}
status_t MediaCodec::onSetParameters(const sp<AMessage> ¶ms) {
+ updateLowLatency(params);
mCodec->signalSetParameters(params);
return OK;
@@ -3758,4 +4016,70 @@
return rval;
}
+// static
+status_t MediaCodec::CanFetchLinearBlock(
+ const std::vector<std::string> &names, bool *isCompatible) {
+ *isCompatible = false;
+ if (names.size() == 0) {
+ *isCompatible = true;
+ return OK;
+ }
+ const CodecListCache &cache = GetCodecListCache();
+ for (const std::string &name : names) {
+ auto it = cache.mCodecInfoMap.find(name);
+ if (it == cache.mCodecInfoMap.end()) {
+ return NAME_NOT_FOUND;
+ }
+ const char *owner = it->second->getOwnerName();
+ if (owner == nullptr || strncmp(owner, "default", 8) == 0) {
+ *isCompatible = false;
+ return OK;
+ } else if (strncmp(owner, "codec2::", 8) != 0) {
+ return NAME_NOT_FOUND;
+ }
+ }
+ return CCodec::CanFetchLinearBlock(names, kDefaultReadWriteUsage, isCompatible);
+}
+
+// static
+std::shared_ptr<C2LinearBlock> MediaCodec::FetchLinearBlock(
+ size_t capacity, const std::vector<std::string> &names) {
+ return CCodec::FetchLinearBlock(capacity, kDefaultReadWriteUsage, names);
+}
+
+// static
+status_t MediaCodec::CanFetchGraphicBlock(
+ const std::vector<std::string> &names, bool *isCompatible) {
+ *isCompatible = false;
+ if (names.size() == 0) {
+ *isCompatible = true;
+ return OK;
+ }
+ const CodecListCache &cache = GetCodecListCache();
+ for (const std::string &name : names) {
+ auto it = cache.mCodecInfoMap.find(name);
+ if (it == cache.mCodecInfoMap.end()) {
+ return NAME_NOT_FOUND;
+ }
+ const char *owner = it->second->getOwnerName();
+ if (owner == nullptr || strncmp(owner, "default", 8) == 0) {
+ *isCompatible = false;
+ return OK;
+ } else if (strncmp(owner, "codec2.", 7) != 0) {
+ return NAME_NOT_FOUND;
+ }
+ }
+ return CCodec::CanFetchGraphicBlock(names, isCompatible);
+}
+
+// static
+std::shared_ptr<C2GraphicBlock> MediaCodec::FetchGraphicBlock(
+ int32_t width,
+ int32_t height,
+ int32_t format,
+ uint64_t usage,
+ const std::vector<std::string> &names) {
+ return CCodec::FetchGraphicBlock(width, height, format, usage, names);
+}
+
} // namespace android
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index 3d58d4b..ac54fa1 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -19,7 +19,6 @@
#include <utils/Log.h>
#include "MediaCodecListOverrides.h"
-#include "StagefrightPluginLoader.h"
#include <binder/IServiceManager.h>
@@ -30,11 +29,14 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/MediaDefs.h>
+#include <media/stagefright/omx/OMXUtils.h>
+#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
+#include <media/stagefright/CCodec.h>
+#include <media/stagefright/Codec2InfoBuilder.h>
#include <media/stagefright/MediaCodecList.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/OmxInfoBuilder.h>
-#include <media/stagefright/omx/OMXUtils.h>
-#include <xmlparser/include/media/stagefright/xmlparser/MediaCodecsXmlParser.h>
+#include <media/stagefright/PersistentSurface.h>
#include <sys/stat.h>
#include <utils/threads.h>
@@ -86,8 +88,7 @@
MediaCodecListBuilderBase *GetCodec2InfoBuilder() {
Mutex::Autolock _l(sCodec2InfoBuilderMutex);
if (!sCodec2InfoBuilder) {
- sCodec2InfoBuilder.reset(
- StagefrightPluginLoader::GetCCodecInstance()->createBuilder());
+ sCodec2InfoBuilder.reset(new Codec2InfoBuilder);
}
return sCodec2InfoBuilder.get();
}
@@ -96,8 +97,7 @@
std::vector<MediaCodecListBuilderBase *> builders;
// if plugin provides the input surface, we cannot use OMX video encoders.
// In this case, rely on plugin to provide list of OMX codecs that are usable.
- sp<PersistentSurface> surfaceTest =
- StagefrightPluginLoader::GetCCodecInstance()->createInputSurface();
+ sp<PersistentSurface> surfaceTest = CCodec::CreateInputSurface();
if (surfaceTest == nullptr) {
ALOGD("Allowing all OMX codecs");
builders.push_back(&sOmxInfoBuilder);
@@ -170,6 +170,7 @@
sp<IMediaCodecList> MediaCodecList::sRemoteList;
sp<MediaCodecList::BinderDeathObserver> MediaCodecList::sBinderDeathObserver;
+sp<IBinder> MediaCodecList::sMediaPlayer; // kept since linked to death
void MediaCodecList::BinderDeathObserver::binderDied(const wp<IBinder> &who __unused) {
Mutex::Autolock _l(sRemoteInitMutex);
@@ -181,15 +182,14 @@
sp<IMediaCodecList> MediaCodecList::getInstance() {
Mutex::Autolock _l(sRemoteInitMutex);
if (sRemoteList == nullptr) {
- sp<IBinder> binder =
- defaultServiceManager()->getService(String16("media.player"));
+ sMediaPlayer = defaultServiceManager()->getService(String16("media.player"));
sp<IMediaPlayerService> service =
- interface_cast<IMediaPlayerService>(binder);
+ interface_cast<IMediaPlayerService>(sMediaPlayer);
if (service.get() != nullptr) {
sRemoteList = service->getCodecList();
if (sRemoteList != nullptr) {
sBinderDeathObserver = new BinderDeathObserver();
- binder->linkToDeath(sBinderDeathObserver.get());
+ sMediaPlayer->linkToDeath(sBinderDeathObserver.get());
}
}
if (sRemoteList == nullptr) {
diff --git a/media/libstagefright/MediaCodecListOverrides.cpp b/media/libstagefright/MediaCodecListOverrides.cpp
index dd7c3e6..4a167d1 100644
--- a/media/libstagefright/MediaCodecListOverrides.cpp
+++ b/media/libstagefright/MediaCodecListOverrides.cpp
@@ -22,7 +22,7 @@
#include <cutils/properties.h>
#include <gui/Surface.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/IMediaCodecList.h>
#include <media/MediaCodecInfo.h>
#include <media/MediaResourcePolicy.h>
@@ -264,7 +264,9 @@
}
}
}
- global_results->add(kPolicySupportsMultipleSecureCodecs, supportMultipleSecureCodecs);
+ global_results->add(
+ MediaResourcePolicy::kPolicySupportsMultipleSecureCodecs(),
+ supportMultipleSecureCodecs);
}
static AString globalResultsToXml(const CodecSettings &results) {
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index 50e454c..7fec072 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -22,10 +22,10 @@
#include <gui/IGraphicBufferProducer.h>
#include <gui/Surface.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/MediaBufferHolder.h>
#include <media/MediaCodecBuffer.h>
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
diff --git a/media/libstagefright/MediaExtractorFactory.cpp b/media/libstagefright/MediaExtractorFactory.cpp
index 4c8be1f..94267a1 100644
--- a/media/libstagefright/MediaExtractorFactory.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -27,8 +27,8 @@
#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MediaExtractorFactory.h>
-#include <media/IMediaExtractor.h>
-#include <media/IMediaExtractorService.h>
+#include <android/IMediaExtractor.h>
+#include <android/IMediaExtractorService.h>
#include <nativeloader/dlext_namespaces.h>
#include <private/android_filesystem_config.h>
#include <cutils/properties.h>
@@ -54,9 +54,13 @@
sp<IBinder> binder = defaultServiceManager()->getService(String16("media.extractor"));
if (binder != 0) {
- sp<IMediaExtractorService> mediaExService(interface_cast<IMediaExtractorService>(binder));
- sp<IMediaExtractor> ex = mediaExService->makeExtractor(
- CreateIDataSourceFromDataSource(source), mime);
+ sp<IMediaExtractorService> mediaExService(
+ interface_cast<IMediaExtractorService>(binder));
+ sp<IMediaExtractor> ex;
+ mediaExService->makeExtractor(
+ CreateIDataSourceFromDataSource(source),
+ mime ? std::make_unique<std::string>(mime) : nullptr,
+ &ex);
return ex;
} else {
ALOGE("extractor service not running");
@@ -71,9 +75,6 @@
ALOGV("MediaExtractorFactory::CreateFromService %s", mime);
- // initialize source decryption if needed
- source->DrmInitialization(nullptr /* mime */);
-
void *meta = nullptr;
void *creator = NULL;
FreeMetaFunc freeMeta = nullptr;
@@ -265,7 +266,7 @@
return strcmp(first->def.extractor_name, second->def.extractor_name) < 0;
}
-static std::unordered_set<std::string> gSupportedExtensions;
+static std::vector<std::string> gSupportedExtensions;
// static
void MediaExtractorFactory::LoadExtractors() {
@@ -279,7 +280,7 @@
std::shared_ptr<std::list<sp<ExtractorPlugin>>> newList(new std::list<sp<ExtractorPlugin>>());
- android_namespace_t *mediaNs = android_get_exported_namespace("media");
+ android_namespace_t *mediaNs = android_get_exported_namespace("com_android_media");
if (mediaNs != NULL) {
const android_dlextinfo dlextinfo = {
.flags = ANDROID_DLEXT_USE_NAMESPACE,
@@ -311,7 +312,7 @@
if (ext == nullptr) {
break;
}
- gSupportedExtensions.insert(std::string(ext));
+ gSupportedExtensions.push_back(std::string(ext));
}
}
}
@@ -320,7 +321,7 @@
}
// static
-std::unordered_set<std::string> MediaExtractorFactory::getSupportedTypes() {
+std::vector<std::string> MediaExtractorFactory::getSupportedTypes() {
if (getuid() == AID_MEDIA_EX) {
return gSupportedExtensions;
}
@@ -329,9 +330,11 @@
if (binder != 0) {
sp<IMediaExtractorService> mediaExService(interface_cast<IMediaExtractorService>(binder));
- return mediaExService->getSupportedTypes();
+ std::vector<std::string> supportedTypes;
+ mediaExService->getSupportedTypes(&supportedTypes);
+ return supportedTypes;
}
- return std::unordered_set<std::string>();
+ return std::vector<std::string>();
}
status_t MediaExtractorFactory::dump(int fd, const Vector<String16>&) {
diff --git a/media/libstagefright/MediaMuxer.cpp b/media/libstagefright/MediaMuxer.cpp
index 7ebdb1a..1cb45ac 100644
--- a/media/libstagefright/MediaMuxer.cpp
+++ b/media/libstagefright/MediaMuxer.cpp
@@ -24,7 +24,7 @@
#include <media/stagefright/MediaMuxer.h>
#include <media/mediarecorder.h>
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
@@ -48,7 +48,8 @@
MediaMuxer::MediaMuxer(int fd, OutputFormat format)
: mFormat(format),
- mState(UNINITIALIZED) {
+ mState(UNINITIALIZED),
+ mError(OK) {
if (isMp4Format(format)) {
mWriter = new MPEG4Writer(fd);
} else if (format == OUTPUT_FORMAT_WEBM) {
@@ -58,6 +59,7 @@
}
if (mWriter != NULL) {
+ mWriter->setMuxerListener(this);
mFileMeta = new MetaData;
if (format == OUTPUT_FORMAT_HEIF) {
// Note that the key uses recorder file types.
@@ -155,15 +157,25 @@
status_t MediaMuxer::stop() {
Mutex::Autolock autoLock(mMuxerLock);
-
- if (mState == STARTED) {
+ if (mState == STARTED || mState == ERROR) {
mState = STOPPED;
for (size_t i = 0; i < mTrackList.size(); i++) {
if (mTrackList[i]->stop() != OK) {
return INVALID_OPERATION;
}
}
- return mWriter->stop();
+ // Unlock this mutex to allow notify to be called during stop process.
+ mMuxerLock.unlock();
+ status_t err = mWriter->stop();
+ mMuxerLock.lock();
+ if (err != OK || mError != OK) {
+ ALOGE("stop err: %d, mError:%d", err, mError);
+ }
+ // Prioritize mError over err.
+ if (mError != OK) {
+ err = mError;
+ }
+ return err;
} else {
ALOGE("stop() is called in invalid state %d", mState);
return INVALID_OPERATION;
@@ -207,9 +219,39 @@
sampleMetaData.setInt32(kKeyIsMuxerData, 1);
}
+ if (flags & MediaCodec::BUFFER_FLAG_EOS) {
+ sampleMetaData.setInt32(kKeyIsEndOfStream, 1);
+ ALOGV("BUFFER_FLAG_EOS");
+ }
+
sp<MediaAdapter> currentTrack = mTrackList[trackIndex];
// This pushBuffer will wait until the mediaBuffer is consumed.
return currentTrack->pushBuffer(mediaBuffer);
}
+void MediaMuxer::notify(int msg, int ext1, int ext2) {
+ switch (msg) {
+ case MEDIA_RECORDER_EVENT_ERROR:
+ case MEDIA_RECORDER_TRACK_EVENT_ERROR: {
+ Mutex::Autolock autoLock(mMuxerLock);
+ mState = ERROR;
+ mError = ext2;
+ ALOGW("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
+ break;
+ }
+ case MEDIA_RECORDER_EVENT_INFO: {
+ if (ext1 == MEDIA_RECORDER_INFO_UNKNOWN) {
+ Mutex::Autolock autoLock(mMuxerLock);
+ mState = ERROR;
+ mError = ext2;
+ ALOGW("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
+ }
+ break;
+ }
+ default:
+ // Ignore INFO and other notifications for now.
+ break;
+ }
+}
+
} // namespace android
diff --git a/media/libstagefright/MediaSource.cpp b/media/libstagefright/MediaSource.cpp
index 5bbd3d8..ee0031f 100644
--- a/media/libstagefright/MediaSource.cpp
+++ b/media/libstagefright/MediaSource.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/IMediaSource.h>
namespace android {
diff --git a/media/libstagefright/MediaTrack.cpp b/media/libstagefright/MediaTrack.cpp
index 89c9b25..24ba38a 100644
--- a/media/libstagefright/MediaTrack.cpp
+++ b/media/libstagefright/MediaTrack.cpp
@@ -183,6 +183,11 @@
meta.setData(kKeyAudioPresentationInfo,
MetaDataBase::Type::TYPE_NONE, valbuf->data(), valbuf->size());
}
+ if (format->mFormat->findBuffer("csd-0", &valbuf)) {
+ meta.setData(kKeyOpaqueCSD0,
+ MetaDataBase::Type::TYPE_NONE, valbuf->data(), valbuf->size());
+ }
+
} else {
*buffer = nullptr;
}
diff --git a/media/libstagefright/MetaDataUtils.cpp b/media/libstagefright/MetaDataUtils.cpp
index 3f0bc7d..db60f04 100644
--- a/media/libstagefright/MetaDataUtils.cpp
+++ b/media/libstagefright/MetaDataUtils.cpp
@@ -25,7 +25,6 @@
#include <media/stagefright/foundation/ByteUtils.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaDataUtils.h>
-#include <media/stagefright/Utils.h>
#include <media/NdkMediaFormat.h>
namespace android {
diff --git a/media/libstagefright/NdkUtils.cpp b/media/libstagefright/NdkUtils.cpp
deleted file mode 100644
index 904fe72..0000000
--- a/media/libstagefright/NdkUtils.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-
-#include <media/stagefright/NdkUtils.h>
-#include <media/stagefright/Utils.h>
-#include <media/stagefright/foundation/AMessage.h>
-
-namespace android {
-
-sp<MetaData> convertMediaFormatWrapperToMetaData(const sp<AMediaFormatWrapper> &fmt) {
- sp<AMessage> msg = fmt->toAMessage();
- sp<MetaData> meta = new MetaData;
- convertMessageToMetaData(msg, meta);
- return meta;
-}
-
-} // namespace android
-
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
deleted file mode 100644
index 522c81d..0000000
--- a/media/libstagefright/NuCachedSource2.cpp
+++ /dev/null
@@ -1,784 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <inttypes.h>
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NuCachedSource2"
-#include <utils/Log.h>
-
-#include "include/NuCachedSource2.h"
-#include "include/HTTPBase.h"
-
-#include <cutils/properties.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaErrors.h>
-
-namespace android {
-
-struct PageCache {
- explicit PageCache(size_t pageSize);
- ~PageCache();
-
- struct Page {
- void *mData;
- size_t mSize;
- };
-
- Page *acquirePage();
- void releasePage(Page *page);
-
- void appendPage(Page *page);
- size_t releaseFromStart(size_t maxBytes);
-
- size_t totalSize() const {
- return mTotalSize;
- }
-
- void copy(size_t from, void *data, size_t size);
-
-private:
- size_t mPageSize;
- size_t mTotalSize;
-
- List<Page *> mActivePages;
- List<Page *> mFreePages;
-
- void freePages(List<Page *> *list);
-
- DISALLOW_EVIL_CONSTRUCTORS(PageCache);
-};
-
-PageCache::PageCache(size_t pageSize)
- : mPageSize(pageSize),
- mTotalSize(0) {
-}
-
-PageCache::~PageCache() {
- freePages(&mActivePages);
- freePages(&mFreePages);
-}
-
-void PageCache::freePages(List<Page *> *list) {
- List<Page *>::iterator it = list->begin();
- while (it != list->end()) {
- Page *page = *it;
-
- free(page->mData);
- delete page;
- page = NULL;
-
- ++it;
- }
-}
-
-PageCache::Page *PageCache::acquirePage() {
- if (!mFreePages.empty()) {
- List<Page *>::iterator it = mFreePages.begin();
- Page *page = *it;
- mFreePages.erase(it);
-
- return page;
- }
-
- Page *page = new Page;
- page->mData = malloc(mPageSize);
- page->mSize = 0;
-
- return page;
-}
-
-void PageCache::releasePage(Page *page) {
- page->mSize = 0;
- mFreePages.push_back(page);
-}
-
-void PageCache::appendPage(Page *page) {
- mTotalSize += page->mSize;
- mActivePages.push_back(page);
-}
-
-size_t PageCache::releaseFromStart(size_t maxBytes) {
- size_t bytesReleased = 0;
-
- while (maxBytes > 0 && !mActivePages.empty()) {
- List<Page *>::iterator it = mActivePages.begin();
-
- Page *page = *it;
-
- if (maxBytes < page->mSize) {
- break;
- }
-
- mActivePages.erase(it);
-
- maxBytes -= page->mSize;
- bytesReleased += page->mSize;
-
- releasePage(page);
- }
-
- mTotalSize -= bytesReleased;
- return bytesReleased;
-}
-
-void PageCache::copy(size_t from, void *data, size_t size) {
- ALOGV("copy from %zu size %zu", from, size);
-
- if (size == 0) {
- return;
- }
-
- CHECK_LE(from + size, mTotalSize);
-
- size_t offset = 0;
- List<Page *>::iterator it = mActivePages.begin();
- while (from >= offset + (*it)->mSize) {
- offset += (*it)->mSize;
- ++it;
- }
-
- size_t delta = from - offset;
- size_t avail = (*it)->mSize - delta;
-
- if (avail >= size) {
- memcpy(data, (const uint8_t *)(*it)->mData + delta, size);
- return;
- }
-
- memcpy(data, (const uint8_t *)(*it)->mData + delta, avail);
- ++it;
- data = (uint8_t *)data + avail;
- size -= avail;
-
- while (size > 0) {
- size_t copy = (*it)->mSize;
- if (copy > size) {
- copy = size;
- }
- memcpy(data, (*it)->mData, copy);
- data = (uint8_t *)data + copy;
- size -= copy;
- ++it;
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-NuCachedSource2::NuCachedSource2(
- const sp<DataSource> &source,
- const char *cacheConfig,
- bool disconnectAtHighwatermark)
- : mSource(source),
- mReflector(new AHandlerReflector<NuCachedSource2>(this)),
- mLooper(new ALooper),
- mCache(new PageCache(kPageSize)),
- mCacheOffset(0),
- mFinalStatus(OK),
- mLastAccessPos(0),
- mFetching(true),
- mDisconnecting(false),
- mLastFetchTimeUs(-1),
- mNumRetriesLeft(kMaxNumRetries),
- mHighwaterThresholdBytes(kDefaultHighWaterThreshold),
- mLowwaterThresholdBytes(kDefaultLowWaterThreshold),
- mKeepAliveIntervalUs(kDefaultKeepAliveIntervalUs),
- mDisconnectAtHighwatermark(disconnectAtHighwatermark) {
- // We are NOT going to support disconnect-at-highwatermark indefinitely
- // and we are not guaranteeing support for client-specified cache
- // parameters. Both of these are temporary measures to solve a specific
- // problem that will be solved in a better way going forward.
-
- updateCacheParamsFromSystemProperty();
-
- if (cacheConfig != NULL) {
- updateCacheParamsFromString(cacheConfig);
- }
-
- if (mDisconnectAtHighwatermark) {
- // Makes no sense to disconnect and do keep-alives...
- mKeepAliveIntervalUs = 0;
- }
-
- mLooper->setName("NuCachedSource2");
- mLooper->registerHandler(mReflector);
-
- // Since it may not be obvious why our looper thread needs to be
- // able to call into java since it doesn't appear to do so at all...
- // IMediaHTTPConnection may be (and most likely is) implemented in JAVA
- // and a local JAVA IBinder will call directly into JNI methods.
- // So whenever we call DataSource::readAt it may end up in a call to
- // IMediaHTTPConnection::readAt and therefore call back into JAVA.
- mLooper->start(false /* runOnCallingThread */, true /* canCallJava */);
-
- mName = String8::format("NuCachedSource2(%s)", mSource->toString().string());
-}
-
-NuCachedSource2::~NuCachedSource2() {
- mLooper->stop();
- mLooper->unregisterHandler(mReflector->id());
-
- delete mCache;
- mCache = NULL;
-}
-
-// static
-sp<NuCachedSource2> NuCachedSource2::Create(
- const sp<DataSource> &source,
- const char *cacheConfig,
- bool disconnectAtHighwatermark) {
- sp<NuCachedSource2> instance = new NuCachedSource2(
- source, cacheConfig, disconnectAtHighwatermark);
- Mutex::Autolock autoLock(instance->mLock);
- (new AMessage(kWhatFetchMore, instance->mReflector))->post();
- return instance;
-}
-
-status_t NuCachedSource2::getEstimatedBandwidthKbps(int32_t *kbps) {
- if (mSource->flags() & kIsHTTPBasedSource) {
- HTTPBase* source = static_cast<HTTPBase *>(mSource.get());
- return source->getEstimatedBandwidthKbps(kbps);
- }
- return ERROR_UNSUPPORTED;
-}
-
-void NuCachedSource2::close() {
- disconnect();
-}
-
-void NuCachedSource2::disconnect() {
- if (mSource->flags() & kIsHTTPBasedSource) {
- ALOGV("disconnecting HTTPBasedSource");
-
- {
- Mutex::Autolock autoLock(mLock);
- // set mDisconnecting to true, if a fetch returns after
- // this, the source will be marked as EOS.
- mDisconnecting = true;
-
- // explicitly signal mCondition so that the pending readAt()
- // will immediately return
- mCondition.signal();
- }
-
- // explicitly disconnect from the source, to allow any
- // pending reads to return more promptly
- static_cast<HTTPBase *>(mSource.get())->disconnect();
- }
-}
-
-status_t NuCachedSource2::setCacheStatCollectFreq(int32_t freqMs) {
- if (mSource->flags() & kIsHTTPBasedSource) {
- HTTPBase *source = static_cast<HTTPBase *>(mSource.get());
- return source->setBandwidthStatCollectFreq(freqMs);
- }
- return ERROR_UNSUPPORTED;
-}
-
-status_t NuCachedSource2::initCheck() const {
- return mSource->initCheck();
-}
-
-status_t NuCachedSource2::getSize(off64_t *size) {
- return mSource->getSize(size);
-}
-
-uint32_t NuCachedSource2::flags() {
- // Remove HTTP related flags since NuCachedSource2 is not HTTP-based.
- uint32_t flags = mSource->flags() & ~(kWantsPrefetching | kIsHTTPBasedSource);
- return (flags | kIsCachingDataSource);
-}
-
-void NuCachedSource2::onMessageReceived(const sp<AMessage> &msg) {
- switch (msg->what()) {
- case kWhatFetchMore:
- {
- onFetch();
- break;
- }
-
- case kWhatRead:
- {
- onRead(msg);
- break;
- }
-
- default:
- TRESPASS();
- }
-}
-
-void NuCachedSource2::fetchInternal() {
- ALOGV("fetchInternal");
-
- bool reconnect = false;
-
- {
- Mutex::Autolock autoLock(mLock);
- CHECK(mFinalStatus == OK || mNumRetriesLeft > 0);
-
- if (mFinalStatus != OK) {
- --mNumRetriesLeft;
-
- reconnect = true;
- }
- }
-
- if (reconnect) {
- status_t err =
- mSource->reconnectAtOffset(mCacheOffset + mCache->totalSize());
-
- Mutex::Autolock autoLock(mLock);
-
- if (mDisconnecting) {
- mNumRetriesLeft = 0;
- mFinalStatus = ERROR_END_OF_STREAM;
- return;
- } else if (err == ERROR_UNSUPPORTED || err == -EPIPE) {
- // These are errors that are not likely to go away even if we
- // retry, i.e. the server doesn't support range requests or similar.
- mNumRetriesLeft = 0;
- return;
- } else if (err != OK) {
- ALOGI("The attempt to reconnect failed, %d retries remaining",
- mNumRetriesLeft);
-
- return;
- }
- }
-
- PageCache::Page *page = mCache->acquirePage();
-
- ssize_t n = mSource->readAt(
- mCacheOffset + mCache->totalSize(), page->mData, kPageSize);
-
- Mutex::Autolock autoLock(mLock);
-
- if (n == 0 || mDisconnecting) {
- ALOGI("caching reached eos.");
-
- mNumRetriesLeft = 0;
- mFinalStatus = ERROR_END_OF_STREAM;
-
- mCache->releasePage(page);
- } else if (n < 0) {
- mFinalStatus = n;
- if (n == ERROR_UNSUPPORTED || n == -EPIPE) {
- // These are errors that are not likely to go away even if we
- // retry, i.e. the server doesn't support range requests or similar.
- mNumRetriesLeft = 0;
- }
-
- ALOGE("source returned error %zd, %d retries left", n, mNumRetriesLeft);
- mCache->releasePage(page);
- } else {
- if (mFinalStatus != OK) {
- ALOGI("retrying a previously failed read succeeded.");
- }
- mNumRetriesLeft = kMaxNumRetries;
- mFinalStatus = OK;
-
- page->mSize = n;
- mCache->appendPage(page);
- }
-}
-
-void NuCachedSource2::onFetch() {
- ALOGV("onFetch");
-
- if (mFinalStatus != OK && mNumRetriesLeft == 0) {
- ALOGV("EOS reached, done prefetching for now");
- mFetching = false;
- }
-
- bool keepAlive =
- !mFetching
- && mFinalStatus == OK
- && mKeepAliveIntervalUs > 0
- && ALooper::GetNowUs() >= mLastFetchTimeUs + mKeepAliveIntervalUs;
-
- if (mFetching || keepAlive) {
- if (keepAlive) {
- ALOGI("Keep alive");
- }
-
- fetchInternal();
-
- mLastFetchTimeUs = ALooper::GetNowUs();
-
- if (mFetching && mCache->totalSize() >= mHighwaterThresholdBytes) {
- ALOGI("Cache full, done prefetching for now");
- mFetching = false;
-
- if (mDisconnectAtHighwatermark
- && (mSource->flags() & DataSource::kIsHTTPBasedSource)) {
- ALOGV("Disconnecting at high watermark");
- static_cast<HTTPBase *>(mSource.get())->disconnect();
- mFinalStatus = -EAGAIN;
- }
- }
- } else {
- Mutex::Autolock autoLock(mLock);
- restartPrefetcherIfNecessary_l();
- }
-
- int64_t delayUs;
- if (mFetching) {
- if (mFinalStatus != OK && mNumRetriesLeft > 0) {
- // We failed this time and will try again in 3 seconds.
- delayUs = 3000000LL;
- } else {
- delayUs = 0;
- }
- } else {
- delayUs = 100000LL;
- }
-
- (new AMessage(kWhatFetchMore, mReflector))->post(delayUs);
-}
-
-void NuCachedSource2::onRead(const sp<AMessage> &msg) {
- ALOGV("onRead");
-
- int64_t offset;
- CHECK(msg->findInt64("offset", &offset));
-
- void *data;
- CHECK(msg->findPointer("data", &data));
-
- size_t size;
- CHECK(msg->findSize("size", &size));
-
- ssize_t result = readInternal(offset, data, size);
-
- if (result == -EAGAIN) {
- msg->post(50000);
- return;
- }
-
- Mutex::Autolock autoLock(mLock);
- if (mDisconnecting) {
- mCondition.signal();
- return;
- }
-
- CHECK(mAsyncResult == NULL);
-
- mAsyncResult = new AMessage;
- mAsyncResult->setInt32("result", result);
-
- mCondition.signal();
-}
-
-void NuCachedSource2::restartPrefetcherIfNecessary_l(
- bool ignoreLowWaterThreshold, bool force) {
- static const size_t kGrayArea = 1024 * 1024;
-
- if (mFetching || (mFinalStatus != OK && mNumRetriesLeft == 0)) {
- return;
- }
-
- if (!ignoreLowWaterThreshold && !force
- && mCacheOffset + mCache->totalSize() - mLastAccessPos
- >= mLowwaterThresholdBytes) {
- return;
- }
-
- size_t maxBytes = mLastAccessPos - mCacheOffset;
-
- if (!force) {
- if (maxBytes < kGrayArea) {
- return;
- }
-
- maxBytes -= kGrayArea;
- }
-
- size_t actualBytes = mCache->releaseFromStart(maxBytes);
- mCacheOffset += actualBytes;
-
- ALOGI("restarting prefetcher, totalSize = %zu", mCache->totalSize());
- mFetching = true;
-}
-
-ssize_t NuCachedSource2::readAt(off64_t offset, void *data, size_t size) {
- Mutex::Autolock autoSerializer(mSerializer);
-
- ALOGV("readAt offset %lld, size %zu", (long long)offset, size);
-
- Mutex::Autolock autoLock(mLock);
- if (mDisconnecting) {
- return ERROR_END_OF_STREAM;
- }
-
- // If the request can be completely satisfied from the cache, do so.
-
- if (offset >= mCacheOffset
- && offset + size <= mCacheOffset + mCache->totalSize()) {
- size_t delta = offset - mCacheOffset;
- mCache->copy(delta, data, size);
-
- mLastAccessPos = offset + size;
-
- return size;
- }
-
- sp<AMessage> msg = new AMessage(kWhatRead, mReflector);
- msg->setInt64("offset", offset);
- msg->setPointer("data", data);
- msg->setSize("size", size);
-
- CHECK(mAsyncResult == NULL);
- msg->post();
-
- while (mAsyncResult == NULL && !mDisconnecting) {
- mCondition.wait(mLock);
- }
-
- if (mDisconnecting) {
- mAsyncResult.clear();
- return ERROR_END_OF_STREAM;
- }
-
- int32_t result;
- CHECK(mAsyncResult->findInt32("result", &result));
-
- mAsyncResult.clear();
-
- if (result > 0) {
- mLastAccessPos = offset + result;
- }
-
- return (ssize_t)result;
-}
-
-size_t NuCachedSource2::cachedSize() {
- Mutex::Autolock autoLock(mLock);
- return mCacheOffset + mCache->totalSize();
-}
-
-status_t NuCachedSource2::getAvailableSize(off64_t offset, off64_t *size) {
- Mutex::Autolock autoLock(mLock);
- status_t finalStatus = UNKNOWN_ERROR;
- *size = approxDataRemaining_l(offset, &finalStatus);
- return finalStatus;
-}
-
-size_t NuCachedSource2::approxDataRemaining(status_t *finalStatus) const {
- Mutex::Autolock autoLock(mLock);
- return approxDataRemaining_l(mLastAccessPos, finalStatus);
-}
-
-size_t NuCachedSource2::approxDataRemaining_l(off64_t offset, status_t *finalStatus) const {
- *finalStatus = mFinalStatus;
-
- if (mFinalStatus != OK && mNumRetriesLeft > 0) {
- // Pretend that everything is fine until we're out of retries.
- *finalStatus = OK;
- }
-
- offset = offset >= 0 ? offset : mLastAccessPos;
- off64_t lastBytePosCached = mCacheOffset + mCache->totalSize();
- if (offset < lastBytePosCached) {
- return lastBytePosCached - offset;
- }
- return 0;
-}
-
-ssize_t NuCachedSource2::readInternal(off64_t offset, void *data, size_t size) {
- CHECK_LE(size, (size_t)mHighwaterThresholdBytes);
-
- ALOGV("readInternal offset %lld size %zu", (long long)offset, size);
-
- Mutex::Autolock autoLock(mLock);
-
- // If we're disconnecting, return EOS and don't access *data pointer.
- // data could be on the stack of the caller to NuCachedSource2::readAt(),
- // which may have exited already.
- if (mDisconnecting) {
- return ERROR_END_OF_STREAM;
- }
-
- if (!mFetching) {
- mLastAccessPos = offset;
- restartPrefetcherIfNecessary_l(
- false, // ignoreLowWaterThreshold
- true); // force
- }
-
- if (offset < mCacheOffset
- || offset >= (off64_t)(mCacheOffset + mCache->totalSize())) {
- static const off64_t kPadding = 256 * 1024;
-
- // In the presence of multiple decoded streams, once of them will
- // trigger this seek request, the other one will request data "nearby"
- // soon, adjust the seek position so that that subsequent request
- // does not trigger another seek.
- off64_t seekOffset = (offset > kPadding) ? offset - kPadding : 0;
-
- seekInternal_l(seekOffset);
- }
-
- size_t delta = offset - mCacheOffset;
-
- if (mFinalStatus != OK && mNumRetriesLeft == 0) {
- if (delta >= mCache->totalSize()) {
- return mFinalStatus;
- }
-
- size_t avail = mCache->totalSize() - delta;
-
- if (avail > size) {
- avail = size;
- }
-
- mCache->copy(delta, data, avail);
-
- return avail;
- }
-
- if (offset + size <= mCacheOffset + mCache->totalSize()) {
- mCache->copy(delta, data, size);
-
- return size;
- }
-
- ALOGV("deferring read");
-
- return -EAGAIN;
-}
-
-status_t NuCachedSource2::seekInternal_l(off64_t offset) {
- mLastAccessPos = offset;
-
- if (offset >= mCacheOffset
- && offset <= (off64_t)(mCacheOffset + mCache->totalSize())) {
- return OK;
- }
-
- ALOGI("new range: offset= %lld", (long long)offset);
-
- mCacheOffset = offset;
-
- size_t totalSize = mCache->totalSize();
- CHECK_EQ(mCache->releaseFromStart(totalSize), totalSize);
-
- mNumRetriesLeft = kMaxNumRetries;
- mFetching = true;
-
- return OK;
-}
-
-void NuCachedSource2::resumeFetchingIfNecessary() {
- Mutex::Autolock autoLock(mLock);
-
- restartPrefetcherIfNecessary_l(true /* ignore low water threshold */);
-}
-
-sp<DecryptHandle> NuCachedSource2::DrmInitialization(const char* mime) {
- return mSource->DrmInitialization(mime);
-}
-
-String8 NuCachedSource2::getUri() {
- return mSource->getUri();
-}
-
-String8 NuCachedSource2::getMIMEType() const {
- return mSource->getMIMEType();
-}
-
-void NuCachedSource2::updateCacheParamsFromSystemProperty() {
- char value[PROPERTY_VALUE_MAX];
- if (!property_get("media.stagefright.cache-params", value, NULL)) {
- return;
- }
-
- updateCacheParamsFromString(value);
-}
-
-void NuCachedSource2::updateCacheParamsFromString(const char *s) {
- ssize_t lowwaterMarkKb, highwaterMarkKb;
- int keepAliveSecs;
-
- if (sscanf(s, "%zd/%zd/%d",
- &lowwaterMarkKb, &highwaterMarkKb, &keepAliveSecs) != 3) {
- ALOGE("Failed to parse cache parameters from '%s'.", s);
- return;
- }
-
- if (lowwaterMarkKb >= 0) {
- mLowwaterThresholdBytes = lowwaterMarkKb * 1024;
- } else {
- mLowwaterThresholdBytes = kDefaultLowWaterThreshold;
- }
-
- if (highwaterMarkKb >= 0) {
- mHighwaterThresholdBytes = highwaterMarkKb * 1024;
- } else {
- mHighwaterThresholdBytes = kDefaultHighWaterThreshold;
- }
-
- if (mLowwaterThresholdBytes >= mHighwaterThresholdBytes) {
- ALOGE("Illegal low/highwater marks specified, reverting to defaults.");
-
- mLowwaterThresholdBytes = kDefaultLowWaterThreshold;
- mHighwaterThresholdBytes = kDefaultHighWaterThreshold;
- }
-
- if (keepAliveSecs >= 0) {
- mKeepAliveIntervalUs = keepAliveSecs * 1000000LL;
- } else {
- mKeepAliveIntervalUs = kDefaultKeepAliveIntervalUs;
- }
-
- ALOGV("lowwater = %zu bytes, highwater = %zu bytes, keepalive = %lld us",
- mLowwaterThresholdBytes,
- mHighwaterThresholdBytes,
- (long long)mKeepAliveIntervalUs);
-}
-
-// static
-void NuCachedSource2::RemoveCacheSpecificHeaders(
- KeyedVector<String8, String8> *headers,
- String8 *cacheConfig,
- bool *disconnectAtHighwatermark) {
- *cacheConfig = String8();
- *disconnectAtHighwatermark = false;
-
- if (headers == NULL) {
- return;
- }
-
- ssize_t index;
- if ((index = headers->indexOfKey(String8("x-cache-config"))) >= 0) {
- *cacheConfig = headers->valueAt(index);
-
- headers->removeItemsAt(index);
-
- ALOGV("Using special cache config '%s'", cacheConfig->string());
- }
-
- if ((index = headers->indexOfKey(
- String8("x-disconnect-at-highwatermark"))) >= 0) {
- *disconnectAtHighwatermark = true;
- headers->removeItemsAt(index);
-
- ALOGV("Client requested disconnection at highwater mark");
- }
-}
-
-} // namespace android
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 680d426..050d7c2 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -22,13 +22,13 @@
#include "include/ESDS.h"
+#include <datasource/DataSourceFactory.h>
+#include <datasource/FileSource.h>
#include <media/DataSource.h>
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSourceFactory.h>
-#include <media/stagefright/FileSource.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
@@ -36,6 +36,7 @@
#include <media/stagefright/MediaExtractorFactory.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
namespace android {
@@ -81,7 +82,7 @@
}
sp<DataSource> dataSource =
- DataSourceFactory::CreateFromURI(httpService, path, headers);
+ DataSourceFactory::getInstance()->CreateFromURI(httpService, path, headers);
if (dataSource == NULL) {
return -ENOENT;
@@ -93,11 +94,16 @@
return ERROR_UNSUPPORTED;
}
+ status_t err = OK;
if (!mCasToken.empty()) {
- mImpl->setMediaCas(mCasToken);
+ err = mImpl->setMediaCas(mCasToken);
+ if (err != OK) {
+ ALOGE("%s: failed to setMediaCas (%d)", __FUNCTION__, err);
+ return err;
+ }
}
- status_t err = updateDurationAndBitrate();
+ err = updateDurationAndBitrate();
if (err == OK) {
mDataSource = dataSource;
}
@@ -130,7 +136,11 @@
}
if (!mCasToken.empty()) {
- mImpl->setMediaCas(mCasToken);
+ err = mImpl->setMediaCas(mCasToken);
+ if (err != OK) {
+ ALOGE("%s: failed to setMediaCas (%d)", __FUNCTION__, err);
+ return err;
+ }
}
err = updateDurationAndBitrate();
@@ -160,7 +170,11 @@
}
if (!mCasToken.empty()) {
- mImpl->setMediaCas(mCasToken);
+ err = mImpl->setMediaCas(mCasToken);
+ if (err != OK) {
+ ALOGE("%s: failed to setMediaCas (%d)", __FUNCTION__, err);
+ return err;
+ }
}
err = updateDurationAndBitrate();
@@ -194,8 +208,12 @@
mCasToken = casToken;
if (mImpl != NULL) {
- mImpl->setMediaCas(casToken);
- status_t err = updateDurationAndBitrate();
+ status_t err = mImpl->setMediaCas(casToken);
+ if (err != OK) {
+ ALOGE("%s: failed to setMediaCas (%d)", __FUNCTION__, err);
+ return err;
+ }
+ err = updateDurationAndBitrate();
if (err != OK) {
return err;
}
diff --git a/media/libstagefright/OggWriter.cpp b/media/libstagefright/OggWriter.cpp
index b738fef..0bc5976 100644
--- a/media/libstagefright/OggWriter.cpp
+++ b/media/libstagefright/OggWriter.cpp
@@ -22,7 +22,7 @@
#include <sys/stat.h>
#include <sys/types.h>
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/mediarecorder.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaDefs.h>
diff --git a/media/libstagefright/RemoteMediaExtractor.cpp b/media/libstagefright/RemoteMediaExtractor.cpp
index 29c3a35..25e43c2 100644
--- a/media/libstagefright/RemoteMediaExtractor.cpp
+++ b/media/libstagefright/RemoteMediaExtractor.cpp
@@ -20,8 +20,8 @@
#include <binder/IPCThreadState.h>
#include <media/stagefright/InterfaceUtils.h>
-#include <media/MediaAnalyticsItem.h>
-#include <media/MediaSource.h>
+#include <media/MediaMetricsItem.h>
+#include <media/stagefright/MediaSource.h>
#include <media/stagefright/RemoteMediaExtractor.h>
// still doing some on/off toggling here.
@@ -48,20 +48,20 @@
mSource(source),
mExtractorPlugin(plugin) {
- mAnalyticsItem = nullptr;
+ mMetricsItem = nullptr;
if (MEDIA_LOG) {
- mAnalyticsItem = MediaAnalyticsItem::create(kKeyExtractor);
+ mMetricsItem = mediametrics::Item::create(kKeyExtractor);
// we're in the extractor service, we want to attribute to the app
// that invoked us.
int uid = IPCThreadState::self()->getCallingUid();
- mAnalyticsItem->setUid(uid);
+ mMetricsItem->setUid(uid);
// track the container format (mpeg, aac, wvm, etc)
size_t ntracks = extractor->countTracks();
- mAnalyticsItem->setCString(kExtractorFormat, extractor->name());
+ mMetricsItem->setCString(kExtractorFormat, extractor->name());
// tracks (size_t)
- mAnalyticsItem->setInt32(kExtractorTracks, ntracks);
+ mMetricsItem->setInt32(kExtractorTracks, ntracks);
// metadata
MetaDataBase pMetaData;
if (extractor->getMetaData(pMetaData) == OK) {
@@ -70,7 +70,7 @@
// 'mime'
const char *mime = nullptr;
if (pMetaData.findCString(kKeyMIMEType, &mime)) {
- mAnalyticsItem->setCString(kExtractorMime, mime);
+ mMetricsItem->setCString(kExtractorMime, mime);
}
// what else is interesting and not already available?
}
@@ -84,15 +84,15 @@
mExtractorPlugin = nullptr;
// log the current record, provided it has some information worth recording
if (MEDIA_LOG) {
- if (mAnalyticsItem != nullptr) {
- if (mAnalyticsItem->count() > 0) {
- mAnalyticsItem->selfrecord();
+ if (mMetricsItem != nullptr) {
+ if (mMetricsItem->count() > 0) {
+ mMetricsItem->selfrecord();
}
}
}
- if (mAnalyticsItem != nullptr) {
- delete mAnalyticsItem;
- mAnalyticsItem = nullptr;
+ if (mMetricsItem != nullptr) {
+ delete mMetricsItem;
+ mMetricsItem = nullptr;
}
}
@@ -123,11 +123,11 @@
}
status_t RemoteMediaExtractor::getMetrics(Parcel *reply) {
- if (mAnalyticsItem == nullptr || reply == nullptr) {
+ if (mMetricsItem == nullptr || reply == nullptr) {
return UNKNOWN_ERROR;
}
- mAnalyticsItem->writeToParcel(reply);
+ mMetricsItem->writeToParcel(reply);
return OK;
}
@@ -139,8 +139,8 @@
return mExtractor->setMediaCas((uint8_t*)casToken.data(), casToken.size());
}
-const char * RemoteMediaExtractor::name() {
- return mExtractor->name();
+String8 RemoteMediaExtractor::name() {
+ return String8(mExtractor->name());
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/media/libstagefright/SimpleDecodingSource.cpp b/media/libstagefright/SimpleDecodingSource.cpp
index babdc7a..771dfea 100644
--- a/media/libstagefright/SimpleDecodingSource.cpp
+++ b/media/libstagefright/SimpleDecodingSource.cpp
@@ -20,7 +20,7 @@
#include <gui/Surface.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/MediaCodecBuffer.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/foundation/ALooper.h>
@@ -36,7 +36,7 @@
using namespace android;
const int64_t kTimeoutWaitForOutputUs = 500000; // 0.5 seconds
-const int64_t kTimeoutWaitForInputUs = 5000; // 5 milliseconds
+const int64_t kTimeoutWaitForInputUs = 0; // don't wait
const int kTimeoutMaxRetries = 20;
//static
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index cf4edae..6fd0805 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -35,7 +35,7 @@
StagefrightMediaScanner::~StagefrightMediaScanner() {}
-static std::unordered_set<std::string> gSupportedExtensions;
+static std::vector<std::string> gSupportedExtensions;
static bool FileHasAcceptableExtension(const char *extension) {
@@ -44,7 +44,12 @@
gSupportedExtensions = MediaExtractorFactory::getSupportedTypes();
}
- return gSupportedExtensions.count(std::string(extension + 1)) != 0;
+ for (auto ext: gSupportedExtensions) {
+ if (ext == (extension + 1)) {
+ return true;
+ }
+ }
+ return false;
}
MediaScanResult StagefrightMediaScanner::processFile(
@@ -158,7 +163,11 @@
if (mRetriever->setDataSource(fd, 0, size) == OK) {
sp<IMemory> mem = mRetriever->extractAlbumArt();
if (mem != NULL) {
- MediaAlbumArt *art = static_cast<MediaAlbumArt *>(mem->pointer());
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
+ MediaAlbumArt *art = static_cast<MediaAlbumArt *>(mem->unsecurePointer());
return art->clone();
}
}
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
deleted file mode 100644
index fa3d372..0000000
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ /dev/null
@@ -1,705 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "StagefrightMetadataRetriever"
-
-#include <inttypes.h>
-
-#include <utils/Log.h>
-#include <cutils/properties.h>
-
-#include "include/FrameDecoder.h"
-#include "include/StagefrightMetadataRetriever.h"
-
-#include <media/IMediaHTTPService.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSourceFactory.h>
-#include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaCodecList.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaExtractorFactory.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
-#include <media/CharacterEncodingDetector.h>
-
-namespace android {
-
-StagefrightMetadataRetriever::StagefrightMetadataRetriever()
- : mParsedMetaData(false),
- mAlbumArt(NULL),
- mLastImageIndex(-1) {
- ALOGV("StagefrightMetadataRetriever()");
-}
-
-StagefrightMetadataRetriever::~StagefrightMetadataRetriever() {
- ALOGV("~StagefrightMetadataRetriever()");
- clearMetadata();
- if (mSource != NULL) {
- mSource->close();
- }
-}
-
-status_t StagefrightMetadataRetriever::setDataSource(
- const sp<IMediaHTTPService> &httpService,
- const char *uri,
- const KeyedVector<String8, String8> *headers) {
- ALOGV("setDataSource(%s)", uri);
-
- clearMetadata();
- mSource = DataSourceFactory::CreateFromURI(httpService, uri, headers);
-
- if (mSource == NULL) {
- ALOGE("Unable to create data source for '%s'.", uri);
- return UNKNOWN_ERROR;
- }
-
- mExtractor = MediaExtractorFactory::Create(mSource);
-
- if (mExtractor == NULL) {
- ALOGE("Unable to instantiate an extractor for '%s'.", uri);
-
- mSource.clear();
-
- return UNKNOWN_ERROR;
- }
-
- return OK;
-}
-
-// Warning caller retains ownership of the filedescriptor! Dup it if necessary.
-status_t StagefrightMetadataRetriever::setDataSource(
- int fd, int64_t offset, int64_t length) {
- fd = dup(fd);
-
- ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
-
- clearMetadata();
- mSource = new FileSource(fd, offset, length);
-
- status_t err;
- if ((err = mSource->initCheck()) != OK) {
- mSource.clear();
-
- return err;
- }
-
- mExtractor = MediaExtractorFactory::Create(mSource);
-
- if (mExtractor == NULL) {
- mSource.clear();
-
- return UNKNOWN_ERROR;
- }
-
- return OK;
-}
-
-status_t StagefrightMetadataRetriever::setDataSource(
- const sp<DataSource>& source, const char *mime) {
- ALOGV("setDataSource(DataSource)");
-
- clearMetadata();
- mSource = source;
- mExtractor = MediaExtractorFactory::Create(mSource, mime);
-
- if (mExtractor == NULL) {
- ALOGE("Failed to instantiate a MediaExtractor.");
- mSource.clear();
- return UNKNOWN_ERROR;
- }
-
- return OK;
-}
-
-sp<IMemory> StagefrightMetadataRetriever::getImageAtIndex(
- int index, int colorFormat, bool metaOnly, bool thumbnail) {
- ALOGV("getImageAtIndex: index(%d) colorFormat(%d) metaOnly(%d) thumbnail(%d)",
- index, colorFormat, metaOnly, thumbnail);
-
- return getImageInternal(index, colorFormat, metaOnly, thumbnail, NULL);
-}
-
-sp<IMemory> StagefrightMetadataRetriever::getImageRectAtIndex(
- int index, int colorFormat, int left, int top, int right, int bottom) {
- ALOGV("getImageRectAtIndex: index(%d) colorFormat(%d) rect {%d, %d, %d, %d}",
- index, colorFormat, left, top, right, bottom);
-
- FrameRect rect = {left, top, right, bottom};
-
- if (mImageDecoder != NULL && index == mLastImageIndex) {
- return mImageDecoder->extractFrame(&rect);
- }
-
- return getImageInternal(
- index, colorFormat, false /*metaOnly*/, false /*thumbnail*/, &rect);
-}
-
-sp<IMemory> StagefrightMetadataRetriever::getImageInternal(
- int index, int colorFormat, bool metaOnly, bool thumbnail, FrameRect* rect) {
-
- if (mExtractor.get() == NULL) {
- ALOGE("no extractor.");
- return NULL;
- }
-
- size_t n = mExtractor->countTracks();
- size_t i;
- int imageCount = 0;
-
- for (i = 0; i < n; ++i) {
- sp<MetaData> meta = mExtractor->getTrackMetaData(i);
- if (!meta) {
- continue;
- }
- ALOGV("getting track %zu of %zu, meta=%s", i, n, meta->toString().c_str());
-
- const char *mime;
- CHECK(meta->findCString(kKeyMIMEType, &mime));
-
- if (!strncasecmp(mime, "image/", 6)) {
- int32_t isPrimary;
- if ((index < 0 && meta->findInt32(
- kKeyTrackIsDefault, &isPrimary) && isPrimary)
- || (index == imageCount++)) {
- break;
- }
- }
- }
-
- if (i == n) {
- ALOGE("image track not found.");
- return NULL;
- }
-
- sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i);
- if (!trackMeta) {
- return NULL;
- }
-
- if (metaOnly) {
- return FrameDecoder::getMetadataOnly(trackMeta, colorFormat, thumbnail);
- }
-
- sp<IMediaSource> source = mExtractor->getTrack(i);
-
- if (source.get() == NULL) {
- ALOGE("unable to instantiate image track.");
- return NULL;
- }
-
- const char *mime;
- CHECK(trackMeta->findCString(kKeyMIMEType, &mime));
- ALOGV("extracting from %s track", mime);
- if (!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC)) {
- mime = MEDIA_MIMETYPE_VIDEO_HEVC;
- trackMeta = new MetaData(*trackMeta);
- trackMeta->setCString(kKeyMIMEType, mime);
- }
-
- bool preferhw = property_get_bool(
- "media.stagefright.thumbnail.prefer_hw_codecs", false);
- uint32_t flags = preferhw ? 0 : MediaCodecList::kPreferSoftwareCodecs;
- Vector<AString> matchingCodecs;
- MediaCodecList::findMatchingCodecs(
- mime,
- false, /* encoder */
- flags,
- &matchingCodecs);
-
- for (size_t i = 0; i < matchingCodecs.size(); ++i) {
- const AString &componentName = matchingCodecs[i];
- sp<ImageDecoder> decoder = new ImageDecoder(componentName, trackMeta, source);
- int64_t frameTimeUs = thumbnail ? -1 : 0;
- if (decoder->init(frameTimeUs, 1 /*numFrames*/, 0 /*option*/, colorFormat) == OK) {
- sp<IMemory> frame = decoder->extractFrame(rect);
-
- if (frame != NULL) {
- if (rect != NULL) {
- // keep the decoder if slice decoding
- mImageDecoder = decoder;
- mLastImageIndex = index;
- }
- return frame;
- }
- }
- ALOGV("%s failed to extract thumbnail, trying next decoder.", componentName.c_str());
- }
-
- return NULL;
-}
-
-sp<IMemory> StagefrightMetadataRetriever::getFrameAtTime(
- int64_t timeUs, int option, int colorFormat, bool metaOnly) {
- ALOGV("getFrameAtTime: %" PRId64 " us option: %d colorFormat: %d, metaOnly: %d",
- timeUs, option, colorFormat, metaOnly);
-
- sp<IMemory> frame;
- status_t err = getFrameInternal(
- timeUs, 1, option, colorFormat, metaOnly, &frame, NULL /*outFrames*/);
- return (err == OK) ? frame : NULL;
-}
-
-status_t StagefrightMetadataRetriever::getFrameAtIndex(
- std::vector<sp<IMemory> >* frames,
- int frameIndex, int numFrames, int colorFormat, bool metaOnly) {
- ALOGV("getFrameAtIndex: frameIndex %d, numFrames %d, colorFormat: %d, metaOnly: %d",
- frameIndex, numFrames, colorFormat, metaOnly);
-
- return getFrameInternal(
- frameIndex, numFrames, MediaSource::ReadOptions::SEEK_FRAME_INDEX,
- colorFormat, metaOnly, NULL /*outFrame*/, frames);
-}
-
-status_t StagefrightMetadataRetriever::getFrameInternal(
- int64_t timeUs, int numFrames, int option, int colorFormat, bool metaOnly,
- sp<IMemory>* outFrame, std::vector<sp<IMemory> >* outFrames) {
- if (mExtractor.get() == NULL) {
- ALOGE("no extractor.");
- return NO_INIT;
- }
-
- sp<MetaData> fileMeta = mExtractor->getMetaData();
-
- if (fileMeta == NULL) {
- ALOGE("extractor doesn't publish metadata, failed to initialize?");
- return NO_INIT;
- }
-
- size_t n = mExtractor->countTracks();
- size_t i;
- for (i = 0; i < n; ++i) {
- sp<MetaData> meta = mExtractor->getTrackMetaData(i);
- if (!meta) {
- continue;
- }
-
- const char *mime;
- CHECK(meta->findCString(kKeyMIMEType, &mime));
-
- if (!strncasecmp(mime, "video/", 6)) {
- break;
- }
- }
-
- if (i == n) {
- ALOGE("no video track found.");
- return INVALID_OPERATION;
- }
-
- sp<MetaData> trackMeta = mExtractor->getTrackMetaData(
- i, MediaExtractor::kIncludeExtensiveMetaData);
- if (!trackMeta) {
- return UNKNOWN_ERROR;
- }
-
- if (metaOnly) {
- if (outFrame != NULL) {
- *outFrame = FrameDecoder::getMetadataOnly(trackMeta, colorFormat);
- if (*outFrame != NULL) {
- return OK;
- }
- }
- return UNKNOWN_ERROR;
- }
-
- sp<IMediaSource> source = mExtractor->getTrack(i);
-
- if (source.get() == NULL) {
- ALOGV("unable to instantiate video track.");
- return UNKNOWN_ERROR;
- }
-
- const void *data;
- uint32_t type;
- size_t dataSize;
- if (fileMeta->findData(kKeyAlbumArt, &type, &data, &dataSize)
- && mAlbumArt == NULL) {
- mAlbumArt = MediaAlbumArt::fromData(dataSize, data);
- }
-
- const char *mime;
- CHECK(trackMeta->findCString(kKeyMIMEType, &mime));
-
- bool preferhw = property_get_bool(
- "media.stagefright.thumbnail.prefer_hw_codecs", false);
- uint32_t flags = preferhw ? 0 : MediaCodecList::kPreferSoftwareCodecs;
- Vector<AString> matchingCodecs;
- MediaCodecList::findMatchingCodecs(
- mime,
- false, /* encoder */
- flags,
- &matchingCodecs);
-
- for (size_t i = 0; i < matchingCodecs.size(); ++i) {
- const AString &componentName = matchingCodecs[i];
- sp<VideoFrameDecoder> decoder = new VideoFrameDecoder(componentName, trackMeta, source);
- if (decoder->init(timeUs, numFrames, option, colorFormat) == OK) {
- if (outFrame != NULL) {
- *outFrame = decoder->extractFrame();
- if (*outFrame != NULL) {
- return OK;
- }
- } else if (outFrames != NULL) {
- status_t err = decoder->extractFrames(outFrames);
- if (err == OK) {
- return OK;
- }
- }
- }
- ALOGV("%s failed to extract frame, trying next decoder.", componentName.c_str());
- }
-
- ALOGE("all codecs failed to extract frame.");
- return UNKNOWN_ERROR;
-}
-
-MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() {
- ALOGV("extractAlbumArt (extractor: %s)", mExtractor.get() != NULL ? "YES" : "NO");
-
- if (mExtractor == NULL) {
- return NULL;
- }
-
- if (!mParsedMetaData) {
- parseMetaData();
-
- mParsedMetaData = true;
- }
-
- if (mAlbumArt) {
- return mAlbumArt->clone();
- }
-
- return NULL;
-}
-
-const char *StagefrightMetadataRetriever::extractMetadata(int keyCode) {
- if (mExtractor == NULL) {
- return NULL;
- }
-
- if (!mParsedMetaData) {
- parseMetaData();
-
- mParsedMetaData = true;
- }
-
- ssize_t index = mMetaData.indexOfKey(keyCode);
-
- if (index < 0) {
- return NULL;
- }
-
- return mMetaData.valueAt(index).string();
-}
-
-void StagefrightMetadataRetriever::parseColorAspects(const sp<MetaData>& meta) {
- sp<AMessage> format = new AMessage();
- if (convertMetaDataToMessage(meta, &format) != OK) {
- return;
- }
-
- int32_t standard, transfer, range;
- if (format->findInt32("color-standard", &standard)
- && format->findInt32("color-transfer", &transfer)
- && format->findInt32("color-range", &range)) {
- ALOGV("found color aspects : standard=%d, transfer=%d, range=%d",
- standard, transfer, range);
-
- mMetaData.add(METADATA_KEY_COLOR_STANDARD, String8::format("%d", standard));
- mMetaData.add(METADATA_KEY_COLOR_TRANSFER, String8::format("%d", transfer));
- mMetaData.add(METADATA_KEY_COLOR_RANGE, String8::format("%d", range));
- }
-}
-
-void StagefrightMetadataRetriever::parseMetaData() {
- sp<MetaData> meta = mExtractor->getMetaData();
-
- if (meta == NULL) {
- ALOGV("extractor doesn't publish metadata, failed to initialize?");
- return;
- }
-
- struct Map {
- int from;
- int to;
- const char *name;
- };
- static const Map kMap[] = {
- { kKeyMIMEType, METADATA_KEY_MIMETYPE, NULL },
- { kKeyCDTrackNumber, METADATA_KEY_CD_TRACK_NUMBER, "tracknumber" },
- { kKeyDiscNumber, METADATA_KEY_DISC_NUMBER, "discnumber" },
- { kKeyAlbum, METADATA_KEY_ALBUM, "album" },
- { kKeyArtist, METADATA_KEY_ARTIST, "artist" },
- { kKeyAlbumArtist, METADATA_KEY_ALBUMARTIST, "albumartist" },
- { kKeyAuthor, METADATA_KEY_AUTHOR, NULL },
- { kKeyComposer, METADATA_KEY_COMPOSER, "composer" },
- { kKeyDate, METADATA_KEY_DATE, NULL },
- { kKeyGenre, METADATA_KEY_GENRE, "genre" },
- { kKeyTitle, METADATA_KEY_TITLE, "title" },
- { kKeyYear, METADATA_KEY_YEAR, "year" },
- { kKeyWriter, METADATA_KEY_WRITER, "writer" },
- { kKeyCompilation, METADATA_KEY_COMPILATION, "compilation" },
- { kKeyLocation, METADATA_KEY_LOCATION, NULL },
- };
-
- static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]);
-
- CharacterEncodingDetector *detector = new CharacterEncodingDetector();
-
- for (size_t i = 0; i < kNumMapEntries; ++i) {
- const char *value;
- if (meta->findCString(kMap[i].from, &value)) {
- if (kMap[i].name) {
- // add to charset detector
- detector->addTag(kMap[i].name, value);
- } else {
- // directly add to output list
- mMetaData.add(kMap[i].to, String8(value));
- }
- }
- }
-
- detector->detectAndConvert();
- int size = detector->size();
- if (size) {
- for (int i = 0; i < size; i++) {
- const char *name;
- const char *value;
- detector->getTag(i, &name, &value);
- for (size_t j = 0; j < kNumMapEntries; ++j) {
- if (kMap[j].name && !strcmp(kMap[j].name, name)) {
- mMetaData.add(kMap[j].to, String8(value));
- }
- }
- }
- }
- delete detector;
-
- const void *data;
- uint32_t type;
- size_t dataSize;
- if (meta->findData(kKeyAlbumArt, &type, &data, &dataSize)
- && mAlbumArt == NULL) {
- mAlbumArt = MediaAlbumArt::fromData(dataSize, data);
- }
-
- size_t numTracks = mExtractor->countTracks();
-
- char tmp[32];
- sprintf(tmp, "%zu", numTracks);
-
- mMetaData.add(METADATA_KEY_NUM_TRACKS, String8(tmp));
-
- float captureFps;
- if (meta->findFloat(kKeyCaptureFramerate, &captureFps)) {
- sprintf(tmp, "%f", captureFps);
- mMetaData.add(METADATA_KEY_CAPTURE_FRAMERATE, String8(tmp));
- }
-
- int64_t exifOffset, exifSize;
- if (meta->findInt64(kKeyExifOffset, &exifOffset)
- && meta->findInt64(kKeyExifSize, &exifSize)) {
- sprintf(tmp, "%lld", (long long)exifOffset);
- mMetaData.add(METADATA_KEY_EXIF_OFFSET, String8(tmp));
- sprintf(tmp, "%lld", (long long)exifSize);
- mMetaData.add(METADATA_KEY_EXIF_LENGTH, String8(tmp));
- }
-
- bool hasAudio = false;
- bool hasVideo = false;
- int32_t videoWidth = -1;
- int32_t videoHeight = -1;
- int32_t videoFrameCount = 0;
- int32_t audioBitrate = -1;
- int32_t rotationAngle = -1;
- int32_t imageCount = 0;
- int32_t imagePrimary = 0;
- int32_t imageWidth = -1;
- int32_t imageHeight = -1;
- int32_t imageRotation = -1;
-
- // The overall duration is the duration of the longest track.
- int64_t maxDurationUs = 0;
- String8 timedTextLang;
- for (size_t i = 0; i < numTracks; ++i) {
- sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i);
- if (!trackMeta) {
- continue;
- }
-
- int64_t durationUs;
- if (trackMeta->findInt64(kKeyDuration, &durationUs)) {
- if (durationUs > maxDurationUs) {
- maxDurationUs = durationUs;
- }
- }
-
- const char *mime;
- if (trackMeta->findCString(kKeyMIMEType, &mime)) {
- if (!hasAudio && !strncasecmp("audio/", mime, 6)) {
- hasAudio = true;
-
- if (!trackMeta->findInt32(kKeyBitRate, &audioBitrate)) {
- audioBitrate = -1;
- }
-
- int32_t bitsPerSample = -1;
- int32_t sampleRate = -1;
- trackMeta->findInt32(kKeyBitsPerSample, &bitsPerSample);
- trackMeta->findInt32(kKeySampleRate, &sampleRate);
- if (bitsPerSample >= 0) {
- sprintf(tmp, "%d", bitsPerSample);
- mMetaData.add(METADATA_KEY_BITS_PER_SAMPLE, String8(tmp));
- }
- if (sampleRate >= 0) {
- sprintf(tmp, "%d", sampleRate);
- mMetaData.add(METADATA_KEY_SAMPLERATE, String8(tmp));
- }
- } else if (!hasVideo && !strncasecmp("video/", mime, 6)) {
- hasVideo = true;
-
- CHECK(trackMeta->findInt32(kKeyWidth, &videoWidth));
- CHECK(trackMeta->findInt32(kKeyHeight, &videoHeight));
- if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
- rotationAngle = 0;
- }
- if (!trackMeta->findInt32(kKeyFrameCount, &videoFrameCount)) {
- videoFrameCount = 0;
- }
-
- parseColorAspects(trackMeta);
- } else if (!strncasecmp("image/", mime, 6)) {
- int32_t isPrimary;
- if (trackMeta->findInt32(
- kKeyTrackIsDefault, &isPrimary) && isPrimary) {
- imagePrimary = imageCount;
- CHECK(trackMeta->findInt32(kKeyWidth, &imageWidth));
- CHECK(trackMeta->findInt32(kKeyHeight, &imageHeight));
- if (!trackMeta->findInt32(kKeyRotation, &imageRotation)) {
- imageRotation = 0;
- }
- }
- imageCount++;
- } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
- const char *lang;
- if (trackMeta->findCString(kKeyMediaLanguage, &lang)) {
- timedTextLang.append(String8(lang));
- timedTextLang.append(String8(":"));
- } else {
- ALOGE("No language found for timed text");
- }
- }
- }
- }
-
- // To save the language codes for all timed text tracks
- // If multiple text tracks present, the format will look
- // like "eng:chi"
- if (!timedTextLang.isEmpty()) {
- mMetaData.add(METADATA_KEY_TIMED_TEXT_LANGUAGES, timedTextLang);
- }
-
- // The duration value is a string representing the duration in ms.
- sprintf(tmp, "%" PRId64, (maxDurationUs + 500) / 1000);
- mMetaData.add(METADATA_KEY_DURATION, String8(tmp));
-
- if (hasAudio) {
- mMetaData.add(METADATA_KEY_HAS_AUDIO, String8("yes"));
- }
-
- if (hasVideo) {
- mMetaData.add(METADATA_KEY_HAS_VIDEO, String8("yes"));
-
- sprintf(tmp, "%d", videoWidth);
- mMetaData.add(METADATA_KEY_VIDEO_WIDTH, String8(tmp));
-
- sprintf(tmp, "%d", videoHeight);
- mMetaData.add(METADATA_KEY_VIDEO_HEIGHT, String8(tmp));
-
- sprintf(tmp, "%d", rotationAngle);
- mMetaData.add(METADATA_KEY_VIDEO_ROTATION, String8(tmp));
-
- if (videoFrameCount > 0) {
- sprintf(tmp, "%d", videoFrameCount);
- mMetaData.add(METADATA_KEY_VIDEO_FRAME_COUNT, String8(tmp));
- }
- }
-
- if (imageCount > 0) {
- mMetaData.add(METADATA_KEY_HAS_IMAGE, String8("yes"));
-
- sprintf(tmp, "%d", imageCount);
- mMetaData.add(METADATA_KEY_IMAGE_COUNT, String8(tmp));
-
- sprintf(tmp, "%d", imagePrimary);
- mMetaData.add(METADATA_KEY_IMAGE_PRIMARY, String8(tmp));
-
- sprintf(tmp, "%d", imageWidth);
- mMetaData.add(METADATA_KEY_IMAGE_WIDTH, String8(tmp));
-
- sprintf(tmp, "%d", imageHeight);
- mMetaData.add(METADATA_KEY_IMAGE_HEIGHT, String8(tmp));
-
- sprintf(tmp, "%d", imageRotation);
- mMetaData.add(METADATA_KEY_IMAGE_ROTATION, String8(tmp));
- }
-
- if (numTracks == 1 && hasAudio && audioBitrate >= 0) {
- sprintf(tmp, "%d", audioBitrate);
- mMetaData.add(METADATA_KEY_BITRATE, String8(tmp));
- } else {
- off64_t sourceSize;
- if (mSource != NULL && mSource->getSize(&sourceSize) == OK) {
- int64_t avgBitRate = (int64_t)(sourceSize * 8E6 / maxDurationUs);
-
- sprintf(tmp, "%" PRId64, avgBitRate);
- mMetaData.add(METADATA_KEY_BITRATE, String8(tmp));
- }
- }
-
- if (numTracks == 1) {
- const char *fileMIME;
-
- if (meta->findCString(kKeyMIMEType, &fileMIME) &&
- !strcasecmp(fileMIME, "video/x-matroska")) {
- sp<MetaData> trackMeta = mExtractor->getTrackMetaData(0);
- const char *trackMIME;
- if (trackMeta != nullptr) {
- CHECK(trackMeta->findCString(kKeyMIMEType, &trackMIME));
- }
- if (!strncasecmp("audio/", trackMIME, 6)) {
- // The matroska file only contains a single audio track,
- // rewrite its mime type.
- mMetaData.add(
- METADATA_KEY_MIMETYPE, String8("audio/x-matroska"));
- }
- }
- }
-}
-
-void StagefrightMetadataRetriever::clearMetadata() {
- mParsedMetaData = false;
- mMetaData.clear();
- delete mAlbumArt;
- mAlbumArt = NULL;
-}
-
-} // namespace android
diff --git a/media/libstagefright/StagefrightPluginLoader.cpp b/media/libstagefright/StagefrightPluginLoader.cpp
deleted file mode 100644
index fb03c5e..0000000
--- a/media/libstagefright/StagefrightPluginLoader.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "StagefrightPluginLoader"
-#include <utils/Log.h>
-
-#include <android-base/properties.h>
-#include <dlfcn.h>
-
-#include "StagefrightPluginLoader.h"
-
-namespace android {
-
-/* static */ Mutex StagefrightPluginLoader::sMutex;
-/* static */ std::unique_ptr<StagefrightPluginLoader> StagefrightPluginLoader::sInstance;
-
-namespace /* unnamed */ {
-
-constexpr const char kCCodecPluginPath[] = "libsfplugin_ccodec.so";
-
-} // unnamed namespace
-
-StagefrightPluginLoader::StagefrightPluginLoader(const char *libPath) {
- if (android::base::GetIntProperty("debug.stagefright.ccodec", 1) == 0) {
- ALOGD("CCodec is disabled.");
- return;
- }
- mLibHandle = dlopen(libPath, RTLD_NOW | RTLD_NODELETE);
- if (mLibHandle == nullptr) {
- ALOGD("Failed to load library: %s (%s)", libPath, dlerror());
- return;
- }
- mCreateCodec = (CodecBase::CreateCodecFunc)dlsym(mLibHandle, "CreateCodec");
- if (mCreateCodec == nullptr) {
- ALOGD("Failed to find symbol: CreateCodec (%s)", dlerror());
- }
- mCreateBuilder = (MediaCodecListBuilderBase::CreateBuilderFunc)dlsym(
- mLibHandle, "CreateBuilder");
- if (mCreateBuilder == nullptr) {
- ALOGD("Failed to find symbol: CreateBuilder (%s)", dlerror());
- }
- mCreateInputSurface = (CodecBase::CreateInputSurfaceFunc)dlsym(
- mLibHandle, "CreateInputSurface");
- if (mCreateInputSurface == nullptr) {
- ALOGD("Failed to find symbol: CreateInputSurface (%s)", dlerror());
- }
-}
-
-StagefrightPluginLoader::~StagefrightPluginLoader() {
- if (mLibHandle != nullptr) {
- ALOGV("Closing handle");
- dlclose(mLibHandle);
- }
-}
-
-CodecBase *StagefrightPluginLoader::createCodec() {
- if (mLibHandle == nullptr || mCreateCodec == nullptr) {
- ALOGD("Handle or CreateCodec symbol is null");
- return nullptr;
- }
- return mCreateCodec();
-}
-
-MediaCodecListBuilderBase *StagefrightPluginLoader::createBuilder() {
- if (mLibHandle == nullptr || mCreateBuilder == nullptr) {
- ALOGD("Handle or CreateBuilder symbol is null");
- return nullptr;
- }
- return mCreateBuilder();
-}
-
-PersistentSurface *StagefrightPluginLoader::createInputSurface() {
- if (mLibHandle == nullptr || mCreateInputSurface == nullptr) {
- ALOGD("Handle or CreateInputSurface symbol is null");
- return nullptr;
- }
- return mCreateInputSurface();
-}
-
-//static
-const std::unique_ptr<StagefrightPluginLoader> &StagefrightPluginLoader::GetCCodecInstance() {
- Mutex::Autolock _l(sMutex);
- if (!sInstance) {
- ALOGV("Loading library");
- sInstance.reset(new StagefrightPluginLoader(kCCodecPluginPath));
- }
- return sInstance;
-}
-
-} // namespace android
diff --git a/media/libstagefright/StagefrightPluginLoader.h b/media/libstagefright/StagefrightPluginLoader.h
deleted file mode 100644
index 78effbf..0000000
--- a/media/libstagefright/StagefrightPluginLoader.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef STAGEFRIGHT_PLUGIN_LOADER_H_
-
-#define STAGEFRIGHT_PLUGIN_LOADER_H_
-
-#include <media/stagefright/CodecBase.h>
-#include <media/stagefright/MediaCodecListWriter.h>
-#include <media/stagefright/PersistentSurface.h>
-#include <utils/Mutex.h>
-
-namespace android {
-
-class StagefrightPluginLoader {
-public:
- static const std::unique_ptr<StagefrightPluginLoader> &GetCCodecInstance();
- ~StagefrightPluginLoader();
-
- CodecBase *createCodec();
- MediaCodecListBuilderBase *createBuilder();
- PersistentSurface *createInputSurface();
-
-private:
- explicit StagefrightPluginLoader(const char *libPath);
-
- static Mutex sMutex;
- static std::unique_ptr<StagefrightPluginLoader> sInstance;
-
- void *mLibHandle{nullptr};
- CodecBase::CreateCodecFunc mCreateCodec{nullptr};
- MediaCodecListBuilderBase::CreateBuilderFunc mCreateBuilder{nullptr};
- CodecBase::CreateInputSurfaceFunc mCreateInputSurface{nullptr};
-};
-
-} // namespace android
-
-#endif // STAGEFRIGHT_PLUGIN_LOADER_H_
diff --git a/media/libstagefright/TEST_MAPPING b/media/libstagefright/TEST_MAPPING
index c1b270c..8b36ea5 100644
--- a/media/libstagefright/TEST_MAPPING
+++ b/media/libstagefright/TEST_MAPPING
@@ -1,13 +1,25 @@
{
- "postsubmit": [
+ "presubmit": [
{
"name": "CtsMediaTestCases",
"options": [
{
- "include-annotation": "android.platform.test.annotations.RequiresDevice"
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.RequiresDevice"
+ },
+ // TODO: b/149314419
+ {
+ "exclude-filter": "android.media.cts.AudioPlaybackCaptureTest"
+ },
+ {
+ "exclude-filter": "android.media.cts.AudioRecordTest"
}
]
- },
+ }
+ ],
+ "postsubmit": [
{
"name": "BatteryChecker_test"
}
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 135151f..a1e4d43 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -227,6 +227,68 @@
}
}
+static void parseDolbyVisionProfileLevelFromDvcc(const uint8_t *ptr, size_t size, sp<AMessage> &format) {
+ // dv_major.dv_minor Should be 1.0 or 2.1
+ if (size != 24 || ((ptr[0] != 1 || ptr[1] != 0) && (ptr[0] != 2 || ptr[1] != 1))) {
+ ALOGV("Size %zu, dv_major %d, dv_minor %d", size, ptr[0], ptr[1]);
+ return;
+ }
+
+ const uint8_t profile = ptr[2] >> 1;
+ const uint8_t level = ((ptr[2] & 0x1) << 5) | ((ptr[3] >> 3) & 0x1f);
+ const uint8_t rpu_present_flag = (ptr[3] >> 2) & 0x01;
+ const uint8_t el_present_flag = (ptr[3] >> 1) & 0x01;
+ const uint8_t bl_present_flag = (ptr[3] & 0x01);
+ const int32_t bl_compatibility_id = (int32_t)(ptr[4] >> 4);
+
+ ALOGV("profile-level-compatibility value in dv(c|v)c box %d-%d-%d",
+ profile, level, bl_compatibility_id);
+
+ // All Dolby Profiles will have profile and level info in MediaFormat
+ // Profile 8 and 9 will have bl_compatibility_id too.
+ const static ALookup<uint8_t, OMX_VIDEO_DOLBYVISIONPROFILETYPE> profiles{
+ {1, OMX_VIDEO_DolbyVisionProfileDvavPen},
+ {3, OMX_VIDEO_DolbyVisionProfileDvheDen},
+ {4, OMX_VIDEO_DolbyVisionProfileDvheDtr},
+ {5, OMX_VIDEO_DolbyVisionProfileDvheStn},
+ {6, OMX_VIDEO_DolbyVisionProfileDvheDth},
+ {7, OMX_VIDEO_DolbyVisionProfileDvheDtb},
+ {8, OMX_VIDEO_DolbyVisionProfileDvheSt},
+ {9, OMX_VIDEO_DolbyVisionProfileDvavSe},
+ {10, OMX_VIDEO_DolbyVisionProfileDvav110},
+ };
+
+ const static ALookup<uint8_t, OMX_VIDEO_DOLBYVISIONLEVELTYPE> levels{
+ {0, OMX_VIDEO_DolbyVisionLevelUnknown},
+ {1, OMX_VIDEO_DolbyVisionLevelHd24},
+ {2, OMX_VIDEO_DolbyVisionLevelHd30},
+ {3, OMX_VIDEO_DolbyVisionLevelFhd24},
+ {4, OMX_VIDEO_DolbyVisionLevelFhd30},
+ {5, OMX_VIDEO_DolbyVisionLevelFhd60},
+ {6, OMX_VIDEO_DolbyVisionLevelUhd24},
+ {7, OMX_VIDEO_DolbyVisionLevelUhd30},
+ {8, OMX_VIDEO_DolbyVisionLevelUhd48},
+ {9, OMX_VIDEO_DolbyVisionLevelUhd60},
+ };
+ // set rpuAssoc
+ if (rpu_present_flag && el_present_flag && !bl_present_flag) {
+ format->setInt32("rpuAssoc", 1);
+ }
+ // set profile & level if they are recognized
+ OMX_VIDEO_DOLBYVISIONPROFILETYPE codecProfile;
+ OMX_VIDEO_DOLBYVISIONLEVELTYPE codecLevel;
+ if (profiles.map(profile, &codecProfile)) {
+ format->setInt32("profile", codecProfile);
+ if (codecProfile == OMX_VIDEO_DolbyVisionProfileDvheSt ||
+ codecProfile == OMX_VIDEO_DolbyVisionProfileDvavSe) {
+ format->setInt32("bl_compatibility_id", bl_compatibility_id);
+ }
+ if (levels.map(level, &codecLevel)) {
+ format->setInt32("level", codecLevel);
+ }
+ }
+}
+
static void parseH263ProfileLevelFromD263(const uint8_t *ptr, size_t size, sp<AMessage> &format) {
if (size < 7) {
return;
@@ -689,6 +751,7 @@
{ "temporal-layer-id", kKeyTemporalLayerId },
{ "thumbnail-width", kKeyThumbnailWidth },
{ "thumbnail-height", kKeyThumbnailHeight },
+ { "track-id", kKeyTrackID },
{ "valid-samples", kKeyValidSamples },
}
};
@@ -896,12 +959,6 @@
msg->setInt32("is-sync-frame", 1);
}
- // this only needs to be translated from meta to message as it is an extractor key
- int32_t trackID;
- if (meta->findInt32(kKeyTrackID, &trackID)) {
- msg->setInt32("track-id", trackID);
- }
-
const char *lang;
if (meta->findCString(kKeyMediaLanguage, &lang)) {
msg->setString("language", lang);
@@ -1411,6 +1468,12 @@
msg->setBuffer("csd-0", buffer);
}
+ if (meta->findData(kKeyDVCC, &type, &data, &size)) {
+ const uint8_t *ptr = (const uint8_t *)data;
+ ALOGV("DV: calling parseDolbyVisionProfileLevelFromDvcc with data size %zu", size);
+ parseDolbyVisionProfileLevelFromDvcc(ptr, size, msg);
+ }
+
*format = msg;
return OK;
@@ -1806,7 +1869,7 @@
if (msg->findInt32("frame-rate", &fps) && fps > 0) {
meta->setInt32(kKeyFrameRate, fps);
} else if (msg->findFloat("frame-rate", &fpsFloat)
- && fpsFloat >= 1 && fpsFloat <= INT32_MAX) {
+ && fpsFloat >= 1 && fpsFloat <= (float)INT32_MAX) {
// truncate values to distinguish between e.g. 24 vs 23.976 fps
meta->setInt32(kKeyFrameRate, (int32_t)fpsFloat);
}
@@ -1839,6 +1902,31 @@
meta->setData(kKeyHVCC, kTypeHVCC, hvcc.data(), outsize);
} else if (mime == MEDIA_MIMETYPE_VIDEO_AV1) {
meta->setData(kKeyAV1C, 0, csd0->data(), csd0->size());
+ } else if (mime == MEDIA_MIMETYPE_VIDEO_DOLBY_VISION) {
+ if (msg->findBuffer("csd-2", &csd2)) {
+ //dvcc should be 24
+ if (csd2->size() == 24) {
+ meta->setData(kKeyDVCC, kTypeDVCC, csd2->data(), csd2->size());
+ uint8_t *dvcc = csd2->data();
+ const uint8_t profile = dvcc[2] >> 1;
+ if (profile > 1 && profile < 9) {
+ std::vector<uint8_t> hvcc(csd0size + 1024);
+ size_t outsize = reassembleHVCC(csd0, hvcc.data(), hvcc.size(), 4);
+ meta->setData(kKeyHVCC, kTypeHVCC, hvcc.data(), outsize);
+ } else if (DolbyVisionProfileDvav110 == profile) {
+ meta->setData(kKeyAV1C, 0, csd0->data(), csd0->size());
+ } else {
+ sp<ABuffer> csd1;
+ if (msg->findBuffer("csd-1", &csd1)) {
+ std::vector<char> avcc(csd0size + csd1->size() + 1024);
+ size_t outsize = reassembleAVCC(csd0, csd1, avcc.data());
+ meta->setData(kKeyAVCC, kTypeAVCC, avcc.data(), outsize);
+ }
+ }
+ }
+ } else {
+ ALOGW("We need csd-2!!. %s", msg->debugString().c_str());
+ }
} else if (mime == MEDIA_MIMETYPE_VIDEO_VP9) {
meta->setData(kKeyVp9CodecPrivate, 0, csd0->data(), csd0->size());
} else if (mime == MEDIA_MIMETYPE_AUDIO_OPUS) {
@@ -1885,8 +1973,18 @@
meta->setData(kKeyStreamHeader, 'mdat', csd0->data(), csd0->size());
} else if (msg->findBuffer("d263", &csd0)) {
meta->setData(kKeyD263, kTypeD263, csd0->data(), csd0->size());
- }
+ } else if (mime == MEDIA_MIMETYPE_VIDEO_DOLBY_VISION && msg->findBuffer("csd-2", &csd2)) {
+ meta->setData(kKeyDVCC, kTypeDVCC, csd2->data(), csd2->size());
+ // Remove CSD-2 from the data here to avoid duplicate data in meta
+ meta->remove(kKeyOpaqueCSD2);
+
+ if (msg->findBuffer("csd-avc", &csd0)) {
+ meta->setData(kKeyAVCC, kTypeAVCC, csd0->data(), csd0->size());
+ } else if (msg->findBuffer("csd-hevc", &csd0)) {
+ meta->setData(kKeyHVCC, kTypeHVCC, csd0->data(), csd0->size());
+ }
+ }
// XXX TODO add whatever other keys there are
#if 0
@@ -1895,22 +1993,6 @@
#endif
}
-AString MakeUserAgent() {
- AString ua;
- ua.append("stagefright/1.2 (Linux;Android ");
-
-#if (PROPERTY_VALUE_MAX < 8)
-#error "PROPERTY_VALUE_MAX must be at least 8"
-#endif
-
- char value[PROPERTY_VALUE_MAX];
- property_get("ro.build.version.release", value, "Unknown");
- ua.append(value);
- ua.append(")");
-
- return ua;
-}
-
status_t sendMetaDataToHal(sp<MediaPlayerBase::AudioSink>& sink,
const sp<MetaData>& meta)
{
@@ -2099,39 +2181,6 @@
return AudioSystem::isOffloadSupported(info);
}
-AString uriDebugString(const AString &uri, bool incognito) {
- if (incognito) {
- return AString("<URI suppressed>");
- }
-
- if (property_get_bool("media.stagefright.log-uri", false)) {
- return uri;
- }
-
- // find scheme
- AString scheme;
- const char *chars = uri.c_str();
- for (size_t i = 0; i < uri.size(); i++) {
- const char c = chars[i];
- if (!isascii(c)) {
- break;
- } else if (isalpha(c)) {
- continue;
- } else if (i == 0) {
- // first character must be a letter
- break;
- } else if (isdigit(c) || c == '+' || c == '.' || c =='-') {
- continue;
- } else if (c != ':') {
- break;
- }
- scheme = AString(uri, 0, i);
- scheme.append("://<suppressed>");
- return scheme;
- }
- return AString("<no-scheme URI suppressed>");
-}
-
HLSTime::HLSTime(const sp<AMessage>& meta) :
mSeq(-1),
mTimeUs(-1LL),
@@ -2230,36 +2279,4 @@
}
}
-AString nameForFd(int fd) {
- const size_t SIZE = 256;
- char buffer[SIZE];
- AString result;
- snprintf(buffer, SIZE, "/proc/%d/fd/%d", getpid(), fd);
- struct stat s;
- if (lstat(buffer, &s) == 0) {
- if ((s.st_mode & S_IFMT) == S_IFLNK) {
- char linkto[256];
- int len = readlink(buffer, linkto, sizeof(linkto));
- if(len > 0) {
- if(len > 255) {
- linkto[252] = '.';
- linkto[253] = '.';
- linkto[254] = '.';
- linkto[255] = 0;
- } else {
- linkto[len] = 0;
- }
- result.append(linkto);
- }
- } else {
- result.append("unexpected type for ");
- result.append(buffer);
- }
- } else {
- result.append("couldn't open ");
- result.append(buffer);
- }
- return result;
-}
-
} // namespace android
diff --git a/media/libstagefright/VideoFrameScheduler2.cpp b/media/libstagefright/VideoFrameScheduler2.cpp
deleted file mode 100644
index 23671f2..0000000
--- a/media/libstagefright/VideoFrameScheduler2.cpp
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "VideoFrameScheduler2"
-#include <utils/Log.h>
-#define ATRACE_TAG ATRACE_TAG_VIDEO
-#include <utils/Mutex.h>
-#include <utils/Thread.h>
-#include <utils/Trace.h>
-
-#include <algorithm>
-#include <jni.h>
-#include <math.h>
-
-#include <android/choreographer.h>
-#include <android/looper.h>
-#include <media/stagefright/VideoFrameScheduler2.h>
-#include <mediaplayer2/JavaVMHelper.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AUtils.h>
-
-namespace android {
-
-static void getVsyncOffset(nsecs_t* appVsyncOffsetPtr, nsecs_t* sfVsyncOffsetPtr);
-
-/* ======================================================================= */
-/* VsyncTracker */
-/* ======================================================================= */
-
-class VsyncTracker : public RefBase{
-public:
- VsyncTracker();
- ~VsyncTracker() {}
- nsecs_t getVsyncPeriod();
- nsecs_t getVsyncTime(nsecs_t periodOffset);
- void addSample(nsecs_t timestamp);
-
-private:
- static const int kMaxSamples = 32;
- static const int kMinSamplesForUpdate = 6;
- int mNumSamples;
- int mFirstSample;
- nsecs_t mReferenceTime;
- nsecs_t mPhase;
- nsecs_t mPeriod;
- nsecs_t mTimestampSamples[kMaxSamples];
- Mutex mLock;
-
- void updateModelLocked();
-};
-
-VsyncTracker::VsyncTracker()
- : mNumSamples(0),
- mFirstSample(0),
- mReferenceTime(0),
- mPhase(0),
- mPeriod(0) {
- for (int i = 0; i < kMaxSamples; i++) {
- mTimestampSamples[i] = 0;
- }
-}
-
-nsecs_t VsyncTracker::getVsyncPeriod() {
- Mutex::Autolock dataLock(mLock);
- return mPeriod;
-}
-
-nsecs_t VsyncTracker::getVsyncTime(nsecs_t periodOffset) {
- Mutex::Autolock dataLock(mLock);
- const nsecs_t now = systemTime();
- nsecs_t phase = mReferenceTime + mPhase;
-
- // result = (((now - phase) / mPeriod) + periodOffset + 1) * mPeriod + phase
- // prevent overflow
- nsecs_t result = (now - phase) / mPeriod;
- if (result > LONG_LONG_MAX - periodOffset - 1) {
- return LONG_LONG_MAX;
- } else {
- result += periodOffset + 1;
- }
- if (result > LONG_LONG_MAX / mPeriod) {
- return LONG_LONG_MAX;
- } else {
- result *= mPeriod;
- }
- if (result > LONG_LONG_MAX - phase) {
- return LONG_LONG_MAX;
- } else {
- result += phase;
- }
-
- return result;
-}
-
-void VsyncTracker::addSample(nsecs_t timestamp) {
- Mutex::Autolock dataLock(mLock);
- if (mNumSamples == 0) {
- mPhase = 0;
- mReferenceTime = timestamp;
- }
- int idx = (mFirstSample + mNumSamples) % kMaxSamples;
- mTimestampSamples[idx] = timestamp;
- if (mNumSamples < kMaxSamples) {
- mNumSamples++;
- } else {
- mFirstSample = (mFirstSample + 1) % kMaxSamples;
- }
- updateModelLocked();
-}
-
-void VsyncTracker::updateModelLocked() {
- if (mNumSamples < kMinSamplesForUpdate) {
- return;
- }
- nsecs_t durationSum = 0;
- nsecs_t minDuration = LONG_MAX;
- nsecs_t maxDuration = 0;
-
- for (int i = 1; i < mNumSamples; i++) {
- int idx = (mFirstSample + i) % kMaxSamples;
- int prev = (idx + kMaxSamples - 1) % kMaxSamples;
- long duration = mTimestampSamples[idx] - mTimestampSamples[prev];
- durationSum += duration;
- if (minDuration > duration) { minDuration = duration; }
- if (maxDuration < duration) { maxDuration = duration; }
- }
-
- durationSum -= (minDuration + maxDuration);
- mPeriod = durationSum / (mNumSamples - 3);
-
- double sampleAvgX = 0.0;
- double sampleAvgY = 0.0;
- double scale = 2.0 * M_PI / (double) mPeriod;
-
- for (int i = 1; i < mNumSamples; i++) {
- int idx = (mFirstSample + i) % kMaxSamples;
- long sample = mTimestampSamples[idx] - mReferenceTime;
- double samplePhase = (double) (sample % mPeriod) * scale;
- sampleAvgX += cos(samplePhase);
- sampleAvgY += sin(samplePhase);
- }
-
- sampleAvgX /= (double) mNumSamples - 1.0;
- sampleAvgY /= (double) mNumSamples - 1.0;
- mPhase = (long) (atan2(sampleAvgY, sampleAvgX) / scale);
-}
-
-static void frameCallback(int64_t frameTimeNanos, void* data) {
- if (data == NULL) {
- return;
- }
- sp<VsyncTracker> vsyncTracker(static_cast<VsyncTracker*>(data));
- vsyncTracker->addSample(frameTimeNanos);
- AChoreographer_postFrameCallback64(AChoreographer_getInstance(),
- frameCallback, static_cast<void*>(vsyncTracker.get()));
-}
-
-/* ======================================================================= */
-/* JNI */
-/* ======================================================================= */
-
-static void getVsyncOffset(nsecs_t* appVsyncOffsetPtr, nsecs_t* sfVsyncOffsetPtr) {
- static const nsecs_t kOneMillisecInNanosec = 1000000;
- static const nsecs_t kOneSecInNanosec = kOneMillisecInNanosec * 1000;
-
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jclass jDisplayManagerGlobalCls = env->FindClass(
- "android/hardware/display/DisplayManagerGlobal");
- jclass jDisplayCls = env->FindClass("android/view/Display");
-
- jmethodID jGetInstance = env->GetStaticMethodID(jDisplayManagerGlobalCls,
- "getInstance", "()Landroid/hardware/display/DisplayManagerGlobal;");
- jobject javaDisplayManagerGlobalObj = env->CallStaticObjectMethod(
- jDisplayManagerGlobalCls, jGetInstance);
-
- jfieldID jDEFAULT_DISPLAY = env->GetStaticFieldID(jDisplayCls, "DEFAULT_DISPLAY", "I");
- jint DEFAULT_DISPLAY = env->GetStaticIntField(jDisplayCls, jDEFAULT_DISPLAY);
-
- jmethodID jgetRealDisplay = env->GetMethodID(jDisplayManagerGlobalCls,
- "getRealDisplay", "(I)Landroid/view/Display;");
- jobject javaDisplayObj = env->CallObjectMethod(
- javaDisplayManagerGlobalObj, jgetRealDisplay, DEFAULT_DISPLAY);
-
- jmethodID jGetRefreshRate = env->GetMethodID(jDisplayCls, "getRefreshRate", "()F");
- jfloat javaRefreshRate = env->CallFloatMethod(javaDisplayObj, jGetRefreshRate);
- nsecs_t vsyncPeriod = (nsecs_t) (kOneSecInNanosec / (float) javaRefreshRate);
-
- jmethodID jGetAppVsyncOffsetNanos = env->GetMethodID(
- jDisplayCls, "getAppVsyncOffsetNanos", "()J");
- jlong javaAppVsyncOffset = env->CallLongMethod(javaDisplayObj, jGetAppVsyncOffsetNanos);
- *appVsyncOffsetPtr = (nsecs_t) javaAppVsyncOffset;
-
- jmethodID jGetPresentationDeadlineNanos = env->GetMethodID(
- jDisplayCls, "getPresentationDeadlineNanos", "()J");
- jlong javaPresentationDeadline = env->CallLongMethod(
- javaDisplayObj, jGetPresentationDeadlineNanos);
-
- *sfVsyncOffsetPtr = vsyncPeriod - ((nsecs_t) javaPresentationDeadline - kOneMillisecInNanosec);
-}
-
-/* ======================================================================= */
-/* Choreographer Thread */
-/* ======================================================================= */
-
-struct ChoreographerThread : public Thread {
- ChoreographerThread(bool canCallJava);
- status_t init(void* data);
- virtual status_t readyToRun() override;
- virtual bool threadLoop() override;
-
-protected:
- virtual ~ChoreographerThread() {}
-
-private:
- DISALLOW_EVIL_CONSTRUCTORS(ChoreographerThread);
- void* mData;
-};
-
-ChoreographerThread::ChoreographerThread(bool canCallJava) : Thread(canCallJava) {
-}
-
-status_t ChoreographerThread::init(void* data) {
- if (data == NULL) {
- return NO_INIT;
- }
- mData = data;
- return OK;
-}
-
-status_t ChoreographerThread::readyToRun() {
- ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
- if (AChoreographer_getInstance() == NULL) {
- return NO_INIT;
- }
- AChoreographer_postFrameCallback64(AChoreographer_getInstance(), frameCallback, mData);
- return OK;
-}
-
-bool ChoreographerThread::threadLoop() {
- ALooper_pollOnce(-1, nullptr, nullptr, nullptr);
- return true;
-}
-
-/* ======================================================================= */
-/* Frame Scheduler */
-/* ======================================================================= */
-
-VideoFrameScheduler2::VideoFrameScheduler2() : VideoFrameSchedulerBase() {
-
- getVsyncOffset(&mAppVsyncOffset, &mSfVsyncOffset);
-
- Mutex::Autolock threadLock(mLock);
- mChoreographerThread = new ChoreographerThread(true);
-
- mVsyncTracker = new VsyncTracker();
- if (mChoreographerThread->init(static_cast<void*>(mVsyncTracker.get())) != OK) {
- mChoreographerThread.clear();
- }
- if (mChoreographerThread != NULL && mChoreographerThread->run("Choreographer") != OK) {
- mChoreographerThread.clear();
- }
-}
-
-void VideoFrameScheduler2::updateVsync() {
- mVsyncTime = 0;
- mVsyncPeriod = 0;
-
- if (mVsyncTracker != NULL) {
- mVsyncPeriod = mVsyncTracker->getVsyncPeriod();
- mVsyncTime = mVsyncTracker->getVsyncTime(mSfVsyncOffset - mAppVsyncOffset);
- }
- mVsyncRefreshAt = systemTime(SYSTEM_TIME_MONOTONIC) + kVsyncRefreshPeriod;
-}
-
-void VideoFrameScheduler2::release() {
- // Do not change order
- {
- Mutex::Autolock threadLock(mLock);
- mChoreographerThread->requestExitAndWait();
- mChoreographerThread.clear();
- }
-
- mVsyncTracker.clear();
-}
-
-VideoFrameScheduler2::~VideoFrameScheduler2() {
- release();
-}
-
-} // namespace android
diff --git a/media/libstagefright/bqhelper/Android.bp b/media/libstagefright/bqhelper/Android.bp
index db67034..37e842a 100644
--- a/media/libstagefright/bqhelper/Android.bp
+++ b/media/libstagefright/bqhelper/Android.bp
@@ -1,10 +1,7 @@
-cc_library_shared {
- name: "libstagefright_bufferqueue_helper",
- vendor_available: true,
- vndk: {
- enabled: true,
- },
+cc_defaults {
+ name: "libstagefright_bufferqueue-defaults",
double_loadable: true,
+
srcs: [
"FrameDropper.cpp",
"GraphicBufferSource.cpp",
@@ -23,29 +20,17 @@
],
shared_libs: [
- "libbinder",
+ "libbase",
"libcutils",
"libhidlbase",
"libhidlmemory",
- "libhidltransport",
"liblog",
"libstagefright_foundation",
"libui",
"libutils",
"android.hardware.graphics.bufferqueue@1.0",
- // Following libs are from libgui_bufferqueue_static
"android.hardware.graphics.bufferqueue@2.0",
- "android.hidl.token@1.0-utils",
- "libbase",
- "libEGL",
- "libhwbinder",
- "libnativewindow",
- "libvndksupport",
- ],
-
- static_libs: [
- "libgui_bufferqueue_static"
],
export_shared_lib_headers: [
@@ -70,3 +55,60 @@
cfi: true,
},
}
+
+cc_library_shared {
+ name: "libstagefright_bufferqueue_helper",
+ defaults: ["libstagefright_bufferqueue-defaults"],
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ shared_libs: [ "libgui" ],
+ target: {
+ vendor: {
+ exclude_shared_libs: [
+ "libgui",
+ ],
+ static_libs: [
+ "libgui_bufferqueue_static",
+ ],
+ shared_libs: [
+ "android.hidl.token@1.0-utils",
+ "libEGL",
+ "libnativewindow",
+ "libvndksupport",
+ ],
+ cflags: [
+ "-DNO_BINDER",
+ ],
+ },
+ },
+}
+
+// This lib is needed on devices that doesn't use vndk,
+// on these devices we still don't want libgui to be pulled
+// in onto the apex build. It should only be used by
+// libcodec2_hidl@1.x, etc. from service side. It could
+// be removed if all builds are using vndk.
+cc_library_shared {
+ name: "libstagefright_bufferqueue_helper_novndk",
+ defaults: ["libstagefright_bufferqueue-defaults"],
+ apex_available: [
+ "com.android.media.swcodec",
+ "test_com.android.media.swcodec",
+ "//apex_available:platform",
+ ],
+ vendor_available: false,
+ static_libs: [
+ "libgui_bufferqueue_static",
+ ],
+ shared_libs: [
+ "android.hidl.token@1.0-utils",
+ "libEGL",
+ "libnativewindow",
+ "libvndksupport",
+ ],
+ cflags: [
+ "-DNO_BINDER",
+ ],
+}
diff --git a/media/libstagefright/bqhelper/GraphicBufferSource.cpp b/media/libstagefright/bqhelper/GraphicBufferSource.cpp
index 59317e7..986c9ac 100644
--- a/media/libstagefright/bqhelper/GraphicBufferSource.cpp
+++ b/media/libstagefright/bqhelper/GraphicBufferSource.cpp
@@ -29,6 +29,7 @@
#include <media/stagefright/foundation/ColorUtils.h>
#include <media/stagefright/foundation/FileDescriptor.h>
+#include <android-base/properties.h>
#include <media/hardware/MetadataBufferType.h>
#include <ui/GraphicBuffer.h>
#include <gui/BufferItem.h>
@@ -411,7 +412,7 @@
B2HGraphicBufferProducer(getIGraphicBufferProducer());
}
-Status GraphicBufferSource::start() {
+status_t GraphicBufferSource::start() {
Mutex::Autolock autoLock(mMutex);
ALOGV("--> start; available=%zu, submittable=%zd",
mAvailableBuffers.size(), mFreeCodecBuffers.size());
@@ -458,10 +459,10 @@
}
}
- return Status::ok();
+ return OK;
}
-Status GraphicBufferSource::stop() {
+status_t GraphicBufferSource::stop() {
ALOGV("stop");
Mutex::Autolock autoLock(mMutex);
@@ -471,10 +472,10 @@
// not loaded->idle.
mExecuting = false;
}
- return Status::ok();
+ return OK;
}
-Status GraphicBufferSource::release(){
+status_t GraphicBufferSource::release(){
sp<ALooper> looper;
{
Mutex::Autolock autoLock(mMutex);
@@ -500,26 +501,26 @@
if (looper != NULL) {
looper->stop();
}
- return Status::ok();
+ return OK;
}
-Status GraphicBufferSource::onInputBufferAdded(codec_buffer_id bufferId) {
+status_t GraphicBufferSource::onInputBufferAdded(codec_buffer_id bufferId) {
Mutex::Autolock autoLock(mMutex);
if (mExecuting) {
// This should never happen -- buffers can only be allocated when
// transitioning from "loaded" to "idle".
ALOGE("addCodecBuffer: buffer added while executing");
- return Status::fromServiceSpecificError(INVALID_OPERATION);
+ return INVALID_OPERATION;
}
ALOGV("addCodecBuffer: bufferId=%u", bufferId);
mFreeCodecBuffers.push_back(bufferId);
- return Status::ok();
+ return OK;
}
-Status GraphicBufferSource::onInputBufferEmptied(codec_buffer_id bufferId, int fenceFd) {
+status_t GraphicBufferSource::onInputBufferEmptied(codec_buffer_id bufferId, int fenceFd) {
Mutex::Autolock autoLock(mMutex);
FileDescriptor::Autoclose fence(fenceFd);
@@ -527,7 +528,7 @@
if (cbi < 0) {
// This should never happen.
ALOGE("onInputBufferEmptied: buffer not recognized (bufferId=%u)", bufferId);
- return Status::fromServiceSpecificError(BAD_VALUE);
+ return BAD_VALUE;
}
std::shared_ptr<AcquiredBuffer> buffer = mSubmittedCodecBuffers.valueAt(cbi);
@@ -547,13 +548,13 @@
ALOGV("onInputBufferEmptied: EOS null buffer (bufferId=%u@%zd)", bufferId, cbi);
}
// No GraphicBuffer to deal with, no additional input or output is expected, so just return.
- return Status::fromServiceSpecificError(BAD_VALUE);
+ return BAD_VALUE;
}
if (!mExecuting) {
// this is fine since this could happen when going from Idle to Loaded
ALOGV("onInputBufferEmptied: no longer executing (bufferId=%u@%zd)", bufferId, cbi);
- return Status::fromServiceSpecificError(OK);
+ return OK;
}
ALOGV("onInputBufferEmptied: bufferId=%d@%zd [slot=%d, useCount=%ld, handle=%p] acquired=%d",
@@ -583,7 +584,7 @@
}
// releaseReleasableBuffers_l();
- return Status::ok();
+ return OK;
}
void GraphicBufferSource::onDataspaceChanged_l(
@@ -800,6 +801,9 @@
}
}
+#ifdef __clang__
+__attribute__((no_sanitize("integer")))
+#endif
bool GraphicBufferSource::calculateCodecTimestamp_l(
nsecs_t bufferTimeNs, int64_t *codecTimeUs) {
int64_t timeUs = bufferTimeNs / 1000;
@@ -816,14 +820,15 @@
mPrevFrameUs = mBaseFrameUs =
std::llround((timeUs * mCaptureFps) / mFps);
mFrameCount = 0;
- } else {
- // snap to nearest capture point
+ } else if (mSnapTimestamps) {
double nFrames = (timeUs - mPrevCaptureUs) * mCaptureFps / 1000000;
if (nFrames < 0.5 - kTimestampFluctuation) {
// skip this frame as it's too close to previous capture
- ALOGD("skipping frame, timeUs %lld", static_cast<long long>(timeUs));
+ ALOGD("skipping frame, timeUs %lld",
+ static_cast<long long>(timeUs));
return false;
}
+ // snap to nearest capture point
if (nFrames <= 1.0) {
nFrames = 1.0;
}
@@ -832,6 +837,22 @@
mFrameCount * 1000000 / mCaptureFps);
mPrevFrameUs = mBaseFrameUs + std::llround(
mFrameCount * 1000000 / mFps);
+ } else {
+ if (timeUs <= mPrevCaptureUs) {
+ if (mFrameDropper != NULL && mFrameDropper->disabled()) {
+ // Warn only, client has disabled frame drop logic possibly for image
+ // encoding cases where camera's ZSL mode could send out of order frames.
+ ALOGW("Received frame that's going backward in time");
+ } else {
+ // Drop the frame if it's going backward in time. Bad timestamp
+ // could disrupt encoder's rate control completely.
+ ALOGW("Dropping frame that's going backward in time");
+ return false;
+ }
+ }
+ mPrevCaptureUs = timeUs;
+ mPrevFrameUs = mBaseFrameUs + std::llround(
+ (timeUs - mBaseCaptureUs) * (mCaptureFps / mFps));
}
ALOGV("timeUs %lld, captureUs %lld, frameUs %lld",
@@ -1359,6 +1380,12 @@
mFps = fps;
mCaptureFps = captureFps;
+ if (captureFps > fps) {
+ mSnapTimestamps = 1 == base::GetIntProperty(
+ "debug.stagefright.snap_timestamps", int64_t(0));
+ } else {
+ mSnapTimestamps = false;
+ }
return OK;
}
@@ -1396,7 +1423,7 @@
// stall since no future events are expected.
mEndOfStream = true;
- if (mStopTimeUs == -1 && mExecuting && !haveAvailableBuffers_l()) {
+ if (mExecuting && !haveAvailableBuffers_l()) {
submitEndOfInputStream_l();
}
diff --git a/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/GraphicBufferSource.h b/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/GraphicBufferSource.h
index b4c4d4a..fe6bcce 100644
--- a/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/GraphicBufferSource.h
+++ b/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/GraphicBufferSource.h
@@ -31,8 +31,6 @@
namespace android {
-using ::android::binder::Status;
-
struct FrameDropper;
class BufferItem;
class IGraphicBufferProducer;
@@ -99,26 +97,26 @@
// This is called when component transitions to running state, which means
// we can start handing it buffers. If we already have buffers of data
// sitting in the BufferQueue, this will send them to the codec.
- Status start();
+ status_t start();
// This is called when component transitions to stopped, indicating that
// the codec is meant to return all buffers back to the client for them
// to be freed. Do NOT submit any more buffers to the component.
- Status stop();
+ status_t stop();
// This is called when component transitions to released, indicating that
// we are shutting down.
- Status release();
+ status_t release();
// A "codec buffer", i.e. a buffer that can be used to pass data into
// the encoder, has been allocated. (This call does not call back into
// component.)
- Status onInputBufferAdded(int32_t bufferId);
+ status_t onInputBufferAdded(int32_t bufferId);
// Called when encoder is no longer using the buffer. If we have a BQ
// buffer available, fill it with a new frame of data; otherwise, just mark
// it as available.
- Status onInputBufferEmptied(int32_t bufferId, int fenceFd);
+ status_t onInputBufferEmptied(int32_t bufferId, int fenceFd);
// IGraphicBufferSource interface
// ------------------------------
@@ -461,12 +459,33 @@
// Slow motion mode is enabled if both encoding and capture frame rates are
// defined and the encoding frame rate is less than half the capture frame
// rate. In this mode, the source is expected to produce frames with an even
- // timestamp interval (after rounding) with the configured capture fps. The
- // first source timestamp is used as the source base time. Afterwards, the
- // timestamp of each source frame is snapped to the nearest expected capture
- // timestamp and scaled to match the configured encoding frame rate.
+ // timestamp interval (after rounding) with the configured capture fps.
+ //
+ // These modes must be configured by calling setTimeLapseConfig() before
+ // using this source.
+ //
+ // Timestamp snapping for slow motion recording
+ // ============================================
+ //
+ // When the slow motion mode is configured with setTimeLapseConfig(), the
+ // property "debug.stagefright.snap_timestamps" will be checked. If the
+ // value of the property is set to any value other than 1, mSnapTimestamps
+ // will be set to false. Otherwise, mSnapTimestamps will be set to true.
+ // (mSnapTimestamps will be false for time lapse recording regardless of the
+ // value of the property.)
+ //
+ // If mSnapTimestamps is true, i.e., timestamp snapping is enabled, the
+ // first source timestamp will be used as the source base time; afterwards,
+ // the timestamp of each source frame will be snapped to the nearest
+ // expected capture timestamp and scaled to match the configured encoding
+ // frame rate.
+ //
+ // If timestamp snapping is disabled, the timestamp of source frames will
+ // be scaled to match the ratio between the configured encoding frame rate
+ // and the configured capture frame rate.
- // These modes must be enabled before using this source.
+ // whether timestamps will be snapped
+ bool mSnapTimestamps{true};
// adjusted capture timestamp of the base frame
int64_t mBaseCaptureUs;
diff --git a/media/libstagefright/codecs/aacdec/DrcPresModeWrap.cpp b/media/libstagefright/codecs/aacdec/DrcPresModeWrap.cpp
index 95d3724..168d140 100644
--- a/media/libstagefright/codecs/aacdec/DrcPresModeWrap.cpp
+++ b/media/libstagefright/codecs/aacdec/DrcPresModeWrap.cpp
@@ -47,10 +47,9 @@
mEncoderTarget = -1;
/* Values from last time. */
- /* Initialized to the same values as the desired values */
- mLastTarget = -1;
- mLastAttFactor = 0;
- mLastBoostFactor = 0;
+ mLastTarget = -2;
+ mLastAttFactor = -1;
+ mLastBoostFactor = -1;
mLastHeavy = 0;
}
@@ -163,7 +162,7 @@
if (mDataUpdate) {
// sanity check
- if (mDesTarget < MAX_TARGET_LEVEL){
+ if ((mDesTarget < MAX_TARGET_LEVEL) && (mDesTarget != -1)){
mDesTarget = MAX_TARGET_LEVEL; // limit target level to -10 dB or below
newTarget = MAX_TARGET_LEVEL;
}
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index 41bc16c..2aeddd7 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -37,6 +37,7 @@
#define DRC_DEFAULT_MOBILE_DRC_BOOST 127 /* maximum compression of dynamic range for mobile conf */
#define DRC_DEFAULT_MOBILE_DRC_HEAVY 1 /* switch for heavy compression for mobile conf */
#define DRC_DEFAULT_MOBILE_DRC_EFFECT 3 /* MPEG-D DRC effect type; 3 => Limited playback range */
+#define DRC_DEFAULT_MOBILE_DRC_ALBUM 0 /* MPEG-D DRC album mode; 0 => album mode is disabled, 1 => album mode is enabled */
#define DRC_DEFAULT_MOBILE_ENC_LEVEL (-1) /* encoder target level; -1 => the value is unknown, otherwise dB step value (e.g. 64 for -16 dB) */
#define MAX_CHANNEL_COUNT 8 /* maximum number of audio channels that can be decoded */
// names of properties that can be used to override the default DRC settings
@@ -219,6 +220,11 @@
ALOGV("AAC decoder using MPEG-D DRC effect type %d (default=%d)",
effectType, DRC_DEFAULT_MOBILE_DRC_EFFECT);
aacDecoder_SetParam(mAACDecoder, AAC_UNIDRC_SET_EFFECT, effectType);
+ // AAC_UNIDRC_ALBUM_MODE
+ int32_t albumMode = DRC_DEFAULT_MOBILE_DRC_ALBUM;
+ ALOGV("AAC decoder using MPEG-D Album mode value %d (default=%d)", albumMode,
+ DRC_DEFAULT_MOBILE_DRC_ALBUM);
+ aacDecoder_SetParam(mAACDecoder, AAC_UNIDRC_ALBUM_MODE, albumMode);
// By default, the decoder creates a 5.1 channel downmix signal.
// For seven and eight channel input streams, enable 6.1 and 7.1 channel output
@@ -459,6 +465,11 @@
ALOGV("set nDrcEffectType=%d", aacPresParams->nDrcEffectType);
aacDecoder_SetParam(mAACDecoder, AAC_UNIDRC_SET_EFFECT, aacPresParams->nDrcEffectType);
}
+ if (aacPresParams->nDrcAlbumMode >= -1) {
+ ALOGV("set nDrcAlbumMode=%d", aacPresParams->nDrcAlbumMode);
+ aacDecoder_SetParam(mAACDecoder, AAC_UNIDRC_ALBUM_MODE,
+ aacPresParams->nDrcAlbumMode);
+ }
bool updateDrcWrapper = false;
if (aacPresParams->nDrcBoost >= 0) {
ALOGV("set nDrcBoost=%d", aacPresParams->nDrcBoost);
@@ -477,7 +488,7 @@
aacPresParams->nHeavyCompression);
updateDrcWrapper = true;
}
- if (aacPresParams->nTargetReferenceLevel >= 0) {
+ if (aacPresParams->nTargetReferenceLevel >= -1) {
ALOGV("set nTargetReferenceLevel=%d", aacPresParams->nTargetReferenceLevel);
mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_TARGET,
aacPresParams->nTargetReferenceLevel);
diff --git a/media/libstagefright/codecs/amrnb/common/Android.bp b/media/libstagefright/codecs/amrnb/common/Android.bp
index 772ebf9..bcf63d5 100644
--- a/media/libstagefright/codecs/amrnb/common/Android.bp
+++ b/media/libstagefright/codecs/amrnb/common/Android.bp
@@ -1,6 +1,7 @@
-cc_library_shared {
+cc_library {
name: "libstagefright_amrnb_common",
vendor_available: true,
+ host_supported: true,
srcs: [
"src/add.cpp",
@@ -73,6 +74,12 @@
"-Werror",
],
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+
//addressing b/25409744
//sanitize: {
// misc_undefined: [
diff --git a/media/libstagefright/codecs/amrnb/dec/Android.bp b/media/libstagefright/codecs/amrnb/dec/Android.bp
index e18117e..3381d2e 100644
--- a/media/libstagefright/codecs/amrnb/dec/Android.bp
+++ b/media/libstagefright/codecs/amrnb/dec/Android.bp
@@ -1,6 +1,7 @@
cc_library_static {
name: "libstagefright_amrnbdec",
vendor_available: true,
+ host_supported: true,
srcs: [
"src/a_refl.cpp",
@@ -61,6 +62,12 @@
"libstagefright_amrnb_common",
"liblog",
],
+
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
}
//###############################################################################
@@ -100,6 +107,7 @@
cc_test {
name: "libstagefright_amrnbdec_test",
gtest: false,
+ host_supported: true,
srcs: ["test/amrnbdec_test.cpp"],
@@ -118,6 +126,12 @@
"liblog",
],
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+
//sanitize: {
// misc_undefined: [
// "signed-integer-overflow",
diff --git a/media/libstagefright/codecs/amrnb/dec/test/AmrnbDecTestEnvironment.h b/media/libstagefright/codecs/amrnb/dec/test/AmrnbDecTestEnvironment.h
new file mode 100644
index 0000000..0344ac5
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/dec/test/AmrnbDecTestEnvironment.h
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#ifndef __AMRNBDEC_TEST_ENVIRONMENT_H__
+#define __AMRNBDEC_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class AmrnbDecTestEnvironment : public ::testing::Environment {
+ public:
+ AmrnbDecTestEnvironment() : res("/data/local/tmp/") {}
+
+ // Parses the command line arguments
+ int initFromOptions(int argc, char **argv);
+
+ void setRes(const char *_res) { res = _res; }
+
+ const string getRes() const { return res; }
+
+ private:
+ string res;
+};
+
+int AmrnbDecTestEnvironment::initFromOptions(int argc, char **argv) {
+ static struct option options[] = {{"res", required_argument, 0, 'P'}, {0, 0, 0, 0}};
+
+ while (true) {
+ int index = 0;
+ int c = getopt_long(argc, argv, "P:", options, &index);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'P':
+ setRes(optarg);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (optind < argc) {
+ fprintf(stderr,
+ "unrecognized option: %s\n\n"
+ "usage: %s <gtest options> <test options>\n\n"
+ "test options are:\n\n"
+ "-P, --path: Resource files directory location\n",
+ argv[optind ?: 1], argv[0]);
+ return 2;
+ }
+ return 0;
+}
+
+#endif // __AMRNBDEC_TEST_ENVIRONMENT_H__
diff --git a/media/libstagefright/codecs/amrnb/dec/test/AmrnbDecoderTest.cpp b/media/libstagefright/codecs/amrnb/dec/test/AmrnbDecoderTest.cpp
new file mode 100644
index 0000000..af62074
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/dec/test/AmrnbDecoderTest.cpp
@@ -0,0 +1,175 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AmrnbDecoderTest"
+#define OUTPUT_FILE "/data/local/tmp/amrnbDecode.out"
+
+#include <utils/Log.h>
+
+#include <audio_utils/sndfile.h>
+#include <stdio.h>
+
+#include "gsmamr_dec.h"
+
+#include "AmrnbDecTestEnvironment.h"
+
+// Constants for AMR-NB
+constexpr int32_t kInputBufferSize = 64;
+constexpr int32_t kSamplesPerFrame = L_FRAME;
+constexpr int32_t kBitsPerSample = 16;
+constexpr int32_t kSampleRate = 8000;
+constexpr int32_t kChannels = 1;
+constexpr int32_t kOutputBufferSize = kSamplesPerFrame * kBitsPerSample / 8;
+const int32_t kFrameSizes[] = {12, 13, 15, 17, 19, 20, 26, 31, -1, -1, -1, -1, -1, -1, -1, -1};
+
+constexpr int32_t kNumFrameReset = 150;
+
+static AmrnbDecTestEnvironment *gEnv = nullptr;
+
+class AmrnbDecoderTest : public ::testing::TestWithParam<string> {
+ public:
+ AmrnbDecoderTest() : mFpInput(nullptr) {}
+
+ ~AmrnbDecoderTest() {
+ if (mFpInput) {
+ fclose(mFpInput);
+ mFpInput = nullptr;
+ }
+ }
+
+ FILE *mFpInput;
+ SNDFILE *openOutputFile(SF_INFO *sfInfo);
+ int32_t DecodeFrames(void *amrHandle, SNDFILE *outFileHandle, int32_t frameCount = INT32_MAX);
+};
+
+SNDFILE *AmrnbDecoderTest::openOutputFile(SF_INFO *sfInfo) {
+ memset(sfInfo, 0, sizeof(SF_INFO));
+ sfInfo->channels = kChannels;
+ sfInfo->format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
+ sfInfo->samplerate = kSampleRate;
+ SNDFILE *outFileHandle = sf_open(OUTPUT_FILE, SFM_WRITE, sfInfo);
+ return outFileHandle;
+}
+
+int32_t AmrnbDecoderTest::DecodeFrames(void *amrHandle, SNDFILE *outFileHandle,
+ int32_t frameCount) {
+ uint8_t inputBuf[kInputBufferSize];
+ int16_t outputBuf[kOutputBufferSize];
+
+ while (frameCount > 0) {
+ uint8_t mode;
+ int32_t bytesRead = fread(&mode, 1, 1, mFpInput);
+ if (bytesRead != 1) break;
+
+ // Find frame type
+ Frame_Type_3GPP frameType = (Frame_Type_3GPP)((mode >> 3) & 0x0f);
+ int32_t frameSize = kFrameSizes[frameType];
+ if (frameSize < 0) {
+ ALOGE("Illegal frame type");
+ return -1;
+ }
+ bytesRead = fread(inputBuf, 1, frameSize, mFpInput);
+ if (bytesRead != frameSize) break;
+
+ int32_t bytesDecoded = AMRDecode(amrHandle, frameType, inputBuf, outputBuf, MIME_IETF);
+ if (bytesDecoded == -1) {
+ ALOGE("Failed to decode the input file");
+ return -1;
+ }
+
+ sf_writef_short(outFileHandle, outputBuf, kSamplesPerFrame);
+ frameCount--;
+ }
+ return 0;
+}
+
+TEST_F(AmrnbDecoderTest, CreateAmrnbDecoderTest) {
+ void *amrHandle;
+ int32_t status = GSMInitDecode(&amrHandle, (Word8 *)"AMRNBDecoder");
+ ASSERT_EQ(status, 0) << "Error creating AMR-NB decoder";
+ GSMDecodeFrameExit(&amrHandle);
+ ASSERT_EQ(amrHandle, nullptr) << "Error deleting AMR-NB decoder";
+}
+
+TEST_P(AmrnbDecoderTest, DecodeTest) {
+ string inputFile = gEnv->getRes() + GetParam();
+ mFpInput = fopen(inputFile.c_str(), "rb");
+ ASSERT_NE(mFpInput, nullptr) << "Error opening input file " << inputFile;
+
+ // Open the output file.
+ SF_INFO sfInfo;
+ SNDFILE *outFileHandle = openOutputFile(&sfInfo);
+ ASSERT_NE(outFileHandle, nullptr) << "Error opening output file for writing decoded output";
+
+ void *amrHandle;
+ int32_t status = GSMInitDecode(&amrHandle, (Word8 *)"AMRNBDecoder");
+ ASSERT_EQ(status, 0) << "Error creating AMR-NB decoder";
+
+ // Decode
+ int32_t decoderErr = DecodeFrames(amrHandle, outFileHandle);
+ ASSERT_EQ(decoderErr, 0) << "DecodeFrames returned error";
+
+ sf_close(outFileHandle);
+ GSMDecodeFrameExit(&amrHandle);
+ ASSERT_EQ(amrHandle, nullptr) << "Error deleting AMR-NB decoder";
+}
+
+TEST_P(AmrnbDecoderTest, ResetDecodeTest) {
+ string inputFile = gEnv->getRes() + GetParam();
+ mFpInput = fopen(inputFile.c_str(), "rb");
+ ASSERT_NE(mFpInput, nullptr) << "Error opening input file " << inputFile;
+
+ // Open the output file.
+ SF_INFO sfInfo;
+ SNDFILE *outFileHandle = openOutputFile(&sfInfo);
+ ASSERT_NE(outFileHandle, nullptr) << "Error opening output file for writing decoded output";
+
+ void *amrHandle;
+ int32_t status = GSMInitDecode(&amrHandle, (Word8 *)"AMRNBDecoder");
+ ASSERT_EQ(status, 0) << "Error creating AMR-NB decoder";
+
+ // Decode kNumFrameReset first
+ int32_t decoderErr = DecodeFrames(amrHandle, outFileHandle, kNumFrameReset);
+ ASSERT_EQ(decoderErr, 0) << "DecodeFrames returned error";
+
+ status = Speech_Decode_Frame_reset(amrHandle);
+ ASSERT_EQ(status, 0) << "Error resting AMR-NB decoder";
+
+ // Start decoding again
+ decoderErr = DecodeFrames(amrHandle, outFileHandle);
+ ASSERT_EQ(decoderErr, 0) << "DecodeFrames returned error";
+
+ sf_close(outFileHandle);
+ GSMDecodeFrameExit(&amrHandle);
+ ASSERT_EQ(amrHandle, nullptr) << "Error deleting AMR-NB decoder";
+}
+
+INSTANTIATE_TEST_SUITE_P(AmrnbDecoderTestAll, AmrnbDecoderTest,
+ ::testing::Values(("bbb_8000hz_1ch_8kbps_amrnb_30sec.amrnb"),
+ ("sine_amrnb_1ch_12kbps_8000hz.amrnb")));
+
+int main(int argc, char **argv) {
+ gEnv = new AmrnbDecTestEnvironment();
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = gEnv->initFromOptions(argc, argv);
+ if (status == 0) {
+ status = RUN_ALL_TESTS();
+ ALOGV("Test result = %d\n", status);
+ }
+ return status;
+}
diff --git a/media/libstagefright/codecs/amrnb/dec/test/Android.bp b/media/libstagefright/codecs/amrnb/dec/test/Android.bp
new file mode 100644
index 0000000..7a95cfa
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/dec/test/Android.bp
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+cc_test {
+ name: "AmrnbDecoderTest",
+ gtest: true,
+
+ srcs: [
+ "AmrnbDecoderTest.cpp",
+ ],
+
+ static_libs: [
+ "libstagefright_amrnb_common",
+ "libstagefright_amrnbdec",
+ "libaudioutils",
+ "libsndfile",
+ ],
+
+ shared_libs: [
+ "liblog",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ sanitize: {
+ cfi: true,
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ },
+}
diff --git a/media/libstagefright/codecs/amrnb/dec/test/README.md b/media/libstagefright/codecs/amrnb/dec/test/README.md
new file mode 100644
index 0000000..62e13ae
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/dec/test/README.md
@@ -0,0 +1,34 @@
+## Media Testing ##
+---
+#### AMR-NB Decoder :
+The Amr-Nb Decoder Test Suite validates the amrnb decoder available in libstagefright.
+
+Run the following steps to build the test suite:
+```
+m AmrnbDecoderTest
+```
+
+The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/
+
+The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/
+
+To test 64-bit binary push binaries from nativetest64.
+```
+adb push ${OUT}/data/nativetest64/AmrnbDecoderTest/AmrnbDecoderTest /data/local/tmp/
+```
+
+To test 32-bit binary push binaries from nativetest.
+```
+adb push ${OUT}/data/nativetest/AmrnbDecoderTest/AmrnbDecoderTest /data/local/tmp/
+```
+
+The resource file for the tests is taken from [here](https://drive.google.com/drive/folders/13cM4tAaVFrmr-zGFqaAzFBbKs75pnm9b). Push these files into device for testing.
+Download amr-nb folder and push all the files in this folder to /data/local/tmp/ on the device.
+```
+adb push amr-nb/. /data/local/tmp/
+```
+
+usage: AmrnbDecoderTest -P \<path_to_folder\>
+```
+adb shell /data/local/tmp/AmrnbDecoderTest -P /data/local/tmp/
+```
diff --git a/media/libstagefright/codecs/amrnb/enc/test/AmrnbEncTestEnvironment.h b/media/libstagefright/codecs/amrnb/enc/test/AmrnbEncTestEnvironment.h
new file mode 100644
index 0000000..5a2fcd1
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/enc/test/AmrnbEncTestEnvironment.h
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#ifndef __AMRNBENC_TEST_ENVIRONMENT_H__
+#define __AMRNBENC_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class AmrnbEncTestEnvironment : public ::testing::Environment {
+ public:
+ AmrnbEncTestEnvironment() : res("/data/local/tmp/") {}
+
+ // Parses the command line arguments
+ int initFromOptions(int argc, char **argv);
+
+ void setRes(const char *_res) { res = _res; }
+
+ const string getRes() const { return res; }
+
+ private:
+ string res;
+};
+
+int AmrnbEncTestEnvironment::initFromOptions(int argc, char **argv) {
+ static struct option options[] = {{"res", required_argument, 0, 'P'}, {0, 0, 0, 0}};
+
+ while (true) {
+ int index = 0;
+ int c = getopt_long(argc, argv, "P:", options, &index);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'P':
+ setRes(optarg);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (optind < argc) {
+ fprintf(stderr,
+ "unrecognized option: %s\n\n"
+ "usage: %s <gtest options> <test options>\n\n"
+ "test options are:\n\n"
+ "-P, --path: Resource files directory location\n",
+ argv[optind ?: 1], argv[0]);
+ return 2;
+ }
+ return 0;
+}
+
+#endif // __AMRNBENC_TEST_ENVIRONMENT_H__
diff --git a/media/libstagefright/codecs/amrnb/enc/test/AmrnbEncoderTest.cpp b/media/libstagefright/codecs/amrnb/enc/test/AmrnbEncoderTest.cpp
new file mode 100644
index 0000000..fb72998
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/enc/test/AmrnbEncoderTest.cpp
@@ -0,0 +1,207 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AmrnbEncoderTest"
+
+#include <utils/Log.h>
+
+#include <audio_utils/sndfile.h>
+#include <stdio.h>
+
+#include "gsmamr_enc.h"
+
+#include "AmrnbEncTestEnvironment.h"
+
+#define OUTPUT_FILE "/data/local/tmp/amrnbEncode.out"
+
+constexpr int32_t kInputBufferSize = L_FRAME * 2; // 160 samples * 16-bit per sample.
+constexpr int32_t kOutputBufferSize = 1024;
+constexpr int32_t kNumFrameReset = 200;
+constexpr int32_t kMaxCount = 10;
+struct AmrNbEncState {
+ void *encCtx;
+ void *pidSyncCtx;
+};
+
+static AmrnbEncTestEnvironment *gEnv = nullptr;
+
+class AmrnbEncoderTest : public ::testing::TestWithParam<pair<string, int32_t>> {
+ public:
+ AmrnbEncoderTest() : mAmrEncHandle(nullptr) {}
+
+ ~AmrnbEncoderTest() {
+ if (mAmrEncHandle) {
+ free(mAmrEncHandle);
+ mAmrEncHandle = nullptr;
+ }
+ }
+
+ AmrNbEncState *mAmrEncHandle;
+ int32_t EncodeFrames(int32_t mode, FILE *fpInput, FILE *mFpOutput,
+ int32_t frameCount = INT32_MAX);
+};
+
+int32_t AmrnbEncoderTest::EncodeFrames(int32_t mode, FILE *fpInput, FILE *mFpOutput,
+ int32_t frameCount) {
+ int32_t frameNum = 0;
+ uint16_t inputBuf[kInputBufferSize];
+ uint8_t outputBuf[kOutputBufferSize];
+ while (frameNum < frameCount) {
+ int32_t bytesRead = fread(inputBuf, 1, kInputBufferSize, fpInput);
+ if (bytesRead != kInputBufferSize && !feof(fpInput)) {
+ ALOGE("Unable to read data from input file");
+ return -1;
+ } else if (feof(fpInput) && bytesRead == 0) {
+ break;
+ }
+ Frame_Type_3GPP frame_type = (Frame_Type_3GPP)mode;
+ int32_t bytesGenerated =
+ AMREncode(mAmrEncHandle->encCtx, mAmrEncHandle->pidSyncCtx, (Mode)mode,
+ (Word16 *)inputBuf, outputBuf, &frame_type, AMR_TX_WMF);
+ frameNum++;
+ if (bytesGenerated < 0) {
+ ALOGE("Error in encoging the file: Invalid output format");
+ return -1;
+ }
+
+ // Convert from WMF to RFC 3267 format.
+ if (bytesGenerated > 0) {
+ outputBuf[0] = ((outputBuf[0] << 3) | 4) & 0x7c;
+ }
+ fwrite(outputBuf, 1, bytesGenerated, mFpOutput);
+ }
+ return 0;
+}
+
+TEST_F(AmrnbEncoderTest, CreateAmrnbEncoderTest) {
+ mAmrEncHandle = (AmrNbEncState *)malloc(sizeof(AmrNbEncState));
+ ASSERT_NE(mAmrEncHandle, nullptr) << "Error in allocating memory to Codec handle";
+ for (int count = 0; count < kMaxCount; count++) {
+ int32_t status = AMREncodeInit(&mAmrEncHandle->encCtx, &mAmrEncHandle->pidSyncCtx, 0);
+ ASSERT_EQ(status, 0) << "Error creating AMR-NB encoder";
+ ALOGV("Successfully created encoder");
+ }
+ if (mAmrEncHandle) {
+ AMREncodeExit(&mAmrEncHandle->encCtx, &mAmrEncHandle->pidSyncCtx);
+ ASSERT_EQ(mAmrEncHandle->encCtx, nullptr) << "Error deleting AMR-NB encoder";
+ ASSERT_EQ(mAmrEncHandle->pidSyncCtx, nullptr) << "Error deleting AMR-NB encoder";
+ free(mAmrEncHandle);
+ mAmrEncHandle = nullptr;
+ ALOGV("Successfully deleted encoder");
+ }
+}
+
+TEST_P(AmrnbEncoderTest, EncodeTest) {
+ mAmrEncHandle = (AmrNbEncState *)malloc(sizeof(AmrNbEncState));
+ ASSERT_NE(mAmrEncHandle, nullptr) << "Error in allocating memory to Codec handle";
+ int32_t status = AMREncodeInit(&mAmrEncHandle->encCtx, &mAmrEncHandle->pidSyncCtx, 0);
+ ASSERT_EQ(status, 0) << "Error creating AMR-NB encoder";
+
+ string inputFile = gEnv->getRes() + GetParam().first;
+ FILE *fpInput = fopen(inputFile.c_str(), "rb");
+ ASSERT_NE(fpInput, nullptr) << "Error opening input file " << inputFile;
+
+ FILE *fpOutput = fopen(OUTPUT_FILE, "wb");
+ ASSERT_NE(fpOutput, nullptr) << "Error opening output file " << OUTPUT_FILE;
+
+ // Write file header.
+ fwrite("#!AMR\n", 1, 6, fpOutput);
+
+ int32_t mode = GetParam().second;
+ int32_t encodeErr = EncodeFrames(mode, fpInput, fpOutput);
+ ASSERT_EQ(encodeErr, 0) << "EncodeFrames returned error for Codec mode: " << mode;
+
+ fclose(fpOutput);
+ fclose(fpInput);
+
+ AMREncodeExit(&mAmrEncHandle->encCtx, &mAmrEncHandle->pidSyncCtx);
+ ASSERT_EQ(mAmrEncHandle->encCtx, nullptr) << "Error deleting AMR-NB encoder";
+ ASSERT_EQ(mAmrEncHandle->pidSyncCtx, nullptr) << "Error deleting AMR-NB encoder";
+ free(mAmrEncHandle);
+ mAmrEncHandle = nullptr;
+ ALOGV("Successfully deleted encoder");
+}
+
+TEST_P(AmrnbEncoderTest, ResetEncoderTest) {
+ mAmrEncHandle = (AmrNbEncState *)malloc(sizeof(AmrNbEncState));
+ ASSERT_NE(mAmrEncHandle, nullptr) << "Error in allocating memory to Codec handle";
+ int32_t status = AMREncodeInit(&mAmrEncHandle->encCtx, &mAmrEncHandle->pidSyncCtx, 0);
+ ASSERT_EQ(status, 0) << "Error creating AMR-NB encoder";
+
+ string inputFile = gEnv->getRes() + GetParam().first;
+ FILE *fpInput = fopen(inputFile.c_str(), "rb");
+ ASSERT_NE(fpInput, nullptr) << "Error opening input file " << inputFile;
+
+ FILE *fpOutput = fopen(OUTPUT_FILE, "wb");
+ ASSERT_NE(fpOutput, nullptr) << "Error opening output file " << OUTPUT_FILE;
+
+ // Write file header.
+ fwrite("#!AMR\n", 1, 6, fpOutput);
+
+ int32_t mode = GetParam().second;
+ // Encode kNumFrameReset first
+ int32_t encodeErr = EncodeFrames(mode, fpInput, fpOutput, kNumFrameReset);
+ ASSERT_EQ(encodeErr, 0) << "EncodeFrames returned error for Codec mode: " << mode;
+
+ status = AMREncodeReset(mAmrEncHandle->encCtx, mAmrEncHandle->pidSyncCtx);
+ ASSERT_EQ(status, 0) << "Error resting AMR-NB encoder";
+
+ // Start encoding again
+ encodeErr = EncodeFrames(mode, fpInput, fpOutput);
+ ASSERT_EQ(encodeErr, 0) << "EncodeFrames returned error for Codec mode: " << mode;
+
+ fclose(fpOutput);
+ fclose(fpInput);
+
+ AMREncodeExit(&mAmrEncHandle->encCtx, &mAmrEncHandle->pidSyncCtx);
+ ASSERT_EQ(mAmrEncHandle->encCtx, nullptr) << "Error deleting AMR-NB encoder";
+ ASSERT_EQ(mAmrEncHandle->pidSyncCtx, nullptr) << "Error deleting AMR-NB encoder";
+ free(mAmrEncHandle);
+ mAmrEncHandle = nullptr;
+ ALOGV("Successfully deleted encoder");
+}
+
+// TODO: Add more test vectors
+INSTANTIATE_TEST_SUITE_P(AmrnbEncoderTestAll, AmrnbEncoderTest,
+ ::testing::Values(make_pair("bbb_raw_1ch_8khz_s16le.raw", MR475),
+ make_pair("bbb_raw_1ch_8khz_s16le.raw", MR515),
+ make_pair("bbb_raw_1ch_8khz_s16le.raw", MR59),
+ make_pair("bbb_raw_1ch_8khz_s16le.raw", MR67),
+ make_pair("bbb_raw_1ch_8khz_s16le.raw", MR74),
+ make_pair("bbb_raw_1ch_8khz_s16le.raw", MR795),
+ make_pair("bbb_raw_1ch_8khz_s16le.raw", MR102),
+ make_pair("bbb_raw_1ch_8khz_s16le.raw", MR122),
+ make_pair("sinesweepraw.raw", MR475),
+ make_pair("sinesweepraw.raw", MR515),
+ make_pair("sinesweepraw.raw", MR59),
+ make_pair("sinesweepraw.raw", MR67),
+ make_pair("sinesweepraw.raw", MR74),
+ make_pair("sinesweepraw.raw", MR795),
+ make_pair("sinesweepraw.raw", MR102),
+ make_pair("sinesweepraw.raw", MR122)));
+
+int main(int argc, char **argv) {
+ gEnv = new AmrnbEncTestEnvironment();
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = gEnv->initFromOptions(argc, argv);
+ if (status == 0) {
+ status = RUN_ALL_TESTS();
+ ALOGV("Test result = %d\n", status);
+ }
+ return status;
+}
diff --git a/media/libstagefright/codecs/amrnb/enc/test/Android.bp b/media/libstagefright/codecs/amrnb/enc/test/Android.bp
new file mode 100644
index 0000000..e8982fe
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/enc/test/Android.bp
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+cc_test {
+ name: "AmrnbEncoderTest",
+ gtest: true,
+
+ srcs: [
+ "AmrnbEncoderTest.cpp",
+ ],
+
+ static_libs: [
+ "libstagefright_amrnb_common",
+ "libstagefright_amrnbenc",
+ "libaudioutils",
+ "libsndfile",
+ ],
+
+ shared_libs: [
+ "liblog",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ sanitize: {
+ cfi: true,
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ },
+}
diff --git a/media/libstagefright/codecs/amrnb/enc/test/AndroidTest.xml b/media/libstagefright/codecs/amrnb/enc/test/AndroidTest.xml
new file mode 100644
index 0000000..9fe61b1
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/enc/test/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Test module config for Amr-nb Encoder unit test">
+ <option name="test-suite-tag" value="AmrnbEncoderTest" />
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="AmrnbEncoderTest->/data/local/tmp/AmrnbEncoderTest" />
+ <option name="push-file"
+ key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/amrnb/enc/test/AmrnbEncoderTest.zip?unzip=true"
+ value="/data/local/tmp/AmrnbEncoderTestRes/" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="AmrnbEncoderTest" />
+ <option name="native-test-flag" value="-P /data/local/tmp/AmrnbEncoderTestRes/" />
+ </test>
+</configuration>
diff --git a/media/libstagefright/codecs/amrnb/enc/test/README.md b/media/libstagefright/codecs/amrnb/enc/test/README.md
new file mode 100644
index 0000000..e9d2c95
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/enc/test/README.md
@@ -0,0 +1,39 @@
+## Media Testing ##
+---
+#### AMR-NB Encoder :
+The Amr-Nb Encoder Test Suite validates the amrnb encoder available in libstagefright.
+
+Run the following steps to build the test suite:
+```
+m AmrnbEncoderTest
+```
+
+The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/
+
+The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/
+
+To test 64-bit binary push binaries from nativetest64.
+```
+adb push ${OUT}/data/nativetest64/AmrnbEncoderTest/AmrnbEncoderTest /data/local/tmp/
+```
+
+To test 32-bit binary push binaries from nativetest.
+```
+adb push ${OUT}/data/nativetest/AmrnbEncoderTest/AmrnbEncoderTest /data/local/tmp/
+```
+
+The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/amrnb/enc/test/AmrnbEncoderTest.zip). Download, unzip and push these files into device for testing.
+
+```
+adb push AmrnbEncoderTestRes/. /data/local/tmp/
+```
+
+usage: AmrnbEncoderTest -P \<path_to_folder\>
+```
+adb shell /data/local/tmp/AmrnbEncoderTest -P /data/local/tmp/AmrnbEncoderTestRes/
+```
+Alternatively, the test can also be run using atest command.
+
+```
+atest AmrnbEncoderTest -- --enable-module-dynamic-download=true
+```
diff --git a/media/libstagefright/codecs/amrnb/fuzzer/Android.bp b/media/libstagefright/codecs/amrnb/fuzzer/Android.bp
new file mode 100644
index 0000000..54de1cc
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/fuzzer/Android.bp
@@ -0,0 +1,37 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *****************************************************************************
+ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
+ */
+
+cc_fuzz {
+ name: "amrnb_dec_fuzzer",
+ host_supported: true,
+ srcs: [
+ "amrnb_dec_fuzzer.cpp",
+ ],
+ static_libs: [
+ "libstagefright_amrnbdec",
+ "libstagefright_amrnb_common",
+ "liblog",
+ ],
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}
diff --git a/media/libstagefright/codecs/amrnb/fuzzer/README.md b/media/libstagefright/codecs/amrnb/fuzzer/README.md
new file mode 100644
index 0000000..7791b83
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/fuzzer/README.md
@@ -0,0 +1,62 @@
+# Fuzzer for libstagefright_amrnbdec decoder
+
+## Plugin Design Considerations
+The fuzzer plugin for AMR-NB is designed based on the understanding of the
+codec and tries to achieve the following:
+
+##### Maximize code coverage
+The configuration parameters are not hardcoded, but instead selected based on
+incoming data. This ensures more code paths are reached by the fuzzer.
+
+AMR-NB supports the following parameters:
+1. Stream format (parameter name: `input_format`)
+2. 3GPP frame type (parameter name: `frame_type`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `input_format` | 0. `MIME_IETF` 1. `IF2` | Bit 0 (LSB) of 1st byte of data. |
+| `frame_type` | 0. `AMR_475` 1. `AMR_515` 2. `AMR_59` 3. `AMR_67` 4. `AMR_74` 5. `AMR_795` 6. `AMR_102` 7. `AMR_122` | Bits 3, 4 and 5 of 1st byte of data. |
+
+
+This also ensures that the plugin is always deterministic for any given input.
+
+##### Maximize utilization of input data
+The plugin feeds the entire input data to the codec using a loop.
+If the decode operation was successful, the input is advanced by the frame size
+which is based on `input_format` and `frame_type` selected.
+If the decode operation was un-successful, the input is still advanced by frame size so
+that the fuzzer can proceed to feed the next frame.
+
+This ensures that the plugin tolerates any kind of input (empty, huge,
+malformed, etc) and doesnt `exit()` on any input and thereby increasing the
+chance of identifying vulnerabilities.
+
+## Build
+
+This describes steps to build amrnb_dec_fuzzer binary.
+
+### Android
+
+#### Steps to build
+Build the fuzzer
+```
+ $ mm -j$(nproc) amrnb_dec_fuzzer
+```
+
+#### Steps to run
+Create a directory CORPUS_DIR and copy some amrnb files to that folder
+Push this directory to device.
+
+To run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/amrnb_dec_fuzzer/amrnb_dec_fuzzer CORPUS_DIR
+```
+To run on host
+```
+ $ $ANDROID_HOST_OUT/fuzz/x86_64/amrnb_dec_fuzzer/amrnb_dec_fuzzer CORPUS_DIR
+```
+
+## References:
+ * http://llvm.org/docs/LibFuzzer.html
+ * https://github.com/google/oss-fuzz
diff --git a/media/libstagefright/codecs/amrnb/fuzzer/amrnb_dec_fuzzer.cpp b/media/libstagefright/codecs/amrnb/fuzzer/amrnb_dec_fuzzer.cpp
new file mode 100644
index 0000000..d4e7e5c
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/fuzzer/amrnb_dec_fuzzer.cpp
@@ -0,0 +1,94 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *****************************************************************************
+ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
+ */
+#include <string.h>
+#include <algorithm>
+#include "gsmamr_dec.h"
+
+// Constants for AMR-NB
+constexpr int32_t kSamplesPerFrame = L_FRAME;
+constexpr int32_t kBitsPerSample = 16;
+constexpr int32_t kOutputBufferSize = kSamplesPerFrame * kBitsPerSample / 8;
+const bitstream_format kBitStreamFormats[2] = {MIME_IETF, IF2};
+const int32_t kLocalWmfDecBytesPerFrame[8] = {12, 13, 15, 17, 19, 20, 26, 31};
+const int32_t kLocalIf2DecBytesPerFrame[8] = {13, 14, 16, 18, 19, 21, 26, 31};
+
+class Codec {
+ public:
+ Codec() = default;
+ ~Codec() { deInitDecoder(); }
+ int16_t initDecoder();
+ void deInitDecoder();
+ void decodeFrames(const uint8_t *data, size_t size);
+
+ private:
+ void *mAmrHandle = nullptr;
+};
+
+int16_t Codec::initDecoder() { return GSMInitDecode(&mAmrHandle, (Word8 *)"AMRNBDecoder"); }
+
+void Codec::deInitDecoder() { GSMDecodeFrameExit(&mAmrHandle); }
+
+void Codec::decodeFrames(const uint8_t *data, size_t size) {
+ while (size > 0) {
+ uint8_t mode = *data;
+ bool bit = mode & 0x01;
+ bitstream_format bitsreamFormat = kBitStreamFormats[bit];
+ int32_t frameSize = 0;
+ /* Find frame type */
+ Frame_Type_3GPP frameType = static_cast<Frame_Type_3GPP>((mode >> 3) & 0x07);
+ ++data;
+ --size;
+ if (bit) {
+ frameSize = kLocalIf2DecBytesPerFrame[frameType];
+ } else {
+ frameSize = kLocalWmfDecBytesPerFrame[frameType];
+ }
+ int16_t outputBuf[kOutputBufferSize];
+ uint8_t *inputBuf = new uint8_t[frameSize];
+ if (!inputBuf) {
+ return;
+ }
+ int32_t minSize = std::min((int32_t)size, frameSize);
+ memcpy(inputBuf, data, minSize);
+ AMRDecode(mAmrHandle, frameType, inputBuf, outputBuf, bitsreamFormat);
+ /* AMRDecode() decodes minSize number of bytes if decode is successful.
+ * AMRDecode() returns -1 if decode fails.
+ * Even if no bytes are decoded, increment by minSize to ensure fuzzer proceeds
+ * to feed next data */
+ data += minSize;
+ size -= minSize;
+ delete[] inputBuf;
+ }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ if (size < 2) {
+ return 0;
+ }
+ Codec *codec = new Codec();
+ if (!codec) {
+ return 0;
+ }
+ if (codec->initDecoder() == 0) {
+ codec->decodeFrames(data, size);
+ }
+ delete codec;
+ return 0;
+}
diff --git a/media/libstagefright/codecs/amrwb/Android.bp b/media/libstagefright/codecs/amrwb/Android.bp
index 88cf7f2..d8cb568 100644
--- a/media/libstagefright/codecs/amrwb/Android.bp
+++ b/media/libstagefright/codecs/amrwb/Android.bp
@@ -1,6 +1,7 @@
cc_library_static {
name: "libstagefright_amrwbdec",
vendor_available: true,
+ host_supported: true,
srcs: [
"src/agc2_amr_wb.cpp",
@@ -44,8 +45,6 @@
"src/weight_amrwb_lpc.cpp",
],
- header_libs: ["libstagefright_headers"],
-
export_include_dirs: [
"src",
"include",
@@ -63,12 +62,19 @@
"signed-integer-overflow",
],
},
+
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
}
//###############################################################################
cc_test {
name: "libstagefright_amrwbdec_test",
gtest: false,
+ host_supported: true,
srcs: ["test/amrwbdec_test.cpp"],
@@ -88,4 +94,10 @@
"signed-integer-overflow",
],
},
+
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
}
diff --git a/media/libstagefright/codecs/amrwb/fuzzer/Android.bp b/media/libstagefright/codecs/amrwb/fuzzer/Android.bp
new file mode 100644
index 0000000..46f77e3
--- /dev/null
+++ b/media/libstagefright/codecs/amrwb/fuzzer/Android.bp
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *****************************************************************************
+ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
+ */
+
+cc_fuzz {
+ name: "amrwb_dec_fuzzer",
+ host_supported: true,
+ srcs: [
+ "amrwb_dec_fuzzer.cpp",
+ ],
+ static_libs: [
+ "libstagefright_amrwbdec",
+ ],
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}
diff --git a/media/libstagefright/codecs/amrwb/fuzzer/README.md b/media/libstagefright/codecs/amrwb/fuzzer/README.md
new file mode 100644
index 0000000..de45784
--- /dev/null
+++ b/media/libstagefright/codecs/amrwb/fuzzer/README.md
@@ -0,0 +1,61 @@
+# Fuzzer for libstagefright_amrwbdec decoder
+
+## Plugin Design Considerations
+The fuzzer plugin for AMR-WB is designed based on the understanding of the
+codec and tries to achieve the following:
+
+##### Maximize code coverage
+The configuration parameters are not hardcoded, but instead selected based on
+incoming data. This ensures more code paths are reached by the fuzzer.
+
+AMR-WB supports the following parameters:
+1. Quality (parameter name: `quality`)
+2. Mode (parameter name: `mode`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `quality` | 0. `Bad Quality` 1. `Good quality` | Bit 0 (LSB) of 1st byte of data. |
+| `mode` | 0. `MODE_7k` 1. `MODE_9k` 2. `MODE_12k` 3. `MODE_14k` 4. `MODE_16k ` 5. `MODE_18k` 6. `MODE_20k` 7. `MODE_23k` 8. `MODE_24k` 9. `MRDTX` | Bits 3, 4, 5 and 6 of 1st byte of data. |
+
+This also ensures that the plugin is always deterministic for any given input.
+
+##### Maximize utilization of input data
+The plugin feeds the entire input data to the codec using a loop.
+If the decode operation was successful, the input is advanced by the frame size
+which is based on `mode` and `quality` selected.
+If the decode operation was un-successful, the input is still advanced by frame size so
+that the fuzzer can proceed to feed the next frame.
+
+This ensures that the plugin tolerates any kind of input (empty, huge,
+malformed, etc) and doesnt `exit()` on any input and thereby increasing the
+chance of identifying vulnerabilities.
+
+## Build
+
+This describes steps to build amrwb_dec_fuzzer binary.
+
+### Android
+
+#### Steps to build
+Build the fuzzer
+```
+ $ mm -j$(nproc) amrwb_dec_fuzzer
+```
+
+#### Steps to run
+Create a directory CORPUS_DIR and copy some amrwb files to that folder
+Push this directory to device.
+
+To run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/amrwb_dec_fuzzer/amrwb_dec_fuzzer CORPUS_DIR
+```
+To run on host
+```
+ $ $ANDROID_HOST_OUT/fuzz/x86_64/amrwb_dec_fuzzer/amrwb_dec_fuzzer CORPUS_DIR
+```
+
+## References:
+ * http://llvm.org/docs/LibFuzzer.html
+ * https://github.com/google/oss-fuzz
diff --git a/media/libstagefright/codecs/amrwb/fuzzer/amrwb_dec_fuzzer.cpp b/media/libstagefright/codecs/amrwb/fuzzer/amrwb_dec_fuzzer.cpp
new file mode 100644
index 0000000..6dc0270
--- /dev/null
+++ b/media/libstagefright/codecs/amrwb/fuzzer/amrwb_dec_fuzzer.cpp
@@ -0,0 +1,110 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *****************************************************************************
+ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
+ */
+#include <malloc.h>
+#include <string.h>
+#include <algorithm>
+#include "pvamrwbdecoder.h"
+#include "pvamrwbdecoder_api.h"
+
+// Constants for AMR-WB.
+constexpr int32_t kSamplesPerFrame = 320;
+constexpr int32_t kBitsPerSample = 16;
+constexpr int32_t kMaxSourceDataUnitSize = KAMRWB_NB_BITS_MAX * sizeof(int16_t);
+constexpr int32_t kOutputBufferSize = kSamplesPerFrame * kBitsPerSample / 8;
+constexpr int32_t kFrameSizes[16] = {17, 23, 32, 36, 40, 46, 50, 58,
+ 60, 17, 23, 32, 36, 40, 46, 50};
+
+class Codec {
+ public:
+ Codec() = default;
+ ~Codec() { deInitDecoder(); }
+ bool initDecoder();
+ void decodeFrames(const uint8_t *data, size_t size);
+ void deInitDecoder();
+
+ private:
+ void *mAmrHandle = nullptr;
+ int16_t *mDecoderCookie = nullptr;
+ void *mDecoderBuffer = nullptr;
+};
+
+bool Codec::initDecoder() {
+ mDecoderBuffer = malloc(pvDecoder_AmrWbMemRequirements());
+ if (mDecoderBuffer) {
+ pvDecoder_AmrWb_Init(&mAmrHandle, mDecoderBuffer, &mDecoderCookie);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void Codec::deInitDecoder() {
+ if (mDecoderBuffer) {
+ free(mDecoderBuffer);
+ mDecoderBuffer = nullptr;
+ }
+ mAmrHandle = nullptr;
+ mDecoderCookie = nullptr;
+}
+
+void Codec::decodeFrames(const uint8_t *data, size_t size) {
+ while (size > 0) {
+ uint8_t modeByte = *data;
+ bool quality = modeByte & 0x01;
+ int16 mode = ((modeByte >> 3) & 0x0f);
+ ++data;
+ --size;
+ int32_t frameSize = kFrameSizes[mode];
+ int16_t inputSampleBuf[kMaxSourceDataUnitSize];
+ uint8_t *inputBuf = new uint8_t[frameSize];
+ if (!inputBuf) {
+ return;
+ }
+ int32_t minSize = std::min((int32_t)size, frameSize);
+ memcpy(inputBuf, data, minSize);
+ int16 frameMode = mode;
+ int16 frameType;
+ RX_State_wb rx_state;
+ mime_unsorting(inputBuf, inputSampleBuf, &frameType, &frameMode, quality, &rx_state);
+
+ int16_t numSamplesOutput;
+ int16_t outputBuf[kOutputBufferSize];
+ pvDecoder_AmrWb(frameMode, inputSampleBuf, outputBuf, &numSamplesOutput, mDecoderBuffer,
+ frameType, mDecoderCookie);
+ data += minSize;
+ size -= minSize;
+ delete[] inputBuf;
+ }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ if (size < 2) {
+ return 0;
+ }
+ Codec *codec = new Codec();
+ if (!codec) {
+ return 0;
+ }
+ if (codec->initDecoder()) {
+ codec->decodeFrames(data, size);
+ }
+ delete codec;
+ return 0;
+}
diff --git a/media/libstagefright/codecs/amrwb/test/AmrwbDecTestEnvironment.h b/media/libstagefright/codecs/amrwb/test/AmrwbDecTestEnvironment.h
new file mode 100644
index 0000000..84d337d
--- /dev/null
+++ b/media/libstagefright/codecs/amrwb/test/AmrwbDecTestEnvironment.h
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#ifndef __AMRWBDEC_TEST_ENVIRONMENT_H__
+#define __AMRWBDEC_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class AmrwbDecTestEnvironment : public ::testing::Environment {
+ public:
+ AmrwbDecTestEnvironment() : res("/data/local/tmp/") {}
+
+ // Parses the command line arguments
+ int initFromOptions(int argc, char **argv);
+
+ void setRes(const char *_res) { res = _res; }
+
+ const string getRes() const { return res; }
+
+ private:
+ string res;
+};
+
+int AmrwbDecTestEnvironment::initFromOptions(int argc, char **argv) {
+ static struct option options[] = {{"res", required_argument, 0, 'P'}, {0, 0, 0, 0}};
+
+ while (true) {
+ int index = 0;
+ int c = getopt_long(argc, argv, "P:", options, &index);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'P':
+ setRes(optarg);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (optind < argc) {
+ fprintf(stderr,
+ "unrecognized option: %s\n\n"
+ "usage: %s <gtest options> <test options>\n\n"
+ "test options are:\n\n"
+ "-P, --path: Resource files directory location\n",
+ argv[optind ?: 1], argv[0]);
+ return 2;
+ }
+ return 0;
+}
+
+#endif // __AMRWBDEC_TEST_ENVIRONMENT_H__
diff --git a/media/libstagefright/codecs/amrwb/test/AmrwbDecoderTest.cpp b/media/libstagefright/codecs/amrwb/test/AmrwbDecoderTest.cpp
new file mode 100644
index 0000000..2aad81b
--- /dev/null
+++ b/media/libstagefright/codecs/amrwb/test/AmrwbDecoderTest.cpp
@@ -0,0 +1,223 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AmrwbDecoderTest"
+#define OUTPUT_FILE "/data/local/tmp/amrwbDecode.out"
+
+#include <utils/Log.h>
+
+#include <audio_utils/sndfile.h>
+#include <stdio.h>
+
+#include "pvamrwbdecoder.h"
+#include "pvamrwbdecoder_api.h"
+
+#include "AmrwbDecTestEnvironment.h"
+
+// Constants for AMR-WB.
+constexpr int32_t kInputBufferSize = 64;
+constexpr int32_t kSamplesPerFrame = 320;
+constexpr int32_t kBitsPerSample = 16;
+constexpr int32_t kSampleRate = 16000;
+constexpr int32_t kChannels = 1;
+constexpr int32_t kMaxSourceDataUnitSize = KAMRWB_NB_BITS_MAX * sizeof(int16_t);
+constexpr int32_t kOutputBufferSize = kSamplesPerFrame * kBitsPerSample / 8;
+const int32_t kFrameSizes[16] = {17, 23, 32, 36, 40, 46, 50, 58, 60, -1, -1, -1, -1, -1, -1, -1};
+constexpr int32_t kNumFrameReset = 150;
+
+constexpr int32_t kMaxCount = 10;
+
+static AmrwbDecTestEnvironment *gEnv = nullptr;
+
+class AmrwbDecoderTest : public ::testing::TestWithParam<string> {
+ public:
+ AmrwbDecoderTest() : mFpInput(nullptr) {}
+
+ ~AmrwbDecoderTest() {
+ if (mFpInput) {
+ fclose(mFpInput);
+ mFpInput = nullptr;
+ }
+ }
+
+ FILE *mFpInput;
+ int32_t DecodeFrames(int16_t *decoderCookie, void *decoderBuf, SNDFILE *outFileHandle,
+ int32_t frameCount = INT32_MAX);
+ SNDFILE *openOutputFile(SF_INFO *sfInfo);
+};
+
+SNDFILE *AmrwbDecoderTest::openOutputFile(SF_INFO *sfInfo) {
+ memset(sfInfo, 0, sizeof(SF_INFO));
+ sfInfo->channels = kChannels;
+ sfInfo->format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
+ sfInfo->samplerate = kSampleRate;
+ SNDFILE *outFileHandle = sf_open(OUTPUT_FILE, SFM_WRITE, sfInfo);
+ return outFileHandle;
+}
+
+int32_t AmrwbDecoderTest::DecodeFrames(int16_t *decoderCookie, void *decoderBuf,
+ SNDFILE *outFileHandle, int32_t frameCount) {
+ uint8_t inputBuf[kInputBufferSize];
+ int16_t inputSampleBuf[kMaxSourceDataUnitSize];
+ int16_t outputBuf[kOutputBufferSize];
+
+ while (frameCount > 0) {
+ uint8_t modeByte;
+ int32_t bytesRead = fread(&modeByte, 1, 1, mFpInput);
+ if (bytesRead != 1) break;
+
+ int16 mode = ((modeByte >> 3) & 0x0f);
+ if (mode >= 9) {
+ // Produce silence for comfort noise, speech lost and no data.
+ int32_t outputBufferSize = kSamplesPerFrame * kBitsPerSample / 8;
+ memset(outputBuf, 0, outputBufferSize);
+ } else {
+ // Read rest of the frame.
+ int32_t frameSize = kFrameSizes[mode];
+ // AMR-WB file format cannot have mode 10, 11, 12 and 13.
+ if (frameSize < 0) {
+ ALOGE("Illegal frame mode");
+ return -1;
+ }
+ bytesRead = fread(inputBuf, 1, frameSize, mFpInput);
+ if (bytesRead != frameSize) break;
+
+ int16 frameMode = mode;
+ int16 frameType;
+ RX_State_wb rx_state;
+ mime_unsorting(inputBuf, inputSampleBuf, &frameType, &frameMode, 1, &rx_state);
+
+ int16_t numSamplesOutput;
+ pvDecoder_AmrWb(frameMode, inputSampleBuf, outputBuf, &numSamplesOutput, decoderBuf,
+ frameType, decoderCookie);
+ if (numSamplesOutput != kSamplesPerFrame) {
+ ALOGE("Failed to decode the input file");
+ return -1;
+ }
+ for (int count = 0; count < kSamplesPerFrame; ++count) {
+ /* Delete the 2 LSBs (14-bit output) */
+ outputBuf[count] &= 0xfffc;
+ }
+ }
+ sf_writef_short(outFileHandle, outputBuf, kSamplesPerFrame / kChannels);
+ frameCount--;
+ }
+ return 0;
+}
+
+TEST_F(AmrwbDecoderTest, MultiCreateAmrwbDecoderTest) {
+ uint32_t memRequirements = pvDecoder_AmrWbMemRequirements();
+ void *decoderBuf = malloc(memRequirements);
+ ASSERT_NE(decoderBuf, nullptr)
+ << "Failed to allocate decoder memory of size " << memRequirements;
+
+ // Create AMR-WB decoder instance.
+ void *amrHandle = nullptr;
+ int16_t *decoderCookie;
+ for (int count = 0; count < kMaxCount; count++) {
+ pvDecoder_AmrWb_Init(&amrHandle, decoderBuf, &decoderCookie);
+ ASSERT_NE(amrHandle, nullptr) << "Failed to initialize decoder";
+ ALOGV("Decoder created successfully");
+ }
+ if (decoderBuf) {
+ free(decoderBuf);
+ decoderBuf = nullptr;
+ }
+}
+
+TEST_P(AmrwbDecoderTest, DecodeTest) {
+ uint32_t memRequirements = pvDecoder_AmrWbMemRequirements();
+ void *decoderBuf = malloc(memRequirements);
+ ASSERT_NE(decoderBuf, nullptr)
+ << "Failed to allocate decoder memory of size " << memRequirements;
+
+ void *amrHandle = nullptr;
+ int16_t *decoderCookie;
+ pvDecoder_AmrWb_Init(&amrHandle, decoderBuf, &decoderCookie);
+ ASSERT_NE(amrHandle, nullptr) << "Failed to initialize decoder";
+
+ string inputFile = gEnv->getRes() + GetParam();
+ mFpInput = fopen(inputFile.c_str(), "rb");
+ ASSERT_NE(mFpInput, nullptr) << "Error opening input file " << inputFile;
+
+ // Open the output file.
+ SF_INFO sfInfo;
+ SNDFILE *outFileHandle = openOutputFile(&sfInfo);
+ ASSERT_NE(outFileHandle, nullptr) << "Error opening output file for writing decoded output";
+
+ int32_t decoderErr = DecodeFrames(decoderCookie, decoderBuf, outFileHandle);
+ ASSERT_EQ(decoderErr, 0) << "DecodeFrames returned error";
+
+ sf_close(outFileHandle);
+ if (decoderBuf) {
+ free(decoderBuf);
+ decoderBuf = nullptr;
+ }
+}
+
+TEST_P(AmrwbDecoderTest, ResetDecoderTest) {
+ uint32_t memRequirements = pvDecoder_AmrWbMemRequirements();
+ void *decoderBuf = malloc(memRequirements);
+ ASSERT_NE(decoderBuf, nullptr)
+ << "Failed to allocate decoder memory of size " << memRequirements;
+
+ void *amrHandle = nullptr;
+ int16_t *decoderCookie;
+ pvDecoder_AmrWb_Init(&amrHandle, decoderBuf, &decoderCookie);
+ ASSERT_NE(amrHandle, nullptr) << "Failed to initialize decoder";
+
+ string inputFile = gEnv->getRes() + GetParam();
+ mFpInput = fopen(inputFile.c_str(), "rb");
+ ASSERT_NE(mFpInput, nullptr) << "Error opening input file " << inputFile;
+
+ // Open the output file.
+ SF_INFO sfInfo;
+ SNDFILE *outFileHandle = openOutputFile(&sfInfo);
+ ASSERT_NE(outFileHandle, nullptr) << "Error opening output file for writing decoded output";
+
+ // Decode 150 frames first
+ int32_t decoderErr = DecodeFrames(decoderCookie, decoderBuf, outFileHandle, kNumFrameReset);
+ ASSERT_EQ(decoderErr, 0) << "DecodeFrames returned error";
+
+ // Reset Decoder
+ pvDecoder_AmrWb_Reset(decoderBuf, 1);
+
+ // Start decoding again
+ decoderErr = DecodeFrames(decoderCookie, decoderBuf, outFileHandle);
+ ASSERT_EQ(decoderErr, 0) << "DecodeFrames returned error";
+
+ sf_close(outFileHandle);
+ if (decoderBuf) {
+ free(decoderBuf);
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(AmrwbDecoderTestAll, AmrwbDecoderTest,
+ ::testing::Values(("bbb_amrwb_1ch_14kbps_16000hz.amrwb"),
+ ("bbb_16000hz_1ch_9kbps_amrwb_30sec.amrwb")));
+
+int main(int argc, char **argv) {
+ gEnv = new AmrwbDecTestEnvironment();
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = gEnv->initFromOptions(argc, argv);
+ if (status == 0) {
+ status = RUN_ALL_TESTS();
+ ALOGV("Test result = %d\n", status);
+ }
+ return status;
+}
diff --git a/media/libstagefright/codecs/amrwb/test/Android.bp b/media/libstagefright/codecs/amrwb/test/Android.bp
new file mode 100644
index 0000000..968215a
--- /dev/null
+++ b/media/libstagefright/codecs/amrwb/test/Android.bp
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+cc_test {
+ name: "AmrwbDecoderTest",
+ gtest: true,
+
+ srcs: [
+ "AmrwbDecoderTest.cpp",
+ ],
+
+ static_libs: [
+ "libstagefright_amrwbdec",
+ "libsndfile",
+ "libaudioutils",
+ ],
+
+ shared_libs: [
+ "liblog",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ sanitize: {
+ cfi: true,
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ },
+}
diff --git a/media/libstagefright/codecs/amrwb/test/AndroidTest.xml b/media/libstagefright/codecs/amrwb/test/AndroidTest.xml
new file mode 100644
index 0000000..e211a1f
--- /dev/null
+++ b/media/libstagefright/codecs/amrwb/test/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Test module config for Amr-wb Decoder unit test">
+ <option name="test-suite-tag" value="AmrwbDecoderTest" />
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="AmrwbDecoderTest->/data/local/tmp/AmrwbDecoderTest" />
+ <option name="push-file"
+ key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/amrwb/test/AmrwbDecoderTest.zip?unzip=true"
+ value="/data/local/tmp/AmrwbDecoderTestRes/" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="AmrwbDecoderTest" />
+ <option name="native-test-flag" value="-P /data/local/tmp/AmrwbDecoderTestRes/" />
+ </test>
+</configuration>
diff --git a/media/libstagefright/codecs/amrwb/test/README.md b/media/libstagefright/codecs/amrwb/test/README.md
new file mode 100644
index 0000000..a9d5c06
--- /dev/null
+++ b/media/libstagefright/codecs/amrwb/test/README.md
@@ -0,0 +1,39 @@
+## Media Testing ##
+---
+#### AMR-WB Decoder :
+The Amr-Wb Decoder Test Suite validates the amrwb decoder available in libstagefright.
+
+Run the following steps to build the test suite:
+```
+m AmrwbDecoderTest
+```
+
+The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/
+
+The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/
+
+To test 64-bit binary push binaries from nativetest64.
+```
+adb push ${OUT}/data/nativetest64/AmrwbDecoderTest/AmrwbDecoderTest /data/local/tmp/
+```
+
+To test 32-bit binary push binaries from nativetest.
+```
+adb push ${OUT}/data/nativetest/AmrwbDecoderTest/AmrwbDecoderTest /data/local/tmp/
+```
+
+The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/amrwb/test/AmrwbDecoderTest.zip). Download, unzip and push these files into device for testing.
+
+```
+adb push AmrwbDecoderTestRes/. /data/local/tmp/
+```
+
+usage: AmrwbDecoderTest -P \<path_to_folder\>
+```
+adb shell /data/local/tmp/AmrwbDecoderTest -P /data/local/tmp/AmrwbDecoderTestRes/
+```
+Alternatively, the test can also be run using atest command.
+
+```
+atest AmrwbDecoderTest -- --enable-module-dynamic-download=true
+```
diff --git a/media/libstagefright/codecs/amrwbenc/test/AmrwbEncTestEnvironment.h b/media/libstagefright/codecs/amrwbenc/test/AmrwbEncTestEnvironment.h
new file mode 100644
index 0000000..08ada66
--- /dev/null
+++ b/media/libstagefright/codecs/amrwbenc/test/AmrwbEncTestEnvironment.h
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#ifndef __AMRWBENC_TEST_ENVIRONMENT_H__
+#define __AMRWBENC_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class AmrwbEncTestEnvironment : public ::testing::Environment {
+ public:
+ AmrwbEncTestEnvironment() : res("/data/local/tmp/") {}
+
+ // Parses the command line arguments
+ int initFromOptions(int argc, char **argv);
+
+ void setRes(const char *_res) { res = _res; }
+
+ const string getRes() const { return res; }
+
+ private:
+ string res;
+};
+
+int AmrwbEncTestEnvironment::initFromOptions(int argc, char **argv) {
+ static struct option options[] = {{"res", required_argument, 0, 'P'}, {0, 0, 0, 0}};
+
+ while (true) {
+ int index = 0;
+ int c = getopt_long(argc, argv, "P:", options, &index);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'P':
+ setRes(optarg);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (optind < argc) {
+ fprintf(stderr,
+ "unrecognized option: %s\n\n"
+ "usage: %s <gtest options> <test options>\n\n"
+ "test options are:\n\n"
+ "-P, --path: Resource files directory location\n",
+ argv[optind ?: 1], argv[0]);
+ return 2;
+ }
+ return 0;
+}
+
+#endif // __AMRWBENC_TEST_ENVIRONMENT_H__
diff --git a/media/libstagefright/codecs/amrwbenc/test/AmrwbEncoderTest.cpp b/media/libstagefright/codecs/amrwbenc/test/AmrwbEncoderTest.cpp
new file mode 100644
index 0000000..1a6ee27
--- /dev/null
+++ b/media/libstagefright/codecs/amrwbenc/test/AmrwbEncoderTest.cpp
@@ -0,0 +1,198 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AmrwbEncoderTest"
+
+#include <utils/Log.h>
+
+#include <stdio.h>
+
+#include "cmnMemory.h"
+#include "voAMRWB.h"
+
+#include "AmrwbEncTestEnvironment.h"
+
+#define OUTPUT_FILE "/data/local/tmp/amrwbEncode.out"
+#define VOAMRWB_RFC3267_HEADER_INFO "#!AMR-WB\n"
+
+constexpr int32_t kInputBufferSize = 640;
+constexpr int32_t kOutputBufferSize = 1024;
+
+static AmrwbEncTestEnvironment *gEnv = nullptr;
+
+class AmrwbEncoderTest : public ::testing::TestWithParam<tuple<string, int32_t, VOAMRWBFRAMETYPE>> {
+ public:
+ AmrwbEncoderTest() : mEncoderHandle(nullptr) {
+ tuple<string, int32_t, VOAMRWBFRAMETYPE> params = GetParam();
+ mInputFile = gEnv->getRes() + get<0>(params);
+ mMode = get<1>(params);
+ mFrameType = get<2>(params);
+ mMemOperator.Alloc = cmnMemAlloc;
+ mMemOperator.Copy = cmnMemCopy;
+ mMemOperator.Free = cmnMemFree;
+ mMemOperator.Set = cmnMemSet;
+ mMemOperator.Check = cmnMemCheck;
+
+ mUserData.memflag = VO_IMF_USERMEMOPERATOR;
+ mUserData.memData = (VO_PTR)(&mMemOperator);
+ }
+
+ ~AmrwbEncoderTest() {
+ if (mEncoderHandle) {
+ mEncoderHandle = nullptr;
+ }
+ }
+
+ string mInputFile;
+ unsigned char mOutputBuf[kOutputBufferSize];
+ unsigned char mInputBuf[kInputBufferSize];
+ VOAMRWBFRAMETYPE mFrameType;
+ VO_AUDIO_CODECAPI mApiHandle;
+ VO_MEM_OPERATOR mMemOperator;
+ VO_CODEC_INIT_USERDATA mUserData;
+ VO_HANDLE mEncoderHandle;
+ int32_t mMode;
+};
+
+TEST_P(AmrwbEncoderTest, CreateAmrwbEncoderTest) {
+ int32_t status = voGetAMRWBEncAPI(&mApiHandle);
+ ASSERT_EQ(status, VO_ERR_NONE) << "Failed to get api handle";
+
+ status = mApiHandle.Init(&mEncoderHandle, VO_AUDIO_CodingAMRWB, &mUserData);
+ ASSERT_EQ(status, VO_ERR_NONE) << "Failed to init AMRWB encoder";
+
+ status = mApiHandle.SetParam(mEncoderHandle, VO_PID_AMRWB_FRAMETYPE, &mFrameType);
+ ASSERT_EQ(status, VO_ERR_NONE) << "Failed to set AMRWB encoder frame type to " << mFrameType;
+
+ status = mApiHandle.SetParam(mEncoderHandle, VO_PID_AMRWB_MODE, &mMode);
+ ASSERT_EQ(status, VO_ERR_NONE) << "Failed to set AMRWB encoder mode to %d" << mMode;
+ ALOGV("AMR-WB encoder created successfully");
+
+ status = mApiHandle.Uninit(mEncoderHandle);
+ ASSERT_EQ(status, VO_ERR_NONE) << "Failed to delete AMRWB encoder";
+ ALOGV("AMR-WB encoder deleted successfully");
+}
+
+TEST_P(AmrwbEncoderTest, AmrwbEncodeTest) {
+ VO_CODECBUFFER inData;
+ VO_CODECBUFFER outData;
+ VO_AUDIO_OUTPUTINFO outFormat;
+
+ FILE *fpInput = fopen(mInputFile.c_str(), "rb");
+ ASSERT_NE(fpInput, nullptr) << "Error opening input file " << mInputFile;
+
+ FILE *fpOutput = fopen(OUTPUT_FILE, "wb");
+ ASSERT_NE(fpOutput, nullptr) << "Error opening output file " << OUTPUT_FILE;
+
+ uint32_t status = voGetAMRWBEncAPI(&mApiHandle);
+ ASSERT_EQ(status, VO_ERR_NONE) << "Failed to get api handle";
+
+ status = mApiHandle.Init(&mEncoderHandle, VO_AUDIO_CodingAMRWB, &mUserData);
+ ASSERT_EQ(status, VO_ERR_NONE) << "Failed to init AMRWB encoder";
+
+ status = mApiHandle.SetParam(mEncoderHandle, VO_PID_AMRWB_FRAMETYPE, &mFrameType);
+ ASSERT_EQ(status, VO_ERR_NONE) << "Failed to set AMRWB encoder frame type to " << mFrameType;
+
+ status = mApiHandle.SetParam(mEncoderHandle, VO_PID_AMRWB_MODE, &mMode);
+ ASSERT_EQ(status, VO_ERR_NONE) << "Failed to set AMRWB encoder mode to " << mMode;
+
+ if (mFrameType == VOAMRWB_RFC3267) {
+ /* write RFC3267 Header info to indicate single channel AMR file storage format */
+ int32_t size = strlen(VOAMRWB_RFC3267_HEADER_INFO);
+ memcpy(mOutputBuf, VOAMRWB_RFC3267_HEADER_INFO, size);
+ fwrite(mOutputBuf, 1, size, fpOutput);
+ }
+
+ int32_t frameNum = 0;
+ while (1) {
+ int32_t buffLength =
+ (int32_t)fread(mInputBuf, sizeof(signed char), kInputBufferSize, fpInput);
+
+ if (buffLength == 0 || feof(fpInput)) break;
+ ASSERT_EQ(buffLength, kInputBufferSize) << "Error in reading input file";
+
+ inData.Buffer = (unsigned char *)mInputBuf;
+ inData.Length = buffLength;
+ outData.Buffer = mOutputBuf;
+ status = mApiHandle.SetInputData(mEncoderHandle, &inData);
+ ASSERT_EQ(status, VO_ERR_NONE) << "Failed to setup Input data";
+
+ do {
+ status = mApiHandle.GetOutputData(mEncoderHandle, &outData, &outFormat);
+ ASSERT_NE(status, VO_ERR_LICENSE_ERROR) << "Failed to encode the file";
+ if (status == 0) {
+ frameNum++;
+ fwrite(outData.Buffer, 1, outData.Length, fpOutput);
+ fflush(fpOutput);
+ }
+ } while (status != VO_ERR_INPUT_BUFFER_SMALL);
+ }
+
+ ALOGV("Number of frames processed: %d", frameNum);
+ status = mApiHandle.Uninit(mEncoderHandle);
+ ASSERT_EQ(status, VO_ERR_NONE) << "Failed to delete AMRWB encoder";
+
+ if (fpInput) {
+ fclose(fpInput);
+ }
+ if (fpOutput) {
+ fclose(fpOutput);
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ AmrwbEncoderTestAll, AmrwbEncoderTest,
+ ::testing::Values(
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD66, VOAMRWB_DEFAULT),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD885, VOAMRWB_DEFAULT),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1265, VOAMRWB_DEFAULT),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1425, VOAMRWB_DEFAULT),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1585, VOAMRWB_DEFAULT),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1825, VOAMRWB_DEFAULT),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1985, VOAMRWB_DEFAULT),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2305, VOAMRWB_DEFAULT),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2385, VOAMRWB_DEFAULT),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD66, VOAMRWB_ITU),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD885, VOAMRWB_ITU),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1265, VOAMRWB_ITU),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1425, VOAMRWB_ITU),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1585, VOAMRWB_ITU),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1825, VOAMRWB_ITU),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1985, VOAMRWB_ITU),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2305, VOAMRWB_ITU),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2385, VOAMRWB_ITU),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD66, VOAMRWB_RFC3267),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD885, VOAMRWB_RFC3267),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1265, VOAMRWB_RFC3267),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1425, VOAMRWB_RFC3267),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1585, VOAMRWB_RFC3267),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1825, VOAMRWB_RFC3267),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1985, VOAMRWB_RFC3267),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2305, VOAMRWB_RFC3267),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2385, VOAMRWB_RFC3267)));
+
+int main(int argc, char **argv) {
+ gEnv = new AmrwbEncTestEnvironment();
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = gEnv->initFromOptions(argc, argv);
+ if (status == 0) {
+ status = RUN_ALL_TESTS();
+ ALOGV("Test result = %d\n", status);
+ }
+ return status;
+}
diff --git a/media/libstagefright/codecs/amrwbenc/test/Android.bp b/media/libstagefright/codecs/amrwbenc/test/Android.bp
new file mode 100644
index 0000000..7042bc5
--- /dev/null
+++ b/media/libstagefright/codecs/amrwbenc/test/Android.bp
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+cc_test {
+ name: "AmrwbEncoderTest",
+ gtest: true,
+
+ srcs: [
+ "AmrwbEncoderTest.cpp",
+ ],
+
+ static_libs: [
+ "libstagefright_enc_common",
+ "libstagefright_amrwbenc",
+ "libaudioutils",
+ "libsndfile",
+ ],
+
+ shared_libs: [
+ "liblog",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ sanitize: {
+ cfi: true,
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ },
+}
diff --git a/media/libstagefright/codecs/amrwbenc/test/AndroidTest.xml b/media/libstagefright/codecs/amrwbenc/test/AndroidTest.xml
new file mode 100644
index 0000000..46f147c
--- /dev/null
+++ b/media/libstagefright/codecs/amrwbenc/test/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Test module config for Amr-wb Encoder unit test">
+ <option name="test-suite-tag" value="AmrwbEncoderTest" />
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="AmrwbEncoderTest->/data/local/tmp/AmrwbEncoderTest" />
+ <option name="push-file"
+ key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/amrwbenc/test/AmrwbEncoderTest.zip?unzip=true"
+ value="/data/local/tmp/AmrwbEncoderTestRes/" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="AmrwbEncoderTest" />
+ <option name="native-test-flag" value="-P /data/local/tmp/AmrwbEncoderTestRes/" />
+ </test>
+</configuration>
diff --git a/media/libstagefright/codecs/amrwbenc/test/README.md b/media/libstagefright/codecs/amrwbenc/test/README.md
new file mode 100644
index 0000000..78762cb
--- /dev/null
+++ b/media/libstagefright/codecs/amrwbenc/test/README.md
@@ -0,0 +1,39 @@
+## Media Testing ##
+---
+#### AMR-WB Encoder :
+The Amr-Wb Encoder Test Suite validates the amrwb encoder available in libstagefright.
+
+Run the following steps to build the test suite:
+```
+m AmrwbEncoderTest
+```
+
+The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/
+
+The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/
+
+To test 64-bit binary push binaries from nativetest64.
+```
+adb push ${OUT}/data/nativetest64/AmrwbEncoderTest/AmrwbEncoderTest /data/local/tmp/
+```
+
+To test 32-bit binary push binaries from nativetest.
+```
+adb push ${OUT}/data/nativetest/AmrwbEncoderTest/AmrwbEncoderTest /data/local/tmp/
+```
+
+The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/amrwbenc/test/AmrwbEncoderTest.zip). Download, unzip and push these files into device for testing.
+
+```
+adb push AmrwbEncoderTestRes/. /data/local/tmp/
+```
+
+usage: AmrwbEncoderTest -P \<path_to_folder\>
+```
+adb shell /data/local/tmp/AmrwbEncoderTest -P /data/local/tmp/AmrwbEncoderTestRes/
+```
+Alternatively, the test can also be run using atest command.
+
+```
+atest AmrwbEncoderTest -- --enable-module-dynamic-download=true
+```
diff --git a/media/libstagefright/codecs/flac/enc/Android.bp b/media/libstagefright/codecs/flac/enc/Android.bp
index d7d871a..f35bce1 100644
--- a/media/libstagefright/codecs/flac/enc/Android.bp
+++ b/media/libstagefright/codecs/flac/enc/Android.bp
@@ -15,8 +15,10 @@
},
header_libs: ["libbase_headers"],
- static_libs: [
+ shared_libs: [
"libaudioutils",
+ ],
+ static_libs: [
"libFLAC",
],
}
diff --git a/media/libstagefright/codecs/m4v_h263/dec/Android.bp b/media/libstagefright/codecs/m4v_h263/dec/Android.bp
index 6b45ea2..c67dc2b 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/Android.bp
+++ b/media/libstagefright/codecs/m4v_h263/dec/Android.bp
@@ -47,9 +47,6 @@
export_include_dirs: ["include"],
cflags: [
- "-DOSCL_EXPORT_REF=",
- "-DOSCL_IMPORT_REF=",
-
"-Werror",
],
@@ -74,8 +71,6 @@
local_include_dirs: ["src"],
cflags: [
- "-DOSCL_EXPORT_REF=",
- "-DOSCL_IMPORT_REF=",
],
static_libs: ["libstagefright_m4vh263dec"],
diff --git a/media/libstagefright/codecs/m4v_h263/dec/include/mp4dec_api.h b/media/libstagefright/codecs/m4v_h263/dec/include/mp4dec_api.h
index 6d4868c..1f404ce 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/include/mp4dec_api.h
+++ b/media/libstagefright/codecs/m4v_h263/dec/include/mp4dec_api.h
@@ -35,6 +35,13 @@
#define PV_TRUE 1
#define PV_FALSE 0
+#ifndef OSCL_IMPORT_REF
+#define OSCL_IMPORT_REF /* empty */
+#endif
+#ifndef OSCL_EXPORT_REF
+#define OSCL_EXPORT_REF /* empty */
+#endif
+
/* flag for post-processing 4/25/00 */
#ifdef DEC_NOPOSTPROC
diff --git a/media/libstagefright/codecs/m4v_h263/dec/test/Android.bp b/media/libstagefright/codecs/m4v_h263/dec/test/Android.bp
new file mode 100644
index 0000000..655491a
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/dec/test/Android.bp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+cc_test {
+ name: "Mpeg4H263DecoderTest",
+ gtest: true,
+
+ srcs: [
+ "Mpeg4H263DecoderTest.cpp",
+ ],
+
+ shared_libs: [
+ "liblog",
+ ],
+
+ static_libs: [
+ "libstagefright_m4vh263dec",
+ "libstagefright_foundation",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ sanitize: {
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ cfi: true,
+ },
+}
diff --git a/media/libstagefright/codecs/m4v_h263/dec/test/AndroidTest.xml b/media/libstagefright/codecs/m4v_h263/dec/test/AndroidTest.xml
new file mode 100755
index 0000000..47e10ca
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/dec/test/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<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">
+ <option name="cleanup" value="true" />
+ <option name="push" value="Mpeg4H263DecoderTest->/data/local/tmp/Mpeg4H263DecoderTest" />
+ <option name="push-file"
+ key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263Decoder.zip?unzip=true"
+ value="/data/local/tmp/Mpeg4H263DecoderTestRes/" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="Mpeg4H263DecoderTest" />
+ <option name="native-test-flag" value="-P /data/local/tmp/Mpeg4H263DecoderTestRes/" />
+ </test>
+</configuration>
diff --git a/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263DecoderTest.cpp b/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263DecoderTest.cpp
new file mode 100644
index 0000000..967c1ea
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263DecoderTest.cpp
@@ -0,0 +1,423 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Mpeg4H263DecoderTest"
+#include <utils/Log.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <utils/String8.h>
+#include <fstream>
+
+#include <media/stagefright/foundation/AUtils.h>
+#include "mp4dec_api.h"
+
+#include "Mpeg4H263DecoderTestEnvironment.h"
+
+using namespace android;
+
+#define OUTPUT_FILE_NAME "/data/local/tmp/Output.yuv"
+#define CODEC_CONFIG_FLAG 32
+#define SYNC_FRAME 1
+#define MPEG4_MAX_WIDTH 1920
+#define MPEG4_MAX_HEIGHT 1080
+#define H263_MAX_WIDTH 352
+#define H263_MAX_HEIGHT 288
+
+constexpr uint32_t kNumOutputBuffers = 2;
+
+struct FrameInfo {
+ int32_t bytesCount;
+ uint32_t flags;
+ int64_t timestamp;
+};
+
+struct tagvideoDecControls;
+
+static Mpeg4H263DecoderTestEnvironment *gEnv = nullptr;
+
+class Mpeg4H263DecoderTest : public ::testing::TestWithParam<tuple<string, string, bool>> {
+ public:
+ Mpeg4H263DecoderTest()
+ : mDecHandle(nullptr),
+ mInputBuffer(nullptr),
+ mInitialized(false),
+ mFramesConfigured(false),
+ mNumSamplesOutput(0),
+ mWidth(352),
+ mHeight(288) {
+ memset(mOutputBuffer, 0x0, sizeof(mOutputBuffer));
+ }
+
+ ~Mpeg4H263DecoderTest() {
+ if (mEleStream.is_open()) mEleStream.close();
+ if (mDecHandle) {
+ delete mDecHandle;
+ mDecHandle = nullptr;
+ }
+ if (mInputBuffer) {
+ free(mInputBuffer);
+ mInputBuffer = nullptr;
+ }
+ freeOutputBuffer();
+ }
+
+ status_t initDecoder();
+ void allocOutputBuffer(size_t outputBufferSize);
+ void dumpOutput(ofstream &ostrm);
+ void freeOutputBuffer();
+ void processMpeg4H263Decoder(vector<FrameInfo> Info, int32_t offset, int32_t range,
+ ifstream &mEleStream, ofstream &ostrm, MP4DecodingMode inputMode);
+ void deInitDecoder();
+
+ ifstream mEleStream;
+ tagvideoDecControls *mDecHandle;
+ char *mInputBuffer;
+ uint8_t *mOutputBuffer[kNumOutputBuffers];
+ bool mInitialized;
+ bool mFramesConfigured;
+ uint32_t mNumSamplesOutput;
+ uint32_t mWidth;
+ uint32_t mHeight;
+};
+
+status_t Mpeg4H263DecoderTest::initDecoder() {
+ if (!mDecHandle) {
+ mDecHandle = new tagvideoDecControls;
+ }
+ if (!mDecHandle) {
+ return NO_MEMORY;
+ }
+ memset(mDecHandle, 0, sizeof(tagvideoDecControls));
+
+ return OK;
+}
+
+void Mpeg4H263DecoderTest::allocOutputBuffer(size_t outputBufferSize) {
+ for (int32_t i = 0; i < kNumOutputBuffers; ++i) {
+ if (!mOutputBuffer[i]) {
+ mOutputBuffer[i] = (uint8_t *)malloc(outputBufferSize);
+ ASSERT_NE(mOutputBuffer[i], nullptr) << "Output buffer allocation failed";
+ }
+ }
+}
+
+void Mpeg4H263DecoderTest::dumpOutput(ofstream &ostrm) {
+ uint8_t *src = mOutputBuffer[mNumSamplesOutput & 1];
+ size_t vStride = align(mHeight, 16);
+ size_t srcYStride = align(mWidth, 16);
+ size_t srcUVStride = srcYStride / 2;
+ uint8_t *srcStart = src;
+
+ /* Y buffer */
+ for (size_t i = 0; i < mHeight; ++i) {
+ ostrm.write(reinterpret_cast<char *>(src), mWidth);
+ src += srcYStride;
+ }
+ /* U buffer */
+ src = srcStart + vStride * srcYStride;
+ for (size_t i = 0; i < mHeight / 2; ++i) {
+ ostrm.write(reinterpret_cast<char *>(src), mWidth / 2);
+ src += srcUVStride;
+ }
+ /* V buffer */
+ src = srcStart + vStride * srcYStride * 5 / 4;
+ for (size_t i = 0; i < mHeight / 2; ++i) {
+ ostrm.write(reinterpret_cast<char *>(src), mWidth / 2);
+ src += srcUVStride;
+ }
+}
+
+void Mpeg4H263DecoderTest::freeOutputBuffer() {
+ for (int32_t i = 0; i < kNumOutputBuffers; ++i) {
+ if (mOutputBuffer[i]) {
+ free(mOutputBuffer[i]);
+ mOutputBuffer[i] = nullptr;
+ }
+ }
+}
+
+void Mpeg4H263DecoderTest::processMpeg4H263Decoder(vector<FrameInfo> Info, int32_t offset,
+ int32_t range, ifstream &mEleStream,
+ ofstream &ostrm, MP4DecodingMode inputMode) {
+ size_t maxWidth = (inputMode == MPEG4_MODE) ? MPEG4_MAX_WIDTH : H263_MAX_WIDTH;
+ size_t maxHeight = (inputMode == MPEG4_MODE) ? MPEG4_MAX_HEIGHT : H263_MAX_HEIGHT;
+ size_t outputBufferSize = align(maxWidth, 16) * align(maxHeight, 16) * 3 / 2;
+ uint32_t frameIndex = offset;
+ bool status = true;
+ ASSERT_GE(range, 0) << "Invalid range";
+ ASSERT_TRUE(offset >= 0 && offset <= Info.size() - 1) << "Invalid offset";
+ ASSERT_LE(range + offset, Info.size()) << "range+offset can't be greater than the no of frames";
+
+ while (1) {
+ if (frameIndex == Info.size() || frameIndex == (offset + range)) break;
+
+ int32_t bytesCount = Info[frameIndex].bytesCount;
+ ASSERT_GT(bytesCount, 0) << "Size for the memory allocation is negative";
+ mInputBuffer = (char *)malloc(bytesCount);
+ ASSERT_NE(mInputBuffer, nullptr) << "Insufficient memory to read frame";
+ mEleStream.read(mInputBuffer, bytesCount);
+ ASSERT_EQ(mEleStream.gcount(), bytesCount) << "mEleStream.gcount() != bytesCount";
+ static const uint8_t volInfo[] = {0x00, 0x00, 0x01, 0xB0};
+ bool volHeader = memcmp(mInputBuffer, volInfo, 4) == 0;
+ if (volHeader) {
+ PVCleanUpVideoDecoder(mDecHandle);
+ mInitialized = false;
+ }
+
+ if (!mInitialized) {
+ uint8_t *volData[1]{};
+ int32_t volSize = 0;
+
+ uint32_t flags = Info[frameIndex].flags;
+ bool codecConfig = flags == CODEC_CONFIG_FLAG;
+ if (codecConfig || volHeader) {
+ volData[0] = reinterpret_cast<uint8_t *>(mInputBuffer);
+ volSize = bytesCount;
+ }
+
+ status = PVInitVideoDecoder(mDecHandle, volData, &volSize, 1, maxWidth, maxHeight,
+ inputMode);
+ ASSERT_TRUE(status) << "PVInitVideoDecoder failed. Unsupported content";
+
+ mInitialized = true;
+ MP4DecodingMode actualMode = PVGetDecBitstreamMode(mDecHandle);
+ ASSERT_EQ(inputMode, actualMode)
+ << "Decoded mode not same as actual mode of the decoder";
+
+ PVSetPostProcType(mDecHandle, 0);
+
+ int32_t dispWidth, dispHeight;
+ PVGetVideoDimensions(mDecHandle, &dispWidth, &dispHeight);
+
+ int32_t bufWidth, bufHeight;
+ PVGetBufferDimensions(mDecHandle, &bufWidth, &bufHeight);
+
+ ASSERT_LE(dispWidth, bufWidth) << "Display width is greater than buffer width";
+ ASSERT_LE(dispHeight, bufHeight) << "Display height is greater than buffer height";
+
+ if (dispWidth != mWidth || dispHeight != mHeight) {
+ mWidth = dispWidth;
+ mHeight = dispHeight;
+ freeOutputBuffer();
+ if (inputMode == H263_MODE) {
+ PVCleanUpVideoDecoder(mDecHandle);
+
+ uint8_t *volData[1]{};
+ int32_t volSize = 0;
+
+ status = PVInitVideoDecoder(mDecHandle, volData, &volSize, 1, maxWidth,
+ maxHeight, H263_MODE);
+ ASSERT_TRUE(status) << "PVInitVideoDecoder failed for H263";
+ }
+ mFramesConfigured = false;
+ }
+
+ if (codecConfig) {
+ frameIndex++;
+ continue;
+ }
+ }
+
+ uint32_t yFrameSize = sizeof(uint8) * mDecHandle->size;
+ ASSERT_GE(outputBufferSize, yFrameSize * 3 / 2)
+ << "Too small output buffer: " << outputBufferSize << " bytes";
+ ASSERT_NO_FATAL_FAILURE(allocOutputBuffer(outputBufferSize));
+
+ if (!mFramesConfigured) {
+ PVSetReferenceYUV(mDecHandle, mOutputBuffer[1]);
+ mFramesConfigured = true;
+ }
+
+ // Need to check if header contains new info, e.g., width/height, etc.
+ VopHeaderInfo headerInfo;
+ uint32_t useExtTimestamp = 1;
+ int32_t inputSize = (Info)[frameIndex].bytesCount;
+ uint32_t timestamp = frameIndex;
+
+ uint8_t *bitstreamTmp = reinterpret_cast<uint8_t *>(mInputBuffer);
+
+ status = PVDecodeVopHeader(mDecHandle, &bitstreamTmp, ×tamp, &inputSize, &headerInfo,
+ &useExtTimestamp, mOutputBuffer[mNumSamplesOutput & 1]);
+ ASSERT_EQ(status, PV_TRUE) << "failed to decode vop header";
+
+ // H263 doesn't have VOL header, the frame size information is in short header, i.e. the
+ // decoder may detect size change after PVDecodeVopHeader.
+ int32_t dispWidth, dispHeight;
+ PVGetVideoDimensions(mDecHandle, &dispWidth, &dispHeight);
+
+ int32_t bufWidth, bufHeight;
+ PVGetBufferDimensions(mDecHandle, &bufWidth, &bufHeight);
+
+ ASSERT_LE(dispWidth, bufWidth) << "Display width is greater than buffer width";
+ ASSERT_LE(dispHeight, bufHeight) << "Display height is greater than buffer height";
+ if (dispWidth != mWidth || dispHeight != mHeight) {
+ mWidth = dispWidth;
+ mHeight = dispHeight;
+ }
+
+ status = PVDecodeVopBody(mDecHandle, &inputSize);
+ ASSERT_EQ(status, PV_TRUE) << "failed to decode video frame No = %d" << frameIndex;
+
+ dumpOutput(ostrm);
+
+ ++mNumSamplesOutput;
+ ++frameIndex;
+ }
+ freeOutputBuffer();
+}
+
+void Mpeg4H263DecoderTest::deInitDecoder() {
+ if (mInitialized) {
+ if (mDecHandle) {
+ PVCleanUpVideoDecoder(mDecHandle);
+ delete mDecHandle;
+ mDecHandle = nullptr;
+ }
+ mInitialized = false;
+ }
+ freeOutputBuffer();
+}
+
+void getInfo(string infoFileName, vector<FrameInfo> &Info) {
+ ifstream eleInfo;
+ eleInfo.open(infoFileName);
+ ASSERT_EQ(eleInfo.is_open(), true) << "Failed to open " << infoFileName;
+ int32_t bytesCount = 0;
+ uint32_t flags = 0;
+ uint32_t timestamp = 0;
+ while (1) {
+ if (!(eleInfo >> bytesCount)) {
+ break;
+ }
+ eleInfo >> flags;
+ eleInfo >> timestamp;
+ Info.push_back({bytesCount, flags, timestamp});
+ }
+ if (eleInfo.is_open()) eleInfo.close();
+}
+
+TEST_P(Mpeg4H263DecoderTest, DecodeTest) {
+ tuple<string /* InputFileName */, string /* InfoFileName */, bool /* mode */> params =
+ GetParam();
+
+ string inputFileName = gEnv->getRes() + get<0>(params);
+ mEleStream.open(inputFileName, ifstream::binary);
+ ASSERT_EQ(mEleStream.is_open(), true) << "Failed to open " << get<0>(params);
+
+ string infoFileName = gEnv->getRes() + get<1>(params);
+ vector<FrameInfo> Info;
+ ASSERT_NO_FATAL_FAILURE(getInfo(infoFileName, Info));
+ ASSERT_NE(Info.empty(), true) << "Invalid Info file";
+
+ ofstream ostrm;
+ ostrm.open(OUTPUT_FILE_NAME, std::ofstream::binary);
+ ASSERT_EQ(ostrm.is_open(), true) << "Failed to open output stream for " << get<0>(params);
+
+ status_t err = initDecoder();
+ ASSERT_EQ(err, OK) << "initDecoder: failed to create decoder " << err;
+
+ bool isMpeg4 = get<2>(params);
+ MP4DecodingMode inputMode = isMpeg4 ? MPEG4_MODE : H263_MODE;
+ ASSERT_NO_FATAL_FAILURE(
+ processMpeg4H263Decoder(Info, 0, Info.size(), mEleStream, ostrm, inputMode));
+ deInitDecoder();
+ ostrm.close();
+ Info.clear();
+}
+
+TEST_P(Mpeg4H263DecoderTest, FlushTest) {
+ tuple<string /* InputFileName */, string /* InfoFileName */, bool /* mode */> params =
+ GetParam();
+
+ string inputFileName = gEnv->getRes() + get<0>(params);
+ mEleStream.open(inputFileName, ifstream::binary);
+ ASSERT_EQ(mEleStream.is_open(), true) << "Failed to open " << get<0>(params);
+
+ string infoFileName = gEnv->getRes() + get<1>(params);
+ vector<FrameInfo> Info;
+ ASSERT_NO_FATAL_FAILURE(getInfo(infoFileName, Info));
+ ASSERT_NE(Info.empty(), true) << "Invalid Info file";
+
+ ofstream ostrm;
+ ostrm.open(OUTPUT_FILE_NAME, std::ofstream::binary);
+ ASSERT_EQ(ostrm.is_open(), true) << "Failed to open output stream for " << get<0>(params);
+
+ status_t err = initDecoder();
+ ASSERT_EQ(err, OK) << "initDecoder: failed to create decoder " << err;
+
+ bool isMpeg4 = get<2>(params);
+ MP4DecodingMode inputMode = isMpeg4 ? MPEG4_MODE : H263_MODE;
+ // Number of frames to be decoded before flush
+ int32_t numFrames = Info.size() / 3;
+ ASSERT_NO_FATAL_FAILURE(
+ processMpeg4H263Decoder(Info, 0, numFrames, mEleStream, ostrm, inputMode));
+
+ if (mInitialized) {
+ int32_t status = PVResetVideoDecoder(mDecHandle);
+ ASSERT_EQ(status, PV_TRUE);
+ }
+
+ // Seek to next key frame and start decoding till the end
+ int32_t index = numFrames;
+ bool keyFrame = false;
+ uint32_t flags = 0;
+ while (index < (int32_t)Info.size()) {
+ if (Info[index].flags) flags = 1u << (Info[index].flags - 1);
+ if ((flags & SYNC_FRAME) == SYNC_FRAME) {
+ keyFrame = true;
+ break;
+ }
+ flags = 0;
+ mEleStream.ignore(Info[index].bytesCount);
+ index++;
+ }
+ ALOGV("Index= %d", index);
+ if (keyFrame) {
+ mNumSamplesOutput = 0;
+ ASSERT_NO_FATAL_FAILURE(processMpeg4H263Decoder(Info, index, (int32_t)Info.size() - index,
+ mEleStream, ostrm, inputMode));
+ }
+ deInitDecoder();
+ ostrm.close();
+ Info.clear();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ Mpeg4H263DecoderTestAll, Mpeg4H263DecoderTest,
+ ::testing::Values(make_tuple("swirl_128x96_h263.h263", "swirl_128x96_h263.info", false),
+ make_tuple("swirl_176x144_h263.h263", "swirl_176x144_h263.info", false),
+ make_tuple("swirl_352x288_h263.h263", "swirl_352x288_h263.info", false),
+ make_tuple("bbb_352x288_h263.h263", "bbb_352x288_h263.info", false),
+ make_tuple("bbb_352x288_mpeg4.m4v", "bbb_352x288_mpeg4.info", true),
+ make_tuple("swirl_128x128_mpeg4.m4v", "swirl_128x128_mpeg4.info", true),
+ make_tuple("swirl_130x132_mpeg4.m4v", "swirl_130x132_mpeg4.info", true),
+ make_tuple("swirl_132x130_mpeg4.m4v", "swirl_132x130_mpeg4.info", true),
+ make_tuple("swirl_136x144_mpeg4.m4v", "swirl_136x144_mpeg4.info", true),
+ make_tuple("swirl_144x136_mpeg4.m4v", "swirl_144x136_mpeg4.info", true)));
+
+int main(int argc, char **argv) {
+ gEnv = new Mpeg4H263DecoderTestEnvironment();
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = gEnv->initFromOptions(argc, argv);
+ if (status == 0) {
+ status = RUN_ALL_TESTS();
+ ALOGD("Decoder Test Result = %d\n", status);
+ }
+ return status;
+}
diff --git a/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263DecoderTestEnvironment.h b/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263DecoderTestEnvironment.h
new file mode 100644
index 0000000..f085845
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263DecoderTestEnvironment.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPEG4_H263_DECODER_TEST_ENVIRONMENT_H__
+#define __MPEG4_H263_DECODER_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class Mpeg4H263DecoderTestEnvironment : public ::testing::Environment {
+ public:
+ Mpeg4H263DecoderTestEnvironment() : res("/data/local/tmp/") {}
+
+ // Parses the command line arguments
+ int initFromOptions(int argc, char **argv);
+
+ void setRes(const char *_res) { res = _res; }
+
+ const string getRes() const { return res; }
+
+ private:
+ string res;
+};
+
+int Mpeg4H263DecoderTestEnvironment::initFromOptions(int argc, char **argv) {
+ static struct option options[] = {{"path", required_argument, 0, 'P'}, {0, 0, 0, 0}};
+
+ while (true) {
+ int index = 0;
+ int c = getopt_long(argc, argv, "P:", options, &index);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'P': {
+ setRes(optarg);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ if (optind < argc) {
+ fprintf(stderr,
+ "unrecognized option: %s\n\n"
+ "usage: %s <gtest options> <test options>\n\n"
+ "test options are:\n\n"
+ "-P, --path: Resource files directory location\n",
+ argv[optind ?: 1], argv[0]);
+ return 2;
+ }
+ return 0;
+}
+
+#endif // __MPEG4_H263_DECODER_TEST_ENVIRONMENT_H__
diff --git a/media/libstagefright/codecs/m4v_h263/dec/test/README.md b/media/libstagefright/codecs/m4v_h263/dec/test/README.md
new file mode 100644
index 0000000..7e4aea1
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/dec/test/README.md
@@ -0,0 +1,39 @@
+## Media Testing ##
+---
+#### Mpeg4H263Decoder :
+The Mpeg4H263Decoder Test Suite validates the Mpeg4 and H263 decoder available in libstagefright.
+
+Run the following steps to build the test suite:
+```
+m Mpeg4H263DecoderTest
+```
+
+The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/
+
+The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/
+
+To test 64-bit binary push binaries from nativetest64.
+```
+adb push ${OUT}/data/nativetest64/Mpeg4H263DecoderTest/Mpeg4H263DecoderTest /data/local/tmp/
+```
+
+To test 32-bit binary push binaries from nativetest.
+```
+adb push ${OUT}/data/nativetest/Mpeg4H263DecoderTest/Mpeg4H263DecoderTest /data/local/tmp/
+```
+
+The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263Decoder.zip). Download, unzip and push these files into device for testing.
+
+```
+adb push Mpeg4H263Decoder /data/local/tmp/
+```
+
+usage: Mpeg4H263DecoderTest -P \<path_to_folder\>
+```
+adb shell /data/local/tmp/Mpeg4H263DecoderTest -P /data/local/tmp/Mpeg4H263Decoder/
+```
+Alternatively, the test can also be run using atest command.
+
+```
+atest Mpeg4H263DecoderTest -- --enable-module-dynamic-download=true
+```
diff --git a/media/libstagefright/codecs/m4v_h263/enc/Android.bp b/media/libstagefright/codecs/m4v_h263/enc/Android.bp
index 2738187..846f614 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/Android.bp
+++ b/media/libstagefright/codecs/m4v_h263/enc/Android.bp
@@ -23,10 +23,6 @@
cflags: [
"-DBX_RC",
- "-DOSCL_IMPORT_REF=",
- "-DOSCL_UNUSED_ARG(x)=(void)(x)",
- "-DOSCL_EXPORT_REF=",
-
"-Werror",
],
@@ -55,9 +51,6 @@
cflags: [
"-DBX_RC",
- "-DOSCL_IMPORT_REF=",
- "-DOSCL_UNUSED_ARG(x)=(void)(x)",
- "-DOSCL_EXPORT_REF=",
],
static_libs: ["libstagefright_m4vh263enc"],
@@ -81,8 +74,6 @@
local_include_dirs: ["src"],
cflags: [
- "-DOSCL_EXPORT_REF=",
- "-DOSCL_IMPORT_REF=",
"-DBX_RC",
"-Wall",
"-Werror",
diff --git a/media/libstagefright/codecs/m4v_h263/enc/include/mp4enc_api.h b/media/libstagefright/codecs/m4v_h263/enc/include/mp4enc_api.h
index d5a3ff1..9f824b1 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/include/mp4enc_api.h
+++ b/media/libstagefright/codecs/m4v_h263/enc/include/mp4enc_api.h
@@ -39,6 +39,16 @@
#define PV_TRUE 1
#define PV_FALSE 0
+#ifndef OSCL_IMPORT_REF
+#define OSCL_IMPORT_REF /* empty */
+#endif
+#ifndef OSCL_EXPORT_REF
+#define OSCL_EXPORT_REF /* empty */
+#endif
+#ifndef OSCL_UNUSED_ARG
+#define OSCL_UNUSED_ARG(x) ((void)(x))
+#endif
+
typedef enum
{
SHORT_HEADER,
diff --git a/media/libstagefright/codecs/m4v_h263/enc/test/Android.bp b/media/libstagefright/codecs/m4v_h263/enc/test/Android.bp
new file mode 100644
index 0000000..b9a8117
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/enc/test/Android.bp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+cc_test {
+ name: "Mpeg4H263EncoderTest",
+ gtest: true,
+
+ srcs : [ "Mpeg4H263EncoderTest.cpp" ],
+
+ shared_libs: [
+ "libutils",
+ "liblog",
+ ],
+
+ static_libs: [
+ "libstagefright_m4vh263enc",
+ ],
+
+ cflags: [
+ "-DOSCL_IMPORT_REF=",
+ "-Wall",
+ "-Werror",
+ ],
+
+ sanitize: {
+ misc_undefined: [
+ "signed-integer-overflow",
+ "unsigned-integer-overflow",
+ ],
+ cfi: true,
+ },
+}
diff --git a/media/libstagefright/codecs/m4v_h263/enc/test/AndroidTest.xml b/media/libstagefright/codecs/m4v_h263/enc/test/AndroidTest.xml
new file mode 100644
index 0000000..5218932
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/enc/test/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Test module config for MPEG4H263 encoder unit tests">
+ <option name="test-suite-tag" value="Mpeg4H263EncoderTest" />
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="Mpeg4H263EncoderTest->/data/local/tmp/Mpeg4H263EncoderTest/" />
+ <option name="push-file"
+ key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/m4v_h263/enc/test/Mpeg4H263Encoder.zip?unzip=true"
+ value="/data/local/tmp/Mpeg4H263EncoderTestRes/" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="Mpeg4H263EncoderTest" />
+ <option name="native-test-flag" value="-P /data/local/tmp/Mpeg4H263EncoderTestRes/" />
+ </test>
+</configuration>
\ No newline at end of file
diff --git a/media/libstagefright/codecs/m4v_h263/enc/test/Mpeg4H263EncoderTest.cpp b/media/libstagefright/codecs/m4v_h263/enc/test/Mpeg4H263EncoderTest.cpp
new file mode 100644
index 0000000..78c705a
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/enc/test/Mpeg4H263EncoderTest.cpp
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Mpeg4H263EncoderTest"
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#include "mp4enc_api.h"
+
+#include "Mpeg4H263EncoderTestEnvironment.h"
+
+#define ENCODED_FILE "/data/local/tmp/Mpeg4H263Output"
+
+// assuming a worst case compression of 2X
+constexpr int16_t kCompressionRatio = 2;
+constexpr int8_t kIDRFrameRefreshIntervalInSec = 1;
+
+static Mpeg4H263EncoderTestEnvironment *gEnv = nullptr;
+
+class Mpeg4H263EncoderTest
+ : public ::testing::TestWithParam<tuple<string, bool, int32_t, int32_t, float, int32_t>> {
+ private:
+ void initEncoderParams();
+
+ public:
+ Mpeg4H263EncoderTest()
+ : mInputBuffer(nullptr),
+ mOutputBuffer(nullptr),
+ mFpInput(nullptr),
+ mFpOutput(nullptr),
+ mEncodeHandle(nullptr),
+ mEncodeControl(nullptr) {}
+
+ ~Mpeg4H263EncoderTest() {
+ if(mFpInput) {
+ fclose(mFpInput);
+ }
+ if(mFpOutput) {
+ fclose(mFpOutput);
+ }
+ if(mInputBuffer) free(mInputBuffer);
+ if(mOutputBuffer) free(mOutputBuffer);
+ if(mEncodeHandle) free(mEncodeHandle);
+ if(mEncodeControl) free(mEncodeControl);
+ }
+
+ void SetUp() override {
+ tuple<string /* fileName */, bool /* isMpeg4 */, int32_t /* frameWidth */,
+ int32_t /* frameHeight */, float /* frameRate */, int32_t /* bitRate */>
+ params = GetParam();
+ mFileName = gEnv->getRes() + get<0>(params);
+ mIsMpeg4 = get<1>(params);
+ mFrameWidth = get<2>(params);
+ mFrameHeight = get<3>(params);
+ mFrameRate = get<4>(params);
+ mBitRate = get<5>(params);
+
+ ASSERT_TRUE(mFrameWidth % 16 == 0) << "Frame Width should be multiple of 16";
+ ASSERT_TRUE(mFrameHeight % 16 == 0) << "Frame Height should be multiple of 16";
+ ASSERT_LE(mFrameWidth, (mIsMpeg4 ? 720 : 352))
+ << "Frame Width <= 720 for Mpeg4 and <= 352 for H263";
+ ASSERT_LE(mFrameHeight, (mIsMpeg4 ? 480 : 288))
+ << "Frame Height <= 480 for Mpeg4 and <= 288 for H263";
+ ASSERT_LE(mFrameRate, 30) << "Frame rate less than or equal to 30";
+ ASSERT_LE(mBitRate, 2048) << "Bit rate less than or equal to 2048 kbps";
+
+ mOutputBufferSize = ( mFrameWidth * mFrameHeight * 3/2 ) / kCompressionRatio;
+ mEncodeHandle = new VideoEncOptions;
+ ASSERT_NE(mEncodeHandle, nullptr) << "Failed to get Video Encoding options object";
+ memset(mEncodeHandle, 0, sizeof(VideoEncOptions));
+ mEncodeControl = new VideoEncControls;
+ ASSERT_NE(mEncodeControl, nullptr) << "Failed to get Video Encoding control object";
+ memset(mEncodeControl, 0, sizeof(VideoEncControls));
+ ASSERT_NO_FATAL_FAILURE(initEncoderParams())
+ << "Failed to get the default Encoding parameters!";
+ }
+
+ int64_t getTotalFrames();
+ void processEncoder(int32_t);
+ bool mIsMpeg4;
+ int32_t mFrameWidth, mFrameHeight, mBitRate;
+ int64_t mOutputBufferSize;
+ float mFrameRate;
+ string mFileName;
+ uint8_t *mInputBuffer, *mOutputBuffer;
+ FILE *mFpInput, *mFpOutput;
+ VideoEncOptions *mEncodeHandle;
+ VideoEncControls *mEncodeControl;
+};
+
+void Mpeg4H263EncoderTest::initEncoderParams() {
+ bool status = PVGetDefaultEncOption(mEncodeHandle, 0);
+ ASSERT_TRUE(status);
+
+ mEncodeHandle->rcType = VBR_1;
+ mEncodeHandle->vbvDelay = 5.0f;
+ mEncodeHandle->profile_level = CORE_PROFILE_LEVEL2;
+ mEncodeHandle->packetSize = 32;
+ mEncodeHandle->rvlcEnable = PV_OFF;
+ mEncodeHandle->numLayers = 1;
+ mEncodeHandle->timeIncRes = 1000;
+ mEncodeHandle->iQuant[0] = 15;
+ mEncodeHandle->pQuant[0] = 12;
+ mEncodeHandle->quantType[0] = 0;
+ mEncodeHandle->noFrameSkipped = PV_OFF;
+ mEncodeHandle->numIntraMB = 0;
+ mEncodeHandle->sceneDetect = PV_ON;
+ mEncodeHandle->searchRange = 16;
+ mEncodeHandle->mv8x8Enable = PV_OFF;
+ mEncodeHandle->gobHeaderInterval = 0;
+ mEncodeHandle->useACPred = PV_ON;
+ mEncodeHandle->intraDCVlcTh = 0;
+ if(!mIsMpeg4) {
+ mEncodeHandle->encMode = H263_MODE;
+ } else {
+ mEncodeHandle->encMode = COMBINE_MODE_WITH_ERR_RES;
+ }
+ mEncodeHandle->encWidth[0] = mFrameWidth;
+ mEncodeHandle->encHeight[0] = mFrameHeight;
+ mEncodeHandle->encFrameRate[0] = mFrameRate;
+ mEncodeHandle->bitRate[0] = mBitRate * 1024;
+ mEncodeHandle->tickPerSrc = mEncodeHandle->timeIncRes / mFrameRate;
+ if (kIDRFrameRefreshIntervalInSec == 0) {
+ // All I frames.
+ mEncodeHandle->intraPeriod = 1;
+ } else {
+ mEncodeHandle->intraPeriod = (kIDRFrameRefreshIntervalInSec * mFrameRate);
+ }
+}
+
+int64_t Mpeg4H263EncoderTest::getTotalFrames() {
+ int32_t frameSize = (mFrameWidth * mFrameHeight * 3) / 2;
+ struct stat buf;
+ stat(mFileName.c_str(), &buf);
+ size_t fileSize = buf.st_size;
+ int64_t totalFrames = (int64_t)(fileSize/frameSize);
+ return totalFrames;
+}
+
+void Mpeg4H263EncoderTest::processEncoder(int32_t numFramesToEncode) {
+ bool status;
+ int64_t numEncodedFrames = 0;
+ int32_t bytesRead;
+ int32_t frameSize = (mFrameWidth * mFrameHeight * 3) / 2;
+ while(numFramesToEncode != 0) {
+ bytesRead = fread(mInputBuffer, 1, frameSize, mFpInput);
+ // End of file.
+ if (bytesRead != frameSize) {
+ break;
+ }
+
+ VideoEncFrameIO videoIn, videoOut;
+ videoIn.height = mFrameHeight;
+ videoIn.pitch = mFrameWidth;
+ videoIn.timestamp = (numEncodedFrames * 1000) / mFrameRate; // in ms.
+ videoIn.yChan = mInputBuffer;
+ videoIn.uChan = videoIn.yChan + videoIn.height * videoIn.pitch;
+ videoIn.vChan = videoIn.uChan + ((videoIn.height * videoIn.pitch) >> 2);
+ uint32_t modTimeMs = 0;
+ int32_t dataLength = mOutputBufferSize;
+ int32_t nLayer = 0;
+ status = PVEncodeVideoFrame(mEncodeControl, &videoIn, &videoOut, &modTimeMs, mOutputBuffer,
+ &dataLength, &nLayer);
+ ASSERT_TRUE(status) << "Failed to Encode: " << mFileName;
+
+ MP4HintTrack hintTrack;
+ status = PVGetHintTrack(mEncodeControl, &hintTrack);
+ ASSERT_TRUE(status) << "Failed to get hint track!";
+ UChar *overrunBuffer = PVGetOverrunBuffer(mEncodeControl);
+ ASSERT_EQ(overrunBuffer, nullptr) << "Overrun of buffer!";
+
+ int64_t numBytes = fwrite(mOutputBuffer, 1, dataLength, mFpOutput);
+ ASSERT_EQ(numBytes, dataLength) << "Failed to write to the output file!";
+ numEncodedFrames++;
+ numFramesToEncode--;
+ }
+}
+
+TEST_P(Mpeg4H263EncoderTest, EncodeTest) {
+ mInputBuffer = (uint8_t *)malloc((mFrameWidth * mFrameWidth * 3) / 2);
+ ASSERT_NE(mInputBuffer, nullptr) << "Failed to allocate the input buffer!";
+
+ mOutputBuffer = (uint8_t *)malloc(mOutputBufferSize);
+ ASSERT_NE(mOutputBuffer, nullptr) << "Failed to allocate the output buffer!";
+
+ mFpInput = fopen(mFileName.c_str(), "rb");
+ ASSERT_NE(mFpInput, nullptr) << "Failed to open the input file: " << mFileName;
+
+ mFpOutput = fopen(ENCODED_FILE, "wb");
+ ASSERT_NE(mFpOutput, nullptr) << "Failed to open the output file:" << ENCODED_FILE;
+
+ bool status = PVInitVideoEncoder(mEncodeControl, mEncodeHandle);
+ ASSERT_TRUE(status) << "Failed to initialize the encoder!";
+
+ // Get VOL header.
+ int32_t size = mOutputBufferSize;
+ status = PVGetVolHeader(mEncodeControl, mOutputBuffer, &size, 0);
+ ASSERT_TRUE(status) << "Failed to get the VOL header!";
+
+ // Write the VOL header on the first frame.
+ int32_t numBytes = fwrite(mOutputBuffer, 1, size, mFpOutput);
+ ASSERT_EQ(numBytes, size) << "Failed to write the VOL header!";
+
+ int64_t totalFrames = getTotalFrames();
+ ASSERT_NO_FATAL_FAILURE(processEncoder(totalFrames)) << "Failed to Encode: " << mFileName;
+ status = PVCleanUpVideoEncoder(mEncodeControl);
+ ASSERT_TRUE(status) << "Failed to clean up the encoder resources!";
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ EncodeTest, Mpeg4H263EncoderTest,
+ ::testing::Values(
+ make_tuple("bbb_352x288_420p_30fps_32frames.yuv", false, 352, 288, 25, 1024),
+ make_tuple("bbb_352x288_420p_30fps_32frames.yuv", true, 352, 288, 25, 1024),
+ make_tuple("bbb_352x288_420p_30fps_32frames.yuv", false, 176, 144, 25, 1024),
+ make_tuple("bbb_352x288_420p_30fps_32frames.yuv", true, 176, 144, 25, 1024),
+ make_tuple("football_qvga.yuv", false, 352, 288, 25, 1024),
+ make_tuple("football_qvga.yuv", true, 352, 288, 25, 1024),
+ make_tuple("football_qvga.yuv", false, 176, 144, 30, 1024),
+ make_tuple("football_qvga.yuv", true, 176, 144, 30, 1024)));
+
+int32_t main(int argc, char **argv) {
+ gEnv = new Mpeg4H263EncoderTestEnvironment();
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ uint8_t status = gEnv->initFromOptions(argc, argv);
+ if (status == 0) {
+ status = RUN_ALL_TESTS();
+ ALOGI("Encoder Test Result = %d\n", status);
+ }
+ return status;
+}
diff --git a/media/libstagefright/codecs/m4v_h263/enc/test/Mpeg4H263EncoderTestEnvironment.h b/media/libstagefright/codecs/m4v_h263/enc/test/Mpeg4H263EncoderTestEnvironment.h
new file mode 100644
index 0000000..7ee36e0
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/enc/test/Mpeg4H263EncoderTestEnvironment.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPEG4_H263_ENCODER_TEST_ENVIRONMENT_H__
+#define __MPEG4_H263_ENCODER_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class Mpeg4H263EncoderTestEnvironment : public::testing::Environment {
+ public:
+ Mpeg4H263EncoderTestEnvironment() : res("/data/local/tmp/Mpeg4H263EncoderTest/") {}
+
+ // Parses the command line arguments
+ int initFromOptions(int argc, char **argv);
+
+ void setRes(const char *_res) { res = _res; }
+
+ const string getRes() const { return res; }
+
+ private:
+ string res;
+};
+
+int Mpeg4H263EncoderTestEnvironment::initFromOptions(int argc, char **argv) {
+ static struct option options[] = {{"path", required_argument, 0, 'P'}, {0, 0, 0, 0}};
+
+ while (true) {
+ int index = 0;
+ int c = getopt_long(argc, argv, "P:", options, &index);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'P': {
+ setRes(optarg);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ if (optind < argc) {
+ fprintf(stderr,
+ "unrecognized option: %s\n\n"
+ "usage: %s <gtest options> <test options>\n\n"
+ "test options are:\n\n"
+ "-P, --path: Resource files directory location\n",
+ argv[optind ?: 1], argv[0]);
+ return 2;
+ }
+ return 0;
+}
+
+#endif // __MPEG4_H263_ENCODER_TEST_ENVIRONMENT_H__
diff --git a/media/libstagefright/codecs/m4v_h263/enc/test/README.md b/media/libstagefright/codecs/m4v_h263/enc/test/README.md
new file mode 100644
index 0000000..25de878
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/enc/test/README.md
@@ -0,0 +1,38 @@
+## Media Testing ##
+---
+
+#### Mpeg4H263Encoder :
+The Mpeg4H263Encoder Test Suite validates the Mpeg4 and H263 encoder available in libstagefright.
+Run the following steps to build the test suite:
+```
+m Mpeg4H263EncoderTest
+```
+
+The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/
+The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/
+
+To test 64-bit binary push binaries from nativetest64.
+```
+adb push ${OUT}/data/nativetest64/Mpeg4H263EncoderTest/Mpeg4H263EncoderTest /data/local/tmp/
+```
+
+To test 32-bit binary push binaries from nativetest.
+```
+adb push ${OUT}/data/nativetest/Mpeg4H263EncoderTest/Mpeg4H263EncoderTest /data/local/tmp/
+```
+
+The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/m4v_h263/enc/test/Mpeg4H263Encoder.zip ) Download, unzip and push these files into device for testing.
+
+```
+adb push Mpeg4H263Encoder/. /data/local/tmp/
+```
+
+usage: Mpeg4H263EncoderTest -P \<path_to_folder\>
+```
+adb shell /data/local/tmp/Mpeg4H263EncoderTest -P /data/local/tmp/
+```
+Alternatively, the test can also be run using atest command.
+
+```
+atest Mpeg4H263EncoderTest -- --enable-module-dynamic-download=true
+```
diff --git a/media/libstagefright/codecs/mp3dec/src/pv_mp3dec_fxd_op_c_equivalent.h b/media/libstagefright/codecs/mp3dec/src/pv_mp3dec_fxd_op_c_equivalent.h
index adb0dd4..f9d91b1 100644
--- a/media/libstagefright/codecs/mp3dec/src/pv_mp3dec_fxd_op_c_equivalent.h
+++ b/media/libstagefright/codecs/mp3dec/src/pv_mp3dec_fxd_op_c_equivalent.h
@@ -44,7 +44,7 @@
#endif
#include "pvmp3_audio_type_defs.h"
-#define Qfmt_31(a) (Int32)((float)(a)*0x7FFFFFFF)
+#define Qfmt_31(a) (Int32)((float)(a)*(float)0x7FFFFFFF)
#define Qfmt15(x) (Int16)((x)*((Int32)1<<15) + ((x)>=0?0.5F:-0.5F))
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_alias_reduction.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_alias_reduction.cpp
index af738ba..6c8102b 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_alias_reduction.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_alias_reduction.cpp
@@ -169,7 +169,7 @@
int32 i, j;
- *used_freq_lines = fxp_mul32_Q32(*used_freq_lines << 16, (int32)(0x7FFFFFFF / (float)18 - 1.0f)) >> 15;
+ *used_freq_lines = fxp_mul32_Q32(*used_freq_lines << 16, (int32)((float)0x7FFFFFFF / (float)18 - 1.0f)) >> 15;
if (gr_info->window_switching_flag && gr_info->block_type == 2)
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_9.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_9.cpp
index bbb247d..9cd0e91 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_9.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_9.cpp
@@ -77,7 +77,7 @@
; Include all pre-processor statements here. Include conditional
; compile variables also.
----------------------------------------------------------------------------*/
-#define Qfmt31(a) (int32)((a)*(0x7FFFFFFF))
+#define Qfmt31(a) (int32)((a)*((float)0x7FFFFFFF))
#define cos_pi_9 Qfmt31( 0.93969262078591f)
#define cos_2pi_9 Qfmt31( 0.76604444311898f)
diff --git a/media/libstagefright/codecs/mp3dec/test/Android.bp b/media/libstagefright/codecs/mp3dec/test/Android.bp
new file mode 100644
index 0000000..0ff8b12
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/test/Android.bp
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+cc_test {
+ name: "Mp3DecoderTest",
+ gtest: true,
+
+ srcs: [
+ "mp3reader.cpp",
+ "Mp3DecoderTest.cpp",
+ ],
+
+ static_libs: [
+ "libstagefright_mp3dec",
+ "libsndfile",
+ "libaudioutils",
+ ],
+
+ shared_libs: [
+ "liblog",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ sanitize: {
+ cfi: true,
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ },
+}
diff --git a/media/libstagefright/codecs/mp3dec/test/AndroidTest.xml b/media/libstagefright/codecs/mp3dec/test/AndroidTest.xml
new file mode 100644
index 0000000..7ff9732
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/test/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Test module config for Mp3 Decoder unit test">
+ <option name="test-suite-tag" value="Mp3DecoderTest" />
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="Mp3DecoderTest->/data/local/tmp/Mp3DecoderTest" />
+ <option name="push-file"
+ key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/mp3dec/test/Mp3DecoderTest.zip?unzip=true"
+ value="/data/local/tmp/Mp3DecoderTestRes/" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="Mp3DecoderTest" />
+ <option name="native-test-flag" value="-P /data/local/tmp/Mp3DecoderTestRes/" />
+ </test>
+</configuration>
diff --git a/media/libstagefright/codecs/mp3dec/test/Mp3DecoderTest.cpp b/media/libstagefright/codecs/mp3dec/test/Mp3DecoderTest.cpp
new file mode 100644
index 0000000..99553ec
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/test/Mp3DecoderTest.cpp
@@ -0,0 +1,200 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Mp3DecoderTest"
+
+#include <utils/Log.h>
+
+#include <audio_utils/sndfile.h>
+#include <stdio.h>
+
+#include "mp3reader.h"
+#include "pvmp3decoder_api.h"
+
+#include "Mp3DecoderTestEnvironment.h"
+
+#define OUTPUT_FILE "/data/local/tmp/mp3Decode.out"
+
+constexpr int32_t kInputBufferSize = 1024 * 10;
+constexpr int32_t kOutputBufferSize = 4608 * 2;
+constexpr int32_t kMaxCount = 10;
+constexpr int32_t kNumFrameReset = 150;
+
+static Mp3DecoderTestEnvironment *gEnv = nullptr;
+
+class Mp3DecoderTest : public ::testing::TestWithParam<string> {
+ public:
+ Mp3DecoderTest() : mConfig(nullptr) {}
+
+ ~Mp3DecoderTest() {
+ if (mConfig) {
+ delete mConfig;
+ mConfig = nullptr;
+ }
+ }
+
+ virtual void SetUp() override {
+ mConfig = new tPVMP3DecoderExternal{};
+ ASSERT_NE(mConfig, nullptr) << "Failed to initialize config. No Memory available";
+ mConfig->equalizerType = flat;
+ mConfig->crcEnabled = false;
+ }
+
+ tPVMP3DecoderExternal *mConfig;
+ Mp3Reader mMp3Reader;
+
+ ERROR_CODE DecodeFrames(void *decoderbuf, SNDFILE *outFileHandle, SF_INFO sfInfo,
+ int32_t frameCount = INT32_MAX);
+ SNDFILE *openOutputFile(SF_INFO *sfInfo);
+};
+
+ERROR_CODE Mp3DecoderTest::DecodeFrames(void *decoderBuf, SNDFILE *outFileHandle, SF_INFO sfInfo,
+ int32_t frameCount) {
+ uint8_t inputBuf[kInputBufferSize];
+ int16_t outputBuf[kOutputBufferSize];
+ uint32_t bytesRead;
+ ERROR_CODE decoderErr;
+ while (frameCount > 0) {
+ bool success = mMp3Reader.getFrame(inputBuf, &bytesRead);
+ if (!success) {
+ break;
+ }
+ mConfig->inputBufferCurrentLength = bytesRead;
+ mConfig->inputBufferMaxLength = 0;
+ mConfig->inputBufferUsedLength = 0;
+ mConfig->pInputBuffer = inputBuf;
+ mConfig->pOutputBuffer = outputBuf;
+ mConfig->outputFrameSize = kOutputBufferSize / sizeof(int16_t);
+ decoderErr = pvmp3_framedecoder(mConfig, decoderBuf);
+ if (decoderErr != NO_DECODING_ERROR) break;
+ sf_writef_short(outFileHandle, outputBuf, mConfig->outputFrameSize / sfInfo.channels);
+ frameCount--;
+ }
+ return decoderErr;
+}
+
+SNDFILE *Mp3DecoderTest::openOutputFile(SF_INFO *sfInfo) {
+ memset(sfInfo, 0, sizeof(SF_INFO));
+ sfInfo->channels = mMp3Reader.getNumChannels();
+ sfInfo->format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
+ sfInfo->samplerate = mMp3Reader.getSampleRate();
+ SNDFILE *outFileHandle = sf_open(OUTPUT_FILE, SFM_WRITE, sfInfo);
+ return outFileHandle;
+}
+
+TEST_F(Mp3DecoderTest, MultiCreateMp3DecoderTest) {
+ size_t memRequirements = pvmp3_decoderMemRequirements();
+ ASSERT_NE(memRequirements, 0) << "Failed to get the memory requirement size";
+ void *decoderBuf = malloc(memRequirements);
+ ASSERT_NE(decoderBuf, nullptr)
+ << "Failed to allocate decoder memory of size " << memRequirements;
+ for (int count = 0; count < kMaxCount; count++) {
+ pvmp3_InitDecoder(mConfig, decoderBuf);
+ ALOGV("Decoder created successfully");
+ }
+ if (decoderBuf) {
+ free(decoderBuf);
+ decoderBuf = nullptr;
+ }
+}
+
+TEST_P(Mp3DecoderTest, DecodeTest) {
+ size_t memRequirements = pvmp3_decoderMemRequirements();
+ ASSERT_NE(memRequirements, 0) << "Failed to get the memory requirement size";
+ void *decoderBuf = malloc(memRequirements);
+ ASSERT_NE(decoderBuf, nullptr)
+ << "Failed to allocate decoder memory of size " << memRequirements;
+
+ pvmp3_InitDecoder(mConfig, decoderBuf);
+ ALOGV("Decoder created successfully");
+ string inputFile = gEnv->getRes() + GetParam();
+ bool status = mMp3Reader.init(inputFile.c_str());
+ ASSERT_TRUE(status) << "Unable to initialize the mp3Reader";
+
+ // Open the output file.
+ SF_INFO sfInfo;
+ SNDFILE *outFileHandle = openOutputFile(&sfInfo);
+ ASSERT_NE(outFileHandle, nullptr) << "Error opening output file for writing decoded output";
+
+ ERROR_CODE decoderErr = DecodeFrames(decoderBuf, outFileHandle, sfInfo);
+ ASSERT_EQ(decoderErr, NO_DECODING_ERROR) << "Failed to decode the frames";
+ ASSERT_EQ(sfInfo.channels, mConfig->num_channels) << "Number of channels does not match";
+ ASSERT_EQ(sfInfo.samplerate, mConfig->samplingRate) << "Sample rate does not match";
+
+ mMp3Reader.close();
+ sf_close(outFileHandle);
+ if (decoderBuf) {
+ free(decoderBuf);
+ decoderBuf = nullptr;
+ }
+}
+
+TEST_P(Mp3DecoderTest, ResetDecoderTest) {
+ size_t memRequirements = pvmp3_decoderMemRequirements();
+ ASSERT_NE(memRequirements, 0) << "Failed to get the memory requirement size";
+ void *decoderBuf = malloc(memRequirements);
+ ASSERT_NE(decoderBuf, nullptr)
+ << "Failed to allocate decoder memory of size " << memRequirements;
+
+ pvmp3_InitDecoder(mConfig, decoderBuf);
+ ALOGV("Decoder created successfully.");
+ string inputFile = gEnv->getRes() + GetParam();
+ bool status = mMp3Reader.init(inputFile.c_str());
+ ASSERT_TRUE(status) << "Unable to initialize the mp3Reader";
+
+ // Open the output file.
+ SF_INFO sfInfo;
+ SNDFILE *outFileHandle = openOutputFile(&sfInfo);
+ ASSERT_NE(outFileHandle, nullptr) << "Error opening output file for writing decoded output";
+
+ ERROR_CODE decoderErr;
+ decoderErr = DecodeFrames(decoderBuf, outFileHandle, sfInfo, kNumFrameReset);
+ ASSERT_EQ(decoderErr, NO_DECODING_ERROR) << "Failed to decode the frames";
+ ASSERT_EQ(sfInfo.channels, mConfig->num_channels) << "Number of channels does not match";
+ ASSERT_EQ(sfInfo.samplerate, mConfig->samplingRate) << "Sample rate does not match";
+
+ pvmp3_resetDecoder(decoderBuf);
+ // Decode the same file.
+ decoderErr = DecodeFrames(decoderBuf, outFileHandle, sfInfo);
+ ASSERT_EQ(decoderErr, NO_DECODING_ERROR) << "Failed to decode the frames";
+ ASSERT_EQ(sfInfo.channels, mConfig->num_channels) << "Number of channels does not match";
+ ASSERT_EQ(sfInfo.samplerate, mConfig->samplingRate) << "Sample rate does not match";
+
+ mMp3Reader.close();
+ sf_close(outFileHandle);
+ if (decoderBuf) {
+ free(decoderBuf);
+ decoderBuf = nullptr;
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(Mp3DecoderTestAll, Mp3DecoderTest,
+ ::testing::Values(("bbb_44100hz_2ch_128kbps_mp3_30sec.mp3"),
+ ("bbb_44100hz_2ch_128kbps_mp3_5mins.mp3"),
+ ("bbb_mp3_stereo_192kbps_48000hz.mp3")));
+
+int main(int argc, char **argv) {
+ gEnv = new Mp3DecoderTestEnvironment();
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = gEnv->initFromOptions(argc, argv);
+ if (status == 0) {
+ status = RUN_ALL_TESTS();
+ ALOGV("Test result = %d\n", status);
+ }
+ return status;
+}
diff --git a/media/libstagefright/codecs/mp3dec/test/Mp3DecoderTestEnvironment.h b/media/libstagefright/codecs/mp3dec/test/Mp3DecoderTestEnvironment.h
new file mode 100644
index 0000000..a54b34c
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/test/Mp3DecoderTestEnvironment.h
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#ifndef __MP3DECODER_TEST_ENVIRONMENT_H__
+#define __MP3DECODER_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class Mp3DecoderTestEnvironment : public ::testing::Environment {
+ public:
+ Mp3DecoderTestEnvironment() : res("/data/local/tmp/") {}
+
+ // Parses the command line arguments
+ int initFromOptions(int argc, char **argv);
+
+ void setRes(const char *_res) { res = _res; }
+
+ const string getRes() const { return res; }
+
+ private:
+ string res;
+};
+
+int Mp3DecoderTestEnvironment::initFromOptions(int argc, char **argv) {
+ static struct option options[] = {{"res", required_argument, 0, 'P'}, {0, 0, 0, 0}};
+
+ while (true) {
+ int index = 0;
+ int c = getopt_long(argc, argv, "P:", options, &index);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'P':
+ setRes(optarg);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (optind < argc) {
+ fprintf(stderr,
+ "unrecognized option: %s\n\n"
+ "usage: %s <gtest options> <test options>\n\n"
+ "test options are:\n\n"
+ "-P, --path: Resource files directory location\n",
+ argv[optind ?: 1], argv[0]);
+ return 2;
+ }
+ return 0;
+}
+
+#endif // __MP3DECODER_TEST_ENVIRONMENT_H__
diff --git a/media/libstagefright/codecs/mp3dec/test/README.md b/media/libstagefright/codecs/mp3dec/test/README.md
new file mode 100644
index 0000000..f59fec7
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/test/README.md
@@ -0,0 +1,39 @@
+## Media Testing ##
+---
+#### Mp3Decoder :
+The Mp3Decoder Test Suite validates the mp3decoder available in libstagefright.
+
+Run the following steps to build the test suite:
+```
+m Mp3DecoderTest
+```
+
+The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/
+
+The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/
+
+To test 64-bit binary push binaries from nativetest64.
+```
+adb push ${OUT}/data/nativetest64/Mp3DecoderTest/Mp3DecoderTest /data/local/tmp/
+```
+
+To test 32-bit binary push binaries from nativetest.
+```
+adb push ${OUT}/data/nativetest/Mp3DecoderTest/Mp3DecoderTest /data/local/tmp/
+```
+
+The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/mp3dec/test/Mp3DecoderTest.zip). Download, unzip and push these files into device for testing.
+
+```
+adb push Mp3DecoderTestRes/. /data/local/tmp/
+```
+
+usage: Mp3DecoderTest -P \<path_to_folder\>
+```
+adb shell /data/local/tmp/Mp3DecoderTest -P /data/local/tmp/Mp3DecoderTestRes/
+```
+Alternatively, the test can also be run using atest command.
+
+```
+atest Mp3DecoderTest -- --enable-module-dynamic-download=true
+```
diff --git a/media/libstagefright/codecs/on2/enc/Android.bp b/media/libstagefright/codecs/on2/enc/Android.bp
index cd69e0d..705e554 100644
--- a/media/libstagefright/codecs/on2/enc/Android.bp
+++ b/media/libstagefright/codecs/on2/enc/Android.bp
@@ -21,4 +21,5 @@
},
shared_libs: ["libvpx"],
+ header_libs: ["libbase_headers"],
}
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
index 1293a74..08e20cc 100644
--- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
@@ -572,16 +572,17 @@
}
void SoftVorbis::onPortFlushCompleted(OMX_U32 portIndex) {
- if (portIndex == 0 && mState != NULL) {
- // Make sure that the next buffer output does not still
- // depend on fragments from the last one decoded.
-
+ if (portIndex == 0) {
mInputBufferCount = 0;
mNumFramesOutput = 0;
mSawInputEos = false;
mSignalledOutputEos = false;
mNumFramesLeftOnPage = -1;
- vorbis_dsp_restart(mState);
+ if (mState != NULL) {
+ // Make sure that the next buffer output does not still
+ // depend on fragments from the last one decoded.
+ vorbis_dsp_restart(mState);
+ }
}
}
@@ -603,6 +604,7 @@
mSawInputEos = false;
mSignalledOutputEos = false;
mSignalledError = false;
+ mNumFramesLeftOnPage = -1;
mOutputPortSettingsChange = NONE;
}
diff --git a/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp b/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp
index da86758..87e8fd4 100644
--- a/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp
+++ b/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp
@@ -1426,75 +1426,90 @@
RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_DO_EXECUTE");
UWORD32 ui_exec_done;
+ WORD32 i_num_preroll = 0;
/* Checking for end of processing */
err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_EXECUTE, IA_CMD_TYPE_DONE_QUERY,
&ui_exec_done);
RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_DONE_QUERY");
-#ifdef ENABLE_MPEG_D_DRC
+ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM,
+ IA_ENHAACPLUS_DEC_CONFIG_GET_NUM_PRE_ROLL_FRAMES,
+ &i_num_preroll);
+
+ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_GET_NUM_PRE_ROLL_FRAMES");
{
- if (ui_exec_done != 1) {
- VOID* p_array; // ITTIAM:buffer to handle gain payload
- WORD32 buf_size = 0; // ITTIAM:gain payload length
- WORD32 bit_str_fmt = 1;
- WORD32 gain_stream_flag = 1;
+ int32_t pi_preroll_frame_offset = 0;
+ do {
+#ifdef ENABLE_MPEG_D_DRC
+ if (ui_exec_done != 1) {
+ VOID* p_array; // ITTIAM:buffer to handle gain payload
+ WORD32 buf_size = 0; // ITTIAM:gain payload length
+ WORD32 bit_str_fmt = 1;
+ WORD32 gain_stream_flag = 1;
- err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM,
- IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_LEN, &buf_size);
- RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_LEN");
+ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM,
+ IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_LEN, &buf_size);
+ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_LEN");
- err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM,
- IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_BUF, &p_array);
- RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_BUF");
+ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM,
+ IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_BUF, &p_array);
+ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_BUF");
- if (buf_size > 0) {
- /*Set bitstream_split_format */
- err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM,
- IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT, &bit_str_fmt);
- RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
+ if (buf_size > 0) {
+ /*Set bitstream_split_format */
+ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM,
+ IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT, &bit_str_fmt);
+ RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
- memcpy(mDrcInBuf, p_array, buf_size);
- /* Set number of bytes to be processed */
- err_code =
- ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_INPUT_BYTES_BS, 0, &buf_size);
- RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
+ memcpy(mDrcInBuf, p_array, buf_size);
+ /* Set number of bytes to be processed */
+ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_INPUT_BYTES_BS,
+ 0, &buf_size);
+ RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
- err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM,
- IA_DRC_DEC_CONFIG_GAIN_STREAM_FLAG, &gain_stream_flag);
- RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
+ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM,
+ IA_DRC_DEC_CONFIG_GAIN_STREAM_FLAG,
+ &gain_stream_flag);
+ RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
- /* Execute process */
- err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT,
- IA_CMD_TYPE_INIT_CPY_BSF_BUFF, NULL);
- RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
+ /* Execute process */
+ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT,
+ IA_CMD_TYPE_INIT_CPY_BSF_BUFF, NULL);
+ RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
- mMpegDDRCPresent = 1;
+ mMpegDDRCPresent = 1;
+ }
}
- }
- }
#endif
- /* How much buffer is used in input buffers */
- err_code =
- ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CURIDX_INPUT_BUF, 0, bytesConsumed);
- RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_CURIDX_INPUT_BUF");
+ /* How much buffer is used in input buffers */
+ err_code =
+ ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CURIDX_INPUT_BUF,
+ 0, bytesConsumed);
+ RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_CURIDX_INPUT_BUF");
- /* Get the output bytes */
- err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_OUTPUT_BYTES, 0, outBytes);
- RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_OUTPUT_BYTES");
+ /* Get the output bytes */
+ err_code = ixheaacd_dec_api(mXheaacCodecHandle,
+ IA_API_CMD_GET_OUTPUT_BYTES, 0, outBytes);
+ RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_OUTPUT_BYTES");
#ifdef ENABLE_MPEG_D_DRC
- if (mMpegDDRCPresent == 1) {
- memcpy(mDrcInBuf, mOutputBuffer, *outBytes);
- err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_INPUT_BYTES, 0, outBytes);
- RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_INPUT_BYTES");
+ if (mMpegDDRCPresent == 1) {
+ memcpy(mDrcInBuf, mOutputBuffer + pi_preroll_frame_offset, *outBytes);
+ pi_preroll_frame_offset += *outBytes;
+ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_INPUT_BYTES,
+ 0, outBytes);
+ RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_INPUT_BYTES");
- err_code =
- ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_EXECUTE, IA_CMD_TYPE_DO_EXECUTE, NULL);
- RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_DO_EXECUTE");
+ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_EXECUTE,
+ IA_CMD_TYPE_DO_EXECUTE, NULL);
+ RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_DO_EXECUTE");
- memcpy(mOutputBuffer, mDrcOutBuf, *outBytes);
- }
+ memcpy(mOutputBuffer, mDrcOutBuf, *outBytes);
+ }
#endif
+ i_num_preroll--;
+ } while (i_num_preroll > 0);
+ }
return IA_NO_ERROR;
}
diff --git a/media/libstagefright/colorconversion/Android.bp b/media/libstagefright/colorconversion/Android.bp
index ba57497..6b08b08 100644
--- a/media/libstagefright/colorconversion/Android.bp
+++ b/media/libstagefright/colorconversion/Android.bp
@@ -15,6 +15,11 @@
"libnativewindow",
],
+ header_libs: [
+ "libstagefright_headers",
+ "libstagefright_foundation_headers",
+ ],
+
static_libs: ["libyuv_static"],
cflags: ["-Werror"],
diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp
index d685321..c7dc415 100644
--- a/media/libstagefright/colorconversion/ColorConverter.cpp
+++ b/media/libstagefright/colorconversion/ColorConverter.cpp
@@ -324,8 +324,8 @@
}
#define DECLARE_YUV2RGBFUNC(func, rgb) int (*func)( \
- const uint8*, int, const uint8*, int, \
- const uint8*, int, uint8*, int, int, int) \
+ const uint8_t*, int, const uint8_t*, int, \
+ const uint8_t*, int, uint8_t*, int, int, int) \
= mSrcColorSpace.isBt709() ? libyuv::H420To##rgb \
: mSrcColorSpace.isJpeg() ? libyuv::J420To##rgb \
: libyuv::I420To##rgb
@@ -350,7 +350,7 @@
{
DECLARE_YUV2RGBFUNC(func, RGB565);
(*func)(src_y, src.mStride, src_u, src.mStride / 2, src_v, src.mStride / 2,
- (uint8 *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight());
+ (uint8_t *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight());
break;
}
@@ -358,7 +358,7 @@
{
DECLARE_YUV2RGBFUNC(func, ABGR);
(*func)(src_y, src.mStride, src_u, src.mStride / 2, src_v, src.mStride / 2,
- (uint8 *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight());
+ (uint8_t *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight());
break;
}
@@ -366,7 +366,7 @@
{
DECLARE_YUV2RGBFUNC(func, ARGB);
(*func)(src_y, src.mStride, src_u, src.mStride / 2, src_v, src.mStride / 2,
- (uint8 *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight());
+ (uint8_t *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight());
break;
}
@@ -391,17 +391,17 @@
switch (mDstFormat) {
case OMX_COLOR_Format16bitRGB565:
- libyuv::NV12ToRGB565(src_y, src.mStride, src_u, src.mStride, (uint8 *)dst_ptr,
+ libyuv::NV12ToRGB565(src_y, src.mStride, src_u, src.mStride, (uint8_t *)dst_ptr,
dst.mStride, src.cropWidth(), src.cropHeight());
break;
case OMX_COLOR_Format32bitBGRA8888:
- libyuv::NV12ToARGB(src_y, src.mStride, src_u, src.mStride, (uint8 *)dst_ptr,
+ libyuv::NV12ToARGB(src_y, src.mStride, src_u, src.mStride, (uint8_t *)dst_ptr,
dst.mStride, src.cropWidth(), src.cropHeight());
break;
case OMX_COLOR_Format32BitRGBA8888:
- libyuv::NV12ToABGR(src_y, src.mStride, src_u, src.mStride, (uint8 *)dst_ptr,
+ libyuv::NV12ToABGR(src_y, src.mStride, src_u, src.mStride, (uint8_t *)dst_ptr,
dst.mStride, src.cropWidth(), src.cropHeight());
break;
diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
index 359df3d..4711315 100644
--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp
+++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
@@ -31,9 +31,14 @@
namespace android {
-static int ALIGN(int x, int y) {
- // y must be a power of 2.
- return (x + y - 1) & ~(y - 1);
+inline void initDstYUV(
+ const android_ycbcr &ycbcr, int32_t cropTop, int32_t cropLeft,
+ uint8_t **dst_y, uint8_t **dst_u, uint8_t **dst_v) {
+ *dst_y = (uint8_t *)ycbcr.y + cropTop * ycbcr.ystride + cropLeft;
+
+ int32_t c_offset = (cropTop / 2) * ycbcr.cstride + cropLeft / 2;
+ *dst_v = (uint8_t *)ycbcr.cr + c_offset;
+ *dst_u = (uint8_t *)ycbcr.cb + c_offset;
}
SoftwareRenderer::SoftwareRenderer(
@@ -269,10 +274,21 @@
Rect bounds(mCropWidth, mCropHeight);
- void *dst;
- CHECK_EQ(0, mapper.lock(buf->handle,
- GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_RARELY,
- bounds, &dst));
+ void *dst = NULL;
+ struct android_ycbcr ycbcr;
+ if ( !mConverter &&
+ (mColorFormat == OMX_COLOR_FormatYUV420Planar ||
+ mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar ||
+ mColorFormat == OMX_TI_COLOR_FormatYUV420PackedSemiPlanar ||
+ mColorFormat == OMX_COLOR_FormatYUV420Planar16)) {
+ CHECK_EQ(0, mapper.lockYCbCr(buf->handle,
+ GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_RARELY,
+ bounds, &ycbcr));
+ } else {
+ CHECK_EQ(0, mapper.lock(buf->handle,
+ GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_RARELY,
+ bounds, &dst));
+ }
// TODO move the other conversions also into ColorConverter, and
// fix cropping issues (when mCropLeft/Top != 0 or mWidth != mCropWidth)
@@ -289,22 +305,14 @@
const uint8_t *src_u = (const uint8_t *)data + mStride * mHeight + mCropTop * mStride / 4;
const uint8_t *src_v = (const uint8_t *)src_u + mStride * mHeight / 4;
- uint8_t *dst_y = (uint8_t *)dst;
- size_t dst_y_size = buf->stride * buf->height;
- size_t dst_c_stride = ALIGN(buf->stride / 2, 16);
- size_t dst_c_size = dst_c_stride * buf->height / 2;
- uint8_t *dst_v = dst_y + dst_y_size;
- uint8_t *dst_u = dst_v + dst_c_size;
-
- dst_y += mCropTop * buf->stride + mCropLeft;
- dst_v += (mCropTop/2) * dst_c_stride + mCropLeft/2;
- dst_u += (mCropTop/2) * dst_c_stride + mCropLeft/2;
+ uint8_t *dst_y, *dst_u, *dst_v;
+ initDstYUV(ycbcr, mCropTop, mCropLeft, &dst_y, &dst_u, &dst_v);
for (int y = 0; y < mCropHeight; ++y) {
memcpy(dst_y, src_y, mCropWidth);
src_y += mStride;
- dst_y += buf->stride;
+ dst_y += ycbcr.ystride;
}
for (int y = 0; y < (mCropHeight + 1) / 2; ++y) {
@@ -313,24 +321,16 @@
src_u += mStride / 2;
src_v += mStride / 2;
- dst_u += dst_c_stride;
- dst_v += dst_c_stride;
+ dst_u += ycbcr.cstride;
+ dst_v += ycbcr.cstride;
}
} else if (mColorFormat == OMX_COLOR_FormatYUV420Planar16) {
const uint8_t *src_y = (const uint8_t *)data + mCropTop * mStride + mCropLeft * 2;
const uint8_t *src_u = (const uint8_t *)data + mStride * mHeight + mCropTop * mStride / 4;
const uint8_t *src_v = (const uint8_t *)src_u + mStride * mHeight / 4;
- uint8_t *dst_y = (uint8_t *)dst;
- size_t dst_y_size = buf->stride * buf->height;
- size_t dst_c_stride = ALIGN(buf->stride / 2, 16);
- size_t dst_c_size = dst_c_stride * buf->height / 2;
- uint8_t *dst_v = dst_y + dst_y_size;
- uint8_t *dst_u = dst_v + dst_c_size;
-
- dst_y += mCropTop * buf->stride + mCropLeft;
- dst_v += (mCropTop / 2) * dst_c_stride + mCropLeft / 2;
- dst_u += (mCropTop / 2) * dst_c_stride + mCropLeft / 2;
+ uint8_t *dst_y, *dst_u, *dst_v;
+ initDstYUV(ycbcr, mCropTop, mCropLeft, &dst_y, &dst_u, &dst_v);
for (int y = 0; y < mCropHeight; ++y) {
for (int x = 0; x < mCropWidth; ++x) {
@@ -338,7 +338,7 @@
}
src_y += mStride;
- dst_y += buf->stride;
+ dst_y += ycbcr.ystride;
}
for (int y = 0; y < (mCropHeight + 1) / 2; ++y) {
@@ -349,8 +349,8 @@
src_u += mStride / 2;
src_v += mStride / 2;
- dst_u += dst_c_stride;
- dst_v += dst_c_stride;
+ dst_u += ycbcr.cstride;
+ dst_v += ycbcr.cstride;
}
} else if (mColorFormat == OMX_TI_COLOR_FormatYUV420PackedSemiPlanar
|| mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) {
@@ -361,23 +361,14 @@
src_y += mCropLeft + mCropTop * mWidth;
src_uv += (mCropLeft + mCropTop * mWidth) / 2;
- uint8_t *dst_y = (uint8_t *)dst;
-
- size_t dst_y_size = buf->stride * buf->height;
- size_t dst_c_stride = ALIGN(buf->stride / 2, 16);
- size_t dst_c_size = dst_c_stride * buf->height / 2;
- uint8_t *dst_v = dst_y + dst_y_size;
- uint8_t *dst_u = dst_v + dst_c_size;
-
- dst_y += mCropTop * buf->stride + mCropLeft;
- dst_v += (mCropTop/2) * dst_c_stride + mCropLeft/2;
- dst_u += (mCropTop/2) * dst_c_stride + mCropLeft/2;
+ uint8_t *dst_y, *dst_u, *dst_v;
+ initDstYUV(ycbcr, mCropTop, mCropLeft, &dst_y, &dst_u, &dst_v);
for (int y = 0; y < mCropHeight; ++y) {
memcpy(dst_y, src_y, mCropWidth);
src_y += mWidth;
- dst_y += buf->stride;
+ dst_y += ycbcr.ystride;
}
for (int y = 0; y < (mCropHeight + 1) / 2; ++y) {
@@ -388,8 +379,8 @@
}
src_uv += mWidth;
- dst_u += dst_c_stride;
- dst_v += dst_c_stride;
+ dst_u += ycbcr.cstride;
+ dst_v += ycbcr.cstride;
}
} else if (mColorFormat == OMX_COLOR_Format24bitRGB888) {
uint8_t* srcPtr = (uint8_t*)data + mWidth * mCropTop * 3 + mCropLeft * 3;
diff --git a/media/libstagefright/data/media_codecs_sw.xml b/media/libstagefright/data/media_codecs_sw.xml
index 67d3f1a..dd2eed3 100644
--- a/media/libstagefright/data/media_codecs_sw.xml
+++ b/media/libstagefright/data/media_codecs_sw.xml
@@ -48,13 +48,13 @@
</MediaCodec>
<MediaCodec name="c2.android.g711.alaw.decoder" type="audio/g711-alaw">
<Alias name="OMX.google.g711.alaw.decoder" />
- <Limit name="channel-count" max="1" />
+ <Limit name="channel-count" max="6" />
<Limit name="sample-rate" ranges="8000-48000" />
<Limit name="bitrate" range="64000" />
</MediaCodec>
<MediaCodec name="c2.android.g711.mlaw.decoder" type="audio/g711-mlaw">
<Alias name="OMX.google.g711.mlaw.decoder" />
- <Limit name="channel-count" max="1" />
+ <Limit name="channel-count" max="6" />
<Limit name="sample-rate" ranges="8000-48000" />
<Limit name="bitrate" range="64000" />
</MediaCodec>
@@ -67,7 +67,7 @@
<MediaCodec name="c2.android.opus.decoder" type="audio/opus">
<Alias name="OMX.google.opus.decoder" />
<Limit name="channel-count" max="8" />
- <Limit name="sample-rate" ranges="48000" />
+ <Limit name="sample-rate" ranges="8000,12000,16000,24000,48000" />
<Limit name="bitrate" range="6000-510000" />
</MediaCodec>
<MediaCodec name="c2.android.raw.decoder" type="audio/raw">
diff --git a/media/libstagefright/exports.lds b/media/libstagefright/exports.lds
index aabc233..f5ddf1e 100644
--- a/media/libstagefright/exports.lds
+++ b/media/libstagefright/exports.lds
@@ -395,7 +395,6 @@
ScaleFilterCols_NEON*;
ScaleFilterReduce;
ScaleFilterRows_NEON*;
- ScaleOffset;
ScalePlane;
ScalePlane_16;
ScalePlaneBilinearDown;
@@ -505,4 +504,8 @@
YUY2ToYRow_Any_NEON*;
YUY2ToYRow_C;
YUY2ToYRow_NEON*;
+ ogg_packet_*;
+ ogg_page_*;
+ ogg_stream_*;
+ ogg_sync_*;
};
diff --git a/media/libstagefright/filters/Android.bp b/media/libstagefright/filters/Android.bp
index 7a67e55..88f30c4 100644
--- a/media/libstagefright/filters/Android.bp
+++ b/media/libstagefright/filters/Android.bp
@@ -8,7 +8,7 @@
"MediaFilter.cpp",
"RSFilter.cpp",
"SaturationFilter.cpp",
- "saturationARGB.rs",
+ "saturationARGB.rscript",
"SimpleFilter.cpp",
"ZeroFilter.cpp",
],
@@ -23,6 +23,10 @@
"-Wall",
],
+ header_libs: [
+ "libmediadrm_headers",
+ ],
+
shared_libs: [
"libgui",
"libmedia",
diff --git a/media/libstagefright/filters/MediaFilter.cpp b/media/libstagefright/filters/MediaFilter.cpp
index 777ab5b..c7baa73 100644
--- a/media/libstagefright/filters/MediaFilter.cpp
+++ b/media/libstagefright/filters/MediaFilter.cpp
@@ -20,13 +20,12 @@
#include <inttypes.h>
#include <utils/Trace.h>
-#include <binder/MemoryDealer.h>
-
-#include <media/stagefright/BufferProducerWrapper.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/BufferProducerWrapper.h>
+#include <media/stagefright/MediaCodecConstants.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaFilter.h>
@@ -42,11 +41,121 @@
#include "SaturationFilter.h"
#include "ZeroFilter.h"
-#include "../include/ACodecBufferChannel.h"
-#include "../include/SharedMemoryBuffer.h"
-
namespace android {
+class MediaFilter::BufferChannel : public BufferChannelBase {
+public:
+ BufferChannel(const sp<AMessage> &in, const sp<AMessage> &out)
+ : mInputBufferFilled(in), mOutputBufferDrained(out) {
+ }
+
+ ~BufferChannel() override = default;
+
+ // BufferChannelBase
+
+ status_t queueInputBuffer(const sp<MediaCodecBuffer> &buffer) override {
+ sp<AMessage> msg = mInputBufferFilled->dup();
+ msg->setObject("buffer", buffer);
+ msg->post();
+ return OK;
+ }
+
+ status_t queueSecureInputBuffer(
+ const sp<MediaCodecBuffer> &,
+ bool,
+ const uint8_t *,
+ const uint8_t *,
+ CryptoPlugin::Mode,
+ CryptoPlugin::Pattern,
+ const CryptoPlugin::SubSample *,
+ size_t,
+ AString *) override {
+ return INVALID_OPERATION;
+ }
+
+ status_t renderOutputBuffer(
+ const sp<MediaCodecBuffer> &buffer, int64_t /* timestampNs */) override {
+ sp<AMessage> msg = mOutputBufferDrained->dup();
+ msg->setObject("buffer", buffer);
+ msg->post();
+ return OK;
+ }
+
+ status_t discardBuffer(const sp<MediaCodecBuffer> &buffer) override {
+ if (FindBufferIndex(&mInputBuffers, buffer) >= 0) {
+ sp<AMessage> msg = mInputBufferFilled->dup();
+ msg->setObject("buffer", buffer);
+ msg->post();
+ return OK;
+ }
+ sp<AMessage> msg = mOutputBufferDrained->dup();
+ msg->setObject("buffer", buffer);
+ msg->post();
+ return OK;
+ }
+
+ void getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
+ if (!array) {
+ return;
+ }
+ array->clear();
+ array->appendVector(mInputBuffers);
+ }
+
+ void getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
+ if (!array) {
+ return;
+ }
+ array->clear();
+ array->appendVector(mOutputBuffers);
+ }
+
+ // For MediaFilter
+
+ void fillThisBuffer(const sp<MediaCodecBuffer> &buffer) {
+ ssize_t index = FindBufferIndex(&mInputBuffers, buffer);
+ mCallback->onInputBufferAvailable(index, buffer);
+ }
+
+ void drainThisBuffer(const sp<MediaCodecBuffer> &buffer, int flags) {
+ ssize_t index = FindBufferIndex(&mOutputBuffers, buffer);
+ buffer->meta()->setInt32("flags", flags);
+ mCallback->onOutputBufferAvailable(index, buffer);
+ }
+
+ template <class T>
+ void setInputBuffers(T begin, T end) {
+ mInputBuffers.clear();
+ for (T it = begin; it != end; ++it) {
+ mInputBuffers.push_back(it->mData);
+ }
+ }
+
+ template <class T>
+ void setOutputBuffers(T begin, T end) {
+ mOutputBuffers.clear();
+ for (T it = begin; it != end; ++it) {
+ mOutputBuffers.push_back(it->mData);
+ }
+ }
+
+private:
+ sp<AMessage> mInputBufferFilled;
+ sp<AMessage> mOutputBufferDrained;
+ Vector<sp<MediaCodecBuffer>> mInputBuffers;
+ Vector<sp<MediaCodecBuffer>> mOutputBuffers;
+
+ static ssize_t FindBufferIndex(
+ Vector<sp<MediaCodecBuffer>> *array, const sp<MediaCodecBuffer> &buffer) {
+ for (size_t i = 0; i < array->size(); ++i) {
+ if (array->itemAt(i) == buffer) {
+ return i;
+ }
+ }
+ return -1;
+ }
+};
+
// parameter: number of input and output buffers
static const size_t kBufferCountActual = 4;
@@ -54,9 +163,6 @@
: mState(UNINITIALIZED),
mGeneration(0),
mGraphicBufferListener(NULL) {
- mBufferChannel = std::make_shared<ACodecBufferChannel>(
- new AMessage(kWhatInputBufferFilled, this),
- new AMessage(kWhatOutputBufferDrained, this));
}
MediaFilter::~MediaFilter() {
@@ -65,6 +171,11 @@
//////////////////// PUBLIC FUNCTIONS //////////////////////////////////////////
std::shared_ptr<BufferChannelBase> MediaFilter::getBufferChannel() {
+ if (!mBufferChannel) {
+ mBufferChannel = std::make_shared<BufferChannel>(
+ new AMessage(kWhatInputBufferFilled, this),
+ new AMessage(kWhatOutputBufferDrained, this));
+ }
return mBufferChannel;
}
@@ -212,28 +323,23 @@
const bool isInput = portIndex == kPortIndexInput;
const size_t bufferSize = isInput ? mMaxInputSize : mMaxOutputSize;
- CHECK(mDealer[portIndex] == NULL);
CHECK(mBuffers[portIndex].isEmpty());
ALOGV("Allocating %zu buffers of size %zu on %s port",
kBufferCountActual, bufferSize,
isInput ? "input" : "output");
- size_t totalSize = kBufferCountActual * bufferSize;
-
- mDealer[portIndex] = new MemoryDealer(totalSize, "MediaFilter");
-
+ // trigger output format change
+ sp<AMessage> outputFormat = mOutputFormat->dup();
for (size_t i = 0; i < kBufferCountActual; ++i) {
- sp<IMemory> mem = mDealer[portIndex]->allocate(bufferSize);
- CHECK(mem.get() != NULL);
-
BufferInfo info;
info.mStatus = BufferInfo::OWNED_BY_US;
info.mBufferID = i;
info.mGeneration = mGeneration;
info.mOutputFlags = 0;
- info.mData = new SharedMemoryBuffer(
- isInput ? mInputFormat : mOutputFormat, mem);
+ info.mData = new MediaCodecBuffer(
+ isInput ? mInputFormat : outputFormat,
+ new ABuffer(bufferSize));
info.mData->meta()->setInt64("timeUs", 0);
mBuffers[portIndex].push_back(info);
@@ -243,27 +349,24 @@
&mBuffers[portIndex].editItemAt(i));
}
}
-
- std::vector<ACodecBufferChannel::BufferAndId> array(mBuffers[portIndex].size());
- for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
- array[i] = {mBuffers[portIndex][i].mData, mBuffers[portIndex][i].mBufferID};
- }
- if (portIndex == kPortIndexInput) {
- mBufferChannel->setInputBufferArray(array);
+ if (isInput) {
+ mBufferChannel->setInputBuffers(
+ mBuffers[portIndex].begin(), mBuffers[portIndex].end());
} else {
- mBufferChannel->setOutputBufferArray(array);
+ mBufferChannel->setOutputBuffers(
+ mBuffers[portIndex].begin(), mBuffers[portIndex].end());
}
return OK;
}
-MediaFilter::BufferInfo* MediaFilter::findBufferByID(
- uint32_t portIndex, IOMX::buffer_id bufferID,
+MediaFilter::BufferInfo* MediaFilter::findBuffer(
+ uint32_t portIndex, const sp<MediaCodecBuffer> &buffer,
ssize_t *index) {
for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
BufferInfo *info = &mBuffers[portIndex].editItemAt(i);
- if (info->mBufferID == bufferID) {
+ if (info->mData == buffer) {
if (index != NULL) {
*index = i;
}
@@ -293,7 +396,7 @@
info->mStatus = BufferInfo::OWNED_BY_UPSTREAM;
- mBufferChannel->fillThisBuffer(info->mBufferID);
+ mBufferChannel->fillThisBuffer(info->mData);
}
void MediaFilter::postDrainThisBuffer(BufferInfo *info) {
@@ -304,7 +407,7 @@
sp<AMessage> reply = new AMessage(kWhatOutputBufferDrained, this);
reply->setInt32("buffer-id", info->mBufferID);
- mBufferChannel->drainThisBuffer(info->mBufferID, info->mOutputFlags);
+ mBufferChannel->drainThisBuffer(info->mData, info->mOutputFlags);
info->mStatus = BufferInfo::OWNED_BY_UPSTREAM;
}
@@ -359,7 +462,7 @@
outputInfo->mOutputFlags = 0;
int32_t eos = 0;
if (inputInfo->mData->meta()->findInt32("eos", &eos) && eos != 0) {
- outputInfo->mOutputFlags |= OMX_BUFFERFLAG_EOS;
+ outputInfo->mOutputFlags |= BUFFER_FLAG_END_OF_STREAM;
mPortEOS[kPortIndexOutput] = true;
outputInfo->mData->meta()->setInt32("eos", eos);
postEOS();
@@ -400,8 +503,7 @@
return;
}
- // HACK - need "OMX.google" to use MediaCodec's software renderer
- mCallback->onComponentAllocated("OMX.google.MediaFilter");
+ mCallback->onComponentAllocated(mComponentName.c_str());
mState = INITIALIZED;
ALOGV("Handled kWhatAllocateComponent.");
}
@@ -477,6 +579,7 @@
mOutputFormat->setRect("crop", 0, 0, mStride, mSliceHeight);
mOutputFormat->setInt32("width", mWidth);
mOutputFormat->setInt32("height", mHeight);
+ mOutputFormat->setInt32("using-sw-renderer", 1);
mCallback->onComponentConfigured(mInputFormat, mOutputFormat);
mState = CONFIGURED;
@@ -509,9 +612,11 @@
}
void MediaFilter::onInputBufferFilled(const sp<AMessage> &msg) {
- IOMX::buffer_id bufferID;
- CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID));
- BufferInfo *info = findBufferByID(kPortIndexInput, bufferID);
+ sp<RefBase> obj;
+ CHECK(msg->findObject("buffer", &obj));
+ sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
+ ssize_t index = -1;
+ BufferInfo *info = findBuffer(kPortIndexInput, buffer, &index);
if (mState != STARTED) {
// we're not running, so we'll just keep that buffer...
@@ -520,7 +625,7 @@
}
if (info->mGeneration != mGeneration) {
- ALOGV("Caught a stale input buffer [ID %d]", bufferID);
+ ALOGV("Caught a stale input buffer [index %zd]", index);
// buffer is stale (taken before a flush/shutdown) - repost it
CHECK_EQ(info->mStatus, BufferInfo::OWNED_BY_US);
postFillThisBuffer(info);
@@ -530,30 +635,9 @@
CHECK_EQ(info->mStatus, BufferInfo::OWNED_BY_UPSTREAM);
info->mStatus = BufferInfo::OWNED_BY_US;
- sp<MediaCodecBuffer> buffer;
int32_t err = OK;
bool eos = false;
- sp<RefBase> obj;
- if (!msg->findObject("buffer", &obj)) {
- // these are unfilled buffers returned by client
- CHECK(msg->findInt32("err", &err));
-
- if (err == OK) {
- // buffers with no errors are returned on MediaCodec.flush
- ALOGV("saw unfilled buffer (MediaCodec.flush)");
- postFillThisBuffer(info);
- return;
- } else {
- ALOGV("saw error %d instead of an input buffer", err);
- eos = true;
- }
-
- buffer.clear();
- } else {
- buffer = static_cast<MediaCodecBuffer *>(obj.get());
- }
-
int32_t isCSD;
if (buffer != NULL && buffer->meta()->findInt32("csd", &isCSD)
&& isCSD != 0) {
@@ -577,13 +661,15 @@
mInputEOSResult = err;
}
- ALOGV("Handled kWhatInputBufferFilled. [ID %u]", bufferID);
+ ALOGV("Handled kWhatInputBufferFilled. [index %zd]", index);
}
void MediaFilter::onOutputBufferDrained(const sp<AMessage> &msg) {
- IOMX::buffer_id bufferID;
- CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID));
- BufferInfo *info = findBufferByID(kPortIndexOutput, bufferID);
+ sp<RefBase> obj;
+ CHECK(msg->findObject("buffer", &obj));
+ sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
+ ssize_t index = -1;
+ BufferInfo *info = findBuffer(kPortIndexOutput, buffer, &index);
if (mState != STARTED) {
// we're not running, so we'll just keep that buffer...
@@ -592,7 +678,7 @@
}
if (info->mGeneration != mGeneration) {
- ALOGV("Caught a stale output buffer [ID %d]", bufferID);
+ ALOGV("Caught a stale output buffer [index %zd]", index);
// buffer is stale (taken before a flush/shutdown) - keep it
CHECK_EQ(info->mStatus, BufferInfo::OWNED_BY_US);
return;
@@ -605,8 +691,7 @@
processBuffers();
- ALOGV("Handled kWhatOutputBufferDrained. [ID %u]",
- bufferID);
+ ALOGV("Handled kWhatOutputBufferDrained. [index %zd]", index);
}
void MediaFilter::onShutdown(const sp<AMessage> &msg) {
@@ -739,7 +824,7 @@
return;
}
- eosBuf->mOutputFlags = OMX_BUFFERFLAG_EOS;
+ eosBuf->mOutputFlags = BUFFER_FLAG_END_OF_STREAM;
eosBuf->mGeneration = mGeneration;
eosBuf->mData->setRange(0, 0);
postDrainThisBuffer(eosBuf);
diff --git a/media/libstagefright/filters/saturation.rs b/media/libstagefright/filters/saturation.rscript
similarity index 100%
rename from media/libstagefright/filters/saturation.rs
rename to media/libstagefright/filters/saturation.rscript
diff --git a/media/libstagefright/filters/saturationARGB.rs b/media/libstagefright/filters/saturationARGB.rscript
similarity index 100%
rename from media/libstagefright/filters/saturationARGB.rs
rename to media/libstagefright/filters/saturationARGB.rscript
diff --git a/media/libstagefright/flac/dec/Android.bp b/media/libstagefright/flac/dec/Android.bp
index b494e16..d65a663 100644
--- a/media/libstagefright/flac/dec/Android.bp
+++ b/media/libstagefright/flac/dec/Android.bp
@@ -18,29 +18,20 @@
cfi: true,
},
- static: {
- whole_static_libs: [
- "libFLAC",
- "libaudioutils",
- ],
- },
-
- shared: {
- static_libs: [
- "libFLAC",
- "libaudioutils",
- ],
- export_static_lib_headers: [
- "libFLAC",
- ],
- },
-
shared_libs: [
+ "libaudioutils",
"liblog",
],
+ static_libs: [
+ "libFLAC",
+ ],
+
+ export_static_lib_headers: [
+ "libFLAC",
+ ],
+
header_libs: [
"libmedia_headers",
- "libFLAC-headers",
],
}
diff --git a/media/libstagefright/flac/dec/test/Android.bp b/media/libstagefright/flac/dec/test/Android.bp
new file mode 100644
index 0000000..70ca80a
--- /dev/null
+++ b/media/libstagefright/flac/dec/test/Android.bp
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+cc_test {
+ name: "FlacDecoderTest",
+ gtest: true,
+
+ srcs: [
+ "FlacDecoderTest.cpp",
+ ],
+
+ shared_libs: [
+ "liblog",
+ ],
+
+ static_libs: [
+ "libstagefright_flacdec",
+ "libFLAC",
+ ],
+
+ header_libs: [
+ "libstagefright_foundation_headers",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ sanitize: {
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ cfi: true,
+ },
+}
diff --git a/media/libstagefright/flac/dec/test/AndroidTest.xml b/media/libstagefright/flac/dec/test/AndroidTest.xml
new file mode 100644
index 0000000..bebba8e
--- /dev/null
+++ b/media/libstagefright/flac/dec/test/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Test module config for flac decoder unit tests">
+ <option name="test-suite-tag" value="FlacDecoderTest" />
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="FlacDecoderTest->/data/local/tmp/FlacDecoderTest/" />
+ <option name="push-file"
+ key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/flac/dec/test/FlacDecoder.zip?unzip=true"
+ value="/data/local/tmp/FlacDecoderTestRes/" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="FlacDecoderTest" />
+ <option name="native-test-flag" value="-P /data/local/tmp/FlacDecoderTestRes/" />
+ </test>
+</configuration>
\ No newline at end of file
diff --git a/media/libstagefright/flac/dec/test/FlacDecoderTest.cpp b/media/libstagefright/flac/dec/test/FlacDecoderTest.cpp
new file mode 100644
index 0000000..34f12db
--- /dev/null
+++ b/media/libstagefright/flac/dec/test/FlacDecoderTest.cpp
@@ -0,0 +1,270 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "FlacDecoderTest"
+
+#include <utils/Log.h>
+#include <fstream>
+
+#include "FLACDecoder.h"
+
+#include "FlacDecoderTestEnvironment.h"
+
+#define OUTPUT_FILE_NAME "/data/local/tmp/FlacDecoderOutput.raw"
+#define CODEC_CONFIG_FLAG 32
+
+constexpr uint32_t kMaxCount = 10;
+constexpr int32_t kMaxBlockSize = 4096;
+
+using namespace android;
+
+struct FrameInfo {
+ int32_t bytesCount;
+ uint32_t flags;
+ int64_t timestamp;
+};
+
+static FlacDecoderTestEnvironment *gEnv = nullptr;
+
+class FLACDecoderTest : public ::testing::TestWithParam<tuple<string, string, bool>> {
+ public:
+ FLACDecoderTest() : mFLACDecoder(nullptr), mHasStreamInfo(false), mInputBufferCount(0) {}
+
+ ~FLACDecoderTest() {
+ if (mEleStream.is_open()) mEleStream.close();
+ if (mFLACDecoder) delete mFLACDecoder;
+ mFLACDecoder = nullptr;
+ }
+
+ virtual void SetUp() override {
+ mFLACDecoder = FLACDecoder::Create();
+ ASSERT_NE(mFLACDecoder, nullptr) << "initDecoder: failed to create FLACDecoder";
+ }
+
+ int32_t processFlacDecoder(vector<FrameInfo> Info, int32_t offset, int32_t range,
+ bool outputFloat, ofstream &ostrm);
+
+ FLACDecoder *mFLACDecoder;
+ FLAC__StreamMetadata_StreamInfo mStreamInfo;
+
+ bool mHasStreamInfo;
+ int32_t mInputBufferCount;
+ ifstream mEleStream;
+};
+
+void getInfo(string infoFileName, vector<FrameInfo> &Info) {
+ ifstream eleInfo;
+ eleInfo.open(infoFileName);
+ ASSERT_EQ(eleInfo.is_open(), true);
+ int32_t bytesCount = 0;
+ uint32_t flags = 0;
+ uint32_t timestamp = 0;
+ while (1) {
+ if (!(eleInfo >> bytesCount)) break;
+ eleInfo >> flags;
+ eleInfo >> timestamp;
+ Info.push_back({bytesCount, flags, timestamp});
+ }
+ if (eleInfo.is_open()) eleInfo.close();
+}
+
+int32_t FLACDecoderTest::processFlacDecoder(vector<FrameInfo> Info, int32_t offset, int32_t range,
+ bool outputFloat, ofstream &ostrm) {
+ memset(&mStreamInfo, 0, sizeof(mStreamInfo));
+
+ int32_t frameID = offset;
+ if (range + offset > Info.size() || range < 0 || offset > Info.size() - 1 || offset < 0) {
+ ALOGE("Invalid offset or range or both passed for decoding");
+ ALOGE("offset = %d \t range = %d \t Info.size() = %zu", offset, range, Info.size());
+ return -1;
+ }
+
+ while (1) {
+ if (frameID == Info.size() || frameID == (offset + range)) break;
+ int64_t flags = (Info)[frameID].flags;
+ int32_t size = (Info)[frameID].bytesCount;
+ if (size < 0) {
+ ALOGE("Size for the memory allocation is negative");
+ return -1;
+ }
+ char *data = (char *)malloc(size);
+ if (!data) {
+ ALOGE("Insufficient memory to read frame");
+ return -1;
+ }
+
+ mEleStream.read(data, size);
+ if (mEleStream.gcount() != size) {
+ if (data) {
+ free(data);
+ data = nullptr;
+ }
+ ALOGE("Invalid size read, requested: %d and read: %zu", size, mEleStream.gcount());
+ return -1;
+ }
+
+ if (flags == CODEC_CONFIG_FLAG && mInputBufferCount == 0) {
+ status_t decoderErr = mFLACDecoder->parseMetadata((uint8_t *)data, size);
+ if (decoderErr == WOULD_BLOCK) {
+ ALOGV("process: parseMetadata is Blocking, Continue %d", decoderErr);
+ } else if (decoderErr == OK) {
+ mStreamInfo = mFLACDecoder->getStreamInfo();
+ if (mStreamInfo.sample_rate && mStreamInfo.max_blocksize && mStreamInfo.channels) {
+ mHasStreamInfo = true;
+ }
+ ALOGV("decoder configuration : %d Hz, %d channels, %d samples,"
+ " %d block size",
+ mStreamInfo.sample_rate, mStreamInfo.channels,
+ (int32_t)mStreamInfo.total_samples, mStreamInfo.max_blocksize);
+ } else {
+ ALOGE("FLACDecoder parseMetaData returns error %d", decoderErr);
+ if (data) {
+ free(data);
+ data = nullptr;
+ }
+ return decoderErr;
+ }
+ } else {
+ const size_t sampleSize = outputFloat ? sizeof(float) : sizeof(int16_t);
+ size_t outSize = mHasStreamInfo
+ ? mStreamInfo.max_blocksize * mStreamInfo.channels * sampleSize
+ : kMaxBlockSize * FLACDecoder::kMaxChannels * sampleSize;
+
+ void *out_buf = malloc(outSize);
+ if (!out_buf) {
+ if (data) {
+ free(data);
+ data = nullptr;
+ }
+ ALOGE("Output buffer allocation failed");
+ return -1;
+ }
+ status_t decoderErr = mFLACDecoder->decodeOneFrame((uint8_t *)data, size, out_buf,
+ &outSize, outputFloat);
+ if (decoderErr != OK) {
+ ALOGE("decodeOneFrame returns error %d", decoderErr);
+ if (data) {
+ free(data);
+ data = nullptr;
+ }
+ if (out_buf) {
+ free(out_buf);
+ out_buf = nullptr;
+ }
+ return decoderErr;
+ }
+ ostrm.write(reinterpret_cast<char *>(out_buf), outSize);
+ free(out_buf);
+ out_buf = nullptr;
+ }
+ mInputBufferCount++;
+ frameID++;
+ free(data);
+ data = nullptr;
+ }
+ ALOGV("frameID=%d", frameID);
+ return 0;
+}
+
+TEST_F(FLACDecoderTest, CreateDeleteTest) {
+ if (mFLACDecoder) delete mFLACDecoder;
+ mFLACDecoder = nullptr;
+
+ for (int32_t i = 0; i < kMaxCount; i++) {
+ mFLACDecoder = FLACDecoder::Create();
+ ASSERT_NE(mFLACDecoder, nullptr) << "FLACDecoder Creation Failed";
+ if (mFLACDecoder) delete mFLACDecoder;
+ mFLACDecoder = nullptr;
+ }
+}
+
+TEST_P(FLACDecoderTest, FlushTest) {
+ tuple<string /* InputFileName */, string /* InfoFileName */, bool /* outputfloat */> params =
+ GetParam();
+
+ string inputFileName = gEnv->getRes() + get<0>(params);
+ string infoFileName = gEnv->getRes() + get<1>(params);
+ bool outputFloat = get<2>(params);
+
+ vector<FrameInfo> Info;
+ getInfo(infoFileName, Info);
+
+ mEleStream.open(inputFileName, ifstream::binary);
+ ASSERT_EQ(mEleStream.is_open(), true);
+
+ ofstream ostrm;
+ ostrm.open(OUTPUT_FILE_NAME, std::ofstream::binary);
+ ASSERT_EQ(ostrm.is_open(), true);
+
+ int32_t status = processFlacDecoder(Info, 0, Info.size() / 3, outputFloat, ostrm);
+ ASSERT_EQ(status, 0) << "Test Failed. Decode returned error = " << status << endl;
+ mFLACDecoder->flush();
+ mHasStreamInfo = false;
+ status = processFlacDecoder(Info, (Info.size() / 3), Info.size() - (Info.size() / 3),
+ outputFloat, ostrm);
+ ostrm.close();
+ Info.clear();
+ ASSERT_EQ(status, 0) << "Test Failed. Decode returned error = " << status << endl;
+}
+
+TEST_P(FLACDecoderTest, DecodeTest) {
+ tuple<string /* InputFileName */, string /* InfoFileName */, bool /* outputfloat */> params =
+ GetParam();
+
+ string inputFileName = gEnv->getRes() + get<0>(params);
+ string infoFileName = gEnv->getRes() + get<1>(params);
+ bool outputFloat = get<2>(params);
+
+ vector<FrameInfo> Info;
+ getInfo(infoFileName, Info);
+
+ mEleStream.open(inputFileName, ifstream::binary);
+ ASSERT_EQ(mEleStream.is_open(), true);
+
+ ofstream ostrm;
+ ostrm.open(OUTPUT_FILE_NAME, std::ofstream::binary);
+ ASSERT_EQ(ostrm.is_open(), true);
+
+ int32_t status = processFlacDecoder(Info, 0, Info.size(), outputFloat, ostrm);
+ ostrm.close();
+ Info.clear();
+ ASSERT_EQ(status, 0) << "Test Failed. Decode returned error = " << status << endl;
+}
+
+// TODO: Add remaining tests
+INSTANTIATE_TEST_SUITE_P(
+ FLACDecoderTestAll, FLACDecoderTest,
+ ::testing::Values(make_tuple("bbb_flac_stereo_680kbps_48000hz.flac",
+ "bbb_flac_stereo_680kbps_48000hz.info", true),
+ make_tuple("bbb_flac_stereo_680kbps_48000hz.flac",
+ "bbb_flac_stereo_680kbps_48000hz.info", false),
+ make_tuple("bbb_flac_stereo_600kbps_44100hz.flac",
+ "bbb_flac_stereo_600kbps_44100hz.info", true),
+ make_tuple("bbb_flac_stereo_600kbps_44100hz.flac",
+ "bbb_flac_stereo_600kbps_44100hz.info", false)));
+
+int main(int argc, char **argv) {
+ gEnv = new FlacDecoderTestEnvironment();
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = gEnv->initFromOptions(argc, argv);
+ if (status == 0) {
+ status = RUN_ALL_TESTS();
+ ALOGV("Flac Decoder Test Result = %d\n", status);
+ }
+ return status;
+}
diff --git a/media/libstagefright/flac/dec/test/FlacDecoderTestEnvironment.h b/media/libstagefright/flac/dec/test/FlacDecoderTestEnvironment.h
new file mode 100644
index 0000000..1334bba
--- /dev/null
+++ b/media/libstagefright/flac/dec/test/FlacDecoderTestEnvironment.h
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+#ifndef __FLAC_DECODER_TEST_ENVIRONMENT_H__
+#define __FLAC_DECODER_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class FlacDecoderTestEnvironment : public ::testing::Environment {
+ public:
+ FlacDecoderTestEnvironment() : res("/data/local/tmp/") {}
+
+ // Parses the command line arguments
+ int initFromOptions(int argc, char **argv);
+
+ void setRes(const char *_res) { res = _res; }
+
+ const string getRes() const { return res; }
+
+ private:
+ string res;
+};
+
+int FlacDecoderTestEnvironment::initFromOptions(int argc, char **argv) {
+ static struct option options[] = {{"path", required_argument, 0, 'P'}, {0, 0, 0, 0}};
+
+ while (true) {
+ int index = 0;
+ int c = getopt_long(argc, argv, "P:", options, &index);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'P': {
+ setRes(optarg);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ if (optind < argc) {
+ fprintf(stderr,
+ "unrecognized option: %s\n\n"
+ "usage: %s <gtest options> <test options>\n\n"
+ "test options are:\n\n"
+ "-P, --path: Resource files directory location\n",
+ argv[optind ?: 1], argv[0]);
+ return 2;
+ }
+ return 0;
+}
+
+#endif // __FLAC_DECODER_TEST_ENVIRONMENT_H__
diff --git a/media/libstagefright/flac/dec/test/README.md b/media/libstagefright/flac/dec/test/README.md
new file mode 100644
index 0000000..4d194cd
--- /dev/null
+++ b/media/libstagefright/flac/dec/test/README.md
@@ -0,0 +1,40 @@
+## Media Testing ##
+---
+#### FlacDecoder :
+The FlacDecoder Test Suite validates the FlacDecoder available in libstagefright.
+
+Run the following steps to build the test suite:
+```
+m FlacDecoderTest
+```
+
+The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/
+
+The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/
+
+To test 64-bit binary push binaries from nativetest64.
+```
+adb push ${OUT}/data/nativetest64/FlacDecoderTest/FlacDecoderTest /data/local/tmp/
+```
+
+To test 32-bit binary push binaries from nativetest.
+```
+adb push ${OUT}/data/nativetest/FlacDecoderTest/FlacDecoderTest /data/local/tmp/
+```
+
+The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/flac/dec/test/FlacDecoder.zip).
+Download, unzip and push these files into device for testing.
+
+```
+adb push FlacDecoder /data/local/tmp/
+```
+
+usage: FlacDecoderTest -P \<path_to_folder\>
+```
+adb shell /data/local/tmp/FlacDecoderTest -P /data/local/tmp/FlacDecoder/
+```
+Alternatively, the test can also be run using atest command.
+
+```
+atest FlacDecoderTest -- --enable-module-dynamic-download=true
+```
diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp
index df66ac6..7752bda 100644
--- a/media/libstagefright/foundation/AMessage.cpp
+++ b/media/libstagefright/foundation/AMessage.cpp
@@ -22,7 +22,6 @@
#include "AMessage.h"
-#include <binder/Parcel.h>
#include <log/log.h>
#include "AAtomizer.h"
@@ -34,6 +33,10 @@
#include <media/stagefright/foundation/hexdump.h>
+#ifndef __ANDROID_VNDK__
+#include <binder/Parcel.h>
+#endif
+
namespace android {
extern ALooperRoster gLooperRoster;
@@ -643,6 +646,7 @@
return s;
}
+#ifndef __ANDROID_VNDK__
// static
sp<AMessage> AMessage::FromParcel(const Parcel &parcel, size_t maxNestingLevel) {
int32_t what = parcel.readInt32();
@@ -809,6 +813,7 @@
}
}
}
+#endif // __ANDROID_VNDK__
sp<AMessage> AMessage::changesFrom(const sp<const AMessage> &other, bool deep) const {
if (other == NULL) {
diff --git a/media/libstagefright/foundation/AString.cpp b/media/libstagefright/foundation/AString.cpp
index fb51cc5..4bd186c 100644
--- a/media/libstagefright/foundation/AString.cpp
+++ b/media/libstagefright/foundation/AString.cpp
@@ -23,11 +23,14 @@
#include <stdlib.h>
#include <string.h>
-#include <binder/Parcel.h>
#include <utils/String8.h>
#include "ADebug.h"
#include "AString.h"
+#ifndef __ANDROID_VNDK__
+#include <binder/Parcel.h>
+#endif
+
namespace android {
// static
@@ -362,11 +365,10 @@
return !strcasecmp(mData + mSize - suffixLen, suffix);
}
+#ifndef __ANDROID_VNDK__
// static
AString AString::FromParcel(const Parcel &parcel) {
size_t size = static_cast<size_t>(parcel.readInt32());
- // The static analyzer incorrectly reports a false-positive here in c++17.
- // https://bugs.llvm.org/show_bug.cgi?id=38176 . NOLINTNEXTLINE
return AString(static_cast<const char *>(parcel.readInplace(size)), size);
}
@@ -378,6 +380,7 @@
}
return err;
}
+#endif
AString AStringPrintf(const char *format, ...) {
va_list ap;
diff --git a/media/libstagefright/foundation/Android.bp b/media/libstagefright/foundation/Android.bp
index 533cd72..9fe879e 100644
--- a/media/libstagefright/foundation/Android.bp
+++ b/media/libstagefright/foundation/Android.bp
@@ -2,6 +2,7 @@
name: "libstagefright_foundation_headers",
export_include_dirs: ["include"],
vendor_available: true,
+ host_supported: true,
}
cc_defaults {
@@ -34,10 +35,6 @@
"media_plugin_headers",
],
- export_shared_lib_headers: [
- "libbinder",
- ],
-
cflags: [
"-Wno-multichar",
"-Werror",
@@ -65,6 +62,7 @@
"AudioPresentationInfo.cpp",
"ByteUtils.cpp",
"ColorUtils.cpp",
+ "FoundationUtils.cpp",
"MediaBuffer.cpp",
"MediaBufferBase.cpp",
"MediaBufferGroup.cpp",
@@ -78,6 +76,17 @@
"hexdump.cpp",
],
+ target: {
+ vendor: {
+ exclude_shared_libs: [
+ "libbinder",
+ ],
+ cflags: [
+ "-DNO_IMEMORY",
+ ],
+ },
+ },
+
clang: true,
sanitize: {
diff --git a/media/libstagefright/foundation/FoundationUtils.cpp b/media/libstagefright/foundation/FoundationUtils.cpp
new file mode 100644
index 0000000..8285e4c
--- /dev/null
+++ b/media/libstagefright/foundation/FoundationUtils.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "FoundationUtils"
+#include <utils/Log.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <cutils/properties.h>
+#include <media/stagefright/foundation/AString.h>
+
+namespace android {
+
+AString uriDebugString(const AString &uri, bool incognito) {
+ if (incognito) {
+ return AString("<URI suppressed>");
+ }
+
+ if (property_get_bool("media.stagefright.log-uri", false)) {
+ return uri;
+ }
+
+ // find scheme
+ AString scheme;
+ const char *chars = uri.c_str();
+ for (size_t i = 0; i < uri.size(); i++) {
+ const char c = chars[i];
+ if (!isascii(c)) {
+ break;
+ } else if (isalpha(c)) {
+ continue;
+ } else if (i == 0) {
+ // first character must be a letter
+ break;
+ } else if (isdigit(c) || c == '+' || c == '.' || c =='-') {
+ continue;
+ } else if (c != ':') {
+ break;
+ }
+ scheme = AString(uri, 0, i);
+ scheme.append("://<suppressed>");
+ return scheme;
+ }
+ return AString("<no-scheme URI suppressed>");
+}
+
+AString MakeUserAgent() {
+ AString ua;
+ ua.append("stagefright/1.2 (Linux;Android ");
+
+#if (PROPERTY_VALUE_MAX < 8)
+#error "PROPERTY_VALUE_MAX must be at least 8"
+#endif
+
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.build.version.release", value, "Unknown");
+ ua.append(value);
+ ua.append(")");
+
+ return ua;
+}
+
+AString nameForFd(int fd) {
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ AString result;
+ snprintf(buffer, SIZE, "/proc/%d/fd/%d", getpid(), fd);
+ struct stat s;
+ if (lstat(buffer, &s) == 0) {
+ if ((s.st_mode & S_IFMT) == S_IFLNK) {
+ char linkto[256];
+ int len = readlink(buffer, linkto, sizeof(linkto));
+ if(len > 0) {
+ if(len > 255) {
+ linkto[252] = '.';
+ linkto[253] = '.';
+ linkto[254] = '.';
+ linkto[255] = 0;
+ } else {
+ linkto[len] = 0;
+ }
+ result.append(linkto);
+ }
+ } else {
+ result.append("unexpected type for ");
+ result.append(buffer);
+ }
+ } else {
+ result.append("couldn't open ");
+ result.append(buffer);
+ }
+ return result;
+}
+
+} // namespace android
diff --git a/media/libstagefright/foundation/MediaBuffer.cpp b/media/libstagefright/foundation/MediaBuffer.cpp
index 9beac05..8e245dc 100644
--- a/media/libstagefright/foundation/MediaBuffer.cpp
+++ b/media/libstagefright/foundation/MediaBuffer.cpp
@@ -72,7 +72,7 @@
}
} else {
getSharedControl()->clear();
- mData = (uint8_t *)mMemory->pointer() + sizeof(SharedControl);
+ mData = (uint8_t *)mMemory->unsecurePointer() + sizeof(SharedControl);
ALOGV("Allocated shared mem buffer of size %zu @ %p", size, mData);
}
}
diff --git a/media/libstagefright/foundation/MediaBufferGroup.cpp b/media/libstagefright/foundation/MediaBufferGroup.cpp
index 84ff9a6..3c25047 100644
--- a/media/libstagefright/foundation/MediaBufferGroup.cpp
+++ b/media/libstagefright/foundation/MediaBufferGroup.cpp
@@ -75,7 +75,7 @@
for (size_t i = 0; i < buffers; ++i) {
sp<IMemory> mem = memoryDealer->allocate(augmented_size);
- if (mem.get() == nullptr || mem->pointer() == nullptr) {
+ if (mem.get() == nullptr || mem->unsecurePointer() == nullptr) {
ALOGW("Only allocated %zu shared buffers of size %zu", i, buffer_size);
break;
}
diff --git a/media/libstagefright/foundation/MetaData.cpp b/media/libstagefright/foundation/MetaData.cpp
index 1d0a607..8174597 100644
--- a/media/libstagefright/foundation/MetaData.cpp
+++ b/media/libstagefright/foundation/MetaData.cpp
@@ -17,7 +17,6 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "MetaData"
#include <inttypes.h>
-#include <binder/Parcel.h>
#include <utils/KeyedVector.h>
#include <utils/Log.h>
@@ -29,6 +28,10 @@
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MetaData.h>
+#ifndef __ANDROID_VNDK__
+#include <binder/Parcel.h>
+#endif
+
namespace android {
@@ -45,6 +48,7 @@
MetaData::~MetaData() {
}
+#ifndef __ANDROID_VNDK__
/* static */
sp<MetaData> MetaData::createFromParcel(const Parcel &parcel) {
@@ -52,6 +56,7 @@
meta->updateFromParcel(parcel);
return meta;
}
+#endif
} // namespace android
diff --git a/media/libstagefright/foundation/MetaDataBase.cpp b/media/libstagefright/foundation/MetaDataBase.cpp
index bfea6f1..4b439c6 100644
--- a/media/libstagefright/foundation/MetaDataBase.cpp
+++ b/media/libstagefright/foundation/MetaDataBase.cpp
@@ -17,7 +17,6 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "MetaDataBase"
#include <inttypes.h>
-#include <binder/Parcel.h>
#include <utils/KeyedVector.h>
#include <utils/Log.h>
@@ -29,6 +28,10 @@
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MetaDataBase.h>
+#ifndef __ANDROID_VNDK__
+#include <binder/Parcel.h>
+#endif
+
namespace android {
struct MetaDataBase::typed_data {
@@ -449,6 +452,7 @@
}
}
+#ifndef __ANDROID_VNDK__
status_t MetaDataBase::writeToParcel(Parcel &parcel) {
status_t ret;
size_t numItems = mInternalData->mItems.size();
@@ -528,6 +532,7 @@
ALOGW("no metadata in parcel");
return UNKNOWN_ERROR;
}
+#endif
} // namespace android
diff --git a/media/libstagefright/foundation/OpusHeader.cpp b/media/libstagefright/foundation/OpusHeader.cpp
index 513e41f..f5687e0 100644
--- a/media/libstagefright/foundation/OpusHeader.cpp
+++ b/media/libstagefright/foundation/OpusHeader.cpp
@@ -292,6 +292,10 @@
*opusHeadSize = data_size;
return true;
} else if (memcmp(AOPUS_CSD_MARKER_PREFIX, data, AOPUS_CSD_MARKER_PREFIX_SIZE) == 0) {
+ if (data_size < AOPUS_UNIFIED_CSD_MINSIZE || data_size > AOPUS_UNIFIED_CSD_MAXSIZE) {
+ ALOGD("Unexpected size for unified opus csd %zu", data_size);
+ return false;
+ }
size_t i = 0;
bool found = false;
while (i <= data_size - AOPUS_MARKER_SIZE - AOPUS_LENGTH_SIZE) {
diff --git a/media/libstagefright/foundation/TEST_MAPPING b/media/libstagefright/foundation/TEST_MAPPING
new file mode 100644
index 0000000..3301c4b
--- /dev/null
+++ b/media/libstagefright/foundation/TEST_MAPPING
@@ -0,0 +1,5 @@
+{
+ "presubmit": [
+ { "name": "sf_foundation_test" }
+ ]
+}
diff --git a/media/libstagefright/foundation/avc_utils.cpp b/media/libstagefright/foundation/avc_utils.cpp
index e8a6083..f53d2c9 100644
--- a/media/libstagefright/foundation/avc_utils.cpp
+++ b/media/libstagefright/foundation/avc_utils.cpp
@@ -166,10 +166,21 @@
unsigned pic_height_in_map_units_minus1 = parseUE(&br);
unsigned frame_mbs_only_flag = br.getBits(1);
- *width = pic_width_in_mbs_minus1 * 16 + 16;
+ // *width = pic_width_in_mbs_minus1 * 16 + 16;
+ if (__builtin_mul_overflow(pic_width_in_mbs_minus1, 16, &pic_width_in_mbs_minus1) ||
+ __builtin_add_overflow(pic_width_in_mbs_minus1, 16, width)) {
+ *width = 0;
+ }
- *height = (2 - frame_mbs_only_flag)
- * (pic_height_in_map_units_minus1 * 16 + 16);
+ // *height = (2 - frame_mbs_only_flag) * (pic_height_in_map_units_minus1 * 16 + 16);
+ if (__builtin_mul_overflow(
+ pic_height_in_map_units_minus1, 16, &pic_height_in_map_units_minus1) ||
+ __builtin_add_overflow(
+ pic_height_in_map_units_minus1, 16, &pic_height_in_map_units_minus1) ||
+ __builtin_mul_overflow(
+ pic_height_in_map_units_minus1, (2 - frame_mbs_only_flag), height)) {
+ *height = 0;
+ }
if (!frame_mbs_only_flag) {
br.getBits(1); // mb_adaptive_frame_field_flag
@@ -202,17 +213,19 @@
// *width -= (frame_crop_left_offset + frame_crop_right_offset) * cropUnitX;
- if(__builtin_add_overflow(frame_crop_left_offset, frame_crop_right_offset, &frame_crop_left_offset) ||
- __builtin_mul_overflow(frame_crop_left_offset, cropUnitX, &frame_crop_left_offset) ||
- __builtin_sub_overflow(*width, frame_crop_left_offset, width) ||
+ if(__builtin_add_overflow(
+ frame_crop_left_offset, frame_crop_right_offset, &frame_crop_left_offset) ||
+ __builtin_mul_overflow(frame_crop_left_offset, cropUnitX, &frame_crop_left_offset) ||
+ __builtin_sub_overflow(*width, frame_crop_left_offset, width) ||
*width < 0) {
*width = 0;
}
//*height -= (frame_crop_top_offset + frame_crop_bottom_offset) * cropUnitY;
- if(__builtin_add_overflow(frame_crop_top_offset, frame_crop_bottom_offset, &frame_crop_top_offset) ||
- __builtin_mul_overflow(frame_crop_top_offset, cropUnitY, &frame_crop_top_offset) ||
- __builtin_sub_overflow(*height, frame_crop_top_offset, height) ||
+ if(__builtin_add_overflow(
+ frame_crop_top_offset, frame_crop_bottom_offset, &frame_crop_top_offset) ||
+ __builtin_mul_overflow(frame_crop_top_offset, cropUnitY, &frame_crop_top_offset) ||
+ __builtin_sub_overflow(*height, frame_crop_top_offset, height) ||
*height < 0) {
*height = 0;
}
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/AMessage.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AMessage.h
index 742651e..b5d6666 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/AMessage.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/AMessage.h
@@ -63,6 +63,7 @@
AMessage();
AMessage(uint32_t what, const sp<const AHandler> &handler);
+#ifndef __ANDROID_VNDK__
// Construct an AMessage from a parcel.
// nestingAllowed determines how many levels AMessage can be nested inside
// AMessage. The default value here is arbitrarily set to 255.
@@ -87,6 +88,7 @@
// All items in the AMessage must have types that are recognized by
// FromParcel(); otherwise, TRESPASS error will occur.
void writeToParcel(Parcel *parcel) const;
+#endif
void setWhat(uint32_t what);
uint32_t what() const;
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/AString.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AString.h
index 0f6299c..deef0d4 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/AString.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/AString.h
@@ -89,8 +89,10 @@
void tolower();
+#ifndef __ANDROID_VNDK__
static AString FromParcel(const Parcel &parcel);
status_t writeToParcel(Parcel *parcel) const;
+#endif
private:
constexpr static const char *kEmptyString = "";
diff --git a/media/libstagefright/foundation/tests/Android.bp b/media/libstagefright/foundation/tests/Android.bp
new file mode 100644
index 0000000..f2157c9
--- /dev/null
+++ b/media/libstagefright/foundation/tests/Android.bp
@@ -0,0 +1,27 @@
+cc_test {
+ name: "sf_foundation_test",
+ test_suites: ["device-tests"],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ include_dirs: [
+ "frameworks/av/include",
+ ],
+
+ shared_libs: [
+ "liblog",
+ "libstagefright_foundation",
+ "libutils",
+ ],
+
+ srcs: [
+ "AData_test.cpp",
+ "Base64_test.cpp",
+ "Flagged_test.cpp",
+ "TypeTraits_test.cpp",
+ "Utils_test.cpp",
+ ],
+}
diff --git a/media/libstagefright/foundation/tests/Android.mk b/media/libstagefright/foundation/tests/Android.mk
deleted file mode 100644
index a9e3c76..0000000
--- a/media/libstagefright/foundation/tests/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-# Build the unit tests.
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_MODULE := sf_foundation_test
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := \
- AData_test.cpp \
- Base64_test.cpp \
- Flagged_test.cpp \
- TypeTraits_test.cpp \
- Utils_test.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
- liblog \
- libstagefright_foundation \
- libutils \
-
-LOCAL_C_INCLUDES := \
- frameworks/av/include \
-
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CLANG := true
-
-include $(BUILD_NATIVE_TEST)
-
-# Include subdirectory makefiles
-# ============================================================
-
-# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
-# team really wants is to build the stuff defined by this makefile.
-ifeq (,$(ONE_SHOT_MAKEFILE))
-include $(call first-makefiles-under,$(LOCAL_PATH))
-endif
diff --git a/media/libstagefright/http/ClearMediaHTTP.cpp b/media/libstagefright/http/ClearMediaHTTP.cpp
deleted file mode 100644
index 9557c8a..0000000
--- a/media/libstagefright/http/ClearMediaHTTP.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "ClearMediaHTTP"
-#include <utils/Log.h>
-
-#include <media/stagefright/ClearMediaHTTP.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/Utils.h>
-
-#include <media/MediaHTTPConnection.h>
-
-namespace android {
-
-ClearMediaHTTP::ClearMediaHTTP(const sp<MediaHTTPConnection> &conn)
- : mInitCheck((conn != NULL) ? OK : NO_INIT),
- mHTTPConnection(conn),
- mCachedSizeValid(false),
- mCachedSize(0ll) {
-}
-
-ClearMediaHTTP::~ClearMediaHTTP() {
-}
-
-status_t ClearMediaHTTP::connect(
- const char *uri,
- const KeyedVector<String8, String8> *headers,
- off64_t /* offset */) {
- if (mInitCheck != OK) {
- return mInitCheck;
- }
-
- KeyedVector<String8, String8> extHeaders;
- if (headers != NULL) {
- extHeaders = *headers;
- }
-
- if (extHeaders.indexOfKey(String8("User-Agent")) < 0) {
- extHeaders.add(String8("User-Agent"), String8(MakeUserAgent().c_str()));
- }
-
- mLastURI = uri;
- // reconnect() calls with uri == old mLastURI.c_str(), which gets zapped
- // as part of the above assignment. Ensure no accidental later use.
- uri = NULL;
-
- bool success = mHTTPConnection->connect(mLastURI.c_str(), &extHeaders);
-
- mLastHeaders = extHeaders;
-
- mCachedSizeValid = false;
-
- if (success) {
- AString sanitized = uriDebugString(mLastURI);
- mName = String8::format("ClearMediaHTTP(%s)", sanitized.c_str());
- }
-
- return success ? OK : UNKNOWN_ERROR;
-}
-
-void ClearMediaHTTP::close() {
- disconnect();
-}
-
-void ClearMediaHTTP::disconnect() {
- mName = String8("ClearMediaHTTP(<disconnected>)");
- if (mInitCheck != OK) {
- return;
- }
-
- mHTTPConnection->disconnect();
-}
-
-status_t ClearMediaHTTP::initCheck() const {
- return mInitCheck;
-}
-
-ssize_t ClearMediaHTTP::readAt(off64_t offset, void *data, size_t size) {
- if (mInitCheck != OK) {
- return mInitCheck;
- }
-
- int64_t startTimeUs = ALooper::GetNowUs();
-
- size_t numBytesRead = 0;
- while (numBytesRead < size) {
- size_t copy = size - numBytesRead;
-
- if (copy > 64 * 1024) {
- // limit the buffer sizes transferred across binder boundaries
- // to avoid spurious transaction failures.
- copy = 64 * 1024;
- }
-
- ssize_t n = mHTTPConnection->readAt(
- offset + numBytesRead, (uint8_t *)data + numBytesRead, copy);
-
- if (n < 0) {
- return n;
- } else if (n == 0) {
- break;
- }
-
- numBytesRead += n;
- }
-
- int64_t delayUs = ALooper::GetNowUs() - startTimeUs;
-
- addBandwidthMeasurement(numBytesRead, delayUs);
-
- return numBytesRead;
-}
-
-status_t ClearMediaHTTP::getSize(off64_t *size) {
- if (mInitCheck != OK) {
- return mInitCheck;
- }
-
- // Caching the returned size so that it stays valid even after a
- // disconnect. NuCachedSource2 relies on this.
-
- if (!mCachedSizeValid) {
- mCachedSize = mHTTPConnection->getSize();
- mCachedSizeValid = true;
- }
-
- *size = mCachedSize;
-
- return *size < 0 ? *size : static_cast<status_t>(OK);
-}
-
-uint32_t ClearMediaHTTP::flags() {
- return kWantsPrefetching | kIsHTTPBasedSource;
-}
-
-status_t ClearMediaHTTP::reconnectAtOffset(off64_t offset) {
- return connect(mLastURI.c_str(), &mLastHeaders, offset);
-}
-
-
-String8 ClearMediaHTTP::getUri() {
- if (mInitCheck != OK) {
- return String8::empty();
- }
-
- String8 uri;
- if (OK == mHTTPConnection->getUri(&uri)) {
- return uri;
- }
- return String8(mLastURI.c_str());
-}
-
-String8 ClearMediaHTTP::getMIMEType() const {
- if (mInitCheck != OK) {
- return String8("application/octet-stream");
- }
-
- String8 mimeType;
- status_t err = mHTTPConnection->getMIMEType(&mimeType);
-
- if (err != OK) {
- return String8("application/octet-stream");
- }
-
- return mimeType;
-}
-
-} // namespace android
diff --git a/media/libstagefright/http/MediaHTTP.cpp b/media/libstagefright/http/MediaHTTP.cpp
deleted file mode 100644
index 0fba3dc..0000000
--- a/media/libstagefright/http/MediaHTTP.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MediaHTTP"
-#include <utils/Log.h>
-
-#include <media/stagefright/MediaHTTP.h>
-
-#include <binder/IServiceManager.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/Utils.h>
-
-#include <media/MediaHTTPConnection.h>
-
-namespace android {
-
-MediaHTTP::MediaHTTP(const sp<MediaHTTPConnection> &conn)
- : ClearMediaHTTP(conn),
- mDrmManagerClient(NULL) {
-}
-
-MediaHTTP::~MediaHTTP() {
- clearDRMState_l();
-}
-
-// DRM...
-
-sp<DecryptHandle> MediaHTTP::DrmInitialization(const char* mime) {
- if (mDrmManagerClient == NULL) {
- mDrmManagerClient = new DrmManagerClient();
- }
-
- if (mDrmManagerClient == NULL) {
- return NULL;
- }
-
- if (mDecryptHandle == NULL) {
- mDecryptHandle = mDrmManagerClient->openDecryptSession(
- String8(mLastURI.c_str()), mime);
- }
-
- if (mDecryptHandle == NULL) {
- delete mDrmManagerClient;
- mDrmManagerClient = NULL;
- }
-
- return mDecryptHandle;
-}
-
-void MediaHTTP::clearDRMState_l() {
- if (mDecryptHandle != NULL) {
- // To release mDecryptHandle
- CHECK(mDrmManagerClient);
- mDrmManagerClient->closeDecryptSession(mDecryptHandle);
- mDecryptHandle = NULL;
- }
-}
-
-} // namespace android
diff --git a/media/libstagefright/httplive/Android.bp b/media/libstagefright/httplive/Android.bp
index c0ee14e..12e7ca6 100644
--- a/media/libstagefright/httplive/Android.bp
+++ b/media/libstagefright/httplive/Android.bp
@@ -31,6 +31,7 @@
"liblog",
"libcrypto",
"libcutils",
+ "libdatasource",
"libmedia",
"libmediandk",
"libstagefright",
diff --git a/media/libstagefright/httplive/HTTPDownloader.cpp b/media/libstagefright/httplive/HTTPDownloader.cpp
index c7e92cd..68f1de9 100644
--- a/media/libstagefright/httplive/HTTPDownloader.cpp
+++ b/media/libstagefright/httplive/HTTPDownloader.cpp
@@ -21,13 +21,13 @@
#include "HTTPDownloader.h"
#include "M3UParser.h"
+#include <datasource/MediaHTTP.h>
+#include <datasource/FileSource.h>
#include <media/DataSource.h>
#include <media/MediaHTTPConnection.h>
#include <media/MediaHTTPService.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/ClearMediaHTTP.h>
-#include <media/stagefright/ClearFileSource.h>
#include <openssl/aes.h>
#include <openssl/md5.h>
#include <utils/Mutex.h>
@@ -38,7 +38,7 @@
HTTPDownloader::HTTPDownloader(
const sp<MediaHTTPService> &httpService,
const KeyedVector<String8, String8> &headers) :
- mHTTPDataSource(new ClearMediaHTTP(httpService->makeHTTPConnection())),
+ mHTTPDataSource(new MediaHTTP(httpService->makeHTTPConnection())),
mExtraHeaders(headers),
mDisconnecting(false) {
}
@@ -91,7 +91,7 @@
if (reconnect) {
if (!strncasecmp(url, "file://", 7)) {
- mDataSource = new ClearFileSource(url + 7);
+ mDataSource = new FileSource(url + 7);
} else if (strncasecmp(url, "http://", 7)
&& strncasecmp(url, "https://", 8)) {
return ERROR_UNSUPPORTED;
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 9cf97c7..3bad015 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -34,6 +34,7 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <utils/Mutex.h>
diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index cb97a3c..e0324e3 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -27,6 +27,7 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <media/mediaplayer.h>
namespace android {
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index 635ecfe..fdcde29 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -28,17 +28,18 @@
#include "mpeg2ts/AnotherPacketSource.h"
#include "mpeg2ts/HlsSampleDecryptor.h"
+#include <datasource/DataURISource.h>
#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ByteUtils.h>
#include <media/stagefright/foundation/MediaKeys.h>
#include <media/stagefright/foundation/avc_utils.h>
-#include <media/stagefright/DataURISource.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MetaDataUtils.h>
#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <ctype.h>
#include <inttypes.h>
@@ -2160,7 +2161,9 @@
return ERROR_MALFORMED;
}
- CHECK_LE(offset + aac_frame_length, buffer->size());
+ if (aac_frame_length > buffer->size() - offset) {
+ return ERROR_MALFORMED;
+ }
int64_t unitTimeUs = timeUs + numSamples * 1000000LL / sampleRate;
offset += aac_frame_length;
diff --git a/media/libstagefright/id3/Android.bp b/media/libstagefright/id3/Android.bp
index 7151d07..c8173cf 100644
--- a/media/libstagefright/id3/Android.bp
+++ b/media/libstagefright/id3/Android.bp
@@ -4,6 +4,7 @@
srcs: ["ID3.cpp"],
header_libs: [
+ "libmedia_headers",
"media_ndk_headers",
],
@@ -33,6 +34,7 @@
],
shared_libs: [
+ "libdatasource",
"libstagefright",
"libutils",
"liblog",
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index 792a68a..425468f 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -32,7 +32,7 @@
static const size_t kMaxMetadataSize = 3 * 1024 * 1024;
-struct MemorySource : public DataSourceBase {
+struct ID3::MemorySource : public DataSourceBase {
MemorySource(const uint8_t *data, size_t size)
: mData(data),
mSize(size) {
@@ -58,7 +58,7 @@
DISALLOW_EVIL_CONSTRUCTORS(MemorySource);
};
-class DataSourceUnwrapper : public DataSourceBase {
+class ID3::DataSourceUnwrapper : public DataSourceBase {
public:
explicit DataSourceUnwrapper(DataSourceHelper *sourcehelper) {
diff --git a/media/libstagefright/id3/test/Android.bp b/media/libstagefright/id3/test/Android.bp
new file mode 100644
index 0000000..9d26eec
--- /dev/null
+++ b/media/libstagefright/id3/test/Android.bp
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+cc_test {
+ name: "ID3Test",
+ gtest: true,
+
+ srcs: ["ID3Test.cpp"],
+
+ static_libs: [
+ "libdatasource",
+ "libstagefright_id3",
+ "libstagefright",
+ "libstagefright_foundation",
+ ],
+
+ shared_libs: [
+ "libutils",
+ "liblog",
+ "libbinder",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ sanitize: {
+ cfi: true,
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ },
+}
diff --git a/media/libstagefright/id3/test/AndroidTest.xml b/media/libstagefright/id3/test/AndroidTest.xml
new file mode 100644
index 0000000..6c6697d
--- /dev/null
+++ b/media/libstagefright/id3/test/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Test module config for ID3 unit tests">
+ <option name="test-suite-tag" value="ID3Test" />
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <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.zip?unzip=true"
+ value="/data/local/tmp/ID3TestRes/" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="ID3Test" />
+ <option name="native-test-flag" value="-P /data/local/tmp/ID3TestRes/" />
+ </test>
+</configuration>
diff --git a/media/libstagefright/id3/test/ID3Test.cpp b/media/libstagefright/id3/test/ID3Test.cpp
new file mode 100644
index 0000000..a8f1470
--- /dev/null
+++ b/media/libstagefright/id3/test/ID3Test.cpp
@@ -0,0 +1,217 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ID3Test"
+#include <utils/Log.h>
+
+#include <ctype.h>
+#include <string>
+#include <sys/stat.h>
+#include <datasource/FileSource.h>
+
+#include <media/stagefright/foundation/hexdump.h>
+#include <ID3.h>
+
+#include "ID3TestEnvironment.h"
+
+using namespace android;
+
+static ID3TestEnvironment *gEnv = nullptr;
+
+class ID3tagTest : public ::testing::TestWithParam<string> {};
+class ID3versionTest : public ::testing::TestWithParam<pair<string, int>> {};
+class ID3textTagTest : public ::testing::TestWithParam<pair<string, int>> {};
+class ID3albumArtTest : public ::testing::TestWithParam<pair<string, bool>> {};
+class ID3multiAlbumArtTest : public ::testing::TestWithParam<pair<string, int>> {};
+
+TEST_P(ID3tagTest, TagTest) {
+ string path = gEnv->getRes() + GetParam();
+ sp<FileSource> file = new FileSource(path.c_str());
+ ASSERT_EQ(file->initCheck(), (status_t)OK) << "File initialization failed! \n";
+ ID3 tag(file.get());
+ ASSERT_TRUE(tag.isValid()) << "No valid ID3 tag found for " << path.c_str() << "\n";
+
+ ID3::Iterator it(tag, nullptr);
+ while (!it.done()) {
+ String8 id;
+ it.getID(&id);
+ ASSERT_GT(id.length(), 0) << "No ID tag found! \n";
+ ALOGV("Found ID tag: %s\n", String8(id).c_str());
+ it.next();
+ }
+}
+
+TEST_P(ID3versionTest, VersionTest) {
+ int versionNumber = GetParam().second;
+ string path = gEnv->getRes() + GetParam().first;
+ sp<android::FileSource> file = new FileSource(path.c_str());
+ ASSERT_EQ(file->initCheck(), (status_t)OK) << "File initialization failed! \n";
+
+ ID3 tag(file.get());
+ ASSERT_TRUE(tag.isValid()) << "No valid ID3 tag found for " << path.c_str() << "\n";
+ ASSERT_TRUE(tag.version() >= versionNumber)
+ << "Expected version: " << tag.version() << " Found version: " << versionNumber;
+}
+
+TEST_P(ID3textTagTest, TextTagTest) {
+ int numTextFrames = GetParam().second;
+ string path = gEnv->getRes() + GetParam().first;
+ sp<android::FileSource> file = new FileSource(path.c_str());
+ ASSERT_EQ(file->initCheck(), (status_t)OK) << "File initialization failed! \n";
+
+ ID3 tag(file.get());
+ ASSERT_TRUE(tag.isValid()) << "No valid ID3 tag found for " << path.c_str() << "\n";
+ int countTextFrames = 0;
+ ID3::Iterator it(tag, nullptr);
+ while (!it.done()) {
+ String8 id;
+ it.getID(&id);
+ ASSERT_GT(id.length(), 0);
+ if (id[0] == 'T') {
+ String8 text;
+ countTextFrames++;
+ it.getString(&text);
+ ALOGV("Found text frame %s : %s \n", id.string(), text.string());
+ }
+ it.next();
+ }
+ ASSERT_EQ(countTextFrames, numTextFrames)
+ << "Expected " << numTextFrames << " text frames, found " << countTextFrames;
+}
+
+TEST_P(ID3albumArtTest, AlbumArtTest) {
+ bool albumArtPresent = GetParam().second;
+ string path = gEnv->getRes() + GetParam().first;
+ sp<android::FileSource> file = new FileSource(path.c_str());
+ ASSERT_EQ(file->initCheck(), (status_t)OK) << "File initialization failed! \n";
+
+ ID3 tag(file.get());
+ ASSERT_TRUE(tag.isValid()) << "No valid ID3 tag found for " << path.c_str() << "\n";
+ size_t dataSize;
+ String8 mime;
+ const void *data = tag.getAlbumArt(&dataSize, &mime);
+
+ if (albumArtPresent) {
+ if (data) {
+ ALOGV("Found album art: size = %zu mime = %s \n", dataSize, mime.string());
+ }
+ ASSERT_NE(data, nullptr) << "Expected album art, found none!" << path;
+ } else {
+ ASSERT_EQ(data, nullptr) << "Found album art when expected none!";
+ }
+#if (LOG_NDEBUG == 0)
+ hexdump(data, dataSize > 128 ? 128 : dataSize);
+#endif
+}
+
+TEST_P(ID3multiAlbumArtTest, MultiAlbumArtTest) {
+ int numAlbumArt = GetParam().second;
+ string path = gEnv->getRes() + GetParam().first;
+ sp<android::FileSource> file = new FileSource(path.c_str());
+ ASSERT_EQ(file->initCheck(), (status_t)OK) << "File initialization failed! \n";
+
+ ID3 tag(file.get());
+ ASSERT_TRUE(tag.isValid()) << "No valid ID3 tag found for " << path.c_str() << "\n";
+ int count = 0;
+ ID3::Iterator it(tag, nullptr);
+ while (!it.done()) {
+ String8 id;
+ it.getID(&id);
+ ASSERT_GT(id.length(), 0);
+ // Check if the tag is an "APIC/PIC" tag.
+ if (String8(id) == "APIC" || String8(id) == "PIC") {
+ count++;
+ size_t dataSize;
+ String8 mime;
+ const void *data = tag.getAlbumArt(&dataSize, &mime);
+ if (data) {
+ ALOGV("Found album art: size = %zu mime = %s \n", dataSize, mime.string());
+#if (LOG_NDEBUG == 0)
+ hexdump(data, dataSize > 128 ? 128 : dataSize);
+#endif
+ }
+ ASSERT_NE(data, nullptr) << "Expected album art, found none!" << path;
+ }
+ it.next();
+ }
+ ASSERT_EQ(count, numAlbumArt) << "Found " << count << " album arts, expected " << numAlbumArt
+ << " album arts! \n";
+}
+
+INSTANTIATE_TEST_SUITE_P(id3TestAll, ID3tagTest,
+ ::testing::Values("bbb_44100hz_2ch_128kbps_mp3_30sec.mp3",
+ "bbb_44100hz_2ch_128kbps_mp3_30sec_1_image.mp3",
+ "bbb_44100hz_2ch_128kbps_mp3_30sec_2_image.mp3",
+ "bbb_44100hz_2ch_128kbps_mp3_5mins.mp3",
+ "bbb_44100hz_2ch_128kbps_mp3_5mins_1_image.mp3",
+ "bbb_44100hz_2ch_128kbps_mp3_5mins_2_image.mp3",
+ "bbb_44100hz_2ch_128kbps_mp3_5mins_largeSize.mp3",
+ "bbb_44100hz_2ch_128kbps_mp3_30sec_moreTextFrames.mp3"));
+
+INSTANTIATE_TEST_SUITE_P(
+ id3TestAll, ID3versionTest,
+ ::testing::Values(make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec.mp3", 4),
+ make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec_1_image.mp3", 4),
+ make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec_2_image.mp3", 4),
+ make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins.mp3", 4),
+ make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins_1_image.mp3", 4),
+ make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins_2_image.mp3", 4),
+ make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins_largeSize.mp3", 4),
+ make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec_moreTextFrames.mp3", 4)));
+
+INSTANTIATE_TEST_SUITE_P(
+ id3TestAll, ID3textTagTest,
+ ::testing::Values(make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec.mp3", 1),
+ make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec_1_image.mp3", 1),
+ make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec_2_image.mp3", 1),
+ make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins.mp3", 1),
+ make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins_1_image.mp3", 1),
+ make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins_2_image.mp3", 1),
+ make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins_largeSize.mp3", 1),
+ make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec_moreTextFrames.mp3", 5)));
+
+INSTANTIATE_TEST_SUITE_P(
+ id3TestAll, ID3albumArtTest,
+ ::testing::Values(make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec.mp3", false),
+ make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec_1_image.mp3", true),
+ make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec_2_image.mp3", true),
+ make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins.mp3", false),
+ make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins_1_image.mp3", true),
+ make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins_2_image.mp3", true),
+ make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins_largeSize.mp3", true)));
+
+INSTANTIATE_TEST_SUITE_P(
+ id3TestAll, ID3multiAlbumArtTest,
+ ::testing::Values(make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec.mp3", 0),
+ make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins.mp3", 0),
+ make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec_1_image.mp3", 1),
+ make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins_1_image.mp3", 1),
+ make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec_2_image.mp3", 2),
+ make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins_2_image.mp3", 2),
+ make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins_largeSize.mp3", 3)));
+
+int main(int argc, char **argv) {
+ gEnv = new ID3TestEnvironment();
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = gEnv->initFromOptions(argc, argv);
+ if (status == 0) {
+ status = RUN_ALL_TESTS();
+ ALOGI("ID3 Test result = %d\n", status);
+ }
+ return status;
+}
diff --git a/media/libstagefright/id3/test/ID3TestEnvironment.h b/media/libstagefright/id3/test/ID3TestEnvironment.h
new file mode 100644
index 0000000..2229718
--- /dev/null
+++ b/media/libstagefright/id3/test/ID3TestEnvironment.h
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+#ifndef __ID3_TEST_ENVIRONMENT_H__
+#define __ID3_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class ID3TestEnvironment : public::testing::Environment {
+ public:
+ ID3TestEnvironment() : res("/data/local/tmp/") {}
+
+ // Parses the command line arguments
+ int initFromOptions(int argc, char **argv);
+
+ void setRes(const char *_res) { res = _res; }
+
+ const string getRes() const { return res; }
+
+ private:
+ string res;
+};
+
+int ID3TestEnvironment::initFromOptions(int argc, char **argv) {
+ static struct option options[] = {{"path", required_argument, 0, 'P'}, {0, 0, 0, 0}};
+
+ while (true) {
+ int index = 0;
+ int c = getopt_long(argc, argv, "P:", options, &index);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'P': {
+ setRes(optarg);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ if (optind < argc) {
+ fprintf(stderr,
+ "unrecognized option: %s\n\n"
+ "usage: %s <gtest options> <test options>\n\n"
+ "test options are:\n\n"
+ "-P, --path: Resource files directory location\n",
+ argv[optind ?: 1], argv[0]);
+ return 2;
+ }
+ return 0;
+}
+
+#endif // __ID3_TEST_ENVIRONMENT_H__
diff --git a/media/libstagefright/id3/test/README.md b/media/libstagefright/id3/test/README.md
new file mode 100644
index 0000000..7fd8901
--- /dev/null
+++ b/media/libstagefright/id3/test/README.md
@@ -0,0 +1,40 @@
+## Media Testing ##
+---
+#### ID3 Test :
+The ID3 Test Suite validates the ID3 parser available in libstagefright.
+
+Run the following command in the id3 folder to build the test suite:
+```
+m ID3Test
+```
+
+The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/
+
+The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/
+
+To test 64-bit binary push binaries from nativetest64.
+```
+adb push ${OUT}/data/nativetest64/ID3Test/ID3Test /data/local/tmp/
+```
+
+To test 32-bit binary push binaries from nativetest.
+```
+adb push ${OUT}/data/nativetest/ID3Test/ID3Test /data/local/tmp/
+```
+
+The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/id3/test/ID3Test.zip ).
+Download, unzip and push these files into device for testing.
+
+```
+adb push ID3Test /data/local/tmp/
+```
+
+usage: ID3Test -P \<path_to_folder\>
+```
+adb shell /data/local/tmp/ID3Test -P /data/local/tmp/ID3/
+```
+Alternatively, the test can also be run using atest command.
+
+```
+atest ID3Test -- --enable-module-dynamic-download=true
+```
diff --git a/media/libstagefright/id3/testid3.cpp b/media/libstagefright/id3/testid3.cpp
index 86e6adf..9984d85 100644
--- a/media/libstagefright/id3/testid3.cpp
+++ b/media/libstagefright/id3/testid3.cpp
@@ -22,7 +22,7 @@
#include <dirent.h>
#include <binder/ProcessState.h>
-#include <media/stagefright/FileSource.h>
+#include <datasource/FileSource.h>
#include <media/stagefright/foundation/ADebug.h>
#define MAXPATHLEN 256
diff --git a/media/libstagefright/include/ACodecBufferChannel.h b/media/libstagefright/include/ACodecBufferChannel.h
index 7c01e45..da962d1 100644
--- a/media/libstagefright/include/ACodecBufferChannel.h
+++ b/media/libstagefright/include/ACodecBufferChannel.h
@@ -25,7 +25,7 @@
#include <media/openmax/OMX_Types.h>
#include <media/stagefright/CodecBase.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/IOMX.h>
namespace android {
@@ -67,6 +67,9 @@
virtual ~ACodecBufferChannel();
// BufferChannelBase interface
+ void setCrypto(const sp<ICrypto> &crypto) override;
+ void setDescrambler(const sp<IDescrambler> &descrambler) override;
+
virtual status_t queueInputBuffer(const sp<MediaCodecBuffer> &buffer) override;
virtual status_t queueSecureInputBuffer(
const sp<MediaCodecBuffer> &buffer,
@@ -78,6 +81,20 @@
const CryptoPlugin::SubSample *subSamples,
size_t numSubSamples,
AString *errorDetailMsg) override;
+ virtual status_t attachBuffer(
+ const std::shared_ptr<C2Buffer> &c2Buffer,
+ const sp<MediaCodecBuffer> &buffer) override;
+ virtual status_t attachEncryptedBuffer(
+ const sp<hardware::HidlMemory> &memory,
+ bool secure,
+ const uint8_t *key,
+ const uint8_t *iv,
+ CryptoPlugin::Mode mode,
+ CryptoPlugin::Pattern pattern,
+ size_t offset,
+ const CryptoPlugin::SubSample *subSamples,
+ size_t numSubSamples,
+ const sp<MediaCodecBuffer> &buffer) override;
virtual status_t renderOutputBuffer(
const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) override;
virtual status_t discardBuffer(const sp<MediaCodecBuffer> &buffer) override;
@@ -115,12 +132,15 @@
void drainThisBuffer(IOMX::buffer_id bufferID, OMX_U32 omxFlags);
private:
+ int32_t getHeapSeqNum(const sp<HidlMemory> &memory);
+
const sp<AMessage> mInputBufferFilled;
const sp<AMessage> mOutputBufferDrained;
sp<MemoryDealer> mDealer;
sp<IMemory> mDecryptDestination;
int32_t mHeapSeqNum;
+ std::map<wp<HidlMemory>, int32_t> mHeapSeqNumMap;
sp<HidlMemory> mHidlMemory;
// These should only be accessed via std::atomic_* functions.
@@ -135,6 +155,9 @@
sp<MemoryDealer> makeMemoryDealer(size_t heapSize);
+ sp<ICrypto> mCrypto;
+ sp<IDescrambler> mDescrambler;
+
bool hasCryptoOrDescrambler() {
return mCrypto != NULL || mDescrambler != NULL;
}
diff --git a/media/libstagefright/include/CallbackDataSource.h b/media/libstagefright/include/CallbackDataSource.h
index 9f413cd..e428494 100644
--- a/media/libstagefright/include/CallbackDataSource.h
+++ b/media/libstagefright/include/CallbackDataSource.h
@@ -41,7 +41,6 @@
virtual String8 toString() {
return mName;
}
- virtual sp<DecryptHandle> DrmInitialization(const char *mime = NULL);
virtual sp<IDataSource> getIDataSource() const;
private:
@@ -70,7 +69,6 @@
virtual String8 toString() {
return mName;
}
- virtual sp<DecryptHandle> DrmInitialization(const char *mime = NULL);
virtual sp<IDataSource> getIDataSource() const;
private:
diff --git a/media/libstagefright/include/FrameCaptureLayer.h b/media/libstagefright/include/FrameCaptureLayer.h
new file mode 100644
index 0000000..23fd5e5
--- /dev/null
+++ b/media/libstagefright/include/FrameCaptureLayer.h
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+#ifndef FRAME_CAPTURE_LAYER_H_
+#define FRAME_CAPTURE_LAYER_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <gui/IConsumerListener.h>
+#include <ui/GraphicTypes.h>
+#include <utils/Mutex.h>
+#include <utils/Condition.h>
+
+namespace android {
+
+class GraphicBuffer;
+class IGraphicBufferConsumer;
+class Rect;
+class Surface;
+
+/*
+ * This class is a simple BufferQueue consumer implementation to
+ * obtain a decoded buffer output from MediaCodec. The output
+ * buffer is then sent to FrameCaptureProcessor to be converted
+ * to sRGB properly.
+ */
+struct FrameCaptureLayer : public ConsumerListener {
+ FrameCaptureLayer();
+ ~FrameCaptureLayer() = default;
+
+ // ConsumerListener
+ void onFrameAvailable(const BufferItem& /*item*/) override;
+ void onBuffersReleased() override;
+ void onSidebandStreamChanged() override;
+
+ status_t init();
+
+ sp<Surface> getSurface() { return mSurface; }
+
+ status_t capture(const ui::PixelFormat reqPixelFormat,
+ const Rect &sourceCrop, sp<GraphicBuffer> *outBuffer);
+
+private:
+ struct BufferLayer;
+ // Note: do not hold any sp ref to GraphicBufferSource
+ // GraphicBufferSource is holding an sp to us, holding any sp ref
+ // to GraphicBufferSource will cause circular dependency and both
+ // object will not be released.
+ sp<IGraphicBufferConsumer> mConsumer;
+ sp<Surface> mSurface;
+ std::map<int32_t, sp<GraphicBuffer> > mSlotToBufferMap;
+
+ Mutex mLock;
+ Condition mCondition;
+ bool mFrameAvailable GUARDED_BY(mLock);
+
+ status_t acquireBuffer(BufferItem *bi);
+ status_t releaseBuffer(const BufferItem &bi);
+
+ DISALLOW_EVIL_CONSTRUCTORS(FrameCaptureLayer);
+};
+
+} // namespace android
+
+#endif // FRAME_CAPTURE_LAYER_H_
diff --git a/media/libstagefright/include/FrameDecoder.h b/media/libstagefright/include/FrameDecoder.h
index dc58c15..19ae0e3 100644
--- a/media/libstagefright/include/FrameDecoder.h
+++ b/media/libstagefright/include/FrameDecoder.h
@@ -22,17 +22,18 @@
#include <media/stagefright/foundation/AString.h>
#include <media/stagefright/foundation/ABase.h>
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/openmax/OMX_Video.h>
-#include <system/graphics-base.h>
+#include <ui/GraphicTypes.h>
namespace android {
struct AMessage;
-class MediaCodecBuffer;
-class IMediaSource;
-class VideoFrame;
struct MediaCodec;
+class IMediaSource;
+class MediaCodecBuffer;
+class Surface;
+class VideoFrame;
struct FrameRect {
int32_t left, top, right, bottom;
@@ -44,13 +45,10 @@
const sp<MetaData> &trackMeta,
const sp<IMediaSource> &source);
- status_t init(
- int64_t frameTimeUs, size_t numFrames, int option, int colorFormat);
+ status_t init(int64_t frameTimeUs, int option, int colorFormat);
sp<IMemory> extractFrame(FrameRect *rect = NULL);
- status_t extractFrames(std::vector<sp<IMemory> >* frames);
-
static sp<IMemory> getMetadataOnly(
const sp<MetaData> &trackMeta, int colorFormat, bool thumbnail = false);
@@ -59,9 +57,9 @@
virtual sp<AMessage> onGetFormatAndSeekOptions(
int64_t frameTimeUs,
- size_t numFrames,
int seekMode,
- MediaSource::ReadOptions *options) = 0;
+ MediaSource::ReadOptions *options,
+ sp<Surface> *window) = 0;
virtual status_t onExtractRect(FrameRect *rect) = 0;
@@ -79,29 +77,30 @@
sp<MetaData> trackMeta() const { return mTrackMeta; }
OMX_COLOR_FORMATTYPE dstFormat() const { return mDstFormat; }
+ ui::PixelFormat captureFormat() const { return mCaptureFormat; }
int32_t dstBpp() const { return mDstBpp; }
-
- void addFrame(const sp<IMemory> &frame) {
- mFrames.push_back(frame);
- }
+ void setFrame(const sp<IMemory> &frameMem) { mFrameMemory = frameMem; }
private:
AString mComponentName;
sp<MetaData> mTrackMeta;
sp<IMediaSource> mSource;
OMX_COLOR_FORMATTYPE mDstFormat;
+ ui::PixelFormat mCaptureFormat;
int32_t mDstBpp;
- std::vector<sp<IMemory> > mFrames;
+ sp<IMemory> mFrameMemory;
MediaSource::ReadOptions mReadOptions;
sp<MediaCodec> mDecoder;
sp<AMessage> mOutputFormat;
bool mHaveMoreInputs;
bool mFirstSample;
+ sp<Surface> mSurface;
status_t extractInternal();
DISALLOW_EVIL_CONSTRUCTORS(FrameDecoder);
};
+struct FrameCaptureLayer;
struct VideoFrameDecoder : public FrameDecoder {
VideoFrameDecoder(
@@ -112,9 +111,9 @@
protected:
virtual sp<AMessage> onGetFormatAndSeekOptions(
int64_t frameTimeUs,
- size_t numFrames,
int seekMode,
- MediaSource::ReadOptions *options) override;
+ MediaSource::ReadOptions *options,
+ sp<Surface> *window) override;
virtual status_t onExtractRect(FrameRect *rect) override {
// Rect extraction for sequences is not supported for now.
@@ -134,11 +133,16 @@
bool *done) override;
private:
+ sp<FrameCaptureLayer> mCaptureLayer;
+ VideoFrame *mFrame;
bool mIsAvcOrHevc;
MediaSource::ReadOptions::SeekMode mSeekMode;
int64_t mTargetTimeUs;
- size_t mNumFrames;
- size_t mNumFramesDecoded;
+ List<int64_t> mSampleDurations;
+ int64_t mDefaultSampleDurationUs;
+
+ sp<Surface> initSurface();
+ status_t captureSurface();
};
struct ImageDecoder : public FrameDecoder {
@@ -150,9 +154,9 @@
protected:
virtual sp<AMessage> onGetFormatAndSeekOptions(
int64_t frameTimeUs,
- size_t numFrames,
int seekMode,
- MediaSource::ReadOptions *options) override;
+ MediaSource::ReadOptions *options,
+ sp<Surface> *window) override;
virtual status_t onExtractRect(FrameRect *rect) override;
diff --git a/media/libstagefright/include/HTTPBase.h b/media/libstagefright/include/HTTPBase.h
deleted file mode 100644
index 8b20187..0000000
--- a/media/libstagefright/include/HTTPBase.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef HTTP_BASE_H_
-
-#define HTTP_BASE_H_
-
-#include <media/DataSource.h>
-#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/MediaErrors.h>
-#include <utils/List.h>
-#include <utils/threads.h>
-
-namespace android {
-
-struct HTTPBase : public DataSource {
- enum Flags {
- // Don't log any URLs.
- kFlagIncognito = 1
- };
-
- HTTPBase();
-
- virtual status_t connect(
- const char *uri,
- const KeyedVector<String8, String8> *headers = NULL,
- off64_t offset = 0) = 0;
-
- virtual void disconnect() = 0;
-
- // Returns true if bandwidth could successfully be estimated,
- // false otherwise.
- virtual bool estimateBandwidth(int32_t *bandwidth_bps);
-
- virtual status_t getEstimatedBandwidthKbps(int32_t *kbps);
-
- virtual status_t setBandwidthStatCollectFreq(int32_t freqMs);
-
- virtual void setBandwidthHistorySize(size_t numHistoryItems);
-
- virtual String8 toString() {
- return mName;
- }
-
-protected:
- virtual void addBandwidthMeasurement(size_t numBytes, int64_t delayUs);
- String8 mName;
-
-private:
- struct BandwidthEntry {
- int64_t mDelayUs;
- size_t mNumBytes;
- };
-
- Mutex mLock;
-
- List<BandwidthEntry> mBandwidthHistory;
- size_t mNumBandwidthHistoryItems;
- int64_t mTotalTransferTimeUs;
- size_t mTotalTransferBytes;
- size_t mMaxBandwidthHistoryItems;
-
- enum {
- kMinBandwidthCollectFreqMs = 1000, // 1 second
- kMaxBandwidthCollectFreqMs = 60000, // one minute
- };
-
- int64_t mPrevBandwidthMeasureTimeUs;
- int32_t mPrevEstimatedBandWidthKbps;
- int32_t mBandWidthCollectFreqMs;
-
- DISALLOW_EVIL_CONSTRUCTORS(HTTPBase);
-};
-
-} // namespace android
-
-#endif // HTTP_BASE_H_
diff --git a/media/libstagefright/include/ID3.h b/media/libstagefright/include/ID3.h
index 5e433ea..2843a7a 100644
--- a/media/libstagefright/include/ID3.h
+++ b/media/libstagefright/include/ID3.h
@@ -77,6 +77,8 @@
size_t rawSize() const { return mRawSize; }
private:
+ class DataSourceUnwrapper;
+ struct MemorySource;
bool mIsValid;
uint8_t *mData;
size_t mSize;
diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libstagefright/include/NuCachedSource2.h
deleted file mode 100644
index 596efb8..0000000
--- a/media/libstagefright/include/NuCachedSource2.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NU_CACHED_SOURCE_2_H_
-
-#define NU_CACHED_SOURCE_2_H_
-
-#include <media/DataSource.h>
-#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/foundation/AHandlerReflector.h>
-
-namespace android {
-
-struct ALooper;
-struct PageCache;
-
-struct NuCachedSource2 : public DataSource {
- static sp<NuCachedSource2> Create(
- const sp<DataSource> &source,
- const char *cacheConfig = NULL,
- bool disconnectAtHighwatermark = false);
-
- virtual status_t initCheck() const;
-
- virtual ssize_t readAt(off64_t offset, void *data, size_t size);
-
- virtual void close();
-
- virtual void disconnect();
-
- virtual status_t getSize(off64_t *size);
- virtual uint32_t flags();
-
- virtual sp<DecryptHandle> DrmInitialization(const char* mime);
- virtual String8 getUri();
-
- virtual String8 getMIMEType() const;
-
- virtual String8 toString() {
- return mName;
- }
-
- status_t getAvailableSize(off64_t offset, off64_t *size);
-
- ////////////////////////////////////////////////////////////////////////////
-
- size_t cachedSize();
- size_t approxDataRemaining(status_t *finalStatus) const;
-
- void resumeFetchingIfNecessary();
-
- // The following methods are supported only if the
- // data source is HTTP-based; otherwise, ERROR_UNSUPPORTED
- // is returned.
- status_t getEstimatedBandwidthKbps(int32_t *kbps);
- status_t setCacheStatCollectFreq(int32_t freqMs);
-
- static void RemoveCacheSpecificHeaders(
- KeyedVector<String8, String8> *headers,
- String8 *cacheConfig,
- bool *disconnectAtHighwatermark);
-
-protected:
- virtual ~NuCachedSource2();
-
-private:
- friend struct AHandlerReflector<NuCachedSource2>;
-
- NuCachedSource2(
- const sp<DataSource> &source,
- const char *cacheConfig,
- bool disconnectAtHighwatermark);
-
- enum {
- kPageSize = 65536,
- kDefaultHighWaterThreshold = 20 * 1024 * 1024,
- kDefaultLowWaterThreshold = 4 * 1024 * 1024,
-
- // Read data after a 15 sec timeout whether we're actively
- // fetching or not.
- kDefaultKeepAliveIntervalUs = 15000000,
- };
-
- enum {
- kWhatFetchMore = 'fetc',
- kWhatRead = 'read',
- };
-
- enum {
- kMaxNumRetries = 10,
- };
-
- sp<DataSource> mSource;
- sp<AHandlerReflector<NuCachedSource2> > mReflector;
- sp<ALooper> mLooper;
- String8 mName;
-
- Mutex mSerializer;
- mutable Mutex mLock;
- Condition mCondition;
-
- PageCache *mCache;
- off64_t mCacheOffset;
- status_t mFinalStatus;
- off64_t mLastAccessPos;
- sp<AMessage> mAsyncResult;
- bool mFetching;
- bool mDisconnecting;
- int64_t mLastFetchTimeUs;
-
- int32_t mNumRetriesLeft;
-
- size_t mHighwaterThresholdBytes;
- size_t mLowwaterThresholdBytes;
-
- // If the keep-alive interval is 0, keep-alives are disabled.
- int64_t mKeepAliveIntervalUs;
-
- bool mDisconnectAtHighwatermark;
-
- void onMessageReceived(const sp<AMessage> &msg);
- void onFetch();
- void onRead(const sp<AMessage> &msg);
-
- void fetchInternal();
- ssize_t readInternal(off64_t offset, void *data, size_t size);
- status_t seekInternal_l(off64_t offset);
-
- size_t approxDataRemaining_l(off64_t offset, status_t *finalStatus) const;
-
- void restartPrefetcherIfNecessary_l(
- bool ignoreLowWaterThreshold = false, bool force = false);
-
- void updateCacheParamsFromSystemProperty();
- void updateCacheParamsFromString(const char *s);
-
- DISALLOW_EVIL_CONSTRUCTORS(NuCachedSource2);
-};
-
-} // namespace android
-
-#endif // NU_CACHED_SOURCE_2_H_
diff --git a/media/libstagefright/include/SecureBuffer.h b/media/libstagefright/include/SecureBuffer.h
index cf7933a..c45e0e5 100644
--- a/media/libstagefright/include/SecureBuffer.h
+++ b/media/libstagefright/include/SecureBuffer.h
@@ -18,7 +18,7 @@
#define SECURE_BUFFER_H_
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/MediaCodecBuffer.h>
namespace android {
diff --git a/media/libstagefright/include/StagefrightMetadataRetriever.h b/media/libstagefright/include/StagefrightMetadataRetriever.h
deleted file mode 100644
index c50677a..0000000
--- a/media/libstagefright/include/StagefrightMetadataRetriever.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef STAGEFRIGHT_METADATA_RETRIEVER_H_
-
-#define STAGEFRIGHT_METADATA_RETRIEVER_H_
-
-#include <media/IMediaExtractor.h>
-#include <media/MediaMetadataRetrieverInterface.h>
-
-#include <utils/KeyedVector.h>
-
-namespace android {
-
-class DataSource;
-struct ImageDecoder;
-struct FrameRect;
-
-struct StagefrightMetadataRetriever : public MediaMetadataRetrieverBase {
- StagefrightMetadataRetriever();
- virtual ~StagefrightMetadataRetriever();
-
- virtual status_t setDataSource(
- const sp<IMediaHTTPService> &httpService,
- const char *url,
- const KeyedVector<String8, String8> *headers);
-
- virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
- virtual status_t setDataSource(const sp<DataSource>& source, const char *mime);
-
- virtual sp<IMemory> getFrameAtTime(
- int64_t timeUs, int option, int colorFormat, bool metaOnly);
- virtual sp<IMemory> getImageAtIndex(
- int index, int colorFormat, bool metaOnly, bool thumbnail);
- virtual sp<IMemory> getImageRectAtIndex(
- int index, int colorFormat, int left, int top, int right, int bottom);
- virtual status_t getFrameAtIndex(
- std::vector<sp<IMemory> >* frames,
- int frameIndex, int numFrames, int colorFormat, bool metaOnly);
-
- virtual MediaAlbumArt *extractAlbumArt();
- virtual const char *extractMetadata(int keyCode);
-
-private:
- sp<DataSource> mSource;
- sp<IMediaExtractor> mExtractor;
-
- bool mParsedMetaData;
- KeyedVector<int, String8> mMetaData;
- MediaAlbumArt *mAlbumArt;
-
- sp<ImageDecoder> mImageDecoder;
- int mLastImageIndex;
- void parseMetaData();
- void parseColorAspects(const sp<MetaData>& meta);
- // Delete album art and clear metadata.
- void clearMetadata();
-
- status_t getFrameInternal(
- int64_t timeUs, int numFrames, int option, int colorFormat, bool metaOnly,
- sp<IMemory>* outFrame, std::vector<sp<IMemory> >* outFrames);
- virtual sp<IMemory> getImageInternal(
- int index, int colorFormat, bool metaOnly, bool thumbnail, FrameRect* rect);
-
- StagefrightMetadataRetriever(const StagefrightMetadataRetriever &);
-
- StagefrightMetadataRetriever &operator=(
- const StagefrightMetadataRetriever &);
-};
-
-} // namespace android
-
-#endif // STAGEFRIGHT_METADATA_RETRIEVER_H_
diff --git a/media/libstagefright/include/ThrottledSource.h b/media/libstagefright/include/ThrottledSource.h
index 71e62f7..5ae0653 100644
--- a/media/libstagefright/include/ThrottledSource.h
+++ b/media/libstagefright/include/ThrottledSource.h
@@ -54,10 +54,6 @@
return mSource->reconnectAtOffset(offset);
}
- virtual sp<DecryptHandle> DrmInitialization(const char *mime = NULL) {
- return mSource->DrmInitialization(mime);
- }
-
virtual String8 getMIMEType() const {
return mSource->getMIMEType();
}
diff --git a/media/libstagefright/include/media/stagefright/AACWriter.h b/media/libstagefright/include/media/stagefright/AACWriter.h
index 7c63ddd..2671138 100644
--- a/media/libstagefright/include/media/stagefright/AACWriter.h
+++ b/media/libstagefright/include/media/stagefright/AACWriter.h
@@ -17,7 +17,7 @@
#ifndef AAC_WRITER_H_
#define AAC_WRITER_H_
-#include "foundation/ABase.h"
+#include "media/stagefright/foundation/ABase.h"
#include <media/stagefright/MediaWriter.h>
#include <utils/threads.h>
diff --git a/media/libstagefright/include/media/stagefright/ACodec.h b/media/libstagefright/include/media/stagefright/ACodec.h
index 784fd36..83e92b9 100644
--- a/media/libstagefright/include/media/stagefright/ACodec.h
+++ b/media/libstagefright/include/media/stagefright/ACodec.h
@@ -37,6 +37,15 @@
#define TRACK_BUFFER_TIMING 0
namespace android {
+namespace hardware {
+namespace media {
+namespace omx {
+namespace V1_0 {
+struct IGraphicBufferSource;
+} // namespace V1_0
+} // namespace omx
+} // namespace media
+} // namespace hardware
struct ABuffer;
class ACodecBufferChannel;
@@ -149,6 +158,7 @@
kFlagIsSecure = 1,
kFlagPushBlankBuffersToNativeWindowOnShutdown = 2,
kFlagIsGrallocUsageProtected = 4,
+ kFlagPreregisterMetadataBuffers = 8,
};
enum {
@@ -279,7 +289,7 @@
size_t mNumUndequeuedBuffers;
sp<DataConverter> mConverter[2];
- sp<IGraphicBufferSource> mGraphicBufferSource;
+ sp<hardware::media::omx::V1_0::IGraphicBufferSource> mGraphicBufferSource;
int64_t mRepeatFrameDelayUs;
int64_t mMaxPtsGapUs;
float mMaxFps;
@@ -466,6 +476,8 @@
int32_t targetRefLevel;
int32_t encodedTargetLevel;
int32_t effectType;
+ int32_t albumMode;
+ int32_t outputLoudness;
} drcParams_t;
status_t setupAACCodec(
@@ -496,6 +508,7 @@
AudioEncoding encoding = kAudioEncodingPcm16bit);
status_t setPriority(int32_t priority);
+ status_t setLowLatency(int32_t lowLatency);
status_t setLatency(uint32_t latency);
status_t getLatency(uint32_t *latency);
status_t setAudioPresentation(int32_t presentationId, int32_t programId);
diff --git a/media/libstagefright/include/media/stagefright/AudioPlayer.h b/media/libstagefright/include/media/stagefright/AudioPlayer.h
deleted file mode 100644
index 7c2c36f..0000000
--- a/media/libstagefright/include/media/stagefright/AudioPlayer.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AUDIO_PLAYER_H_
-
-#define AUDIO_PLAYER_H_
-
-#include <media/MediaSource.h>
-#include <media/MediaPlayerInterface.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <utils/threads.h>
-
-namespace android {
-
-struct AudioPlaybackRate;
-class AudioTrack;
-struct AwesomePlayer;
-
-class AudioPlayer {
-public:
- enum {
- REACHED_EOS,
- SEEK_COMPLETE
- };
-
- enum {
- ALLOW_DEEP_BUFFERING = 0x01,
- USE_OFFLOAD = 0x02,
- HAS_VIDEO = 0x1000,
- IS_STREAMING = 0x2000
-
- };
-
- AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink,
- uint32_t flags = 0);
-
- virtual ~AudioPlayer();
-
- // Caller retains ownership of "source".
- void setSource(const sp<MediaSource> &source);
-
- status_t start(bool sourceAlreadyStarted = false);
-
- void pause(bool playPendingSamples = false);
- status_t resume();
-
- status_t seekTo(int64_t time_us);
-
- bool isSeeking();
- bool reachedEOS(status_t *finalStatus);
-
- status_t setPlaybackRate(const AudioPlaybackRate &rate);
- status_t getPlaybackRate(AudioPlaybackRate *rate /* nonnull */);
-
-private:
- sp<MediaSource> mSource;
- sp<AudioTrack> mAudioTrack;
-
- MediaBufferBase *mInputBuffer;
-
- int mSampleRate;
- int64_t mLatencyUs;
- size_t mFrameSize;
-
- Mutex mLock;
- int64_t mNumFramesPlayed;
- int64_t mNumFramesPlayedSysTimeUs;
-
- int64_t mPositionTimeMediaUs;
- int64_t mPositionTimeRealUs;
-
- bool mSeeking;
- bool mReachedEOS;
- status_t mFinalStatus;
- int64_t mSeekTimeUs;
-
- bool mStarted;
-
- bool mIsFirstBuffer;
- status_t mFirstBufferResult;
- MediaBufferBase *mFirstBuffer;
-
- sp<MediaPlayerBase::AudioSink> mAudioSink;
-
- bool mPlaying;
- int64_t mStartPosUs;
- const uint32_t mCreateFlags;
-
- static void AudioCallback(int event, void *user, void *info);
- void AudioCallback(int event, void *info);
-
- static size_t AudioSinkCallback(
- MediaPlayerBase::AudioSink *audioSink,
- void *data, size_t size, void *me,
- MediaPlayerBase::AudioSink::cb_event_t event);
-
- size_t fillBuffer(void *data, size_t size);
-
- void reset();
-
- int64_t getOutputPlayPositionUs_l();
-
- bool allowDeepBuffering() const { return (mCreateFlags & ALLOW_DEEP_BUFFERING) != 0; }
- bool useOffload() const { return (mCreateFlags & USE_OFFLOAD) != 0; }
-
- AudioPlayer(const AudioPlayer &);
- AudioPlayer &operator=(const AudioPlayer &);
-};
-
-} // namespace android
-
-#endif // AUDIO_PLAYER_H_
diff --git a/media/libstagefright/include/media/stagefright/AudioSource.h b/media/libstagefright/include/media/stagefright/AudioSource.h
index af04dad..451aa57 100644
--- a/media/libstagefright/include/media/stagefright/AudioSource.h
+++ b/media/libstagefright/include/media/stagefright/AudioSource.h
@@ -20,7 +20,7 @@
#include <media/AudioRecord.h>
#include <media/AudioSystem.h>
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/MicrophoneInfo.h>
#include <media/stagefright/MediaBuffer.h>
#include <utils/List.h>
@@ -37,7 +37,7 @@
// Note that the "channels" parameter _is_ the number of channels,
// _not_ a bitmask of audio_channels_t constants.
AudioSource(
- audio_source_t inputSource,
+ const audio_attributes_t *attr,
const String16 &opPackageName,
uint32_t sampleRate,
uint32_t channels,
diff --git a/media/libstagefright/include/media/stagefright/CallbackMediaSource.h b/media/libstagefright/include/media/stagefright/CallbackMediaSource.h
index 33453fa..d2adbb9 100644
--- a/media/libstagefright/include/media/stagefright/CallbackMediaSource.h
+++ b/media/libstagefright/include/media/stagefright/CallbackMediaSource.h
@@ -17,7 +17,7 @@
#ifndef CALLBACK_MEDIA_SOURCE_H_
#define CALLBACK_MEDIA_SOURCE_H_
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/stagefright/foundation/ABase.h>
namespace android {
diff --git a/media/libstagefright/include/media/stagefright/CameraSource.h b/media/libstagefright/include/media/stagefright/CameraSource.h
index 3037b72..6f0d3b5 100644
--- a/media/libstagefright/include/media/stagefright/CameraSource.h
+++ b/media/libstagefright/include/media/stagefright/CameraSource.h
@@ -19,7 +19,7 @@
#define CAMERA_SOURCE_H_
#include <deque>
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MediaBuffer.h>
#include <camera/android/hardware/ICamera.h>
#include <camera/ICameraRecordingProxy.h>
diff --git a/media/libstagefright/include/media/stagefright/ClearFileSource.h b/media/libstagefright/include/media/stagefright/ClearFileSource.h
deleted file mode 100644
index be83748..0000000
--- a/media/libstagefright/include/media/stagefright/ClearFileSource.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CLEAR_FILE_SOURCE_H_
-
-#define CLEAR_FILE_SOURCE_H_
-
-#include <stdio.h>
-
-#include <media/DataSource.h>
-#include <media/stagefright/MediaErrors.h>
-#include <utils/threads.h>
-
-namespace android {
-
-class ClearFileSource : public DataSource {
-public:
- ClearFileSource(const char *filename);
- // ClearFileSource takes ownership and will close the fd
- ClearFileSource(int fd, int64_t offset, int64_t length);
-
- virtual status_t initCheck() const;
-
- virtual ssize_t readAt(off64_t offset, void *data, size_t size);
-
- virtual status_t getSize(off64_t *size);
-
- virtual uint32_t flags() {
- return kIsLocalFileSource;
- }
-
- virtual String8 toString() {
- return mName;
- }
-
-protected:
- virtual ~ClearFileSource();
- virtual ssize_t readAt_l(off64_t offset, void *data, size_t size);
-
- int mFd;
- int64_t mOffset;
- int64_t mLength;
- Mutex mLock;
-
-private:
- String8 mName;
-
- ClearFileSource(const ClearFileSource &);
- ClearFileSource &operator=(const ClearFileSource &);
-};
-
-} // namespace android
-
-#endif // CLEAR_FILE_SOURCE_H_
-
diff --git a/media/libstagefright/include/media/stagefright/ClearMediaHTTP.h b/media/libstagefright/include/media/stagefright/ClearMediaHTTP.h
deleted file mode 100644
index 72907a9..0000000
--- a/media/libstagefright/include/media/stagefright/ClearMediaHTTP.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CLEAR_MEDIA_HTTP_H_
-
-#define CLEAR_MEDIA_HTTP_H_
-
-#include <media/stagefright/foundation/AString.h>
-
-#include "include/HTTPBase.h"
-
-namespace android {
-
-struct MediaHTTPConnection;
-
-struct ClearMediaHTTP : public HTTPBase {
- ClearMediaHTTP(const sp<MediaHTTPConnection> &conn);
-
- virtual status_t connect(
- const char *uri,
- const KeyedVector<String8, String8> *headers,
- off64_t offset);
-
- virtual void close();
-
- virtual void disconnect();
-
- virtual status_t initCheck() const;
-
- virtual ssize_t readAt(off64_t offset, void *data, size_t size);
-
- virtual status_t getSize(off64_t *size);
-
- virtual uint32_t flags();
-
- virtual status_t reconnectAtOffset(off64_t offset);
-
-protected:
- virtual ~ClearMediaHTTP();
-
- virtual String8 getUri();
- virtual String8 getMIMEType() const;
-
- AString mLastURI;
-
-private:
- status_t mInitCheck;
- sp<MediaHTTPConnection> mHTTPConnection;
-
- KeyedVector<String8, String8> mLastHeaders;
-
- bool mCachedSizeValid;
- off64_t mCachedSize;
-
- DISALLOW_EVIL_CONSTRUCTORS(ClearMediaHTTP);
-};
-
-} // namespace android
-
-#endif // CLEAR_MEDIA_HTTP_H_
diff --git a/media/libstagefright/include/media/stagefright/CodecBase.h b/media/libstagefright/include/media/stagefright/CodecBase.h
index ad60f46..dd6df90 100644
--- a/media/libstagefright/include/media/stagefright/CodecBase.h
+++ b/media/libstagefright/include/media/stagefright/CodecBase.h
@@ -34,6 +34,8 @@
#include <system/graphics.h>
#include <utils/NativeHandle.h>
+class C2Buffer;
+
namespace android {
class BufferChannelBase;
struct BufferProducerWrapper;
@@ -42,12 +44,21 @@
struct RenderedFrameInfo;
class Surface;
struct ICrypto;
+class IMemory;
+
namespace hardware {
+class HidlMemory;
namespace cas {
namespace native {
namespace V1_0 {
struct IDescrambler;
-}}}}
+}}}
+namespace drm {
+namespace V1_0 {
+struct SharedBuffer;
+}}
+}
+
using hardware::cas::native::V1_0::IDescrambler;
struct CodecBase : public AHandler, /* static */ ColorUtils {
@@ -249,15 +260,15 @@
*/
class BufferChannelBase {
public:
+ BufferChannelBase() = default;
virtual ~BufferChannelBase() = default;
inline void setCallback(std::unique_ptr<CodecBase::BufferCallback> &&callback) {
mCallback = std::move(callback);
}
- void setCrypto(const sp<ICrypto> &crypto);
-
- void setDescrambler(const sp<IDescrambler> &descrambler);
+ virtual void setCrypto(const sp<ICrypto> &) {}
+ virtual void setDescrambler(const sp<IDescrambler> &) {}
/**
* Queue an input buffer into the buffer channel.
@@ -287,6 +298,50 @@
size_t numSubSamples,
AString *errorDetailMsg) = 0;
/**
+ * Attach a Codec 2.0 buffer to MediaCodecBuffer.
+ *
+ * @return OK if successful;
+ * -ENOENT if index is not recognized
+ * -ENOSYS if attaching buffer is not possible or not supported
+ */
+ virtual status_t attachBuffer(
+ const std::shared_ptr<C2Buffer> &c2Buffer,
+ const sp<MediaCodecBuffer> &buffer) {
+ (void)c2Buffer;
+ (void)buffer;
+ return -ENOSYS;
+ }
+ /**
+ * Attach an encrypted HidlMemory buffer to an index
+ *
+ * @return OK if successful;
+ * -ENOENT if index is not recognized
+ * -ENOSYS if attaching buffer is not possible or not supported
+ */
+ virtual status_t attachEncryptedBuffer(
+ const sp<hardware::HidlMemory> &memory,
+ bool secure,
+ const uint8_t *key,
+ const uint8_t *iv,
+ CryptoPlugin::Mode mode,
+ CryptoPlugin::Pattern pattern,
+ size_t offset,
+ const CryptoPlugin::SubSample *subSamples,
+ size_t numSubSamples,
+ const sp<MediaCodecBuffer> &buffer) {
+ (void)memory;
+ (void)secure;
+ (void)key;
+ (void)iv;
+ (void)mode;
+ (void)pattern;
+ (void)offset;
+ (void)subSamples;
+ (void)numSubSamples;
+ (void)buffer;
+ return -ENOSYS;
+ }
+ /**
* Request buffer rendering at specified time.
*
* @param timestampNs nanosecond timestamp for rendering time.
@@ -314,10 +369,20 @@
*/
virtual void getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) = 0;
+ /**
+ * Convert binder IMemory to drm SharedBuffer
+ *
+ * \param memory IMemory object to store encrypted content.
+ * \param heapSeqNum Heap sequence number from ICrypto; -1 if N/A
+ * \param buf SharedBuffer structure to fill.
+ */
+ static void IMemoryToSharedBuffer(
+ const sp<IMemory> &memory,
+ int32_t heapSeqNum,
+ hardware::drm::V1_0::SharedBuffer *buf);
+
protected:
std::unique_ptr<CodecBase::BufferCallback> mCallback;
- sp<ICrypto> mCrypto;
- sp<IDescrambler> mDescrambler;
};
} // namespace android
diff --git a/media/libstagefright/include/media/stagefright/DataSource.h b/media/libstagefright/include/media/stagefright/DataSource.h
deleted file mode 100644
index 1f7a473..0000000
--- a/media/libstagefright/include/media/stagefright/DataSource.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef DATA_SOURCE_H_
-
-#define DATA_SOURCE_H_
-
-#include <sys/types.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/DataSourceBase.h>
-#include <media/IDataSource.h>
-#include <media/MediaExtractorPluginApi.h>
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-#include <utils/threads.h>
-#include <drm/DrmManagerClient.h>
-
-
-namespace android {
-
-class String8;
-
-class DataSource : public DataSourceBase, public virtual RefBase {
-public:
- DataSource() : mWrapper(NULL) {}
-
- // returns a pointer to IDataSource if it is wrapped.
- virtual sp<IDataSource> getIDataSource() const {
- return nullptr;
- }
-
- virtual String8 toString() {
- return String8("<unspecified>");
- }
-
- virtual status_t reconnectAtOffset(off64_t /*offset*/) {
- return ERROR_UNSUPPORTED;
- }
-
- ////////////////////////////////////////////////////////////////////////////
-
- // for DRM
- virtual sp<DecryptHandle> DrmInitialization(const char * /*mime*/ = NULL) {
- return NULL;
- }
-
- virtual String8 getUri() {
- return String8();
- }
-
- virtual bool getUri(char *uriString, size_t bufferSize) final {
- int ret = snprintf(uriString, bufferSize, "%s", getUri().c_str());
- return ret >= 0 && static_cast<size_t>(ret) < bufferSize;
- }
-
- virtual String8 getMIMEType() const {
- return String8("application/octet-stream");
- }
-
- CDataSource *wrap() {
- if (mWrapper) {
- return mWrapper;
- }
- mWrapper = new CDataSource();
- mWrapper->handle = this;
-
- mWrapper->readAt = [](void *handle, off64_t offset, void *data, size_t size) -> ssize_t {
- return ((DataSource*)handle)->readAt(offset, data, size);
- };
- mWrapper->getSize = [](void *handle, off64_t *size) -> status_t {
- return ((DataSource*)handle)->getSize(size);
- };
- mWrapper->flags = [](void *handle) -> uint32_t {
- return ((DataSource*)handle)->flags();
- };
- mWrapper->getUri = [](void *handle, char *uriString, size_t bufferSize) -> bool {
- return ((DataSource*)handle)->getUri(uriString, bufferSize);
- };
- return mWrapper;
- }
-
-protected:
- virtual ~DataSource() {
- delete mWrapper;
- }
-
-private:
- CDataSource *mWrapper;
- DataSource(const DataSource &);
- DataSource &operator=(const DataSource &);
-};
-
-} // namespace android
-
-#endif // DATA_SOURCE_H_
diff --git a/media/libstagefright/include/media/stagefright/DataSourceFactory.h b/media/libstagefright/include/media/stagefright/DataSourceFactory.h
deleted file mode 100644
index 2a1d491..0000000
--- a/media/libstagefright/include/media/stagefright/DataSourceFactory.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef DATA_SOURCE_FACTORY_H_
-
-#define DATA_SOURCE_FACTORY_H_
-
-#include <sys/types.h>
-#include <utils/RefBase.h>
-
-namespace android {
-
-struct MediaHTTPService;
-class String8;
-struct HTTPBase;
-
-class DataSourceFactory {
-public:
- static sp<DataSource> CreateFromURI(
- const sp<MediaHTTPService> &httpService,
- const char *uri,
- const KeyedVector<String8, String8> *headers = NULL,
- String8 *contentType = NULL,
- HTTPBase *httpSource = NULL);
-
- static sp<DataSource> CreateMediaHTTP(const sp<MediaHTTPService> &httpService);
- static sp<DataSource> CreateFromFd(int fd, int64_t offset, int64_t length);
-};
-
-} // namespace android
-
-#endif // DATA_SOURCE_FACTORY_H_
diff --git a/media/libstagefright/include/media/stagefright/FileSource.h b/media/libstagefright/include/media/stagefright/FileSource.h
deleted file mode 100644
index b610eef..0000000
--- a/media/libstagefright/include/media/stagefright/FileSource.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef FILE_SOURCE_H_
-
-#define FILE_SOURCE_H_
-
-#include <stdio.h>
-
-#include <media/stagefright/ClearFileSource.h>
-#include <media/stagefright/MediaErrors.h>
-#include <utils/threads.h>
-#include <drm/DrmManagerClient.h>
-
-namespace android {
-
-class FileSource : public ClearFileSource {
-public:
- FileSource(const char *filename);
- // FileSource takes ownership and will close the fd
- FileSource(int fd, int64_t offset, int64_t length);
-
- virtual ssize_t readAt(off64_t offset, void *data, size_t size);
-
- virtual sp<DecryptHandle> DrmInitialization(const char *mime);
-
- static bool requiresDrm(int fd, int64_t offset, int64_t length, const char *mime);
-
-protected:
- virtual ~FileSource();
-
-private:
- /*for DRM*/
- sp<DecryptHandle> mDecryptHandle;
- DrmManagerClient *mDrmManagerClient;
- int64_t mDrmBufOffset;
- ssize_t mDrmBufSize;
- unsigned char *mDrmBuf;
-
- ssize_t readAtDRM_l(off64_t offset, void *data, size_t size);
-
- FileSource(const FileSource &);
- FileSource &operator=(const FileSource &);
-};
-
-} // namespace android
-
-#endif // FILE_SOURCE_H_
-
diff --git a/media/libstagefright/include/media/stagefright/FoundationUtils.h b/media/libstagefright/include/media/stagefright/FoundationUtils.h
new file mode 100644
index 0000000..1548981
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/FoundationUtils.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+#ifndef FOUNDATION_UTILS_H_
+
+#define FOUNDATION_UTILS_H_
+
+#include <media/stagefright/foundation/AString.h>
+
+namespace android {
+
+AString MakeUserAgent();
+
+AString uriDebugString(const AString &uri, bool incognito = false);
+
+AString nameForFd(int fd);
+} // namespace android
+
+#endif // FOUNDATION_UTILS_H_
diff --git a/media/libstagefright/include/media/stagefright/FrameCaptureProcessor.h b/media/libstagefright/include/media/stagefright/FrameCaptureProcessor.h
new file mode 100644
index 0000000..66e5daa
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/FrameCaptureProcessor.h
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+#ifndef FRAME_CAPTURE_PROCESSOR_H_
+#define FRAME_CAPTURE_PROCESSOR_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/AHandler.h>
+
+namespace android {
+
+struct AMessage;
+class GraphicBuffer;
+class Rect;
+
+namespace renderengine {
+class RenderEngine;
+struct LayerSettings;
+}
+
+/*
+ * Process a decoded graphic buffer through RenderEngine to
+ * convert it to sRGB.
+ *
+ * This class is a singleton that holds one instance of RenderEngine
+ * and its event queue (on which the GL context runs). The RenderEngine
+ * is created upon the first getInstance().
+ */
+class FrameCaptureProcessor : public AHandler {
+
+public:
+
+ struct Layer : public RefBase {
+ virtual void getLayerSettings(
+ const Rect &sourceCrop, uint32_t textureName,
+ renderengine::LayerSettings *layerSettings) = 0;
+ };
+
+ static sp<FrameCaptureProcessor> getInstance();
+
+ status_t capture(
+ const sp<Layer> &layer,
+ const Rect &sourceCrop, const sp<GraphicBuffer> &outBuffer);
+
+protected:
+ virtual ~FrameCaptureProcessor();
+ void onMessageReceived(const sp<AMessage> &msg);
+
+private:
+ FrameCaptureProcessor();
+
+ enum {
+ kWhatCreate,
+ kWhatCapture,
+ };
+
+ static Mutex sLock;
+ static sp<FrameCaptureProcessor> sInstance GUARDED_BY(sLock);
+
+ constexpr static float sDefaultMaxLumiance = 500.0f;
+
+ status_t mInitStatus;
+ sp<ALooper> mLooper;
+ std::unique_ptr<renderengine::RenderEngine> mRE;
+ uint32_t mTextureName;
+
+ static status_t PostAndAwaitResponse(
+ const sp<AMessage> &msg, sp<AMessage> *response);
+ static void PostReplyWithError(
+ const sp<AReplyToken> &replyID, status_t err);
+
+ status_t initCheck() { return mInitStatus; }
+ void createRenderEngine();
+
+ // message handlers
+ status_t onCreate();
+ status_t onCapture(const sp<Layer> &layer,
+ const Rect &sourceCrop, const sp<GraphicBuffer> &outBuffer);
+
+ DISALLOW_EVIL_CONSTRUCTORS(FrameCaptureProcessor);
+};
+
+} // namespace android
+
+#endif // FRAME_CAPTURE_PROCESSOR_H_
diff --git a/media/libstagefright/include/media/stagefright/InterfaceUtils.h b/media/libstagefright/include/media/stagefright/InterfaceUtils.h
index b83a958..92ef543 100644
--- a/media/libstagefright/include/media/stagefright/InterfaceUtils.h
+++ b/media/libstagefright/include/media/stagefright/InterfaceUtils.h
@@ -19,8 +19,8 @@
#include <utils/RefBase.h>
#include <media/stagefright/RemoteMediaExtractor.h>
-#include <media/MediaSource.h>
-#include <media/IMediaExtractor.h>
+#include <media/stagefright/MediaSource.h>
+#include <android/IMediaExtractor.h>
#include <media/IMediaSource.h>
namespace android {
diff --git a/media/libstagefright/include/media/stagefright/JPEGSource.h b/media/libstagefright/include/media/stagefright/JPEGSource.h
index 8ab3d11..53cb344 100644
--- a/media/libstagefright/include/media/stagefright/JPEGSource.h
+++ b/media/libstagefright/include/media/stagefright/JPEGSource.h
@@ -18,7 +18,7 @@
#define JPEG_SOURCE_H_
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
namespace android {
diff --git a/media/libstagefright/include/media/stagefright/MPEG4Writer.h b/media/libstagefright/include/media/stagefright/MPEG4Writer.h
index 6f19023..34a7d55 100644
--- a/media/libstagefright/include/media/stagefright/MPEG4Writer.h
+++ b/media/libstagefright/include/media/stagefright/MPEG4Writer.h
@@ -23,8 +23,10 @@
#include <media/stagefright/MediaWriter.h>
#include <utils/List.h>
#include <utils/threads.h>
+#include <map>
#include <media/stagefright/foundation/AHandlerReflector.h>
#include <media/stagefright/foundation/ALooper.h>
+#include <mutex>
namespace android {
@@ -58,6 +60,10 @@
void writeFourcc(const char *fourcc);
void write(const void *data, size_t size);
inline size_t write(const void *ptr, size_t size, size_t nmemb);
+ // Write to file system by calling ::write() or post error message to looper on failure.
+ void writeOrPostError(int fd, const void *buf, size_t count);
+ // Seek in the file by calling ::lseek64() or post error message to looper on failure.
+ void seekOrPostError(int fd, off64_t offset, int whence);
void endBox();
uint32_t interleaveDuration() const { return mInterleaveDurationUs; }
status_t setInterleaveDuration(uint32_t duration);
@@ -80,6 +86,8 @@
enum {
kWhatSwitch = 'swch',
+ kWhatHandleIOError = 'ioer',
+ kWhatHandleFallocateError = 'faer'
};
int mFd;
@@ -88,14 +96,15 @@
status_t mInitCheck;
bool mIsRealTimeRecording;
bool mUse4ByteNalLength;
- bool mUse32BitOffset;
bool mIsFileSizeLimitExplicitlyRequested;
bool mPaused;
bool mStarted; // Writer thread + track threads started successfully
bool mWriterThreadStarted; // Only writer thread started successfully
bool mSendNotify;
off64_t mOffset;
- off_t mMdatOffset;
+ off64_t mPreAllocateFileEndOffset; //End of file offset during preallocation.
+ off64_t mMdatOffset;
+ off64_t mMdatEndOffset; // End offset of mdat atom.
uint8_t *mInMemoryCache;
off64_t mInMemoryCacheOffset;
off64_t mInMemoryCacheSize;
@@ -106,17 +115,24 @@
uint32_t mInterleaveDurationUs;
int32_t mTimeScale;
int64_t mStartTimestampUs;
- int32_t mStartTimeOffsetBFramesUs; // Start time offset when B Frames are present
+ int32_t mStartTimeOffsetBFramesUs; // Longest offset needed for reordering tracks with B Frames
int mLatitudex10000;
int mLongitudex10000;
bool mAreGeoTagsAvailable;
int32_t mStartTimeOffsetMs;
bool mSwitchPending;
+ bool mWriteSeekErr;
+ bool mFallocateErr;
+ bool mPreAllocationEnabled;
sp<ALooper> mLooper;
sp<AHandlerReflector<MPEG4Writer> > mReflector;
Mutex mLock;
+ std::mutex mResetMutex;
+ std::mutex mFallocMutex;
+ bool mPreAllocFirstTime; // Pre-allocate space for file and track headers only once per file.
+ uint64_t mPrevAllTracksTotalMetaDataSizeEstimate;
List<Track *> mTracks;
@@ -200,19 +216,23 @@
} ItemProperty;
bool mHasFileLevelMeta;
+ uint64_t mFileLevelMetaDataSize;
bool mHasMoovBox;
uint32_t mPrimaryItemId;
uint32_t mAssociationEntryCount;
uint32_t mNumGrids;
+ uint16_t mNextItemId;
bool mHasRefs;
- Vector<ItemInfo> mItems;
+ std::map<uint32_t, ItemInfo> mItems;
Vector<ItemProperty> mProperties;
// Writer thread handling
status_t startWriterThread();
- void stopWriterThread();
+ status_t stopWriterThread();
static void *ThreadWrapper(void *me);
void threadFunc();
+ void setupAndStartLooper();
+ void stopAndReleaseLooper();
// Buffer a single chunk to be written out later.
void bufferChunk(const Chunk& chunk);
@@ -259,11 +279,11 @@
void addLengthPrefixedSample_l(MediaBuffer *buffer);
void addMultipleLengthPrefixedSamples_l(MediaBuffer *buffer);
uint16_t addProperty_l(const ItemProperty &);
+ status_t reserveItemId_l(size_t numItems, uint16_t *itemIdBase);
uint16_t addItem_l(const ItemInfo &);
void addRefs_l(uint16_t itemId, const ItemRefs &);
bool exceedsFileSizeLimit();
- bool use32BitFileOffset() const;
bool exceedsFileDurationLimit();
bool approachingFileSizeLimit();
bool isFileStreamable() const;
@@ -284,6 +304,16 @@
void writeIlst();
void writeMoovLevelMetaBox();
+ /*
+ * Allocate space needed for MOOV atom in advance and maintain just enough before write
+ * of any data. Stop writing and save MOOV atom if there was any error.
+ */
+ bool preAllocate(uint64_t wantSize);
+ /*
+ * Truncate file as per the size used for meta data and actual data in a session.
+ */
+ bool truncatePreAllocation();
+
// HEIF writing
void writeIlocBox();
void writeInfeBox(uint16_t itemId, const char *type, uint32_t flags);
diff --git a/media/libstagefright/include/media/stagefright/MediaAdapter.h b/media/libstagefright/include/media/stagefright/MediaAdapter.h
index 589c827..177a9e9 100644
--- a/media/libstagefright/include/media/stagefright/MediaAdapter.h
+++ b/media/libstagefright/include/media/stagefright/MediaAdapter.h
@@ -17,7 +17,7 @@
#ifndef MEDIA_ADAPTER_H
#define MEDIA_ADAPTER_H
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MetaData.h>
diff --git a/media/libstagefright/include/media/stagefright/MediaBuffer.h b/media/libstagefright/include/media/stagefright/MediaBuffer.h
index ace63ae..9145b63 100644
--- a/media/libstagefright/include/media/stagefright/MediaBuffer.h
+++ b/media/libstagefright/include/media/stagefright/MediaBuffer.h
@@ -48,7 +48,11 @@
explicit MediaBuffer(const sp<ABuffer> &buffer);
#ifndef NO_IMEMORY
MediaBuffer(const sp<IMemory> &mem) :
- MediaBuffer((uint8_t *)mem->pointer() + sizeof(SharedControl), mem->size()) {
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
+ MediaBuffer((uint8_t *)mem->unsecurePointer() + sizeof(SharedControl), mem->size()) {
// delegate and override mMemory
mMemory = mem;
}
@@ -94,9 +98,13 @@
virtual int remoteRefcount() const {
#ifndef NO_IMEMORY
- if (mMemory.get() == nullptr || mMemory->pointer() == nullptr) return 0;
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
+ if (mMemory.get() == nullptr || mMemory->unsecurePointer() == nullptr) return 0;
int32_t remoteRefcount =
- reinterpret_cast<SharedControl *>(mMemory->pointer())->getRemoteRefcount();
+ reinterpret_cast<SharedControl *>(mMemory->unsecurePointer())->getRemoteRefcount();
// Sanity check so that remoteRefCount() is non-negative.
return remoteRefcount >= 0 ? remoteRefcount : 0; // do not allow corrupted data.
#else
@@ -107,8 +115,12 @@
// returns old value
int addRemoteRefcount(int32_t value) {
#ifndef NO_IMEMORY
- if (mMemory.get() == nullptr || mMemory->pointer() == nullptr) return 0;
- return reinterpret_cast<SharedControl *>(mMemory->pointer())->addRemoteRefcount(value);
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
+ if (mMemory.get() == nullptr || mMemory->unsecurePointer() == nullptr) return 0;
+ return reinterpret_cast<SharedControl *>(mMemory->unsecurePointer())->addRemoteRefcount(value);
#else
(void) value;
return 0;
@@ -121,8 +133,12 @@
static bool isDeadObject(const sp<IMemory> &memory) {
#ifndef NO_IMEMORY
- if (memory.get() == nullptr || memory->pointer() == nullptr) return false;
- return reinterpret_cast<SharedControl *>(memory->pointer())->isDeadObject();
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
+ if (memory.get() == nullptr || memory->unsecurePointer() == nullptr) return false;
+ return reinterpret_cast<SharedControl *>(memory->unsecurePointer())->isDeadObject();
#else
(void) memory;
return false;
@@ -220,7 +236,11 @@
inline SharedControl *getSharedControl() const {
#ifndef NO_IMEMORY
- return reinterpret_cast<SharedControl *>(mMemory->pointer());
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
+ return reinterpret_cast<SharedControl *>(mMemory->unsecurePointer());
#else
return nullptr;
#endif
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index cd30347..022c48e 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -24,12 +24,23 @@
#include <gui/IGraphicBufferProducer.h>
#include <media/hardware/CryptoAPI.h>
#include <media/MediaCodecInfo.h>
-#include <media/MediaResource.h>
-#include <media/MediaAnalyticsItem.h>
+#include <media/MediaMetrics.h>
#include <media/stagefright/foundation/AHandler.h>
#include <media/stagefright/FrameRenderTracker.h>
#include <utils/Vector.h>
+class C2Buffer;
+class C2GraphicBlock;
+class C2LinearBlock;
+
+namespace aidl {
+namespace android {
+namespace media {
+class MediaResourceParcel;
+} // media
+} // android
+} // aidl
+
namespace android {
struct ABuffer;
@@ -43,8 +54,6 @@
struct ICrypto;
class MediaCodecBuffer;
class IMemory;
-class IResourceManagerClient;
-class IResourceManagerService;
struct PersistentSurface;
class SoftwareRenderer;
class Surface;
@@ -54,11 +63,14 @@
namespace V1_0 {
struct IDescrambler;
}}}}
+
using hardware::cas::native::V1_0::IDescrambler;
+using aidl::android::media::MediaResourceParcel;
struct MediaCodec : public AHandler {
enum ConfigureFlags {
- CONFIGURE_FLAG_ENCODE = 1,
+ CONFIGURE_FLAG_ENCODE = 1,
+ CONFIGURE_FLAG_USE_BLOCK_MODEL = 2,
};
enum BufferFlags {
@@ -150,6 +162,38 @@
uint32_t flags,
AString *errorDetailMsg = NULL);
+ status_t queueBuffer(
+ size_t index,
+ const std::shared_ptr<C2Buffer> &buffer,
+ int64_t presentationTimeUs,
+ uint32_t flags,
+ const sp<AMessage> &tunings,
+ AString *errorDetailMsg = NULL);
+
+ status_t queueEncryptedBuffer(
+ size_t index,
+ const sp<hardware::HidlMemory> &memory,
+ size_t offset,
+ const CryptoPlugin::SubSample *subSamples,
+ size_t numSubSamples,
+ const uint8_t key[16],
+ const uint8_t iv[16],
+ CryptoPlugin::Mode mode,
+ const CryptoPlugin::Pattern &pattern,
+ int64_t presentationTimeUs,
+ uint32_t flags,
+ const sp<AMessage> &tunings,
+ AString *errorDetailMsg = NULL);
+
+ std::shared_ptr<C2Buffer> decrypt(
+ const std::shared_ptr<C2Buffer> &buffer,
+ const CryptoPlugin::SubSample *subSamples,
+ size_t numSubSamples,
+ const uint8_t key[16],
+ const uint8_t iv[16],
+ CryptoPlugin::Mode mode,
+ const CryptoPlugin::Pattern &pattern);
+
status_t dequeueInputBuffer(size_t *index, int64_t timeoutUs = 0ll);
status_t dequeueOutputBuffer(
@@ -189,7 +233,7 @@
status_t getCodecInfo(sp<MediaCodecInfo> *codecInfo) const;
- status_t getMetrics(MediaAnalyticsItem * &reply);
+ status_t getMetrics(mediametrics_handle_t &reply);
status_t setParameters(const sp<AMessage> ¶ms);
@@ -199,6 +243,29 @@
static size_t CreateFramesRenderedMessage(
const std::list<FrameRenderTracker::Info> &done, sp<AMessage> &msg);
+ static status_t CanFetchLinearBlock(
+ const std::vector<std::string> &names, bool *isCompatible);
+
+ static std::shared_ptr<C2LinearBlock> FetchLinearBlock(
+ size_t capacity, const std::vector<std::string> &names);
+
+ static status_t CanFetchGraphicBlock(
+ const std::vector<std::string> &names, bool *isCompatible);
+
+ static std::shared_ptr<C2GraphicBlock> FetchGraphicBlock(
+ int32_t width,
+ int32_t height,
+ int32_t format,
+ uint64_t usage,
+ const std::vector<std::string> &names);
+
+ template <typename T>
+ struct WrapperObject : public RefBase {
+ WrapperObject(const T& v) : value(v) {}
+ WrapperObject(T&& v) : value(std::move(v)) {}
+ T value;
+ };
+
protected:
virtual ~MediaCodec();
virtual void onMessageReceived(const sp<AMessage> &msg);
@@ -275,6 +342,7 @@
kFlagIsAsync = 1024,
kFlagIsComponentAllocated = 2048,
kFlagPushBlankBuffersOnShutdown = 4096,
+ kFlagUseBlockModel = 8192,
};
struct BufferInfo {
@@ -284,34 +352,7 @@
bool mOwnedByClient;
};
- struct ResourceManagerServiceProxy : public IBinder::DeathRecipient {
- ResourceManagerServiceProxy(pid_t pid, uid_t uid);
- ~ResourceManagerServiceProxy();
-
- void init();
-
- // implements DeathRecipient
- virtual void binderDied(const wp<IBinder>& /*who*/);
-
- void addResource(
- int64_t clientId,
- const sp<IResourceManagerClient> &client,
- const Vector<MediaResource> &resources);
-
- void removeResource(
- int64_t clientId,
- const Vector<MediaResource> &resources);
-
- void removeClient(int64_t clientId);
-
- bool reclaimResource(const Vector<MediaResource> &resources);
-
- private:
- Mutex mLock;
- sp<IResourceManagerService> mService;
- pid_t mPid;
- uid_t mUid;
- };
+ struct ResourceManagerServiceProxy;
State mState;
uid_t mUid;
@@ -328,19 +369,19 @@
sp<Surface> mSurface;
SoftwareRenderer *mSoftRenderer;
- MediaAnalyticsItem *mAnalyticsItem;
- void initAnalyticsItem();
- void updateAnalyticsItem();
- void flushAnalyticsItem();
- void updateEphemeralAnalytics(MediaAnalyticsItem *item);
+ mediametrics_handle_t mMetricsHandle;
+ void initMediametrics();
+ void updateMediametrics();
+ void flushMediametrics();
+ void updateEphemeralMediametrics(mediametrics_handle_t item);
+ void updateLowLatency(const sp<AMessage> &msg);
sp<AMessage> mOutputFormat;
sp<AMessage> mInputFormat;
sp<AMessage> mCallback;
sp<AMessage> mOnFrameRenderedNotification;
- sp<IResourceManagerClient> mResourceManagerClient;
- sp<ResourceManagerServiceProxy> mResourceManagerService;
+ sp<ResourceManagerServiceProxy> mResourceManagerProxy;
bool mIsVideo;
int32_t mVideoWidth;
@@ -434,8 +475,6 @@
bool isExecuting() const;
uint64_t getGraphicBufferSize();
- void addResource(MediaResource::Type type, MediaResource::SubType subtype, uint64_t value);
- void removeResource(MediaResource::Type type, MediaResource::SubType subtype, uint64_t value);
void requestCpuBoostIfNeeded();
bool hasPendingBuffer(int portIndex);
@@ -463,6 +502,12 @@
std::deque<BufferFlightTiming_t> mBuffersInFlight;
Mutex mLatencyLock;
int64_t mLatencyUnknown; // buffers for which we couldn't calculate latency
+ int64_t mNumLowLatencyEnables; // how many times low latency mode is enabled
+ int64_t mNumLowLatencyDisables; // how many times low latency mode is disabled
+ bool mIsLowLatencyModeOn; // is low latency mode on currently
+ int64_t mIndexOfFirstFrameWhenLowLatencyOn; // index of the first frame queued
+ // when low latency is on
+ int64_t mInputBufferCounter; // number of input buffers queued since last reset/flush
sp<BatteryChecker> mBatteryChecker;
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
index 50d7724..bfdc9e7 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
@@ -510,22 +510,24 @@
constexpr int32_t DolbyVisionProfileDvheStn = 0x20;
constexpr int32_t DolbyVisionProfileDvheDth = 0x40;
constexpr int32_t DolbyVisionProfileDvheDtb = 0x80;
-constexpr int32_t DolbyVisionProfileDvheSt = 0x100;
-constexpr int32_t DolbyVisionProfileDvavSe = 0x200;
+constexpr int32_t DolbyVisionProfileDvheSt = 0x100;
+constexpr int32_t DolbyVisionProfileDvavSe = 0x200;
+constexpr int32_t DolbyVisionProfileDvav110 = 0x400;
inline static const char *asString_DolbyVisionProfile(int32_t i, const char *def = "??") {
switch (i) {
- case DolbyVisionProfileDvavPer: return "DvavPer";
- case DolbyVisionProfileDvavPen: return "DvavPen";
- case DolbyVisionProfileDvheDer: return "DvheDer";
- case DolbyVisionProfileDvheDen: return "DvheDen";
- case DolbyVisionProfileDvheDtr: return "DvheDtr";
- case DolbyVisionProfileDvheStn: return "DvheStn";
- case DolbyVisionProfileDvheDth: return "DvheDth";
- case DolbyVisionProfileDvheDtb: return "DvheDtb";
- case DolbyVisionProfileDvheSt: return "DvheSt";
- case DolbyVisionProfileDvavSe: return "DvavSe";
- default: return def;
+ case DolbyVisionProfileDvavPer: return "DvavPer";
+ case DolbyVisionProfileDvavPen: return "DvavPen";
+ case DolbyVisionProfileDvheDer: return "DvheDer";
+ case DolbyVisionProfileDvheDen: return "DvheDen";
+ case DolbyVisionProfileDvheDtr: return "DvheDtr";
+ case DolbyVisionProfileDvheStn: return "DvheStn";
+ case DolbyVisionProfileDvheDth: return "DvheDth";
+ case DolbyVisionProfileDvheDtb: return "DvheDtb";
+ case DolbyVisionProfileDvheSt: return "DvheSt";
+ case DolbyVisionProfileDvavSe: return "DvavSe";
+ case DolbyVisionProfileDvav110: return "Dav110";
+ default: return def;
}
}
@@ -731,10 +733,12 @@
constexpr int32_t COLOR_TRANSFER_SDR_VIDEO = 3;
constexpr int32_t COLOR_TRANSFER_ST2084 = 6;
+constexpr char KEY_AAC_DRC_ALBUM_MODE[] = "aac-drc-album-mode";
constexpr char KEY_AAC_DRC_ATTENUATION_FACTOR[] = "aac-drc-cut-level";
constexpr char KEY_AAC_DRC_BOOST_FACTOR[] = "aac-drc-boost-level";
constexpr char KEY_AAC_DRC_EFFECT_TYPE[] = "aac-drc-effect-type";
constexpr char KEY_AAC_DRC_HEAVY_COMPRESSION[] = "aac-drc-heavy-compression";
+constexpr char KEY_AAC_DRC_OUTPUT_LOUDNESS[] = "aac-drc-output-loudness";
constexpr char KEY_AAC_DRC_TARGET_REFERENCE_LEVEL[] = "aac-target-ref-level";
constexpr char KEY_AAC_ENCODED_TARGET_LEVEL[] = "aac-encoded-target-level";
constexpr char KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT[] = "aac-max-output-channel_count";
@@ -774,6 +778,7 @@
constexpr char KEY_LANGUAGE[] = "language";
constexpr char KEY_LATENCY[] = "latency";
constexpr char KEY_LEVEL[] = "level";
+constexpr char KEY_LOW_LATENCY[] = "low-latency";
constexpr char KEY_MAX_B_FRAMES[] = "max-bframes";
constexpr char KEY_MAX_BIT_RATE[] = "max-bitrate";
constexpr char KEY_MAX_FPS_TO_ENCODER[] = "max-fps-to-encoder";
@@ -827,6 +832,7 @@
constexpr int32_t BUFFER_FLAG_PARTIAL_FRAME = 8;
constexpr int32_t BUFFER_FLAG_SYNC_FRAME = 1;
constexpr int32_t CONFIGURE_FLAG_ENCODE = 1;
+constexpr int32_t CONFIGURE_FLAG_USE_BLOCK_MODEL = 2;
constexpr int32_t CRYPTO_MODE_AES_CBC = 2;
constexpr int32_t CRYPTO_MODE_AES_CTR = 1;
constexpr int32_t CRYPTO_MODE_UNENCRYPTED = 0;
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecList.h b/media/libstagefright/include/media/stagefright/MediaCodecList.h
index e44b0a4..e681d25 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecList.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecList.h
@@ -83,6 +83,7 @@
};
static sp<BinderDeathObserver> sBinderDeathObserver;
+ static sp<IBinder> sMediaPlayer;
static sp<IMediaCodecList> sCodecList;
static sp<IMediaCodecList> sRemoteList;
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecSource.h b/media/libstagefright/include/media/stagefright/MediaCodecSource.h
index a68cc19..2f98af1 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecSource.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecSource.h
@@ -17,7 +17,7 @@
#ifndef MediaCodecSource_H_
#define MediaCodecSource_H_
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/foundation/AHandlerReflector.h>
#include <media/stagefright/foundation/Mutexed.h>
diff --git a/media/libstagefright/include/media/stagefright/MediaErrors.h b/media/libstagefright/include/media/stagefright/MediaErrors.h
index 09639e2..5418f10 100644
--- a/media/libstagefright/include/media/stagefright/MediaErrors.h
+++ b/media/libstagefright/include/media/stagefright/MediaErrors.h
@@ -99,7 +99,14 @@
ERROR_CAS_DEVICE_REVOKED = CAS_ERROR_BASE - 9,
ERROR_CAS_RESOURCE_BUSY = CAS_ERROR_BASE - 10,
ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION = CAS_ERROR_BASE - 11,
- ERROR_CAS_LAST_USED_ERRORCODE = CAS_ERROR_BASE - 11,
+ ERROR_CAS_NEED_ACTIVATION = CAS_ERROR_BASE - 12,
+ ERROR_CAS_NEED_PAIRING = CAS_ERROR_BASE - 13,
+ ERROR_CAS_NO_CARD = CAS_ERROR_BASE - 14,
+ ERROR_CAS_CARD_MUTE = CAS_ERROR_BASE - 15,
+ ERROR_CAS_CARD_INVALID = CAS_ERROR_BASE - 16,
+ ERROR_CAS_BLACKOUT = CAS_ERROR_BASE - 17,
+ ERROR_CAS_REBOOTING = CAS_ERROR_BASE - 18,
+ ERROR_CAS_LAST_USED_ERRORCODE = CAS_ERROR_BASE - 18,
ERROR_CAS_VENDOR_MAX = CAS_ERROR_BASE - 500,
ERROR_CAS_VENDOR_MIN = CAS_ERROR_BASE - 999,
diff --git a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
index 2ab98e1..745e342 100644
--- a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
+++ b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
@@ -22,7 +22,7 @@
#include <unordered_set>
#include <android/dlext.h>
-#include <media/IMediaExtractor.h>
+#include <android/IMediaExtractor.h>
namespace android {
@@ -36,7 +36,7 @@
static sp<IMediaExtractor> CreateFromService(
const sp<DataSource> &source, const char *mime = NULL);
static status_t dump(int fd, const Vector<String16>& args);
- static std::unordered_set<std::string> getSupportedTypes();
+ static std::vector<std::string> getSupportedTypes();
static void LoadExtractors();
private:
diff --git a/media/libstagefright/include/media/stagefright/MediaFilter.h b/media/libstagefright/include/media/stagefright/MediaFilter.h
index a28c49d..1255e0f 100644
--- a/media/libstagefright/include/media/stagefright/MediaFilter.h
+++ b/media/libstagefright/include/media/stagefright/MediaFilter.h
@@ -21,9 +21,7 @@
namespace android {
-class ACodecBufferChannel;
struct GraphicBufferListener;
-class MemoryDealer;
struct SimpleFilter;
struct MediaFilter : public CodecBase {
@@ -65,6 +63,8 @@
sp<MediaCodecBuffer> mData;
};
+ class BufferChannel;
+
enum State {
UNINITIALIZED,
INITIALIZED,
@@ -104,7 +104,6 @@
sp<AMessage> mInputFormat;
sp<AMessage> mOutputFormat;
- sp<MemoryDealer> mDealer[2];
Vector<BufferInfo> mBuffers[2];
Vector<BufferInfo*> mAvailableInputBuffers;
Vector<BufferInfo*> mAvailableOutputBuffers;
@@ -113,15 +112,15 @@
sp<SimpleFilter> mFilter;
sp<GraphicBufferListener> mGraphicBufferListener;
- std::shared_ptr<ACodecBufferChannel> mBufferChannel;
+ std::shared_ptr<BufferChannel> mBufferChannel;
// helper functions
void signalProcessBuffers();
void signalError(status_t error);
status_t allocateBuffersOnPort(OMX_U32 portIndex);
- BufferInfo *findBufferByID(
- uint32_t portIndex, uint32_t bufferID,
+ BufferInfo *findBuffer(
+ uint32_t portIndex, const sp<MediaCodecBuffer> &buffer,
ssize_t *index = NULL);
void postFillThisBuffer(BufferInfo *info);
void postDrainThisBuffer(BufferInfo *info);
diff --git a/media/libstagefright/include/media/stagefright/MediaHTTP.h b/media/libstagefright/include/media/stagefright/MediaHTTP.h
deleted file mode 100644
index acaa6c4..0000000
--- a/media/libstagefright/include/media/stagefright/MediaHTTP.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef MEDIA_HTTP_H_
-
-#define MEDIA_HTTP_H_
-
-#include <media/stagefright/foundation/AString.h>
-#include <media/stagefright/ClearMediaHTTP.h>
-
-namespace android {
-
-struct MediaHTTPConnection;
-
-struct MediaHTTP : public ClearMediaHTTP {
- MediaHTTP(const sp<MediaHTTPConnection> &conn);
-
-protected:
- virtual ~MediaHTTP();
-
- virtual sp<DecryptHandle> DrmInitialization(const char* mime);
-
-private:
- sp<DecryptHandle> mDecryptHandle;
- DrmManagerClient *mDrmManagerClient;
-
- void clearDRMState_l();
-
- DISALLOW_EVIL_CONSTRUCTORS(MediaHTTP);
-};
-
-} // namespace android
-
-#endif // MEDIA_HTTP_H_
diff --git a/media/libstagefright/include/media/stagefright/MediaMuxer.h b/media/libstagefright/include/media/stagefright/MediaMuxer.h
index 69d6cde..7c75f74 100644
--- a/media/libstagefright/include/media/stagefright/MediaMuxer.h
+++ b/media/libstagefright/include/media/stagefright/MediaMuxer.h
@@ -22,7 +22,7 @@
#include <utils/Vector.h>
#include <utils/threads.h>
-#include "foundation/ABase.h"
+#include "media/stagefright/foundation/ABase.h"
namespace android {
@@ -117,21 +117,24 @@
status_t writeSampleData(const sp<ABuffer> &buffer, size_t trackIndex,
int64_t timeUs, uint32_t flags) ;
+ void notify(int msg, int ext1, int ext2);
+
private:
const OutputFormat mFormat;
sp<MediaWriter> mWriter;
Vector< sp<MediaAdapter> > mTrackList; // Each track has its MediaAdapter.
sp<MetaData> mFileMeta; // Metadata for the whole file.
-
Mutex mMuxerLock;
enum State {
UNINITIALIZED,
INITIALIZED,
STARTED,
- STOPPED
+ STOPPED,
+ ERROR
};
State mState;
+ status_t mError;
DISALLOW_EVIL_CONSTRUCTORS(MediaMuxer);
};
diff --git a/media/libstagefright/include/media/stagefright/MediaWriter.h b/media/libstagefright/include/media/stagefright/MediaWriter.h
index 972ae1d..08e54b3 100644
--- a/media/libstagefright/include/media/stagefright/MediaWriter.h
+++ b/media/libstagefright/include/media/stagefright/MediaWriter.h
@@ -19,8 +19,9 @@
#define MEDIA_WRITER_H_
#include <utils/RefBase.h>
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/IMediaRecorderClient.h>
+#include <media/stagefright/MediaMuxer.h>
namespace android {
@@ -36,7 +37,7 @@
virtual status_t stop() = 0;
virtual status_t pause() = 0;
virtual status_t setCaptureRate(float /* captureFps */) {
- ALOGW("setCaptureRate unsupported");
+ ALOG(LOG_WARN, "MediaWriter", "setCaptureRate unsupported");
return ERROR_UNSUPPORTED;
}
@@ -45,6 +46,7 @@
virtual void setListener(const sp<IMediaRecorderClient>& listener) {
mListener = listener;
}
+ virtual void setMuxerListener(const wp<MediaMuxer>& muxer) { mMuxer = muxer; }
virtual status_t dump(int /*fd*/, const Vector<String16>& /*args*/) {
return OK;
@@ -59,11 +61,17 @@
int64_t mMaxFileSizeLimitBytes;
int64_t mMaxFileDurationLimitUs;
sp<IMediaRecorderClient> mListener;
+ wp<MediaMuxer> mMuxer;
void notify(int msg, int ext1, int ext2) {
- if (mListener != NULL) {
+ ALOG(LOG_VERBOSE, "MediaWriter", "notify msg:%d, ext1:%d, ext2:%d", msg, ext1, ext2);
+ if (mListener != nullptr) {
mListener->notify(msg, ext1, ext2);
}
+ sp<MediaMuxer> muxer = mMuxer.promote();
+ if (muxer != nullptr) {
+ muxer->notify(msg, ext1, ext2);
+ }
}
private:
MediaWriter(const MediaWriter &);
diff --git a/media/libstagefright/include/media/stagefright/MetaData.h b/media/libstagefright/include/media/stagefright/MetaData.h
index f625358..68adf346 100644
--- a/media/libstagefright/include/media/stagefright/MetaData.h
+++ b/media/libstagefright/include/media/stagefright/MetaData.h
@@ -41,7 +41,9 @@
friend class BnMediaSource;
friend class BpMediaSource;
friend class BpMediaExtractor;
+#ifndef __ANDROID_VNDK__
static sp<MetaData> createFromParcel(const Parcel &parcel);
+#endif
};
} // namespace android
diff --git a/media/libstagefright/include/media/stagefright/MetaDataBase.h b/media/libstagefright/include/media/stagefright/MetaDataBase.h
index 8dc2dd5..3b701f6 100644
--- a/media/libstagefright/include/media/stagefright/MetaDataBase.h
+++ b/media/libstagefright/include/media/stagefright/MetaDataBase.h
@@ -59,6 +59,7 @@
kKeyAACProfile = 'aacp', // int32_t
kKeyAVCC = 'avcc', // raw data
kKeyHVCC = 'hvcc', // raw data
+ kKeyDVCC = 'dvcc', // raw data
kKeyAV1C = 'av1c', // raw data
kKeyThumbnailHVCC = 'thvc', // raw data
kKeyD263 = 'd263', // raw data
@@ -69,6 +70,7 @@
kKeyIsSyncFrame = 'sync', // int32_t (bool)
kKeyIsCodecConfig = 'conf', // int32_t (bool)
kKeyIsMuxerData = 'muxd', // int32_t (bool)
+ kKeyIsEndOfStream = 'feos', // int32_t (bool)
kKeyTime = 'time', // int64_t (usecs)
kKeyDecodingTime = 'decT', // int64_t (decoding timestamp in usecs)
kKeyNTPTime = 'ntpT', // uint64_t (ntp-timestamp)
@@ -112,8 +114,6 @@
kKeyVideoProfile = 'vprf', // int32_t
kKeyVideoLevel = 'vlev', // int32_t
- // Set this key to enable authoring files in 64-bit offset
- kKey64BitFileOffset = 'fobt', // int32_t (bool)
kKey2ByteNalLength = '2NAL', // int32_t (bool)
// Identify the file output format for authoring
@@ -238,6 +238,9 @@
kKeyOpaqueCSD2 = 'csd2',
kKeyHapticChannelCount = 'hapC',
+
+ // Treat empty track as malformed for MediaRecorder.
+ kKeyEmptyTrackMalFormed = 'nemt', // bool (int32_t)
};
enum {
@@ -245,6 +248,7 @@
kTypeAVCC = 'avcc',
kTypeHVCC = 'hvcc',
kTypeAV1C = 'av1c',
+ kTypeDVCC = 'dvcc',
kTypeD263 = 'd263',
};
@@ -319,8 +323,10 @@
struct Rect;
struct MetaDataInternal;
MetaDataInternal *mInternalData;
+#ifndef __ANDROID_VNDK__
status_t writeToParcel(Parcel &parcel);
status_t updateFromParcel(const Parcel &parcel);
+#endif
};
} // namespace android
diff --git a/media/libstagefright/include/media/stagefright/NdkUtils.h b/media/libstagefright/include/media/stagefright/NdkUtils.h
deleted file mode 100644
index a68884a..0000000
--- a/media/libstagefright/include/media/stagefright/NdkUtils.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NDK_UTILS_H_
-
-#define NDK_UTILS_H_
-
-#include <media/stagefright/MetaData.h>
-#include <media/NdkWrapper.h>
-
-namespace android {
-
-sp<MetaData> convertMediaFormatWrapperToMetaData(
- const sp<AMediaFormatWrapper> &fmt);
-
-} // namespace android
-
-#endif // NDK_UTILS_H_
diff --git a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
index 4307110..227cead 100644
--- a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
@@ -21,8 +21,8 @@
#include <media/mediaplayer.h>
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/foundation/AudioPresentationInfo.h>
-#include <media/IMediaExtractor.h>
-#include <media/MediaSource.h>
+#include <android/IMediaExtractor.h>
+#include <media/stagefright/MediaSource.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
diff --git a/media/libstagefright/include/media/stagefright/PersistentSurface.h b/media/libstagefright/include/media/stagefright/PersistentSurface.h
index 49b36c9..f4943c3 100644
--- a/media/libstagefright/include/media/stagefright/PersistentSurface.h
+++ b/media/libstagefright/include/media/stagefright/PersistentSurface.h
@@ -18,31 +18,21 @@
#define PERSISTENT_SURFACE_H_
-#include <android/IGraphicBufferSource.h>
#include <binder/Parcel.h>
#include <hidl/HidlSupport.h>
#include <hidl/HybridInterface.h>
#include <gui/IGraphicBufferProducer.h>
#include <media/stagefright/foundation/ABase.h>
-using android::hidl::base::V1_0::IBase;
-
namespace android {
struct PersistentSurface : public RefBase {
PersistentSurface() {}
- // create an OMX persistent surface
+ // create a persistent surface
PersistentSurface(
const sp<IGraphicBufferProducer>& bufferProducer,
- const sp<IGraphicBufferSource>& bufferSource) :
- mBufferProducer(bufferProducer),
- mBufferSource(bufferSource) { }
-
- // create a HIDL persistent surface
- PersistentSurface(
- const sp<IGraphicBufferProducer>& bufferProducer,
- const sp<IBase>& hidlTarget) :
+ const sp<hidl::base::V1_0::IBase>& hidlTarget) :
mBufferProducer(bufferProducer),
mHidlTarget(hidlTarget) { }
@@ -50,18 +40,12 @@
return mBufferProducer;
}
- sp<IGraphicBufferSource> getBufferSource() const {
- return mBufferSource;
- }
-
- sp<IBase> getHidlTarget() const {
+ sp<hidl::base::V1_0::IBase> getHidlTarget() const {
return mHidlTarget;
}
status_t writeToParcel(Parcel *parcel) const {
parcel->writeStrongBinder(IInterface::asBinder(mBufferProducer));
- // this can handle null
- parcel->writeStrongBinder(IInterface::asBinder(mBufferSource));
// write hidl target
if (mHidlTarget != nullptr) {
HalToken token;
@@ -79,8 +63,6 @@
status_t readFromParcel(const Parcel *parcel) {
mBufferProducer = interface_cast<IGraphicBufferProducer>(
parcel->readStrongBinder());
- mBufferSource = interface_cast<IGraphicBufferSource>(
- parcel->readStrongBinder());
// read hidl target
bool haveHidlTarget = parcel->readBool();
if (haveHidlTarget) {
@@ -97,8 +79,7 @@
private:
sp<IGraphicBufferProducer> mBufferProducer;
- sp<IGraphicBufferSource> mBufferSource;
- sp<IBase> mHidlTarget;
+ sp<hidl::base::V1_0::IBase> mHidlTarget;
DISALLOW_EVIL_CONSTRUCTORS(PersistentSurface);
};
diff --git a/media/libstagefright/include/media/stagefright/RemoteDataSource.h b/media/libstagefright/include/media/stagefright/RemoteDataSource.h
index e191e6a..d82be8a 100644
--- a/media/libstagefright/include/media/stagefright/RemoteDataSource.h
+++ b/media/libstagefright/include/media/stagefright/RemoteDataSource.h
@@ -17,10 +17,10 @@
#ifndef REMOTE_DATA_SOURCE_H_
#define REMOTE_DATA_SOURCE_H_
+#include <android/IDataSource.h>
#include <binder/IMemory.h>
#include <binder/MemoryDealer.h>
#include <media/DataSource.h>
-#include <media/IDataSource.h>
namespace android {
@@ -48,7 +48,7 @@
if (size > kBufferSize) {
size = kBufferSize;
}
- return mSource->readAt(offset, mMemory->pointer(), size);
+ return mSource->readAt(offset, mMemory->unsecurePointer(), size);
}
virtual status_t getSize(off64_t *size) {
return mSource->getSize(size);
@@ -66,9 +66,6 @@
virtual String8 toString() {
return mName;
}
- virtual sp<DecryptHandle> DrmInitialization(const char *mime) {
- return mSource->DrmInitialization(mime);
- }
private:
enum {
diff --git a/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h b/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
index 9925114..2ce7bc7 100644
--- a/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
@@ -17,13 +17,13 @@
#ifndef REMOTE_MEDIA_EXTRACTOR_H_
#define REMOTE_MEDIA_EXTRACTOR_H_
-#include <media/IMediaExtractor.h>
+#include <android/IMediaExtractor.h>
+#include <media/MediaMetricsItem.h>
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/foundation/ABase.h>
namespace android {
-class MediaAnalyticsItem;
// IMediaExtractor wrapper to the MediaExtractor.
class RemoteMediaExtractor : public BnMediaExtractor {
@@ -41,14 +41,14 @@
virtual status_t getMetrics(Parcel *reply);
virtual uint32_t flags() const;
virtual status_t setMediaCas(const HInterfaceToken &casToken);
- virtual const char * name();
+ virtual String8 name();
private:
MediaExtractor *mExtractor;
sp<DataSource> mSource;
sp<RefBase> mExtractorPlugin;
- MediaAnalyticsItem *mAnalyticsItem;
+ mediametrics::Item *mMetricsItem;
explicit RemoteMediaExtractor(
MediaExtractor *extractor,
diff --git a/media/libstagefright/include/media/stagefright/RemoteMediaSource.h b/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
index 03d3869..2cd23f0 100644
--- a/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
+++ b/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
@@ -18,7 +18,7 @@
#define REMOTE_MEDIA_SOURCE_H_
#include <media/IMediaSource.h>
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/stagefright/foundation/ABase.h>
namespace android {
diff --git a/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h b/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h
index 23defb4..a97ae23 100644
--- a/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h
+++ b/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h
@@ -17,7 +17,7 @@
#ifndef SIMPLE_DECODING_SOURCE_H_
#define SIMPLE_DECODING_SOURCE_H_
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/stagefright/foundation/AString.h>
#include <media/stagefright/foundation/Mutexed.h>
diff --git a/media/libstagefright/include/media/stagefright/Utils.h b/media/libstagefright/include/media/stagefright/Utils.h
index e8e0a11..2b9b759 100644
--- a/media/libstagefright/include/media/stagefright/Utils.h
+++ b/media/libstagefright/include/media/stagefright/Utils.h
@@ -41,8 +41,6 @@
// TODO: combine this with avc_utils::getNextNALUnit
const uint8_t *findNextNalStartCode(const uint8_t *data, size_t length);
-AString MakeUserAgent();
-
// Convert a MIME type to a AudioSystem::audio_format
status_t mapMimeToAudioFormat(audio_format_t& format, const char* mime);
@@ -60,8 +58,6 @@
bool canOffloadStream(const sp<MetaData>& meta, bool hasVideo,
bool isStreaming, audio_stream_type_t streamType);
-AString uriDebugString(const AString &uri, bool incognito = false);
-
struct HLSTime {
int32_t mSeq;
int64_t mTimeUs;
@@ -85,7 +81,6 @@
void writeToAMessage(const sp<AMessage> &msg, const BufferingSettings &buffering);
void readFromAMessage(const sp<AMessage> &msg, BufferingSettings *buffering /* nonnull */);
-AString nameForFd(int fd);
} // namespace android
#endif // UTILS_H_
diff --git a/media/libstagefright/include/media/stagefright/foundation b/media/libstagefright/include/media/stagefright/foundation
deleted file mode 120000
index b9fd3b3..0000000
--- a/media/libstagefright/include/media/stagefright/foundation
+++ /dev/null
@@ -1 +0,0 @@
-../../../foundation/include/media/stagefright/foundation/
\ No newline at end of file
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index 0ff2d7e..49578d3 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -20,7 +20,7 @@
#include <sys/types.h>
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AudioPresentationInfo.h>
diff --git a/media/libstagefright/mpeg2ts/Android.bp b/media/libstagefright/mpeg2ts/Android.bp
index a507b91..42afea3 100644
--- a/media/libstagefright/mpeg2ts/Android.bp
+++ b/media/libstagefright/mpeg2ts/Android.bp
@@ -29,7 +29,6 @@
shared_libs: [
"libcrypto",
- "libmedia",
"libhidlmemory",
"android.hardware.cas.native@1.0",
"android.hidl.memory@1.0",
@@ -37,9 +36,13 @@
],
header_libs: [
+ "libmedia_headers",
+ "libaudioclient_headers",
"media_ndk_headers",
],
+ export_include_dirs: ["."],
+
whole_static_libs: [
"libstagefright_metadatautils",
],
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
index f4a6acb..44fe2c8 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.h
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
@@ -18,7 +18,7 @@
#define ANOTHER_PACKET_SOURCE_H_
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/stagefright/foundation/ABase.h>
#include <utils/threads.h>
#include <utils/List.h>
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 5af7b23..657144c 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -36,6 +36,10 @@
#include <inttypes.h>
#include <netinet/in.h>
+#ifndef __ANDROID_APEX__
+#include "HlsSampleDecryptor.h"
+#endif
+
namespace android {
ElementaryStreamQueue::ElementaryStreamQueue(Mode mode, uint32_t flags)
@@ -50,7 +54,13 @@
// Create the decryptor anyway since we don't know the use-case unless key is provided
// Won't decrypt if key info not available (e.g., scanner/extractor just parsing ts files)
- mSampleDecryptor = isSampleEncrypted() ? new HlsSampleDecryptor : NULL;
+ mSampleDecryptor = isSampleEncrypted() ?
+#ifdef __ANDROID_APEX__
+ new SampleDecryptor
+#else
+ new HlsSampleDecryptor
+#endif
+ : NULL;
}
sp<MetaData> ElementaryStreamQueue::getFormat() {
diff --git a/media/libstagefright/mpeg2ts/ESQueue.h b/media/libstagefright/mpeg2ts/ESQueue.h
index 3227f47..a06bd6a 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.h
+++ b/media/libstagefright/mpeg2ts/ESQueue.h
@@ -25,7 +25,7 @@
#include <utils/RefBase.h>
#include <vector>
-#include "HlsSampleDecryptor.h"
+#include "SampleDecryptor.h"
namespace android {
@@ -109,7 +109,7 @@
sp<MetaData> mFormat;
- sp<HlsSampleDecryptor> mSampleDecryptor;
+ sp<SampleDecryptor> mSampleDecryptor;
int mAUIndex;
bool isSampleEncrypted() const {
diff --git a/media/libstagefright/mpeg2ts/HlsSampleDecryptor.h b/media/libstagefright/mpeg2ts/HlsSampleDecryptor.h
index 2c76620..63b4d7b 100644
--- a/media/libstagefright/mpeg2ts/HlsSampleDecryptor.h
+++ b/media/libstagefright/mpeg2ts/HlsSampleDecryptor.h
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-#ifndef SAMPLE_AES_PROCESSOR_H_
+#ifndef HLS_SAMPLE_AES_PROCESSOR_H_
-#define SAMPLE_AES_PROCESSOR_H_
+#define HLS_SAMPLE_AES_PROCESSOR_H_
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AString.h>
@@ -28,18 +28,20 @@
#include <utils/RefBase.h>
#include <utils/Vector.h>
+#include "SampleDecryptor.h"
+
namespace android {
-struct HlsSampleDecryptor : RefBase {
+struct HlsSampleDecryptor : SampleDecryptor {
HlsSampleDecryptor();
explicit HlsSampleDecryptor(const sp<AMessage> &sampleAesKeyItem);
- void signalNewSampleAesKey(const sp<AMessage> &sampleAesKeyItem);
+ virtual void signalNewSampleAesKey(const sp<AMessage> &sampleAesKeyItem);
- size_t processNal(uint8_t *nalData, size_t nalSize);
- void processAAC(size_t adtsHdrSize, uint8_t *data, size_t size);
- void processAC3(uint8_t *data, size_t size);
+ virtual size_t processNal(uint8_t *nalData, size_t nalSize);
+ virtual void processAAC(size_t adtsHdrSize, uint8_t *data, size_t size);
+ virtual void processAC3(uint8_t *data, size_t size);
static AString aesBlockToStr(uint8_t block[AES_BLOCK_SIZE]);
@@ -60,4 +62,4 @@
} // namespace android
-#endif // SAMPLE_AES_PROCESSOR_H_
+#endif // HLS_SAMPLE_AES_PROCESSOR_H_
diff --git a/media/libstagefright/mpeg2ts/SampleDecryptor.h b/media/libstagefright/mpeg2ts/SampleDecryptor.h
new file mode 100644
index 0000000..6bc4ac8
--- /dev/null
+++ b/media/libstagefright/mpeg2ts/SampleDecryptor.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#ifndef SAMPLE_AES_PROCESSOR_H_
+
+#define SAMPLE_AES_PROCESSOR_H_
+
+#include <media/stagefright/foundation/AMessage.h>
+
+#include <utils/RefBase.h>
+
+namespace android {
+
+// Base class of HlsSampleDecryptor which has dummy default implementation.
+struct SampleDecryptor : RefBase {
+
+ SampleDecryptor() { };
+
+ virtual void signalNewSampleAesKey(const sp<AMessage> &) { };
+
+ virtual size_t processNal(uint8_t *, size_t) { return -1; };
+ virtual void processAAC(size_t, uint8_t *, size_t) { };
+ virtual void processAC3(uint8_t *, size_t) { };
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(SampleDecryptor);
+};
+
+} // namespace android
+
+#endif // SAMPLE_AES_PROCESSOR_H_
diff --git a/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp b/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp
index ed272bb..7d217eb 100644
--- a/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp
+++ b/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+#ifdef __LP64__
+#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
+#endif
+
//#define LOG_NDEBUG 0
#define LOG_TAG "TWGraphicBufferSource"
@@ -21,6 +25,7 @@
#include <media/stagefright/omx/1.0/WOmxNode.h>
#include <media/stagefright/omx/1.0/Conversion.h>
#include <media/stagefright/omx/OMXUtils.h>
+#include <media/stagefright/omx/OmxGraphicBufferSource.h>
#include <android/hardware/media/omx/1.0/IOmxBufferSource.h>
#include <android/hardware/media/omx/1.0/IOmxNode.h>
#include <media/openmax/OMX_Component.h>
diff --git a/media/libstagefright/omx/Android.bp b/media/libstagefright/omx/Android.bp
index 7d03d98..78b4f19 100644
--- a/media/libstagefright/omx/Android.bp
+++ b/media/libstagefright/omx/Android.bp
@@ -4,6 +4,7 @@
vndk: {
enabled: true,
},
+ double_loadable: true,
srcs: [
"OMXMaster.cpp",
@@ -45,7 +46,6 @@
"libdl",
"libhidlbase",
"libhidlmemory",
- "libhidltransport",
"libvndksupport",
"android.hardware.media.omx@1.0",
"android.hardware.graphics.bufferqueue@1.0",
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index ddb4ba0..2f69f45 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -128,7 +128,7 @@
}
OMX_U8 *getPointer() {
- return mMem.get() ? static_cast<OMX_U8*>(mMem->pointer()) :
+ return mMem.get() ? static_cast<OMX_U8*>(mMem->unsecurePointer()) :
mHidlMemory.get() ? static_cast<OMX_U8*>(
static_cast<void*>(mHidlMemory->getPointer())) : nullptr;
}
@@ -492,6 +492,12 @@
}
case OMX_StateLoaded:
+ {
+ if (mActiveBuffers.size() > 0) {
+ freeActiveBuffers();
+ }
+ FALLTHROUGH_INTENDED;
+ }
case OMX_StateInvalid:
break;
@@ -1173,7 +1179,11 @@
return BAD_VALUE;
}
if (params != NULL) {
- paramsPointer = params->pointer();
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
+ paramsPointer = params->unsecurePointer();
paramsSize = params->size();
} else if (hParams != NULL) {
paramsPointer = hParams->getPointer();
diff --git a/media/libstagefright/omx/OmxGraphicBufferSource.cpp b/media/libstagefright/omx/OmxGraphicBufferSource.cpp
index 8de1f4f..9484046 100644
--- a/media/libstagefright/omx/OmxGraphicBufferSource.cpp
+++ b/media/libstagefright/omx/OmxGraphicBufferSource.cpp
@@ -14,12 +14,18 @@
* limitations under the License.
*/
+#ifdef __LP64__
+#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
+#endif
+
#include <inttypes.h>
#define LOG_TAG "OmxGraphicBufferSource"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
+#include <media/openmax/OMX_Core.h>
+
#include <media/stagefright/bqhelper/ComponentWrapper.h>
#include <media/stagefright/bqhelper/GraphicBufferSource.h>
#include <media/stagefright/omx/OmxGraphicBufferSource.h>
@@ -59,15 +65,18 @@
} // namespace
Status OmxGraphicBufferSource::onOmxExecuting() {
- return start();
+ status_t err = start();
+ return (OK == err) ? Status::ok() : Status::fromServiceSpecificError(err);
}
Status OmxGraphicBufferSource::onOmxIdle() {
- return stop();
+ status_t err = stop();
+ return (OK == err) ? Status::ok() : Status::fromServiceSpecificError(err);
}
Status OmxGraphicBufferSource::onOmxLoaded(){
- return release();
+ status_t err = release();
+ return (OK == err) ? Status::ok() : Status::fromServiceSpecificError(err);
}
status_t OmxGraphicBufferSource::configure(
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/1.0/Conversion.h b/media/libstagefright/omx/include/media/stagefright/omx/1.0/Conversion.h
index 9669677..264c01d 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/1.0/Conversion.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/1.0/Conversion.h
@@ -48,7 +48,6 @@
#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
#include <android/hardware/media/omx/1.0/IOmxObserver.h>
-#include <android/IGraphicBufferSource.h>
#include <android/IOMXBufferSource.h>
namespace android {
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/1.0/WGraphicBufferSource.h b/media/libstagefright/omx/include/media/stagefright/omx/1.0/WGraphicBufferSource.h
index 4e56c98..02d4b7b 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/1.0/WGraphicBufferSource.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/1.0/WGraphicBufferSource.h
@@ -26,18 +26,16 @@
#include <android/hardware/media/omx/1.0/IOmxNode.h>
#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
-#include <android/BnGraphicBufferSource.h>
-
-#include <media/stagefright/omx/OmxGraphicBufferSource.h>
-
namespace android {
+
+class OmxGraphicBufferSource;
+
namespace hardware {
namespace media {
namespace omx {
namespace V1_0 {
namespace implementation {
-using ::android::OmxGraphicBufferSource;
using ::android::hardware::graphics::common::V1_0::Dataspace;
using ::android::hardware::media::omx::V1_0::ColorAspects;
using ::android::hardware::media::omx::V1_0::IGraphicBufferSource;
@@ -52,8 +50,6 @@
using ::android::hardware::Void;
using ::android::sp;
-using ::android::IOMXNode;
-
/**
* Wrapper classes for conversion
* ==============================
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/OmxGraphicBufferSource.h b/media/libstagefright/omx/include/media/stagefright/omx/OmxGraphicBufferSource.h
index 518e0cb..e576d75 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/OmxGraphicBufferSource.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/OmxGraphicBufferSource.h
@@ -21,7 +21,6 @@
#include <media/stagefright/bqhelper/GraphicBufferSource.h>
#include <media/stagefright/foundation/ABase.h>
-#include <android/BnGraphicBufferSource.h>
#include <android/BnOMXBufferSource.h>
#include "IOmxNodeWrapper.h"
diff --git a/media/libstagefright/omx/tests/Android.bp b/media/libstagefright/omx/tests/Android.bp
index 569fa88..fefb3bb 100644
--- a/media/libstagefright/omx/tests/Android.bp
+++ b/media/libstagefright/omx/tests/Android.bp
@@ -7,6 +7,7 @@
shared_libs: [
"libstagefright",
"libbinder",
+ "libdatasource",
"libmedia",
"libmedia_omx",
"libutils",
@@ -22,6 +23,7 @@
header_libs: [
"libbase_headers",
+ "libmediametrics_headers",
"media_ndk_headers",
],
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index cc8c234..7893148 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -27,13 +27,13 @@
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <cutils/properties.h>
+#include <datasource/DataSourceFactory.h>
#include <media/DataSource.h>
#include <media/IMediaHTTPService.h>
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/OMXBuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/DataSourceFactory.h>
#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaDefs.h>
@@ -278,7 +278,7 @@
static sp<IMediaExtractor> CreateExtractorFromURI(const char *uri) {
sp<DataSource> source =
- DataSourceFactory::CreateFromURI(NULL /* httpService */, uri);
+ DataSourceFactory::getInstance()->CreateFromURI(NULL /* httpService */, uri);
if (source == NULL) {
return NULL;
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index 1aa8a20..574bd7a 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -112,7 +112,9 @@
sp<ABuffer> profileLevelID = NULL;
if (GetAttribute(params, "profile-level-id", &val)) {
profileLevelID = decodeHex(val);
- CHECK_EQ(profileLevelID->size(), 3u);
+ if (profileLevelID != NULL && profileLevelID->size() != 3u) {
+ profileLevelID = NULL;
+ }
}
Vector<sp<ABuffer> > paramSets;
diff --git a/media/libstagefright/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp
index 4f86773..58d6086 100644
--- a/media/libstagefright/rtsp/ARTPWriter.cpp
+++ b/media/libstagefright/rtsp/ARTPWriter.cpp
@@ -22,7 +22,7 @@
#include <fcntl.h>
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index 789e62a..bb66f4c 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -21,12 +21,14 @@
#include "ARTSPConnection.h"
#include "NetworkUtils.h"
+#include <datasource/HTTPBase.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/base64.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <arpa/inet.h>
#include <fcntl.h>
@@ -34,7 +36,6 @@
#include <openssl/md5.h>
#include <sys/socket.h>
-#include "include/HTTPBase.h"
namespace android {
@@ -953,7 +954,7 @@
CHECK_GE(space2, 0);
method->setTo(request, 0, space1);
- url->setTo(request, space1 + 1, space2 - space1);
+ url->setTo(request, space1 + 1, space2 - space1 - 1);
}
void ARTSPConnection::addAuthentication(AString *request) {
diff --git a/media/libstagefright/rtsp/ARTSPConnection.h b/media/libstagefright/rtsp/ARTSPConnection.h
index 8df2676..56b604d 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.h
+++ b/media/libstagefright/rtsp/ARTSPConnection.h
@@ -46,6 +46,8 @@
const char *url, AString *host, unsigned *port, AString *path,
AString *user, AString *pass);
+ int getSocket() { return mSocket; }
+
protected:
virtual ~ARTSPConnection();
virtual void onMessageReceived(const sp<AMessage> &msg);
diff --git a/media/libstagefright/rtsp/ASessionDescription.cpp b/media/libstagefright/rtsp/ASessionDescription.cpp
index 9263565..2b42040 100644
--- a/media/libstagefright/rtsp/ASessionDescription.cpp
+++ b/media/libstagefright/rtsp/ASessionDescription.cpp
@@ -141,6 +141,12 @@
AString key, value;
ssize_t equalPos = line.find("=");
+ /* The condition 'if (line.size() < 2 || line.c_str()[1] != '=')' a few lines above
+ * ensures '=' is at position 1. However for robustness we do the following check.
+ */
+ if (equalPos < 0) {
+ return false;
+ }
key = AString(line, 0, equalPos + 1);
value = AString(line, equalPos + 1, line.size() - equalPos - 1);
diff --git a/media/libstagefright/rtsp/Android.bp b/media/libstagefright/rtsp/Android.bp
index 9bc9c89..a5a895e 100644
--- a/media/libstagefright/rtsp/Android.bp
+++ b/media/libstagefright/rtsp/Android.bp
@@ -21,6 +21,7 @@
shared_libs: [
"libcrypto",
+ "libdatasource",
"libmedia",
],
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 48bc8ce..7f025a5 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -36,18 +36,19 @@
#include <ctype.h>
#include <cutils/properties.h>
+#include <datasource/HTTPBase.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
-#include "HTTPBase.h"
#if LOG_NDEBUG
#define UNUSED_UNLESS_VERBOSE(x) (void)(x)
@@ -257,6 +258,10 @@
msg->post();
}
+ sp<ARTSPConnection> getARTSPConnection() {
+ return mConn;
+ }
+
static void addRR(const sp<ABuffer> &buf) {
uint8_t *ptr = buf->data() + buf->size();
ptr[0] = 0x80 | 0;
diff --git a/media/libstagefright/rtsp/SDPLoader.cpp b/media/libstagefright/rtsp/SDPLoader.cpp
index 665d51a..e236267 100644
--- a/media/libstagefright/rtsp/SDPLoader.cpp
+++ b/media/libstagefright/rtsp/SDPLoader.cpp
@@ -22,12 +22,13 @@
#include "ASessionDescription.h"
+#include <datasource/MediaHTTP.h>
#include <media/MediaHTTPConnection.h>
#include <media/MediaHTTPService.h>
-#include <media/stagefright/ClearMediaHTTP.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#define DEFAULT_SDP_SIZE 100000
@@ -41,7 +42,7 @@
mFlags(flags),
mNetLooper(new ALooper),
mCancelled(false),
- mHTTPDataSource(new ClearMediaHTTP(httpService->makeHTTPConnection())) {
+ mHTTPDataSource(new MediaHTTP(httpService->makeHTTPConnection())) {
mNetLooper->setName("sdp net");
mNetLooper->start(false /* runOnCallingThread */,
false /* canCallJava */,
diff --git a/media/libstagefright/rtsp/VideoSource.h b/media/libstagefright/rtsp/VideoSource.h
index 4be9bf6..f29db57 100644
--- a/media/libstagefright/rtsp/VideoSource.h
+++ b/media/libstagefright/rtsp/VideoSource.h
@@ -18,7 +18,7 @@
#define VIDEO_SOURCE_H_
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
diff --git a/media/libstagefright/tests/writer/Android.bp b/media/libstagefright/tests/writer/Android.bp
new file mode 100644
index 0000000..7e169cb
--- /dev/null
+++ b/media/libstagefright/tests/writer/Android.bp
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+cc_test {
+ name: "writerTest",
+ gtest: true,
+
+ srcs: [
+ "WriterUtility.cpp",
+ "WriterTest.cpp",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "libcutils",
+ "liblog",
+ "libutils",
+ ],
+
+ static_libs: [
+ "libstagefright_webm",
+ "libdatasource",
+ "libstagefright",
+ "libstagefright_foundation",
+ "libstagefright_esds",
+ "libogg",
+ ],
+
+ include_dirs: [
+ "frameworks/av/media/libstagefright",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ sanitize: {
+ cfi: true,
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ },
+}
diff --git a/media/libstagefright/tests/writer/AndroidTest.xml b/media/libstagefright/tests/writer/AndroidTest.xml
new file mode 100644
index 0000000..d831555
--- /dev/null
+++ b/media/libstagefright/tests/writer/AndroidTest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Test module config for writer tests">
+ <option name="test-suite-tag" value="writerTest" />
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="writerTest->/data/local/tmp/writerTest" />
+ <option name="push-file"
+ key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/tests/writer/Writer.zip?unzip=true"
+ value="/data/local/tmp/writerTestRes/" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="writerTest" />
+ <option name="native-test-flag" value="-P /data/local/tmp/writerTestRes/" />
+ </test>
+</configuration>
diff --git a/media/libstagefright/tests/writer/README.md b/media/libstagefright/tests/writer/README.md
new file mode 100644
index 0000000..ae07917
--- /dev/null
+++ b/media/libstagefright/tests/writer/README.md
@@ -0,0 +1,31 @@
+## Media Testing ##
+---
+#### Writer :
+The Writer Test Suite validates the writers available in libstagefright.
+
+Run the following steps to build the test suite:
+```
+mmm frameworks/av/media/libstagefright/tests/writer/
+```
+
+The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/
+The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/
+
+To test 64-bit binary push binaries from nativetest64.
+
+adb push ${OUT}/data/nativetest64/writerTest/writerTest /data/local/tmp/
+
+To test 32-bit binary push binaries from nativetest.
+
+adb push ${OUT}/data/nativetest/writerTest/writerTest /data/local/tmp/
+
+The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/tests/writer/writerTestRes.zip).
+Download and extract the folder. Push all the files in this folder to /data/local/tmp/ on the device.
+```
+adb push writerTestRes /data/local/tmp/
+```
+
+usage: writerTest -P \<path_to_res_folder\>
+```
+adb shell /data/local/tmp/writerTest -P /data/local/tmp/
+```
diff --git a/media/libstagefright/tests/writer/WriterTest.cpp b/media/libstagefright/tests/writer/WriterTest.cpp
new file mode 100644
index 0000000..ff063e3
--- /dev/null
+++ b/media/libstagefright/tests/writer/WriterTest.cpp
@@ -0,0 +1,476 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "WriterTest"
+#include <utils/Log.h>
+
+#include <fstream>
+#include <iostream>
+
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+
+#include <media/mediarecorder.h>
+
+#include <media/stagefright/AACWriter.h>
+#include <media/stagefright/AMRWriter.h>
+#include <media/stagefright/MPEG2TSWriter.h>
+#include <media/stagefright/MPEG4Writer.h>
+#include <media/stagefright/OggWriter.h>
+#include <webm/WebmWriter.h>
+
+#include "WriterTestEnvironment.h"
+#include "WriterUtility.h"
+
+#define OUTPUT_FILE_NAME "/data/local/tmp/writer.out"
+
+static WriterTestEnvironment *gEnv = nullptr;
+
+struct configFormat {
+ char mime[128];
+ int32_t width;
+ int32_t height;
+ int32_t sampleRate;
+ int32_t channelCount;
+};
+
+// LookUpTable of clips and metadata for component testing
+static const struct InputData {
+ const char *mime;
+ string inputFile;
+ string info;
+ int32_t firstParam;
+ int32_t secondParam;
+ bool isAudio;
+} kInputData[] = {
+ {MEDIA_MIMETYPE_AUDIO_OPUS, "bbb_opus_stereo_128kbps_48000hz.opus",
+ "bbb_opus_stereo_128kbps_48000hz.info", 48000, 2, true},
+ {MEDIA_MIMETYPE_AUDIO_AAC, "bbb_aac_stereo_128kbps_48000hz.aac",
+ "bbb_aac_stereo_128kbps_48000hz.info", 48000, 2, true},
+ {MEDIA_MIMETYPE_AUDIO_AAC_ADTS, "Mps_2_c2_fr1_Sc1_Dc2_0x03_raw.adts",
+ "Mps_2_c2_fr1_Sc1_Dc2_0x03_raw.info", 48000, 2, true},
+ {MEDIA_MIMETYPE_AUDIO_AMR_NB, "sine_amrnb_1ch_12kbps_8000hz.amrnb",
+ "sine_amrnb_1ch_12kbps_8000hz.info", 8000, 1, true},
+ {MEDIA_MIMETYPE_AUDIO_AMR_WB, "bbb_amrwb_1ch_14kbps_16000hz.amrwb",
+ "bbb_amrwb_1ch_14kbps_16000hz.info", 16000, 1, true},
+ {MEDIA_MIMETYPE_AUDIO_VORBIS, "bbb_vorbis_stereo_128kbps_48000hz.vorbis",
+ "bbb_vorbis_stereo_128kbps_48000hz.info", 48000, 2, true},
+ {MEDIA_MIMETYPE_AUDIO_FLAC, "bbb_flac_stereo_680kbps_48000hz.flac",
+ "bbb_flac_stereo_680kbps_48000hz.info", 48000, 2, true},
+ {MEDIA_MIMETYPE_VIDEO_VP9, "bbb_vp9_176x144_285kbps_60fps.vp9",
+ "bbb_vp9_176x144_285kbps_60fps.info", 176, 144, false},
+ {MEDIA_MIMETYPE_VIDEO_VP8, "bbb_vp8_176x144_240kbps_60fps.vp8",
+ "bbb_vp8_176x144_240kbps_60fps.info", 176, 144, false},
+ {MEDIA_MIMETYPE_VIDEO_AVC, "bbb_avc_176x144_300kbps_60fps.h264",
+ "bbb_avc_176x144_300kbps_60fps.info", 176, 144, false},
+ {MEDIA_MIMETYPE_VIDEO_HEVC, "bbb_hevc_176x144_176kbps_60fps.hevc",
+ "bbb_hevc_176x144_176kbps_60fps.info", 176, 144, false},
+ {MEDIA_MIMETYPE_VIDEO_AV1, "bbb_av1_176_144.av1", "bbb_av1_176_144.info", 176, 144, false},
+ {MEDIA_MIMETYPE_VIDEO_H263, "bbb_h263_352x288_300kbps_12fps.h263",
+ "bbb_h263_352x288_300kbps_12fps.info", 352, 288, false},
+ {MEDIA_MIMETYPE_VIDEO_MPEG4, "bbb_mpeg4_352x288_512kbps_30fps.m4v",
+ "bbb_mpeg4_352x288_512kbps_30fps.info", 352, 288, false},
+};
+
+class WriterTest : public ::testing::TestWithParam<pair<string, int32_t>> {
+ public:
+ WriterTest() : mWriter(nullptr), mFileMeta(nullptr), mCurrentTrack(nullptr) {}
+
+ ~WriterTest() {
+ if (mWriter) {
+ mWriter.clear();
+ mWriter = nullptr;
+ }
+ if (mFileMeta) {
+ mFileMeta.clear();
+ mFileMeta = nullptr;
+ }
+ if (mCurrentTrack) {
+ mCurrentTrack.clear();
+ mCurrentTrack = nullptr;
+ }
+ }
+
+ virtual void SetUp() override {
+ mNumCsds = 0;
+ mInputFrameId = 0;
+ mWriterName = unknown_comp;
+ mDisableTest = false;
+
+ static const std::map<std::string, standardWriters> mapWriter = {
+ {"ogg", OGG}, {"aac", AAC}, {"aac_adts", AAC_ADTS}, {"webm", WEBM},
+ {"mpeg4", MPEG4}, {"amrnb", AMR_NB}, {"amrwb", AMR_WB}, {"mpeg2Ts", MPEG2TS}};
+ // Find the component type
+ string writerFormat = GetParam().first;
+ if (mapWriter.find(writerFormat) != mapWriter.end()) {
+ mWriterName = mapWriter.at(writerFormat);
+ }
+ if (mWriterName == standardWriters::unknown_comp) {
+ cout << "[ WARN ] Test Skipped. No specific writer mentioned\n";
+ mDisableTest = true;
+ }
+ }
+
+ virtual void TearDown() override {
+ mBufferInfo.clear();
+ if (mInputStream.is_open()) mInputStream.close();
+ }
+
+ void getInputBufferInfo(string inputFileName, string inputInfo);
+
+ int32_t createWriter(int32_t fd);
+
+ int32_t addWriterSource(bool isAudio, configFormat params);
+
+ enum standardWriters {
+ OGG,
+ AAC,
+ AAC_ADTS,
+ WEBM,
+ MPEG4,
+ AMR_NB,
+ AMR_WB,
+ MPEG2TS,
+ unknown_comp,
+ };
+
+ standardWriters mWriterName;
+ sp<MediaWriter> mWriter;
+ sp<MetaData> mFileMeta;
+ sp<MediaAdapter> mCurrentTrack;
+
+ bool mDisableTest;
+ int32_t mNumCsds;
+ int32_t mInputFrameId;
+ ifstream mInputStream;
+ vector<BufferInfo> mBufferInfo;
+};
+
+void WriterTest::getInputBufferInfo(string inputFileName, string inputInfo) {
+ std::ifstream eleInfo;
+ eleInfo.open(inputInfo.c_str());
+ ASSERT_EQ(eleInfo.is_open(), true);
+ int32_t bytesCount = 0;
+ uint32_t flags = 0;
+ int64_t timestamp = 0;
+ while (1) {
+ if (!(eleInfo >> bytesCount)) break;
+ eleInfo >> flags;
+ eleInfo >> timestamp;
+ mBufferInfo.push_back({bytesCount, flags, timestamp});
+ if (flags == CODEC_CONFIG_FLAG) mNumCsds++;
+ }
+ eleInfo.close();
+ mInputStream.open(inputFileName.c_str(), std::ifstream::binary);
+ ASSERT_EQ(mInputStream.is_open(), true);
+}
+
+int32_t WriterTest::createWriter(int32_t fd) {
+ mFileMeta = new MetaData;
+ switch (mWriterName) {
+ case OGG:
+ mWriter = new OggWriter(fd);
+ mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_OGG);
+ break;
+ case AAC:
+ mWriter = new AACWriter(fd);
+ mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AAC_ADIF);
+ break;
+ case AAC_ADTS:
+ mWriter = new AACWriter(fd);
+ mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AAC_ADTS);
+ break;
+ case WEBM:
+ mWriter = new WebmWriter(fd);
+ mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_WEBM);
+ break;
+ case MPEG4:
+ mWriter = new MPEG4Writer(fd);
+ mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_MPEG_4);
+ break;
+ case AMR_NB:
+ mWriter = new AMRWriter(fd);
+ mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AMR_NB);
+ break;
+ case AMR_WB:
+ mWriter = new AMRWriter(fd);
+ mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AMR_WB);
+ break;
+ case MPEG2TS:
+ mWriter = new MPEG2TSWriter(fd);
+ mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_MPEG2TS);
+ break;
+ default:
+ return -1;
+ }
+ if (mWriter == nullptr) return -1;
+ mFileMeta->setInt32(kKeyRealTimeRecording, false);
+ return 0;
+}
+
+int32_t WriterTest::addWriterSource(bool isAudio, configFormat params) {
+ if (mInputFrameId) return -1;
+ sp<AMessage> format = new AMessage;
+ if (mInputStream.is_open()) {
+ format->setString("mime", params.mime);
+ if (isAudio) {
+ format->setInt32("channel-count", params.channelCount);
+ format->setInt32("sample-rate", params.sampleRate);
+ } else {
+ format->setInt32("width", params.width);
+ format->setInt32("height", params.height);
+ }
+
+ int32_t status =
+ writeHeaderBuffers(mInputStream, mBufferInfo, mInputFrameId, format, mNumCsds);
+ if (status != 0) return -1;
+ }
+ sp<MetaData> trackMeta = new MetaData;
+ convertMessageToMetaData(format, trackMeta);
+ mCurrentTrack = new MediaAdapter(trackMeta);
+ if (mCurrentTrack == nullptr) {
+ ALOGE("MediaAdapter returned nullptr");
+ return -1;
+ }
+ status_t result = mWriter->addSource(mCurrentTrack);
+ return result;
+}
+
+void getFileDetails(string &inputFilePath, string &info, configFormat ¶ms, bool &isAudio,
+ int32_t streamIndex = 0) {
+ if (streamIndex >= sizeof(kInputData) / sizeof(kInputData[0])) {
+ return;
+ }
+ inputFilePath += kInputData[streamIndex].inputFile;
+ info += kInputData[streamIndex].info;
+ strcpy(params.mime, kInputData[streamIndex].mime);
+ isAudio = kInputData[streamIndex].isAudio;
+ if (isAudio) {
+ params.sampleRate = kInputData[streamIndex].firstParam;
+ params.channelCount = kInputData[streamIndex].secondParam;
+ } else {
+ params.width = kInputData[streamIndex].firstParam;
+ params.height = kInputData[streamIndex].secondParam;
+ }
+ return;
+}
+
+TEST_P(WriterTest, CreateWriterTest) {
+ if (mDisableTest) return;
+ ALOGV("Tests the creation of writers");
+
+ string outputFile = OUTPUT_FILE_NAME;
+ int32_t fd =
+ open(outputFile.c_str(), O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
+ ASSERT_GE(fd, 0) << "Failed to open output file to dump writer's data";
+
+ // Creating writer within a test scope. Destructor should be called when the test ends
+ ASSERT_EQ((status_t)OK, createWriter(fd))
+ << "Failed to create writer for output format:" << GetParam().first;
+}
+
+TEST_P(WriterTest, WriterTest) {
+ if (mDisableTest) return;
+ ALOGV("Checks if for a given input, a valid muxed file has been created or not");
+
+ string writerFormat = GetParam().first;
+ string outputFile = OUTPUT_FILE_NAME;
+ int32_t fd =
+ open(outputFile.c_str(), O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
+ ASSERT_GE(fd, 0) << "Failed to open output file to dump writer's data";
+
+ int32_t status = createWriter(fd);
+ ASSERT_EQ((status_t)OK, status) << "Failed to create writer for output format:" << writerFormat;
+
+ string inputFile = gEnv->getRes();
+ string inputInfo = gEnv->getRes();
+ configFormat param;
+ bool isAudio;
+ int32_t inputFileIdx = GetParam().second;
+ getFileDetails(inputFile, inputInfo, param, isAudio, inputFileIdx);
+ ASSERT_NE(inputFile.compare(gEnv->getRes()), 0) << "No input file specified";
+
+ ASSERT_NO_FATAL_FAILURE(getInputBufferInfo(inputFile, inputInfo));
+ status = addWriterSource(isAudio, param);
+ ASSERT_EQ((status_t)OK, status) << "Failed to add source for " << writerFormat << "Writer";
+
+ status = mWriter->start(mFileMeta.get());
+ ASSERT_EQ((status_t)OK, status);
+ status = sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack, 0,
+ mBufferInfo.size());
+ ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
+ mCurrentTrack->stop();
+
+ status = mWriter->stop();
+ ASSERT_EQ((status_t)OK, status) << "Failed to stop the writer";
+ close(fd);
+}
+
+TEST_P(WriterTest, PauseWriterTest) {
+ if (mDisableTest) return;
+ ALOGV("Validates the pause() api of writers");
+
+ string writerFormat = GetParam().first;
+ string outputFile = OUTPUT_FILE_NAME;
+ int32_t fd =
+ open(outputFile.c_str(), O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
+ ASSERT_GE(fd, 0) << "Failed to open output file to dump writer's data";
+
+ int32_t status = createWriter(fd);
+ ASSERT_EQ((status_t)OK, status) << "Failed to create writer for output format:" << writerFormat;
+
+ string inputFile = gEnv->getRes();
+ string inputInfo = gEnv->getRes();
+ configFormat param;
+ bool isAudio;
+ int32_t inputFileIdx = GetParam().second;
+ getFileDetails(inputFile, inputInfo, param, isAudio, inputFileIdx);
+ ASSERT_NE(inputFile.compare(gEnv->getRes()), 0) << "No input file specified";
+
+ ASSERT_NO_FATAL_FAILURE(getInputBufferInfo(inputFile, inputInfo));
+ status = addWriterSource(isAudio, param);
+ ASSERT_EQ((status_t)OK, status) << "Failed to add source for " << writerFormat << "Writer";
+
+ status = mWriter->start(mFileMeta.get());
+ ASSERT_EQ((status_t)OK, status);
+ status = sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack, 0,
+ mBufferInfo.size() / 4);
+ ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
+
+ bool isPaused = false;
+ if ((mWriterName != standardWriters::MPEG2TS) && (mWriterName != standardWriters::MPEG4)) {
+ status = mWriter->pause();
+ ASSERT_EQ((status_t)OK, status);
+ isPaused = true;
+ }
+ // In the pause state, writers shouldn't write anything. Testing the writers for the same
+ int32_t numFramesPaused = mBufferInfo.size() / 4;
+ status = sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack,
+ mInputFrameId, numFramesPaused, isPaused);
+ ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
+
+ if (isPaused) {
+ status = mWriter->start(mFileMeta.get());
+ ASSERT_EQ((status_t)OK, status);
+ }
+ status = sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack,
+ mInputFrameId, mBufferInfo.size());
+ ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
+ mCurrentTrack->stop();
+
+ status = mWriter->stop();
+ ASSERT_EQ((status_t)OK, status) << "Failed to stop the writer";
+ close(fd);
+}
+
+TEST_P(WriterTest, MultiStartStopPauseTest) {
+ // TODO: (b/144821804)
+ // Enable the test for MPE2TS writer
+ if (mDisableTest || mWriterName == standardWriters::MPEG2TS) return;
+ ALOGV("Test writers for multiple start, stop and pause calls");
+
+ string outputFile = OUTPUT_FILE_NAME;
+ int32_t fd =
+ open(outputFile.c_str(), O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
+ ASSERT_GE(fd, 0) << "Failed to open output file to dump writer's data";
+
+ string writerFormat = GetParam().first;
+ int32_t status = createWriter(fd);
+ ASSERT_EQ(status, (status_t)OK) << "Failed to create writer for output format:" << writerFormat;
+
+ string inputFile = gEnv->getRes();
+ string inputInfo = gEnv->getRes();
+ configFormat param;
+ bool isAudio;
+ int32_t inputFileIdx = GetParam().second;
+ getFileDetails(inputFile, inputInfo, param, isAudio, inputFileIdx);
+ ASSERT_NE(inputFile.compare(gEnv->getRes()), 0) << "No input file specified";
+
+ ASSERT_NO_FATAL_FAILURE(getInputBufferInfo(inputFile, inputInfo));
+ status = addWriterSource(isAudio, param);
+ ASSERT_EQ((status_t)OK, status) << "Failed to add source for " << writerFormat << "Writer";
+
+ // first start should succeed.
+ status = mWriter->start(mFileMeta.get());
+ ASSERT_EQ((status_t)OK, status) << "Could not start the writer";
+
+ // Multiple start() may/may not succeed.
+ // Writers are expected to not crash on multiple start() calls.
+ for (int32_t count = 0; count < kMaxCount; count++) {
+ mWriter->start(mFileMeta.get());
+ }
+
+ status = sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack, 0,
+ mBufferInfo.size() / 4);
+ ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
+
+ for (int32_t count = 0; count < kMaxCount; count++) {
+ mWriter->pause();
+ mWriter->start(mFileMeta.get());
+ }
+
+ mWriter->pause();
+ int32_t numFramesPaused = mBufferInfo.size() / 4;
+ status = sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack,
+ mInputFrameId, numFramesPaused, true);
+ ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
+
+ for (int32_t count = 0; count < kMaxCount; count++) {
+ mWriter->start(mFileMeta.get());
+ }
+
+ status = sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack,
+ mInputFrameId, mBufferInfo.size());
+ ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
+
+ mCurrentTrack->stop();
+
+ // first stop should succeed.
+ status = mWriter->stop();
+ ASSERT_EQ((status_t)OK, status) << "Failed to stop the writer";
+ // Multiple stop() may/may not succeed.
+ // Writers are expected to not crash on multiple stop() calls.
+ for (int32_t count = 0; count < kMaxCount; count++) {
+ mWriter->stop();
+ }
+ close(fd);
+}
+
+// TODO: (b/144476164)
+// Add AAC_ADTS, FLAC, AV1 input
+INSTANTIATE_TEST_SUITE_P(WriterTestAll, WriterTest,
+ ::testing::Values(make_pair("ogg", 0), make_pair("webm", 0),
+ make_pair("aac", 1), make_pair("mpeg4", 1),
+ make_pair("amrnb", 3), make_pair("amrwb", 4),
+ make_pair("webm", 5), make_pair("webm", 7),
+ make_pair("webm", 8), make_pair("mpeg4", 9),
+ make_pair("mpeg4", 10), make_pair("mpeg4", 12),
+ make_pair("mpeg4", 13), make_pair("mpeg2Ts", 1),
+ make_pair("mpeg2Ts", 9)));
+
+int main(int argc, char **argv) {
+ gEnv = new WriterTestEnvironment();
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = gEnv->initFromOptions(argc, argv);
+ if (status == 0) {
+ status = RUN_ALL_TESTS();
+ ALOGV("Test result = %d\n", status);
+ }
+ return status;
+}
diff --git a/media/libstagefright/tests/writer/WriterTestEnvironment.h b/media/libstagefright/tests/writer/WriterTestEnvironment.h
new file mode 100644
index 0000000..99e686f
--- /dev/null
+++ b/media/libstagefright/tests/writer/WriterTestEnvironment.h
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#ifndef __WRITER_TEST_ENVIRONMENT_H__
+#define __WRITER_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class WriterTestEnvironment : public ::testing::Environment {
+ public:
+ WriterTestEnvironment() : res("/data/local/tmp/") {}
+
+ // Parses the command line arguments
+ int initFromOptions(int argc, char **argv);
+
+ void setRes(const char *_res) { res = _res; }
+
+ const string getRes() const { return res; }
+
+ private:
+ string res;
+};
+
+int WriterTestEnvironment::initFromOptions(int argc, char **argv) {
+ static struct option options[] = {{"res", required_argument, 0, 'P'}, {0, 0, 0, 0}};
+
+ while (true) {
+ int index = 0;
+ int c = getopt_long(argc, argv, "P:", options, &index);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'P':
+ setRes(optarg);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (optind < argc) {
+ fprintf(stderr,
+ "unrecognized option: %s\n\n"
+ "usage: %s <gtest options> <test options>\n\n"
+ "test options are:\n\n"
+ "-P, --path: Resource files directory location\n",
+ argv[optind ?: 1], argv[0]);
+ return 2;
+ }
+ return 0;
+}
+
+#endif // __WRITER_TEST_ENVIRONMENT_H__
diff --git a/media/libstagefright/tests/writer/WriterUtility.cpp b/media/libstagefright/tests/writer/WriterUtility.cpp
new file mode 100644
index 0000000..f24ccb6
--- /dev/null
+++ b/media/libstagefright/tests/writer/WriterUtility.cpp
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "WriterUtility"
+#include <utils/Log.h>
+
+#include <media/stagefright/MediaBuffer.h>
+
+#include "WriterUtility.h"
+
+int32_t sendBuffersToWriter(ifstream &inputStream, vector<BufferInfo> &bufferInfo,
+ int32_t &inputFrameId, sp<MediaAdapter> ¤tTrack, int32_t offset,
+ int32_t range, bool isPaused) {
+ while (1) {
+ if (inputFrameId >= (int)bufferInfo.size() || inputFrameId >= (offset + range)) break;
+ int32_t size = bufferInfo[inputFrameId].size;
+ char *data = (char *)malloc(size);
+ if (!data) {
+ ALOGE("Insufficient memeory to read input");
+ return -1;
+ }
+
+ inputStream.read(data, size);
+ CHECK_EQ(inputStream.gcount(), size);
+
+ sp<ABuffer> buffer = new ABuffer((void *)data, size);
+ if (buffer.get() == nullptr) {
+ ALOGE("sendBuffersToWriter() got a nullptr buffer.");
+ return -1;
+ }
+ MediaBuffer *mediaBuffer = new MediaBuffer(buffer);
+
+ // Released in MediaAdapter::signalBufferReturned().
+ mediaBuffer->add_ref();
+ mediaBuffer->set_range(buffer->offset(), buffer->size());
+
+ MetaDataBase &sampleMetaData = mediaBuffer->meta_data();
+ sampleMetaData.setInt64(kKeyTime, bufferInfo[inputFrameId].timeUs);
+ // Just set the kKeyDecodingTime as the presentation time for now.
+ sampleMetaData.setInt64(kKeyDecodingTime, bufferInfo[inputFrameId].timeUs);
+
+ if (bufferInfo[inputFrameId].flags == 1) {
+ sampleMetaData.setInt32(kKeyIsSyncFrame, true);
+ }
+
+ // This pushBuffer will wait until the mediaBuffer is consumed.
+ int status = currentTrack->pushBuffer(mediaBuffer);
+ free(data);
+ inputFrameId++;
+
+ if (OK != status) {
+ if (!isPaused) return status;
+ else {
+ ALOGD("Writer is in paused state. Input buffers won't get consumed");
+ return 0;
+ }
+ }
+ }
+ return 0;
+}
+
+int32_t writeHeaderBuffers(ifstream &inputStream, vector<BufferInfo> &bufferInfo,
+ int32_t &inputFrameId, sp<AMessage> &format, int32_t numCsds) {
+ char csdName[kMaxCSDStrlen];
+ for (int csdId = 0; csdId < numCsds; csdId++) {
+ int32_t flags = bufferInfo[inputFrameId].flags;
+ if (flags == CODEC_CONFIG_FLAG) {
+ int32_t size = bufferInfo[inputFrameId].size;
+ char *data = (char *)malloc(size);
+ if (!data) {
+ ALOGE("Insufficient memeory to read input");
+ return -1;
+ }
+ inputStream.read(data, size);
+ CHECK_EQ(inputStream.gcount(), size);
+
+ sp<ABuffer> csdBuffer = ABuffer::CreateAsCopy((void *)data, size);
+ if (csdBuffer.get() == nullptr || csdBuffer->base() == nullptr) {
+ return -1;
+ }
+ snprintf(csdName, sizeof(csdName), "csd-%d", csdId);
+ format->setBuffer(csdName, csdBuffer);
+ inputFrameId++;
+ free(data);
+ }
+ }
+ return 0;
+}
diff --git a/media/libstagefright/tests/writer/WriterUtility.h b/media/libstagefright/tests/writer/WriterUtility.h
new file mode 100644
index 0000000..cdd6246
--- /dev/null
+++ b/media/libstagefright/tests/writer/WriterUtility.h
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+#ifndef WRITER_UTILITY_H_
+#define WRITER_UTILITY_H_
+
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+#include <media/stagefright/MediaAdapter.h>
+
+using namespace android;
+using namespace std;
+
+#define CODEC_CONFIG_FLAG 32
+
+constexpr uint32_t kMaxCSDStrlen = 16;
+constexpr uint32_t kMaxCount = 20;
+
+struct BufferInfo {
+ int32_t size;
+ uint32_t flags;
+ int64_t timeUs;
+};
+
+int32_t sendBuffersToWriter(ifstream &inputStream, vector<BufferInfo> &bufferInfo,
+ int32_t &inputFrameId, sp<MediaAdapter> ¤tTrack, int32_t offset,
+ int32_t range, bool isPaused = false);
+
+int32_t writeHeaderBuffers(ifstream &inputStream, vector<BufferInfo> &bufferInfo,
+ int32_t &inputFrameId, sp<AMessage> &format, int32_t numCsds);
+
+#endif // WRITER_UTILITY_H_
diff --git a/media/libstagefright/timedtext/Android.bp b/media/libstagefright/timedtext/Android.bp
index 6935655..4f4ceb1 100644
--- a/media/libstagefright/timedtext/Android.bp
+++ b/media/libstagefright/timedtext/Android.bp
@@ -23,32 +23,4 @@
shared_libs: ["libmedia"],
}
-cc_library_static {
- name: "libstagefright_timedtext2",
- srcs: ["TextDescriptions2.cpp"],
-
- static_libs: [
- "libmediaplayer2-protos",
- "libprotobuf-cpp-lite",
- ],
-
- cflags: [
- "-Wno-multichar",
- "-Werror",
- "-Wall",
- ],
-
- sanitize: {
- misc_undefined: [
- "signed-integer-overflow",
- ],
- cfi: true,
- },
-
- include_dirs: [
- "frameworks/av/media/libstagefright",
- ],
-
- shared_libs: ["libmedia"],
-}
diff --git a/media/libstagefright/timedtext/TextDescriptions2.cpp b/media/libstagefright/timedtext/TextDescriptions2.cpp
deleted file mode 100644
index f48eacc..0000000
--- a/media/libstagefright/timedtext/TextDescriptions2.cpp
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "TextDescriptions2.h"
-#include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/MediaErrors.h>
-
-namespace android {
-
-TextDescriptions2::TextDescriptions2() {
-}
-
-status_t TextDescriptions2::getPlayerMessageOfDescriptions(
- const uint8_t *data, ssize_t size,
- uint32_t flags, int timeMs, PlayerMessage *playerMsg) {
- if (flags & IN_BAND_TEXT_3GPP) {
- if (flags & GLOBAL_DESCRIPTIONS) {
- return extract3GPPGlobalDescriptions(data, size, playerMsg);
- } else if (flags & LOCAL_DESCRIPTIONS) {
- return extract3GPPLocalDescriptions(data, size, timeMs, playerMsg);
- }
- } else if (flags & OUT_OF_BAND_TEXT_SRT) {
- if (flags & LOCAL_DESCRIPTIONS) {
- return extractSRTLocalDescriptions(data, size, timeMs, playerMsg);
- }
- }
-
- return ERROR_UNSUPPORTED;
-}
-
-// Parse the SRT text sample, and store the timing and text sample in a PlayerMessage.
-// The PlayerMessage will be sent to MediaPlayer2.java through event, and will be
-// parsed in TimedText.java.
-status_t TextDescriptions2::extractSRTLocalDescriptions(
- const uint8_t *data, ssize_t size, int timeMs, PlayerMessage *playerMsg) {
- playerMsg->add_values()->set_int32_value(KEY_LOCAL_SETTING);
- playerMsg->add_values()->set_int32_value(KEY_START_TIME);
- playerMsg->add_values()->set_int32_value(timeMs);
-
- playerMsg->add_values()->set_int32_value(KEY_STRUCT_TEXT);
- playerMsg->add_values()->set_bytes_value(data, size);
-
- return OK;
-}
-
-// Extract the local 3GPP display descriptions. 3GPP local descriptions
-// are appended to the text sample if any.
-status_t TextDescriptions2::extract3GPPLocalDescriptions(
- const uint8_t *data, ssize_t size,
- int timeMs, PlayerMessage *playerMsg) {
-
- playerMsg->add_values()->set_int32_value(KEY_LOCAL_SETTING);
-
- // write start time to display this text sample
- playerMsg->add_values()->set_int32_value(KEY_START_TIME);
- playerMsg->add_values()->set_int32_value(timeMs);
-
- if (size < 2) {
- return OK;
- }
- ssize_t textLen = (*data) << 8 | (*(data + 1));
-
- if (size < textLen + 2) {
- return OK;
- }
-
- // write text sample length and text sample itself
- playerMsg->add_values()->set_int32_value(KEY_STRUCT_TEXT);
- playerMsg->add_values()->set_bytes_value(data + 2, textLen);
-
- if (size > textLen + 2) {
- data += (textLen + 2);
- size -= (textLen + 2);
- } else {
- return OK;
- }
-
- while (size >= 8) {
- const uint8_t *tmpData = data;
- ssize_t chunkSize = U32_AT(tmpData); // size includes size and type
- uint32_t chunkType = U32_AT(tmpData + 4);
-
- if (chunkSize <= 8 || chunkSize > size) {
- return OK;
- }
-
- size_t remaining = chunkSize - 8;
-
- tmpData += 8;
-
- switch(chunkType) {
- // 'tbox' box to indicate the position of the text with values
- // of top, left, bottom and right
- case FOURCC('t', 'b', 'o', 'x'):
- {
- if (remaining < 8) {
- return OK;
- }
- playerMsg->add_values()->set_int32_value(KEY_STRUCT_TEXT_POS);
- playerMsg->add_values()->set_int32_value(U16_AT(tmpData));
- playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 2));
- playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 4));
- playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 6));
-
- tmpData += 8;
- remaining -= 8;
- break;
- }
- default:
- {
- break;
- }
- }
-
- data += chunkSize;
- size -= chunkSize;
- }
-
- return OK;
-}
-
-// To extract box 'tx3g' defined in 3GPP TS 26.245, and store it in a PlayerMessage
-status_t TextDescriptions2::extract3GPPGlobalDescriptions(
- const uint8_t *data, ssize_t size, PlayerMessage *playerMsg) {
-
- playerMsg->add_values()->set_int32_value(KEY_GLOBAL_SETTING);
-
- while (size >= 8) {
- ssize_t chunkSize = U32_AT(data);
- uint32_t chunkType = U32_AT(data + 4);
- const uint8_t *tmpData = data;
- tmpData += 8;
- size_t remaining = size - 8;
-
- if (size < chunkSize) {
- return OK;
- }
- switch(chunkType) {
- case FOURCC('t', 'x', '3', 'g'):
- {
- if (remaining < 18) {
- return OK;
- }
- // Skip DISPLAY_FLAGS, STRUCT_JUSTIFICATION, and BACKGROUND_COLOR_RGBA
- tmpData += 18;
- remaining -= 18;
-
- if (remaining < 8) {
- return OK;
- }
- playerMsg->add_values()->set_int32_value(KEY_STRUCT_TEXT_POS);
- playerMsg->add_values()->set_int32_value(U16_AT(tmpData));
- playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 2));
- playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 4));
- playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 6));
-
- tmpData += 8;
- remaining -= 18;
- // Ignore remaining data.
- break;
- }
- default:
- {
- break;
- }
- }
-
- data += chunkSize;
- size -= chunkSize;
- }
-
- return OK;
-}
-
-} // namespace android
diff --git a/media/libstagefright/timedtext/TextDescriptions2.h b/media/libstagefright/timedtext/TextDescriptions2.h
deleted file mode 100644
index 7c7d2d0..0000000
--- a/media/libstagefright/timedtext/TextDescriptions2.h
+++ /dev/null
@@ -1,88 +0,0 @@
- /*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef TEXT_DESCRIPTIONS2_H_
-
-#define TEXT_DESCRIPTIONS2_H_
-
-#include <binder/Parcel.h>
-#include <media/stagefright/foundation/ABase.h>
-
-#include "mediaplayer2.pb.h"
-
-using android::media::MediaPlayer2Proto::PlayerMessage;
-
-namespace android {
-
-class TextDescriptions2 {
-public:
- enum {
- IN_BAND_TEXT_3GPP = 0x01,
- OUT_OF_BAND_TEXT_SRT = 0x02,
-
- GLOBAL_DESCRIPTIONS = 0x100,
- LOCAL_DESCRIPTIONS = 0x200,
- };
-
- static status_t getPlayerMessageOfDescriptions(
- const uint8_t *data, ssize_t size,
- uint32_t flags, int timeMs, PlayerMessage *playerMsg);
-private:
- TextDescriptions2();
-
- enum {
- // These keys must be in sync with the keys in TimedText.java
- KEY_DISPLAY_FLAGS = 1, // int
- KEY_STYLE_FLAGS = 2, // int
- KEY_BACKGROUND_COLOR_RGBA = 3, // int
- KEY_HIGHLIGHT_COLOR_RGBA = 4, // int
- KEY_SCROLL_DELAY = 5, // int
- KEY_WRAP_TEXT = 6, // int
- KEY_START_TIME = 7, // int
- KEY_STRUCT_BLINKING_TEXT_LIST = 8, // List<CharPos>
- KEY_STRUCT_FONT_LIST = 9, // List<Font>
- KEY_STRUCT_HIGHLIGHT_LIST = 10, // List<CharPos>
- KEY_STRUCT_HYPER_TEXT_LIST = 11, // List<HyperText>
- KEY_STRUCT_KARAOKE_LIST = 12, // List<Karaoke>
- KEY_STRUCT_STYLE_LIST = 13, // List<Style>
- KEY_STRUCT_TEXT_POS = 14, // TextPos
- KEY_STRUCT_JUSTIFICATION = 15, // Justification
- KEY_STRUCT_TEXT = 16, // Text
-
- KEY_GLOBAL_SETTING = 101,
- KEY_LOCAL_SETTING = 102,
- KEY_START_CHAR = 103,
- KEY_END_CHAR = 104,
- KEY_FONT_ID = 105,
- KEY_FONT_SIZE = 106,
- KEY_TEXT_COLOR_RGBA = 107,
- };
-
- static status_t extractSRTLocalDescriptions(
- const uint8_t *data, ssize_t size,
- int timeMs, PlayerMessage *playerMsg);
- static status_t extract3GPPGlobalDescriptions(
- const uint8_t *data, ssize_t size,
- PlayerMessage *playerMsg);
- static status_t extract3GPPLocalDescriptions(
- const uint8_t *data, ssize_t size,
- int timeMs, PlayerMessage *playerMsg);
-
- DISALLOW_EVIL_CONSTRUCTORS(TextDescriptions2);
-};
-
-} // namespace android
-#endif // TEXT_DESCRIPTIONS2_H_
diff --git a/media/libstagefright/webm/Android.bp b/media/libstagefright/webm/Android.bp
index 64ecc2d..2cebe8f 100644
--- a/media/libstagefright/webm/Android.bp
+++ b/media/libstagefright/webm/Android.bp
@@ -27,12 +27,14 @@
include_dirs: ["frameworks/av/include"],
shared_libs: [
+ "libdatasource",
"libstagefright_foundation",
"libutils",
"liblog",
],
header_libs: [
+ "libmedia_headers",
"media_ndk_headers",
],
}
diff --git a/media/libstagefright/webm/WebmFrameThread.cpp b/media/libstagefright/webm/WebmFrameThread.cpp
index 631a2ab..59ce8db 100644
--- a/media/libstagefright/webm/WebmFrameThread.cpp
+++ b/media/libstagefright/webm/WebmFrameThread.cpp
@@ -321,6 +321,7 @@
status_t WebmFrameMediaSourceThread::pause() {
if (mStarted) {
mPaused = true;
+ mResumed = false;
}
return OK;
}
diff --git a/media/libstagefright/webm/WebmFrameThread.h b/media/libstagefright/webm/WebmFrameThread.h
index 1ddaf9a..5aa6feb 100644
--- a/media/libstagefright/webm/WebmFrameThread.h
+++ b/media/libstagefright/webm/WebmFrameThread.h
@@ -20,8 +20,8 @@
#include "WebmFrame.h"
#include "LinkedBlockingQueue.h"
-#include <media/MediaSource.h>
-#include <media/stagefright/FileSource.h>
+#include <datasource/FileSource.h>
+#include <media/stagefright/MediaSource.h>
#include <utils/List.h>
#include <utils/Errors.h>
diff --git a/media/libstagefright/webm/WebmWriter.h b/media/libstagefright/webm/WebmWriter.h
index ffe4c79..ed5bc4c 100644
--- a/media/libstagefright/webm/WebmWriter.h
+++ b/media/libstagefright/webm/WebmWriter.h
@@ -21,7 +21,7 @@
#include "WebmFrameThread.h"
#include "LinkedBlockingQueue.h"
-#include <media/MediaSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MediaWriter.h>
#include <utils/Errors.h>
diff --git a/media/libstagefright/webm/tests/Android.bp b/media/libstagefright/webm/tests/Android.bp
new file mode 100644
index 0000000..5183a49
--- /dev/null
+++ b/media/libstagefright/webm/tests/Android.bp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+cc_test {
+ name: "WebmFrameThreadUnitTest",
+ gtest: true,
+
+ srcs: [
+ "WebmFrameThreadUnitTest.cpp",
+ ],
+
+ include_dirs: [
+ "frameworks/av/media/libstagefright",
+ ],
+
+ static_libs: [
+ "libdatasource",
+ "libstagefright",
+ "libstagefright_webm",
+ "libstagefright_foundation",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "liblog",
+ "libutils",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ sanitize: {
+ cfi: true,
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ },
+}
diff --git a/media/libstagefright/webm/tests/README.md b/media/libstagefright/webm/tests/README.md
new file mode 100644
index 0000000..2e74f34
--- /dev/null
+++ b/media/libstagefright/webm/tests/README.md
@@ -0,0 +1,26 @@
+## Media Testing ##
+---
+#### Webm Writer Utility Tests :
+The Webm Writer Utility Test Suite validates the APIs being used by the WebmWriter.
+
+Run the following steps to build the test suite:
+```
+mmm frameworks/av/media/libstagefright/webm/tests/
+```
+
+The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/
+
+The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/
+
+#### WebmFrameThread
+To test 64-bit binary push binaries from nativetest64.
+
+adb push ${OUT}/data/nativetest64/WebmFrameThreadUnitTest/WebmFrameThreadUnitTest /data/local/tmp/
+
+To test 32-bit binary push binaries from nativetest.
+
+adb push ${OUT}/data/nativetest/WebmFrameThreadUnitTest/WebmFrameThreadUnitTest /data/local/tmp/
+
+```
+adb shell /data/local/tmp/WebmFrameThreadUnitTest
+```
diff --git a/media/libstagefright/webm/tests/WebmFrameThreadUnitTest.cpp b/media/libstagefright/webm/tests/WebmFrameThreadUnitTest.cpp
new file mode 100644
index 0000000..89cd2ca
--- /dev/null
+++ b/media/libstagefright/webm/tests/WebmFrameThreadUnitTest.cpp
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "WebmFrameThreadUnitTest"
+#include <utils/Log.h>
+
+#include <gtest/gtest.h>
+
+#include <media/stagefright/MediaAdapter.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/OpusHeader.h>
+
+#include "webm/EbmlUtil.h"
+#include "webm/WebmConstants.h"
+#include "webm/WebmFrameThread.h"
+
+using namespace android;
+using namespace webm;
+
+static constexpr int32_t kVideoIdx = 0;
+static constexpr int32_t kAudioIdx = 1;
+static constexpr int32_t kMaxStreamCount = 2;
+
+static constexpr int32_t kCsdSize = 32;
+static constexpr int32_t kFrameSize = 128;
+
+static constexpr int32_t kMaxLoopCount = 20;
+static constexpr int32_t kNumFramesToWrite = 32;
+static constexpr int32_t kSyncFrameInterval = 10;
+static constexpr uint64_t kDefaultTimeCodeScaleUs = 1000000; /* 1sec */
+
+#define OUTPUT_FILE_NAME "/data/local/tmp/webmFrameThreadOutput.webm"
+
+// LookUpTable of clips and metadata for component testing
+static const struct InputData {
+ const char *mime;
+ int32_t firstParam;
+ int32_t secondParam;
+ bool isAudio;
+} kInputData[] = {
+ {MEDIA_MIMETYPE_AUDIO_OPUS, 48000, 6, true},
+ {MEDIA_MIMETYPE_AUDIO_VORBIS, 44100, 1, true},
+ {MEDIA_MIMETYPE_VIDEO_VP9, 176, 144, false},
+ {MEDIA_MIMETYPE_VIDEO_VP8, 1920, 1080, false},
+};
+
+class WebmFrameThreadUnitTest : public ::testing::TestWithParam<std::pair<int32_t, int32_t>> {
+ public:
+ WebmFrameThreadUnitTest()
+ : mSinkThread(nullptr), mAudioThread(nullptr), mVideoThread(nullptr), mSource{} {}
+
+ ~WebmFrameThreadUnitTest() {
+ if (mSinkThread) mSinkThread.clear();
+ if (mAudioThread) mAudioThread.clear();
+ if (mVideoThread) mVideoThread.clear();
+ }
+
+ virtual void SetUp() override {
+ mSegmentDataStart = 0;
+ mFd = open(OUTPUT_FILE_NAME, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
+ ASSERT_GE(mFd, 0) << "Failed to open output file " << OUTPUT_FILE_NAME;
+ }
+
+ virtual void TearDown() override {
+ if (mFd >= 0) close(mFd);
+ for (int32_t idx = 0; idx < kMaxStreamCount; idx++) {
+ if (mSource[idx] != nullptr) {
+ mSource[idx].clear();
+ }
+ }
+ mVSink.clear();
+ mASink.clear();
+ mCuePoints.clear();
+ }
+
+ void addTrack(bool isAudio, int32_t index);
+ void writeFileData(int32_t inputFrameId, int32_t range);
+
+ void createWebmThreads(std::initializer_list<int32_t> indexList);
+ void startWebmFrameThreads();
+ void stopWebmFrameThreads();
+
+ int32_t mFd;
+ uint64_t mSegmentDataStart;
+
+ sp<WebmFrameSinkThread> mSinkThread;
+ sp<WebmFrameSourceThread> mAudioThread;
+ sp<WebmFrameSourceThread> mVideoThread;
+
+ List<sp<WebmElement>> mCuePoints;
+ sp<MediaAdapter> mSource[kMaxStreamCount];
+ LinkedBlockingQueue<const sp<WebmFrame>> mVSink;
+ LinkedBlockingQueue<const sp<WebmFrame>> mASink;
+};
+
+void writeAudioHeaderData(const sp<AMessage> &format, const char *mimeType) {
+ if (strncasecmp(mimeType, MEDIA_MIMETYPE_AUDIO_OPUS, strlen(MEDIA_MIMETYPE_AUDIO_OPUS) + 1) &&
+ strncasecmp(mimeType, MEDIA_MIMETYPE_AUDIO_VORBIS,
+ strlen(MEDIA_MIMETYPE_AUDIO_VORBIS) + 1)) {
+ ASSERT_TRUE(false) << "Unsupported mime type";
+ }
+
+ // Dummy CSD buffers for Opus and Vorbis
+ char csdBuffer[kCsdSize];
+ memset(csdBuffer, 0xFF, sizeof(csdBuffer));
+
+ sp<ABuffer> csdBuffer0 = ABuffer::CreateAsCopy((void *)csdBuffer, kCsdSize);
+ ASSERT_NE(csdBuffer0.get(), nullptr) << "Unable to allocate buffer for CSD0 data";
+ ASSERT_NE(csdBuffer0->base(), nullptr) << "ABuffer base is null for CSD0";
+
+ sp<ABuffer> csdBuffer1 = ABuffer::CreateAsCopy((void *)csdBuffer, kCsdSize);
+ ASSERT_NE(csdBuffer1.get(), nullptr) << "Unable to allocate buffer for CSD1 data";
+ ASSERT_NE(csdBuffer1->base(), nullptr) << "ABuffer base is null for CSD1";
+
+ sp<ABuffer> csdBuffer2 = ABuffer::CreateAsCopy((void *)csdBuffer, kCsdSize);
+ ASSERT_NE(csdBuffer2.get(), nullptr) << "Unable to allocate buffer for CSD2 data";
+ ASSERT_NE(csdBuffer2->base(), nullptr) << "ABuffer base is null for CSD2";
+
+ format->setBuffer("csd-0", csdBuffer0);
+ format->setBuffer("csd-1", csdBuffer1);
+ format->setBuffer("csd-2", csdBuffer2);
+}
+
+void WebmFrameThreadUnitTest::addTrack(bool isAudio, int32_t index) {
+ ASSERT_LT(index, sizeof(kInputData) / sizeof(kInputData[0]))
+ << "Invalid index for loopup table";
+
+ sp<AMessage> format = new AMessage;
+ format->setString("mime", kInputData[index].mime);
+ if (!isAudio) {
+ format->setInt32("width", kInputData[index].firstParam);
+ format->setInt32("height", kInputData[index].secondParam);
+ } else {
+ format->setInt32("sample-rate", kInputData[index].firstParam);
+ format->setInt32("channel-count", kInputData[index].secondParam);
+ ASSERT_NO_FATAL_FAILURE(writeAudioHeaderData(format, kInputData[index].mime));
+ }
+
+ sp<MetaData> trackMeta = new MetaData;
+ convertMessageToMetaData(format, trackMeta);
+
+ if (!isAudio) {
+ mSource[kVideoIdx] = new MediaAdapter(trackMeta);
+ ASSERT_NE(mSource[kVideoIdx], nullptr) << "Unable to create source";
+ } else {
+ mSource[kAudioIdx] = new MediaAdapter(trackMeta);
+ ASSERT_NE(mSource[kAudioIdx], nullptr) << "Unable to create source";
+ }
+}
+
+void WebmFrameThreadUnitTest::createWebmThreads(std::initializer_list<int32_t> indexList) {
+ mSinkThread = new WebmFrameSinkThread(mFd, mSegmentDataStart, mVSink, mASink, mCuePoints);
+ ASSERT_NE(mSinkThread, nullptr) << "Failed to create Sink Thread";
+
+ bool isAudio;
+ // MultiTrack input
+ for (int32_t index : indexList) {
+ isAudio = kInputData[index].isAudio;
+ ASSERT_NO_FATAL_FAILURE(addTrack(isAudio, index));
+ if (!isAudio) {
+ mVideoThread = new WebmFrameMediaSourceThread(mSource[kVideoIdx], kVideoType, mVSink,
+ kDefaultTimeCodeScaleUs, 0, 0, 1, 0);
+ } else {
+ mAudioThread = new WebmFrameMediaSourceThread(mSource[kAudioIdx], kAudioType, mASink,
+ kDefaultTimeCodeScaleUs, 0, 0, 1, 0);
+ }
+ }
+ // To handle single track file
+ if (!mVideoThread) {
+ mVideoThread = new WebmFrameEmptySourceThread(kVideoType, mVSink);
+ } else if (!mAudioThread) {
+ mAudioThread = new WebmFrameEmptySourceThread(kAudioType, mASink);
+ }
+ ASSERT_NE(mVideoThread, nullptr) << "Failed to create Video Thread";
+ ASSERT_NE(mAudioThread, nullptr) << "Failed to create Audio Thread";
+}
+
+void WebmFrameThreadUnitTest::startWebmFrameThreads() {
+ status_t status = mAudioThread->start();
+ ASSERT_EQ(status, AMEDIA_OK) << "Failed to start Audio Thread";
+ status = mVideoThread->start();
+ ASSERT_EQ(status, AMEDIA_OK) << "Failed to start Video Thread";
+ status = mSinkThread->start();
+ ASSERT_EQ(status, AMEDIA_OK) << "Failed to start Sink Thread";
+}
+
+void WebmFrameThreadUnitTest::stopWebmFrameThreads() {
+ status_t status = mAudioThread->stop();
+ ASSERT_EQ(status, AMEDIA_OK) << "Failed to stop Audio Thread";
+ status = mVideoThread->stop();
+ ASSERT_EQ(status, AMEDIA_OK) << "Failed to stop Video Thread";
+ status = mSinkThread->stop();
+ ASSERT_EQ(status, AMEDIA_OK) << "Failed to stop Sink Thread";
+}
+
+// Write dummy data to a file
+void WebmFrameThreadUnitTest::writeFileData(int32_t inputFrameId, int32_t range) {
+ char data[kFrameSize];
+ memset(data, 0xFF, sizeof(data));
+ int32_t status = OK;
+ do {
+ // Queue frames for both A/V tracks
+ for (int32_t idx = kVideoIdx; idx < kMaxStreamCount; idx++) {
+ sp<ABuffer> buffer = new ABuffer((void *)data, kFrameSize);
+ ASSERT_NE(buffer.get(), nullptr) << "ABuffer returned nullptr";
+
+ // Released in MediaAdapter::signalBufferReturned().
+ MediaBuffer *mediaBuffer = new MediaBuffer(buffer);
+ ASSERT_NE(mediaBuffer, nullptr) << "MediaBuffer returned nullptr";
+
+ mediaBuffer->add_ref();
+ mediaBuffer->set_range(buffer->offset(), buffer->size());
+
+ MetaDataBase &sampleMetaData = mediaBuffer->meta_data();
+ sampleMetaData.setInt64(kKeyTime, inputFrameId * kDefaultTimeCodeScaleUs);
+
+ // For audio codecs, treat all frame as sync frame
+ if ((idx == kAudioIdx) || (inputFrameId % kSyncFrameInterval == 0)) {
+ sampleMetaData.setInt32(kKeyIsSyncFrame, true);
+ }
+
+ // This pushBuffer will wait until the mediaBuffer is consumed.
+ if (mSource[idx] != nullptr) {
+ status = mSource[idx]->pushBuffer(mediaBuffer);
+ }
+ ASSERT_EQ(status, OK);
+ }
+ inputFrameId++;
+ } while (inputFrameId < range);
+}
+
+TEST_P(WebmFrameThreadUnitTest, WriteTest) {
+ int32_t index1 = GetParam().first;
+ int32_t index2 = GetParam().second;
+ ASSERT_NO_FATAL_FAILURE(createWebmThreads({index1, index2}));
+
+ ASSERT_NO_FATAL_FAILURE(startWebmFrameThreads());
+
+ ASSERT_NO_FATAL_FAILURE(writeFileData(0, kNumFramesToWrite));
+
+ if (mSource[kAudioIdx]) mSource[kAudioIdx]->stop();
+ if (mSource[kVideoIdx]) mSource[kVideoIdx]->stop();
+
+ ASSERT_NO_FATAL_FAILURE(stopWebmFrameThreads());
+}
+
+TEST_P(WebmFrameThreadUnitTest, PauseTest) {
+ int32_t index1 = GetParam().first;
+ int32_t index2 = GetParam().second;
+ ASSERT_NO_FATAL_FAILURE(createWebmThreads({index1, index2}));
+
+ ASSERT_NO_FATAL_FAILURE(startWebmFrameThreads());
+
+ int32_t offset = 0;
+ ASSERT_NO_FATAL_FAILURE(writeFileData(offset, kNumFramesToWrite));
+ offset += kNumFramesToWrite;
+
+ for (int idx = 0; idx < kMaxLoopCount; idx++) {
+ // pause the threads
+ status_t status = mAudioThread->pause();
+ ASSERT_EQ(status, AMEDIA_OK) << "Failed to pause Audio Thread";
+ status = mVideoThread->pause();
+ ASSERT_EQ(status, AMEDIA_OK) << "Failed to pause Video Thread";
+
+ // Under pause state, no write should happen
+ ASSERT_NO_FATAL_FAILURE(writeFileData(offset, kNumFramesToWrite));
+ offset += kNumFramesToWrite;
+
+ status = mAudioThread->resume();
+ ASSERT_EQ(status, AMEDIA_OK) << "Failed to resume Audio Thread";
+ status = mVideoThread->resume();
+ ASSERT_EQ(status, AMEDIA_OK) << "Failed to resume Video Thread";
+
+ ASSERT_NO_FATAL_FAILURE(writeFileData(offset, kNumFramesToWrite));
+ offset += kNumFramesToWrite;
+ }
+
+ if (mSource[kAudioIdx]) mSource[kAudioIdx]->stop();
+ if (mSource[kVideoIdx]) mSource[kVideoIdx]->stop();
+ ASSERT_NO_FATAL_FAILURE(stopWebmFrameThreads());
+}
+
+INSTANTIATE_TEST_SUITE_P(WebmFrameThreadUnitTestAll, WebmFrameThreadUnitTest,
+ ::testing::Values(std::make_pair(0, 1), std::make_pair(0, 2),
+ std::make_pair(0, 3), std::make_pair(1, 0),
+ std::make_pair(1, 2), std::make_pair(1, 3),
+ std::make_pair(2, 3)));
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGV("Test result = %d\n", status);
+ return status;
+}
diff --git a/media/libstagefright/xmlparser/Android.bp b/media/libstagefright/xmlparser/Android.bp
index 38de831..7ed0e88 100644
--- a/media/libstagefright/xmlparser/Android.bp
+++ b/media/libstagefright/xmlparser/Android.bp
@@ -10,6 +10,7 @@
vndk: {
enabled: true,
},
+ double_loadable: true,
srcs: [
"MediaCodecsXmlParser.cpp",
diff --git a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
index 9783e9b..a232150 100644
--- a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
+++ b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
@@ -21,6 +21,7 @@
#include <android-base/logging.h>
#include <android-base/macros.h>
+#include <android-base/properties.h>
#include <utils/Log.h>
#include <media/stagefright/MediaErrors.h>
@@ -38,8 +39,6 @@
namespace android {
-using MCXP = MediaCodecsXmlParser;
-
namespace {
bool fileExists(const std::string &path) {
@@ -118,8 +117,8 @@
}
}
-MCXP::StringSet parseCommaSeparatedStringSet(const char *s) {
- MCXP::StringSet result;
+MediaCodecsXmlParser::StringSet parseCommaSeparatedStringSet(const char *s) {
+ MediaCodecsXmlParser::StringSet result;
for (const char *ptr = s ? : ""; *ptr; ) {
const char *end = strchrnul(ptr, ',');
if (ptr != end) { // skip empty values
@@ -136,6 +135,23 @@
} // unnamed namespace
+std::vector<std::string> MediaCodecsXmlParser::getDefaultXmlNames() {
+ static constexpr char const* prefixes[] = {
+ "media_codecs",
+ "media_codecs_performance"
+ };
+ static std::vector<std::string> variants = {
+ android::base::GetProperty("ro.media.xml_variant.codecs", ""),
+ android::base::GetProperty("ro.media.xml_variant.codecs_performance", "")
+ };
+ static std::vector<std::string> names = {
+ prefixes[0] + variants[0] + ".xml",
+ prefixes[1] + variants[1] + ".xml"
+ };
+ return names;
+}
+
+
struct MediaCodecsXmlParser::Impl {
// status + error message
struct Result {
@@ -1269,7 +1285,7 @@
void MediaCodecsXmlParser::Impl::State::addDetail(
const std::string &key, const std::string &value) {
CHECK(inType());
- ALOGI("limit: %s = %s", key.c_str(), value.c_str());
+ ALOGV("limit: %s = %s", key.c_str(), value.c_str());
const StringSet &variants = mVariantsStack.back();
if (variants.empty()) {
type()[key] = value;
diff --git a/media/libstagefright/xmlparser/include/media/stagefright/xmlparser/MediaCodecsXmlParser.h b/media/libstagefright/xmlparser/include/media/stagefright/xmlparser/MediaCodecsXmlParser.h
index b666de4..e224452 100644
--- a/media/libstagefright/xmlparser/include/media/stagefright/xmlparser/MediaCodecsXmlParser.h
+++ b/media/libstagefright/xmlparser/include/media/stagefright/xmlparser/MediaCodecsXmlParser.h
@@ -33,13 +33,17 @@
class MediaCodecsXmlParser {
public:
- // Treblized media codec list will be located in /odm/etc or /vendor/etc.
+ // Treblized media codec list will be located in /product/etc, /odm/etc or
+ // /vendor/etc.
static std::vector<std::string> getDefaultSearchDirs() {
- return { "/odm/etc", "/vendor/etc", "/etc" };
+ return { "/product/etc",
+ "/odm/etc",
+ "/vendor/etc",
+ "/system/etc" };
}
- static std::vector<std::string> getDefaultXmlNames() {
- return { "media_codecs.xml", "media_codecs_performance.xml" };
- }
+
+ static std::vector<std::string> getDefaultXmlNames();
+
static constexpr char const* defaultProfilingResultsXmlPath =
"/data/misc/media/media_codecs_profiling_results.xml";
diff --git a/media/libwatchdog/Android.bp b/media/libwatchdog/Android.bp
new file mode 100644
index 0000000..2aefa7d
--- /dev/null
+++ b/media/libwatchdog/Android.bp
@@ -0,0 +1,34 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library {
+ name: "libwatchdog",
+ srcs: [
+ "Watchdog.cpp",
+ ],
+ export_include_dirs: ["include"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ ],
+ target: {
+ windows: {
+ enabled: false,
+ },
+ darwin: {
+ enabled: false,
+ },
+ },
+ apex_available: ["com.android.media"],
+}
diff --git a/media/libwatchdog/Watchdog.cpp b/media/libwatchdog/Watchdog.cpp
new file mode 100644
index 0000000..bb012b9
--- /dev/null
+++ b/media/libwatchdog/Watchdog.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Watchdog"
+
+#include <watchdog/Watchdog.h>
+
+#include <android-base/logging.h>
+#include <android-base/threads.h>
+#include <signal.h>
+#include <time.h>
+#include <cstring>
+#include <utils/Log.h>
+
+namespace android {
+
+Watchdog::Watchdog(::std::chrono::steady_clock::duration timeout) {
+ // Create the timer.
+ struct sigevent sev;
+ sev.sigev_notify = SIGEV_THREAD_ID;
+ sev.sigev_notify_thread_id = base::GetThreadId();
+ sev.sigev_signo = SIGABRT;
+ sev.sigev_value.sival_ptr = &mTimerId;
+ int err = timer_create(CLOCK_MONOTONIC, &sev, &mTimerId);
+ if (err != 0) {
+ PLOG(FATAL) << "Failed to create timer";
+ }
+
+ // Start the timer.
+ struct itimerspec spec;
+ memset(&spec, 0, sizeof(spec));
+ auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(timeout);
+ LOG_ALWAYS_FATAL_IF(timeout.count() <= 0, "Duration must be positive");
+ spec.it_value.tv_sec = ns.count() / 1000000000;
+ spec.it_value.tv_nsec = ns.count() % 1000000000;
+ err = timer_settime(mTimerId, 0, &spec, nullptr);
+ if (err != 0) {
+ PLOG(FATAL) << "Failed to start timer";
+ }
+}
+
+Watchdog::~Watchdog() {
+ // Delete the timer.
+ int err = timer_delete(mTimerId);
+ if (err != 0) {
+ PLOG(FATAL) << "Failed to delete timer";
+ }
+}
+
+} // namespace android
diff --git a/media/libwatchdog/include/watchdog/Watchdog.h b/media/libwatchdog/include/watchdog/Watchdog.h
new file mode 100644
index 0000000..2819f8a
--- /dev/null
+++ b/media/libwatchdog/include/watchdog/Watchdog.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_WATCHDOG_H
+#define ANDROID_WATCHDOG_H
+
+#include <chrono>
+#include <time.h>
+
+namespace android {
+
+/*
+ * An RAII-style object, which would crash the process if a timeout expires
+ * before the object is destroyed.
+ * The calling thread would be sent a SIGABORT, which would typically result in
+ * a stack trace.
+ *
+ * Sample usage:
+ * {
+ * Watchdog watchdog(std::chrono::milliseconds(10));
+ * DoSomething();
+ * }
+ * // If we got here, the function completed in time.
+ */
+class Watchdog final {
+public:
+ Watchdog(std::chrono::steady_clock::duration timeout);
+ ~Watchdog();
+
+private:
+ timer_t mTimerId;
+};
+
+} // namespace android
+
+#endif // ANDROID_WATCHDOG_H
diff --git a/media/mediaserver/manifest_media_c2_software.xml b/media/mediaserver/manifest_media_c2_software.xml
index 5196336..f23ed446 100644
--- a/media/mediaserver/manifest_media_c2_software.xml
+++ b/media/mediaserver/manifest_media_c2_software.xml
@@ -2,7 +2,7 @@
<hal>
<name>android.hardware.media.c2</name>
<transport>hwbinder</transport>
- <version>1.0</version>
+ <version>1.1</version>
<interface>
<name>IComponentStore</name>
<instance>software</instance>
diff --git a/media/mediaserver/mediaserver.rc b/media/mediaserver/mediaserver.rc
index f6c325c..ecb75a9 100644
--- a/media/mediaserver/mediaserver.rc
+++ b/media/mediaserver/mediaserver.rc
@@ -1,3 +1,6 @@
+on property:init.svc.media=*
+ setprop init.svc.mediadrm ${init.svc.media}
+
service media /system/bin/mediaserver
class main
user media
diff --git a/media/mtp/IMtpHandle.h b/media/mtp/IMtpHandle.h
index fd14b18..0435e82 100644
--- a/media/mtp/IMtpHandle.h
+++ b/media/mtp/IMtpHandle.h
@@ -16,7 +16,7 @@
#ifndef _IMTP_HANDLE_H
#define _IMTP_HANDLE_H
-#include <linux/usb/f_mtp.h>
+#include "f_mtp.h"
namespace android {
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index ca8cb78..8677b90 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -42,8 +42,10 @@
#include "MtpServer.h"
#include "MtpStorage.h"
#include "MtpStringBuffer.h"
+#include "android-base/strings.h"
namespace android {
+static const int SN_EVENT_LOG_ID = 0x534e4554;
static const MtpOperationCode kSupportedOperationCodes[] = {
MTP_OPERATION_GET_DEVICE_INFO,
@@ -82,8 +84,8 @@
// MTP_OPERATION_SET_OBJECT_PROP_LIST,
// MTP_OPERATION_GET_INTERDEPENDENT_PROP_DESC,
// MTP_OPERATION_SEND_OBJECT_PROP_LIST,
- MTP_OPERATION_GET_OBJECT_REFERENCES,
- MTP_OPERATION_SET_OBJECT_REFERENCES,
+// MTP_OPERATION_GET_OBJECT_REFERENCES,
+// MTP_OPERATION_SET_OBJECT_REFERENCES,
// MTP_OPERATION_SKIP,
// Android extension for direct file IO
MTP_OPERATION_GET_PARTIAL_OBJECT_64,
@@ -955,12 +957,28 @@
if (!mData.getString(modified)) return MTP_RESPONSE_INVALID_PARAMETER; // date modified
// keywords follow
+ int type = storage->getType();
+ if (type == MTP_STORAGE_REMOVABLE_RAM) {
+ std::string str = android::base::Trim((const char*)name);
+ name.set(str.c_str());
+ }
ALOGV("name: %s format: 0x%04X (%s)\n", (const char*)name, format,
MtpDebug::getFormatCodeName(format));
time_t modifiedTime;
if (!parseDateTime(modified, modifiedTime))
modifiedTime = 0;
+ if ((strcmp(name, ".") == 0) || (strcmp(name, "..") == 0) ||
+ (strchr(name, '/') != NULL)) {
+ char errMsg[80];
+
+ snprintf(errMsg, sizeof(errMsg), "Invalid name: %s", (const char *) name);
+ ALOGE("%s (b/130656917)", errMsg);
+ android_errorWriteWithInfoLog(SN_EVENT_LOG_ID, "130656917", -1, errMsg,
+ strlen(errMsg));
+
+ return MTP_RESPONSE_INVALID_PARAMETER;
+ }
if (path[path.size() - 1] != '/')
path.append("/");
path.append(name);
diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h
index 1f8799f..8cc9a9a 100644
--- a/media/mtp/MtpServer.h
+++ b/media/mtp/MtpServer.h
@@ -34,8 +34,11 @@
class IMtpDatabase;
class MtpStorage;
+class MtpMockServer;
class MtpServer {
+ // libFuzzer testing
+ friend class MtpMockServer;
private:
IMtpDatabase* mDatabase;
diff --git a/media/mtp/MtpStringBuffer.cpp b/media/mtp/MtpStringBuffer.cpp
index cd379bf..d8d425b 100644
--- a/media/mtp/MtpStringBuffer.cpp
+++ b/media/mtp/MtpStringBuffer.cpp
@@ -26,14 +26,31 @@
namespace {
-std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> gConvert;
+const char * utf16_cerror = "__CONVERSION_ERROR__";
+const char16_t * utf8_cerror = u"__CONVERSION_ERROR__";
+
+std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> gConvert(utf16_cerror, utf8_cerror);
static std::string utf16ToUtf8(std::u16string input_str) {
- return gConvert.to_bytes(input_str);
+ std::string conversion = gConvert.to_bytes(input_str);
+
+ if (conversion == utf16_cerror) {
+ ALOGE("Unable to convert UTF-16 string to UTF-8");
+ return "";
+ } else {
+ return conversion;
+ }
}
static std::u16string utf8ToUtf16(std::string input_str) {
- return gConvert.from_bytes(input_str);
+ std::u16string conversion = gConvert.from_bytes(input_str);
+
+ if (conversion == utf8_cerror) {
+ ALOGE("Unable to convert UTF-8 string to UTF-16");
+ return u"";
+ } else {
+ return conversion;
+ }
}
} // namespace
diff --git a/media/mtp/MtpUtils.cpp b/media/mtp/MtpUtils.cpp
index 8564576..84a20d3 100644
--- a/media/mtp/MtpUtils.cpp
+++ b/media/mtp/MtpUtils.cpp
@@ -150,6 +150,7 @@
ret += copyFile(oldFile.c_str(), newFile.c_str());
}
}
+ closedir(dir);
return ret;
}
diff --git a/media/mtp/PosixAsyncIO.cpp b/media/mtp/PosixAsyncIO.cpp
index 72c07cc..8205e3b 100644
--- a/media/mtp/PosixAsyncIO.cpp
+++ b/media/mtp/PosixAsyncIO.cpp
@@ -47,10 +47,10 @@
CHECK(aiocbp->queued);
int ret;
if (aiocbp->read) {
- ret = TEMP_FAILURE_RETRY(pread(aiocbp->aio_fildes,
+ ret = TEMP_FAILURE_RETRY(pread64(aiocbp->aio_fildes,
aiocbp->aio_buf, aiocbp->aio_nbytes, aiocbp->aio_offset));
} else {
- ret = TEMP_FAILURE_RETRY(pwrite(aiocbp->aio_fildes,
+ ret = TEMP_FAILURE_RETRY(pwrite64(aiocbp->aio_fildes,
aiocbp->aio_buf, aiocbp->aio_nbytes, aiocbp->aio_offset));
}
{
@@ -139,7 +139,7 @@
return 0;
}
-void aio_prepare(struct aiocb *aiocbp, void* buf, size_t count, off_t offset) {
+void aio_prepare(struct aiocb *aiocbp, void* buf, size_t count, off64_t offset) {
aiocbp->aio_buf = buf;
aiocbp->aio_offset = offset;
aiocbp->aio_nbytes = count;
diff --git a/media/mtp/PosixAsyncIO.h b/media/mtp/PosixAsyncIO.h
index 2bb5735..2bcae4c 100644
--- a/media/mtp/PosixAsyncIO.h
+++ b/media/mtp/PosixAsyncIO.h
@@ -32,7 +32,7 @@
int aio_fildes;
void *aio_buf;
- off_t aio_offset;
+ off64_t aio_offset;
size_t aio_nbytes;
// Used internally
@@ -61,7 +61,7 @@
ssize_t aio_return(struct aiocb *);
// Helper method for setting aiocb members
-void aio_prepare(struct aiocb *, void*, size_t, off_t);
+void aio_prepare(struct aiocb *, void*, size_t, off64_t);
#endif // POSIXASYNCIO_H
diff --git a/media/mtp/f_mtp.h b/media/mtp/f_mtp.h
new file mode 100644
index 0000000..22ec771
--- /dev/null
+++ b/media/mtp/f_mtp.h
@@ -0,0 +1,43 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ *** This header was automatically generated from a Linux kernel header
+ *** of the same name, to make information necessary for userspace to
+ *** call into the kernel available to libc. It contains only constants,
+ *** structures, and macros generated from the original header, and thus,
+ *** contains no copyrightable information.
+ ***
+ *** To edit the content of this header, modify the corresponding
+ *** source file (e.g. under external/kernel-headers/original/) then
+ *** run bionic/libc/kernel/tools/update_all.py
+ ***
+ *** Any manual change here will be lost the next time this script will
+ *** be run. You've been warned!
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _UAPI_LINUX_USB_F_MTP_H
+#define _UAPI_LINUX_USB_F_MTP_H
+#include <linux/ioctl.h>
+#include <linux/types.h>
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+struct mtp_file_range {
+ int fd;
+ loff_t offset;
+ int64_t length;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ uint16_t command;
+ uint32_t transaction_id;
+};
+struct mtp_event {
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ size_t length;
+ void * data;
+};
+#define MTP_SEND_FILE _IOW('M', 0, struct mtp_file_range)
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define MTP_RECEIVE_FILE _IOW('M', 1, struct mtp_file_range)
+#define MTP_SEND_EVENT _IOW('M', 3, struct mtp_event)
+#define MTP_SEND_FILE_WITH_HEADER _IOW('M', 4, struct mtp_file_range)
+#endif
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index 9c7a630..a04a962 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -42,6 +42,7 @@
name: "libmediandk",
srcs: [
+ "NdkJavaVMHelper.cpp",
"NdkMediaCodec.cpp",
"NdkMediaCrypto.cpp",
"NdkMediaDataSource.cpp",
@@ -54,7 +55,6 @@
],
include_dirs: [
- "bionic/libc/private",
"frameworks/base/core/jni",
"frameworks/native/include/media/openmax",
"system/media/camera/include",
@@ -70,28 +70,32 @@
"libgrallocusage",
],
+ header_libs: [
+ "libmediadrm_headers",
+ "libmediametrics_headers",
+ ],
+
shared_libs: [
"android.hardware.graphics.bufferqueue@1.0",
"android.hidl.token@1.0-utils",
"libandroid_runtime_lazy",
"libbase",
- "libbinder",
+ "libdatasource",
"libmedia",
+ "libmediadrm",
"libmedia_omx",
"libmedia_jni_utils",
- "libmediadrm",
"libstagefright",
"libstagefright_foundation",
"liblog",
"libutils",
"libcutils",
"libnativewindow",
- "libbinder",
"libhidlbase",
"libgui",
"libui",
- "libmedia2_jni_core",
"libmediandk_utils",
+ "libnativehelper",
],
export_include_dirs: ["include"],
@@ -142,6 +146,10 @@
"-Wall",
],
+ header_libs: [
+ "libmedia_headers",
+ ],
+
shared_libs: [
],
@@ -168,6 +176,10 @@
"libcutils",
"android.hardware.graphics.bufferqueue@1.0",
],
+ header_libs: [
+ "libstagefright_foundation_headers",
+ ],
+
cflags: [
"-D__ANDROID_VNDK__",
],
diff --git a/media/ndk/NdkJavaVMHelper.cpp b/media/ndk/NdkJavaVMHelper.cpp
new file mode 100644
index 0000000..a77016c
--- /dev/null
+++ b/media/ndk/NdkJavaVMHelper.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright 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.
+ */
+
+#define LOG_TAG "NdkJavaVMHelper"
+
+#include "NdkJavaVMHelperPriv.h"
+#include <utils/Log.h>
+
+namespace android {
+
+// static
+JNIEnv *NdkJavaVMHelper::getJNIEnv() {
+ JNIEnv *env;
+ jsize nVMs;
+ JavaVM *vm;
+
+ int status = JNI_GetCreatedJavaVMs(&vm, 1, &nVMs);
+ if (status != JNI_OK || nVMs == 0 || vm == NULL) {
+ ALOGE("Failed to get JVM instance");
+ return NULL;
+ } else if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+ ALOGE("Failed to get JNIEnv for JavaVM: %p", vm);
+ return NULL;
+ }
+
+ return env;
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/media/ndk/NdkJavaVMHelperPriv.h b/media/ndk/NdkJavaVMHelperPriv.h
new file mode 100644
index 0000000..49f087e
--- /dev/null
+++ b/media/ndk/NdkJavaVMHelperPriv.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef NDK_JAVA_VM_HELPER_PRIV_H_
+
+#define NDK_JAVA_VM_HELPER_PRIV_H_
+
+#include "jni.h"
+
+namespace android {
+
+struct NdkJavaVMHelper {
+ static JNIEnv *getJNIEnv();
+};
+
+} // namespace android
+
+#endif // NDK_JAVA_VM_HELPER_PRIV_H_
\ No newline at end of file
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index e041533..af21a99 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -250,8 +250,8 @@
ALOGE("CB_ERROR: err is expected.");
break;
}
- if (!msg->findInt32("action", &actionCode)) {
- ALOGE("CB_ERROR: action is expected.");
+ if (!msg->findInt32("actionCode", &actionCode)) {
+ ALOGE("CB_ERROR: actionCode is expected.");
break;
}
msg->findString("detail", &detail);
diff --git a/media/ndk/NdkMediaCrypto.cpp b/media/ndk/NdkMediaCrypto.cpp
index ce2c660..741e58b 100644
--- a/media/ndk/NdkMediaCrypto.cpp
+++ b/media/ndk/NdkMediaCrypto.cpp
@@ -26,9 +26,8 @@
#include <cutils/properties.h>
#include <utils/Log.h>
#include <utils/StrongPointer.h>
-#include <binder/IServiceManager.h>
-#include <media/ICrypto.h>
-#include <media/IMediaDrmService.h>
+#include <mediadrm/DrmUtils.h>
+#include <mediadrm/ICrypto.h>
#include <android_util_Binder.h>
#include <jni.h>
@@ -36,19 +35,7 @@
using namespace android;
static sp<ICrypto> makeCrypto() {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder = sm->getService(String16("media.drm"));
-
- sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
- if (service == NULL) {
- return NULL;
- }
-
- sp<ICrypto> crypto = service->makeCrypto();
- if (crypto == NULL || (crypto->initCheck() != OK && crypto->initCheck() != NO_INIT)) {
- return NULL;
- }
- return crypto;
+ return DrmUtils::MakeCrypto();
}
struct AMediaCrypto {
diff --git a/media/ndk/NdkMediaCryptoPriv.h b/media/ndk/NdkMediaCryptoPriv.h
index 14ea928..8664d95 100644
--- a/media/ndk/NdkMediaCryptoPriv.h
+++ b/media/ndk/NdkMediaCryptoPriv.h
@@ -30,7 +30,7 @@
#include <sys/types.h>
#include <utils/StrongPointer.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
using namespace android;
diff --git a/media/ndk/NdkMediaDataSource.cpp b/media/ndk/NdkMediaDataSource.cpp
index 7979c2f..3e6d7d6 100644
--- a/media/ndk/NdkMediaDataSource.cpp
+++ b/media/ndk/NdkMediaDataSource.cpp
@@ -17,6 +17,7 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "NdkMediaDataSource"
+#include "NdkJavaVMHelperPriv.h"
#include "NdkMediaDataSourcePriv.h"
#include <inttypes.h>
@@ -26,18 +27,16 @@
#include <android_runtime/AndroidRuntime.h>
#include <android_util_Binder.h>
#include <cutils/properties.h>
-#include <utils/Log.h>
-#include <utils/StrongPointer.h>
+#include <datasource/DataSourceFactory.h>
+#include <datasource/HTTPBase.h>
+#include <datasource/NuCachedSource2.h>
#include <media/IMediaHTTPService.h>
#include <media/NdkMediaError.h>
#include <media/NdkMediaDataSource.h>
-#include <media/stagefright/DataSourceFactory.h>
#include <media/stagefright/InterfaceUtils.h>
-#include <mediaplayer2/JavaVMHelper.h>
-#include <mediaplayer2/JMedia2HTTPService.h>
+#include <utils/Log.h>
+#include <utils/StrongPointer.h>
-#include "../../libstagefright/include/HTTPBase.h"
-#include "../../libstagefright/include/NuCachedSource2.h"
#include "NdkMediaDataSourceCallbacksPriv.h"
@@ -120,18 +119,11 @@
return size >= 0 ? OK : UNKNOWN_ERROR;
}
-static sp<MediaHTTPService> createMediaHttpServiceFromJavaObj(JNIEnv *env, jobject obj, int version) {
+static sp<MediaHTTPService> createMediaHttpServiceFromJavaObj(JNIEnv *env, jobject obj) {
if (obj == NULL) {
return NULL;
}
- switch (version) {
- case 1:
- return interface_cast<IMediaHTTPService>(ibinderForJavaObject(env, obj));
- case 2:
- return new JMedia2HTTPService(env, obj);
- default:
- return NULL;
- }
+ return interface_cast<IMediaHTTPService>(ibinderForJavaObject(env, obj));
}
static sp<MediaHTTPService> createMediaHttpServiceTemplate(
@@ -139,8 +131,7 @@
const char *uri,
const char *clazz,
const char *method,
- const char *signature,
- int version) {
+ const char *signature) {
jobject service = NULL;
if (env == NULL) {
ALOGE("http service must be created from Java thread");
@@ -167,34 +158,23 @@
env->DeleteLocalRef(juri);
env->ExceptionClear();
- sp<MediaHTTPService> httpService = createMediaHttpServiceFromJavaObj(env, service, version);
+ sp<MediaHTTPService> httpService = createMediaHttpServiceFromJavaObj(env, service);
return httpService;
}
-sp<MediaHTTPService> createMediaHttpService(const char *uri, int version) {
+sp<MediaHTTPService> createMediaHttpService(const char *uri) {
JNIEnv *env;
const char *clazz, *method, *signature;
- switch (version) {
- case 1:
- env = AndroidRuntime::getJNIEnv();
- clazz = "android/media/MediaHTTPService";
- method = "createHttpServiceBinderIfNecessary";
- signature = "(Ljava/lang/String;)Landroid/os/IBinder;";
- break;
- case 2:
- env = JavaVMHelper::getJNIEnv();
- clazz = "android/media/Media2HTTPService";
- method = "createHTTPService";
- signature = "(Ljava/lang/String;)Landroid/media/Media2HTTPService;";
- break;
- default:
- return NULL;
- }
+ env = NdkJavaVMHelper::getJNIEnv();
- return createMediaHttpServiceTemplate(env, uri, clazz, method, signature, version);
+ clazz = "android/media/MediaHTTPService";
+ method = "createHttpServiceBinderIfNecessary";
+ signature = "(Ljava/lang/String;)Landroid/os/IBinder;";
+
+ return createMediaHttpServiceTemplate(env, uri, clazz, method, signature);
}
@@ -216,7 +196,7 @@
int numheaders,
const char * const *key_values) {
- sp<MediaHTTPService> service = createMediaHttpService(uri, /* version = */ 1);
+ sp<MediaHTTPService> service = createMediaHttpService(uri);
KeyedVector<String8, String8> headers;
for (int i = 0; i < numheaders; ++i) {
String8 key8(key_values[i * 2]);
@@ -224,7 +204,7 @@
headers.add(key8, value8);
}
- sp<DataSource> source = DataSourceFactory::CreateFromURI(service, uri, &headers);
+ sp<DataSource> source = DataSourceFactory::getInstance()->CreateFromURI(service, uri, &headers);
if (source == NULL) {
ALOGE("AMediaDataSource_newUri source is null");
return NULL;
diff --git a/media/ndk/NdkMediaDataSourcePriv.h b/media/ndk/NdkMediaDataSourcePriv.h
index 16ff974..ddcd7da 100644
--- a/media/ndk/NdkMediaDataSourcePriv.h
+++ b/media/ndk/NdkMediaDataSourcePriv.h
@@ -62,7 +62,7 @@
};
-sp<MediaHTTPService> createMediaHttpService(const char *uri, int version);
+sp<MediaHTTPService> createMediaHttpService(const char *uri);
#endif // _NDK_MEDIA_DATASOURCE_PRIV_H
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index cd5a23a..3af9771 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -20,6 +20,10 @@
#include <inttypes.h>
#include <unistd.h>
+#include <iostream>
+#include <fstream>
+#include <string>
+
#include <media/NdkMediaDrm.h>
#include <cutils/properties.h>
@@ -28,12 +32,10 @@
#include <gui/Surface.h>
#include <android-base/properties.h>
-#include <binder/PermissionController.h>
-#include <media/IDrm.h>
-#include <media/IDrmClient.h>
+#include <mediadrm/DrmUtils.h>
+#include <mediadrm/IDrm.h>
+#include <mediadrm/IDrmClient.h>
#include <media/stagefright/MediaErrors.h>
-#include <binder/IServiceManager.h>
-#include <media/IMediaDrmService.h>
#include <media/NdkMediaCrypto.h>
@@ -41,7 +43,7 @@
typedef Vector<uint8_t> idvec_t;
-struct DrmListener: virtual public BnDrmClient
+struct DrmListener: virtual public IDrmClient
{
private:
AMediaDrm *mObj;
@@ -71,12 +73,27 @@
mKeysChangeListener = listener;
}
- void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj);
+ void sendEvent(
+ DrmPlugin::EventType eventType,
+ const hardware::hidl_vec<uint8_t> &sessionId,
+ const hardware::hidl_vec<uint8_t> &data) override;
+
+ void sendExpirationUpdate(
+ const hardware::hidl_vec<uint8_t> &sessionId,
+ int64_t expiryTimeInMS) override;
+
+ void sendKeysChange(
+ const hardware::hidl_vec<uint8_t> &sessionId,
+ const std::vector<DrmKeyStatus> &keyStatusList,
+ bool hasNewUsableKey) override;
+
+ void sendSessionLostState(
+ const hardware::hidl_vec<uint8_t> &) override {}
+
};
struct AMediaDrm {
sp<IDrm> mDrm;
- sp<IDrmClient> mDrmClient;
List<idvec_t> mIds;
KeyedVector<String8, String8> mQueryResults;
Vector<uint8_t> mKeyRequest;
@@ -88,71 +105,52 @@
sp<DrmListener> mListener;
};
-void DrmListener::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
- if (!mEventListener || !mExpirationUpdateListener || !mKeysChangeListener) {
- ALOGE("No listeners are specified");
+void DrmListener::sendExpirationUpdate(
+ const hardware::hidl_vec<uint8_t> &sessionId,
+ int64_t expiryTimeInMS) {
+ if (!mExpirationUpdateListener) {
+ ALOGE("No ExpirationUpdateListener specified");
return;
}
- obj->setDataPosition(0);
+ if (expiryTimeInMS >= 0) {
+ AMediaDrmSessionId asid = {sessionId.data(), sessionId.size()};
+ (*mExpirationUpdateListener)(mObj, &asid, expiryTimeInMS);
+ } else {
+ ALOGE("expiry time negative, status=%" PRId64 "", expiryTimeInMS);
+ }
+}
- AMediaDrmSessionId sessionId = {NULL, 0};
- int32_t sessionIdSize = obj->readInt32();
- if (sessionIdSize <= 0) {
- ALOGE("Invalid session id size");
+void DrmListener::sendKeysChange(
+ const hardware::hidl_vec<uint8_t> &sessionId,
+ const std::vector<DrmKeyStatus> &keyStatusList,
+ bool hasNewUsableKey) {
+ if (!mKeysChangeListener) {
+ ALOGE("No KeysChangeListener specified");
return;
}
- std::unique_ptr<uint8_t[]> sessionIdData(new uint8_t[sessionIdSize]);
- sessionId.ptr = sessionIdData.get();
- sessionId.length = sessionIdSize;
- status_t err = obj->read(sessionIdData.get(), sessionId.length);
- if (err != OK) {
- ALOGE("Failed to read session id, error=%d", err);
- return;
- }
-
- if (DrmPlugin::kDrmPluginEventExpirationUpdate == eventType) {
- int64_t expiryTimeInMS = obj->readInt64();
- if (expiryTimeInMS >= 0) {
- (*mExpirationUpdateListener)(mObj, &sessionId, expiryTimeInMS);
- } else {
- ALOGE("Failed to read expiry time, status=%" PRId64 "", expiryTimeInMS);
- }
- return;
- } else if (DrmPlugin::kDrmPluginEventKeysChange == eventType) {
- int32_t numKeys = 0;
- err = obj->readInt32(&numKeys);
- if (err != OK) {
- ALOGE("Failed to read number of keys status, error=%d", err);
- return;
- }
-
- Vector<AMediaDrmKeyStatus> keysStatus;
- std::vector<std::unique_ptr<uint8_t[]> > dataPointers;
+ Vector<AMediaDrmKeyStatus> keysStatus;
+ for (const auto &drmKeyStatus : keyStatusList) {
AMediaDrmKeyStatus keyStatus;
+ keyStatus.keyId.ptr = drmKeyStatus.keyId.data();
+ keyStatus.keyId.length = drmKeyStatus.keyId.size();
+ keyStatus.keyType = static_cast<AMediaDrmKeyStatusType>(drmKeyStatus.type);
+ keysStatus.push(keyStatus);
+ }
- for (size_t i = 0; i < numKeys; ++i) {
- keyStatus.keyId.ptr = nullptr;
- keyStatus.keyId.length = 0;
- int32_t idSize = obj->readInt32();
- if (idSize > 0) {
- std::unique_ptr<uint8_t[]> data(new uint8_t[idSize]);
- err = obj->read(data.get(), idSize);
- if (err != OK) {
- ALOGE("Failed to read key data, error=%d", err);
- return;
- }
- keyStatus.keyId.ptr = data.get();
- keyStatus.keyId.length = idSize;
- dataPointers.push_back(std::move(data));
- }
- keyStatus.keyType = static_cast<AMediaDrmKeyStatusType>(obj->readInt32());
- keysStatus.push(keyStatus);
- }
+ AMediaDrmSessionId asid = {sessionId.data(), sessionId.size()};
+ int32_t numKeys = keyStatusList.size();
+ (*mKeysChangeListener)(mObj, &asid, keysStatus.array(), numKeys, hasNewUsableKey);
+ return;
+}
- bool hasNewUsableKey = obj->readInt32();
- (*mKeysChangeListener)(mObj, &sessionId, keysStatus.array(), numKeys, hasNewUsableKey);
+void DrmListener::sendEvent(
+ DrmPlugin::EventType eventType,
+ const hardware::hidl_vec<uint8_t> &sessionId,
+ const hardware::hidl_vec<uint8_t> &data) {
+ if (!mEventListener) {
+ ALOGE("No EventListener specified");
return;
}
@@ -176,23 +174,17 @@
ndkEventType = EVENT_SESSION_RECLAIMED;
break;
default:
- ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
+ ALOGE("Invalid event DrmPlugin::EventType %d, ignored", eventType);
return;
}
- int32_t dataSize = obj->readInt32();
- uint8_t *data = NULL;
+ AMediaDrmSessionId asid = {sessionId.data(), sessionId.size()};
+ int32_t dataSize = data.size();
+ const uint8_t *dataPtr = data.data();
if (dataSize > 0) {
- data = new uint8_t[dataSize];
- err = obj->read(data, dataSize);
- if (err == OK) {
- (*mEventListener)(mObj, &sessionId, ndkEventType, extra, data, dataSize);
- } else {
- ALOGE("Failed to read event data, error=%d", err);
- }
- delete [] data;
+ (*mEventListener)(mObj, &asid, ndkEventType, 0, dataPtr, dataSize);
} else {
- ALOGE("Error reading parcel: invalid event data size=%d", dataSize);
+ ALOGE("invalid event data size=%d", dataSize);
}
}
@@ -246,41 +238,20 @@
}
static status_t GetAppPackageName(String8 *packageName) {
- sp<IServiceManager> serviceManager = defaultServiceManager();
- sp<IBinder> binder = serviceManager->getService(String16("permission"));
-
- sp<IPermissionController> permissionContol = interface_cast<IPermissionController>(binder);
- if (permissionContol == NULL) {
- ALOGE("Failed to get permission service");
+ // todo(robertshih): use refactored/renamed libneuralnetworks_packageinfo which is stable
+ std::string appName;
+ std::ifstream cmdline("/proc/self/cmdline");
+ std::getline(cmdline, appName);
+ cmdline.close();
+ if (appName.empty()) {
return UNKNOWN_ERROR;
}
-
- Vector<String16> packages;
- permissionContol->getPackagesForUid(getuid(), packages);
-
- if (packages.isEmpty()) {
- ALOGE("Unable to get package name for current UID");
- return UNKNOWN_ERROR;
- }
-
- *packageName = String8(packages[0]);
+ *packageName = String8(appName.c_str());
return OK;
}
static sp<IDrm> CreateDrm() {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder = sm->getService(String16("media.drm"));
-
- sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
- if (service == NULL) {
- return NULL;
- }
-
- sp<IDrm> drm = service->makeDrm();
- if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
- return NULL;
- }
- return drm;
+ return DrmUtils::MakeDrm();
}
diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
index c83b255..0da0740 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -89,7 +89,7 @@
ALOGV("setDataSource(%s)", uri);
- sp<MediaHTTPService> httpService = createMediaHttpService(uri, /* version = */ 1);
+ sp<MediaHTTPService> httpService = createMediaHttpService(uri);
if (httpService == NULL) {
ALOGE("can't create http service");
return AMEDIA_ERROR_UNSUPPORTED;
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index 51138c8..ab0cb63 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -341,6 +341,7 @@
EXPORT const char* AMEDIAFORMAT_KEY_LEVEL = "level";
EXPORT const char* AMEDIAFORMAT_KEY_LOCATION = "location";
EXPORT const char* AMEDIAFORMAT_KEY_LOOP = "loop";
+EXPORT const char* AMEDIAFORMAT_KEY_LOW_LATENCY = "low-latency";
EXPORT const char* AMEDIAFORMAT_KEY_LYRICIST = "lyricist";
EXPORT const char* AMEDIAFORMAT_KEY_MANUFACTURER = "manufacturer";
EXPORT const char* AMEDIAFORMAT_KEY_MAX_BIT_RATE = "max-bitrate";
diff --git a/media/ndk/include/media/NdkImage.h b/media/ndk/include/media/NdkImage.h
index 3e60de0..62b8624 100644
--- a/media/ndk/include/media/NdkImage.h
+++ b/media/ndk/include/media/NdkImage.h
@@ -570,6 +570,8 @@
* return {@link AMEDIA_ERROR_INVALID_OBJECT}. Application still needs to call this method on those
* {@link AImage} objects to fully delete the {@link AImage} object from memory.</p>
*
+ * Available since API level 24.
+ *
* @param image The {@link AImage} to be deleted.
*/
void AImage_delete(AImage* image) __INTRODUCED_IN(24);
@@ -577,6 +579,8 @@
/**
* Query the width of the input {@link AImage}.
*
+ * Available since API level 24.
+ *
* @param image the {@link AImage} of interest.
* @param width the width of the image will be filled here if the method call succeeeds.
*
@@ -591,6 +595,8 @@
/**
* Query the height of the input {@link AImage}.
*
+ * Available since API level 24.
+ *
* @param image the {@link AImage} of interest.
* @param height the height of the image will be filled here if the method call succeeeds.
*
@@ -607,6 +613,8 @@
*
* <p>The format value will be one of AIMAGE_FORMAT_* enum value.</p>
*
+ * Available since API level 24.
+ *
* @param image the {@link AImage} of interest.
* @param format the format of the image will be filled here if the method call succeeeds.
*
@@ -624,6 +632,8 @@
* <p>The crop rectangle specifies the region of valid pixels in the image, using coordinates in the
* largest-resolution plane.</p>
*
+ * Available since API level 24.
+ *
* @param image the {@link AImage} of interest.
* @param rect the cropped rectangle of the image will be filled here if the method call succeeeds.
*
@@ -648,6 +658,8 @@
* {@link ACameraCaptureSession_captureCallbacks#onCaptureCompleted} callback.
* </p>
*
+ * Available since API level 24.
+ *
* @param image the {@link AImage} of interest.
* @param timestampNs the timestamp of the image will be filled here if the method call succeeeds.
*
@@ -665,6 +677,8 @@
* <p>The number of plane of an {@link AImage} is determined by its format, which can be queried by
* {@link AImage_getFormat} method.</p>
*
+ * Available since API level 24.
+ *
* @param image the {@link AImage} of interest.
* @param numPlanes the number of planes of the image will be filled here if the method call
* succeeeds.
@@ -687,6 +701,8 @@
* being returned.
* For formats where pixel stride is well defined, the pixel stride is always greater than 0.</p>
*
+ * Available since API level 24.
+ *
* @param image the {@link AImage} of interest.
* @param planeIdx the index of the plane. Must be less than the number of planes of input image.
* @param pixelStride the pixel stride of the image will be filled here if the method call succeeeds.
@@ -714,6 +730,8 @@
* being returned.
* For formats where row stride is well defined, the row stride is always greater than 0.</p>
*
+ * Available since API level 24.
+ *
* @param image the {@link AImage} of interest.
* @param planeIdx the index of the plane. Must be less than the number of planes of input image.
* @param rowStride the row stride of the image will be filled here if the method call succeeeds.
@@ -739,6 +757,8 @@
* pointer from previous AImage_getPlaneData call becomes invalid. Do NOT use it after the
* {@link AImage} or the parent {@link AImageReader} is deleted.</p>
*
+ * Available since API level 24.
+ *
* @param image the {@link AImage} of interest.
* @param planeIdx the index of the plane. Must be less than the number of planes of input image.
* @param data the data pointer of the image will be filled here if the method call succeeeds.
@@ -769,6 +789,8 @@
* signal the release of the hardware buffer back to the {@link AImageReader}'s queue using
* releaseFenceFd.</p>
*
+ * Available since API level 26.
+ *
* @param image The {@link AImage} to be deleted.
* @param releaseFenceFd A sync fence fd defined in {@link sync.h}, which signals the release of
* underlying {@link AHardwareBuffer}.
@@ -794,6 +816,8 @@
* {@link AImageReader_setBufferRemovedListener} to be notified when the buffer is no longer used
* by {@link AImageReader}.</p>
*
+ * Available since API level 26.
+ *
* @param image the {@link AImage} of interest.
* @param outBuffer The memory area pointed to by buffer will contain the acquired AHardwareBuffer
* handle.
diff --git a/media/ndk/include/media/NdkImageReader.h b/media/ndk/include/media/NdkImageReader.h
index e5d863c..600ffc9 100644
--- a/media/ndk/include/media/NdkImageReader.h
+++ b/media/ndk/include/media/NdkImageReader.h
@@ -67,6 +67,8 @@
* The valid sizes and formats depend on the source of the image data.
* </p>
*
+ * Available since API level 24.
+ *
* @param width The default width in pixels of the Images that this reader will produce.
* @param height The default height in pixels of the Images that this reader will produce.
* @param format The format of the Image that this reader will produce. This must be one of the
@@ -101,6 +103,8 @@
* making any of data pointers obtained from {@link AImage_getPlaneData} invalid. Do NOT access
* the reader object or any of those data pointers after this method returns.</p>
*
+ * Available since API level 24.
+ *
* @param reader The image reader to be deleted.
*/
void AImageReader_delete(AImageReader* reader) __INTRODUCED_IN(24);
@@ -108,6 +112,8 @@
/**
* Get a {@link ANativeWindow} that can be used to produce {@link AImage} for this image reader.
*
+ * Available since API level 24.
+ *
* @param reader The image reader of interest.
* @param window The output {@link ANativeWindow} will be filled here if the method call succeeds.
* The {@link ANativeWindow} is managed by this image reader. Do NOT call
@@ -126,6 +132,8 @@
* {@link ANativeWindow}. If so, the actual width of the images can be found using
* {@link AImage_getWidth}.</p>
*
+ * Available since API level 24.
+ *
* @param reader The image reader of interest.
* @param width the default width of the reader will be filled here if the method call succeeeds.
*
@@ -142,6 +150,8 @@
* {@link ANativeWindow}. If so, the actual height of the images can be found using
* {@link AImage_getHeight}.</p>
*
+ * Available since API level 24.
+ *
* @param reader The image reader of interest.
* @param height the default height of the reader will be filled here if the method call succeeeds.
*
@@ -154,6 +164,8 @@
/**
* Query the format of the {@link AImage} generated by this reader.
*
+ * Available since API level 24.
+ *
* @param reader The image reader of interest.
* @param format the fromat of the reader will be filled here if the method call succeeeds. The
* value will be one of the AIMAGE_FORMAT_* enum value defiend in {@link NdkImage.h}.
@@ -167,6 +179,8 @@
/**
* Query the maximum number of concurrently acquired {@link AImage}s of this reader.
*
+ * Available since API level 24.
+ *
* @param reader The image reader of interest.
* @param maxImages the maximum number of concurrently acquired images of the reader will be filled
* here if the method call succeeeds.
@@ -197,6 +211,8 @@
* {@link AImage_delete}.
* </p>
*
+ * Available since API level 24.
+ *
* @param reader The image reader of interest.
* @param image the acquired {@link AImage} will be filled here if the method call succeeeds.
*
@@ -214,7 +230,6 @@
media_status_t AImageReader_acquireNextImage(AImageReader* reader, /*out*/AImage** image) __INTRODUCED_IN(24);
/**
-
* Acquire the latest {@link AImage} from the image reader's queue, dropping older images.
*
* <p>
@@ -241,6 +256,8 @@
* {@link AImage_delete}.
* </p>
*
+ * Available since API level 24.
+ *
* @param reader The image reader of interest.
* @param image the acquired {@link AImage} will be filled here if the method call succeeeds.
*
@@ -290,6 +307,8 @@
*
* Calling this method will replace previously registered listeners.
*
+ * Available since API level 24.
+ *
* @param reader The image reader of interest.
* @param listener The {@link AImageReader_ImageListener} to be registered. Set this to NULL if
* the application no longer needs to listen to new images.
@@ -356,6 +375,9 @@
* {@link AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE}, or combined</td>
* </tr>
* </table>
+ *
+ * Available since API level 26.
+ *
* @return <ul>
* <li>{@link AMEDIA_OK} if the method call succeeds.</li>
* <li>{@link AMEDIA_ERROR_INVALID_PARAMETER} if reader is NULL, or one or more of width,
@@ -377,6 +399,8 @@
* additional parameter for the sync fence. All other parameters and the return values are
* identical to those passed to {@link AImageReader_acquireNextImage}.</p>
*
+ * Available since API level 26.
+ *
* @param acquireFenceFd A sync fence fd defined in {@link sync.h}, which is used to signal when the
* buffer is ready to consume. When synchronization fence is not needed, fence will be set
* to -1 and the {@link AImage} returned is ready for use immediately. Otherwise, user shall
@@ -397,6 +421,8 @@
* additional parameter for the sync fence. All other parameters and the return values are
* identical to those passed to {@link AImageReader_acquireLatestImage}.</p>
*
+ * Available since API level 26.
+ *
* @param acquireFenceFd A sync fence fd defined in {@link sync.h}, which is used to signal when the
* buffer is ready to consume. When synchronization fence is not needed, fence will be set
* to -1 and the {@link AImage} returned is ready for use immediately. Otherwise, user shall
@@ -408,6 +434,7 @@
*/
media_status_t AImageReader_acquireLatestImageAsync(
AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd) __INTRODUCED_IN(26);
+
/**
* Signature of the callback which is called when {@link AImageReader} is about to remove a buffer.
*
@@ -451,6 +478,8 @@
*
* <p>Note that calling this method will replace previously registered listeners.</p>
*
+ * Available since API level 26.
+ *
* @param reader The image reader of interest.
* @param listener the {@link AImageReader_BufferRemovedListener} to be registered. Set this to
* NULL if application no longer needs to listen to buffer removed events.
diff --git a/media/ndk/include/media/NdkMediaCodec.h b/media/ndk/include/media/NdkMediaCodec.h
index b3ee853..8fb6a87 100644
--- a/media/ndk/include/media/NdkMediaCodec.h
+++ b/media/ndk/include/media/NdkMediaCodec.h
@@ -127,27 +127,37 @@
* Create codec by name. Use this if you know the exact codec you want to use.
* When configuring, you will need to specify whether to use the codec as an
* encoder or decoder.
+ *
+ * Available since API level 21.
*/
AMediaCodec* AMediaCodec_createCodecByName(const char *name) __INTRODUCED_IN(21);
/**
* Create codec by mime type. Most applications will use this, specifying a
* mime type obtained from media extractor.
+ *
+ * Available since API level 21.
*/
AMediaCodec* AMediaCodec_createDecoderByType(const char *mime_type) __INTRODUCED_IN(21);
/**
* Create encoder by name.
+ *
+ * Available since API level 21.
*/
AMediaCodec* AMediaCodec_createEncoderByType(const char *mime_type) __INTRODUCED_IN(21);
/**
- * delete the codec and free its resources
+ * Delete the codec and free its resources.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaCodec_delete(AMediaCodec*) __INTRODUCED_IN(21);
/**
* Configure the codec. For decoding you would typically get the format from an extractor.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaCodec_configure(
AMediaCodec*,
@@ -159,29 +169,39 @@
/**
* Start the codec. A codec must be configured before it can be started, and must be started
* before buffers can be sent to it.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaCodec_start(AMediaCodec*) __INTRODUCED_IN(21);
/**
* Stop the codec.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaCodec_stop(AMediaCodec*) __INTRODUCED_IN(21);
/*
* Flush the codec's input and output. All indices previously returned from calls to
* AMediaCodec_dequeueInputBuffer and AMediaCodec_dequeueOutputBuffer become invalid.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaCodec_flush(AMediaCodec*) __INTRODUCED_IN(21);
/**
* Get an input buffer. The specified buffer index must have been previously obtained from
* dequeueInputBuffer, and not yet queued.
+ *
+ * Available since API level 21.
*/
uint8_t* AMediaCodec_getInputBuffer(AMediaCodec*, size_t idx, size_t *out_size) __INTRODUCED_IN(21);
/**
* Get an output buffer. The specified buffer index must have been previously obtained from
* dequeueOutputBuffer, and not yet queued.
+ *
+ * Available since API level 21.
*/
uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec*, size_t idx, size_t *out_size) __INTRODUCED_IN(21);
@@ -189,6 +209,8 @@
* Get the index of the next available input buffer. An app will typically use this with
* getInputBuffer() to get a pointer to the buffer, then copy the data to be encoded or decoded
* into the buffer before passing it to the codec.
+ *
+ * Available since API level 21.
*/
ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec*, int64_t timeoutUs) __INTRODUCED_IN(21);
@@ -218,6 +240,8 @@
/**
* Send the specified buffer to the codec for processing.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaCodec_queueInputBuffer(AMediaCodec*, size_t idx,
_off_t_compat offset, size_t size,
@@ -225,6 +249,8 @@
/**
* Send the specified buffer to the codec for processing.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaCodec_queueSecureInputBuffer(AMediaCodec*, size_t idx,
_off_t_compat offset,
@@ -235,15 +261,26 @@
/**
* Get the index of the next available buffer of processed data.
+ *
+ * Available since API level 21.
*/
ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec*, AMediaCodecBufferInfo *info,
int64_t timeoutUs) __INTRODUCED_IN(21);
+
+/**
+ * Returns the format of the codec's output.
+ * The caller must free the returned format.
+ *
+ * Available since API level 21.
+ */
AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec*) __INTRODUCED_IN(21);
/**
* If you are done with a buffer, use this call to return the buffer to
* the codec. If you previously specified a surface when configuring this
* video decoder you can optionally render the buffer.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaCodec_releaseOutputBuffer(AMediaCodec*, size_t idx, bool render) __INTRODUCED_IN(21);
@@ -256,6 +293,8 @@
* to ImageReader (software readable) output.
*
* For more details, see the Java documentation for MediaCodec.setOutputSurface.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaCodec_setOutputSurface(AMediaCodec*, ANativeWindow* surface) __INTRODUCED_IN(21);
@@ -266,6 +305,8 @@
* this call will simply return the buffer to the codec.
*
* For more details, see the Java documentation for MediaCodec.releaseOutputBuffer.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaCodec_releaseOutputBufferAtTime(
AMediaCodec *mData, size_t idx, int64_t timestampNs) __INTRODUCED_IN(21);
@@ -282,6 +323,8 @@
* ANativeWindow_release() when done.
*
* For more details, see the Java documentation for MediaCodec.createInputSurface.
+ *
+ * Available since API level 26.
*/
media_status_t AMediaCodec_createInputSurface(
AMediaCodec *mData, ANativeWindow **surface) __INTRODUCED_IN(26);
@@ -298,6 +341,8 @@
* ANativeWindow_release() when done.
*
* For more details, see the Java documentation for MediaCodec.createPersistentInputSurface.
+ *
+ * Available since API level 26.
*/
media_status_t AMediaCodec_createPersistentInputSurface(
ANativeWindow **surface) __INTRODUCED_IN(26);
@@ -311,6 +356,8 @@
* AMediaCodec_configure(..); and before AMediaCodec_start() has been called.
*
* For more details, see the Java documentation for MediaCodec.setInputSurface.
+ *
+ * Available since API level 26.
*/
media_status_t AMediaCodec_setInputSurface(
AMediaCodec *mData, ANativeWindow *surface) __INTRODUCED_IN(26);
@@ -322,6 +369,8 @@
* after AMediaCodec_start() has been called.
*
* NOTE: Some of these parameter changes may silently fail to apply.
+ *
+ * Available since API level 26.
*/
media_status_t AMediaCodec_setParameters(
AMediaCodec *mData, const AMediaFormat* params) __INTRODUCED_IN(26);
@@ -339,6 +388,8 @@
* Returns AMEDIA_OK when completed succesfully.
*
* For more details, see the Java documentation for MediaCodec.signalEndOfInputStream.
+ *
+ * Available since API level 26.
*/
media_status_t AMediaCodec_signalEndOfInputStream(AMediaCodec *mData) __INTRODUCED_IN(26);
@@ -349,6 +400,9 @@
/**
* Get format of the buffer. The specified buffer index must have been previously obtained from
* dequeueOutputBuffer.
+ * The caller must free the returned format.
+ *
+ * Available since API level 28.
*/
AMediaFormat* AMediaCodec_getBufferFormat(AMediaCodec*, size_t index) __INTRODUCED_IN(28);
@@ -356,11 +410,15 @@
* Get the component name. If the codec was created by createDecoderByType
* or createEncoderByType, what component is chosen is not known beforehand.
* Caller shall call AMediaCodec_releaseName to free the returned pointer.
+ *
+ * Available since API level 28.
*/
media_status_t AMediaCodec_getName(AMediaCodec*, char** out_name) __INTRODUCED_IN(28);
/**
* Free the memory pointed by name which is returned by AMediaCodec_getName.
+ *
+ * Available since API level 28.
*/
void AMediaCodec_releaseName(AMediaCodec*, char* name) __INTRODUCED_IN(28);
@@ -382,6 +440,8 @@
* All callbacks are fired on one NDK internal thread.
* AMediaCodec_setAsyncNotifyCallback should not be called on the callback thread.
* No heavy duty task should be performed on callback thread.
+ *
+ * Available since API level 28.
*/
media_status_t AMediaCodec_setAsyncNotifyCallback(
AMediaCodec*,
@@ -390,6 +450,8 @@
/**
* Release the crypto if applicable.
+ *
+ * Available since API level 28.
*/
media_status_t AMediaCodec_releaseCrypto(AMediaCodec*) __INTRODUCED_IN(28);
@@ -397,12 +459,17 @@
* Call this after AMediaCodec_configure() returns successfully to get the input
* format accepted by the codec. Do this to determine what optional configuration
* parameters were supported by the codec.
+ * The caller must free the returned format.
+ *
+ * Available since API level 28.
*/
AMediaFormat* AMediaCodec_getInputFormat(AMediaCodec*) __INTRODUCED_IN(28);
/**
* Returns true if the codec cannot proceed further, but can be recovered by stopping,
* configuring, and starting again.
+ *
+ * Available since API level 28.
*/
bool AMediaCodecActionCode_isRecoverable(int32_t actionCode) __INTRODUCED_IN(28);
@@ -410,6 +477,8 @@
* Returns true if the codec error is a transient issue, perhaps due to
* resource constraints, and that the method (or encoding/decoding) may be
* retried at a later time.
+ *
+ * Available since API level 28.
*/
bool AMediaCodecActionCode_isTransient(int32_t actionCode) __INTRODUCED_IN(28);
@@ -440,6 +509,8 @@
* numBytesOfClearData can be null to indicate that all data is encrypted.
* This information encapsulates per-sample metadata as outlined in
* ISO/IEC FDIS 23001-7:2011 "Common encryption in ISO base media file format files".
+ *
+ * Available since API level 21.
*/
AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new(
int numsubsamples,
@@ -450,13 +521,17 @@
size_t *encryptedbytes) __INTRODUCED_IN(21);
/**
- * delete an AMediaCodecCryptoInfo created previously with AMediaCodecCryptoInfo_new, or
- * obtained from AMediaExtractor
+ * Delete an AMediaCodecCryptoInfo created previously with AMediaCodecCryptoInfo_new, or
+ * obtained from AMediaExtractor.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo*) __INTRODUCED_IN(21);
/**
- * Set the crypto pattern on an AMediaCryptoInfo object
+ * Set the crypto pattern on an AMediaCryptoInfo object.
+ *
+ * Available since API level 21.
*/
void AMediaCodecCryptoInfo_setPattern(
AMediaCodecCryptoInfo *info,
@@ -464,32 +539,44 @@
/**
* The number of subsamples that make up the buffer's contents.
+ *
+ * Available since API level 21.
*/
size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo*) __INTRODUCED_IN(21);
/**
- * A 16-byte opaque key
+ * A 16-byte opaque key.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo*, uint8_t *dst) __INTRODUCED_IN(21);
/**
- * A 16-byte initialization vector
+ * A 16-byte initialization vector.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo*, uint8_t *dst) __INTRODUCED_IN(21);
/**
* The type of encryption that has been applied,
* one of AMEDIACODECRYPTOINFO_MODE_CLEAR or AMEDIACODECRYPTOINFO_MODE_AES_CTR.
+ *
+ * Available since API level 21.
*/
cryptoinfo_mode_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo*) __INTRODUCED_IN(21);
/**
* The number of leading unencrypted bytes in each subsample.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo*, size_t *dst) __INTRODUCED_IN(21);
/**
* The number of trailing encrypted bytes in each subsample.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo*, size_t *dst) __INTRODUCED_IN(21);
diff --git a/media/ndk/include/media/NdkMediaCrypto.h b/media/ndk/include/media/NdkMediaCrypto.h
index bcdf9a0..3fa07c7 100644
--- a/media/ndk/include/media/NdkMediaCrypto.h
+++ b/media/ndk/include/media/NdkMediaCrypto.h
@@ -49,12 +49,24 @@
#if __ANDROID_API__ >= 21
+/**
+ * Available since API level 21.
+ */
bool AMediaCrypto_isCryptoSchemeSupported(const AMediaUUID uuid) __INTRODUCED_IN(21);
+/**
+ * Available since API level 21.
+ */
bool AMediaCrypto_requiresSecureDecoderComponent(const char *mime) __INTRODUCED_IN(21);
+/**
+ * Available since API level 21.
+ */
AMediaCrypto* AMediaCrypto_new(const AMediaUUID uuid, const void *initData, size_t initDataSize) __INTRODUCED_IN(21);
+/**
+ * Available since API level 21.
+ */
void AMediaCrypto_delete(AMediaCrypto* crypto) __INTRODUCED_IN(21);
#endif /* __ANDROID_API__ >= 21 */
diff --git a/media/ndk/include/media/NdkMediaDataSource.h b/media/ndk/include/media/NdkMediaDataSource.h
index 16b1eb3..0577df2 100644
--- a/media/ndk/include/media/NdkMediaDataSource.h
+++ b/media/ndk/include/media/NdkMediaDataSource.h
@@ -88,6 +88,8 @@
/**
* Create new media data source. Returns NULL if memory allocation
* for the new data source object fails.
+ *
+ * Available since API level 28.
*/
AMediaDataSource* AMediaDataSource_new() __INTRODUCED_IN(28);
@@ -116,6 +118,7 @@
* ...
* key_values[(numheaders - 1) * 2]:key_values[(numheaders - 1) * 2 + 1]
*
+ * Available since API level 29.
*/
AMediaDataSource* AMediaDataSource_newUri(const char *uri,
int numheaders,
@@ -125,12 +128,16 @@
/**
* Delete a previously created media data source.
+ *
+ * Available since API level 28.
*/
void AMediaDataSource_delete(AMediaDataSource*) __INTRODUCED_IN(28);
/**
* Set an user provided opaque handle. This opaque handle is passed as
* the first argument to the data source callbacks.
+ *
+ * Available since API level 28.
*/
void AMediaDataSource_setUserdata(
AMediaDataSource*, void *userdata) __INTRODUCED_IN(28);
@@ -145,6 +152,8 @@
*
* Please refer to the definition of AMediaDataSourceReadAt for
* additional details.
+ *
+ * Available since API level 28.
*/
void AMediaDataSource_setReadAt(
AMediaDataSource*,
@@ -156,6 +165,8 @@
*
* Please refer to the definition of AMediaDataSourceGetSize for
* additional details.
+ *
+ * Available since API level 28.
*/
void AMediaDataSource_setGetSize(
AMediaDataSource*,
@@ -167,6 +178,8 @@
*
* Please refer to the definition of AMediaDataSourceClose for
* additional details.
+ *
+ * Available since API level 28.
*/
void AMediaDataSource_setClose(
AMediaDataSource*,
@@ -181,6 +194,8 @@
*
* Please refer to the definition of AMediaDataSourceClose for
* additional details.
+ *
+ * Available since API level 29.
*/
void AMediaDataSource_close(AMediaDataSource*) __INTRODUCED_IN(29);
@@ -191,6 +206,8 @@
*
* Please refer to the definition of AMediaDataSourceGetAvailableSize
* for additional details.
+ *
+ * Available since API level 29.
*/
void AMediaDataSource_setGetAvailableSize(
AMediaDataSource*,
diff --git a/media/ndk/include/media/NdkMediaDrm.h b/media/ndk/include/media/NdkMediaDrm.h
index 2e438d9..31f5c7d 100644
--- a/media/ndk/include/media/NdkMediaDrm.h
+++ b/media/ndk/include/media/NdkMediaDrm.h
@@ -174,41 +174,53 @@
* uuid identifies the universal unique ID of the crypto scheme. uuid must be 16 bytes.
* mimeType is the MIME type of the media container, e.g. "video/mp4". If mimeType
* is not known or required, it can be provided as NULL.
+ *
+ * Available since API level 21.
*/
bool AMediaDrm_isCryptoSchemeSupported(const uint8_t *uuid,
const char *mimeType) __INTRODUCED_IN(21);
/**
- * Create a MediaDrm instance from a UUID
+ * Create a MediaDrm instance from a UUID.
* uuid identifies the universal unique ID of the crypto scheme. uuid must be 16 bytes.
+ *
+ * Available since API level 21.
*/
AMediaDrm* AMediaDrm_createByUUID(const uint8_t *uuid) __INTRODUCED_IN(21);
/**
- * Release a MediaDrm object
+ * Release a MediaDrm object.
+ *
+ * Available since API level 21.
*/
void AMediaDrm_release(AMediaDrm *) __INTRODUCED_IN(21);
/**
- * Register a callback to be invoked when an event occurs
+ * Register a callback to be invoked when an event occurs.
*
- * listener is the callback that will be invoked on event
+ * listener is the callback that will be invoked on event.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaDrm_setOnEventListener(AMediaDrm *,
AMediaDrmEventListener listener) __INTRODUCED_IN(21);
/**
- * Register a callback to be invoked when an expiration update event occurs
+ * Register a callback to be invoked when an expiration update event occurs.
*
- * listener is the callback that will be invoked on event
+ * listener is the callback that will be invoked on event.
+ *
+ * Available since API level 29.
*/
media_status_t AMediaDrm_setOnExpirationUpdateListener(AMediaDrm *,
AMediaDrmExpirationUpdateListener listener) __INTRODUCED_IN(29);
/**
- * Register a callback to be invoked when a key status change event occurs
+ * Register a callback to be invoked when a key status change event occurs.
*
- * listener is the callback that will be invoked on event
+ * listener is the callback that will be invoked on event.
+ *
+ * Available since API level 29.
*/
media_status_t AMediaDrm_setOnKeysChangeListener(AMediaDrm *,
AMediaDrmKeysChangeListener listener) __INTRODUCED_IN(29);
@@ -216,8 +228,10 @@
/**
* Open a new session with the MediaDrm object. A session ID is returned.
*
- * returns MEDIADRM_NOT_PROVISIONED_ERROR if provisioning is needed
- * returns MEDIADRM_RESOURCE_BUSY_ERROR if required resources are in use
+ * Returns MEDIADRM_NOT_PROVISIONED_ERROR if provisioning is needed.
+ * Returns MEDIADRM_RESOURCE_BUSY_ERROR if required resources are in use.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaDrm_openSession(AMediaDrm *,
AMediaDrmSessionId *sessionId) __INTRODUCED_IN(21);
@@ -225,6 +239,8 @@
/**
* Close a session on the MediaDrm object that was previously opened
* with AMediaDrm_openSession.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaDrm_closeSession(AMediaDrm *,
const AMediaDrmSessionId *sessionId) __INTRODUCED_IN(21);
@@ -272,9 +288,11 @@
* MediaDrm object is released.
* 2. keyRequestSize will be set to the size of the request
*
- * returns MEDIADRM_NOT_PROVISIONED_ERROR if reprovisioning is needed, due to a
+ * Returns MEDIADRM_NOT_PROVISIONED_ERROR if reprovisioning is needed, due to a
* problem with the device certificate.
-*/
+ *
+ * Available since API level 21.
+ */
media_status_t AMediaDrm_getKeyRequest(AMediaDrm *, const AMediaDrmScope *scope,
const uint8_t *init, size_t initSize, const char *mimeType, AMediaDrmKeyType keyType,
const AMediaDrmKeyValue *optionalParameters, size_t numOptionalParameters,
@@ -295,8 +313,9 @@
*
* response points to the opaque response from the server
* responseSize should be set to the size of the response in bytes
+ *
+ * Available since API level 21.
*/
-
media_status_t AMediaDrm_provideKeyResponse(AMediaDrm *, const AMediaDrmScope *scope,
const uint8_t *response, size_t responseSize,
AMediaDrmKeySetId *keySetId) __INTRODUCED_IN(21);
@@ -305,8 +324,10 @@
* Restore persisted offline keys into a new session. keySetId identifies the
* keys to load, obtained from a prior call to AMediaDrm_provideKeyResponse.
*
- * sessionId is the session ID for the DRM session
- * keySetId identifies the saved key set to restore
+ * sessionId is the session ID for the DRM session.
+ * keySetId identifies the saved key set to restore.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaDrm_restoreKeys(AMediaDrm *, const AMediaDrmSessionId *sessionId,
const AMediaDrmKeySetId *keySetId) __INTRODUCED_IN(21);
@@ -314,7 +335,9 @@
/**
* Remove the current keys from a session.
*
- * keySetId identifies keys to remove
+ * keySetId identifies keys to remove.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaDrm_removeKeys(AMediaDrm *,
const AMediaDrmSessionId *keySetId) __INTRODUCED_IN(21);
@@ -331,6 +354,8 @@
* to the number of entries written to the array. If the number of {key, value} pairs
* to be returned is greater than *numPairs, MEDIADRM_SHORT_BUFFER will be returned
* and numPairs will be set to the number of pairs available.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaDrm_queryKeyStatus(AMediaDrm *, const AMediaDrmSessionId *sessionId,
AMediaDrmKeyValue *keyValuePairs, size_t *numPairs) __INTRODUCED_IN(21);
@@ -350,6 +375,8 @@
* 3. serverUrl will reference a NULL terminated string containing the URL
* the provisioning request should be sent to. It will remain accessible until
* the next call to getProvisionRequest.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaDrm_getProvisionRequest(AMediaDrm *, const uint8_t **provisionRequest,
size_t *provisionRequestSize, const char **serverUrl) __INTRODUCED_IN(21);
@@ -363,8 +390,10 @@
* DRM engine plugin.
* responseSize is the length of the provisioning response in bytes.
*
- * returns MEDIADRM_DEVICE_REVOKED_ERROR if the response indicates that the
+ * Returns MEDIADRM_DEVICE_REVOKED_ERROR if the response indicates that the
* server rejected the request
+ *
+ * Available since API level 21.
*/
media_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *,
const uint8_t *response, size_t responseSize) __INTRODUCED_IN(21);
@@ -390,6 +419,8 @@
* If *numSecureStops is too small for the number of secure stops available,
* MEDIADRM_SHORT_BUFFER will be returned and *numSecureStops will be set to the
* number required.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaDrm_getSecureStops(AMediaDrm *,
AMediaDrmSecureStop *secureStops, size_t *numSecureStops) __INTRODUCED_IN(21);
@@ -399,6 +430,8 @@
* the message, remove the SecureStops identified in the response.
*
* ssRelease is the server response indicating which secure stops to release
+ *
+ * Available since API level 21.
*/
media_status_t AMediaDrm_releaseSecureStops(AMediaDrm *,
const AMediaDrmSecureStop *ssRelease) __INTRODUCED_IN(21);
@@ -432,6 +465,8 @@
* On return, propertyValue will be set to point to the property value. The
* memory that the value resides in is owned by the NDK MediaDrm API and
* will remain valid until the next call to AMediaDrm_getPropertyString.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaDrm_getPropertyString(AMediaDrm *, const char *propertyName,
const char **propertyValue) __INTRODUCED_IN(21);
@@ -447,18 +482,24 @@
* On return, *propertyValue will be set to point to the property value. The
* memory that the value resides in is owned by the NDK MediaDrm API and
* will remain valid until the next call to AMediaDrm_getPropertyByteArray.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *, const char *propertyName,
AMediaDrmByteArray *propertyValue) __INTRODUCED_IN(21);
/**
* Set a DRM engine plugin String property value.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaDrm_setPropertyString(AMediaDrm *, const char *propertyName,
const char *value) __INTRODUCED_IN(21);
/**
* Set a DRM engine plugin byte array property value.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *, const char *propertyName,
const uint8_t *value, size_t valueSize) __INTRODUCED_IN(21);
@@ -487,6 +528,8 @@
* ensure that the output buffer is large enough to accept dataSize bytes. The key
* to use is identified by the 16 byte keyId. The key must have been loaded into
* the session using provideKeyResponse.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaDrm_encrypt(AMediaDrm *, const AMediaDrmSessionId *sessionId,
const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
@@ -498,6 +541,8 @@
* ensure that the output buffer is large enough to accept dataSize bytes. The key
* to use is identified by the 16 byte keyId. The key must have been loaded into
* the session using provideKeyResponse.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaDrm_decrypt(AMediaDrm *, const AMediaDrmSessionId *sessionId,
const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
@@ -511,6 +556,8 @@
* *signatureSize is set to the buffer size required. The key to use is identified
* by the 16 byte keyId. The key must have been loaded into the session using
* provideKeyResponse.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaDrm_sign(AMediaDrm *, const AMediaDrmSessionId *sessionId,
const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize,
@@ -522,6 +569,8 @@
* if the signature matches, otherwise MEDAIDRM_VERIFY_FAILED is returned. The key to
* use is identified by the 16 byte keyId. The key must have been loaded into the
* session using provideKeyResponse.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaDrm_verify(AMediaDrm *, const AMediaDrmSessionId *sessionId,
const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize,
diff --git a/media/ndk/include/media/NdkMediaExtractor.h b/media/ndk/include/media/NdkMediaExtractor.h
index e3d9fe6..14319c4 100644
--- a/media/ndk/include/media/NdkMediaExtractor.h
+++ b/media/ndk/include/media/NdkMediaExtractor.h
@@ -52,23 +52,31 @@
#if __ANDROID_API__ >= 21
/**
- * Create new media extractor
+ * Create new media extractor.
+ *
+ * Available since API level 21.
*/
AMediaExtractor* AMediaExtractor_new() __INTRODUCED_IN(21);
/**
- * Delete a previously created media extractor
+ * Delete a previously created media extractor.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaExtractor_delete(AMediaExtractor*) __INTRODUCED_IN(21);
/**
- * Set the file descriptor from which the extractor will read.
+ * Set the file descriptor from which the extractor will read.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaExtractor_setDataSourceFd(AMediaExtractor*, int fd, off64_t offset,
off64_t length) __INTRODUCED_IN(21);
/**
* Set the URI from which the extractor will read.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaExtractor_setDataSource(AMediaExtractor*,
const char *location) __INTRODUCED_IN(21);
@@ -77,6 +85,8 @@
/**
* Set the custom data source implementation from which the extractor will read.
+ *
+ * Available since API level 28.
*/
media_status_t AMediaExtractor_setDataSourceCustom(AMediaExtractor*,
AMediaDataSource *src) __INTRODUCED_IN(28);
@@ -85,11 +95,15 @@
/**
* Return the number of tracks in the previously specified media file
+ *
+ * Available since API level 21.
*/
size_t AMediaExtractor_getTrackCount(AMediaExtractor*) __INTRODUCED_IN(21);
/**
* Return the format of the specified track. The caller must free the returned format
+ *
+ * Available since API level 21.
*/
AMediaFormat* AMediaExtractor_getTrackFormat(AMediaExtractor*, size_t idx) __INTRODUCED_IN(21);
@@ -98,41 +112,55 @@
* getSampleTime only retrieve information for the subset of tracks selected.
* Selecting the same track multiple times has no effect, the track is
* only selected once.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaExtractor_selectTrack(AMediaExtractor*, size_t idx) __INTRODUCED_IN(21);
/**
* Unselect the specified track. Subsequent calls to readSampleData, getSampleTrackIndex and
- * getSampleTime only retrieve information for the subset of tracks selected..
+ * getSampleTime only retrieve information for the subset of tracks selected.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaExtractor_unselectTrack(AMediaExtractor*, size_t idx) __INTRODUCED_IN(21);
/**
* Read the current sample.
+ *
+ * Available since API level 21.
*/
ssize_t AMediaExtractor_readSampleData(AMediaExtractor*,
uint8_t *buffer, size_t capacity) __INTRODUCED_IN(21);
/**
* Read the current sample's flags.
+ *
+ * Available since API level 21.
*/
uint32_t AMediaExtractor_getSampleFlags(AMediaExtractor*) __INTRODUCED_IN(21);
/**
* Returns the track index the current sample originates from (or -1
* if no more samples are available)
+ *
+ * Available since API level 21.
*/
int AMediaExtractor_getSampleTrackIndex(AMediaExtractor*) __INTRODUCED_IN(21);
/**
* Returns the current sample's presentation time in microseconds.
* or -1 if no more samples are available.
+ *
+ * Available since API level 21.
*/
int64_t AMediaExtractor_getSampleTime(AMediaExtractor*) __INTRODUCED_IN(21);
/**
* Advance to the next sample. Returns false if no more sample data
* is available (end of stream).
+ *
+ * Available since API level 21.
*/
bool AMediaExtractor_advance(AMediaExtractor*) __INTRODUCED_IN(21);
@@ -143,7 +171,7 @@
} SeekMode;
/**
- *
+ * Available since API level 21.
*/
media_status_t AMediaExtractor_seekTo(AMediaExtractor*,
int64_t seekPosUs, SeekMode mode) __INTRODUCED_IN(21);
@@ -167,10 +195,14 @@
/**
* Get the PSSH info if present.
+ *
+ * Available since API level 21.
*/
PsshInfo* AMediaExtractor_getPsshInfo(AMediaExtractor*) __INTRODUCED_IN(21);
-
+/**
+ * Available since API level 21.
+ */
AMediaCodecCryptoInfo *AMediaExtractor_getSampleCryptoInfo(AMediaExtractor *) __INTRODUCED_IN(21);
enum {
@@ -186,6 +218,8 @@
*
* This function will always return a format; however, the format could be empty
* (no key-value pairs) if the media container does not provide format information.
+ *
+ * Available since API level 28.
*/
AMediaFormat* AMediaExtractor_getFileFormat(AMediaExtractor*) __INTRODUCED_IN(28);
@@ -198,6 +232,7 @@
* uint8_t *buf = new uint8_t[sampleSize];
* AMediaExtractor_readSampleData(ex, buf, sampleSize);
*
+ * Available since API level 28.
*/
ssize_t AMediaExtractor_getSampleSize(AMediaExtractor*) __INTRODUCED_IN(28);
@@ -211,6 +246,8 @@
* Returns -1 when the extractor is not reading from a network data source, or when the
* cached duration cannot be calculated (bitrate, duration, and file size information
* not available).
+ *
+ * Available since API level 28.
*/
int64_t AMediaExtractor_getCachedDuration(AMediaExtractor *) __INTRODUCED_IN(28);
@@ -222,6 +259,8 @@
* Returns AMEDIA_OK on success or AMEDIA_ERROR_* to indicate failure reason.
* Existing key-value pairs in |fmt| would be removed if this API returns AMEDIA_OK.
* The contents of |fmt| is undefined if this API returns AMEDIA_ERROR_*.
+ *
+ * Available since API level 28.
*/
media_status_t AMediaExtractor_getSampleFormat(AMediaExtractor *ex,
AMediaFormat *fmt) __INTRODUCED_IN(28);
diff --git a/media/ndk/include/media/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
index fd43f36..49d8b4a 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -48,40 +48,78 @@
#if __ANDROID_API__ >= 21
+/**
+ * Available since API level 21.
+ */
AMediaFormat *AMediaFormat_new() __INTRODUCED_IN(21);
+
+/**
+ * Available since API level 21.
+ */
media_status_t AMediaFormat_delete(AMediaFormat*) __INTRODUCED_IN(21);
/**
* Human readable representation of the format. The returned string is owned by the format,
* and remains valid until the next call to toString, or until the format is deleted.
+ *
+ * Available since API level 21.
*/
const char* AMediaFormat_toString(AMediaFormat*) __INTRODUCED_IN(21);
+/**
+ * Available since API level 21.
+ */
bool AMediaFormat_getInt32(AMediaFormat*, const char *name, int32_t *out) __INTRODUCED_IN(21);
+/**
+ * Available since API level 21.
+ */
bool AMediaFormat_getInt64(AMediaFormat*, const char *name, int64_t *out) __INTRODUCED_IN(21);
+/**
+ * Available since API level 21.
+ */
bool AMediaFormat_getFloat(AMediaFormat*, const char *name, float *out) __INTRODUCED_IN(21);
+/**
+ * Available since API level 21.
+ */
bool AMediaFormat_getSize(AMediaFormat*, const char *name, size_t *out) __INTRODUCED_IN(21);
/**
* The returned data is owned by the format and remains valid as long as the named entry
* is part of the format.
+ *
+ * Available since API level 21.
*/
bool AMediaFormat_getBuffer(AMediaFormat*, const char *name, void** data, size_t *size) __INTRODUCED_IN(21);
/**
* The returned string is owned by the format, and remains valid until the next call to getString,
* or until the format is deleted.
+ *
+ * Available since API level 21.
*/
bool AMediaFormat_getString(AMediaFormat*, const char *name, const char **out) __INTRODUCED_IN(21);
+/**
+ * Available since API level 21.
+ */
void AMediaFormat_setInt32(AMediaFormat*, const char* name, int32_t value) __INTRODUCED_IN(21);
+/**
+ * Available since API level 21.
+ */
void AMediaFormat_setInt64(AMediaFormat*, const char* name, int64_t value) __INTRODUCED_IN(21);
+/**
+ * Available since API level 21.
+ */
void AMediaFormat_setFloat(AMediaFormat*, const char* name, float value) __INTRODUCED_IN(21);
/**
* The provided string is copied into the format.
+ *
+ * Available since API level 21.
*/
void AMediaFormat_setString(AMediaFormat*, const char* name, const char* value) __INTRODUCED_IN(21);
/**
* The provided data is copied into the format.
+ *
+ * Available since API level 21.
*/
void AMediaFormat_setBuffer(AMediaFormat*, const char* name, const void* data, size_t size) __INTRODUCED_IN(21);
@@ -155,24 +193,43 @@
#endif /* __ANDROID_API__ >= 21 */
#if __ANDROID_API__ >= 28
+/**
+ * Available since API level 28.
+ */
bool AMediaFormat_getDouble(AMediaFormat*, const char *name, double *out) __INTRODUCED_IN(28);
+/**
+ * Available since API level 28.
+ */
bool AMediaFormat_getRect(AMediaFormat*, const char *name,
int32_t *left, int32_t *top, int32_t *right, int32_t *bottom) __INTRODUCED_IN(28);
+/**
+ * Available since API level 28.
+ */
void AMediaFormat_setDouble(AMediaFormat*, const char* name, double value) __INTRODUCED_IN(28);
+/**
+ * Available since API level 28.
+ */
void AMediaFormat_setSize(AMediaFormat*, const char* name, size_t value) __INTRODUCED_IN(28);
+/**
+ * Available since API level 28.
+ */
void AMediaFormat_setRect(AMediaFormat*, const char* name,
int32_t left, int32_t top, int32_t right, int32_t bottom) __INTRODUCED_IN(28);
#endif /* __ANDROID_API__ >= 28 */
#if __ANDROID_API__ >= 29
/**
- * remove all key/value pairs from the given AMediaFormat
+ * Remove all key/value pairs from the given AMediaFormat.
+ *
+ * Available since API level 29.
*/
void AMediaFormat_clear(AMediaFormat*) __INTRODUCED_IN(29);
/**
- * copy one AMediaFormat to another
+ * Copy one AMediaFormat to another.
+ *
+ * Available since API level 29.
*/
media_status_t AMediaFormat_copy(AMediaFormat *to, AMediaFormat *from) __INTRODUCED_IN(29);
@@ -237,6 +294,19 @@
#endif /* __ANDROID_API__ >= 29 */
+#if __ANDROID_API__ >= 30
+/**
+ * An optional key describing the low latency decoding mode. This is an optional parameter
+ * that applies only to decoders. If enabled, the decoder doesn't hold input and output
+ * data more than required by the codec standards.
+ * The associated value is an integer (0 or 1): 1 when low-latency decoding is enabled,
+ * 0 otherwise. The default value is 0.
+ *
+ * Available since API level 30.
+ */
+extern const char* AMEDIAFORMAT_KEY_LOW_LATENCY __INTRODUCED_IN(30);
+#endif /* __ANDROID_API__ >= 30 */
+
__END_DECLS
#endif // _NDK_MEDIA_FORMAT_H
diff --git a/media/ndk/include/media/NdkMediaMuxer.h b/media/ndk/include/media/NdkMediaMuxer.h
index 7393867..9de3fbf 100644
--- a/media/ndk/include/media/NdkMediaMuxer.h
+++ b/media/ndk/include/media/NdkMediaMuxer.h
@@ -51,17 +51,22 @@
typedef enum {
AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4 = 0,
AMEDIAMUXER_OUTPUT_FORMAT_WEBM = 1,
+ AMEDIAMUXER_OUTPUT_FORMAT_THREE_GPP = 2,
} OutputFormat;
#if __ANDROID_API__ >= 21
/**
- * Create new media muxer
+ * Create new media muxer.
+ *
+ * Available since API level 21.
*/
AMediaMuxer* AMediaMuxer_new(int fd, OutputFormat format) __INTRODUCED_IN(21);
/**
- * Delete a previously created media muxer
+ * Delete a previously created media muxer.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaMuxer_delete(AMediaMuxer*) __INTRODUCED_IN(21);
@@ -75,6 +80,8 @@
* Both values are specified in degrees.
* Latitude must be in the range [-90, 90].
* Longitude must be in the range [-180, 180].
+ *
+ * Available since API level 21.
*/
media_status_t AMediaMuxer_setLocation(AMediaMuxer*,
float latitude, float longitude) __INTRODUCED_IN(21);
@@ -90,6 +97,8 @@
* during playback.
* The angle is specified in degrees, clockwise.
* The supported angles are 0, 90, 180, and 270 degrees.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaMuxer_setOrientationHint(AMediaMuxer*, int degrees) __INTRODUCED_IN(21);
@@ -97,18 +106,24 @@
* Adds a track with the specified format.
* Returns the index of the new track or a negative value in case of failure,
* which can be interpreted as a media_status_t.
+ *
+ * Available since API level 21.
*/
ssize_t AMediaMuxer_addTrack(AMediaMuxer*, const AMediaFormat* format) __INTRODUCED_IN(21);
/**
* Start the muxer. Should be called after AMediaMuxer_addTrack and
* before AMediaMuxer_writeSampleData.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaMuxer_start(AMediaMuxer*) __INTRODUCED_IN(21);
/**
* Stops the muxer.
* Once the muxer stops, it can not be restarted.
+ *
+ * Available since API level 21.
*/
media_status_t AMediaMuxer_stop(AMediaMuxer*) __INTRODUCED_IN(21);
@@ -118,6 +133,8 @@
* the right tracks. Also, it needs to make sure the samples for each track
* are written in chronological order (e.g. in the order they are provided
* by the encoder.)
+ *
+ * Available since API level 21.
*/
media_status_t AMediaMuxer_writeSampleData(AMediaMuxer *muxer,
size_t trackIdx, const uint8_t *data,
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index f666ad0..29f1da8 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -4,7 +4,7 @@
AImageReader_acquireLatestImageAsync; # introduced=26
AImageReader_acquireNextImage; # introduced=24
AImageReader_acquireNextImageAsync; # introduced=26
- AImageReader_getWindowNativeHandle; #vndk
+ AImageReader_getWindowNativeHandle; # llndk
AImageReader_delete; # introduced=24
AImageReader_getFormat; # introduced=24
AImageReader_getHeight; # introduced=24
@@ -105,6 +105,7 @@
AMEDIAFORMAT_KEY_LEVEL; # var introduced=28
AMEDIAFORMAT_KEY_LOCATION; # var introduced=29
AMEDIAFORMAT_KEY_LOOP; # var introduced=29
+ AMEDIAFORMAT_KEY_LOW_LATENCY; # var introduced=30
AMEDIAFORMAT_KEY_LYRICIST; # var introduced=29
AMEDIAFORMAT_KEY_MANUFACTURER; # var introduced=29
AMEDIAFORMAT_KEY_MAX_BIT_RATE; # var introduced=29
diff --git a/media/tests/benchmark/.clang-format b/media/tests/benchmark/.clang-format
new file mode 100644
index 0000000..bf1e355
--- /dev/null
+++ b/media/tests/benchmark/.clang-format
@@ -0,0 +1,13 @@
+BasedOnStyle: Google
+Standard: Cpp11
+AccessModifierOffset: -2
+AllowShortFunctionsOnASingleLine: Inline
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+IncludeBlocks: Preserve
+IndentWidth: 4
+ContinuationIndentWidth: 8
+PointerAlignment: Right
+TabWidth: 4
+UseTab: Never
diff --git a/media/tests/benchmark/Android.bp b/media/tests/benchmark/Android.bp
new file mode 100644
index 0000000..de408dd
--- /dev/null
+++ b/media/tests/benchmark/Android.bp
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+subdirs = [
+ "src",
+ "tests",
+ "MediaBenchmarkTest",
+]
diff --git a/media/tests/benchmark/MediaBenchmarkTest/Android.bp b/media/tests/benchmark/MediaBenchmarkTest/Android.bp
new file mode 100644
index 0000000..d80d9a5
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/Android.bp
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+android_test {
+ name: "MediaBenchmarkTest",
+
+ defaults: [
+ "MediaBenchmark-defaults",
+ ],
+
+ // Include all the test code
+ srcs: ["src/androidTest/**/*.java"],
+
+ resource_dirs: ["res"],
+
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+
+ jni_libs: [
+ "libmediabenchmark_jni",
+ ],
+
+ static_libs: [
+ "libMediaBenchmark",
+ "junit",
+ "androidx.test.runner",
+ ],
+}
+
+android_library {
+ name: "libMediaBenchmark",
+
+ defaults: [
+ "MediaBenchmark-defaults",
+ ],
+
+ // Include all the libraries
+ srcs: ["src/main/**/*.java"],
+
+ static_libs: [
+ "androidx.test.core",
+ ],
+}
+
+java_defaults {
+ name: "MediaBenchmark-defaults",
+
+ sdk_version: "system_current",
+ min_sdk_version: "28",
+ target_sdk_version: "29",
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/AndroidManifest.xml b/media/tests/benchmark/MediaBenchmarkTest/AndroidManifest.xml
new file mode 100644
index 0000000..eea9914
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.android.media.benchmark">
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
+
+ <application
+ tools:ignore="AllowBackup,GoogleAppIndexingWarning,MissingApplicationIcon"
+ tools:remove="android:appComponentFactory">
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.media.benchmark"
+ android:label="Benchmark Media Test"/>
+</manifest>
\ No newline at end of file
diff --git a/media/tests/benchmark/MediaBenchmarkTest/AndroidTest.xml b/media/tests/benchmark/MediaBenchmarkTest/AndroidTest.xml
new file mode 100644
index 0000000..1890661
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/AndroidTest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs Media Benchmark Tests">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push-file"
+ key="https://storage.googleapis.com/android_media/frameworks/av/media/tests/benchmark/MediaBenchmark.zip?unzip=true"
+ value="/data/local/tmp/MediaBenchmark/res/" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="cleanup-apks" value="false" />
+ <option name="test-file-name" value="MediaBenchmarkTest.apk" />
+ </target_preparer>
+
+ <option name="test-tag" value="MediaBenchmarkTest" />
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.media.benchmark" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+</configuration>
diff --git a/media/tests/benchmark/MediaBenchmarkTest/build.gradle b/media/tests/benchmark/MediaBenchmarkTest/build.gradle
new file mode 100644
index 0000000..b2aee1a
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/build.gradle
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+buildscript {
+ repositories {
+ google()
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.5.0'
+ }
+}
+
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 29
+ defaultConfig {
+ applicationId "com.android.media.benchmark"
+ minSdkVersion 28
+ targetSdkVersion 29
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+ sourceSets {
+ main {
+ java.srcDirs 'src/main/java'
+ res.srcDirs 'res'
+ manifest.srcFile 'AndroidManifest.xml'
+ }
+ androidTest {
+ java.srcDirs 'src/androidTest/java'
+ res.srcDirs 'res'
+ manifest.srcFile 'AndroidManifest.xml'
+ }
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+ externalNativeBuild {
+ cmake {
+ path "src/main/cpp/CMakeLists.txt"
+ version "3.10.2"
+ }
+ }
+}
+
+repositories {
+ google()
+ jcenter()
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ implementation 'androidx.appcompat:appcompat:1.1.0'
+ testImplementation 'junit:junit:4.12'
+ androidTestImplementation 'androidx.test:runner:1.2.0'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.1'
+}
\ No newline at end of file
diff --git a/media/tests/benchmark/MediaBenchmarkTest/res/values/strings.xml b/media/tests/benchmark/MediaBenchmarkTest/res/values/strings.xml
new file mode 100644
index 0000000..24dbccc
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/res/values/strings.xml
@@ -0,0 +1,4 @@
+<resources>
+ <string name="input_file_path">/data/local/tmp/MediaBenchmark/res/</string>
+ <string name="output_file_path">/data/local/tmp/MediaBenchmark/output/</string>
+</resources>
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/DecoderTest.java b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/DecoderTest.java
new file mode 100644
index 0000000..afd70a3
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/DecoderTest.java
@@ -0,0 +1,220 @@
+/*
+ * 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.
+ */
+
+package com.android.media.benchmark.tests;
+
+import android.content.Context;
+import android.media.MediaCodec;
+import android.media.MediaFormat;
+import android.util.Log;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.media.benchmark.R;
+import com.android.media.benchmark.library.CodecUtils;
+import com.android.media.benchmark.library.Decoder;
+import com.android.media.benchmark.library.Extractor;
+import com.android.media.benchmark.library.Native;
+import com.android.media.benchmark.library.Stats;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+
+@RunWith(Parameterized.class)
+public class DecoderTest {
+ private static final Context mContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
+ private static final String mInputFilePath = mContext.getString(R.string.input_file_path);
+ private static final String mOutputFilePath = mContext.getString(R.string.output_file_path);
+ private static final String mStatsFile =
+ mContext.getExternalFilesDir(null) + "/Decoder." + System.currentTimeMillis() + ".csv";
+ private static final String TAG = "DecoderTest";
+ private static final long PER_TEST_TIMEOUT_MS = 60000;
+ private static final boolean DEBUG = false;
+ private static final boolean WRITE_OUTPUT = false;
+ private String mInputFile;
+ private boolean mAsyncMode;
+
+ public DecoderTest(String inputFile, boolean asyncMode) {
+ this.mInputFile = inputFile;
+ this.mAsyncMode = asyncMode;
+ }
+
+ @Parameterized.Parameters
+ public static Collection<Object[]> input() {
+ return Arrays.asList(new Object[][]{
+ //Audio Sync Test
+ {"bbb_44100hz_2ch_128kbps_aac_30sec.mp4", false},
+ {"bbb_44100hz_2ch_128kbps_mp3_30sec.mp3", false},
+ {"bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", false},
+ {"bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", false},
+ {"bbb_44100hz_2ch_80kbps_vorbis_30sec.webm", false},
+ {"bbb_44100hz_2ch_600kbps_flac_30sec.mp4", false},
+ {"bbb_48000hz_2ch_100kbps_opus_30sec.webm", false},
+ // Audio Async Test
+ {"bbb_44100hz_2ch_128kbps_aac_30sec.mp4", true},
+ {"bbb_44100hz_2ch_128kbps_mp3_30sec.mp3", true},
+ {"bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", true},
+ {"bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", true},
+ {"bbb_44100hz_2ch_80kbps_vorbis_30sec.webm", true},
+ {"bbb_44100hz_2ch_600kbps_flac_30sec.mp4", true},
+ {"bbb_48000hz_2ch_100kbps_opus_30sec.webm", true},
+ // Video Sync Test
+ {"crowd_1920x1080_25fps_4000kbps_vp9.webm", false},
+ {"crowd_1920x1080_25fps_4000kbps_vp8.webm", false},
+ {"crowd_1920x1080_25fps_4000kbps_av1.webm", false},
+ {"crowd_1920x1080_25fps_7300kbps_mpeg2.mp4", false},
+ {"crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", false},
+ {"crowd_352x288_25fps_6000kbps_h263.3gp", false},
+ {"crowd_1920x1080_25fps_6700kbps_h264.ts", false},
+ {"crowd_1920x1080_25fps_4000kbps_h265.mkv", false},
+ // Video Async Test
+ {"crowd_1920x1080_25fps_4000kbps_vp9.webm", true},
+ {"crowd_1920x1080_25fps_4000kbps_vp8.webm", true},
+ {"crowd_1920x1080_25fps_4000kbps_av1.webm", true},
+ {"crowd_1920x1080_25fps_7300kbps_mpeg2.mp4", true},
+ {"crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", true},
+ {"crowd_352x288_25fps_6000kbps_h263.3gp", true},
+ {"crowd_1920x1080_25fps_6700kbps_h264.ts", true},
+ {"crowd_1920x1080_25fps_4000kbps_h265.mkv", true}});
+ }
+
+ @BeforeClass
+ public static void writeStatsHeaderToFile() throws IOException {
+ Stats mStats = new Stats();
+ boolean status = mStats.writeStatsHeader(mStatsFile);
+ assertTrue("Unable to open stats file for writing!", status);
+ Log.d(TAG, "Saving Benchmark results in: " + mStatsFile);
+ }
+
+ @Test(timeout = PER_TEST_TIMEOUT_MS)
+ public void testDecoder() throws IOException {
+ File inputFile = new File(mInputFilePath + mInputFile);
+ assertTrue("Cannot find " + mInputFile + " in directory " + mInputFilePath,
+ inputFile.exists());
+ FileInputStream fileInput = new FileInputStream(inputFile);
+ FileDescriptor fileDescriptor = fileInput.getFD();
+ Extractor extractor = new Extractor();
+ int trackCount = extractor.setUpExtractor(fileDescriptor);
+ assertTrue("Extraction failed. No tracks for file: " + mInputFile, (trackCount > 0));
+ ArrayList<ByteBuffer> inputBuffer = new ArrayList<>();
+ ArrayList<MediaCodec.BufferInfo> frameInfo = new ArrayList<>();
+ for (int currentTrack = 0; currentTrack < trackCount; currentTrack++) {
+ extractor.selectExtractorTrack(currentTrack);
+ MediaFormat format = extractor.getFormat(currentTrack);
+ String mime = format.getString(MediaFormat.KEY_MIME);
+ ArrayList<String> mediaCodecs = CodecUtils.selectCodecs(mime, false);
+ assertTrue("No suitable codecs found for file: " + mInputFile + " track : " +
+ currentTrack + " mime: " + mime, (mediaCodecs.size() > 0));
+
+ // Get samples from extractor
+ int sampleSize;
+ do {
+ sampleSize = extractor.getFrameSample();
+ MediaCodec.BufferInfo bufInfo = new MediaCodec.BufferInfo();
+ MediaCodec.BufferInfo info = extractor.getBufferInfo();
+ ByteBuffer dataBuffer = ByteBuffer.allocate(info.size);
+ dataBuffer.put(extractor.getFrameBuffer().array(), 0, info.size);
+ bufInfo.set(info.offset, info.size, info.presentationTimeUs, info.flags);
+ inputBuffer.add(dataBuffer);
+ frameInfo.add(bufInfo);
+ if (DEBUG) {
+ Log.d(TAG, "Extracted bufInfo: flag = " + bufInfo.flags + " timestamp = " +
+ bufInfo.presentationTimeUs + " size = " + bufInfo.size);
+ }
+ } while (sampleSize > 0);
+ for (String codecName : mediaCodecs) {
+ FileOutputStream decodeOutputStream = null;
+ if (WRITE_OUTPUT) {
+ if (!Paths.get(mOutputFilePath).toFile().exists()) {
+ Files.createDirectories(Paths.get(mOutputFilePath));
+ }
+ File outFile = new File(mOutputFilePath + "decoder.out");
+ if (outFile.exists()) {
+ assertTrue(" Unable to delete existing file" + outFile.toString(),
+ outFile.delete());
+ }
+ assertTrue("Unable to create file: " + outFile.toString(),
+ outFile.createNewFile());
+ decodeOutputStream = new FileOutputStream(outFile);
+ }
+ Decoder decoder = new Decoder();
+ decoder.setupDecoder(decodeOutputStream);
+ int status = decoder.decode(inputBuffer, frameInfo, mAsyncMode, format, codecName);
+ decoder.deInitCodec();
+ assertEquals("Decoder returned error " + status + " for file: " + mInputFile +
+ " with codec: " + codecName, 0, status);
+ decoder.dumpStatistics(mInputFile, codecName, (mAsyncMode ? "async" : "sync"),
+ extractor.getClipDuration(), mStatsFile);
+ Log.i(TAG, "Decoding Successful for file: " + mInputFile + " with codec: " +
+ codecName);
+ decoder.resetDecoder();
+ if (decodeOutputStream != null) {
+ decodeOutputStream.close();
+ }
+ }
+ extractor.unselectExtractorTrack(currentTrack);
+ inputBuffer.clear();
+ frameInfo.clear();
+ }
+ extractor.deinitExtractor();
+ fileInput.close();
+ }
+
+ @Test
+ public void testNativeDecoder() throws IOException {
+ File inputFile = new File(mInputFilePath + mInputFile);
+ assertTrue("Cannot find " + mInputFile + " in directory " + mInputFilePath,
+ inputFile.exists());
+ FileInputStream fileInput = new FileInputStream(inputFile);
+ FileDescriptor fileDescriptor = fileInput.getFD();
+ Extractor extractor = new Extractor();
+ int trackCount = extractor.setUpExtractor(fileDescriptor);
+ assertTrue("Extraction failed. No tracks for file: ", trackCount > 0);
+ for (int currentTrack = 0; currentTrack < trackCount; currentTrack++) {
+ extractor.selectExtractorTrack(currentTrack);
+ MediaFormat format = extractor.getFormat(currentTrack);
+ String mime = format.getString(MediaFormat.KEY_MIME);
+ ArrayList<String> mediaCodecs = CodecUtils.selectCodecs(mime, false);
+ for (String codecName : mediaCodecs) {
+ Log.i("Test: %s\n", mInputFile);
+ Native nativeDecoder = new Native();
+ int status = nativeDecoder.Decode(
+ mInputFilePath, mInputFile, mStatsFile, codecName, mAsyncMode);
+ assertEquals("Decoder returned error " + status + " for file: " + mInputFile, 0,
+ status);
+ }
+ }
+ fileInput.close();
+ }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/EncoderTest.java b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/EncoderTest.java
new file mode 100644
index 0000000..48e1422
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/EncoderTest.java
@@ -0,0 +1,308 @@
+/*
+ * 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.
+ */
+
+package com.android.media.benchmark.tests;
+
+import android.content.Context;
+import android.media.MediaCodec;
+import android.media.MediaFormat;
+
+import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible;
+
+import android.util.Log;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.media.benchmark.R;
+import com.android.media.benchmark.library.CodecUtils;
+import com.android.media.benchmark.library.Decoder;
+import com.android.media.benchmark.library.Encoder;
+import com.android.media.benchmark.library.Extractor;
+import com.android.media.benchmark.library.Native;
+import com.android.media.benchmark.library.Stats;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+
+@RunWith(Parameterized.class)
+public class EncoderTest {
+ private static final Context mContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
+ private static final String mInputFilePath = mContext.getString(R.string.input_file_path);
+ private static final String mOutputFilePath = mContext.getString(R.string.output_file_path);
+ private static final String mStatsFile =
+ mContext.getExternalFilesDir(null) + "/Encoder." + System.currentTimeMillis() + ".csv";
+ private static final String TAG = "EncoderTest";
+ private static final long PER_TEST_TIMEOUT_MS = 120000;
+ private static final boolean DEBUG = false;
+ private static final boolean WRITE_OUTPUT = false;
+ private static final int ENCODE_DEFAULT_FRAME_RATE = 25;
+ private static final int ENCODE_DEFAULT_BIT_RATE = 8000000 /* 8 Mbps */;
+ private static final int ENCODE_MIN_BIT_RATE = 600000 /* 600 Kbps */;
+ private static final int ENCODE_DEFAULT_AUDIO_BIT_RATE = 128000 /* 128 Kbps */;
+ private String mInputFile;
+
+ @Parameterized.Parameters
+ public static Collection<Object[]> inputFiles() {
+ return Arrays.asList(new Object[][]{
+ // Audio Test
+ {"bbb_44100hz_2ch_128kbps_aac_30sec.mp4"},
+ {"bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp"},
+ {"bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp"},
+ {"bbb_44100hz_2ch_600kbps_flac_30sec.mp4"},
+ {"bbb_48000hz_2ch_100kbps_opus_30sec.webm"},
+ // Video Test
+ {"crowd_1920x1080_25fps_4000kbps_vp8.webm"},
+ {"crowd_1920x1080_25fps_6700kbps_h264.ts"},
+ {"crowd_1920x1080_25fps_4000kbps_h265.mkv"},
+ {"crowd_1920x1080_25fps_4000kbps_vp9.webm"},
+ {"crowd_176x144_25fps_6000kbps_mpeg4.mp4"},
+ {"crowd_176x144_25fps_6000kbps_h263.3gp"}});
+ }
+
+ public EncoderTest(String inputFileName) {
+ this.mInputFile = inputFileName;
+ }
+
+ @BeforeClass
+ public static void writeStatsHeaderToFile() throws IOException {
+ Stats mStats = new Stats();
+ boolean status = mStats.writeStatsHeader(mStatsFile);
+ assertTrue("Unable to open stats file for writing!", status);
+ Log.d(TAG, "Saving Benchmark results in: " + mStatsFile);
+ }
+
+ @Test(timeout = PER_TEST_TIMEOUT_MS)
+ public void testEncoder() throws Exception {
+ int status;
+ int frameSize;
+ //Parameters for video
+ int width = 0;
+ int height = 0;
+ int profile = 0;
+ int level = 0;
+ int frameRate = 0;
+
+ //Parameters for audio
+ int bitRate = 0;
+ int sampleRate = 0;
+ int numChannels = 0;
+ File inputFile = new File(mInputFilePath + mInputFile);
+ assertTrue("Cannot find " + mInputFile + " in directory " + mInputFilePath,
+ inputFile.exists());
+ FileInputStream fileInput = new FileInputStream(inputFile);
+ FileDescriptor fileDescriptor = fileInput.getFD();
+ Extractor extractor = new Extractor();
+ int trackCount = extractor.setUpExtractor(fileDescriptor);
+ assertTrue("Extraction failed. No tracks for file: " + mInputFile, (trackCount > 0));
+ ArrayList<ByteBuffer> inputBuffer = new ArrayList<>();
+ ArrayList<MediaCodec.BufferInfo> frameInfo = new ArrayList<>();
+ for (int currentTrack = 0; currentTrack < trackCount; currentTrack++) {
+ int colorFormat = COLOR_FormatYUV420Flexible;
+ extractor.selectExtractorTrack(currentTrack);
+ MediaFormat format = extractor.getFormat(currentTrack);
+ // Get samples from extractor
+ int sampleSize;
+ do {
+ sampleSize = extractor.getFrameSample();
+ MediaCodec.BufferInfo bufInfo = new MediaCodec.BufferInfo();
+ MediaCodec.BufferInfo info = extractor.getBufferInfo();
+ ByteBuffer dataBuffer = ByteBuffer.allocate(info.size);
+ dataBuffer.put(extractor.getFrameBuffer().array(), 0, info.size);
+ bufInfo.set(info.offset, info.size, info.presentationTimeUs, info.flags);
+ inputBuffer.add(dataBuffer);
+ frameInfo.add(bufInfo);
+ if (DEBUG) {
+ Log.d(TAG, "Extracted bufInfo: flag = " + bufInfo.flags + " timestamp = " +
+ bufInfo.presentationTimeUs + " size = " + bufInfo.size);
+ }
+ } while (sampleSize > 0);
+ int tid = android.os.Process.myTid();
+ File decodedFile = new File(mContext.getFilesDir() + "/decoder_" + tid + ".out");
+ FileOutputStream decodeOutputStream = new FileOutputStream(decodedFile);
+ Decoder decoder = new Decoder();
+ decoder.setupDecoder(decodeOutputStream);
+ status = decoder.decode(inputBuffer, frameInfo, false, format, "");
+ assertEquals("Decoder returned error " + status + " for file: " + mInputFile, 0,
+ status);
+ MediaFormat decoderFormat = decoder.getFormat();
+ decoder.deInitCodec();
+ extractor.unselectExtractorTrack(currentTrack);
+ inputBuffer.clear();
+ frameInfo.clear();
+ if (decodeOutputStream != null) {
+ decodeOutputStream.close();
+ }
+ String mime = format.getString(MediaFormat.KEY_MIME);
+ ArrayList<String> mediaCodecs = CodecUtils.selectCodecs(mime, true);
+ assertTrue("No suitable codecs found for file: " + mInputFile + " track : " +
+ currentTrack + " mime: " + mime, (mediaCodecs.size() > 0));
+ Boolean[] encodeMode = {true, false};
+ /* Encoding the decoder's output */
+ for (Boolean asyncMode : encodeMode) {
+ for (String codecName : mediaCodecs) {
+ FileOutputStream encodeOutputStream = null;
+ if (WRITE_OUTPUT) {
+ File outEncodeFile = new File(mOutputFilePath + "encoder.out");
+ if (outEncodeFile.exists()) {
+ assertTrue(" Unable to delete existing file" + outEncodeFile.toString(),
+ outEncodeFile.delete());
+ }
+ assertTrue("Unable to create file to write encoder output: " +
+ outEncodeFile.toString(), outEncodeFile.createNewFile());
+ encodeOutputStream = new FileOutputStream(outEncodeFile);
+ }
+ File rawFile = new File(mContext.getFilesDir() + "/decoder_" + tid + ".out");
+ assertTrue("Cannot open file to write decoded output", rawFile.exists());
+ if (DEBUG) {
+ Log.i(TAG, "Path of decoded input file: " + rawFile.toString());
+ }
+ FileInputStream eleStream = new FileInputStream(rawFile);
+ if (mime.startsWith("video/")) {
+ width = format.getInteger(MediaFormat.KEY_WIDTH);
+ height = format.getInteger(MediaFormat.KEY_HEIGHT);
+ if (format.containsKey(MediaFormat.KEY_FRAME_RATE)) {
+ frameRate = format.getInteger(MediaFormat.KEY_FRAME_RATE);
+ } else if (frameRate <= 0) {
+ frameRate = ENCODE_DEFAULT_FRAME_RATE;
+ }
+ if (format.containsKey(MediaFormat.KEY_BIT_RATE)) {
+ bitRate = format.getInteger(MediaFormat.KEY_BIT_RATE);
+ } else if (bitRate <= 0) {
+ if (mime.contains("video/3gpp") || mime.contains("video/mp4v-es")) {
+ bitRate = ENCODE_MIN_BIT_RATE;
+ } else {
+ bitRate = ENCODE_DEFAULT_BIT_RATE;
+ }
+ }
+ if (format.containsKey(MediaFormat.KEY_PROFILE)) {
+ profile = format.getInteger(MediaFormat.KEY_PROFILE);
+ }
+ if (format.containsKey(MediaFormat.KEY_PROFILE)) {
+ level = format.getInteger(MediaFormat.KEY_LEVEL);
+ }
+ if (decoderFormat.containsKey(MediaFormat.KEY_COLOR_FORMAT)) {
+ colorFormat = decoderFormat.getInteger(MediaFormat.KEY_COLOR_FORMAT);
+ }
+ } else {
+ sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
+ numChannels = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
+ if (decoderFormat.containsKey(MediaFormat.KEY_BIT_RATE)) {
+ bitRate = decoderFormat.getInteger(MediaFormat.KEY_BIT_RATE);
+ } else {
+ bitRate = ENCODE_DEFAULT_AUDIO_BIT_RATE;
+ }
+ }
+ /*Setup Encode Format*/
+ MediaFormat encodeFormat;
+ if (mime.startsWith("video/")) {
+ frameSize = width * height * 3 / 2;
+ encodeFormat = MediaFormat.createVideoFormat(mime, width, height);
+ encodeFormat.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
+ encodeFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
+ encodeFormat.setInteger(MediaFormat.KEY_PROFILE, profile);
+ encodeFormat.setInteger(MediaFormat.KEY_LEVEL, level);
+ encodeFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);
+ encodeFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, frameSize);
+ encodeFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
+ } else {
+ encodeFormat = MediaFormat.createAudioFormat(mime, sampleRate, numChannels);
+ encodeFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
+ frameSize = 4096;
+ }
+ Encoder encoder = new Encoder();
+ encoder.setupEncoder(encodeOutputStream, eleStream);
+ status = encoder.encode(codecName, encodeFormat, mime, frameRate, sampleRate,
+ frameSize, asyncMode);
+ encoder.deInitEncoder();
+ assertEquals(
+ codecName + " encoder returned error " + status + " for " + "file:" +
+ " " + mInputFile, 0, status);
+ encoder.dumpStatistics(mInputFile, codecName, (asyncMode ? "async" : "sync"),
+ extractor.getClipDuration(), mStatsFile);
+ Log.i(TAG, "Encoding complete for file: " + mInputFile + " with codec: " +
+ codecName + " for aSyncMode = " + asyncMode);
+ encoder.resetEncoder();
+ eleStream.close();
+ if (encodeOutputStream != null) {
+ encodeOutputStream.close();
+ }
+
+ }
+ }
+ //Cleanup temporary input file
+ if (decodedFile.exists()) {
+ assertTrue(" Unable to delete decoded file" + decodedFile.toString(),
+ decodedFile.delete());
+ Log.i(TAG, "Successfully deleted decoded file");
+ }
+ }
+ extractor.deinitExtractor();
+ fileInput.close();
+ }
+
+ @Test(timeout = PER_TEST_TIMEOUT_MS)
+ public void testNativeEncoder() throws Exception {
+ File inputFile = new File(mInputFilePath + mInputFile);
+ assertTrue("Cannot find " + mInputFile + " in directory " + mInputFilePath,
+ inputFile.exists());
+ int tid = android.os.Process.myTid();
+ final String mDecodedFile = mContext.getFilesDir() + "/decoder_" + tid + ".out";
+ FileInputStream fileInput = new FileInputStream(inputFile);
+ FileDescriptor fileDescriptor = fileInput.getFD();
+ Extractor extractor = new Extractor();
+ int trackCount = extractor.setUpExtractor(fileDescriptor);
+ assertTrue("Extraction failed. No tracks for file: ", trackCount > 0);
+ for (int currentTrack = 0; currentTrack < trackCount; currentTrack++) {
+ extractor.selectExtractorTrack(currentTrack);
+ MediaFormat format = extractor.getFormat(currentTrack);
+ String mime = format.getString(MediaFormat.KEY_MIME);
+ ArrayList<String> mediaCodecs = CodecUtils.selectCodecs(mime, true);
+ // Encoding the decoder's output
+ for (String codecName : mediaCodecs) {
+ Native nativeEncoder = new Native();
+ int status = nativeEncoder
+ .Encode(mInputFilePath, mInputFile, mDecodedFile, mStatsFile, codecName);
+ assertEquals(
+ codecName + " encoder returned error " + status + " for " + "file:" + " " +
+ mInputFile, 0, status);
+ }
+ }
+ File decodedFile = new File(mDecodedFile);
+ // Cleanup temporary input file
+ if (decodedFile.exists()) {
+ assertTrue("Unable to delete - " + mDecodedFile, decodedFile.delete());
+ Log.i(TAG, "Successfully deleted - " + mDecodedFile);
+ }
+ fileInput.close();
+ }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/ExtractorTest.java b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/ExtractorTest.java
new file mode 100644
index 0000000..4d026c1
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/ExtractorTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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.
+ */
+
+package com.android.media.benchmark.tests;
+
+import com.android.media.benchmark.R;
+import com.android.media.benchmark.library.Extractor;
+import com.android.media.benchmark.library.Native;
+import com.android.media.benchmark.library.Stats;
+
+import android.content.Context;
+import android.media.MediaFormat;
+import android.util.Log;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+
+import static org.junit.Assert.assertTrue;
+
+@RunWith(Parameterized.class)
+public class ExtractorTest {
+ private static Context mContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
+ private static final String mInputFilePath = mContext.getString(R.string.input_file_path);
+ private static final String mStatsFile = mContext.getExternalFilesDir(null) + "/Extractor."
+ + System.currentTimeMillis() + ".csv";
+ private static final String TAG = "ExtractorTest";
+ private String mInputFileName;
+ private int mTrackId;
+
+ @Parameterized.Parameters
+ public static Collection<Object[]> inputFiles() {
+ return Arrays.asList(new Object[][]{/* Parameters: filename, trackId*/
+ {"crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", 0},
+ {"crowd_1920x1080_25fps_6700kbps_h264.ts", 0},
+ {"crowd_1920x1080_25fps_7300kbps_mpeg2.mp4", 0},
+ {"crowd_1920x1080_25fps_4000kbps_av1.webm", 0},
+ {"crowd_1920x1080_25fps_4000kbps_h265.mkv", 0},
+ {"crowd_1920x1080_25fps_4000kbps_vp8.webm", 0},
+ {"bbb_44100hz_2ch_128kbps_aac_5mins.mp4", 0},
+ {"bbb_44100hz_2ch_128kbps_mp3_5mins.mp3", 0},
+ {"bbb_44100hz_2ch_600kbps_flac_5mins.flac", 0},
+ {"bbb_8000hz_1ch_8kbps_amrnb_5mins.3gp", 0},
+ {"bbb_16000hz_1ch_9kbps_amrwb_5mins.3gp", 0},
+ {"bbb_44100hz_2ch_80kbps_vorbis_5mins.webm", 0},
+ {"bbb_48000hz_2ch_100kbps_opus_5mins.webm", 0}});
+ }
+
+ public ExtractorTest(String filename, int track) {
+ this.mInputFileName = filename;
+ this.mTrackId = track;
+ }
+
+ @BeforeClass
+ public static void writeStatsHeaderToFile() throws IOException {
+ Stats mStats = new Stats();
+ boolean status = mStats.writeStatsHeader(mStatsFile);
+ assertTrue("Unable to open stats file for writing!", status);
+ Log.d(TAG, "Saving Benchmark results in: " + mStatsFile);
+ }
+
+ @Test
+ public void testExtractor() throws IOException {
+ File inputFile = new File(mInputFilePath + mInputFileName);
+ assertTrue("Cannot find " + mInputFileName + " in directory " + mInputFilePath,
+ inputFile.exists());
+ FileInputStream fileInput = new FileInputStream(inputFile);
+ FileDescriptor fileDescriptor = fileInput.getFD();
+ Extractor extractor = new Extractor();
+ extractor.setUpExtractor(fileDescriptor);
+ MediaFormat format = extractor.getFormat(mTrackId);
+ String mime = format.getString(MediaFormat.KEY_MIME);
+ int status = extractor.extractSample(mTrackId);
+ assertEquals("Extraction failed for " + mInputFileName, 0, status);
+ Log.i(TAG, "Extracted " + mInputFileName + " successfully.");
+ extractor.deinitExtractor();
+ extractor.dumpStatistics(mInputFileName, mime, mStatsFile);
+ fileInput.close();
+ }
+
+ @Test
+ public void testNativeExtractor() throws IOException {
+ Native nativeExtractor = new Native();
+ File inputFile = new File(mInputFilePath + mInputFileName);
+ assertTrue("Cannot find " + mInputFileName + " in directory " + mInputFilePath,
+ inputFile.exists());
+ FileInputStream fileInput = new FileInputStream(inputFile);
+ int status = nativeExtractor.Extract(mInputFilePath, mInputFileName, mStatsFile);
+ fileInput.close();
+ assertEquals("Extraction failed for " + mInputFileName, 0, status);
+ Log.i(TAG, "Extracted " + mInputFileName + " successfully.");
+ }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/MuxerTest.java b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/MuxerTest.java
new file mode 100644
index 0000000..21ba957
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/MuxerTest.java
@@ -0,0 +1,180 @@
+/*
+ * 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.
+ */
+package com.android.media.benchmark.tests;
+
+import com.android.media.benchmark.R;
+import com.android.media.benchmark.library.Extractor;
+import com.android.media.benchmark.library.Muxer;
+import com.android.media.benchmark.library.Native;
+import com.android.media.benchmark.library.Stats;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import android.content.Context;
+import android.media.MediaCodec;
+import android.media.MediaFormat;
+import android.media.MediaMuxer;
+import android.util.Log;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Hashtable;
+import java.util.Map;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import static org.junit.Assert.assertTrue;
+
+@RunWith(Parameterized.class)
+public class MuxerTest {
+ private static Context mContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
+ private static final String mInputFilePath = mContext.getString(R.string.input_file_path);
+ private static final String mStatsFile =
+ mContext.getExternalFilesDir(null) + "/Muxer." + System.currentTimeMillis() + ".csv";
+ private static final String TAG = "MuxerTest";
+ private static final Map<String, Integer> mMapFormat = new Hashtable<String, Integer>() {
+ {
+ put("mp4", MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
+ put("webm", MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM);
+ put("3gpp", MediaMuxer.OutputFormat.MUXER_OUTPUT_3GPP);
+ put("ogg", MediaMuxer.OutputFormat.MUXER_OUTPUT_OGG);
+ }
+ };
+ private String mInputFileName;
+ private String mFormat;
+
+ @Parameterized.Parameters
+ public static Collection<Object[]> inputFiles() {
+ return Arrays.asList(new Object[][]{
+ /* Parameters: filename, format */
+ {"crowd_1920x1080_25fps_4000kbps_vp8.webm", "webm"},
+ {"crowd_1920x1080_25fps_4000kbps_vp9.webm", "webm"},
+ {"crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", "mp4"},
+ {"crowd_352x288_25fps_6000kbps_h263.3gp", "mp4"},
+ {"crowd_1920x1080_25fps_6700kbps_h264.ts", "mp4"},
+ {"crowd_1920x1080_25fps_4000kbps_h265.mkv", "mp4"},
+ {"crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", "3gpp"},
+ {"crowd_352x288_25fps_6000kbps_h263.3gp", "3gpp"},
+ {"crowd_1920x1080_25fps_6700kbps_h264.ts", "3gpp"},
+ {"crowd_1920x1080_25fps_4000kbps_h265.mkv", "3gpp"},
+ {"bbb_48000hz_2ch_100kbps_opus_5mins.webm", "ogg"},
+ {"bbb_44100hz_2ch_80kbps_vorbis_5mins.webm", "webm"},
+ {"bbb_48000hz_2ch_100kbps_opus_5mins.webm", "webm"},
+ {"bbb_44100hz_2ch_128kbps_aac_5mins.mp4", "mp4"},
+ {"bbb_8000hz_1ch_8kbps_amrnb_5mins.3gp", "mp4"},
+ {"bbb_16000hz_1ch_9kbps_amrwb_5mins.3gp", "mp4"},
+ {"bbb_44100hz_2ch_128kbps_aac_5mins.mp4", "3gpp"},
+ {"bbb_8000hz_1ch_8kbps_amrnb_5mins.3gp", "3gpp"},
+ {"bbb_16000hz_1ch_9kbps_amrwb_5mins.3gp", "3gpp"}});
+ }
+
+ public MuxerTest(String filename, String outputFormat) {
+ this.mInputFileName = filename;
+ this.mFormat = outputFormat;
+ }
+
+ @BeforeClass
+ public static void writeStatsHeaderToFile() throws IOException {
+ Stats mStats = new Stats();
+ boolean status = mStats.writeStatsHeader(mStatsFile);
+ assertTrue("Unable to open stats file for writing!", status);
+ Log.d(TAG, "Saving Benchmark results in: " + mStatsFile);
+ }
+
+ @Test
+ public void testMuxer() throws IOException {
+ File inputFile = new File(mInputFilePath + mInputFileName);
+ assertTrue("Cannot find " + mInputFileName + " in directory " + mInputFilePath,
+ inputFile.exists());
+ FileInputStream fileInput = new FileInputStream(inputFile);
+ FileDescriptor fileDescriptor = fileInput.getFD();
+ ArrayList<ByteBuffer> inputBuffer = new ArrayList<>();
+ ArrayList<MediaCodec.BufferInfo> inputBufferInfo = new ArrayList<>();
+ Extractor extractor = new Extractor();
+ int trackCount = extractor.setUpExtractor(fileDescriptor);
+ for (int currentTrack = 0; currentTrack < trackCount; currentTrack++) {
+ extractor.selectExtractorTrack(currentTrack);
+ while (true) {
+ int sampleSize = extractor.getFrameSample();
+ MediaCodec.BufferInfo bufferInfo = extractor.getBufferInfo();
+ MediaCodec.BufferInfo tempBufferInfo = new MediaCodec.BufferInfo();
+ tempBufferInfo
+ .set(bufferInfo.offset, bufferInfo.size, bufferInfo.presentationTimeUs,
+ bufferInfo.flags);
+ inputBufferInfo.add(tempBufferInfo);
+ ByteBuffer tempSampleBuffer = ByteBuffer.allocate(tempBufferInfo.size);
+ tempSampleBuffer.put(extractor.getFrameBuffer().array(), 0, bufferInfo.size);
+ inputBuffer.add(tempSampleBuffer);
+ if (sampleSize < 0) {
+ break;
+ }
+ }
+ MediaFormat format = extractor.getFormat(currentTrack);
+ int outputFormat = mMapFormat.getOrDefault(mFormat, -1);
+ assertNotEquals("Test failed for " + mInputFileName + ". Returned invalid " +
+ "output format for given " + mFormat + " format.", -1, outputFormat);
+ Muxer muxer = new Muxer();
+ int trackIndex = muxer.setUpMuxer(mContext, outputFormat, format);
+ int status = muxer.mux(trackIndex, inputBuffer, inputBufferInfo);
+ assertEquals("Cannot perform write operation for " + mInputFileName, 0, status);
+ Log.i(TAG, "Muxed " + mInputFileName + " successfully.");
+ muxer.deInitMuxer();
+ muxer.dumpStatistics(mInputFileName, mFormat, extractor.getClipDuration(), mStatsFile);
+ muxer.resetMuxer();
+ extractor.unselectExtractorTrack(currentTrack);
+ inputBufferInfo.clear();
+ inputBuffer.clear();
+
+ }
+ extractor.deinitExtractor();
+ fileInput.close();
+ }
+
+ @Test
+ public void testNativeMuxer() {
+ Native nativeMuxer = new Native();
+ File inputFile = new File(mInputFilePath + mInputFileName);
+ assertTrue("Cannot find " + mInputFileName + " in directory " + mInputFilePath,
+ inputFile.exists());
+ int tid = android.os.Process.myTid();
+ String mMuxOutputFile = (mContext.getFilesDir() + "/mux_" + tid + ".out");
+ int status = nativeMuxer.Mux(
+ mInputFilePath, mInputFileName, mMuxOutputFile, mStatsFile, mFormat);
+ assertEquals("Cannot perform write operation for " + mInputFileName, 0, status);
+ Log.i(TAG, "Muxed " + mInputFileName + " successfully.");
+ File muxedFile = new File(mMuxOutputFile);
+ // Cleanup temporary output file
+ if (muxedFile.exists()) {
+ assertTrue("Unable to delete" + mMuxOutputFile + " file.",
+ muxedFile.delete());
+ }
+ }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/Android.bp b/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/Android.bp
new file mode 100644
index 0000000..3e5e4c8
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/Android.bp
@@ -0,0 +1,33 @@
+cc_test_library {
+ name: "libmediabenchmark_jni",
+ sdk_version: "current",
+
+ defaults: [
+ "libmediabenchmark_common-defaults",
+ "libmediabenchmark_soft_sanitize_all-defaults",
+ ],
+
+ srcs: [
+ "NativeExtractor.cpp",
+ "NativeMuxer.cpp",
+ "NativeEncoder.cpp",
+ "NativeDecoder.cpp",
+ ],
+
+ shared_libs: [
+ "liblog",
+ ],
+
+ static_libs: [
+ "libmediabenchmark_common",
+ "libmediabenchmark_extractor",
+ "libmediabenchmark_muxer",
+ "libmediabenchmark_decoder",
+ "libmediabenchmark_encoder",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/CMakeLists.txt b/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/CMakeLists.txt
new file mode 100644
index 0000000..5823883
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/CMakeLists.txt
@@ -0,0 +1,44 @@
+#
+# 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.
+#
+
+cmake_minimum_required(VERSION 3.4.1)
+
+set(native_source_path "../../../../src/native")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror")
+
+add_library(
+ mediabenchmark_jni SHARED
+ NativeExtractor.cpp
+ NativeMuxer.cpp
+ NativeDecoder.cpp
+ NativeEncoder.cpp
+ ${native_source_path}/common/BenchmarkCommon.cpp
+ ${native_source_path}/common/Stats.cpp
+ ${native_source_path}/common/utils/Timers.cpp
+ ${native_source_path}/extractor/Extractor.cpp
+ ${native_source_path}/muxer/Muxer.cpp
+ ${native_source_path}/decoder/Decoder.cpp
+ ${native_source_path}/encoder/Encoder.cpp)
+
+include_directories(${native_source_path}/common)
+include_directories(${native_source_path}/extractor)
+include_directories(${native_source_path}/muxer)
+include_directories(${native_source_path}/decoder)
+include_directories(${native_source_path}/encoder)
+
+find_library(log-lib log)
+
+target_link_libraries(mediabenchmark_jni mediandk ${log-lib})
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/NativeDecoder.cpp b/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/NativeDecoder.cpp
new file mode 100644
index 0000000..043bc9e
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/NativeDecoder.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "NativeDecoder"
+
+#include <jni.h>
+#include <fstream>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <android/log.h>
+
+#include "Decoder.h"
+
+extern "C" JNIEXPORT int JNICALL Java_com_android_media_benchmark_library_Native_Decode(
+ JNIEnv *env, jobject thiz, jstring jFilePath, jstring jFileName, jstring jStatsFile,
+ jstring jCodecName, jboolean asyncMode) {
+ const char *filePath = env->GetStringUTFChars(jFilePath, nullptr);
+ const char *fileName = env->GetStringUTFChars(jFileName, nullptr);
+ string sFilePath = string(filePath) + string(fileName);
+ UNUSED(thiz);
+ FILE *inputFp = fopen(sFilePath.c_str(), "rb");
+ env->ReleaseStringUTFChars(jFileName, fileName);
+ env->ReleaseStringUTFChars(jFilePath, filePath);
+ if (!inputFp) {
+ ALOGE("Unable to open input file for reading");
+ return -1;
+ }
+
+ Decoder *decoder = new Decoder();
+ Extractor *extractor = decoder->getExtractor();
+ if (!extractor) {
+ ALOGE("Extractor creation failed");
+ return -1;
+ }
+
+ // Read file properties
+ struct stat buf;
+ stat(sFilePath.c_str(), &buf);
+ size_t fileSize = buf.st_size;
+ if (fileSize > kMaxBufferSize) {
+ ALOGE("File size greater than maximum buffer size");
+ return -1;
+ }
+ int32_t fd = fileno(inputFp);
+ int32_t trackCount = extractor->initExtractor(fd, fileSize);
+ if (trackCount <= 0) {
+ ALOGE("initExtractor failed");
+ return -1;
+ }
+ for (int curTrack = 0; curTrack < trackCount; curTrack++) {
+ int32_t status = extractor->setupTrackFormat(curTrack);
+ if (status != 0) {
+ ALOGE("Track Format invalid");
+ return -1;
+ }
+
+ uint8_t *inputBuffer = (uint8_t *) malloc(fileSize);
+ if (!inputBuffer) {
+ ALOGE("Insufficient memory");
+ return -1;
+ }
+
+ vector<AMediaCodecBufferInfo> frameInfo;
+ AMediaCodecBufferInfo info;
+ uint32_t inputBufferOffset = 0;
+
+ // Get frame data
+ while (1) {
+ status = extractor->getFrameSample(info);
+ if (status || !info.size) break;
+ // copy the meta data and buffer to be passed to decoder
+ if (inputBufferOffset + info.size > kMaxBufferSize) {
+ ALOGE("Memory allocated not sufficient");
+ free(inputBuffer);
+ return -1;
+ }
+ memcpy(inputBuffer + inputBufferOffset, extractor->getFrameBuf(), info.size);
+ frameInfo.push_back(info);
+ inputBufferOffset += info.size;
+ }
+
+ const char *codecName = env->GetStringUTFChars(jCodecName, nullptr);
+ string sCodecName = string(codecName);
+ decoder->setupDecoder();
+ status = decoder->decode(inputBuffer, frameInfo, sCodecName, asyncMode);
+ if (status != AMEDIA_OK) {
+ ALOGE("Decode returned error");
+ free(inputBuffer);
+ env->ReleaseStringUTFChars(jCodecName, codecName);
+ return -1;
+ }
+ decoder->deInitCodec();
+ const char *inputReference = env->GetStringUTFChars(jFileName, nullptr);
+ const char *statsFile = env->GetStringUTFChars(jStatsFile, nullptr);
+ string sInputReference = string(inputReference);
+ decoder->dumpStatistics(sInputReference, sCodecName, (asyncMode ? "async" : "sync"),
+ statsFile);
+ env->ReleaseStringUTFChars(jCodecName, codecName);
+ env->ReleaseStringUTFChars(jStatsFile, statsFile);
+ env->ReleaseStringUTFChars(jFileName, inputReference);
+ if (inputBuffer) {
+ free(inputBuffer);
+ inputBuffer = nullptr;
+ }
+ decoder->resetDecoder();
+ }
+ if (inputFp) {
+ fclose(inputFp);
+ inputFp = nullptr;
+ }
+ extractor->deInitExtractor();
+ delete decoder;
+ return 0;
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/NativeEncoder.cpp b/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/NativeEncoder.cpp
new file mode 100644
index 0000000..1277c8b
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/NativeEncoder.cpp
@@ -0,0 +1,218 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "NativeEncoder"
+
+#include <jni.h>
+#include <sys/stat.h>
+#include <fstream>
+#include <iostream>
+
+#include <android/log.h>
+
+#include "Decoder.h"
+#include "Encoder.h"
+
+#include <stdio.h>
+
+constexpr int32_t ENCODE_DEFAULT_FRAME_RATE = 25;
+constexpr int32_t ENCODE_DEFAULT_AUDIO_BIT_RATE = 128000 /* 128 Kbps */;
+constexpr int32_t ENCODE_DEFAULT_BIT_RATE = 8000000 /* 8 Mbps */;
+constexpr int32_t ENCODE_MIN_BIT_RATE = 600000 /* 600 Kbps */;
+
+extern "C" JNIEXPORT int JNICALL Java_com_android_media_benchmark_library_Native_Encode(
+ JNIEnv *env, jobject thiz, jstring jFilePath, jstring jFileName, jstring jOutFilePath,
+ jstring jStatsFile, jstring jCodecName) {
+ const char *filePath = env->GetStringUTFChars(jFilePath, nullptr);
+ const char *fileName = env->GetStringUTFChars(jFileName, nullptr);
+ string sFilePath = string(filePath) + string(fileName);
+ UNUSED(thiz);
+ FILE *inputFp = fopen(sFilePath.c_str(), "rb");
+ env->ReleaseStringUTFChars(jFileName, fileName);
+ env->ReleaseStringUTFChars(jFilePath, filePath);
+ if (!inputFp) {
+ ALOGE("Unable to open input file for reading");
+ return -1;
+ }
+
+ Decoder *decoder = new Decoder();
+ Extractor *extractor = decoder->getExtractor();
+ if (!extractor) {
+ ALOGE("Extractor creation failed");
+ return -1;
+ }
+
+ // Read file properties
+ struct stat buf;
+ stat(sFilePath.c_str(), &buf);
+ size_t fileSize = buf.st_size;
+ if (fileSize > kMaxBufferSize) {
+ ALOGE("File size greater than maximum buffer size");
+ return -1;
+ }
+ int32_t fd = fileno(inputFp);
+ int32_t trackCount = extractor->initExtractor(fd, fileSize);
+ if (trackCount <= 0) {
+ ALOGE("initExtractor failed");
+ return -1;
+ }
+
+ for (int curTrack = 0; curTrack < trackCount; curTrack++) {
+ int32_t status = extractor->setupTrackFormat(curTrack);
+ if (status != 0) {
+ ALOGE("Track Format invalid");
+ return -1;
+ }
+ uint8_t *inputBuffer = (uint8_t *)malloc(fileSize);
+ if (!inputBuffer) {
+ ALOGE("Insufficient memory");
+ return -1;
+ }
+ vector<AMediaCodecBufferInfo> frameInfo;
+ AMediaCodecBufferInfo info;
+ uint32_t inputBufferOffset = 0;
+
+ // Get frame data
+ while (1) {
+ status = extractor->getFrameSample(info);
+ if (status || !info.size) break;
+ // copy the meta data and buffer to be passed to decoder
+ if (inputBufferOffset + info.size > kMaxBufferSize) {
+ ALOGE("Memory allocated not sufficient");
+ free(inputBuffer);
+ return -1;
+ }
+ memcpy(inputBuffer + inputBufferOffset, extractor->getFrameBuf(), info.size);
+ frameInfo.push_back(info);
+ inputBufferOffset += info.size;
+ }
+ string decName = "";
+ const char *outputFilePath = env->GetStringUTFChars(jOutFilePath, nullptr);
+ FILE *outFp = fopen(outputFilePath, "wb");
+ if (outFp == nullptr) {
+ ALOGE("%s - File failed to open for writing!", outputFilePath);
+ free(inputBuffer);
+ return -1;
+ }
+ decoder->setupDecoder();
+ status = decoder->decode(inputBuffer, frameInfo, decName, false /*asyncMode */, outFp);
+ if (status != AMEDIA_OK) {
+ ALOGE("Decode returned error");
+ free(inputBuffer);
+ return -1;
+ }
+
+ AMediaFormat *decoderFormat = decoder->getFormat();
+ AMediaFormat *format = extractor->getFormat();
+ if (inputBuffer) {
+ free(inputBuffer);
+ inputBuffer = nullptr;
+ }
+ const char *mime = nullptr;
+ AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime);
+ if (!mime) {
+ ALOGE("Error in AMediaFormat_getString");
+ return -1;
+ }
+ ifstream eleStream;
+ eleStream.open(outputFilePath, ifstream::binary | ifstream::ate);
+ if (!eleStream.is_open()) {
+ ALOGE("%s - File failed to open for reading!", outputFilePath);
+ env->ReleaseStringUTFChars(jOutFilePath, outputFilePath);
+ return -1;
+ }
+ const char *codecName = env->GetStringUTFChars(jCodecName, NULL);
+ const char *inputReference = env->GetStringUTFChars(jFileName, nullptr);
+ string sCodecName = string(codecName);
+ string sInputReference = string(inputReference);
+
+ bool asyncMode[2] = {true, false};
+ for (int i = 0; i < 2; i++) {
+ size_t eleSize = eleStream.tellg();
+ eleStream.seekg(0, ifstream::beg);
+
+ // Get encoder params
+ encParameter encParams;
+ if (!strncmp(mime, "video/", 6)) {
+ AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &encParams.width);
+ AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &encParams.height);
+ AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_FRAME_RATE, &encParams.frameRate);
+ AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, &encParams.bitrate);
+ if (encParams.bitrate <= 0 || encParams.frameRate <= 0) {
+ encParams.frameRate = ENCODE_DEFAULT_FRAME_RATE;
+ if (!strcmp(mime, "video/3gpp") || !strcmp(mime, "video/mp4v-es")) {
+ encParams.bitrate = ENCODE_MIN_BIT_RATE /* 600 Kbps */;
+ } else {
+ encParams.bitrate = ENCODE_DEFAULT_BIT_RATE /* 8 Mbps */;
+ }
+ }
+ AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_PROFILE, &encParams.profile);
+ AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_LEVEL, &encParams.level);
+ AMediaFormat_getInt32(decoderFormat, AMEDIAFORMAT_KEY_COLOR_FORMAT,
+ &encParams.colorFormat);
+ } else {
+ AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, &encParams.sampleRate);
+ AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT,
+ &encParams.numChannels);
+ encParams.bitrate = ENCODE_DEFAULT_AUDIO_BIT_RATE;
+ }
+ Encoder *encoder = new Encoder();
+ encoder->setupEncoder();
+ status = encoder->encode(sCodecName, eleStream, eleSize, asyncMode[i], encParams,
+ (char *)mime);
+ if (status != AMEDIA_OK) {
+ ALOGE("Encoder returned error");
+ return -1;
+ }
+ ALOGV("Encoding complete with codec %s for asyncMode = %d", sCodecName.c_str(),
+ asyncMode[i]);
+ encoder->deInitCodec();
+ const char *statsFile = env->GetStringUTFChars(jStatsFile, nullptr);
+ encoder->dumpStatistics(sInputReference, extractor->getClipDuration(), sCodecName,
+ (asyncMode[i] ? "async" : "sync"), statsFile);
+ env->ReleaseStringUTFChars(jStatsFile, statsFile);
+ encoder->resetEncoder();
+ delete encoder;
+ encoder = nullptr;
+ }
+ eleStream.close();
+ if (outFp) {
+ fclose(outFp);
+ outFp = nullptr;
+ }
+ env->ReleaseStringUTFChars(jFileName, inputReference);
+ env->ReleaseStringUTFChars(jCodecName, codecName);
+ env->ReleaseStringUTFChars(jOutFilePath, outputFilePath);
+ if (format) {
+ AMediaFormat_delete(format);
+ format = nullptr;
+ }
+ if (decoderFormat) {
+ AMediaFormat_delete(decoderFormat);
+ decoderFormat = nullptr;
+ }
+ decoder->deInitCodec();
+ decoder->resetDecoder();
+ }
+ if (inputFp) {
+ fclose(inputFp);
+ inputFp = nullptr;
+ }
+ extractor->deInitExtractor();
+ delete decoder;
+ return 0;
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/NativeExtractor.cpp b/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/NativeExtractor.cpp
new file mode 100644
index 0000000..a762760
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/NativeExtractor.cpp
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "NativeExtractor"
+
+#include <jni.h>
+#include <fstream>
+#include <string>
+#include <sys/stat.h>
+
+#include "Extractor.h"
+
+extern "C" JNIEXPORT int32_t JNICALL Java_com_android_media_benchmark_library_Native_Extract(
+ JNIEnv *env, jobject thiz, jstring jInputFilePath, jstring jInputFileName,
+ jstring jStatsFile) {
+ UNUSED(thiz);
+ const char *inputFilePath = env->GetStringUTFChars(jInputFilePath, nullptr);
+ const char *inputFileName = env->GetStringUTFChars(jInputFileName, nullptr);
+ string sFilePath = string(inputFilePath) + string(inputFileName);
+ FILE *inputFp = fopen(sFilePath.c_str(), "rb");
+
+ // Read file properties
+ struct stat buf;
+ stat(sFilePath.c_str(), &buf);
+ size_t fileSize = buf.st_size;
+ int32_t fd = fileno(inputFp);
+
+ Extractor *extractObj = new Extractor();
+ int32_t trackCount = extractObj->initExtractor((long) fd, fileSize);
+ if (trackCount <= 0) {
+ ALOGE("initExtractor failed");
+ return -1;
+ }
+
+ int32_t trackID = 0;
+ const char *mime = nullptr;
+ int32_t status = extractObj->extract(trackID);
+ if (status != AMEDIA_OK) {
+ ALOGE("Extraction failed");
+ return -1;
+ }
+
+ if (inputFp) {
+ fclose(inputFp);
+ inputFp = nullptr;
+ }
+ status = extractObj->setupTrackFormat(trackID);
+ AMediaFormat *format = extractObj->getFormat();
+ if (!format) {
+ ALOGE("format is null!");
+ return -1;
+ }
+ AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime);
+ if (!mime) {
+ ALOGE("mime is null!");
+ return -1;
+ }
+ extractObj->deInitExtractor();
+ const char *statsFile = env->GetStringUTFChars(jStatsFile, nullptr);
+ extractObj->dumpStatistics(string(inputFileName), string(mime), statsFile);
+ env->ReleaseStringUTFChars(jStatsFile, statsFile);
+ env->ReleaseStringUTFChars(jInputFilePath, inputFilePath);
+ env->ReleaseStringUTFChars(jInputFileName, inputFileName);
+
+ delete extractObj;
+ return status;
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/NativeMuxer.cpp b/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/NativeMuxer.cpp
new file mode 100644
index 0000000..a5ef5b8
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/NativeMuxer.cpp
@@ -0,0 +1,184 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "NativeMuxer"
+
+#include <jni.h>
+#include <fstream>
+#include <string>
+#include <sys/stat.h>
+
+#include "Muxer.h"
+
+MUXER_OUTPUT_T getMuxerOutFormat(const char *fmt);
+
+extern "C" JNIEXPORT int32_t JNICALL Java_com_android_media_benchmark_library_Native_Mux(
+ JNIEnv *env, jobject thiz, jstring jInputFilePath, jstring jInputFileName,
+ jstring jOutputFilePath, jstring jStatsFile, jstring jFormat) {
+ UNUSED(thiz);
+ ALOGV("Mux the samples given by extractor");
+ const char *inputFilePath = env->GetStringUTFChars(jInputFilePath, nullptr);
+ const char *inputFileName = env->GetStringUTFChars(jInputFileName, nullptr);
+ string sInputFile = string(inputFilePath) + string(inputFileName);
+ FILE *inputFp = fopen(sInputFile.c_str(), "rb");
+ if (!inputFp) {
+ ALOGE("Unable to open input file for reading");
+ return -1;
+ }
+
+ const char *fmt = env->GetStringUTFChars(jFormat, nullptr);
+ MUXER_OUTPUT_T outputFormat = getMuxerOutFormat(fmt);
+ if (outputFormat == MUXER_OUTPUT_FORMAT_INVALID) {
+ ALOGE("output format is MUXER_OUTPUT_FORMAT_INVALID");
+ return MUXER_OUTPUT_FORMAT_INVALID;
+ }
+
+ Muxer *muxerObj = new Muxer();
+ Extractor *extractor = muxerObj->getExtractor();
+ if (!extractor) {
+ ALOGE("Extractor creation failed");
+ return -1;
+ }
+
+ // Read file properties
+ struct stat buf;
+ stat(sInputFile.c_str(), &buf);
+ size_t fileSize = buf.st_size;
+ int32_t fd = fileno(inputFp);
+
+ int32_t trackCount = extractor->initExtractor(fd, fileSize);
+ if (trackCount <= 0) {
+ ALOGE("initExtractor failed");
+ return -1;
+ }
+
+ for (int curTrack = 0; curTrack < trackCount; curTrack++) {
+ int32_t status = extractor->setupTrackFormat(curTrack);
+ if (status != 0) {
+ ALOGE("Track Format invalid");
+ return -1;
+ }
+
+ uint8_t *inputBuffer = (uint8_t *) malloc(fileSize);
+ if (!inputBuffer) {
+ ALOGE("Allocation Failed");
+ return -1;
+ }
+ vector<AMediaCodecBufferInfo> frameInfos;
+ AMediaCodecBufferInfo info;
+ uint32_t inputBufferOffset = 0;
+
+ // Get Frame Data
+ while (1) {
+ status = extractor->getFrameSample(info);
+ if (status || !info.size) break;
+ // copy the meta data and buffer to be passed to muxer
+ if (inputBufferOffset + info.size > fileSize) {
+ ALOGE("Memory allocated not sufficient");
+ if (inputBuffer) {
+ free(inputBuffer);
+ inputBuffer = nullptr;
+ }
+ return -1;
+ }
+ memcpy(inputBuffer + inputBufferOffset, extractor->getFrameBuf(),
+ static_cast<size_t>(info.size));
+ info.offset = inputBufferOffset;
+ frameInfos.push_back(info);
+ inputBufferOffset += info.size;
+ }
+
+ const char *outputFilePath = env->GetStringUTFChars(jOutputFilePath, nullptr);
+ FILE *outputFp = fopen(((string) outputFilePath).c_str(), "w+b");
+ env->ReleaseStringUTFChars(jOutputFilePath, outputFilePath);
+
+ if (!outputFp) {
+ ALOGE("Unable to open output file for writing");
+ if (inputBuffer) {
+ free(inputBuffer);
+ inputBuffer = nullptr;
+ }
+ return -1;
+ }
+ int32_t outFd = fileno(outputFp);
+
+ status = muxerObj->initMuxer(outFd, (MUXER_OUTPUT_T) outputFormat);
+ if (status != 0) {
+ ALOGE("initMuxer failed");
+ if (inputBuffer) {
+ free(inputBuffer);
+ inputBuffer = nullptr;
+ }
+ return -1;
+ }
+
+ status = muxerObj->mux(inputBuffer, frameInfos);
+ if (status != 0) {
+ ALOGE("Mux failed");
+ if (inputBuffer) {
+ free(inputBuffer);
+ inputBuffer = nullptr;
+ }
+ return -1;
+ }
+ muxerObj->deInitMuxer();
+ const char *statsFile = env->GetStringUTFChars(jStatsFile, nullptr);
+ string muxFormat(fmt);
+ muxerObj->dumpStatistics(string(inputFileName), muxFormat, statsFile);
+ env->ReleaseStringUTFChars(jStatsFile, statsFile);
+ env->ReleaseStringUTFChars(jInputFilePath, inputFilePath);
+ env->ReleaseStringUTFChars(jInputFileName, inputFileName);
+
+ if (inputBuffer) {
+ free(inputBuffer);
+ inputBuffer = nullptr;
+ }
+ if (outputFp) {
+ fclose(outputFp);
+ outputFp = nullptr;
+ }
+ muxerObj->resetMuxer();
+ }
+ if (inputFp) {
+ fclose(inputFp);
+ inputFp = nullptr;
+ }
+ env->ReleaseStringUTFChars(jFormat, fmt);
+ extractor->deInitExtractor();
+ delete muxerObj;
+
+ return 0;
+}
+
+MUXER_OUTPUT_T getMuxerOutFormat(const char *fmt) {
+ static const struct {
+ const char *name;
+ int value;
+ } kFormatMaps[] = {{"mp4", MUXER_OUTPUT_FORMAT_MPEG_4},
+ {"webm", MUXER_OUTPUT_FORMAT_WEBM},
+ {"3gpp", MUXER_OUTPUT_FORMAT_3GPP},
+ {"ogg", MUXER_OUTPUT_FORMAT_OGG}};
+
+ int32_t muxOutputFormat = MUXER_OUTPUT_FORMAT_INVALID;
+ for (auto kFormatMap : kFormatMaps) {
+ if (!strcmp(fmt, kFormatMap.name)) {
+ muxOutputFormat = kFormatMap.value;
+ break;
+ }
+ }
+ return (MUXER_OUTPUT_T) muxOutputFormat;
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/CodecUtils.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/CodecUtils.java
new file mode 100644
index 0000000..08035c9
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/CodecUtils.java
@@ -0,0 +1,39 @@
+package com.android.media.benchmark.library;
+
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecList;
+import android.os.Build;
+
+import java.util.ArrayList;
+
+public class CodecUtils {
+ private CodecUtils() {}
+
+ /**
+ * Queries the MediaCodecList and returns codec names of supported codecs.
+ *
+ * @param mimeType Mime type of input
+ * @param isEncoder Specifies encoder or decoder
+ * @return ArrayList of codec names
+ */
+ public static ArrayList<String> selectCodecs(String mimeType, boolean isEncoder) {
+ MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+ MediaCodecInfo[] codecInfos = codecList.getCodecInfos();
+ ArrayList<String> supportedCodecs = new ArrayList<>();
+ for (MediaCodecInfo codecInfo : codecInfos) {
+ if (isEncoder != codecInfo.isEncoder()) {
+ continue;
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && codecInfo.isAlias()) {
+ continue;
+ }
+ String[] types = codecInfo.getSupportedTypes();
+ for (String type : types) {
+ if (type.equalsIgnoreCase(mimeType)) {
+ supportedCodecs.add(codecInfo.getName());
+ }
+ }
+ }
+ return supportedCodecs;
+ }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java
new file mode 100644
index 0000000..66fee33
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java
@@ -0,0 +1,312 @@
+/*
+ * 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.
+ */
+
+package com.android.media.benchmark.library;
+
+import android.media.MediaCodec;
+import android.media.MediaCodec.BufferInfo;
+import android.media.MediaFormat;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+public class Decoder {
+ private static final String TAG = "Decoder";
+ private static final boolean DEBUG = false;
+ private static final int kQueueDequeueTimeoutUs = 1000;
+
+ private final Object mLock = new Object();
+ private MediaCodec mCodec;
+ private ArrayList<BufferInfo> mInputBufferInfo;
+ private Stats mStats;
+
+ private boolean mSawInputEOS;
+ private boolean mSawOutputEOS;
+ private boolean mSignalledError;
+
+ private int mNumOutputFrame;
+ private int mIndex;
+
+ private ArrayList<ByteBuffer> mInputBuffer;
+ private FileOutputStream mOutputStream;
+
+ public Decoder() { mStats = new Stats(); }
+
+ /**
+ * Setup of decoder
+ *
+ * @param outputStream Will dump the output in this stream if not null.
+ */
+ public void setupDecoder(FileOutputStream outputStream) {
+ mSignalledError = false;
+ mOutputStream = outputStream;
+ }
+
+ private MediaCodec createCodec(String codecName, MediaFormat format) throws IOException {
+ String mime = format.getString(MediaFormat.KEY_MIME);
+ try {
+ MediaCodec codec;
+ if (codecName.isEmpty()) {
+ Log.i(TAG, "File mime type: " + mime);
+ if (mime != null) {
+ codec = MediaCodec.createDecoderByType(mime);
+ Log.i(TAG, "Decoder created for mime type " + mime);
+ return codec;
+ } else {
+ Log.e(TAG, "Mime type is null, please specify a mime type to create decoder");
+ return null;
+ }
+ } else {
+ codec = MediaCodec.createByCodecName(codecName);
+ Log.i(TAG, "Decoder created with codec name: " + codecName + " mime: " + mime);
+ return codec;
+ }
+ } catch (IllegalArgumentException ex) {
+ ex.printStackTrace();
+ Log.e(TAG, "Failed to create decoder for " + codecName + " mime:" + mime);
+ return null;
+ }
+ }
+
+ /**
+ * Decodes the given input buffer,
+ * provided valid list of buffer info and format are passed as inputs.
+ *
+ * @param inputBuffer Decode the provided list of ByteBuffers
+ * @param inputBufferInfo List of buffer info corresponding to provided input buffers
+ * @param asyncMode Will run on async implementation if true
+ * @param format For creating the decoder if codec name is empty and configuring it
+ * @param codecName Will create the decoder with codecName
+ * @return 0 if decode was successful , -1 for fail, -2 for decoder not created
+ * @throws IOException if the codec cannot be created.
+ */
+ public int decode(@NonNull ArrayList<ByteBuffer> inputBuffer,
+ @NonNull ArrayList<BufferInfo> inputBufferInfo, final boolean asyncMode,
+ @NonNull MediaFormat format, String codecName) throws IOException {
+ mInputBuffer = new ArrayList<>(inputBuffer.size());
+ mInputBuffer.addAll(inputBuffer);
+ mInputBufferInfo = new ArrayList<>(inputBufferInfo.size());
+ mInputBufferInfo.addAll(inputBufferInfo);
+ mSawInputEOS = false;
+ mSawOutputEOS = false;
+ mNumOutputFrame = 0;
+ mIndex = 0;
+ long sTime = mStats.getCurTime();
+ mCodec = createCodec(codecName, format);
+ if (mCodec == null) {
+ return -2;
+ }
+ if (asyncMode) {
+ mCodec.setCallback(new MediaCodec.Callback() {
+ @Override
+ public void onInputBufferAvailable(
+ @NonNull MediaCodec mediaCodec, int inputBufferId) {
+ try {
+ mStats.addInputTime();
+ onInputAvailable(inputBufferId, mediaCodec);
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.e(TAG, e.toString());
+ }
+ }
+
+ @Override
+ public void onOutputBufferAvailable(@NonNull MediaCodec mediaCodec,
+ int outputBufferId, @NonNull MediaCodec.BufferInfo bufferInfo) {
+ mStats.addOutputTime();
+ onOutputAvailable(mediaCodec, outputBufferId, bufferInfo);
+ if (mSawOutputEOS) {
+ synchronized (mLock) { mLock.notify(); }
+ }
+ }
+
+ @Override
+ public void onOutputFormatChanged(
+ @NonNull MediaCodec mediaCodec, @NonNull MediaFormat format) {
+ Log.i(TAG, "Output format changed. Format: " + format.toString());
+ }
+
+ @Override
+ public void onError(
+ @NonNull MediaCodec mediaCodec, @NonNull MediaCodec.CodecException e) {
+ mSignalledError = true;
+ Log.e(TAG, "Codec Error: " + e.toString());
+ e.printStackTrace();
+ synchronized (mLock) { mLock.notify(); }
+ }
+ });
+ }
+ int isEncoder = 0;
+ if (DEBUG) {
+ Log.d(TAG, "Media Format : " + format.toString());
+ }
+ mCodec.configure(format, null, null, isEncoder);
+ mCodec.start();
+ Log.i(TAG, "Codec started ");
+ long eTime = mStats.getCurTime();
+ mStats.setInitTime(mStats.getTimeDiff(sTime, eTime));
+ mStats.setStartTime();
+ if (asyncMode) {
+ try {
+ synchronized (mLock) { mLock.wait(); }
+ if (mSignalledError) {
+ return -1;
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ } else {
+ while (!mSawOutputEOS && !mSignalledError) {
+ /* Queue input data */
+ if (!mSawInputEOS) {
+ int inputBufferId = mCodec.dequeueInputBuffer(kQueueDequeueTimeoutUs);
+ if (inputBufferId < 0 && inputBufferId != MediaCodec.INFO_TRY_AGAIN_LATER) {
+ Log.e(TAG,
+ "MediaCodec.dequeueInputBuffer "
+ + " returned invalid index : " + inputBufferId);
+ return -1;
+ }
+ mStats.addInputTime();
+ onInputAvailable(inputBufferId, mCodec);
+ }
+ /* Dequeue output data */
+ BufferInfo outputBufferInfo = new BufferInfo();
+ int outputBufferId =
+ mCodec.dequeueOutputBuffer(outputBufferInfo, kQueueDequeueTimeoutUs);
+ if (outputBufferId < 0) {
+ if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+ MediaFormat outFormat = mCodec.getOutputFormat();
+ Log.i(TAG, "Output format changed. Format: " + outFormat.toString());
+ } else if (outputBufferId == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
+ Log.i(TAG, "Ignoring deprecated flag: INFO_OUTPUT_BUFFERS_CHANGED");
+ } else if (outputBufferId != MediaCodec.INFO_TRY_AGAIN_LATER) {
+ Log.e(TAG,
+ "MediaCodec.dequeueOutputBuffer"
+ + " returned invalid index " + outputBufferId);
+ return -1;
+ }
+ } else {
+ mStats.addOutputTime();
+ if (DEBUG) {
+ Log.d(TAG, "Dequeue O/P buffer with BufferID " + outputBufferId);
+ }
+ onOutputAvailable(mCodec, outputBufferId, outputBufferInfo);
+ }
+ }
+ }
+ mInputBuffer.clear();
+ mInputBufferInfo.clear();
+ return 0;
+ }
+
+ /**
+ * Stops the codec and releases codec resources.
+ */
+ public void deInitCodec() {
+ long sTime = mStats.getCurTime();
+ if (mCodec != null) {
+ mCodec.stop();
+ mCodec.release();
+ mCodec = null;
+ }
+ long eTime = mStats.getCurTime();
+ mStats.setDeInitTime(mStats.getTimeDiff(sTime, eTime));
+ }
+
+ /**
+ * Prints out the statistics in the information log
+ *
+ * @param inputReference The operation being performed, in this case decode
+ * @param componentName Name of the component/codec
+ * @param mode The operating mode: Sync/Async
+ * @param durationUs Duration of the clip in microseconds
+ * @param statsFile The output file where the stats data is written
+ */
+ public void dumpStatistics(String inputReference, String componentName, String mode,
+ long durationUs, String statsFile) throws IOException {
+ String operation = "decode";
+ mStats.dumpStatistics(
+ inputReference, operation, componentName, mode, durationUs, statsFile);
+ }
+
+ /**
+ * Resets the stats
+ */
+ public void resetDecoder() { mStats.reset(); }
+
+ /**
+ * Returns the format of the output buffers
+ */
+ public MediaFormat getFormat() {
+ return mCodec.getOutputFormat();
+ }
+
+ private void onInputAvailable(int inputBufferId, MediaCodec mediaCodec) {
+ if ((inputBufferId >= 0) && !mSawInputEOS) {
+ ByteBuffer inputCodecBuffer = mediaCodec.getInputBuffer(inputBufferId);
+ BufferInfo bufInfo = mInputBufferInfo.get(mIndex);
+ inputCodecBuffer.put(mInputBuffer.get(mIndex).array());
+ mIndex++;
+ mSawInputEOS = (bufInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
+ if (mSawInputEOS) {
+ Log.i(TAG, "Saw input EOS");
+ }
+ mStats.addFrameSize(bufInfo.size);
+ mediaCodec.queueInputBuffer(inputBufferId, bufInfo.offset, bufInfo.size,
+ bufInfo.presentationTimeUs, bufInfo.flags);
+ if (DEBUG) {
+ Log.d(TAG,
+ "Codec Input: "
+ + "flag = " + bufInfo.flags + " timestamp = "
+ + bufInfo.presentationTimeUs + " size = " + bufInfo.size);
+ }
+ }
+ }
+
+ private void onOutputAvailable(
+ MediaCodec mediaCodec, int outputBufferId, BufferInfo outputBufferInfo) {
+ if (mSawOutputEOS || outputBufferId < 0) {
+ return;
+ }
+ mNumOutputFrame++;
+ if (DEBUG) {
+ Log.d(TAG,
+ "In OutputBufferAvailable ,"
+ + " output frame number = " + mNumOutputFrame);
+ }
+ if (mOutputStream != null) {
+ try {
+ ByteBuffer outputBuffer = mediaCodec.getOutputBuffer(outputBufferId);
+ byte[] bytesOutput = new byte[outputBuffer.remaining()];
+ outputBuffer.get(bytesOutput);
+ mOutputStream.write(bytesOutput);
+ } catch (IOException e) {
+ e.printStackTrace();
+ Log.d(TAG, "Error Dumping File: Exception " + e.toString());
+ }
+ }
+ mediaCodec.releaseOutputBuffer(outputBufferId, false);
+ mSawOutputEOS = (outputBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
+ if (mSawOutputEOS) {
+ Log.i(TAG, "Saw output EOS");
+ }
+ }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Encoder.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Encoder.java
new file mode 100644
index 0000000..45e5574
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Encoder.java
@@ -0,0 +1,364 @@
+/*
+ * 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.
+ */
+
+package com.android.media.benchmark.library;
+
+import android.media.MediaCodec;
+import android.media.MediaCodec.CodecException;
+import android.media.MediaFormat;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public class Encoder {
+ // Change in AUDIO_ENCODE_DEFAULT_MAX_INPUT_SIZE should also be taken to
+ // kDefaultAudioEncodeFrameSize present in BenchmarkCommon.h
+ private static final int AUDIO_ENCODE_DEFAULT_MAX_INPUT_SIZE = 4096;
+ private static final String TAG = "Encoder";
+ private static final boolean DEBUG = false;
+ private static final int kQueueDequeueTimeoutUs = 1000;
+
+ private final Object mLock = new Object();
+ private MediaCodec mCodec;
+ private String mMime;
+ private Stats mStats;
+
+ private int mOffset;
+ private int mFrameSize;
+ private int mNumInputFrame;
+ private int mNumFrames;
+ private int mFrameRate;
+ private int mSampleRate;
+ private long mInputBufferSize;
+
+ private boolean mSawInputEOS;
+ private boolean mSawOutputEOS;
+ private boolean mSignalledError;
+
+ private FileInputStream mInputStream;
+ private FileOutputStream mOutputStream;
+
+ public Encoder() {
+ mStats = new Stats();
+ mNumInputFrame = 0;
+ mSawInputEOS = false;
+ mSawOutputEOS = false;
+ mSignalledError = false;
+ }
+
+ /**
+ * Setup of encoder
+ *
+ * @param encoderOutputStream Will dump the encoder output in this stream if not null.
+ * @param fileInputStream Will read the decoded output from this stream
+ */
+ public void setupEncoder(FileOutputStream encoderOutputStream,
+ FileInputStream fileInputStream) {
+ this.mInputStream = fileInputStream;
+ this.mOutputStream = encoderOutputStream;
+ }
+
+ private MediaCodec createCodec(String codecName, String mime) throws IOException {
+ try {
+ MediaCodec codec;
+ if (codecName.isEmpty()) {
+ Log.i(TAG, "Mime type: " + mime);
+ if (mime != null) {
+ codec = MediaCodec.createEncoderByType(mime);
+ Log.i(TAG, "Encoder created for mime type " + mime);
+ return codec;
+ } else {
+ Log.e(TAG, "Mime type is null, please specify a mime type to create encoder");
+ return null;
+ }
+ } else {
+ codec = MediaCodec.createByCodecName(codecName);
+ Log.i(TAG, "Encoder created with codec name: " + codecName + " and mime: " + mime);
+ return codec;
+ }
+ } catch (IllegalArgumentException ex) {
+ ex.printStackTrace();
+ Log.e(TAG, "Failed to create encoder for " + codecName + " mime: " + mime);
+ return null;
+ }
+ }
+
+ /**
+ * Encodes the given raw input file and measures the performance of encode operation,
+ * provided a valid list of parameters are passed as inputs.
+ *
+ * @param codecName Will create the encoder with codecName
+ * @param mime For creating encode format
+ * @param encodeFormat Format of the output data
+ * @param frameSize Size of the frame
+ * @param asyncMode Will run on async implementation if true
+ * @return 0 if encode was successful , -1 for fail, -2 for encoder not created
+ * @throws IOException If the codec cannot be created.
+ */
+ public int encode(String codecName, MediaFormat encodeFormat, String mime, int frameRate,
+ int sampleRate, int frameSize, boolean asyncMode) throws IOException {
+ mInputBufferSize = mInputStream.getChannel().size();
+ mMime = mime;
+ mOffset = 0;
+ mFrameRate = frameRate;
+ mSampleRate = sampleRate;
+ long sTime = mStats.getCurTime();
+ mCodec = createCodec(codecName, mime);
+ if (mCodec == null) {
+ return -2;
+ }
+ /*Configure Codec*/
+ try {
+ mCodec.configure(encodeFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
+ } catch (IllegalArgumentException | IllegalStateException | MediaCodec.CryptoException e) {
+ Log.e(TAG, "Failed to configure " + mCodec.getName() + " encoder.");
+ e.printStackTrace();
+ return -2;
+ }
+ if (mMime.startsWith("video/")) {
+ mFrameSize = frameSize;
+ } else {
+ int maxInputSize = AUDIO_ENCODE_DEFAULT_MAX_INPUT_SIZE;
+ MediaFormat format = mCodec.getInputFormat();
+ if (format.containsKey(MediaFormat.KEY_MAX_INPUT_SIZE)) {
+ maxInputSize = format.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);
+ }
+ mFrameSize = frameSize;
+ if (mFrameSize > maxInputSize && maxInputSize > 0) {
+ mFrameSize = maxInputSize;
+ }
+ }
+ mNumFrames = (int) ((mInputBufferSize + mFrameSize - 1) / mFrameSize);
+ if (asyncMode) {
+ mCodec.setCallback(new MediaCodec.Callback() {
+ @Override
+ public void onInputBufferAvailable(@NonNull MediaCodec mediaCodec,
+ int inputBufferId) {
+ try {
+ mStats.addInputTime();
+ onInputAvailable(mediaCodec, inputBufferId);
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.e(TAG, e.toString());
+ }
+ }
+
+ @Override
+ public void onOutputBufferAvailable(@NonNull MediaCodec mediaCodec,
+ int outputBufferId,
+ @NonNull MediaCodec.BufferInfo bufferInfo) {
+ mStats.addOutputTime();
+ onOutputAvailable(mediaCodec, outputBufferId, bufferInfo);
+ if (mSawOutputEOS) {
+ Log.i(TAG, "Saw output EOS");
+ synchronized (mLock) { mLock.notify(); }
+ }
+ }
+
+ @Override
+ public void onError(@NonNull MediaCodec mediaCodec, @NonNull CodecException e) {
+ mediaCodec.stop();
+ mediaCodec.release();
+ Log.e(TAG, "CodecError: " + e.toString());
+ e.printStackTrace();
+ }
+
+ @Override
+ public void onOutputFormatChanged(@NonNull MediaCodec mediaCodec,
+ @NonNull MediaFormat format) {
+ Log.i(TAG, "Output format changed. Format: " + format.toString());
+ }
+ });
+ }
+ mCodec.start();
+ long eTime = mStats.getCurTime();
+ mStats.setInitTime(mStats.getTimeDiff(sTime, eTime));
+ mStats.setStartTime();
+ if (asyncMode) {
+ try {
+ synchronized (mLock) { mLock.wait(); }
+ if (mSignalledError) {
+ return -1;
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ } else {
+ while (!mSawOutputEOS && !mSignalledError) {
+ /* Queue input data */
+ if (!mSawInputEOS) {
+ int inputBufferId = mCodec.dequeueInputBuffer(kQueueDequeueTimeoutUs);
+ if (inputBufferId < 0 && inputBufferId != MediaCodec.INFO_TRY_AGAIN_LATER) {
+ Log.e(TAG, "MediaCodec.dequeueInputBuffer " + "returned invalid index : " +
+ inputBufferId);
+ return -1;
+ }
+ mStats.addInputTime();
+ onInputAvailable(mCodec, inputBufferId);
+ }
+ /* Dequeue output data */
+ MediaCodec.BufferInfo outputBufferInfo = new MediaCodec.BufferInfo();
+ int outputBufferId =
+ mCodec.dequeueOutputBuffer(outputBufferInfo, kQueueDequeueTimeoutUs);
+ if (outputBufferId < 0) {
+ if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+ MediaFormat outFormat = mCodec.getOutputFormat();
+ Log.i(TAG, "Output format changed. Format: " + outFormat.toString());
+ } else if (outputBufferId != MediaCodec.INFO_TRY_AGAIN_LATER) {
+ Log.e(TAG, "MediaCodec.dequeueOutputBuffer" + " returned invalid index " +
+ outputBufferId);
+ return -1;
+ }
+ } else {
+ mStats.addOutputTime();
+ if (DEBUG) {
+ Log.d(TAG, "Dequeue O/P buffer with BufferID " + outputBufferId);
+ }
+ onOutputAvailable(mCodec, outputBufferId, outputBufferInfo);
+ }
+ }
+ }
+ return 0;
+ }
+
+ private void onOutputAvailable(MediaCodec mediaCodec, int outputBufferId,
+ MediaCodec.BufferInfo outputBufferInfo) {
+ if (mSawOutputEOS || outputBufferId < 0) {
+ if (mSawOutputEOS) {
+ Log.i(TAG, "Saw output EOS");
+ }
+ return;
+ }
+ ByteBuffer outputBuffer = mediaCodec.getOutputBuffer(outputBufferId);
+ if (mOutputStream != null) {
+ try {
+
+ byte[] bytesOutput = new byte[outputBuffer.remaining()];
+ outputBuffer.get(bytesOutput);
+ mOutputStream.write(bytesOutput);
+ } catch (IOException e) {
+ e.printStackTrace();
+ Log.d(TAG, "Error Dumping File: Exception " + e.toString());
+ return;
+ }
+ }
+ mStats.addFrameSize(outputBuffer.remaining());
+ mediaCodec.releaseOutputBuffer(outputBufferId, false);
+ mSawOutputEOS = (outputBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
+ }
+
+ private void onInputAvailable(MediaCodec mediaCodec, int inputBufferId) throws IOException {
+ if (mSawInputEOS || inputBufferId < 0) {
+ if (mSawInputEOS) {
+ Log.i(TAG, "Saw input EOS");
+ }
+ return;
+ }
+ if (mInputBufferSize < mOffset) {
+ Log.e(TAG, "Out of bound access of input buffer");
+ mSignalledError = true;
+ return;
+ }
+ ByteBuffer inputBuffer = mCodec.getInputBuffer(inputBufferId);
+ if (inputBuffer == null) {
+ mSignalledError = true;
+ return;
+ }
+ int bufSize = inputBuffer.capacity();
+ int bytesToRead = mFrameSize;
+ if (mInputBufferSize - mOffset < mFrameSize) {
+ bytesToRead = (int) (mInputBufferSize - mOffset);
+ }
+ //b/148655275 - Update Frame size, as Format value may not be valid
+ if (bufSize < bytesToRead) {
+ if(mNumInputFrame == 0) {
+ mFrameSize = bufSize;
+ bytesToRead = bufSize;
+ mNumFrames = (int) ((mInputBufferSize + mFrameSize - 1) / mFrameSize);
+ } else {
+ mSignalledError = true;
+ return;
+ }
+ }
+
+ byte[] inputArray = new byte[bytesToRead];
+ mInputStream.read(inputArray, 0, bytesToRead);
+ inputBuffer.put(inputArray);
+ int flag = 0;
+ if (mNumInputFrame >= mNumFrames - 1 || bytesToRead == 0) {
+ Log.i(TAG, "Sending EOS on input last frame");
+ mSawInputEOS = true;
+ flag = MediaCodec.BUFFER_FLAG_END_OF_STREAM;
+ }
+ int presentationTimeUs;
+ if (mMime.startsWith("video/")) {
+ presentationTimeUs = mNumInputFrame * (1000000 / mFrameRate);
+ } else {
+ presentationTimeUs = mNumInputFrame * mFrameSize * 1000000 / mSampleRate;
+ }
+ mediaCodec.queueInputBuffer(inputBufferId, 0, bytesToRead, presentationTimeUs, flag);
+ mNumInputFrame++;
+ mOffset += bytesToRead;
+ }
+
+ /**
+ * Stops the codec and releases codec resources.
+ */
+ public void deInitEncoder() {
+ long sTime = mStats.getCurTime();
+ if (mCodec != null) {
+ mCodec.stop();
+ mCodec.release();
+ mCodec = null;
+ }
+ long eTime = mStats.getCurTime();
+ mStats.setDeInitTime(mStats.getTimeDiff(sTime, eTime));
+ }
+
+ /**
+ * Prints out the statistics in the information log
+ *
+ * @param inputReference The operation being performed, in this case decode
+ * @param componentName Name of the component/codec
+ * @param mode The operating mode: Sync/Async
+ * @param durationUs Duration of the clip in microseconds
+ * @param statsFile The output file where the stats data is written
+ */
+ public void dumpStatistics(String inputReference, String componentName, String mode,
+ long durationUs, String statsFile) throws IOException {
+ String operation = "encode";
+ mStats.dumpStatistics(
+ inputReference, operation, componentName, mode, durationUs, statsFile);
+ }
+
+ /**
+ * Resets the stats
+ */
+ public void resetEncoder() {
+ mOffset = 0;
+ mInputBufferSize = 0;
+ mNumInputFrame = 0;
+ mSawInputEOS = false;
+ mSawOutputEOS = false;
+ mSignalledError = false;
+ mStats.reset();
+ }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Extractor.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Extractor.java
new file mode 100644
index 0000000..f3024e7
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Extractor.java
@@ -0,0 +1,178 @@
+/*
+ * 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.
+ */
+
+package com.android.media.benchmark.library;
+
+import android.media.MediaCodec;
+import android.media.MediaExtractor;
+import android.media.MediaFormat;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public class Extractor {
+ private static final String TAG = "Extractor";
+ private static final int kMaxBufSize = 1024 * 1024 * 16;
+ private MediaExtractor mExtractor;
+ private ByteBuffer mFrameBuffer;
+ private MediaCodec.BufferInfo mBufferInfo;
+ private Stats mStats;
+ private long mDurationUs;
+
+ public Extractor() {
+ mFrameBuffer = ByteBuffer.allocate(kMaxBufSize);
+ mBufferInfo = new MediaCodec.BufferInfo();
+ mStats = new Stats();
+ }
+
+ /**
+ * Creates a Media Extractor and sets data source(FileDescriptor)to use
+ *
+ * @param fileDescriptor FileDescriptor for the file which is to be extracted
+ * @return TrackCount of the sample
+ * @throws IOException If FileDescriptor is null
+ */
+ public int setUpExtractor(FileDescriptor fileDescriptor) throws IOException {
+ long sTime = mStats.getCurTime();
+ mExtractor = new MediaExtractor();
+ mExtractor.setDataSource(fileDescriptor);
+ long eTime = mStats.getCurTime();
+ long timeTaken = mStats.getTimeDiff(sTime, eTime);
+ mStats.setInitTime(timeTaken);
+ return mExtractor.getTrackCount();
+ }
+
+ /**
+ * Returns the track format of the specified index
+ *
+ * @param trackID Index of the track
+ * @return Format of the track
+ */
+ public MediaFormat getFormat(int trackID) { return mExtractor.getTrackFormat(trackID); }
+
+ /**
+ * Returns the extracted buffer for the input clip
+ */
+ public ByteBuffer getFrameBuffer() { return this.mFrameBuffer; }
+
+ /**
+ * Returns the information of buffer related to sample
+ */
+ public MediaCodec.BufferInfo getBufferInfo() { return this.mBufferInfo; }
+
+ /**
+ * Returns the duration of the sample
+ */
+ public long getClipDuration() { return this.mDurationUs; }
+
+ /**
+ * Retrieve the current sample and store it in the byte buffer
+ * Also, sets the information related to extracted sample and store it in buffer info
+ *
+ * @return Sample size of the extracted sample
+ */
+ public int getFrameSample() {
+ int sampleSize = mExtractor.readSampleData(mFrameBuffer, 0);
+ if (sampleSize < 0) {
+ mBufferInfo.flags = MediaCodec.BUFFER_FLAG_END_OF_STREAM;
+ mBufferInfo.size = 0;
+ } else {
+ mBufferInfo.size = sampleSize;
+ mBufferInfo.offset = 0;
+ mBufferInfo.flags = mExtractor.getSampleFlags();
+ mBufferInfo.presentationTimeUs = mExtractor.getSampleTime();
+ mExtractor.advance();
+ }
+ return sampleSize;
+ }
+
+ /**
+ * Setup the track format and get the duration of the sample
+ * Track is selected here for extraction
+ *
+ * @param trackId Track index to be selected
+ * @return 0 for valid track, otherwise -1
+ */
+ public int selectExtractorTrack(int trackId) {
+ MediaFormat trackFormat = mExtractor.getTrackFormat(trackId);
+ mDurationUs = trackFormat.getLong(MediaFormat.KEY_DURATION);
+ if (mDurationUs < 0) {
+ Log.e(TAG, "Invalid Clip");
+ return -1;
+ }
+ mExtractor.selectTrack(trackId);
+ return 0;
+ }
+
+ /**
+ * Unselect the track
+ *
+ * @param trackId Track Index to be unselected
+ */
+ public void unselectExtractorTrack(int trackId) { mExtractor.unselectTrack(trackId); }
+
+ /**
+ * Free up the resources
+ */
+ public void deinitExtractor() {
+ long sTime = mStats.getCurTime();
+ mExtractor.release();
+ long eTime = mStats.getCurTime();
+ long timeTaken = mStats.getTimeDiff(sTime, eTime);
+ mStats.setDeInitTime(timeTaken);
+ }
+
+ /**
+ * Performs extract operation
+ *
+ * @param currentTrack Track index to be extracted
+ * @return Status as 0 if extraction is successful, -1 otherwise
+ */
+ public int extractSample(int currentTrack) {
+ int status;
+ status = selectExtractorTrack(currentTrack);
+ if (status == -1) {
+ Log.e(TAG, "Failed to select track");
+ return -1;
+ }
+ mStats.setStartTime();
+ while (true) {
+ int readSampleSize = getFrameSample();
+ if (readSampleSize <= 0) {
+ break;
+ }
+ mStats.addOutputTime();
+ mStats.addFrameSize(readSampleSize);
+ }
+ unselectExtractorTrack(currentTrack);
+ return 0;
+ }
+
+ /**
+ * Write the benchmark logs for the given input file
+ *
+ * @param inputReference Name of the input file
+ * @param mimeType Mime type of the muxed file
+ * @param statsFile The output file where the stats data is written
+ */
+ public void dumpStatistics(String inputReference, String mimeType, String statsFile)
+ throws IOException {
+ String operation = "extract";
+ mStats.dumpStatistics(inputReference, operation, mimeType, "", mDurationUs, statsFile);
+ }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Muxer.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Muxer.java
new file mode 100644
index 0000000..340b539
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Muxer.java
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+package com.android.media.benchmark.library;
+
+import android.content.Context;
+import android.media.MediaCodec;
+import android.media.MediaFormat;
+import android.media.MediaMuxer;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+public class Muxer {
+ private Stats mStats;
+ private MediaMuxer mMuxer;
+
+ /**
+ * Creates a Media Muxer for the specified path
+ *
+ * @param context App context to specify the output file path
+ * @param outputFormat Format of the output media file
+ * @param trackFormat Format of the current track
+ * @return Returns the track index of the newly added track, -1 otherwise
+ */
+ public int setUpMuxer(Context context, int outputFormat, MediaFormat trackFormat) {
+ try {
+ mStats = new Stats();
+ long sTime = mStats.getCurTime();
+ mMuxer = new MediaMuxer(context.getFilesDir().getPath() + "/mux.out.", outputFormat);
+ int trackIndex = mMuxer.addTrack(trackFormat);
+ mMuxer.start();
+ long eTime = mStats.getCurTime();
+ long timeTaken = mStats.getTimeDiff(sTime, eTime);
+ mStats.setInitTime(timeTaken);
+ return trackIndex;
+ } catch (IllegalArgumentException | IOException e) {
+ e.printStackTrace();
+ return -1;
+ }
+ }
+
+ /**
+ * Performs the Mux operation
+ *
+ * @param trackIndex Track index of the sample
+ * @param inputExtractedBuffer Buffer containing encoded samples
+ * @param inputBufferInfo Buffer information related to these samples
+ * @return Returns Status as 0 if write operation is successful, -1 otherwise
+ */
+ public int mux(int trackIndex, ArrayList<ByteBuffer> inputExtractedBuffer,
+ ArrayList<MediaCodec.BufferInfo> inputBufferInfo) {
+ mStats.setStartTime();
+ for (int sampleCount = 0; sampleCount < inputExtractedBuffer.size(); sampleCount++) {
+ try {
+ mMuxer.writeSampleData(trackIndex, inputExtractedBuffer.get(sampleCount),
+ inputBufferInfo.get(sampleCount));
+ mStats.addOutputTime();
+ mStats.addFrameSize(inputBufferInfo.get(sampleCount).size);
+ } catch (IllegalArgumentException | IllegalStateException e) {
+ e.printStackTrace();
+ return -1;
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Stops the muxer and free up the resources
+ */
+ public void deInitMuxer() {
+ long sTime = mStats.getCurTime();
+ mMuxer.stop();
+ mMuxer.release();
+ long eTime = mStats.getCurTime();
+ long timeTaken = mStats.getTimeDiff(sTime, eTime);
+ mStats.setDeInitTime(timeTaken);
+ }
+
+ /**
+ * Resets the stats
+ */
+ public void resetMuxer() {
+ mStats.reset();
+ }
+
+ /**
+ * Write the benchmark logs for the given input file
+ *
+ * @param inputReference Name of the input file
+ * @param muxFormat Format of the muxed output
+ * @param clipDuration Duration of the given inputReference file
+ * @param statsFile The output file where the stats data is written
+ */
+ public void dumpStatistics(String inputReference, String muxFormat, long clipDuration,
+ String statsFile) throws IOException {
+ String operation = "mux";
+ mStats.dumpStatistics(inputReference, operation, muxFormat, "", clipDuration, statsFile);
+ }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Native.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Native.java
new file mode 100644
index 0000000..38b608a
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Native.java
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+package com.android.media.benchmark.library;
+
+public class Native {
+ static { System.loadLibrary("mediabenchmark_jni"); }
+
+ public native int Extract(String inputFilePath, String inputFileName, String statsFile);
+
+ public native int Mux(String inputFilePath, String inputFileName, String outputFilePath,
+ String statsFile, String format);
+
+ public native int Decode(String inputFilePath, String inputFileName, String statsFile,
+ String codecName, boolean asyncMode);
+
+ public native int Encode(String inputFilePath, String inputFileName, String outputFilePath,
+ String statsFile, String codecName);
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Stats.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Stats.java
new file mode 100644
index 0000000..7245a3a
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Stats.java
@@ -0,0 +1,178 @@
+/*
+ * 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.
+ */
+
+package com.android.media.benchmark.library;
+
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * Measures Performance.
+ */
+public class Stats {
+ private static final String TAG = "Stats";
+ private long mInitTimeNs;
+ private long mDeInitTimeNs;
+ private long mStartTimeNs;
+ private ArrayList<Integer> mFrameSizes;
+ private ArrayList<Long> mInputTimer;
+ private ArrayList<Long> mOutputTimer;
+
+ public Stats() {
+ mFrameSizes = new ArrayList<>();
+ mInputTimer = new ArrayList<>();
+ mOutputTimer = new ArrayList<>();
+ mInitTimeNs = 0;
+ mDeInitTimeNs = 0;
+ }
+
+ public long getCurTime() { return System.nanoTime(); }
+
+ public void setInitTime(long initTime) { mInitTimeNs = initTime; }
+
+ public void setDeInitTime(long deInitTime) { mDeInitTimeNs = deInitTime; }
+
+ public void setStartTime() { mStartTimeNs = System.nanoTime(); }
+
+ public void addFrameSize(int size) { mFrameSizes.add(size); }
+
+ public void addInputTime() { mInputTimer.add(System.nanoTime()); }
+
+ public void addOutputTime() { mOutputTimer.add(System.nanoTime()); }
+
+ public void reset() {
+ if (mFrameSizes.size() != 0) {
+ mFrameSizes.clear();
+ }
+
+ if (mInputTimer.size() != 0) {
+ mInputTimer.clear();
+ }
+
+ if (mOutputTimer.size() != 0) {
+ mOutputTimer.clear();
+ }
+ }
+
+ public long getInitTime() { return mInitTimeNs; }
+
+ public long getDeInitTime() { return mDeInitTimeNs; }
+
+ public long getTimeDiff(long sTime, long eTime) { return (eTime - sTime); }
+
+ private long getTotalTime() {
+ if (mOutputTimer.size() == 0) {
+ return -1;
+ }
+ long lastTime = mOutputTimer.get(mOutputTimer.size() - 1);
+ return lastTime - mStartTimeNs;
+ }
+
+ private long getTotalSize() {
+ long totalSize = 0;
+ for (long size : mFrameSizes) {
+ totalSize += size;
+ }
+ return totalSize;
+ }
+
+ /**
+ * Writes the stats header to a file
+ * <p>
+ * \param statsFile file where the stats data is to be written
+ **/
+ public boolean writeStatsHeader(String statsFile) throws IOException {
+ File outputFile = new File(statsFile);
+ FileOutputStream out = new FileOutputStream(outputFile, true);
+ if (!outputFile.exists())
+ return false;
+ String statsHeader =
+ "currentTime, fileName, operation, componentName, NDK/SDK, sync/async, setupTime, "
+ + "destroyTime, minimumTime, maximumTime, "
+ + "averageTime, timeToProcess1SecContent, totalBytesProcessedPerSec, "
+ + "timeToFirstFrame, totalSizeInBytes, totalTime\n";
+ out.write(statsHeader.getBytes());
+ out.close();
+ return true;
+ }
+
+ /**
+ * Dumps the stats of the operation for a given input media.
+ * <p>
+ * \param inputReference input media
+ * \param operation describes the operation performed on the input media
+ * (i.e. extract/mux/decode/encode)
+ * \param componentName name of the codec/muxFormat/mime
+ * \param mode the operating mode: sync/async.
+ * \param durationUs is a duration of the input media in microseconds.
+ * \param statsFile the file where the stats data is to be written.
+ */
+ public void dumpStatistics(String inputReference, String operation, String componentName,
+ String mode, long durationUs, String statsFile) throws IOException {
+ if (mOutputTimer.size() == 0) {
+ Log.e(TAG, "No output produced");
+ return;
+ }
+ long totalTimeTakenNs = getTotalTime();
+ long timeTakenPerSec = (totalTimeTakenNs * 1000000) / durationUs;
+ long timeToFirstFrameNs = mOutputTimer.get(0) - mStartTimeNs;
+ long size = getTotalSize();
+ // get min and max output intervals.
+ long intervalNs;
+ long minTimeTakenNs = Long.MAX_VALUE;
+ long maxTimeTakenNs = 0;
+ long prevIntervalNs = mStartTimeNs;
+ for (int idx = 0; idx < mOutputTimer.size() - 1; idx++) {
+ intervalNs = mOutputTimer.get(idx) - prevIntervalNs;
+ prevIntervalNs = mOutputTimer.get(idx);
+ if (minTimeTakenNs > intervalNs) {
+ minTimeTakenNs = intervalNs;
+ } else if (maxTimeTakenNs < intervalNs) {
+ maxTimeTakenNs = intervalNs;
+ }
+ }
+
+ // Write the stats row data to file
+ String rowData = "";
+ rowData += System.nanoTime() + ", ";
+ rowData += inputReference + ", ";
+ rowData += operation + ", ";
+ rowData += componentName + ", ";
+ rowData += "SDK, ";
+ rowData += mode + ", ";
+ rowData += mInitTimeNs + ", ";
+ rowData += mDeInitTimeNs + ", ";
+ rowData += minTimeTakenNs + ", ";
+ rowData += maxTimeTakenNs + ", ";
+ rowData += totalTimeTakenNs / mOutputTimer.size() + ", ";
+ rowData += timeTakenPerSec + ", ";
+ rowData += (size * 1000000000) / totalTimeTakenNs + ", ";
+ rowData += timeToFirstFrameNs + ", ";
+ rowData += size + ", ";
+ rowData += totalTimeTakenNs + "\n";
+
+ File outputFile = new File(statsFile);
+ FileOutputStream out = new FileOutputStream(outputFile, true);
+ assert outputFile.exists() : "Failed to open the stats file for writing!";
+ out.write(rowData.getBytes());
+ out.close();
+ }
+}
diff --git a/media/tests/benchmark/README.md b/media/tests/benchmark/README.md
new file mode 100644
index 0000000..05fbe6f
--- /dev/null
+++ b/media/tests/benchmark/README.md
@@ -0,0 +1,156 @@
+# Benchmark tests
+
+Benchmark app analyses the time taken by MediaCodec, MediaExtractor and MediaMuxer for given set of inputs. It is used to benchmark these modules on android devices.
+Benchmark results are emitted to logcat.
+
+This page describes steps to run the NDK and SDK layer test.
+
+Run the following steps to build the test suite:
+```
+mmm frameworks/av/media/tests/benchmark/
+```
+
+# NDK
+
+To run the test suite for measuring performance of the native layer, follow the following steps:
+
+The binaries will be created in the following path : $OUT/data/nativetest64/
+
+adb push $OUT/data/nativetest64/* /data/local/tmp/
+
+Eg. adb push $OUT/data/nativetest64/extractorTest/extractorTest /data/local/tmp/
+
+To run the binary, follow the commands mentioned below under each module.
+
+The resource file for the tests is taken from [here](https://drive.google.com/open?id=1ghMr17BBJ7n0pqbm7oREiTN_MNemJUqy)
+
+Download the MediaBenchmark.zip file, unzip and push it to /data/local/tmp/ on the device.
+
+```
+unzip MediaBenchmark.zip
+adb push MediaBenchmark /data/local/tmp
+```
+
+## Extractor
+
+The test extracts elementary stream and benchmarks the extractors available in NDK.
+
+The resource files are assumed to be at /data/local/tmp/MediaBenchmark/res/. You can use a different location, but you have to modify the rest of the instructions to replace /data/local/tmp/MediaBenchmark/res/ with wherever you chose to put the files.
+
+The path to these files on the device is required to be given for the test.
+
+```
+adb shell /data/local/tmp/extractorTest -P /data/local/tmp/MediaBenchmark/res/
+```
+
+## Decoder
+
+The test decodes input stream and benchmarks the decoders available in NDK.
+
+Setup steps are same as extractor.
+
+```
+adb shell /data/local/tmp/decoderTest -P /data/local/tmp/MediaBenchmark/res/
+```
+
+## Muxer
+
+The test muxes elementary stream and benchmarks the muxers available in NDK.
+
+Setup steps are same as extractor.
+
+```
+adb shell /data/local/tmp/muxerTest -P /data/local/tmp/MediaBenchmark/res/
+```
+
+## Encoder
+
+The test encodes input stream and benchmarks the encoders available in NDK.
+
+Setup steps are same as extractor.
+
+```
+adb shell /data/local/tmp/encoderTest -P /data/local/tmp/MediaBenchmark/res/
+```
+
+# SDK
+
+To run the test suite for measuring performance of the SDK APIs, follow the following steps:
+
+The apk will be created at the following path:
+$OUT/testcases/MediaBenchmarkTest/arm64/
+
+To get the resorce files for the test follow instructions given in [NDK](#NDK)
+
+For installing the apk, run the command:
+```
+adb install -f -r $OUT/testcases/MediaBenchmarkTest/arm64/MediaBenchmarkTest.apk
+```
+
+For running all the tests, run the command:
+```
+adb shell am instrument -w -r -e package com.android.media.benchmark.tests com.android.media.benchmark/androidx.test.runner.AndroidJUnitRunner
+```
+
+## Extractor
+
+The test extracts elementary stream and benchmarks the extractors available in SDK.
+```
+adb shell am instrument -w -r -e class 'com.android.media.benchmark.tests.ExtractorTest' com.android.media.benchmark/androidx.test.runner.AndroidJUnitRunner
+```
+
+## Decoder
+
+The test decodes input stream and benchmarks the decoders available in SDK.
+```
+adb shell am instrument -w -r -e class 'com.android.media.benchmark.tests.DecoderTest' com.android.media.benchmark/androidx.test.runner.AndroidJUnitRunner
+```
+
+## Muxer
+
+The test muxes elementary stream and benchmarks different writers available in SDK.
+```
+adb shell am instrument -w -r -e class 'com.android.media.benchmark.tests.MuxerTest' com.android.media.benchmark/androidx.test.runner.AndroidJUnitRunner
+```
+
+## Encoder
+
+The test encodes input stream and benchmarks the encoders available in SDK.
+```
+adb shell am instrument -w -r -e class 'com.android.media.benchmark.tests.EncoderTest' com.android.media.benchmark/androidx.test.runner.AndroidJUnitRunner
+```
+
+# Codec2
+To run the test suite for measuring performance of the codec2 layer, follow the following steps:
+
+The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/
+The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/
+
+To test 64-bit binary push binaries from nativetest64.
+adb push $(OUT)/data/nativetest64/* /data/local/tmp/
+Eg. adb push $(OUT)/data/nativetest64/C2DecoderTest/C2DecoderTest /data/local/tmp/
+
+To test 32-bit binary push binaries from nativetest.
+adb push $(OUT)/data/nativetest/* /data/local/tmp/
+Eg. adb push $(OUT)/data/nativetest/C2DecoderTest/C2DecoderTest /data/local/tmp/
+
+To get the resource files for the test follow instructions given in [NDK](#NDK)
+
+## C2 Decoder
+
+The test decodes input stream and benchmarks the codec2 decoders available in device.
+
+Setup steps are same as [extractor](#extractor).
+
+```
+adb shell /data/local/tmp/C2DecoderTest -P /data/local/tmp/MediaBenchmark/res/
+```
+## C2 Encoder
+
+The test encodes input stream and benchmarks the codec2 encoders available in device.
+
+Setup steps are same as [extractor](#extractor).
+
+```
+adb shell /data/local/tmp/C2EncoderTest -P /data/local/tmp/MediaBenchmark/res/
+```
diff --git a/media/tests/benchmark/src/native/common/Android.bp b/media/tests/benchmark/src/native/common/Android.bp
new file mode 100644
index 0000000..d4389da
--- /dev/null
+++ b/media/tests/benchmark/src/native/common/Android.bp
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+
+cc_library_static {
+ name: "libmediabenchmark_common",
+ defaults: [
+ "libmediabenchmark-defaults",
+ "libmediabenchmark_soft_sanitize_all-defaults",
+ ],
+
+ srcs: [
+ "BenchmarkCommon.cpp",
+ "Stats.cpp",
+ "utils/Timers.cpp",
+ ],
+
+ export_include_dirs: ["."],
+
+ ldflags: ["-Wl,-Bsymbolic"],
+}
+
+cc_defaults {
+ name: "libmediabenchmark_common-defaults",
+
+ defaults: [
+ "libmediabenchmark-defaults",
+ ],
+
+ static_libs: [
+ "libmediabenchmark_common",
+ ],
+}
+
+cc_defaults {
+ name: "libmediabenchmark-defaults",
+ sdk_version: "current",
+ stl: "c++_shared",
+
+ shared_libs: [
+ "libmediandk",
+ "liblog",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
+
+cc_library_static {
+ name: "libmediabenchmark_codec2_common",
+ defaults: [
+ "libmediabenchmark_codec2_common-defaults",
+ ],
+
+ srcs: [
+ "BenchmarkC2Common.cpp",
+ "BenchmarkCommon.cpp",
+ "Stats.cpp",
+ "utils/Timers.cpp",
+ ],
+
+ export_include_dirs: ["."],
+
+ ldflags: ["-Wl,-Bsymbolic"],
+}
+
+cc_defaults {
+ name: "libmediabenchmark_codec2_common-defaults",
+
+ defaults: [
+ "libcodec2-hidl-client-defaults",
+ "libmediabenchmark_soft_sanitize_all-defaults",
+ ],
+
+ include_dirs: [
+ "frameworks/av/media/codec2/hidl/client/include",
+ ],
+
+ shared_libs: [
+ "libcodec2_client",
+ "libmediandk",
+ "liblog",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
+
+// public dependency for native implementation
+// to be used by code under media/benchmark/* only
+cc_defaults {
+ name: "libmediabenchmark_soft_sanitize_all-defaults",
+
+ sanitize: {
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ cfi: true,
+ },
+}
diff --git a/media/tests/benchmark/src/native/common/BenchmarkC2Common.cpp b/media/tests/benchmark/src/native/common/BenchmarkC2Common.cpp
new file mode 100644
index 0000000..e09f468
--- /dev/null
+++ b/media/tests/benchmark/src/native/common/BenchmarkC2Common.cpp
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "BenchmarkC2Common"
+
+#include "BenchmarkC2Common.h"
+
+int32_t BenchmarkC2Common::setupCodec2() {
+ ALOGV("In %s", __func__);
+ mClient = android::Codec2Client::CreateFromService("default");
+ if (!mClient) {
+ mClient = android::Codec2Client::CreateFromService("software");
+ }
+ if (!mClient) return -1;
+
+ std::shared_ptr<C2AllocatorStore> store = android::GetCodec2PlatformAllocatorStore();
+ if (!store) return -1;
+
+ c2_status_t status = store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &mLinearAllocator);
+ if (status != C2_OK) return status;
+
+ mLinearPool = std::make_shared<C2PooledBlockPool>(mLinearAllocator, mBlockPoolId++);
+ if (!mLinearPool) return -1;
+
+ status = store->fetchAllocator(C2AllocatorStore::DEFAULT_GRAPHIC, &mGraphicAllocator);
+ if (status != C2_OK) return status;
+
+ mGraphicPool = std::make_shared<C2PooledBlockPool>(mGraphicAllocator, mBlockPoolId++);
+ if (!mGraphicPool) return -1;
+
+ for (int i = 0; i < MAX_INPUT_BUFFERS; ++i) {
+ mWorkQueue.emplace_back(new C2Work);
+ }
+ if (!mStats) mStats = new Stats();
+
+ return status;
+}
+
+vector<string> BenchmarkC2Common::getSupportedComponentList(bool isEncoder) {
+ // Get List of components from all known services
+ vector<string> codecList;
+ const std::vector<C2Component::Traits> listTraits = mClient->ListComponents();
+ if (listTraits.size() == 0)
+ ALOGE("ComponentInfo list empty.");
+ else {
+ for (size_t i = 0; i < listTraits.size(); i++) {
+ if (isEncoder && C2Component::KIND_ENCODER == listTraits[i].kind) {
+ codecList.push_back(listTraits[i].name);
+ } else if (!isEncoder && C2Component::KIND_DECODER == listTraits[i].kind) {
+ codecList.push_back(listTraits[i].name);
+ }
+ }
+ }
+ return codecList;
+}
+
+void BenchmarkC2Common::waitOnInputConsumption() {
+ typedef std::unique_lock<std::mutex> ULock;
+ uint32_t queueSize;
+ uint32_t maxRetry = 0;
+ {
+ ULock l(mQueueLock);
+ queueSize = mWorkQueue.size();
+ }
+ while ((maxRetry < MAX_RETRY) && (queueSize < MAX_INPUT_BUFFERS)) {
+ ULock l(mQueueLock);
+ if (queueSize != mWorkQueue.size()) {
+ queueSize = mWorkQueue.size();
+ maxRetry = 0;
+ } else {
+ mQueueCondition.wait_for(l, TIME_OUT);
+ maxRetry++;
+ }
+ }
+}
+
+void BenchmarkC2Common::handleWorkDone(std::list<std::unique_ptr<C2Work>> &workItems) {
+ ALOGV("In %s", __func__);
+ mStats->addOutputTime();
+ for (std::unique_ptr<C2Work> &work : workItems) {
+ if (!work->worklets.empty()) {
+ if (work->worklets.front()->output.flags != C2FrameData::FLAG_INCOMPLETE) {
+ mEos = (work->worklets.front()->output.flags & C2FrameData::FLAG_END_OF_STREAM) !=
+ 0;
+ ALOGV("WorkDone: frameID received %d , mEos : %d",
+ (int)work->worklets.front()->output.ordinal.frameIndex.peeku(), mEos);
+ work->input.buffers.clear();
+ work->worklets.clear();
+ {
+ typedef std::unique_lock<std::mutex> ULock;
+ ULock l(mQueueLock);
+ mWorkQueue.push_back(std::move(work));
+ mQueueCondition.notify_all();
+ }
+ }
+ }
+ }
+}
+
diff --git a/media/tests/benchmark/src/native/common/BenchmarkC2Common.h b/media/tests/benchmark/src/native/common/BenchmarkC2Common.h
new file mode 100644
index 0000000..d67758a
--- /dev/null
+++ b/media/tests/benchmark/src/native/common/BenchmarkC2Common.h
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+
+#ifndef __BENCHMARK_C2_COMMON_H__
+#define __BENCHMARK_C2_COMMON_H__
+
+#include "codec2/hidl/client.h"
+
+#include <C2Component.h>
+#include <C2Config.h>
+
+#include <hidl/HidlSupport.h>
+
+#include <C2AllocatorIon.h>
+#include <C2Buffer.h>
+#include <C2BufferPriv.h>
+
+#include "BenchmarkCommon.h"
+
+#define MAX_RETRY 20
+#define TIME_OUT 400ms
+#define MAX_INPUT_BUFFERS 8
+
+using android::C2AllocatorIon;
+
+class LinearBuffer : public C2Buffer {
+ public:
+ explicit LinearBuffer(const std::shared_ptr<C2LinearBlock> &block)
+ : C2Buffer({block->share(block->offset(), block->size(), ::C2Fence())}) {}
+
+ explicit LinearBuffer(const std::shared_ptr<C2LinearBlock> &block, size_t size)
+ : C2Buffer({block->share(block->offset(), size, ::C2Fence())}) {}
+};
+
+class GraphicBuffer : public C2Buffer {
+ public:
+ explicit GraphicBuffer(const std::shared_ptr<C2GraphicBlock> &block)
+ : C2Buffer({block->share(C2Rect(block->width(), block->height()), ::C2Fence())}) {}
+};
+
+/**
+ * Handle Callback functions onWorkDone(), onTripped(),
+ * onError(), onDeath(), onFramesRendered() for C2 Components
+ */
+struct CodecListener : public android::Codec2Client::Listener {
+ public:
+ CodecListener(
+ const std::function<void(std::list<std::unique_ptr<C2Work>> &workItems)> fn = nullptr)
+ : callBack(fn) {}
+ virtual void onWorkDone(const std::weak_ptr<android::Codec2Client::Component> &comp,
+ std::list<std::unique_ptr<C2Work>> &workItems) override {
+ ALOGV("onWorkDone called");
+ (void)comp;
+ if (callBack) callBack(workItems);
+ }
+
+ virtual void onTripped(
+ const std::weak_ptr<android::Codec2Client::Component> &comp,
+ const std::vector<std::shared_ptr<C2SettingResult>> &settingResults) override {
+ (void)comp;
+ (void)settingResults;
+ }
+
+ virtual void onError(const std::weak_ptr<android::Codec2Client::Component> &comp,
+ uint32_t errorCode) override {
+ (void)comp;
+ ALOGV("onError called");
+ if (errorCode != 0) ALOGE("Error : %u", errorCode);
+ }
+
+ virtual void onDeath(const std::weak_ptr<android::Codec2Client::Component> &comp) override {
+ (void)comp;
+ }
+
+ virtual void onInputBufferDone(uint64_t frameIndex, size_t arrayIndex) override {
+ (void)frameIndex;
+ (void)arrayIndex;
+ }
+
+ virtual void onFrameRendered(uint64_t bufferQueueId, int32_t slotId,
+ int64_t timestampNs) override {
+ (void)bufferQueueId;
+ (void)slotId;
+ (void)timestampNs;
+ }
+
+ std::function<void(std::list<std::unique_ptr<C2Work>> &workItems)> callBack;
+};
+
+class BenchmarkC2Common {
+ public:
+ BenchmarkC2Common()
+ : mEos(false),
+ mStats(nullptr),
+ mClient(nullptr),
+ mBlockPoolId(0),
+ mLinearPool(nullptr),
+ mGraphicPool(nullptr),
+ mLinearAllocator(nullptr),
+ mGraphicAllocator(nullptr) {}
+
+ int32_t setupCodec2();
+
+ vector<string> getSupportedComponentList(bool isEncoder);
+
+ void waitOnInputConsumption();
+
+ // callback function to process onWorkDone received by Listener
+ void handleWorkDone(std::list<std::unique_ptr<C2Work>> &workItems);
+
+ bool mEos;
+ protected:
+ Stats *mStats;
+
+ std::shared_ptr<android::Codec2Client> mClient;
+
+ C2BlockPool::local_id_t mBlockPoolId;
+ std::shared_ptr<C2BlockPool> mLinearPool;
+ std::shared_ptr<C2BlockPool> mGraphicPool;
+ std::shared_ptr<C2Allocator> mLinearAllocator;
+ std::shared_ptr<C2Allocator> mGraphicAllocator;
+
+ std::mutex mQueueLock;
+ std::condition_variable mQueueCondition;
+ std::list<std::unique_ptr<C2Work>> mWorkQueue;
+};
+
+#endif // __BENCHMARK_C2_COMMON_H__
diff --git a/media/tests/benchmark/src/native/common/BenchmarkCommon.cpp b/media/tests/benchmark/src/native/common/BenchmarkCommon.cpp
new file mode 100644
index 0000000..cb49b8e
--- /dev/null
+++ b/media/tests/benchmark/src/native/common/BenchmarkCommon.cpp
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "BenchmarkCommon"
+
+#include "BenchmarkCommon.h"
+#include <iostream>
+
+void CallBackHandle::ioThread() {
+ ALOGV("In %s mIsDone : %d, mSawError : %d ", __func__, mIsDone, mSawError);
+ while (!mIsDone && !mSawError) {
+ auto task = mIOQueue.pop();
+ task();
+ }
+}
+
+void OnInputAvailableCB(AMediaCodec *codec, void *userdata, int32_t index) {
+ ALOGV("OnInputAvailableCB: index(%d)", index);
+ CallBackHandle *self = (CallBackHandle *)userdata;
+ self->getStats()->addInputTime();
+ self->mIOQueue.push([self, codec, index]() { self->onInputAvailable(codec, index); });
+}
+
+void OnOutputAvailableCB(AMediaCodec *codec, void *userdata, int32_t index,
+ AMediaCodecBufferInfo *bufferInfo) {
+ ALOGV("OnOutputAvailableCB: index(%d), (%d, %d, %lld, 0x%x)", index, bufferInfo->offset,
+ bufferInfo->size, (long long)bufferInfo->presentationTimeUs, bufferInfo->flags);
+ CallBackHandle *self = (CallBackHandle *)userdata;
+ self->getStats()->addOutputTime();
+ AMediaCodecBufferInfo bufferInfoCopy = *bufferInfo;
+ self->mIOQueue.push([self, codec, index, bufferInfoCopy]() {
+ AMediaCodecBufferInfo bc = bufferInfoCopy;
+ self->onOutputAvailable(codec, index, &bc);
+ });
+}
+
+void OnFormatChangedCB(AMediaCodec *codec, void *userdata, AMediaFormat *format) {
+ ALOGV("OnFormatChangedCB: format(%s)", AMediaFormat_toString(format));
+ CallBackHandle *self = (CallBackHandle *)userdata;
+ self->mIOQueue.push([self, codec, format]() { self->onFormatChanged(codec, format); });
+}
+
+void OnErrorCB(AMediaCodec *codec, void *userdata, media_status_t err, int32_t actionCode,
+ const char *detail) {
+ (void)codec;
+ ALOGE("OnErrorCB: err(%d), actionCode(%d), detail(%s)", err, actionCode, detail);
+ CallBackHandle *self = (CallBackHandle *)userdata;
+ self->mSawError = true;
+ self->mIOQueue.push([self, codec, err]() { self->onError(codec, err); });
+}
+
+AMediaCodec *createMediaCodec(AMediaFormat *format, const char *mime, string codecName,
+ bool isEncoder) {
+ ALOGV("In %s", __func__);
+ if (!mime) {
+ ALOGE("Please specify a mime type to create codec");
+ return nullptr;
+ }
+
+ AMediaCodec *codec;
+ if (!codecName.empty()) {
+ codec = AMediaCodec_createCodecByName(codecName.c_str());
+ if (!codec) {
+ ALOGE("Unable to create codec by name: %s", codecName.c_str());
+ return nullptr;
+ }
+ } else {
+ if (isEncoder) {
+ codec = AMediaCodec_createEncoderByType(mime);
+ } else {
+ codec = AMediaCodec_createDecoderByType(mime);
+ }
+ if (!codec) {
+ ALOGE("Unable to create codec by mime: %s", mime);
+ return nullptr;
+ }
+ }
+
+ /* Configure codec with the given format*/
+ const char *s = AMediaFormat_toString(format);
+ ALOGI("Input format: %s\n", s);
+
+ media_status_t status = AMediaCodec_configure(codec, format, nullptr, nullptr, isEncoder);
+ if (status != AMEDIA_OK) {
+ ALOGE("AMediaCodec_configure failed %d", status);
+ return nullptr;
+ }
+ return codec;
+}
diff --git a/media/tests/benchmark/src/native/common/BenchmarkCommon.h b/media/tests/benchmark/src/native/common/BenchmarkCommon.h
new file mode 100644
index 0000000..40a8c9e
--- /dev/null
+++ b/media/tests/benchmark/src/native/common/BenchmarkCommon.h
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+
+#ifndef __BENCHMARK_COMMON_H__
+#define __BENCHMARK_COMMON_H__
+
+#include <sys/stat.h>
+#include <inttypes.h>
+#include <mutex>
+#include <queue>
+#include <thread>
+#include <iostream>
+
+#include <media/NdkMediaCodec.h>
+#include <media/NdkMediaError.h>
+
+#include "Stats.h"
+#define UNUSED(x) (void)(x)
+
+using namespace std;
+
+constexpr uint32_t kQueueDequeueTimeoutUs = 1000;
+constexpr uint32_t kMaxCSDStrlen = 16;
+constexpr uint32_t kMaxBufferSize = 1024 * 1024 * 16;
+// Change in kDefaultAudioEncodeFrameSize should also be taken to
+// AUDIO_ENCODE_DEFAULT_MAX_INPUT_SIZE present in Encoder.java
+constexpr uint32_t kDefaultAudioEncodeFrameSize = 4096;
+
+template <typename T>
+class CallBackQueue {
+ public:
+ CallBackQueue() {}
+ ~CallBackQueue() {}
+
+ void push(T elem) {
+ bool needsNotify = false;
+ {
+ lock_guard<mutex> lock(mMutex);
+ needsNotify = mQueue.empty();
+ mQueue.push(move(elem));
+ }
+ if (needsNotify) mQueueNotEmptyCondition.notify_one();
+ }
+
+ T pop() {
+ unique_lock<mutex> lock(mMutex);
+ if (mQueue.empty()) {
+ mQueueNotEmptyCondition.wait(lock, [this]() { return !mQueue.empty(); });
+ }
+ auto result = mQueue.front();
+ mQueue.pop();
+ return result;
+ }
+
+ private:
+ mutex mMutex;
+ queue<T> mQueue;
+ condition_variable mQueueNotEmptyCondition;
+};
+
+class CallBackHandle {
+ public:
+ CallBackHandle() : mSawError(false), mIsDone(false), mStats(nullptr) {
+ mStats = new Stats();
+ }
+
+ virtual ~CallBackHandle() {
+ if (mIOThread.joinable()) mIOThread.join();
+ if (mStats) delete mStats;
+ }
+
+ void ioThread();
+
+ // Implementation in child class (Decoder/Encoder)
+ virtual void onInputAvailable(AMediaCodec *codec, int32_t index) {
+ (void)codec;
+ (void)index;
+ }
+ virtual void onFormatChanged(AMediaCodec *codec, AMediaFormat *format) {
+ (void)codec;
+ (void)format;
+ }
+ virtual void onError(AMediaCodec *codec, media_status_t err) {
+ (void)codec;
+ (void)err;
+ }
+ virtual void onOutputAvailable(AMediaCodec *codec, int32_t index,
+ AMediaCodecBufferInfo *bufferInfo) {
+ (void)codec;
+ (void)index;
+ (void)bufferInfo;
+ }
+
+ Stats *getStats() { return mStats; }
+
+ // Keep a queue of all function callbacks.
+ typedef function<void()> IOTask;
+ CallBackQueue<IOTask> mIOQueue;
+ thread mIOThread;
+ bool mSawError;
+ bool mIsDone;
+
+ protected:
+ Stats *mStats;
+};
+
+// Async API's callback
+void OnInputAvailableCB(AMediaCodec *codec, void *userdata, int32_t index);
+
+void OnOutputAvailableCB(AMediaCodec *codec, void *userdata, int32_t index,
+ AMediaCodecBufferInfo *bufferInfo);
+
+void OnFormatChangedCB(AMediaCodec *codec, void *userdata, AMediaFormat *format);
+
+void OnErrorCB(AMediaCodec *codec, void * /* userdata */, media_status_t err, int32_t actionCode,
+ const char *detail);
+
+// Utility to create and configure AMediaCodec
+AMediaCodec *createMediaCodec(AMediaFormat *format, const char *mime, string codecName,
+ bool isEncoder);
+
+#endif // __BENCHMARK_COMMON_H__
diff --git a/media/tests/benchmark/src/native/common/Stats.cpp b/media/tests/benchmark/src/native/common/Stats.cpp
new file mode 100644
index 0000000..bfde125
--- /dev/null
+++ b/media/tests/benchmark/src/native/common/Stats.cpp
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Stats"
+
+#include <ctime>
+#include <iostream>
+#include <stdint.h>
+#include <fstream>
+
+#include "Stats.h"
+
+/**
+ * Dumps the stats of the operation for a given input media.
+ *
+ * \param operation describes the operation performed on the input media
+ * (i.e. extract/mux/decode/encode)
+ * \param inputReference input media
+ * \param durationUs is a duration of the input media in microseconds.
+ * \param componentName describes the codecName/muxFormat/mimeType.
+ * \param mode the operating mode: sync/async.
+ * \param statsFile the file where the stats data is to be written.
+ */
+void Stats::dumpStatistics(string operation, string inputReference, int64_t durationUs,
+ string componentName, string mode, string statsFile) {
+ ALOGV("In %s", __func__);
+ if (!mOutputTimer.size()) {
+ ALOGE("No output produced");
+ return;
+ }
+ nsecs_t totalTimeTakenNs = getTotalTime();
+ nsecs_t timeTakenPerSec = (totalTimeTakenNs * 1000000) / durationUs;
+ nsecs_t timeToFirstFrameNs = *mOutputTimer.begin() - mStartTimeNs;
+ int32_t size = std::accumulate(mFrameSizes.begin(), mFrameSizes.end(), 0);
+ // get min and max output intervals.
+ nsecs_t intervalNs;
+ nsecs_t minTimeTakenNs = INT64_MAX;
+ nsecs_t maxTimeTakenNs = 0;
+ nsecs_t prevIntervalNs = mStartTimeNs;
+ for (int32_t idx = 0; idx < mOutputTimer.size() - 1; idx++) {
+ intervalNs = mOutputTimer.at(idx) - prevIntervalNs;
+ prevIntervalNs = mOutputTimer.at(idx);
+ if (minTimeTakenNs > intervalNs) minTimeTakenNs = intervalNs;
+ else if (maxTimeTakenNs < intervalNs) maxTimeTakenNs = intervalNs;
+ }
+
+ // Write the stats data to file.
+ int64_t dataSize = size;
+ int64_t bytesPerSec = ((int64_t)dataSize * 1000000000) / totalTimeTakenNs;
+ string rowData = "";
+ rowData.append(to_string(systemTime(CLOCK_MONOTONIC)) + ", ");
+ rowData.append(inputReference + ", ");
+ rowData.append(operation + ", ");
+ rowData.append(componentName + ", ");
+ rowData.append("NDK, ");
+ rowData.append(mode + ", ");
+ rowData.append(to_string(mInitTimeNs) + ", ");
+ rowData.append(to_string(mDeInitTimeNs) + ", ");
+ rowData.append(to_string(minTimeTakenNs) + ", ");
+ rowData.append(to_string(maxTimeTakenNs) + ", ");
+ rowData.append(to_string(totalTimeTakenNs / mOutputTimer.size()) + ", ");
+ rowData.append(to_string(timeTakenPerSec) + ", ");
+ rowData.append(to_string(bytesPerSec) + ", ");
+ rowData.append(to_string(timeToFirstFrameNs) + ", ");
+ rowData.append(to_string(size) + ",");
+ rowData.append(to_string(totalTimeTakenNs) + ",\n");
+
+ ofstream out(statsFile, ios::out | ios::app);
+ if(out.bad()) {
+ ALOGE("Failed to open stats file for writing!");
+ return;
+ }
+ out << rowData;
+ out.close();
+}
diff --git a/media/tests/benchmark/src/native/common/Stats.h b/media/tests/benchmark/src/native/common/Stats.h
new file mode 100644
index 0000000..18e4b06
--- /dev/null
+++ b/media/tests/benchmark/src/native/common/Stats.h
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+#ifndef __STATS_H__
+#define __STATS_H__
+
+#include <android/log.h>
+#include <inttypes.h>
+
+#ifndef ALOG
+#define ALOG(priority, tag, ...) ((void)__android_log_print(ANDROID_##priority, tag, __VA_ARGS__))
+
+#define ALOGI(...) ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define ALOGE(...) ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)
+#define ALOGD(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
+#define ALOGW(...) ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)
+
+#ifndef LOG_NDEBUG
+#define LOG_NDEBUG 1
+#endif
+
+#if LOG_NDEBUG
+#define ALOGV(cond, ...) ((void)0)
+#else
+#define ALOGV(...) ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
+#endif
+#endif // ALOG
+
+#include <sys/time.h>
+#include <algorithm>
+#include <numeric>
+#include <vector>
+
+// Include local copy of Timers taken from system/core/libutils
+#include "utils/Timers.h"
+
+using namespace std;
+
+class Stats {
+ public:
+ Stats() {
+ mInitTimeNs = 0;
+ mDeInitTimeNs = 0;
+ }
+
+ ~Stats() {
+ reset();
+ }
+
+ private:
+ nsecs_t mInitTimeNs;
+ nsecs_t mDeInitTimeNs;
+ nsecs_t mStartTimeNs;
+ std::vector<int32_t> mFrameSizes;
+ std::vector<nsecs_t> mInputTimer;
+ std::vector<nsecs_t> mOutputTimer;
+
+ public:
+ nsecs_t getCurTime() { return systemTime(CLOCK_MONOTONIC); }
+
+ void setInitTime(nsecs_t initTime) { mInitTimeNs = initTime; }
+
+ void setDeInitTime(nsecs_t deInitTime) { mDeInitTimeNs = deInitTime; }
+
+ void setStartTime() { mStartTimeNs = systemTime(CLOCK_MONOTONIC); }
+
+ void addFrameSize(int32_t size) { mFrameSizes.push_back(size); }
+
+ void addInputTime() { mInputTimer.push_back(systemTime(CLOCK_MONOTONIC)); }
+
+ void addOutputTime() { mOutputTimer.push_back(systemTime(CLOCK_MONOTONIC)); }
+
+ void reset() {
+ if (!mFrameSizes.empty()) mFrameSizes.clear();
+ if (!mInputTimer.empty()) mInputTimer.clear();
+ if (!mOutputTimer.empty()) mOutputTimer.clear();
+ }
+
+ std::vector<nsecs_t> getOutputTimer() { return mOutputTimer; }
+
+ nsecs_t getInitTime() { return mInitTimeNs; }
+
+ nsecs_t getDeInitTime() { return mDeInitTimeNs; }
+
+ nsecs_t getTimeDiff(nsecs_t sTime, nsecs_t eTime) { return (eTime - sTime); }
+
+ nsecs_t getTotalTime() {
+ if (mOutputTimer.empty()) return -1;
+ return (*(mOutputTimer.end() - 1) - mStartTimeNs);
+ }
+
+ void dumpStatistics(string operation, string inputReference, int64_t duarationUs,
+ string codecName = "", string mode = "", string statsFile = "");
+};
+
+#endif // __STATS_H__
diff --git a/media/tests/benchmark/src/native/common/utils/Timers.cpp b/media/tests/benchmark/src/native/common/utils/Timers.cpp
new file mode 100644
index 0000000..1acbdb3
--- /dev/null
+++ b/media/tests/benchmark/src/native/common/utils/Timers.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Timer functions.
+//
+
+#define LOG_TAG "Timers"
+
+#include <limits.h>
+#include <time.h>
+
+#include "Timers.h"
+
+#if defined(__ANDROID__)
+nsecs_t systemTime(int clock) {
+ static const clockid_t clocks[] = {CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID,
+ CLOCK_THREAD_CPUTIME_ID, CLOCK_BOOTTIME};
+ struct timespec t;
+ t.tv_sec = t.tv_nsec = 0;
+ clock_gettime(clocks[clock], &t);
+ return nsecs_t(t.tv_sec) * 1000000000LL + t.tv_nsec;
+}
+#else
+nsecs_t systemTime(int /*clock*/) {
+ // Clock support varies widely across hosts. Mac OS doesn't support
+ // posix clocks, older glibcs don't support CLOCK_BOOTTIME and Windows
+ // is windows.
+ struct timeval t;
+ t.tv_sec = t.tv_usec = 0;
+ gettimeofday(&t, NULL);
+ return nsecs_t(t.tv_sec) * 1000000000LL + nsecs_t(t.tv_usec) * 1000LL;
+}
+#endif
+
+int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime) {
+ nsecs_t timeoutDelayMillis;
+ if (timeoutTime > referenceTime) {
+ uint64_t timeoutDelay = uint64_t(timeoutTime - referenceTime);
+ if (timeoutDelay > uint64_t((INT_MAX - 1) * 1000000LL)) {
+ timeoutDelayMillis = -1;
+ } else {
+ timeoutDelayMillis = (timeoutDelay + 999999LL) / 1000000LL;
+ }
+ } else {
+ timeoutDelayMillis = 0;
+ }
+ return (int)timeoutDelayMillis;
+}
diff --git a/media/tests/benchmark/src/native/common/utils/Timers.h b/media/tests/benchmark/src/native/common/utils/Timers.h
new file mode 100644
index 0000000..d643dcd
--- /dev/null
+++ b/media/tests/benchmark/src/native/common/utils/Timers.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Timer functions.
+//
+
+#ifndef _LIBS_UTILS_TIMERS_H
+#define _LIBS_UTILS_TIMERS_H
+
+#include <stdint.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+// ------------------------------------------------------------------
+// C API
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int64_t nsecs_t; // nano-seconds
+
+static inline nsecs_t seconds_to_nanoseconds(nsecs_t secs) {
+ return secs * 1000000000;
+}
+
+static inline nsecs_t milliseconds_to_nanoseconds(nsecs_t secs) {
+ return secs * 1000000;
+}
+
+static inline nsecs_t microseconds_to_nanoseconds(nsecs_t secs) {
+ return secs * 1000;
+}
+
+static inline nsecs_t nanoseconds_to_seconds(nsecs_t secs) {
+ return secs / 1000000000;
+}
+
+static inline nsecs_t nanoseconds_to_milliseconds(nsecs_t secs) {
+ return secs / 1000000;
+}
+
+static inline nsecs_t nanoseconds_to_microseconds(nsecs_t secs) {
+ return secs / 1000;
+}
+
+static inline nsecs_t s2ns(nsecs_t v) {
+ return seconds_to_nanoseconds(v);
+}
+static inline nsecs_t ms2ns(nsecs_t v) {
+ return milliseconds_to_nanoseconds(v);
+}
+static inline nsecs_t us2ns(nsecs_t v) {
+ return microseconds_to_nanoseconds(v);
+}
+static inline nsecs_t ns2s(nsecs_t v) {
+ return nanoseconds_to_seconds(v);
+}
+static inline nsecs_t ns2ms(nsecs_t v) {
+ return nanoseconds_to_milliseconds(v);
+}
+static inline nsecs_t ns2us(nsecs_t v) {
+ return nanoseconds_to_microseconds(v);
+}
+
+static inline nsecs_t seconds(nsecs_t v) {
+ return s2ns(v);
+}
+static inline nsecs_t milliseconds(nsecs_t v) {
+ return ms2ns(v);
+}
+static inline nsecs_t microseconds(nsecs_t v) {
+ return us2ns(v);
+}
+
+enum {
+ SYSTEM_TIME_REALTIME = 0, // system-wide realtime clock
+ SYSTEM_TIME_MONOTONIC = 1, // monotonic time since unspecified starting point
+ SYSTEM_TIME_PROCESS = 2, // high-resolution per-process clock
+ SYSTEM_TIME_THREAD = 3, // high-resolution per-thread clock
+ SYSTEM_TIME_BOOTTIME = 4 // same as SYSTEM_TIME_MONOTONIC, but including CPU suspend time
+};
+
+// return the system-time according to the specified clock
+#ifdef __cplusplus
+nsecs_t systemTime(int clock = SYSTEM_TIME_MONOTONIC);
+#else
+nsecs_t systemTime(int clock);
+#endif // def __cplusplus
+
+/**
+ * Returns the number of milliseconds to wait between the reference time and the timeout time.
+ * If the timeout is in the past relative to the reference time, returns 0.
+ * If the timeout is more than INT_MAX milliseconds in the future relative to the reference time,
+ * such as when timeoutTime == LLONG_MAX, returns -1 to indicate an infinite timeout delay.
+ * Otherwise, returns the difference between the reference time and timeout time
+ * rounded up to the next millisecond.
+ */
+int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _LIBS_UTILS_TIMERS_H
diff --git a/media/tests/benchmark/src/native/decoder/Android.bp b/media/tests/benchmark/src/native/decoder/Android.bp
new file mode 100644
index 0000000..9791c11
--- /dev/null
+++ b/media/tests/benchmark/src/native/decoder/Android.bp
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+cc_library_static {
+ name: "libmediabenchmark_decoder",
+ defaults: [
+ "libmediabenchmark_common-defaults",
+ "libmediabenchmark_soft_sanitize_all-defaults",
+ ],
+
+ srcs: ["Decoder.cpp"],
+
+ static_libs: ["libmediabenchmark_extractor"],
+
+ export_include_dirs: ["."],
+
+ ldflags: ["-Wl,-Bsymbolic"],
+}
+
+cc_library_static {
+ name: "libmediabenchmark_codec2_decoder",
+ defaults: [
+ "libmediabenchmark_codec2_common-defaults",
+ ],
+
+ srcs: [
+ "C2Decoder.cpp",
+ "Decoder.cpp",
+ ],
+
+ static_libs: [
+ "libmediabenchmark_codec2_common",
+ "libmediabenchmark_codec2_extractor",
+ ],
+
+ export_include_dirs: ["."],
+
+ ldflags: ["-Wl,-Bsymbolic"],
+}
diff --git a/media/tests/benchmark/src/native/decoder/C2Decoder.cpp b/media/tests/benchmark/src/native/decoder/C2Decoder.cpp
new file mode 100644
index 0000000..20a1468
--- /dev/null
+++ b/media/tests/benchmark/src/native/decoder/C2Decoder.cpp
@@ -0,0 +1,168 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2Decoder"
+#include <log/log.h>
+
+#include "C2Decoder.h"
+#include <iostream>
+
+int32_t C2Decoder::createCodec2Component(string compName, AMediaFormat *format) {
+ ALOGV("In %s", __func__);
+ mListener.reset(new CodecListener(
+ [this](std::list<std::unique_ptr<C2Work>> &workItems) { handleWorkDone(workItems); }));
+ if (!mListener) return -1;
+
+ const char *mime = nullptr;
+ AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime);
+ if (!mime) {
+ ALOGE("Error in AMediaFormat_getString");
+ return -1;
+ }
+ // Configure the plugin with Input properties
+ std::vector<C2Param *> configParam;
+ if (!strncmp(mime, "audio/", 6)) {
+ int32_t sampleRate, numChannels;
+ AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, &sampleRate);
+ AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &numChannels);
+ C2StreamSampleRateInfo::output sampleRateInfo(0u, sampleRate);
+ C2StreamChannelCountInfo::output channelCountInfo(0u, numChannels);
+ configParam.push_back(&sampleRateInfo);
+ configParam.push_back(&channelCountInfo);
+
+ } else {
+ int32_t width, height;
+ AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &width);
+ AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &height);
+ C2StreamPictureSizeInfo::input inputSize(0u, width, height);
+ configParam.push_back(&inputSize);
+ }
+
+ int64_t sTime = mStats->getCurTime();
+ mComponent = mClient->CreateComponentByName(compName.c_str(), mListener, &mClient);
+ if (mComponent == nullptr) {
+ ALOGE("Create component failed for %s", compName.c_str());
+ return -1;
+ }
+ std::vector<std::unique_ptr<C2SettingResult>> failures;
+ int32_t status = mComponent->config(configParam, C2_DONT_BLOCK, &failures);
+ if (failures.size() != 0) {
+ ALOGE("Invalid Configuration");
+ return -1;
+ }
+
+ status |= mComponent->start();
+ int64_t eTime = mStats->getCurTime();
+ int64_t timeTaken = mStats->getTimeDiff(sTime, eTime);
+ mStats->setInitTime(timeTaken);
+ return status;
+}
+
+int32_t C2Decoder::decodeFrames(uint8_t *inputBuffer, vector<AMediaCodecBufferInfo> &frameInfo) {
+ ALOGV("In %s", __func__);
+ typedef std::unique_lock<std::mutex> ULock;
+ c2_status_t status = C2_OK;
+ mStats->setStartTime();
+ while (1) {
+ if (mNumInputFrame == frameInfo.size()) break;
+ std::unique_ptr<C2Work> work;
+ // Prepare C2Work
+ {
+ ULock l(mQueueLock);
+ if (mWorkQueue.empty()) mQueueCondition.wait_for(l, MAX_RETRY * TIME_OUT);
+ if (!mWorkQueue.empty()) {
+ mStats->addInputTime();
+ work.swap(mWorkQueue.front());
+ mWorkQueue.pop_front();
+ } else {
+ std::cout << "Wait for generating C2Work exceeded timeout" << std::endl;
+ return -1;
+ }
+ }
+
+ uint32_t flags = frameInfo[mNumInputFrame].flags;
+ if (flags == AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG) {
+ flags = C2FrameData::FLAG_CODEC_CONFIG;
+ }
+ if (mNumInputFrame == (frameInfo.size() - 1)) {
+ flags |= C2FrameData::FLAG_END_OF_STREAM;
+ }
+ work->input.flags = (C2FrameData::flags_t)flags;
+ work->input.ordinal.timestamp = frameInfo[mNumInputFrame].presentationTimeUs;
+ work->input.ordinal.frameIndex = mNumInputFrame;
+ work->input.buffers.clear();
+ int size = frameInfo[mNumInputFrame].size;
+ int alignedSize = ALIGN(size, PAGE_SIZE);
+ if (size) {
+ std::shared_ptr<C2LinearBlock> block;
+ status = mLinearPool->fetchLinearBlock(
+ alignedSize, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, &block);
+ if (status != C2_OK || block == nullptr) {
+ std::cout << "C2LinearBlock::map() failed : " << status << std::endl;
+ return status;
+ }
+
+ C2WriteView view = block->map().get();
+ if (view.error() != C2_OK) {
+ std::cout << "C2LinearBlock::map() failed : " << view.error() << std::endl;
+ return view.error();
+ }
+ memcpy(view.base(), inputBuffer + mOffset, size);
+ work->input.buffers.emplace_back(new LinearBuffer(block, size));
+ mStats->addFrameSize(size);
+ }
+ work->worklets.clear();
+ work->worklets.emplace_back(new C2Worklet);
+
+ std::list<std::unique_ptr<C2Work>> items;
+ items.push_back(std::move(work));
+ // queue() invokes process() function of C2 Plugin.
+ status = mComponent->queue(&items);
+ if (status != C2_OK) {
+ ALOGE("queue failed");
+ return status;
+ }
+ ALOGV("Frame #%d size = %d queued", mNumInputFrame, size);
+ mNumInputFrame++;
+ mOffset += size;
+ }
+ return status;
+}
+
+void C2Decoder::deInitCodec() {
+ ALOGV("In %s", __func__);
+ if (!mComponent) return;
+
+ int64_t sTime = mStats->getCurTime();
+ mComponent->stop();
+ mComponent->release();
+ mComponent = nullptr;
+ int64_t eTime = mStats->getCurTime();
+ int64_t timeTaken = mStats->getTimeDiff(sTime, eTime);
+ mStats->setDeInitTime(timeTaken);
+}
+
+void C2Decoder::dumpStatistics(string inputReference, int64_t durationUs) {
+ string operation = "c2decode";
+ mStats->dumpStatistics(operation, inputReference, durationUs);
+}
+
+void C2Decoder::resetDecoder() {
+ mOffset = 0;
+ mNumInputFrame = 0;
+ if (mStats) mStats->reset();
+}
diff --git a/media/tests/benchmark/src/native/decoder/C2Decoder.h b/media/tests/benchmark/src/native/decoder/C2Decoder.h
new file mode 100644
index 0000000..4a3eb96
--- /dev/null
+++ b/media/tests/benchmark/src/native/decoder/C2Decoder.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+#ifndef __C2_DECODER_H__
+#define __C2_DECODER_H__
+
+#include "BenchmarkC2Common.h"
+
+#define ALIGN(_sz, _align) (((_sz) + ((_align) - 1)) & ~((_align) - 1))
+
+class C2Decoder : public BenchmarkC2Common {
+ public:
+ C2Decoder() : mOffset(0), mNumInputFrame(0), mComponent(nullptr) {}
+
+ int32_t createCodec2Component(string codecName, AMediaFormat *format);
+
+ int32_t decodeFrames(uint8_t *inputBuffer, vector<AMediaCodecBufferInfo> &frameInfo);
+
+ void deInitCodec();
+
+ void dumpStatistics(string inputReference, int64_t durationUs);
+
+ void resetDecoder();
+
+ private:
+ int32_t mOffset;
+ int32_t mNumInputFrame;
+ vector<AMediaCodecBufferInfo> mFrameMetaData;
+
+ std::shared_ptr<android::Codec2Client::Listener> mListener;
+ std::shared_ptr<android::Codec2Client::Component> mComponent;
+};
+
+#endif // __C2_DECODER_H__
diff --git a/media/tests/benchmark/src/native/decoder/Decoder.cpp b/media/tests/benchmark/src/native/decoder/Decoder.cpp
new file mode 100644
index 0000000..090f3e1
--- /dev/null
+++ b/media/tests/benchmark/src/native/decoder/Decoder.cpp
@@ -0,0 +1,257 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "decoder"
+
+#include <iostream>
+
+#include "Decoder.h"
+
+tuple<ssize_t, uint32_t, int64_t> readSampleData(uint8_t *inputBuffer, int32_t &offset,
+ vector<AMediaCodecBufferInfo> &frameInfo,
+ uint8_t *buf, int32_t frameID, size_t bufSize) {
+ ALOGV("In %s", __func__);
+ if (frameID == (int32_t)frameInfo.size()) {
+ return make_tuple(0, AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM, 0);
+ }
+ uint32_t flags = frameInfo[frameID].flags;
+ int64_t timestamp = frameInfo[frameID].presentationTimeUs;
+ ssize_t bytesCount = frameInfo[frameID].size;
+ if (bufSize < bytesCount) {
+ ALOGE("Error : Buffer size is insufficient to read sample");
+ return make_tuple(0, AMEDIA_ERROR_MALFORMED, 0);
+ }
+
+ memcpy(buf, inputBuffer + offset, bytesCount);
+ offset += bytesCount;
+ return make_tuple(bytesCount, flags, timestamp);
+}
+
+void Decoder::onInputAvailable(AMediaCodec *mediaCodec, int32_t bufIdx) {
+ ALOGV("In %s", __func__);
+ if (mediaCodec == mCodec && mediaCodec) {
+ if (mSawInputEOS || bufIdx < 0) return;
+ if (mSignalledError) {
+ CallBackHandle::mSawError = true;
+ mDecoderDoneCondition.notify_one();
+ return;
+ }
+
+ size_t bufSize;
+ uint8_t *buf = AMediaCodec_getInputBuffer(mCodec, bufIdx, &bufSize);
+ if (!buf) {
+ mErrorCode = AMEDIA_ERROR_IO;
+ mSignalledError = true;
+ mDecoderDoneCondition.notify_one();
+ return;
+ }
+
+ ssize_t bytesRead = 0;
+ uint32_t flag = 0;
+ int64_t presentationTimeUs = 0;
+ tie(bytesRead, flag, presentationTimeUs) =
+ readSampleData(mInputBuffer, mOffset, mFrameMetaData, buf, mNumInputFrame, bufSize);
+ if (flag == AMEDIA_ERROR_MALFORMED) {
+ mErrorCode = (media_status_t)flag;
+ mSignalledError = true;
+ mDecoderDoneCondition.notify_one();
+ return;
+ }
+
+ if (flag == AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) mSawInputEOS = true;
+ ALOGV("%s bytesRead : %zd presentationTimeUs : %" PRId64 " mSawInputEOS : %s", __FUNCTION__,
+ bytesRead, presentationTimeUs, mSawInputEOS ? "TRUE" : "FALSE");
+
+ media_status_t status = AMediaCodec_queueInputBuffer(mCodec, bufIdx, 0 /* offset */,
+ bytesRead, presentationTimeUs, flag);
+ if (AMEDIA_OK != status) {
+ mErrorCode = status;
+ mSignalledError = true;
+ mDecoderDoneCondition.notify_one();
+ return;
+ }
+ mStats->addFrameSize(bytesRead);
+ mNumInputFrame++;
+ }
+}
+
+void Decoder::onOutputAvailable(AMediaCodec *mediaCodec, int32_t bufIdx,
+ AMediaCodecBufferInfo *bufferInfo) {
+ ALOGV("In %s", __func__);
+ if (mediaCodec == mCodec && mediaCodec) {
+ if (mSawOutputEOS || bufIdx < 0) return;
+ if (mSignalledError) {
+ CallBackHandle::mSawError = true;
+ mDecoderDoneCondition.notify_one();
+ return;
+ }
+
+ if (mOutFp != nullptr) {
+ size_t bufSize;
+ uint8_t *buf = AMediaCodec_getOutputBuffer(mCodec, bufIdx, &bufSize);
+ if (buf) {
+ fwrite(buf, sizeof(char), bufferInfo->size, mOutFp);
+ ALOGV("bytes written into file %d\n", bufferInfo->size);
+ }
+ }
+
+ AMediaCodec_releaseOutputBuffer(mCodec, bufIdx, false);
+ mSawOutputEOS = (0 != (bufferInfo->flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM));
+ mNumOutputFrame++;
+ ALOGV("%s index : %d mSawOutputEOS : %s count : %u", __FUNCTION__, bufIdx,
+ mSawOutputEOS ? "TRUE" : "FALSE", mNumOutputFrame);
+
+ if (mSawOutputEOS) {
+ CallBackHandle::mIsDone = true;
+ mDecoderDoneCondition.notify_one();
+ }
+ }
+}
+
+void Decoder::onFormatChanged(AMediaCodec *mediaCodec, AMediaFormat *format) {
+ ALOGV("In %s", __func__);
+ if (mediaCodec == mCodec && mediaCodec) {
+ ALOGV("%s { %s }", __FUNCTION__, AMediaFormat_toString(format));
+ mFormat = format;
+ }
+}
+
+void Decoder::onError(AMediaCodec *mediaCodec, media_status_t err) {
+ ALOGV("In %s", __func__);
+ if (mediaCodec == mCodec && mediaCodec) {
+ ALOGE("Received Error %d", err);
+ mErrorCode = err;
+ mSignalledError = true;
+ mDecoderDoneCondition.notify_one();
+ }
+}
+
+void Decoder::setupDecoder() {
+ if (!mFormat) mFormat = mExtractor->getFormat();
+}
+
+AMediaFormat *Decoder::getFormat() {
+ ALOGV("In %s", __func__);
+ return AMediaCodec_getOutputFormat(mCodec);
+}
+
+int32_t Decoder::decode(uint8_t *inputBuffer, vector<AMediaCodecBufferInfo> &frameInfo,
+ string &codecName, bool asyncMode, FILE *outFp) {
+ ALOGV("In %s", __func__);
+ mInputBuffer = inputBuffer;
+ mFrameMetaData = frameInfo;
+ mOffset = 0;
+ mOutFp = outFp;
+
+ const char *mime = nullptr;
+ AMediaFormat_getString(mFormat, AMEDIAFORMAT_KEY_MIME, &mime);
+ if (!mime) return AMEDIA_ERROR_INVALID_OBJECT;
+
+ int64_t sTime = mStats->getCurTime();
+ mCodec = createMediaCodec(mFormat, mime, codecName, false /*isEncoder*/);
+ if (!mCodec) return AMEDIA_ERROR_INVALID_OBJECT;
+
+ if (asyncMode) {
+ AMediaCodecOnAsyncNotifyCallback aCB = {OnInputAvailableCB, OnOutputAvailableCB,
+ OnFormatChangedCB, OnErrorCB};
+ AMediaCodec_setAsyncNotifyCallback(mCodec, aCB, this);
+
+ mIOThread = thread(&CallBackHandle::ioThread, this);
+ }
+
+ AMediaCodec_start(mCodec);
+ int64_t eTime = mStats->getCurTime();
+ int64_t timeTaken = mStats->getTimeDiff(sTime, eTime);
+ mStats->setInitTime(timeTaken);
+
+ mStats->setStartTime();
+ if (!asyncMode) {
+ while (!mSawOutputEOS && !mSignalledError) {
+ /* Queue input data */
+ if (!mSawInputEOS) {
+ ssize_t inIdx = AMediaCodec_dequeueInputBuffer(mCodec, kQueueDequeueTimeoutUs);
+ if (inIdx < 0 && inIdx != AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
+ ALOGE("AMediaCodec_dequeueInputBuffer returned invalid index %zd\n", inIdx);
+ mErrorCode = (media_status_t)inIdx;
+ return mErrorCode;
+ } else if (inIdx >= 0) {
+ mStats->addInputTime();
+ onInputAvailable(mCodec, inIdx);
+ }
+ }
+
+ /* Dequeue output data */
+ AMediaCodecBufferInfo info;
+ ssize_t outIdx = AMediaCodec_dequeueOutputBuffer(mCodec, &info, kQueueDequeueTimeoutUs);
+ if (outIdx == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
+ mFormat = AMediaCodec_getOutputFormat(mCodec);
+ const char *s = AMediaFormat_toString(mFormat);
+ ALOGI("Output format: %s\n", s);
+ } else if (outIdx >= 0) {
+ mStats->addOutputTime();
+ onOutputAvailable(mCodec, outIdx, &info);
+ } else if (!(outIdx == AMEDIACODEC_INFO_TRY_AGAIN_LATER ||
+ outIdx == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED)) {
+ ALOGE("AMediaCodec_dequeueOutputBuffer returned invalid index %zd\n", outIdx);
+ mErrorCode = (media_status_t)outIdx;
+ return mErrorCode;
+ }
+ }
+ } else {
+ unique_lock<mutex> lock(mMutex);
+ mDecoderDoneCondition.wait(lock, [this]() { return (mSawOutputEOS || mSignalledError); });
+ }
+ if (mSignalledError) {
+ ALOGE("Received Error while Decoding");
+ return mErrorCode;
+ }
+
+ if (codecName.empty()) {
+ char *decName;
+ AMediaCodec_getName(mCodec, &decName);
+ codecName.assign(decName);
+ AMediaCodec_releaseName(mCodec, decName);
+ }
+ return AMEDIA_OK;
+}
+
+void Decoder::deInitCodec() {
+ if (mFormat) {
+ AMediaFormat_delete(mFormat);
+ mFormat = nullptr;
+ }
+ if (!mCodec) return;
+ int64_t sTime = mStats->getCurTime();
+ AMediaCodec_stop(mCodec);
+ AMediaCodec_delete(mCodec);
+ int64_t eTime = mStats->getCurTime();
+ int64_t timeTaken = mStats->getTimeDiff(sTime, eTime);
+ mStats->setDeInitTime(timeTaken);
+}
+
+void Decoder::dumpStatistics(string inputReference, string componentName, string mode,
+ string statsFile) {
+ int64_t durationUs = mExtractor->getClipDuration();
+ string operation = "decode";
+ mStats->dumpStatistics(operation, inputReference, durationUs, componentName, mode, statsFile);
+}
+
+void Decoder::resetDecoder() {
+ if (mStats) mStats->reset();
+ if (mInputBuffer) mInputBuffer = nullptr;
+ if (!mFrameMetaData.empty()) mFrameMetaData.clear();
+}
diff --git a/media/tests/benchmark/src/native/decoder/Decoder.h b/media/tests/benchmark/src/native/decoder/Decoder.h
new file mode 100644
index 0000000..e619cb4
--- /dev/null
+++ b/media/tests/benchmark/src/native/decoder/Decoder.h
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+
+#ifndef __DECODER_H__
+#define __DECODER_H__
+
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+#include <queue>
+#include <thread>
+
+#include "BenchmarkCommon.h"
+#include "Extractor.h"
+#include "Stats.h"
+
+class Decoder : public CallBackHandle {
+ public:
+ Decoder()
+ : mCodec(nullptr),
+ mFormat(nullptr),
+ mExtractor(nullptr),
+ mNumInputFrame(0),
+ mNumOutputFrame(0),
+ mSawInputEOS(false),
+ mSawOutputEOS(false),
+ mSignalledError(false),
+ mErrorCode(AMEDIA_OK),
+ mInputBuffer(nullptr),
+ mOutFp(nullptr) {
+ mExtractor = new Extractor();
+ }
+
+ virtual ~Decoder() {
+ if (mExtractor) delete mExtractor;
+ }
+
+ Extractor *getExtractor() { return mExtractor; }
+
+ // Decoder related utilities
+ void setupDecoder();
+
+ void deInitCodec();
+
+ void resetDecoder();
+
+ AMediaFormat *getFormat();
+
+ // Async callback APIs
+ void onInputAvailable(AMediaCodec *codec, int32_t index) override;
+
+ void onFormatChanged(AMediaCodec *codec, AMediaFormat *format) override;
+
+ void onError(AMediaCodec *mediaCodec, media_status_t err) override;
+
+ void onOutputAvailable(AMediaCodec *codec, int32_t index,
+ AMediaCodecBufferInfo *bufferInfo) override;
+
+ // Process the frames and give decoded output
+ int32_t decode(uint8_t *inputBuffer, vector<AMediaCodecBufferInfo> &frameInfo,
+ string &codecName, bool asyncMode, FILE *outFp = nullptr);
+
+ void dumpStatistics(string inputReference, string componentName = "", string mode = "",
+ string statsFile = "");
+
+ private:
+ AMediaCodec *mCodec;
+ AMediaFormat *mFormat;
+
+ Extractor *mExtractor;
+
+ int32_t mNumInputFrame;
+ int32_t mNumOutputFrame;
+
+ bool mSawInputEOS;
+ bool mSawOutputEOS;
+ bool mSignalledError;
+ media_status_t mErrorCode;
+
+ int32_t mOffset;
+ uint8_t *mInputBuffer;
+ vector<AMediaCodecBufferInfo> mFrameMetaData;
+ FILE *mOutFp;
+
+ /* Asynchronous locks */
+ mutex mMutex;
+ condition_variable mDecoderDoneCondition;
+};
+
+// Read input samples
+tuple<ssize_t, uint32_t, int64_t> readSampleData(uint8_t *inputBuffer, int32_t &offset,
+ vector<AMediaCodecBufferInfo> &frameSizes,
+ uint8_t *buf, int32_t frameID, size_t bufSize);
+
+#endif // __DECODER_H__
diff --git a/media/tests/benchmark/src/native/encoder/Android.bp b/media/tests/benchmark/src/native/encoder/Android.bp
new file mode 100644
index 0000000..8de7823
--- /dev/null
+++ b/media/tests/benchmark/src/native/encoder/Android.bp
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+cc_library_static {
+ name: "libmediabenchmark_encoder",
+ defaults: [
+ "libmediabenchmark_common-defaults",
+ "libmediabenchmark_soft_sanitize_all-defaults",
+ ],
+
+ srcs: ["Encoder.cpp"],
+
+ static_libs: [
+ "libmediabenchmark_extractor",
+ "libmediabenchmark_decoder",
+ ],
+
+ export_include_dirs: ["."],
+
+ ldflags: ["-Wl,-Bsymbolic"],
+}
+
+cc_library_static {
+ name: "libmediabenchmark_codec2_encoder",
+ defaults: [
+ "libmediabenchmark_codec2_common-defaults",
+ ],
+
+ srcs: ["C2Encoder.cpp"],
+
+ static_libs: [
+ "libmediabenchmark_codec2_common",
+ "libmediabenchmark_codec2_extractor",
+ "libmediabenchmark_codec2_decoder",
+ ],
+
+ export_include_dirs: ["."],
+
+ ldflags: ["-Wl,-Bsymbolic"],
+}
diff --git a/media/tests/benchmark/src/native/encoder/C2Encoder.cpp b/media/tests/benchmark/src/native/encoder/C2Encoder.cpp
new file mode 100644
index 0000000..33429ef
--- /dev/null
+++ b/media/tests/benchmark/src/native/encoder/C2Encoder.cpp
@@ -0,0 +1,264 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2Encoder"
+
+#include "C2Encoder.h"
+
+int32_t C2Encoder::createCodec2Component(string compName, AMediaFormat *format) {
+ ALOGV("In %s", __func__);
+ mListener.reset(new CodecListener(
+ [this](std::list<std::unique_ptr<C2Work>> &workItems) { handleWorkDone(workItems); }));
+ if (!mListener) return -1;
+
+ const char *mime = nullptr;
+ AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime);
+ if (!mime) {
+ ALOGE("Error in AMediaFormat_getString");
+ return -1;
+ }
+ // Configure the plugin with Input properties
+ std::vector<C2Param *> configParam;
+ if (!strncmp(mime, "audio/", 6)) {
+ mIsAudioEncoder = true;
+ int32_t numChannels;
+ if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, &mSampleRate)) {
+ ALOGE("AMEDIAFORMAT_KEY_SAMPLE_RATE not set");
+ return -1;
+ }
+ if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &numChannels)) {
+ ALOGE("AMEDIAFORMAT_KEY_CHANNEL_COUNT not set");
+ return -1;
+ }
+ C2StreamSampleRateInfo::input sampleRateInfo(0u, mSampleRate);
+ C2StreamChannelCountInfo::input channelCountInfo(0u, numChannels);
+ configParam.push_back(&sampleRateInfo);
+ configParam.push_back(&channelCountInfo);
+ } else {
+ mIsAudioEncoder = false;
+ if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &mWidth)) {
+ ALOGE("AMEDIAFORMAT_KEY_WIDTH not set");
+ return -1;
+ }
+ if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &mHeight)) {
+ ALOGE("AMEDIAFORMAT_KEY_HEIGHT not set");
+ return -1;
+ }
+ C2StreamPictureSizeInfo::input inputSize(0u, mWidth, mHeight);
+ configParam.push_back(&inputSize);
+
+ if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_FRAME_RATE, &mFrameRate) ||
+ (mFrameRate <= 0)) {
+ mFrameRate = KDefaultFrameRate;
+ }
+ }
+
+ int64_t sTime = mStats->getCurTime();
+ mComponent = mClient->CreateComponentByName(compName.c_str(), mListener, &mClient);
+ if (mComponent == nullptr) {
+ ALOGE("Create component failed for %s", compName.c_str());
+ return -1;
+ }
+ std::vector<std::unique_ptr<C2SettingResult>> failures;
+ int32_t status = mComponent->config(configParam, C2_DONT_BLOCK, &failures);
+ if (failures.size() != 0) {
+ ALOGE("Invalid Configuration");
+ return -1;
+ }
+
+ status |= mComponent->start();
+ int64_t eTime = mStats->getCurTime();
+ int64_t timeTaken = mStats->getTimeDiff(sTime, eTime);
+ mStats->setInitTime(timeTaken);
+ return status;
+}
+
+// In encoder components, fetch the size of input buffer allocated
+int32_t C2Encoder::getInputMaxBufSize() {
+ int32_t bitStreamInfo[1] = {0};
+ std::vector<std::unique_ptr<C2Param>> inParams;
+ c2_status_t status = mComponent->query({}, {C2StreamMaxBufferSizeInfo::input::PARAM_TYPE},
+ C2_DONT_BLOCK, &inParams);
+ if (status != C2_OK && inParams.size() == 0) {
+ ALOGE("Query MaxBufferSizeInfo failed => %d", status);
+ return status;
+ } else {
+ size_t offset = sizeof(C2Param);
+ for (size_t i = 0; i < inParams.size(); ++i) {
+ C2Param *param = inParams[i].get();
+ bitStreamInfo[i] = *(int32_t *)((uint8_t *)param + offset);
+ }
+ }
+ mInputMaxBufSize = bitStreamInfo[0];
+ if (mInputMaxBufSize < 0) {
+ ALOGE("Invalid mInputMaxBufSize %d\n", mInputMaxBufSize);
+ return -1;
+ }
+ return status;
+}
+
+int32_t C2Encoder::encodeFrames(ifstream &eleStream, size_t inputBufferSize) {
+ ALOGV("In %s", __func__);
+ int32_t frameSize = 0;
+ if (!mIsAudioEncoder) {
+ frameSize = mWidth * mHeight * 3 / 2;
+ } else {
+ frameSize = DEFAULT_AUDIO_FRAME_SIZE;
+ if (getInputMaxBufSize() != 0) return -1;
+ if (frameSize > mInputMaxBufSize) {
+ frameSize = mInputMaxBufSize;
+ }
+ }
+ int32_t numFrames = (inputBufferSize + frameSize - 1) / frameSize;
+ // Temporary buffer to read data from the input file
+ char *data = (char *)malloc(frameSize);
+ if (!data) {
+ ALOGE("Insufficient memory to read from input file");
+ return -1;
+ }
+
+ typedef std::unique_lock<std::mutex> ULock;
+ uint64_t presentationTimeUs = 0;
+ size_t offset = 0;
+ c2_status_t status = C2_OK;
+
+ mStats->setStartTime();
+ while (numFrames > 0) {
+ std::unique_ptr<C2Work> work;
+ // Prepare C2Work
+ {
+ ULock l(mQueueLock);
+ if (mWorkQueue.empty()) mQueueCondition.wait_for(l, MAX_RETRY * TIME_OUT);
+ if (!mWorkQueue.empty()) {
+ mStats->addInputTime();
+ work.swap(mWorkQueue.front());
+ mWorkQueue.pop_front();
+ } else {
+ cout << "Wait for generating C2Work exceeded timeout" << endl;
+ return -1;
+ }
+ }
+
+ if (mIsAudioEncoder) {
+ presentationTimeUs = mNumInputFrame * frameSize * (1000000 / mSampleRate);
+ } else {
+ presentationTimeUs = mNumInputFrame * (1000000 / mFrameRate);
+ }
+ uint32_t flags = 0;
+ if (numFrames == 1) flags |= C2FrameData::FLAG_END_OF_STREAM;
+
+ work->input.flags = (C2FrameData::flags_t)flags;
+ work->input.ordinal.timestamp = presentationTimeUs;
+ work->input.ordinal.frameIndex = mNumInputFrame;
+ work->input.buffers.clear();
+
+ if (inputBufferSize - offset < frameSize) {
+ frameSize = inputBufferSize - offset;
+ }
+ eleStream.read(data, frameSize);
+ if (eleStream.gcount() != frameSize) {
+ ALOGE("read() from file failed. Incorrect bytes read");
+ return -1;
+ }
+ offset += frameSize;
+
+ if (frameSize) {
+ if (mIsAudioEncoder) {
+ std::shared_ptr<C2LinearBlock> block;
+ status = mLinearPool->fetchLinearBlock(
+ frameSize, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, &block);
+ if (status != C2_OK || !block) {
+ cout << "fetchLinearBlock failed : " << status << endl;
+ return status;
+ }
+ C2WriteView view = block->map().get();
+ if (view.error() != C2_OK) {
+ cout << "C2LinearBlock::map() failed : " << view.error() << endl;
+ return view.error();
+ }
+
+ memcpy(view.base(), data, frameSize);
+ work->input.buffers.emplace_back(new LinearBuffer(block));
+ } else {
+ std::shared_ptr<C2GraphicBlock> block;
+ status = mGraphicPool->fetchGraphicBlock(
+ mWidth, mHeight, HAL_PIXEL_FORMAT_YV12,
+ {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, &block);
+ if (status != C2_OK || !block) {
+ cout << "fetchGraphicBlock failed : " << status << endl;
+ return status;
+ }
+ C2GraphicView view = block->map().get();
+ if (view.error() != C2_OK) {
+ cout << "C2GraphicBlock::map() failed : " << view.error() << endl;
+ return view.error();
+ }
+
+ uint8_t *pY = view.data()[C2PlanarLayout::PLANE_Y];
+ uint8_t *pU = view.data()[C2PlanarLayout::PLANE_U];
+ uint8_t *pV = view.data()[C2PlanarLayout::PLANE_V];
+ memcpy(pY, data, mWidth * mHeight);
+ memcpy(pU, data + mWidth * mHeight, (mWidth * mHeight >> 2));
+ memcpy(pV, data + (mWidth * mHeight * 5 >> 2), mWidth * mHeight >> 2);
+ work->input.buffers.emplace_back(new GraphicBuffer(block));
+ }
+ mStats->addFrameSize(frameSize);
+ }
+
+ work->worklets.clear();
+ work->worklets.emplace_back(new C2Worklet);
+
+ std::list<std::unique_ptr<C2Work>> items;
+ items.push_back(std::move(work));
+ // queue() invokes process() function of C2 Plugin.
+ status = mComponent->queue(&items);
+ if (status != C2_OK) {
+ ALOGE("queue failed");
+ return status;
+ }
+ ALOGV("Frame #%d size = %d queued", mNumInputFrame, frameSize);
+ numFrames--;
+ mNumInputFrame++;
+ }
+ free(data);
+ return status;
+}
+
+void C2Encoder::deInitCodec() {
+ ALOGV("In %s", __func__);
+ if (!mComponent) return;
+
+ int64_t sTime = mStats->getCurTime();
+ mComponent->stop();
+ mComponent->release();
+ mComponent = nullptr;
+ int64_t eTime = mStats->getCurTime();
+ int64_t timeTaken = mStats->getTimeDiff(sTime, eTime);
+ mStats->setDeInitTime(timeTaken);
+}
+
+void C2Encoder::dumpStatistics(string inputReference, int64_t durationUs) {
+ string operation = "c2encode";
+ mStats->dumpStatistics(operation, inputReference, durationUs);
+}
+
+void C2Encoder::resetEncoder() {
+ mIsAudioEncoder = false;
+ mNumInputFrame = 0;
+ mEos = false;
+ if (mStats) mStats->reset();
+}
diff --git a/media/tests/benchmark/src/native/encoder/C2Encoder.h b/media/tests/benchmark/src/native/encoder/C2Encoder.h
new file mode 100644
index 0000000..a4ca097
--- /dev/null
+++ b/media/tests/benchmark/src/native/encoder/C2Encoder.h
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+#ifndef __C2_ENCODER_H__
+#define __C2_ENCODER_H__
+
+#include <stdio.h>
+#include <algorithm>
+#include <fstream>
+
+#include "BenchmarkC2Common.h"
+
+#define DEFAULT_AUDIO_FRAME_SIZE 4096
+
+constexpr int32_t KDefaultFrameRate = 25;
+
+class C2Encoder : public BenchmarkC2Common {
+ public:
+ C2Encoder()
+ : mIsAudioEncoder(false),
+ mWidth(0),
+ mHeight(0),
+ mNumInputFrame(0),
+ mComponent(nullptr) {}
+
+ int32_t createCodec2Component(string codecName, AMediaFormat *format);
+
+ int32_t encodeFrames(ifstream &eleStream, size_t inputBufferSize);
+
+ int32_t getInputMaxBufSize();
+
+ void deInitCodec();
+
+ void dumpStatistics(string inputReference, int64_t durationUs);
+
+ void resetEncoder();
+
+ private:
+ bool mIsAudioEncoder;
+
+ int32_t mWidth;
+ int32_t mHeight;
+ int32_t mFrameRate;
+ int32_t mSampleRate;
+
+ int32_t mNumInputFrame;
+ int32_t mInputMaxBufSize;
+
+ std::shared_ptr<android::Codec2Client::Listener> mListener;
+ std::shared_ptr<android::Codec2Client::Component> mComponent;
+};
+
+#endif // __C2_ENCODER_H__
diff --git a/media/tests/benchmark/src/native/encoder/Encoder.cpp b/media/tests/benchmark/src/native/encoder/Encoder.cpp
new file mode 100644
index 0000000..26fb1b9
--- /dev/null
+++ b/media/tests/benchmark/src/native/encoder/Encoder.cpp
@@ -0,0 +1,304 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "encoder"
+
+#include <fstream>
+
+#include "Encoder.h"
+
+void Encoder::onInputAvailable(AMediaCodec *mediaCodec, int32_t bufIdx) {
+ ALOGV("In %s", __func__);
+ if (mediaCodec == mCodec && mediaCodec) {
+ if (mSawInputEOS || bufIdx < 0) return;
+ if (mSignalledError) {
+ CallBackHandle::mSawError = true;
+ mEncoderDoneCondition.notify_one();
+ return;
+ }
+
+ size_t bufSize = 0;
+ char *buf = (char *)AMediaCodec_getInputBuffer(mCodec, bufIdx, &bufSize);
+ if (!buf) {
+ mErrorCode = AMEDIA_ERROR_IO;
+ mSignalledError = true;
+ mEncoderDoneCondition.notify_one();
+ return;
+ }
+
+ if (mInputBufferSize < mOffset) {
+ ALOGE("Out of bound access of input buffer\n");
+ mErrorCode = AMEDIA_ERROR_MALFORMED;
+ mSignalledError = true;
+ mEncoderDoneCondition.notify_one();
+ return;
+ }
+ size_t bytesToRead = mParams.frameSize;
+ if (mInputBufferSize - mOffset < mParams.frameSize) {
+ bytesToRead = mInputBufferSize - mOffset;
+ }
+ //b/148655275 - Update Frame size, as Format value may not be valid
+ if (bufSize < bytesToRead) {
+ if(mNumInputFrame == 0) {
+ mParams.frameSize = bufSize;
+ bytesToRead = bufSize;
+ mParams.numFrames = (mInputBufferSize + mParams.frameSize - 1) / mParams.frameSize;
+ } else {
+ ALOGE("bytes to read %zu bufSize %zu \n", bytesToRead, bufSize);
+ mErrorCode = AMEDIA_ERROR_MALFORMED;
+ mSignalledError = true;
+ mEncoderDoneCondition.notify_one();
+ return;
+ }
+ }
+ if (bytesToRead < mParams.frameSize && mNumInputFrame < mParams.numFrames - 1) {
+ ALOGE("Partial frame at frameID %d bytesToRead %zu frameSize %d total numFrames %d\n",
+ mNumInputFrame, bytesToRead, mParams.frameSize, mParams.numFrames);
+ mErrorCode = AMEDIA_ERROR_MALFORMED;
+ mSignalledError = true;
+ mEncoderDoneCondition.notify_one();
+ return;
+ }
+ mEleStream->read(buf, bytesToRead);
+ size_t bytesgcount = mEleStream->gcount();
+ if (bytesgcount != bytesToRead) {
+ ALOGE("bytes to read %zu actual bytes read %zu \n", bytesToRead, bytesgcount);
+ mErrorCode = AMEDIA_ERROR_MALFORMED;
+ mSignalledError = true;
+ mEncoderDoneCondition.notify_one();
+ return;
+ }
+
+ uint32_t flag = 0;
+ if (mNumInputFrame == mParams.numFrames - 1 || bytesToRead == 0) {
+ ALOGD("Sending EOS on input Last frame\n");
+ flag |= AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM;
+ }
+
+ uint64_t presentationTimeUs;
+ if (!strncmp(mMime, "video/", 6)) {
+ presentationTimeUs = mNumInputFrame * (1000000 / mParams.frameRate);
+ } else {
+ presentationTimeUs =
+ (uint64_t)mNumInputFrame * mParams.frameSize * 1000000 / mParams.sampleRate;
+ }
+
+ if (flag == AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) mSawInputEOS = true;
+ ALOGV("%s bytesRead : %zd presentationTimeUs : %" PRIu64 " mSawInputEOS : %s", __FUNCTION__,
+ bytesToRead, presentationTimeUs, mSawInputEOS ? "TRUE" : "FALSE");
+
+ media_status_t status = AMediaCodec_queueInputBuffer(mCodec, bufIdx, 0 /* offset */,
+ bytesToRead, presentationTimeUs, flag);
+ if (AMEDIA_OK != status) {
+ mErrorCode = status;
+ mSignalledError = true;
+ mEncoderDoneCondition.notify_one();
+ return;
+ }
+ mNumInputFrame++;
+ mOffset += bytesToRead;
+ }
+}
+
+void Encoder::onOutputAvailable(AMediaCodec *mediaCodec, int32_t bufIdx,
+ AMediaCodecBufferInfo *bufferInfo) {
+ ALOGV("In %s", __func__);
+ if (mediaCodec == mCodec && mediaCodec) {
+ if (mSawOutputEOS || bufIdx < 0) return;
+ if (mSignalledError) {
+ CallBackHandle::mSawError = true;
+ mEncoderDoneCondition.notify_one();
+ return;
+ }
+
+ mStats->addFrameSize(bufferInfo->size);
+ AMediaCodec_releaseOutputBuffer(mCodec, bufIdx, false);
+ mSawOutputEOS = (0 != (bufferInfo->flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM));
+ mNumOutputFrame++;
+ ALOGV("%s index : %d mSawOutputEOS : %s count : %u", __FUNCTION__, bufIdx,
+ mSawOutputEOS ? "TRUE" : "FALSE", mNumOutputFrame);
+ if (mSawOutputEOS) {
+ CallBackHandle::mIsDone = true;
+ mEncoderDoneCondition.notify_one();
+ }
+ }
+}
+
+void Encoder::onFormatChanged(AMediaCodec *mediaCodec, AMediaFormat *format) {
+ ALOGV("In %s", __func__);
+ if (mediaCodec == mCodec && mediaCodec) {
+ ALOGV("%s { %s }", __FUNCTION__, AMediaFormat_toString(format));
+ mFormat = format;
+ }
+}
+
+void Encoder::onError(AMediaCodec *mediaCodec, media_status_t err) {
+ ALOGV("In %s", __func__);
+ if (mediaCodec == mCodec && mediaCodec) {
+ ALOGE("Received Error %d", err);
+ mErrorCode = err;
+ mSignalledError = true;
+ mEncoderDoneCondition.notify_one();
+ }
+}
+
+void Encoder::setupEncoder() {
+ if (!mFormat) mFormat = AMediaFormat_new();
+}
+
+void Encoder::deInitCodec() {
+ if (mFormat) {
+ AMediaFormat_delete(mFormat);
+ mFormat = nullptr;
+ }
+ if (!mCodec) return;
+ int64_t sTime = mStats->getCurTime();
+ AMediaCodec_stop(mCodec);
+ AMediaCodec_delete(mCodec);
+ int64_t eTime = mStats->getCurTime();
+ int64_t timeTaken = mStats->getTimeDiff(sTime, eTime);
+ mStats->setDeInitTime(timeTaken);
+}
+
+void Encoder::resetEncoder() {
+ if (mStats) mStats->reset();
+ if (mEleStream) mEleStream = nullptr;
+ if (mMime) mMime = nullptr;
+ mInputBufferSize = 0;
+ memset(&mParams, 0, sizeof mParams);
+}
+
+void Encoder::dumpStatistics(string inputReference, int64_t durationUs, string componentName,
+ string mode, string statsFile) {
+ string operation = "encode";
+ mStats->dumpStatistics(operation, inputReference, durationUs, componentName, mode, statsFile);
+}
+
+int32_t Encoder::encode(string &codecName, ifstream &eleStream, size_t eleSize, bool asyncMode,
+ encParameter encParams, char *mime) {
+ ALOGV("In %s", __func__);
+ mEleStream = &eleStream;
+ mInputBufferSize = eleSize;
+ mParams = encParams;
+ mOffset = 0;
+ mMime = mime;
+ AMediaFormat_setString(mFormat, AMEDIAFORMAT_KEY_MIME, mMime);
+
+ // Set Format
+ if (!strncmp(mMime, "video/", 6)) {
+ AMediaFormat_setInt32(mFormat, AMEDIAFORMAT_KEY_WIDTH, mParams.width);
+ AMediaFormat_setInt32(mFormat, AMEDIAFORMAT_KEY_HEIGHT, mParams.height);
+ AMediaFormat_setInt32(mFormat, AMEDIAFORMAT_KEY_FRAME_RATE, mParams.frameRate);
+ AMediaFormat_setInt32(mFormat, AMEDIAFORMAT_KEY_BIT_RATE, mParams.bitrate);
+ AMediaFormat_setInt32(mFormat, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, 1);
+ if (mParams.profile && mParams.level) {
+ AMediaFormat_setInt32(mFormat, AMEDIAFORMAT_KEY_PROFILE, mParams.profile);
+ AMediaFormat_setInt32(mFormat, AMEDIAFORMAT_KEY_LEVEL, mParams.level);
+ }
+ AMediaFormat_setInt32(mFormat, AMEDIAFORMAT_KEY_COLOR_FORMAT, mParams.colorFormat);
+ } else {
+ AMediaFormat_setInt32(mFormat, AMEDIAFORMAT_KEY_SAMPLE_RATE, mParams.sampleRate);
+ AMediaFormat_setInt32(mFormat, AMEDIAFORMAT_KEY_CHANNEL_COUNT, mParams.numChannels);
+ AMediaFormat_setInt32(mFormat, AMEDIAFORMAT_KEY_BIT_RATE, mParams.bitrate);
+ }
+ const char *s = AMediaFormat_toString(mFormat);
+ ALOGI("Input format: %s\n", s);
+
+ int64_t sTime = mStats->getCurTime();
+ mCodec = createMediaCodec(mFormat, mMime, codecName, true /*isEncoder*/);
+ if (!mCodec) return AMEDIA_ERROR_INVALID_OBJECT;
+ int64_t eTime = mStats->getCurTime();
+ int64_t timeTaken = mStats->getTimeDiff(sTime, eTime);
+
+ if (!strncmp(mMime, "video/", 6)) {
+ mParams.frameSize = mParams.width * mParams.height * 3 / 2;
+ } else {
+ mParams.frameSize = kDefaultAudioEncodeFrameSize;
+ // Get mInputMaxBufSize
+ AMediaFormat *inputFormat = AMediaCodec_getInputFormat(mCodec);
+ AMediaFormat_getInt32(inputFormat, AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, &mParams.maxFrameSize);
+ if (mParams.maxFrameSize < 0) {
+ mParams.maxFrameSize = kDefaultAudioEncodeFrameSize;
+ }
+ if (mParams.frameSize > mParams.maxFrameSize) {
+ mParams.frameSize = mParams.maxFrameSize;
+ }
+ }
+ mParams.numFrames = (mInputBufferSize + mParams.frameSize - 1) / mParams.frameSize;
+
+ sTime = mStats->getCurTime();
+ if (asyncMode) {
+ AMediaCodecOnAsyncNotifyCallback aCB = {OnInputAvailableCB, OnOutputAvailableCB,
+ OnFormatChangedCB, OnErrorCB};
+ AMediaCodec_setAsyncNotifyCallback(mCodec, aCB, this);
+ mIOThread = thread(&CallBackHandle::ioThread, this);
+ }
+ AMediaCodec_start(mCodec);
+ eTime = mStats->getCurTime();
+ timeTaken += mStats->getTimeDiff(sTime, eTime);
+ mStats->setInitTime(timeTaken);
+
+ mStats->setStartTime();
+ if (!asyncMode) {
+ while (!mSawOutputEOS && !mSignalledError) {
+ // Queue input data
+ if (!mSawInputEOS) {
+ ssize_t inIdx = AMediaCodec_dequeueInputBuffer(mCodec, kQueueDequeueTimeoutUs);
+ if (inIdx < 0 && inIdx != AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
+ ALOGE("AMediaCodec_dequeueInputBuffer returned invalid index %zd\n", inIdx);
+ mErrorCode = (media_status_t)inIdx;
+ return mErrorCode;
+ } else if (inIdx >= 0) {
+ mStats->addInputTime();
+ onInputAvailable(mCodec, inIdx);
+ }
+ }
+
+ // Dequeue output data
+ AMediaCodecBufferInfo info;
+ ssize_t outIdx = AMediaCodec_dequeueOutputBuffer(mCodec, &info, kQueueDequeueTimeoutUs);
+ if (outIdx == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
+ mFormat = AMediaCodec_getOutputFormat(mCodec);
+ const char *s = AMediaFormat_toString(mFormat);
+ ALOGI("Output format: %s\n", s);
+ } else if (outIdx >= 0) {
+ mStats->addOutputTime();
+ onOutputAvailable(mCodec, outIdx, &info);
+ } else if (!(outIdx == AMEDIACODEC_INFO_TRY_AGAIN_LATER ||
+ outIdx == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED)) {
+ ALOGE("AMediaCodec_dequeueOutputBuffer returned invalid index %zd\n", outIdx);
+ mErrorCode = (media_status_t)outIdx;
+ return mErrorCode;
+ }
+ }
+ } else {
+ unique_lock<mutex> lock(mMutex);
+ mEncoderDoneCondition.wait(lock, [this]() { return (mSawOutputEOS || mSignalledError); });
+ }
+ if (mSignalledError) {
+ ALOGE("Received Error while Encoding");
+ return mErrorCode;
+ }
+
+ if (codecName.empty()) {
+ char *encName;
+ AMediaCodec_getName(mCodec, &encName);
+ codecName.assign(encName);
+ AMediaCodec_releaseName(mCodec, encName);
+ }
+ return AMEDIA_OK;
+}
diff --git a/media/tests/benchmark/src/native/encoder/Encoder.h b/media/tests/benchmark/src/native/encoder/Encoder.h
new file mode 100644
index 0000000..5ad142b
--- /dev/null
+++ b/media/tests/benchmark/src/native/encoder/Encoder.h
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+#ifndef __ENCODER_H__
+#define __ENCODER_H__
+
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+#include <queue>
+#include <thread>
+
+#include "media/NdkImage.h"
+#include "BenchmarkCommon.h"
+#include "Stats.h"
+
+
+struct encParameter {
+ int32_t bitrate = -1;
+ int32_t numFrames = -1;
+ int32_t frameSize = -1;
+ int32_t sampleRate = 0;
+ int32_t numChannels = 0;
+ int32_t maxFrameSize = -1;
+ int32_t width = 0;
+ int32_t height = 0;
+ int32_t frameRate = -1;
+ int32_t profile = 0;
+ int32_t level = 0;
+ int32_t colorFormat = AIMAGE_FORMAT_YUV_420_888;
+};
+
+class Encoder : public CallBackHandle {
+ public:
+ Encoder()
+ : mCodec(nullptr),
+ mFormat(nullptr),
+ mNumInputFrame(0),
+ mNumOutputFrame(0),
+ mSawInputEOS(false),
+ mSawOutputEOS(false),
+ mSignalledError(false),
+ mErrorCode(AMEDIA_OK) {}
+
+ virtual ~Encoder() {}
+
+ // Encoder related utilities
+ void setupEncoder();
+
+ void deInitCodec();
+
+ void resetEncoder();
+
+ // Async callback APIs
+ void onInputAvailable(AMediaCodec *codec, int32_t index) override;
+
+ void onFormatChanged(AMediaCodec *codec, AMediaFormat *format) override;
+
+ void onError(AMediaCodec *mediaCodec, media_status_t err) override;
+
+ void onOutputAvailable(AMediaCodec *codec, int32_t index,
+ AMediaCodecBufferInfo *bufferInfo) override;
+
+ // Process the frames and give encoded output
+ int32_t encode(std::string &codecName, std::ifstream &eleStream, size_t eleSize, bool asyncMode,
+ encParameter encParams, char *mime);
+
+ void dumpStatistics(string inputReference, int64_t durationUs, string codecName = "",
+ string mode = "", string statsFile = "");
+
+ private:
+ AMediaCodec *mCodec;
+ AMediaFormat *mFormat;
+
+ int32_t mNumInputFrame;
+ int32_t mNumOutputFrame;
+ bool mSawInputEOS;
+ bool mSawOutputEOS;
+ bool mSignalledError;
+ media_status_t mErrorCode;
+
+ char *mMime;
+ int32_t mOffset;
+ std::ifstream *mEleStream;
+ size_t mInputBufferSize;
+ encParameter mParams;
+
+ // Asynchronous locks
+ std::mutex mMutex;
+ std::condition_variable mEncoderDoneCondition;
+};
+#endif // __ENCODER_H__
diff --git a/media/tests/benchmark/src/native/extractor/Android.bp b/media/tests/benchmark/src/native/extractor/Android.bp
new file mode 100644
index 0000000..7ed9476
--- /dev/null
+++ b/media/tests/benchmark/src/native/extractor/Android.bp
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+cc_library_static {
+ name: "libmediabenchmark_extractor",
+ defaults: [
+ "libmediabenchmark_common-defaults",
+ "libmediabenchmark_soft_sanitize_all-defaults",
+ ],
+
+ srcs: ["Extractor.cpp"],
+
+ export_include_dirs: ["."],
+
+ ldflags: ["-Wl,-Bsymbolic"]
+}
+
+cc_library_static {
+ name: "libmediabenchmark_codec2_extractor",
+ defaults: [
+ "libmediabenchmark_codec2_common-defaults",
+ ],
+
+ srcs: ["Extractor.cpp"],
+
+ static_libs: [
+ "libmediabenchmark_codec2_common",
+ ],
+
+ export_include_dirs: ["."],
+
+ ldflags: ["-Wl,-Bsymbolic"]
+}
diff --git a/media/tests/benchmark/src/native/extractor/Extractor.cpp b/media/tests/benchmark/src/native/extractor/Extractor.cpp
new file mode 100644
index 0000000..f0bb3b9
--- /dev/null
+++ b/media/tests/benchmark/src/native/extractor/Extractor.cpp
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "extractor"
+
+#include <iostream>
+
+#include "Extractor.h"
+
+int32_t Extractor::initExtractor(int32_t fd, size_t fileSize) {
+ mStats = new Stats();
+
+ mFrameBuf = (uint8_t *)calloc(kMaxBufferSize, sizeof(uint8_t));
+ if (!mFrameBuf) return -1;
+
+ int64_t sTime = mStats->getCurTime();
+
+ mExtractor = AMediaExtractor_new();
+ if (!mExtractor) return AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE;
+ media_status_t status = AMediaExtractor_setDataSourceFd(mExtractor, fd, 0, fileSize);
+ if (status != AMEDIA_OK) return status;
+
+ int64_t eTime = mStats->getCurTime();
+ int64_t timeTaken = mStats->getTimeDiff(sTime, eTime);
+ mStats->setInitTime(timeTaken);
+
+ return AMediaExtractor_getTrackCount(mExtractor);
+}
+
+void *Extractor::getCSDSample(AMediaCodecBufferInfo &frameInfo, int32_t csdIndex) {
+ char csdName[kMaxCSDStrlen];
+ void *csdBuffer = nullptr;
+ frameInfo.presentationTimeUs = 0;
+ frameInfo.flags = AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG;
+ snprintf(csdName, sizeof(csdName), "csd-%d", csdIndex);
+
+ size_t size;
+ bool csdFound = AMediaFormat_getBuffer(mFormat, csdName, &csdBuffer, &size);
+ if (!csdFound) return nullptr;
+ frameInfo.size = (int32_t)size;
+ mStats->addFrameSize(frameInfo.size);
+
+ return csdBuffer;
+}
+
+int32_t Extractor::getFrameSample(AMediaCodecBufferInfo &frameInfo) {
+ int32_t size = AMediaExtractor_readSampleData(mExtractor, mFrameBuf, kMaxBufferSize);
+ if (size < 0) return -1;
+
+ frameInfo.flags = AMediaExtractor_getSampleFlags(mExtractor);
+ frameInfo.size = size;
+ mStats->addFrameSize(frameInfo.size);
+ frameInfo.presentationTimeUs = AMediaExtractor_getSampleTime(mExtractor);
+ AMediaExtractor_advance(mExtractor);
+
+ return 0;
+}
+
+int32_t Extractor::setupTrackFormat(int32_t trackId) {
+ AMediaExtractor_selectTrack(mExtractor, trackId);
+ mFormat = AMediaExtractor_getTrackFormat(mExtractor, trackId);
+ if (!mFormat) return AMEDIA_ERROR_INVALID_OBJECT;
+
+ bool durationFound = AMediaFormat_getInt64(mFormat, AMEDIAFORMAT_KEY_DURATION, &mDurationUs);
+ if (!durationFound) return AMEDIA_ERROR_INVALID_OBJECT;
+
+ return AMEDIA_OK;
+}
+
+int32_t Extractor::extract(int32_t trackId) {
+ int32_t status = setupTrackFormat(trackId);
+ if (status != AMEDIA_OK) return status;
+
+ int32_t idx = 0;
+ AMediaCodecBufferInfo frameInfo;
+ while (1) {
+ memset(&frameInfo, 0, sizeof(AMediaCodecBufferInfo));
+ void *csdBuffer = getCSDSample(frameInfo, idx);
+ if (!csdBuffer || !frameInfo.size) break;
+ idx++;
+ }
+
+ mStats->setStartTime();
+ while (1) {
+ int32_t status = getFrameSample(frameInfo);
+ if (status || !frameInfo.size) break;
+ mStats->addOutputTime();
+ }
+
+ if (mFormat) {
+ AMediaFormat_delete(mFormat);
+ mFormat = nullptr;
+ }
+
+ AMediaExtractor_unselectTrack(mExtractor, trackId);
+
+ return AMEDIA_OK;
+}
+
+void Extractor::dumpStatistics(string inputReference, string componentName, string statsFile) {
+ string operation = "extract";
+ mStats->dumpStatistics(operation, inputReference, mDurationUs, componentName, "", statsFile);
+}
+
+void Extractor::deInitExtractor() {
+ if (mFrameBuf) {
+ free(mFrameBuf);
+ mFrameBuf = nullptr;
+ }
+
+ int64_t sTime = mStats->getCurTime();
+ if (mExtractor) {
+ // TODO: (b/140128505) Multiple calls result in DoS.
+ // Uncomment call to AMediaExtractor_delete() once this is resolved
+ // AMediaExtractor_delete(mExtractor);
+ mExtractor = nullptr;
+ }
+ int64_t eTime = mStats->getCurTime();
+ int64_t deInitTime = mStats->getTimeDiff(sTime, eTime);
+ mStats->setDeInitTime(deInitTime);
+}
diff --git a/media/tests/benchmark/src/native/extractor/Extractor.h b/media/tests/benchmark/src/native/extractor/Extractor.h
new file mode 100644
index 0000000..1694fc7
--- /dev/null
+++ b/media/tests/benchmark/src/native/extractor/Extractor.h
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+#ifndef __EXTRACTOR_H__
+#define __EXTRACTOR_H__
+
+#include <media/NdkMediaExtractor.h>
+
+#include "BenchmarkCommon.h"
+#include "Stats.h"
+
+class Extractor {
+ public:
+ Extractor()
+ : mFormat(nullptr),
+ mExtractor(nullptr),
+ mStats(nullptr),
+ mFrameBuf{nullptr},
+ mDurationUs{0} {}
+
+ ~Extractor() {
+ if (mStats) delete mStats;
+ }
+
+ int32_t initExtractor(int32_t fd, size_t fileSize);
+
+ int32_t setupTrackFormat(int32_t trackId);
+
+ void *getCSDSample(AMediaCodecBufferInfo &frameInfo, int32_t csdIndex);
+
+ int32_t getFrameSample(AMediaCodecBufferInfo &frameInfo);
+
+ int32_t extract(int32_t trackId);
+
+ void dumpStatistics(string inputReference, string componentName = "", string statsFile = "");
+
+ void deInitExtractor();
+
+ AMediaFormat *getFormat() { return mFormat; }
+
+ uint8_t *getFrameBuf() { return mFrameBuf; }
+
+ int64_t getClipDuration() { return mDurationUs; }
+
+ private:
+ AMediaFormat *mFormat;
+ AMediaExtractor *mExtractor;
+ Stats *mStats;
+ uint8_t *mFrameBuf;
+ int64_t mDurationUs;
+};
+
+#endif // __EXTRACTOR_H__
\ No newline at end of file
diff --git a/media/tests/benchmark/src/native/muxer/Android.bp b/media/tests/benchmark/src/native/muxer/Android.bp
new file mode 100644
index 0000000..f669d4a
--- /dev/null
+++ b/media/tests/benchmark/src/native/muxer/Android.bp
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+cc_library_static {
+ name: "libmediabenchmark_muxer",
+ defaults: [
+ "libmediabenchmark_common-defaults",
+ "libmediabenchmark_soft_sanitize_all-defaults",
+ ],
+
+ srcs: ["Muxer.cpp"],
+
+ static_libs: ["libmediabenchmark_extractor"],
+
+ export_include_dirs: ["."],
+
+ ldflags: ["-Wl,-Bsymbolic"]
+}
diff --git a/media/tests/benchmark/src/native/muxer/Muxer.cpp b/media/tests/benchmark/src/native/muxer/Muxer.cpp
new file mode 100644
index 0000000..3e150ca
--- /dev/null
+++ b/media/tests/benchmark/src/native/muxer/Muxer.cpp
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "muxer"
+
+#include <fstream>
+#include <iostream>
+
+#include "Muxer.h"
+
+int32_t Muxer::initMuxer(int32_t fd, MUXER_OUTPUT_T outputFormat) {
+ if (!mFormat) mFormat = mExtractor->getFormat();
+ if (!mStats) mStats = new Stats();
+
+ int64_t sTime = mStats->getCurTime();
+ mMuxer = AMediaMuxer_new(fd, (OutputFormat)outputFormat);
+ if (!mMuxer) {
+ ALOGV("Unable to create muxer");
+ return AMEDIA_ERROR_INVALID_OBJECT;
+ }
+ /*
+ * AMediaMuxer_addTrack returns the index of the new track or a negative value
+ * in case of failure, which can be interpreted as a media_status_t.
+ */
+ ssize_t index = AMediaMuxer_addTrack(mMuxer, mFormat);
+ if (index < 0) {
+ ALOGV("Format not supported");
+ return index;
+ }
+ AMediaMuxer_start(mMuxer);
+ int64_t eTime = mStats->getCurTime();
+ int64_t timeTaken = mStats->getTimeDiff(sTime, eTime);
+ mStats->setInitTime(timeTaken);
+ return AMEDIA_OK;
+}
+
+void Muxer::deInitMuxer() {
+ if (mFormat) {
+ AMediaFormat_delete(mFormat);
+ mFormat = nullptr;
+ }
+ if (!mMuxer) return;
+ int64_t sTime = mStats->getCurTime();
+ AMediaMuxer_stop(mMuxer);
+ AMediaMuxer_delete(mMuxer);
+ int64_t eTime = mStats->getCurTime();
+ int64_t timeTaken = mStats->getTimeDiff(sTime, eTime);
+ mStats->setDeInitTime(timeTaken);
+}
+
+void Muxer::resetMuxer() {
+ if (mStats) mStats->reset();
+}
+
+void Muxer::dumpStatistics(string inputReference, string componentName, string statsFile) {
+ string operation = "mux";
+ mStats->dumpStatistics(operation, inputReference, mExtractor->getClipDuration(), componentName,
+ "", statsFile);
+}
+
+int32_t Muxer::mux(uint8_t *inputBuffer, vector<AMediaCodecBufferInfo> &frameInfos) {
+ // Mux frame data
+ size_t frameIdx = 0;
+ mStats->setStartTime();
+ while (frameIdx < frameInfos.size()) {
+ AMediaCodecBufferInfo info = frameInfos.at(frameIdx);
+ media_status_t status = AMediaMuxer_writeSampleData(mMuxer, 0, inputBuffer, &info);
+ if (status != 0) {
+ ALOGE("Error in AMediaMuxer_writeSampleData");
+ return status;
+ }
+ mStats->addOutputTime();
+ mStats->addFrameSize(info.size);
+ frameIdx++;
+ }
+ return AMEDIA_OK;
+}
diff --git a/media/tests/benchmark/src/native/muxer/Muxer.h b/media/tests/benchmark/src/native/muxer/Muxer.h
new file mode 100644
index 0000000..860fdaf
--- /dev/null
+++ b/media/tests/benchmark/src/native/muxer/Muxer.h
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+#ifndef __MUXER_H__
+#define __MUXER_H__
+
+#include <media/NdkMediaMuxer.h>
+
+#include "BenchmarkCommon.h"
+#include "Stats.h"
+#include "Extractor.h"
+
+typedef enum {
+ MUXER_OUTPUT_FORMAT_MPEG_4 = 0,
+ MUXER_OUTPUT_FORMAT_WEBM = 1,
+ MUXER_OUTPUT_FORMAT_3GPP = 2,
+ MUXER_OUTPUT_FORMAT_OGG = 4,
+ MUXER_OUTPUT_FORMAT_INVALID = 5,
+} MUXER_OUTPUT_T;
+
+class Muxer {
+ public:
+ Muxer() : mFormat(nullptr), mMuxer(nullptr), mStats(nullptr) { mExtractor = new Extractor(); }
+
+ virtual ~Muxer() {
+ if (mStats) delete mStats;
+ if (mExtractor) delete mExtractor;
+ }
+
+ Stats *getStats() { return mStats; }
+ Extractor *getExtractor() { return mExtractor; }
+
+ /* Muxer related utilities */
+ int32_t initMuxer(int32_t fd, MUXER_OUTPUT_T outputFormat);
+ void deInitMuxer();
+ void resetMuxer();
+
+ /* Process the frames and give Muxed output */
+ int32_t mux(uint8_t *inputBuffer, vector<AMediaCodecBufferInfo> &frameSizes);
+
+ void dumpStatistics(string inputReference, string codecName = "", string statsFile = "");
+
+ private:
+ AMediaFormat *mFormat;
+ AMediaMuxer *mMuxer;
+ Extractor *mExtractor;
+ Stats *mStats;
+};
+
+#endif // __MUXER_H__
diff --git a/media/tests/benchmark/tests/Android.bp b/media/tests/benchmark/tests/Android.bp
new file mode 100644
index 0000000..f46fa4a
--- /dev/null
+++ b/media/tests/benchmark/tests/Android.bp
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+cc_test {
+ name: "extractorTest",
+ gtest: true,
+ defaults: [
+ "libmediabenchmark_common-defaults",
+ "libmediabenchmark_soft_sanitize_all-defaults",
+ ],
+
+ srcs: ["ExtractorTest.cpp"],
+
+ static_libs: ["libmediabenchmark_extractor"]
+}
+
+cc_test {
+ name: "decoderTest",
+ gtest: true,
+ defaults: [
+ "libmediabenchmark_common-defaults",
+ "libmediabenchmark_soft_sanitize_all-defaults",
+ ],
+
+ srcs: ["DecoderTest.cpp"],
+
+ static_libs: [
+ "libmediabenchmark_extractor",
+ "libmediabenchmark_decoder",
+ ],
+}
+
+cc_test {
+ name: "muxerTest",
+ gtest: true,
+ defaults: [
+ "libmediabenchmark_common-defaults",
+ "libmediabenchmark_soft_sanitize_all-defaults",
+ ],
+
+ srcs: ["MuxerTest.cpp"],
+
+ static_libs: [
+ "libmediabenchmark_extractor",
+ "libmediabenchmark_muxer",
+ ],
+}
+
+cc_test {
+ name: "encoderTest",
+ gtest: true,
+ defaults: [
+ "libmediabenchmark_common-defaults",
+ "libmediabenchmark_soft_sanitize_all-defaults",
+ ],
+
+ srcs: ["EncoderTest.cpp"],
+
+ static_libs: [
+ "libmediabenchmark_extractor",
+ "libmediabenchmark_decoder",
+ "libmediabenchmark_encoder",
+ ],
+}
+
+cc_test {
+ name: "C2DecoderTest",
+ gtest: true,
+ defaults: [
+ "libmediabenchmark_codec2_common-defaults",
+ "libmediabenchmark_soft_sanitize_all-defaults",
+ ],
+
+ srcs: ["C2DecoderTest.cpp"],
+
+ static_libs: [
+ "libmediabenchmark_codec2_extractor",
+ "libmediabenchmark_codec2_common",
+ "libmediabenchmark_codec2_decoder",
+ ],
+}
+
+cc_test {
+ name: "C2EncoderTest",
+ gtest: true,
+ defaults: [
+ "libmediabenchmark_codec2_common-defaults",
+ ],
+
+ srcs: ["C2EncoderTest.cpp"],
+
+ static_libs: [
+ "libmediabenchmark_codec2_extractor",
+ "libmediabenchmark_codec2_decoder",
+ "libmediabenchmark_codec2_common",
+ "libmediabenchmark_codec2_encoder",
+ ],
+}
diff --git a/media/tests/benchmark/tests/BenchmarkTestEnvironment.h b/media/tests/benchmark/tests/BenchmarkTestEnvironment.h
new file mode 100644
index 0000000..ae2eee1
--- /dev/null
+++ b/media/tests/benchmark/tests/BenchmarkTestEnvironment.h
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+#ifndef __BENCHMARK_TEST_ENVIRONMENT_H__
+#define __BENCHMARK_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class BenchmarkTestEnvironment : public ::testing::Environment {
+ public:
+ BenchmarkTestEnvironment() : res("/sdcard/media/") {}
+
+ // Parses the command line argument
+ int initFromOptions(int argc, char **argv);
+
+ void setRes(const char *_res) { res = _res; }
+
+ const string getRes() const { return res; }
+
+ private:
+ string res;
+};
+
+int BenchmarkTestEnvironment::initFromOptions(int argc, char **argv) {
+ static struct option options[] = {{"path", required_argument, 0, 'P'}, {0, 0, 0, 0}};
+
+ while (true) {
+ int index = 0;
+ int c = getopt_long(argc, argv, "P:", options, &index);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'P': {
+ setRes(optarg);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ if (optind < argc) {
+ fprintf(stderr,
+ "unrecognized option: %s\n\n"
+ "usage: %s <gtest options> <test options>\n\n"
+ "test options are:\n\n"
+ "-P, --path: Resource files directory location\n",
+ argv[optind ?: 1], argv[0]);
+ return 2;
+ }
+ return 0;
+}
+
+#endif // __BENCHMARK_TEST_ENVIRONMENT_H__
diff --git a/media/tests/benchmark/tests/C2DecoderTest.cpp b/media/tests/benchmark/tests/C2DecoderTest.cpp
new file mode 100644
index 0000000..dedc743
--- /dev/null
+++ b/media/tests/benchmark/tests/C2DecoderTest.cpp
@@ -0,0 +1,185 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2DecoderTest"
+
+#include <fstream>
+#include <iostream>
+#include <limits>
+
+#include "BenchmarkTestEnvironment.h"
+#include "C2Decoder.h"
+#include "Extractor.h"
+
+static BenchmarkTestEnvironment *gEnv = nullptr;
+
+class C2DecoderTest : public ::testing::TestWithParam<pair<string, string>> {
+ public:
+ C2DecoderTest() : mDecoder(nullptr) {}
+
+ ~C2DecoderTest() {
+ if (!mCodecList.empty()) {
+ mCodecList.clear();
+ }
+ if (mDecoder) {
+ delete mDecoder;
+ mDecoder = nullptr;
+ }
+ }
+
+ virtual void SetUp() override { setupC2DecoderTest(); }
+
+ void setupC2DecoderTest();
+
+ vector<string> mCodecList;
+ C2Decoder *mDecoder;
+};
+
+void C2DecoderTest::setupC2DecoderTest() {
+ mDecoder = new C2Decoder();
+ ASSERT_NE(mDecoder, nullptr) << "C2Decoder creation failed";
+
+ int32_t status = mDecoder->setupCodec2();
+ ASSERT_EQ(status, 0) << "Codec2 setup failed";
+
+ mCodecList = mDecoder->getSupportedComponentList(false /* isEncoder*/);
+ ASSERT_GT(mCodecList.size(), 0) << "Codec2 client didn't recognise any component";
+}
+
+TEST_P(C2DecoderTest, Codec2Decode) {
+ ALOGV("Decode the samples given by extractor using codec2");
+ string inputFile = gEnv->getRes() + GetParam().first;
+ FILE *inputFp = fopen(inputFile.c_str(), "rb");
+ ASSERT_NE(inputFp, nullptr) << "Unable to open " << inputFile << " file for reading";
+
+ Extractor *extractor = new Extractor();
+ ASSERT_NE(extractor, nullptr) << "Extractor creation failed";
+
+ // Read file properties
+ struct stat buf;
+ stat(inputFile.c_str(), &buf);
+ size_t fileSize = buf.st_size;
+ int32_t fd = fileno(inputFp);
+
+ ASSERT_LE(fileSize, kMaxBufferSize)
+ << "Input file size is greater than the threshold memory dedicated to the test";
+
+ int32_t trackCount = extractor->initExtractor(fd, fileSize);
+ ASSERT_GT(trackCount, 0) << "initExtractor failed";
+
+ for (int32_t curTrack = 0; curTrack < trackCount; curTrack++) {
+ int32_t status = extractor->setupTrackFormat(curTrack);
+ ASSERT_EQ(status, 0) << "Track Format invalid";
+
+ uint8_t *inputBuffer = (uint8_t *)malloc(fileSize);
+ ASSERT_NE(inputBuffer, nullptr) << "Insufficient memory";
+
+ vector<AMediaCodecBufferInfo> frameInfo;
+ AMediaCodecBufferInfo info;
+ uint32_t inputBufferOffset = 0;
+ int32_t idx = 0;
+
+ // Get CSD data
+ while (1) {
+ void *csdBuffer = extractor->getCSDSample(info, idx);
+ if (!csdBuffer || !info.size) break;
+ // copy the meta data and buffer to be passed to decoder
+ ASSERT_LE(inputBufferOffset + info.size, fileSize) << "Memory allocated not sufficient";
+
+ memcpy(inputBuffer + inputBufferOffset, csdBuffer, info.size);
+ frameInfo.push_back(info);
+ inputBufferOffset += info.size;
+ idx++;
+ }
+
+ // Get frame data
+ while (1) {
+ status = extractor->getFrameSample(info);
+ if (status || !info.size) break;
+ // copy the meta data and buffer to be passed to decoder
+ ASSERT_LE(inputBufferOffset + info.size, fileSize) << "Memory allocated not sufficient";
+
+ memcpy(inputBuffer + inputBufferOffset, extractor->getFrameBuf(), info.size);
+ frameInfo.push_back(info);
+ inputBufferOffset += info.size;
+ }
+
+ AMediaFormat *format = extractor->getFormat();
+ // Decode the given input stream for all C2 codecs supported by device
+ for (string codecName : mCodecList) {
+ if (codecName.find(GetParam().second) != string::npos &&
+ codecName.find("secure") == string::npos) {
+ status = mDecoder->createCodec2Component(codecName, format);
+ ASSERT_EQ(status, 0) << "Create component failed for " << codecName;
+
+ // Send the inputs to C2 Decoder and wait till all buffers are returned.
+ status = mDecoder->decodeFrames(inputBuffer, frameInfo);
+ ASSERT_EQ(status, 0) << "Decoder failed for " << codecName;
+
+ mDecoder->waitOnInputConsumption();
+ ASSERT_TRUE(mDecoder->mEos) << "Test Failed. Didn't receive EOS \n";
+
+ mDecoder->deInitCodec();
+ int64_t durationUs = extractor->getClipDuration();
+ ALOGV("codec : %s", codecName.c_str());
+ mDecoder->dumpStatistics(GetParam().first, durationUs);
+ mDecoder->resetDecoder();
+ }
+ }
+ free(inputBuffer);
+ fclose(inputFp);
+ extractor->deInitExtractor();
+ delete extractor;
+ delete mDecoder;
+ mDecoder = nullptr;
+ }
+}
+
+// TODO: (b/140549596)
+// Add wav files
+INSTANTIATE_TEST_SUITE_P(
+ AudioDecoderTest, C2DecoderTest,
+ ::testing::Values(make_pair("bbb_44100hz_2ch_128kbps_aac_30sec.mp4", "aac"),
+ make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec.mp3", "mp3"),
+ make_pair("bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", "amrnb"),
+ make_pair("bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", "amrnb"),
+ make_pair("bbb_44100hz_2ch_80kbps_vorbis_30sec.webm", "vorbis"),
+ make_pair("bbb_44100hz_2ch_600kbps_flac_30sec.mp4", "flac"),
+ make_pair("bbb_48000hz_2ch_100kbps_opus_30sec.webm", "opus")));
+
+INSTANTIATE_TEST_SUITE_P(
+ VideoDecoderTest, C2DecoderTest,
+ ::testing::Values(make_pair("crowd_1920x1080_25fps_4000kbps_vp9.webm", "vp9"),
+ make_pair("crowd_1920x1080_25fps_4000kbps_vp8.webm", "vp8"),
+ make_pair("crowd_1920x1080_25fps_4000kbps_av1.webm", "av1"),
+ make_pair("crowd_1920x1080_25fps_7300kbps_mpeg2.mp4", "mpeg2"),
+ make_pair("crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", "mpeg4"),
+ make_pair("crowd_352x288_25fps_6000kbps_h263.3gp", "h263"),
+ make_pair("crowd_1920x1080_25fps_6700kbps_h264.ts", "avc"),
+ make_pair("crowd_1920x1080_25fps_4000kbps_h265.mkv", "hevc")));
+
+int main(int argc, char **argv) {
+ gEnv = new BenchmarkTestEnvironment();
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = gEnv->initFromOptions(argc, argv);
+ if (status == 0) {
+ status = RUN_ALL_TESTS();
+ ALOGV("C2 Decoder Test result = %d\n", status);
+ }
+ return status;
+}
diff --git a/media/tests/benchmark/tests/C2EncoderTest.cpp b/media/tests/benchmark/tests/C2EncoderTest.cpp
new file mode 100644
index 0000000..98eb17a6
--- /dev/null
+++ b/media/tests/benchmark/tests/C2EncoderTest.cpp
@@ -0,0 +1,187 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2EncoderTest"
+
+#include <fstream>
+#include <iostream>
+#include <limits>
+
+#include "BenchmarkTestEnvironment.h"
+#include "C2Encoder.h"
+#include "Decoder.h"
+
+static BenchmarkTestEnvironment *gEnv = nullptr;
+
+class C2EncoderTest : public ::testing::TestWithParam<pair<string, string>> {
+ public:
+ C2EncoderTest() : mEncoder(nullptr) {}
+
+ ~C2EncoderTest() {
+ if (!mCodecList.empty()) {
+ mCodecList.clear();
+ }
+ if (mEncoder) {
+ delete mEncoder;
+ mEncoder = nullptr;
+ }
+ }
+
+ virtual void SetUp() override { setupC2EncoderTest(); }
+
+ void setupC2EncoderTest();
+
+ vector<string> mCodecList;
+ C2Encoder *mEncoder;
+};
+
+void C2EncoderTest::setupC2EncoderTest() {
+ mEncoder = new C2Encoder();
+ ASSERT_NE(mEncoder, nullptr) << "C2Encoder creation failed";
+
+ int32_t status = mEncoder->setupCodec2();
+ ASSERT_EQ(status, 0) << "Codec2 setup failed";
+
+ mCodecList = mEncoder->getSupportedComponentList(true /* isEncoder*/);
+ ASSERT_GT(mCodecList.size(), 0) << "Codec2 client didn't recognise any component";
+}
+
+TEST_P(C2EncoderTest, Codec2Encode) {
+ ALOGV("Encodes the input using codec2 framework");
+ string inputFile = gEnv->getRes() + GetParam().first;
+ FILE *inputFp = fopen(inputFile.c_str(), "rb");
+ ASSERT_NE(inputFp, nullptr) << "Unable to open input file for reading";
+
+ Decoder *decoder = new Decoder();
+ ASSERT_NE(decoder, nullptr) << "Decoder creation failed";
+
+ Extractor *extractor = decoder->getExtractor();
+ ASSERT_NE(extractor, nullptr) << "Extractor creation failed";
+
+ // Read file properties
+ struct stat buf;
+ stat(inputFile.c_str(), &buf);
+ size_t fileSize = buf.st_size;
+ int32_t fd = fileno(inputFp);
+
+ ASSERT_LE(fileSize, kMaxBufferSize)
+ << "Input file size is greater than the threshold memory dedicated to the test";
+
+ int32_t trackCount = extractor->initExtractor(fd, fileSize);
+ ASSERT_GT(trackCount, 0) << "initExtractor failed";
+
+ for (int curTrack = 0; curTrack < trackCount; curTrack++) {
+ int32_t status = extractor->setupTrackFormat(curTrack);
+ ASSERT_EQ(status, 0) << "Track Format invalid";
+
+ uint8_t *inputBuffer = (uint8_t *)malloc(fileSize);
+ ASSERT_NE(inputBuffer, nullptr) << "Insufficient memory";
+
+ vector<AMediaCodecBufferInfo> frameInfo;
+ AMediaCodecBufferInfo info;
+ uint32_t inputBufferOffset = 0;
+
+ // Get frame data
+ while (1) {
+ status = extractor->getFrameSample(info);
+ if (status || !info.size) break;
+ // copy the meta data and buffer to be passed to decoder
+ ASSERT_LE(inputBufferOffset + info.size, fileSize) << "Memory allocated not sufficient";
+
+ memcpy(inputBuffer + inputBufferOffset, extractor->getFrameBuf(), info.size);
+ frameInfo.push_back(info);
+ inputBufferOffset += info.size;
+ }
+
+ string decName = "";
+ string outputFileName = "decode.out";
+ FILE *outFp = fopen(outputFileName.c_str(), "wb");
+ ASSERT_NE(outFp, nullptr) << "Unable to open output file" << outputFileName
+ << " for dumping decoder's output";
+
+ decoder->setupDecoder();
+ status = decoder->decode(inputBuffer, frameInfo, decName, false /*asyncMode */, outFp);
+ ASSERT_EQ(status, AMEDIA_OK) << "Decode returned error : " << status;
+
+ // Encode the given input stream for all C2 codecs supported by device
+ AMediaFormat *format = extractor->getFormat();
+ ifstream eleStream;
+ eleStream.open(outputFileName.c_str(), ifstream::binary | ifstream::ate);
+ ASSERT_EQ(eleStream.is_open(), true) << outputFileName.c_str() << " - file not found";
+ size_t eleSize = eleStream.tellg();
+
+ for (string codecName : mCodecList) {
+ if (codecName.find(GetParam().second) != string::npos) {
+ status = mEncoder->createCodec2Component(codecName, format);
+ ASSERT_EQ(status, 0) << "Create component failed for " << codecName;
+
+ // Send the inputs to C2 Encoder and wait till all buffers are returned.
+ eleStream.seekg(0, ifstream::beg);
+ status = mEncoder->encodeFrames(eleStream, eleSize);
+ ASSERT_EQ(status, 0) << "Encoder failed for " << codecName;
+
+ mEncoder->waitOnInputConsumption();
+ ASSERT_TRUE(mEncoder->mEos) << "Test Failed. Didn't receive EOS \n";
+
+ mEncoder->deInitCodec();
+ int64_t durationUs = extractor->getClipDuration();
+ ALOGV("codec : %s", codecName.c_str());
+ mEncoder->dumpStatistics(GetParam().first, durationUs);
+ mEncoder->resetEncoder();
+ }
+ }
+
+ // Destroy the decoder for the given input
+ decoder->deInitCodec();
+ decoder->resetDecoder();
+ free(inputBuffer);
+ }
+ fclose(inputFp);
+ extractor->deInitExtractor();
+ delete decoder;
+ delete mEncoder;
+ mEncoder = nullptr;
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ AudioEncoderTest, C2EncoderTest,
+ ::testing::Values(make_pair("bbb_44100hz_2ch_128kbps_aac_30sec.mp4", "aac"),
+ make_pair("bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", "amrnb"),
+ make_pair("bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", "amrwb"),
+ make_pair("bbb_44100hz_2ch_600kbps_flac_30sec.mp4", "flac"),
+ make_pair("bbb_48000hz_2ch_100kbps_opus_30sec.webm", "opus")));
+
+INSTANTIATE_TEST_SUITE_P(
+ VideoEncoderTest, C2EncoderTest,
+ ::testing::Values(make_pair("crowd_1920x1080_25fps_4000kbps_vp9.webm", "vp9"),
+ make_pair("crowd_1920x1080_25fps_4000kbps_vp8.webm", "vp8"),
+ make_pair("crowd_176x144_25fps_6000kbps_mpeg4.mp4", "mpeg4"),
+ make_pair("crowd_176x144_25fps_6000kbps_h263.3gp", "h263"),
+ make_pair("crowd_1920x1080_25fps_6700kbps_h264.ts", "avc"),
+ make_pair("crowd_1920x1080_25fps_4000kbps_h265.mkv", "hevc")));
+
+int main(int argc, char **argv) {
+ gEnv = new BenchmarkTestEnvironment();
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = gEnv->initFromOptions(argc, argv);
+ if (status == 0) {
+ status = RUN_ALL_TESTS();
+ ALOGV("C2 Encoder Test result = %d\n", status);
+ }
+ return status;
+}
diff --git a/media/tests/benchmark/tests/DecoderTest.cpp b/media/tests/benchmark/tests/DecoderTest.cpp
new file mode 100644
index 0000000..9f96d3b
--- /dev/null
+++ b/media/tests/benchmark/tests/DecoderTest.cpp
@@ -0,0 +1,186 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "decoderTest"
+
+#include <fstream>
+#include <iostream>
+#include <limits>
+
+#include "BenchmarkTestEnvironment.h"
+#include "Decoder.h"
+
+static BenchmarkTestEnvironment *gEnv = nullptr;
+
+class DecoderTest : public ::testing::TestWithParam<tuple<string, string, bool>> {};
+
+TEST_P(DecoderTest, Decode) {
+ ALOGV("Decode the samples given by extractor");
+ tuple<string /* InputFile */, string /* CodecName */, bool /* asyncMode */> params = GetParam();
+
+ string inputFile = gEnv->getRes() + get<0>(params);
+ FILE *inputFp = fopen(inputFile.c_str(), "rb");
+ ASSERT_NE(inputFp, nullptr) << "Unable to open " << inputFile << " file for reading";
+
+ Decoder *decoder = new Decoder();
+ ASSERT_NE(decoder, nullptr) << "Decoder creation failed";
+
+ Extractor *extractor = decoder->getExtractor();
+ ASSERT_NE(extractor, nullptr) << "Extractor creation failed";
+
+ // Read file properties
+ struct stat buf;
+ stat(inputFile.c_str(), &buf);
+ size_t fileSize = buf.st_size;
+ int32_t fd = fileno(inputFp);
+
+ int32_t trackCount = extractor->initExtractor(fd, fileSize);
+ ASSERT_GT(trackCount, 0) << "initExtractor failed";
+
+ for (int curTrack = 0; curTrack < trackCount; curTrack++) {
+ int32_t status = extractor->setupTrackFormat(curTrack);
+ ASSERT_EQ(status, 0) << "Track Format invalid";
+
+ uint8_t *inputBuffer = (uint8_t *)malloc(kMaxBufferSize);
+ ASSERT_NE(inputBuffer, nullptr) << "Insufficient memory";
+
+ vector<AMediaCodecBufferInfo> frameInfo;
+ AMediaCodecBufferInfo info;
+ uint32_t inputBufferOffset = 0;
+
+ // Get frame data
+ while (1) {
+ status = extractor->getFrameSample(info);
+ if (status || !info.size) break;
+ // copy the meta data and buffer to be passed to decoder
+ ASSERT_LE(inputBufferOffset + info.size, kMaxBufferSize)
+ << "Memory allocated not sufficient";
+
+ memcpy(inputBuffer + inputBufferOffset, extractor->getFrameBuf(), info.size);
+ frameInfo.push_back(info);
+ inputBufferOffset += info.size;
+ }
+
+ string codecName = get<1>(params);
+ bool asyncMode = get<2>(params);
+ decoder->setupDecoder();
+ status = decoder->decode(inputBuffer, frameInfo, codecName, asyncMode);
+ ASSERT_EQ(status, AMEDIA_OK) << "Decoder failed for " << codecName;
+
+ decoder->deInitCodec();
+ ALOGV("codec : %s", codecName.c_str());
+ string inputReference = get<0>(params);
+ decoder->dumpStatistics(inputReference);
+ free(inputBuffer);
+ decoder->resetDecoder();
+ }
+ fclose(inputFp);
+ extractor->deInitExtractor();
+ delete decoder;
+}
+
+// TODO: (b/140549596)
+// Add wav files
+INSTANTIATE_TEST_SUITE_P(
+ AudioDecoderSyncTest, DecoderTest,
+ ::testing::Values(make_tuple("bbb_44100hz_2ch_128kbps_aac_30sec.mp4", "", false),
+ make_tuple("bbb_44100hz_2ch_128kbps_mp3_30sec.mp3", "", false),
+ make_tuple("bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", "", false),
+ make_tuple("bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", "", false),
+ make_tuple("bbb_44100hz_2ch_80kbps_vorbis_30sec.webm", "", false),
+ make_tuple("bbb_44100hz_2ch_600kbps_flac_30sec.mp4", "", false),
+ make_tuple("bbb_48000hz_2ch_100kbps_opus_30sec.webm", "", false)));
+
+INSTANTIATE_TEST_SUITE_P(
+ AudioDecoderAsyncTest, DecoderTest,
+ ::testing::Values(make_tuple("bbb_44100hz_2ch_128kbps_aac_30sec.mp4", "", true),
+ make_tuple("bbb_44100hz_2ch_128kbps_mp3_30sec.mp3", "", true),
+ make_tuple("bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", "", true),
+ make_tuple("bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", "", true),
+ make_tuple("bbb_44100hz_2ch_80kbps_vorbis_30sec.webm", "", true),
+ make_tuple("bbb_44100hz_2ch_600kbps_flac_30sec.mp4", "", true),
+ make_tuple("bbb_48000hz_2ch_100kbps_opus_30sec.webm", "", true)));
+
+INSTANTIATE_TEST_SUITE_P(VideDecoderSyncTest, DecoderTest,
+ ::testing::Values(
+ // Hardware codecs
+ make_tuple("crowd_1920x1080_25fps_4000kbps_vp9.webm", "", false),
+ make_tuple("crowd_1920x1080_25fps_4000kbps_vp8.webm", "", false),
+ make_tuple("crowd_1920x1080_25fps_4000kbps_av1.webm", "", false),
+ make_tuple("crowd_1920x1080_25fps_7300kbps_mpeg2.mp4", "", false),
+ make_tuple("crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", "", false),
+ make_tuple("crowd_352x288_25fps_6000kbps_h263.3gp", "", false),
+ make_tuple("crowd_1920x1080_25fps_6700kbps_h264.ts", "", false),
+ make_tuple("crowd_1920x1080_25fps_4000kbps_h265.mkv", "", false),
+ // Software codecs
+ make_tuple("crowd_1920x1080_25fps_4000kbps_vp9.webm",
+ "c2.android.vp9.decoder", false),
+ make_tuple("crowd_1920x1080_25fps_4000kbps_vp8.webm",
+ "c2.android.vp8.decoder", false),
+ make_tuple("crowd_1920x1080_25fps_4000kbps_av1.webm",
+ "c2.android.av1.decoder", false),
+ make_tuple("crowd_1920x1080_25fps_7300kbps_mpeg2.mp4",
+ "c2.android.mpeg2.decoder", false),
+ make_tuple("crowd_1920x1080_25fps_6000kbps_mpeg4.mp4",
+ "c2.android.mpeg4.decoder", false),
+ make_tuple("crowd_352x288_25fps_6000kbps_h263.3gp",
+ "c2.android.h263.decoder", false),
+ make_tuple("crowd_1920x1080_25fps_6700kbps_h264.ts",
+ "c2.android.avc.decoder", false),
+ make_tuple("crowd_1920x1080_25fps_4000kbps_h265.mkv",
+ "c2.android.hevc.decoder", false)));
+
+INSTANTIATE_TEST_SUITE_P(VideoDecoderAsyncTest, DecoderTest,
+ ::testing::Values(
+ // Hardware codecs
+ make_tuple("crowd_1920x1080_25fps_4000kbps_vp9.webm", "", true),
+ make_tuple("crowd_1920x1080_25fps_4000kbps_vp8.webm", "", true),
+ make_tuple("crowd_1920x1080_25fps_4000kbps_av1.webm", "", true),
+ make_tuple("crowd_1920x1080_25fps_7300kbps_mpeg2.mp4", "", true),
+ make_tuple("crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", "", true),
+ make_tuple("crowd_352x288_25fps_6000kbps_h263.3gp", "", true),
+ make_tuple("crowd_1920x1080_25fps_6700kbps_h264.ts", "", true),
+ make_tuple("crowd_1920x1080_25fps_4000kbps_h265.mkv", "", true),
+ // Software codecs
+ make_tuple("crowd_1920x1080_25fps_4000kbps_vp9.webm",
+ "c2.android.vp9.decoder", true),
+ make_tuple("crowd_1920x1080_25fps_4000kbps_vp8.webm",
+ "c2.android.vp8.decoder", true),
+ make_tuple("crowd_1920x1080_25fps_4000kbps_av1.webm",
+ "c2.android.av1.decoder", true),
+ make_tuple("crowd_1920x1080_25fps_7300kbps_mpeg2.mp4",
+ "c2.android.mpeg2.decoder", true),
+ make_tuple("crowd_1920x1080_25fps_6000kbps_mpeg4.mp4",
+ "c2.android.mpeg4.decoder", true),
+ make_tuple("crowd_352x288_25fps_6000kbps_h263.3gp",
+ "c2.android.h263.decoder", true),
+ make_tuple("crowd_1920x1080_25fps_6700kbps_h264.ts",
+ "c2.android.avc.decoder", true),
+ make_tuple("crowd_1920x1080_25fps_4000kbps_h265.mkv",
+ "c2.android.hevc.decoder", true)));
+
+int main(int argc, char **argv) {
+ gEnv = new BenchmarkTestEnvironment();
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = gEnv->initFromOptions(argc, argv);
+ if (status == 0) {
+ status = RUN_ALL_TESTS();
+ ALOGD("Decoder Test result = %d\n", status);
+ }
+ return status;
+}
\ No newline at end of file
diff --git a/media/tests/benchmark/tests/EncoderTest.cpp b/media/tests/benchmark/tests/EncoderTest.cpp
new file mode 100644
index 0000000..dc2a2dd
--- /dev/null
+++ b/media/tests/benchmark/tests/EncoderTest.cpp
@@ -0,0 +1,221 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "encoderTest"
+
+#include <fstream>
+
+#include "BenchmarkTestEnvironment.h"
+#include "Decoder.h"
+#include "Encoder.h"
+
+static BenchmarkTestEnvironment *gEnv = nullptr;
+
+class EncoderTest : public ::testing::TestWithParam<tuple<string, string, bool>> {};
+
+TEST_P(EncoderTest, Encode) {
+ ALOGD("Encode test for all codecs");
+ tuple<string /* InputFile */, string /* CodecName */, bool /* asyncMode */> params = GetParam();
+
+ string inputFile = gEnv->getRes() + get<0>(params);
+ FILE *inputFp = fopen(inputFile.c_str(), "rb");
+ ASSERT_NE(inputFp, nullptr) << "Unable to open " << inputFile << " file for reading";
+
+ Decoder *decoder = new Decoder();
+ ASSERT_NE(decoder, nullptr) << "Decoder creation failed";
+
+ Extractor *extractor = decoder->getExtractor();
+ ASSERT_NE(extractor, nullptr) << "Extractor creation failed";
+
+ // Read file properties
+ struct stat buf;
+ stat(inputFile.c_str(), &buf);
+ size_t fileSize = buf.st_size;
+ int32_t fd = fileno(inputFp);
+
+ int32_t trackCount = extractor->initExtractor(fd, fileSize);
+ ASSERT_GT(trackCount, 0) << "initExtractor failed";
+
+ Encoder *encoder = new Encoder();
+ ASSERT_NE(encoder, nullptr) << "Decoder creation failed";
+
+ for (int curTrack = 0; curTrack < trackCount; curTrack++) {
+ int32_t status = extractor->setupTrackFormat(curTrack);
+ ASSERT_EQ(status, 0) << "Track Format invalid";
+
+ uint8_t *inputBuffer = (uint8_t *)malloc(kMaxBufferSize);
+ ASSERT_NE(inputBuffer, nullptr) << "Insufficient memory";
+
+ vector<AMediaCodecBufferInfo> frameInfo;
+ AMediaCodecBufferInfo info;
+ uint32_t inputBufferOffset = 0;
+
+ // Get frame data
+ while (1) {
+ status = extractor->getFrameSample(info);
+ if (status || !info.size) break;
+ // copy the meta data and buffer to be passed to decoder
+ ASSERT_LE(inputBufferOffset + info.size, kMaxBufferSize)
+ << "Memory allocated not sufficient";
+
+ memcpy(inputBuffer + inputBufferOffset, extractor->getFrameBuf(), info.size);
+ frameInfo.push_back(info);
+ inputBufferOffset += info.size;
+ }
+
+ string decName = "";
+ string outputFileName = "decode.out";
+ FILE *outFp = fopen(outputFileName.c_str(), "wb");
+ ASSERT_NE(outFp, nullptr) << "Unable to open output file" << outputFileName
+ << " for dumping decoder's output";
+
+ decoder->setupDecoder();
+ status = decoder->decode(inputBuffer, frameInfo, decName, false /*asyncMode */, outFp);
+ ASSERT_EQ(status, AMEDIA_OK) << "Decode returned error : " << status;
+
+ ifstream eleStream;
+ eleStream.open(outputFileName.c_str(), ifstream::binary | ifstream::ate);
+ ASSERT_EQ(eleStream.is_open(), true) << outputFileName.c_str() << " - file not found";
+ size_t eleSize = eleStream.tellg();
+ eleStream.seekg(0, ifstream::beg);
+
+ AMediaFormat *format = extractor->getFormat();
+ const char *mime = nullptr;
+ AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime);
+ ASSERT_NE(mime, nullptr) << "Invalid mime type";
+
+ // Get encoder params
+ encParameter encParams;
+ if (!strncmp(mime, "video/", 6)) {
+ ASSERT_TRUE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &encParams.width));
+ ASSERT_TRUE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &encParams.height));
+ AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_FRAME_RATE, &encParams.frameRate);
+ AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, &encParams.bitrate);
+ if (encParams.bitrate <= 0 || encParams.frameRate <= 0) {
+ encParams.frameRate = 25;
+ if (!strcmp(mime, "video/3gpp") || !strcmp(mime, "video/mp4v-es")) {
+ encParams.bitrate = 600000 /* 600 Kbps */;
+ } else {
+ encParams.bitrate = 8000000 /* 8 Mbps */;
+ }
+ }
+ AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_PROFILE, &encParams.profile);
+ AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_LEVEL, &encParams.level);
+ } else {
+ ASSERT_TRUE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE,
+ &encParams.sampleRate));
+ ASSERT_TRUE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT,
+ &encParams.numChannels));
+ encParams.bitrate =
+ encParams.sampleRate * encParams.numChannels * 16 /* bitsPerSample */;
+ }
+
+ encoder->setupEncoder();
+ string codecName = get<1>(params);
+ bool asyncMode = get<2>(params);
+ status = encoder->encode(codecName, eleStream, eleSize, asyncMode, encParams, (char *)mime);
+ ASSERT_EQ(status, 0) << "Encoder failed for " << codecName;
+
+ encoder->deInitCodec();
+ ALOGV("codec : %s", codecName.c_str());
+ string inputReference = get<0>(params);
+ encoder->dumpStatistics(inputReference, extractor->getClipDuration());
+ eleStream.close();
+ if (outFp) fclose(outFp);
+
+ if (format) {
+ AMediaFormat_delete(format);
+ format = nullptr;
+ }
+ encoder->resetEncoder();
+ decoder->deInitCodec();
+ free(inputBuffer);
+ decoder->resetDecoder();
+ }
+ delete encoder;
+ fclose(inputFp);
+ extractor->deInitExtractor();
+ delete decoder;
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ AudioEncoderSyncTest, EncoderTest,
+ ::testing::Values(make_tuple("bbb_44100hz_2ch_128kbps_aac_30sec.mp4", "", false),
+ make_tuple("bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", "", false),
+ make_tuple("bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", "", false),
+ make_tuple("bbb_44100hz_2ch_600kbps_flac_30sec.mp4", "", false),
+ make_tuple("bbb_48000hz_2ch_100kbps_opus_30sec.webm", "", false)));
+
+INSTANTIATE_TEST_SUITE_P(
+ AudioEncoderAsyncTest, EncoderTest,
+ ::testing::Values(make_tuple("bbb_44100hz_2ch_128kbps_aac_30sec.mp4", "", true),
+ make_tuple("bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", "", true),
+ make_tuple("bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", "", true),
+ make_tuple("bbb_44100hz_2ch_600kbps_flac_30sec.mp4", "", true),
+ make_tuple("bbb_48000hz_2ch_100kbps_opus_30sec.webm", "", true)));
+
+INSTANTIATE_TEST_SUITE_P(VideEncoderSyncTest, EncoderTest,
+ ::testing::Values(
+ // Hardware codecs
+ make_tuple("crowd_1920x1080_25fps_4000kbps_vp8.webm", "", false),
+ make_tuple("crowd_1920x1080_25fps_6700kbps_h264.ts", "", false),
+ make_tuple("crowd_1920x1080_25fps_4000kbps_h265.mkv", "", false),
+ // Software codecs
+ make_tuple("crowd_1920x1080_25fps_4000kbps_vp9.webm",
+ "c2.android.vp9.encoder", false),
+ make_tuple("crowd_1920x1080_25fps_4000kbps_vp8.webm",
+ "c2.android.vp8.encoder", false),
+ make_tuple("crowd_176x144_25fps_6000kbps_mpeg4.mp4",
+ "c2.android.mpeg4.encoder", false),
+ make_tuple("crowd_176x144_25fps_6000kbps_h263.3gp",
+ "c2.android.h263.encoder", false),
+ make_tuple("crowd_1920x1080_25fps_6700kbps_h264.ts",
+ "c2.android.avc.encoder", false),
+ make_tuple("crowd_1920x1080_25fps_4000kbps_h265.mkv",
+ "c2.android.hevc.encoder", false)));
+
+INSTANTIATE_TEST_SUITE_P(VideoEncoderAsyncTest, EncoderTest,
+ ::testing::Values(
+ // Hardware codecs
+ make_tuple("crowd_1920x1080_25fps_4000kbps_vp8.webm", "", true),
+ make_tuple("crowd_1920x1080_25fps_6700kbps_h264.ts", "", true),
+ make_tuple("crowd_1920x1080_25fps_4000kbps_h265.mkv", "", true),
+ // Software codecs
+ make_tuple("crowd_1920x1080_25fps_4000kbps_vp9.webm",
+ "c2.android.vp9.encoder", true),
+ make_tuple("crowd_1920x1080_25fps_4000kbps_vp8.webm",
+ "c2.android.vp8.encoder", true),
+ make_tuple("crowd_176x144_25fps_6000kbps_mpeg4.mp4",
+ "c2.android.mpeg4.encoder", true),
+ make_tuple("crowd_176x144_25fps_6000kbps_h263.3gp",
+ "c2.android.h263.encoder", true),
+ make_tuple("crowd_1920x1080_25fps_6700kbps_h264.ts",
+ "c2.android.avc.encoder", true),
+ make_tuple("crowd_1920x1080_25fps_4000kbps_h265.mkv",
+ "c2.android.hevc.encoder", true)));
+
+int main(int argc, char **argv) {
+ gEnv = new BenchmarkTestEnvironment();
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = gEnv->initFromOptions(argc, argv);
+ if (status == 0) {
+ status = RUN_ALL_TESTS();
+ ALOGD("Encoder Test result = %d\n", status);
+ }
+ return status;
+}
diff --git a/media/tests/benchmark/tests/ExtractorTest.cpp b/media/tests/benchmark/tests/ExtractorTest.cpp
new file mode 100644
index 0000000..ad8f1e6
--- /dev/null
+++ b/media/tests/benchmark/tests/ExtractorTest.cpp
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "extractorTest"
+
+#include <gtest/gtest.h>
+
+#include "BenchmarkTestEnvironment.h"
+#include "Extractor.h"
+
+static BenchmarkTestEnvironment *gEnv = nullptr;
+
+class ExtractorTest : public ::testing::TestWithParam<pair<string, int32_t>> {};
+
+TEST_P(ExtractorTest, Extract) {
+ Extractor *extractObj = new Extractor();
+ ASSERT_NE(extractObj, nullptr) << "Extractor creation failed";
+
+ string inputFile = gEnv->getRes() + GetParam().first;
+ FILE *inputFp = fopen(inputFile.c_str(), "rb");
+ ASSERT_NE(inputFp, nullptr) << "Unable to open " << inputFile << " file for reading";
+
+ // Read file properties
+ struct stat buf;
+ stat(inputFile.c_str(), &buf);
+ size_t fileSize = buf.st_size;
+ int32_t fd = fileno(inputFp);
+
+ int32_t trackCount = extractObj->initExtractor(fd, fileSize);
+ ASSERT_GT(trackCount, 0) << "initExtractor failed";
+
+ int32_t trackID = GetParam().second;
+ int32_t status = extractObj->extract(trackID);
+ ASSERT_EQ(status, AMEDIA_OK) << "Extraction failed \n";
+
+ extractObj->deInitExtractor();
+
+ extractObj->dumpStatistics(GetParam().first);
+
+ fclose(inputFp);
+ delete extractObj;
+}
+
+INSTANTIATE_TEST_SUITE_P(ExtractorTestAll, ExtractorTest,
+ ::testing::Values(make_pair("crowd_1920x1080_25fps_4000kbps_vp9.webm", 0),
+ make_pair("crowd_1920x1080_25fps_6000kbps_h263.3gp", 0),
+ make_pair("crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", 0),
+ make_pair("crowd_1920x1080_25fps_6700kbps_h264.ts", 0),
+ make_pair("crowd_1920x1080_25fps_7300kbps_mpeg2.mp4", 0),
+ make_pair("crowd_1920x1080_25fps_4000kbps_av1.webm", 0),
+ make_pair("crowd_1920x1080_25fps_4000kbps_h265.mkv", 0),
+ make_pair("crowd_1920x1080_25fps_4000kbps_vp8.webm", 0),
+ make_pair("bbb_44100hz_2ch_128kbps_aac_5mins.mp4", 0),
+ make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins.mp3", 0),
+ make_pair("bbb_44100hz_2ch_600kbps_flac_5mins.flac", 0),
+ make_pair("bbb_8000hz_1ch_8kbps_amrnb_5mins.3gp", 0),
+ make_pair("bbb_16000hz_1ch_9kbps_amrwb_5mins.3gp", 0),
+ make_pair("bbb_44100hz_2ch_80kbps_vorbis_5mins.webm", 0),
+ make_pair("bbb_48000hz_2ch_100kbps_opus_5mins.webm",
+ 0)));
+
+int main(int argc, char **argv) {
+ gEnv = new BenchmarkTestEnvironment();
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = gEnv->initFromOptions(argc, argv);
+ if (status == 0) {
+ status = RUN_ALL_TESTS();
+ ALOGD(" Extractor Test result = %d\n", status);
+ }
+ return status;
+}
diff --git a/media/tests/benchmark/tests/MuxerTest.cpp b/media/tests/benchmark/tests/MuxerTest.cpp
new file mode 100644
index 0000000..fa2635d
--- /dev/null
+++ b/media/tests/benchmark/tests/MuxerTest.cpp
@@ -0,0 +1,158 @@
+
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "muxerTest"
+
+#include <fstream>
+#include <iostream>
+
+#include "BenchmarkTestEnvironment.h"
+#include "Muxer.h"
+
+#define OUTPUT_FILE_NAME "/data/local/tmp/mux.out"
+
+static BenchmarkTestEnvironment *gEnv = nullptr;
+
+class MuxerTest : public ::testing::TestWithParam<pair<string, string>> {};
+
+static MUXER_OUTPUT_T getMuxerOutFormat(string fmt) {
+ static const struct {
+ string name;
+ MUXER_OUTPUT_T value;
+ } kFormatMaps[] = {{"mp4", MUXER_OUTPUT_FORMAT_MPEG_4},
+ {"webm", MUXER_OUTPUT_FORMAT_WEBM},
+ {"3gpp", MUXER_OUTPUT_FORMAT_3GPP},
+ {"ogg", MUXER_OUTPUT_FORMAT_OGG}};
+
+ MUXER_OUTPUT_T format = MUXER_OUTPUT_FORMAT_INVALID;
+ for (size_t i = 0; i < sizeof(kFormatMaps) / sizeof(kFormatMaps[0]); ++i) {
+ if (!fmt.compare(kFormatMaps[i].name)) {
+ format = kFormatMaps[i].value;
+ break;
+ }
+ }
+ return format;
+}
+
+TEST_P(MuxerTest, Mux) {
+ ALOGV("Mux the samples given by extractor");
+ string inputFile = gEnv->getRes() + GetParam().first;
+ FILE *inputFp = fopen(inputFile.c_str(), "rb");
+ ASSERT_NE(inputFp, nullptr) << "Unable to open " << inputFile << " file for reading";
+
+ string fmt = GetParam().second;
+ MUXER_OUTPUT_T outputFormat = getMuxerOutFormat(fmt);
+ ASSERT_NE(outputFormat, MUXER_OUTPUT_FORMAT_INVALID) << "Invalid muxer output format";
+
+ Muxer *muxerObj = new Muxer();
+ ASSERT_NE(muxerObj, nullptr) << "Muxer creation failed";
+
+ Extractor *extractor = muxerObj->getExtractor();
+ ASSERT_NE(extractor, nullptr) << "Extractor creation failed";
+
+ // Read file properties
+ struct stat buf;
+ stat(inputFile.c_str(), &buf);
+ size_t fileSize = buf.st_size;
+ int32_t fd = fileno(inputFp);
+
+ int32_t trackCount = extractor->initExtractor(fd, fileSize);
+ ASSERT_GT(trackCount, 0) << "initExtractor failed";
+
+ for (int curTrack = 0; curTrack < trackCount; curTrack++) {
+ int32_t status = extractor->setupTrackFormat(curTrack);
+ ASSERT_EQ(status, 0) << "Track Format invalid";
+
+ uint8_t *inputBuffer = (uint8_t *)malloc(kMaxBufferSize);
+ ASSERT_NE(inputBuffer, nullptr) << "Insufficient memory";
+
+ // AMediaCodecBufferInfo : <size of frame> <flags> <presentationTimeUs> <offset>
+ vector<AMediaCodecBufferInfo> frameInfos;
+ AMediaCodecBufferInfo info;
+ uint32_t inputBufferOffset = 0;
+
+ // Get Frame Data
+ while (1) {
+ status = extractor->getFrameSample(info);
+ if (status || !info.size) break;
+ // copy the meta data and buffer to be passed to muxer
+ ASSERT_LE(inputBufferOffset + info.size, kMaxBufferSize)
+ << "Memory allocated not sufficient";
+
+ memcpy(inputBuffer + inputBufferOffset, extractor->getFrameBuf(), info.size);
+ info.offset = inputBufferOffset;
+ frameInfos.push_back(info);
+ inputBufferOffset += info.size;
+ }
+
+ string outputFileName = OUTPUT_FILE_NAME;
+ FILE *outputFp = fopen(outputFileName.c_str(), "w+b");
+ ASSERT_NE(outputFp, nullptr)
+ << "Unable to open output file" << outputFileName << " for writing";
+
+ int32_t fd = fileno(outputFp);
+ status = muxerObj->initMuxer(fd, outputFormat);
+ ASSERT_EQ(status, 0) << "initMuxer failed";
+
+ status = muxerObj->mux(inputBuffer, frameInfos);
+ ASSERT_EQ(status, 0) << "Mux failed";
+
+ muxerObj->deInitMuxer();
+ muxerObj->dumpStatistics(GetParam().first + "." + fmt.c_str());
+ free(inputBuffer);
+ fclose(outputFp);
+ muxerObj->resetMuxer();
+ }
+ fclose(inputFp);
+ extractor->deInitExtractor();
+ delete muxerObj;
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ MuxerTestAll, MuxerTest,
+ ::testing::Values(make_pair("crowd_1920x1080_25fps_4000kbps_vp8.webm", "webm"),
+ make_pair("crowd_1920x1080_25fps_4000kbps_vp9.webm", "webm"),
+ make_pair("crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", "mp4"),
+ make_pair("crowd_352x288_25fps_6000kbps_h263.3gp", "mp4"),
+ make_pair("crowd_1920x1080_25fps_6700kbps_h264.ts", "mp4"),
+ make_pair("crowd_1920x1080_25fps_4000kbps_h265.mkv", "mp4"),
+ make_pair("crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", "3gpp"),
+ make_pair("crowd_352x288_25fps_6000kbps_h263.3gp", "3gpp"),
+ make_pair("crowd_1920x1080_25fps_6700kbps_h264.ts", "3gpp"),
+ make_pair("crowd_1920x1080_25fps_4000kbps_h265.mkv", "3gpp"),
+ make_pair("bbb_48000hz_2ch_100kbps_opus_5mins.webm", "ogg"),
+ make_pair("bbb_44100hz_2ch_80kbps_vorbis_5mins.webm", "webm"),
+ make_pair("bbb_48000hz_2ch_100kbps_opus_5mins.webm", "webm"),
+ make_pair("bbb_44100hz_2ch_128kbps_aac_5mins.mp4", "mp4"),
+ make_pair("bbb_8000hz_1ch_8kbps_amrnb_5mins.3gp", "mp4"),
+ make_pair("bbb_16000hz_1ch_9kbps_amrwb_5mins.3gp", "mp4"),
+ make_pair("bbb_44100hz_2ch_128kbps_aac_5mins.mp4", "3gpp"),
+ make_pair("bbb_8000hz_1ch_8kbps_amrnb_5mins.3gp", "3gpp"),
+ make_pair("bbb_16000hz_1ch_9kbps_amrwb_5mins.3gp", "3gpp")));
+
+int main(int argc, char **argv) {
+ gEnv = new BenchmarkTestEnvironment();
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = gEnv->initFromOptions(argc, argv);
+ if (status == 0) {
+ status = RUN_ALL_TESTS();
+ ALOGV("Test result = %d\n", status);
+ }
+ return status;
+}
diff --git a/media/utils/Android.bp b/media/utils/Android.bp
index e2cd4e3..b7037e9 100644
--- a/media/utils/Android.bp
+++ b/media/utils/Android.bp
@@ -25,12 +25,15 @@
"ServiceUtilities.cpp",
"TimeCheck.cpp",
],
+ static_libs: [
+ "libc_malloc_debug_backtrace",
+ ],
shared_libs: [
+ "libaudioutils", // for clock.h
"libbinder",
"libcutils",
"liblog",
"libutils",
- "libmemunreachable",
"libhidlbase",
"android.hardware.graphics.bufferqueue@1.0",
"android.hidl.token@1.0-utils",
@@ -44,15 +47,14 @@
"-Werror",
],
- product_variables: {
- product_is_iot: {
- cflags: ["-DTARGET_ANDROID_THINGS"],
- },
- },
+ header_libs: [
+ "bionic_libc_platform_headers",
+ "libmedia_headers",
+ ],
include_dirs: [
- // For android_mallopt definitions.
- "bionic/libc/private"
+ // For DEBUGGER_SIGNAL
+ "system/core/debuggerd/include",
],
local_include_dirs: ["include"],
export_include_dirs: ["include"],
diff --git a/media/utils/ISchedulingPolicyService.cpp b/media/utils/ISchedulingPolicyService.cpp
index b210404..e60e230 100644
--- a/media/utils/ISchedulingPolicyService.cpp
+++ b/media/utils/ISchedulingPolicyService.cpp
@@ -62,12 +62,12 @@
return reply.readInt32();
}
- virtual int requestCpusetBoost(bool enable, const sp<IInterface>& client)
+ virtual int requestCpusetBoost(bool enable, const sp<IBinder>& client)
{
Parcel data, reply;
data.writeInterfaceToken(ISchedulingPolicyService::getInterfaceDescriptor());
data.writeInt32(enable);
- data.writeStrongBinder(IInterface::asBinder(client));
+ data.writeStrongBinder(client);
status_t status = remote()->transact(REQUEST_CPUSET_BOOST, data, &reply, 0);
if (status != NO_ERROR) {
return status;
diff --git a/media/utils/ISchedulingPolicyService.h b/media/utils/ISchedulingPolicyService.h
index e4f7c0d..6fa100a 100644
--- a/media/utils/ISchedulingPolicyService.h
+++ b/media/utils/ISchedulingPolicyService.h
@@ -29,7 +29,7 @@
virtual int requestPriority(/*pid_t*/int32_t pid, /*pid_t*/int32_t tid,
int32_t prio, bool isForApp, bool asynchronous) = 0;
- virtual int requestCpusetBoost(bool enable, const sp<IInterface>& client) = 0;
+ virtual int requestCpusetBoost(bool enable, const sp<IBinder>& client) = 0;
};
class BnSchedulingPolicyService : public BnInterface<ISchedulingPolicyService>
diff --git a/media/utils/MemoryLeakTrackUtil.cpp b/media/utils/MemoryLeakTrackUtil.cpp
index 2988b52..6166859 100644
--- a/media/utils/MemoryLeakTrackUtil.cpp
+++ b/media/utils/MemoryLeakTrackUtil.cpp
@@ -22,7 +22,7 @@
#include "media/MemoryLeakTrackUtil.h"
#include <sstream>
-#include <bionic_malloc.h>
+#include <bionic/malloc.h>
/*
* The code here originally resided in MediaPlayerService.cpp
diff --git a/media/utils/ProcessInfo.cpp b/media/utils/ProcessInfo.cpp
index 27f1a79..113e4a7 100644
--- a/media/utils/ProcessInfo.cpp
+++ b/media/utils/ProcessInfo.cpp
@@ -23,6 +23,7 @@
#include <binder/IPCThreadState.h>
#include <binder/IProcessInfoService.h>
#include <binder/IServiceManager.h>
+#include <private/android_filesystem_config.h>
namespace android {
@@ -55,8 +56,9 @@
bool ProcessInfo::isValidPid(int pid) {
int callingPid = IPCThreadState::self()->getCallingPid();
+ int callingUid = IPCThreadState::self()->getCallingUid();
// Trust it if this is called from the same process otherwise pid has to match the calling pid.
- return (callingPid == getpid()) || (callingPid == pid);
+ return (callingPid == getpid()) || (callingPid == pid) || (callingUid == AID_MEDIA);
}
ProcessInfo::~ProcessInfo() {}
diff --git a/media/utils/SchedulingPolicyService.cpp b/media/utils/SchedulingPolicyService.cpp
index 4e9792f..ad38862 100644
--- a/media/utils/SchedulingPolicyService.cpp
+++ b/media/utils/SchedulingPolicyService.cpp
@@ -59,7 +59,7 @@
return ret;
}
-int requestCpusetBoost(bool enable, const sp<IInterface> &client)
+int requestCpusetBoost(bool enable, const sp<IBinder> &client)
{
int ret;
sMutex.lock();
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index bc8fff6..7fd4d0a 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "ServiceUtilities"
+#include <audio_utils/clock.h>
#include <binder/AppOpsManager.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
@@ -24,6 +25,7 @@
#include <iterator>
#include <algorithm>
+#include <pwd.h>
/* When performing permission checks we do not use permission cache for
* runtime permissions (protection level dangerous) as they may change at
@@ -61,12 +63,12 @@
static bool checkRecordingInternal(const String16& opPackageName, pid_t pid,
uid_t uid, bool start) {
- // Okay to not track in app ops as audio server is us and if
+ // Okay to not track in app ops as audio server or media server is us and if
// device is rooted security model is considered compromised.
// system_server loses its RECORD_AUDIO permission when a secondary
// user is active, but it is a core system service so let it through.
// TODO(b/141210120): UserManager.DISALLOW_RECORD_AUDIO should not affect system user 0
- if (isAudioServerOrSystemServerOrRootUid(uid)) return true;
+ if (isAudioServerOrMediaServerOrSystemServerOrRootUid(uid)) return true;
// We specify a pid and uid here as mediaserver (aka MediaRecorder or StageFrightRecorder)
// may open a record track on behalf of a client. Note that pid may be a tid.
@@ -143,6 +145,15 @@
return ok;
}
+bool captureVoiceCommunicationOutputAllowed(pid_t pid, uid_t uid) {
+ if (isAudioServerOrRootUid(uid)) return true;
+ static const String16 sCaptureVoiceCommOutput(
+ "android.permission.CAPTURE_VOICE_COMMUNICATION_OUTPUT");
+ bool ok = PermissionCache::checkPermission(sCaptureVoiceCommOutput, pid, uid);
+ if (!ok) ALOGE("Request requires android.permission.CAPTURE_VOICE_COMMUNICATION_OUTPUT");
+ return ok;
+}
+
bool captureHotwordAllowed(const String16& opPackageName, pid_t pid, uid_t uid) {
// CAPTURE_AUDIO_HOTWORD permission implies RECORD_AUDIO permission
bool ok = recordingAllowed(opPackageName, pid, uid);
@@ -167,30 +178,33 @@
}
bool modifyAudioRoutingAllowed() {
+ return modifyAudioRoutingAllowed(
+ IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid());
+}
+
+bool modifyAudioRoutingAllowed(pid_t pid, uid_t uid) {
+ if (isAudioServerUid(IPCThreadState::self()->getCallingUid())) return true;
// IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
- bool ok = PermissionCache::checkCallingPermission(sModifyAudioRouting);
- if (!ok) ALOGE("android.permission.MODIFY_AUDIO_ROUTING");
+ bool ok = PermissionCache::checkPermission(sModifyAudioRouting, pid, uid);
+ if (!ok) ALOGE("%s(): android.permission.MODIFY_AUDIO_ROUTING denied for uid %d",
+ __func__, uid);
return ok;
}
bool modifyDefaultAudioEffectsAllowed() {
+ return modifyDefaultAudioEffectsAllowed(
+ IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid());
+}
+
+bool modifyDefaultAudioEffectsAllowed(pid_t pid, uid_t uid) {
+ if (isAudioServerUid(IPCThreadState::self()->getCallingUid())) return true;
+
static const String16 sModifyDefaultAudioEffectsAllowed(
"android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS");
// IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
- bool ok = PermissionCache::checkCallingPermission(sModifyDefaultAudioEffectsAllowed);
-
-#ifdef TARGET_ANDROID_THINGS
- if (!ok) {
- // Use a secondary permission on Android Things to allow a more lenient level of protection.
- static const String16 sModifyDefaultAudioEffectsAndroidThingsAllowed(
- "com.google.android.things.permission.MODIFY_DEFAULT_AUDIO_EFFECTS");
- ok = PermissionCache::checkCallingPermission(
- sModifyDefaultAudioEffectsAndroidThingsAllowed);
- }
- if (!ok) ALOGE("com.google.android.things.permission.MODIFY_DEFAULT_AUDIO_EFFECTS");
-#else
- if (!ok) ALOGE("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS");
-#endif
+ bool ok = PermissionCache::checkPermission(sModifyDefaultAudioEffectsAllowed, pid, uid);
+ ALOGE_IF(!ok, "%s(): android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS denied for uid %d",
+ __func__, uid);
return ok;
}
@@ -209,6 +223,25 @@
return ok;
}
+bool accessCallAudioAllowed(const String16& opPackageName, pid_t pid, uid_t uid) {
+ static const String16 sAccessCallAudio("android.permission.ACCESS_CALL_AUDIO");
+ PermissionController permissionController;
+ const String16 resolvedOpPackageName = resolveCallingPackage(
+ permissionController, opPackageName, uid);
+ if (resolvedOpPackageName.size() == 0) {
+ ALOGE("accessCallAudioAllowed - FAIL - package not found.");
+ return false;
+ }
+ AppOpsManager appOps;
+ const int32_t op = appOps.permissionToOpCode(sAccessCallAudio);
+ const int32_t opResult = appOps.noteOp(op, uid, resolvedOpPackageName);
+ if (opResult == PermissionController::MODE_DEFAULT) {
+ // Only allow in case this is a system app with the proper privilege permission
+ return PermissionCache::checkPermission(sAccessCallAudio, pid, uid);
+ }
+ return opResult == PermissionController::MODE_ALLOWED;
+}
+
// privileged behavior needed by Dialer, Settings, SetupWizard and CellBroadcastReceiver
bool bypassInterruptionPolicyAllowed(pid_t pid, uid_t uid) {
static const String16 sWriteSecureSettings("android.permission.WRITE_SECURE_SETTINGS");
@@ -236,37 +269,38 @@
off_t size = lseek(heap->getHeapID(), 0, SEEK_END);
lseek(heap->getHeapID(), 0, SEEK_SET);
- if (iMemory->pointer() == NULL || size < (off_t)iMemory->size()) {
+ if (iMemory->unsecurePointer() == NULL || size < (off_t)iMemory->size()) {
ALOGE("%s check failed: pointer %p size %zu fd size %u",
- __FUNCTION__, iMemory->pointer(), iMemory->size(), (uint32_t)size);
+ __FUNCTION__, iMemory->unsecurePointer(), iMemory->size(), (uint32_t)size);
return BAD_VALUE;
}
return NO_ERROR;
}
-sp<content::pm::IPackageManagerNative> MediaPackageManager::retreivePackageManager() {
+void MediaPackageManager::loadPackageManager() {
+ if (mPackageManager != nullptr) {
+ return;
+ }
const sp<IServiceManager> sm = defaultServiceManager();
if (sm == nullptr) {
ALOGW("%s: failed to retrieve defaultServiceManager", __func__);
- return nullptr;
+ return;
}
sp<IBinder> packageManager = sm->checkService(String16(nativePackageManagerName));
if (packageManager == nullptr) {
ALOGW("%s: failed to retrieve native package manager", __func__);
- return nullptr;
+ return;
}
- return interface_cast<content::pm::IPackageManagerNative>(packageManager);
+ mPackageManager = interface_cast<content::pm::IPackageManagerNative>(packageManager);
}
std::optional<bool> MediaPackageManager::doIsAllowed(uid_t uid) {
+ /** Can not fetch package manager at construction it may not yet be registered. */
+ loadPackageManager();
if (mPackageManager == nullptr) {
- /** Can not fetch package manager at construction it may not yet be registered. */
- mPackageManager = retreivePackageManager();
- if (mPackageManager == nullptr) {
- ALOGW("%s: Playback capture is denied as package manager is not reachable", __func__);
- return std::nullopt;
- }
+ ALOGW("%s: Playback capture is denied as package manager is not reachable", __func__);
+ return std::nullopt;
}
std::vector<std::string> packageNames;
@@ -326,4 +360,130 @@
}
}
+// How long we hold info before we re-fetch it (24 hours) if we found it previously.
+static constexpr nsecs_t INFO_EXPIRATION_NS = 24 * 60 * 60 * NANOS_PER_SECOND;
+// Maximum info records we retain before clearing everything.
+static constexpr size_t INFO_CACHE_MAX = 1000;
+
+// The original code is from MediaMetricsService.cpp.
+mediautils::UidInfo::Info mediautils::UidInfo::getInfo(uid_t uid)
+{
+ const nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
+ struct mediautils::UidInfo::Info info;
+ {
+ std::lock_guard _l(mLock);
+ auto it = mInfoMap.find(uid);
+ if (it != mInfoMap.end()) {
+ info = it->second;
+ ALOGV("%s: uid %d expiration %lld now %lld",
+ __func__, uid, (long long)info.expirationNs, (long long)now);
+ if (info.expirationNs <= now) {
+ // purge the stale entry and fall into re-fetching
+ ALOGV("%s: entry for uid %d expired, now %lld",
+ __func__, uid, (long long)now);
+ mInfoMap.erase(it);
+ info.uid = (uid_t)-1; // this is always fully overwritten
+ }
+ }
+ }
+
+ // if we did not find it in our map, look it up
+ if (info.uid == (uid_t)(-1)) {
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<content::pm::IPackageManagerNative> package_mgr;
+ if (sm.get() == nullptr) {
+ ALOGE("%s: Cannot find service manager", __func__);
+ } else {
+ sp<IBinder> binder = sm->getService(String16("package_native"));
+ if (binder.get() == nullptr) {
+ ALOGE("%s: Cannot find package_native", __func__);
+ } else {
+ package_mgr = interface_cast<content::pm::IPackageManagerNative>(binder);
+ }
+ }
+
+ // find package name
+ std::string pkg;
+ if (package_mgr != nullptr) {
+ std::vector<std::string> names;
+ binder::Status status = package_mgr->getNamesForUids({(int)uid}, &names);
+ if (!status.isOk()) {
+ ALOGE("%s: getNamesForUids failed: %s",
+ __func__, status.exceptionMessage().c_str());
+ } else {
+ if (!names[0].empty()) {
+ pkg = names[0].c_str();
+ }
+ }
+ }
+
+ if (pkg.empty()) {
+ struct passwd pw{}, *result;
+ char buf[8192]; // extra buffer space - should exceed what is
+ // required in struct passwd_pw (tested),
+ // and even then this is only used in backup
+ // when the package manager is unavailable.
+ if (getpwuid_r(uid, &pw, buf, sizeof(buf), &result) == 0
+ && result != nullptr
+ && result->pw_name != nullptr) {
+ pkg = result->pw_name;
+ }
+ }
+
+ // strip any leading "shared:" strings that came back
+ if (pkg.compare(0, 7, "shared:") == 0) {
+ pkg.erase(0, 7);
+ }
+
+ // determine how pkg was installed and the versionCode
+ std::string installer;
+ int64_t versionCode = 0;
+ bool notFound = false;
+ if (pkg.empty()) {
+ pkg = std::to_string(uid); // not found
+ notFound = true;
+ } else if (strchr(pkg.c_str(), '.') == nullptr) {
+ // not of form 'com.whatever...'; assume internal
+ // so we don't need to look it up in package manager.
+ } else if (strncmp(pkg.c_str(), "android.", 8) == 0) {
+ // android.* packages are assumed fine
+ } else if (package_mgr.get() != nullptr) {
+ String16 pkgName16(pkg.c_str());
+ binder::Status status = package_mgr->getInstallerForPackage(pkgName16, &installer);
+ if (!status.isOk()) {
+ ALOGE("%s: getInstallerForPackage failed: %s",
+ __func__, status.exceptionMessage().c_str());
+ }
+
+ // skip if we didn't get an installer
+ if (status.isOk()) {
+ status = package_mgr->getVersionCodeForPackage(pkgName16, &versionCode);
+ if (!status.isOk()) {
+ ALOGE("%s: getVersionCodeForPackage failed: %s",
+ __func__, status.exceptionMessage().c_str());
+ }
+ }
+
+ ALOGV("%s: package '%s' installed by '%s' versioncode %lld",
+ __func__, pkg.c_str(), installer.c_str(), (long long)versionCode);
+ }
+
+ // add it to the map, to save a subsequent lookup
+ std::lock_guard _l(mLock);
+ // first clear if we have too many cached elements. This would be rare.
+ if (mInfoMap.size() >= INFO_CACHE_MAX) mInfoMap.clear();
+
+ // always overwrite
+ info.uid = uid;
+ info.package = std::move(pkg);
+ info.installer = std::move(installer);
+ info.versionCode = versionCode;
+ info.expirationNs = now + (notFound ? 0 : INFO_EXPIRATION_NS);
+ ALOGV("%s: adding uid %d package '%s' expirationNs: %lld",
+ __func__, uid, info.package.c_str(), (long long)info.expirationNs);
+ mInfoMap[uid] = info;
+ }
+ return info;
+}
+
} // namespace android
diff --git a/media/utils/TimeCheck.cpp b/media/utils/TimeCheck.cpp
index f16776f..4a3e470 100644
--- a/media/utils/TimeCheck.cpp
+++ b/media/utils/TimeCheck.cpp
@@ -14,13 +14,50 @@
* limitations under the License.
*/
+#define LOG_TAG "TimeCheck"
#include <utils/Log.h>
-#include <media/TimeCheck.h>
-#include <media/EventLog.h>
+#include <mediautils/TimeCheck.h>
+#include <mediautils/EventLog.h>
+#include "debuggerd/handler.h"
namespace android {
+// Audio HAL server pids vector used to generate audio HAL processes tombstone
+// when audioserver watchdog triggers.
+// We use a lockless storage to avoid potential deadlocks in the context of watchdog
+// trigger.
+// Protection again simultaneous writes is not needed given one update takes place
+// during AudioFlinger construction and other comes necessarily later once the IAudioFlinger
+// interface is available.
+// The use of an atomic index just guaranties that current vector is fully initialized
+// when read.
+/* static */
+void TimeCheck::accessAudioHalPids(std::vector<pid_t>* pids, bool update) {
+ static constexpr int kNumAudioHalPidsVectors = 3;
+ static std::vector<pid_t> audioHalPids[kNumAudioHalPidsVectors];
+ static std::atomic<int> curAudioHalPids = 0;
+
+ if (update) {
+ audioHalPids[(curAudioHalPids + 1) % kNumAudioHalPidsVectors] = *pids;
+ curAudioHalPids++;
+ } else {
+ *pids = audioHalPids[curAudioHalPids];
+ }
+}
+
+/* static */
+void TimeCheck::setAudioHalPids(const std::vector<pid_t>& pids) {
+ accessAudioHalPids(&(const_cast<std::vector<pid_t>&>(pids)), true);
+}
+
+/* static */
+std::vector<pid_t> TimeCheck::getAudioHalPids() {
+ std::vector<pid_t> pids;
+ accessAudioHalPids(&pids, false);
+ return pids;
+}
+
/* static */
sp<TimeCheck::TimeCheckThread> TimeCheck::getTimeCheckThread()
{
@@ -83,6 +120,18 @@
status = mCond.waitRelative(mMutex, waitTimeNs);
}
if (status != NO_ERROR) {
+ // Generate audio HAL processes tombstones and allow time to complete
+ // before forcing restart
+ std::vector<pid_t> pids = getAudioHalPids();
+ if (pids.size() != 0) {
+ for (const auto& pid : pids) {
+ ALOGI("requesting tombstone for pid: %d", pid);
+ sigqueue(pid, DEBUGGER_SIGNAL, {.sival_int = 0});
+ }
+ sleep(1);
+ } else {
+ ALOGI("No HAL process pid available, skipping tombstones");
+ }
LOG_EVENT_STRING(LOGTAG_AUDIO_BINDER_TIMEOUT, tag);
LOG_ALWAYS_FATAL("TimeCheck timeout for %s", tag);
}
diff --git a/media/utils/include/mediautils/SchedulingPolicyService.h b/media/utils/include/mediautils/SchedulingPolicyService.h
index a33539f..546cec5 100644
--- a/media/utils/include/mediautils/SchedulingPolicyService.h
+++ b/media/utils/include/mediautils/SchedulingPolicyService.h
@@ -21,7 +21,7 @@
namespace android {
-class IInterface;
+class IBinder;
// Request elevated priority for thread tid, whose thread group leader must be pid.
// The priority parameter is currently restricted to either 1 or 2.
// The asynchronous parameter should be 'true' to return immediately,
@@ -35,7 +35,7 @@
// for the server to receive death notifications. When 'enable' is 'false', server
// will attempt to move media.codec process back to the original cpuset, and
// 'client' is ignored in this case.
-int requestCpusetBoost(bool enable, const sp<IInterface> &client);
+int requestCpusetBoost(bool enable, const sp<IBinder> &client);
} // namespace android
diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h
index e1089d5..060e849 100644
--- a/media/utils/include/mediautils/ServiceUtilities.h
+++ b/media/utils/include/mediautils/ServiceUtilities.h
@@ -28,6 +28,7 @@
#include <map>
#include <optional>
#include <string>
+#include <unordered_map>
#include <vector>
namespace android {
@@ -58,10 +59,11 @@
return multiuser_get_app_id(uid) == AID_SYSTEM || uid == AID_AUDIOSERVER;
}
-// used for calls that should come from system_server or audio_server and
+// used for calls that should come from system_server or audio_server or media server and
// include AID_ROOT for command-line tests.
-static inline bool isAudioServerOrSystemServerOrRootUid(uid_t uid) {
- return multiuser_get_app_id(uid) == AID_SYSTEM || uid == AID_AUDIOSERVER || uid == AID_ROOT;
+static inline bool isAudioServerOrMediaServerOrSystemServerOrRootUid(uid_t uid) {
+ return multiuser_get_app_id(uid) == AID_SYSTEM || uid == AID_AUDIOSERVER
+ || uid == AID_MEDIA || uid == AID_ROOT;
}
// Mediaserver may forward the client PID and UID as part of a binder interface call;
@@ -81,13 +83,17 @@
void finishRecording(const String16& opPackageName, uid_t uid);
bool captureAudioOutputAllowed(pid_t pid, uid_t uid);
bool captureMediaOutputAllowed(pid_t pid, uid_t uid);
+bool captureVoiceCommunicationOutputAllowed(pid_t pid, uid_t uid);
bool captureHotwordAllowed(const String16& opPackageName, pid_t pid, uid_t uid);
bool settingsAllowed();
bool modifyAudioRoutingAllowed();
+bool modifyAudioRoutingAllowed(pid_t pid, uid_t uid);
bool modifyDefaultAudioEffectsAllowed();
+bool modifyDefaultAudioEffectsAllowed(pid_t pid, uid_t uid);
bool dumpAllowed();
bool modifyPhoneStateAllowed(pid_t pid, uid_t uid);
bool bypassInterruptionPolicyAllowed(pid_t pid, uid_t uid);
+bool accessCallAudioAllowed(const String16& opPackageName, pid_t pid, uid_t uid);
status_t checkIMemory(const sp<IMemory>& iMemory);
@@ -105,7 +111,7 @@
private:
static constexpr const char* nativePackageManagerName = "package_native";
std::optional<bool> doIsAllowed(uid_t uid);
- sp<content::pm::IPackageManagerNative> retreivePackageManager();
+ void loadPackageManager();
sp<content::pm::IPackageManagerNative> mPackageManager; // To check apps manifest
uint_t mPackageManagerErrors = 0;
struct Package {
@@ -115,6 +121,40 @@
using Packages = std::vector<Package>;
std::map<uid_t, Packages> mDebugLog;
};
-}
+
+namespace mediautils {
+
+/**
+ * This class is used to retrieve (and cache) package information
+ * for a given uid.
+ */
+class UidInfo {
+public:
+ struct Info {
+ uid_t uid = -1; // uid used for lookup.
+ std::string package; // package name.
+ std::string installer; // installer for the package (e.g. preload, play store).
+ int64_t versionCode = 0; // reported version code.
+ int64_t expirationNs = 0; // after this time in SYSTEM_TIME_REALTIME we refetch.
+ };
+
+ /**
+ * Returns the package information for a UID.
+ *
+ * The package name will be the uid if we cannot find the associated name.
+ *
+ * \param uid is the uid of the app or service.
+ */
+ Info getInfo(uid_t uid);
+
+private:
+ std::mutex mLock;
+ // TODO: use concurrent hashmap with striped lock.
+ std::unordered_map<uid_t, Info> mInfoMap; // GUARDED_BY(mLock)
+};
+
+} // namespace mediautils
+
+} // namespace android
#endif // ANDROID_MEDIAUTILS_SERVICEUTILITIES_H
diff --git a/media/utils/include/mediautils/TimeCheck.h b/media/utils/include/mediautils/TimeCheck.h
index 6c5f656..5ba6d7c 100644
--- a/media/utils/include/mediautils/TimeCheck.h
+++ b/media/utils/include/mediautils/TimeCheck.h
@@ -20,7 +20,7 @@
#include <utils/KeyedVector.h>
#include <utils/Thread.h>
-
+#include <vector>
namespace android {
@@ -35,6 +35,8 @@
TimeCheck(const char *tag, uint32_t timeoutMs = kDefaultTimeOutMs);
~TimeCheck();
+ static void setAudioHalPids(const std::vector<pid_t>& pids);
+ static std::vector<pid_t> getAudioHalPids();
private:
@@ -63,6 +65,7 @@
};
static sp<TimeCheckThread> getTimeCheckThread();
+ static void accessAudioHalPids(std::vector<pid_t>* pids, bool update);
const nsecs_t mEndTimeNs;
};
diff --git a/services/audioflinger/Android.bp b/services/audioflinger/Android.bp
index 96ad54b..3873600 100644
--- a/services/audioflinger/Android.bp
+++ b/services/audioflinger/Android.bp
@@ -9,6 +9,7 @@
"AudioStreamOut.cpp",
"AudioWatchdog.cpp",
"BufLog.cpp",
+ "DeviceEffectManager.cpp",
"Effects.cpp",
"FastCapture.cpp",
"FastCaptureDumpState.cpp",
@@ -34,6 +35,7 @@
],
shared_libs: [
+ "libaudiofoundation",
"libaudiohal",
"libaudioprocessing",
"libaudiospdif",
@@ -60,6 +62,11 @@
"libsndfile",
],
+ header_libs: [
+ "libaudiohal_headers",
+ "libmedia_headers",
+ ],
+
cflags: [
"-DSTATE_QUEUE_INSTANTIATIONS=\"StateQueueInstantiations.cpp\"",
"-fvisibility=hidden",
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 8bbdc69..ecda56b 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -19,6 +19,9 @@
#define LOG_TAG "AudioFlinger"
//#define LOG_NDEBUG 0
+// Define AUDIO_ARRAYS_STATIC_CHECK to check all audio arrays are correct
+#define AUDIO_ARRAYS_STATIC_CHECK 1
+
#include "Configuration.h"
#include <dirent.h>
#include <math.h>
@@ -26,6 +29,7 @@
#include <string>
#include <sys/time.h>
#include <sys/resource.h>
+#include <thread>
#include <android/os/IExternalVibratorService.h>
#include <binder/IPCThreadState.h>
@@ -37,6 +41,7 @@
#include <media/audiohal/DevicesFactoryHalInterface.h>
#include <media/audiohal/EffectsFactoryHalInterface.h>
#include <media/AudioParameter.h>
+#include <media/MediaMetricsItem.h>
#include <media/TypeConverter.h>
#include <memunreachable/memunreachable.h>
#include <utils/String16.h>
@@ -67,6 +72,7 @@
#include <media/nbaio/PipeReader.h>
#include <mediautils/BatteryNotifier.h>
#include <mediautils/ServiceUtilities.h>
+#include <mediautils/TimeCheck.h>
#include <private/android_filesystem_config.h>
//#define BUFLOG_NDEBUG 0
@@ -139,6 +145,19 @@
return sExternalVibratorService;
}
+class DevicesFactoryHalCallbackImpl : public DevicesFactoryHalCallback {
+ public:
+ void onNewDevicesAvailable() override {
+ // Start a detached thread to execute notification in parallel.
+ // This is done to prevent mutual blocking of audio_flinger and
+ // audio_policy services during system initialization.
+ std::thread notifier([]() {
+ AudioSystem::onNewAudioModulesAvailable();
+ });
+ notifier.detach();
+ }
+};
+
// ----------------------------------------------------------------------------
std::string formatToString(audio_format_t format) {
@@ -166,6 +185,7 @@
mClientSharedHeapSize(kMinimumClientSharedHeapSizeBytes),
mGlobalEffectEnableTime(0),
mPatchPanel(this),
+ mDeviceEffectManager(this),
mSystemReady(false)
{
// unsigned instead of audio_unique_id_use_t, because ++ operator is unavailable for enum
@@ -190,6 +210,14 @@
mEffectsFactoryHal = EffectsFactoryHalInterface::create();
mMediaLogNotifier->run("MediaLogNotifier");
+ std::vector<pid_t> halPids;
+ mDevicesFactoryHal->getHalPids(&halPids);
+ TimeCheck::setAudioHalPids(halPids);
+
+ // Notify that we have started (also called when audioserver service restarts)
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR)
+ .record();
}
void AudioFlinger::onFirstRef()
@@ -213,6 +241,14 @@
mMode = AUDIO_MODE_NORMAL;
gAudioFlinger = this;
+
+ mDevicesFactoryHalCallback = new DevicesFactoryHalCallbackImpl;
+ mDevicesFactoryHal->setCallbackOnce(mDevicesFactoryHalCallback);
+}
+
+status_t AudioFlinger::setAudioHalPids(const std::vector<pid_t>& pids) {
+ TimeCheck::setAudioHalPids(pids);
+ return NO_ERROR;
}
AudioFlinger::~AudioFlinger()
@@ -307,7 +343,7 @@
ret = AudioSystem::getOutputForAttr(&localAttr, &io,
actualSessionId,
&streamType, client.clientPid, client.clientUid,
- &fullConfig,
+ client.packageName, &fullConfig,
(audio_output_flags_t)(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ |
AUDIO_OUTPUT_FLAG_DIRECT),
deviceId, &portId, &secondaryOutputs);
@@ -335,6 +371,9 @@
thread->configure(&localAttr, streamType, actualSessionId, callback, *deviceId, portId);
*handle = portId;
*sessionId = actualSessionId;
+ config->sample_rate = thread->sampleRate();
+ config->channel_mask = thread->channelMask();
+ config->format = thread->format();
} else {
if (direction == MmapStreamInterface::DIRECTION_OUTPUT) {
AudioSystem::releaseOutput(portId);
@@ -370,6 +409,24 @@
}
}
+status_t AudioFlinger::addEffectToHal(audio_port_handle_t deviceId,
+ audio_module_handle_t hwModuleId, sp<EffectHalInterface> effect) {
+ AudioHwDevice *audioHwDevice = mAudioHwDevs.valueFor(hwModuleId);
+ if (audioHwDevice == nullptr) {
+ return NO_INIT;
+ }
+ return audioHwDevice->hwDevice()->addDeviceEffect(deviceId, effect);
+}
+
+status_t AudioFlinger::removeEffectFromHal(audio_port_handle_t deviceId,
+ audio_module_handle_t hwModuleId, sp<EffectHalInterface> effect) {
+ AudioHwDevice *audioHwDevice = mAudioHwDevs.valueFor(hwModuleId);
+ if (audioHwDevice == nullptr) {
+ return NO_INIT;
+ }
+ return audioHwDevice->hwDevice()->removeDeviceEffect(deviceId, effect);
+}
+
static const char * const audio_interfaces[] = {
AUDIO_HARDWARE_MODULE_ID_PRIMARY,
AUDIO_HARDWARE_MODULE_ID_A2DP,
@@ -378,7 +435,7 @@
AudioHwDevice* AudioFlinger::findSuitableHwDev_l(
audio_module_handle_t module,
- audio_devices_t devices)
+ audio_devices_t deviceType)
{
// if module is 0, the request comes from an old policy manager and we should load
// well known modules
@@ -393,7 +450,7 @@
sp<DeviceHalInterface> dev = audioHwDevice->hwDevice();
uint32_t supportedDevices;
if (dev->getSupportedDevices(&supportedDevices) == OK &&
- (supportedDevices & devices) == devices) {
+ (supportedDevices & deviceType) == deviceType) {
return audioHwDevice;
}
}
@@ -410,31 +467,32 @@
void AudioFlinger::dumpClients(int fd, const Vector<String16>& args __unused)
{
- const size_t SIZE = 256;
- char buffer[SIZE];
String8 result;
result.append("Clients:\n");
for (size_t i = 0; i < mClients.size(); ++i) {
sp<Client> client = mClients.valueAt(i).promote();
if (client != 0) {
- snprintf(buffer, SIZE, " pid: %d\n", client->pid());
- result.append(buffer);
+ result.appendFormat(" pid: %d\n", client->pid());
}
}
result.append("Notification Clients:\n");
+ result.append(" pid uid name\n");
for (size_t i = 0; i < mNotificationClients.size(); ++i) {
- snprintf(buffer, SIZE, " pid: %d\n", mNotificationClients.keyAt(i));
- result.append(buffer);
+ const pid_t pid = mNotificationClients[i]->getPid();
+ const uid_t uid = mNotificationClients[i]->getUid();
+ const mediautils::UidInfo::Info info = mUidInfo.getInfo(uid);
+ result.appendFormat("%6d %6u %s\n", pid, uid, info.package.c_str());
}
result.append("Global session refs:\n");
- result.append(" session pid count\n");
+ result.append(" session cnt pid uid name\n");
for (size_t i = 0; i < mAudioSessionRefs.size(); i++) {
AudioSessionRef *r = mAudioSessionRefs[i];
- snprintf(buffer, SIZE, " %7d %5d %5d\n", r->mSessionid, r->mPid, r->mCnt);
- result.append(buffer);
+ const mediautils::UidInfo::Info info = mUidInfo.getInfo(r->mUid);
+ result.appendFormat(" %7d %4d %7d %6u %s\n", r->mSessionid, r->mCnt, r->mPid,
+ r->mUid, info.package.c_str());
}
write(fd, result.string(), result.size());
}
@@ -546,6 +604,8 @@
mPatchPanel.dump(fd);
+ mDeviceEffectManager.dump(fd);
+
// dump external setParameters
auto dumpLogger = [fd](SimpleLog& logger, const char* name) {
dprintf(fd, "\n%s setParameters:\n", name);
@@ -652,7 +712,7 @@
return new NBLog::Writer();
}
success:
- NBLog::Shared *sharedRawPtr = (NBLog::Shared *) shared->pointer();
+ NBLog::Shared *sharedRawPtr = (NBLog::Shared *) shared->unsecurePointer();
new((void *) sharedRawPtr) NBLog::Shared(); // placement new here, but the corresponding
// explicit destructor not needed since it is POD
sMediaLogService->registerWriter(shared, size, name);
@@ -723,8 +783,9 @@
output.outputId = AUDIO_IO_HANDLE_NONE;
output.selectedDeviceId = input.selectedDeviceId;
lStatus = AudioSystem::getOutputForAttr(&localAttr, &output.outputId, sessionId, &streamType,
- clientPid, clientUid, &input.config, input.flags,
- &output.selectedDeviceId, &portId, &secondaryOutputs);
+ clientPid, clientUid, input.opPackageName,
+ &input.config, input.flags, &output.selectedDeviceId,
+ &portId, &secondaryOutputs);
if (lStatus != NO_ERROR || output.outputId == AUDIO_IO_HANDLE_NONE) {
ALOGE("createTrack() getOutputForAttr() return error %d or invalid output handle", lStatus);
@@ -789,7 +850,7 @@
input.notificationsPerBuffer, input.speed,
input.sharedBuffer, sessionId, &output.flags,
callingPid, input.clientInfo.clientTid, clientUid,
- &lStatus, portId);
+ &lStatus, portId, input.audioTrackCallback);
LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (track == 0));
// we don't abort yet if lStatus != NO_ERROR; there is still work to be done regardless
@@ -1159,16 +1220,16 @@
return mute;
}
-void AudioFlinger::setRecordSilenced(uid_t uid, bool silenced)
+void AudioFlinger::setRecordSilenced(audio_port_handle_t portId, bool silenced)
{
- ALOGV("AudioFlinger::setRecordSilenced(uid:%d, silenced:%d)", uid, silenced);
+ ALOGV("AudioFlinger::setRecordSilenced(portId:%d, silenced:%d)", portId, silenced);
AutoMutex lock(mLock);
for (size_t i = 0; i < mRecordThreads.size(); i++) {
- mRecordThreads[i]->setRecordSilenced(uid, silenced);
+ mRecordThreads[i]->setRecordSilenced(portId, silenced);
}
for (size_t i = 0; i < mMmapThreads.size(); i++) {
- mMmapThreads[i]->setRecordSilenced(uid, silenced);
+ mMmapThreads[i]->setRecordSilenced(portId, silenced);
}
}
@@ -1354,6 +1415,13 @@
}
}
+void AudioFlinger::updateOutDevicesForRecordThreads_l(const DeviceDescriptorBaseVector& devices)
+{
+ for (size_t i = 0; i < mRecordThreads.size(); i++) {
+ mRecordThreads.valueAt(i)->updateOutDevices(devices);
+ }
+}
+
// forwardAudioHwSyncToDownstreamPatches_l() must be called with AudioFlinger::mLock held
void AudioFlinger::forwardParametersToDownstreamPatches_l(
audio_io_handle_t upStream, const String8& keyValuePairs,
@@ -1384,8 +1452,8 @@
String8(AudioParameter::keyFrameCount),
String8(AudioParameter::keyInputSource),
String8(AudioParameter::keyMonoOutput),
- String8(AudioParameter::keyStreamConnect),
- String8(AudioParameter::keyStreamDisconnect),
+ String8(AudioParameter::keyDeviceConnect),
+ String8(AudioParameter::keyDeviceDisconnect),
String8(AudioParameter::keyStreamSupportedFormats),
String8(AudioParameter::keyStreamSupportedChannels),
String8(AudioParameter::keyStreamSupportedSamplingRates),
@@ -1563,40 +1631,64 @@
AutoMutex lock(mHardwareLock);
mHardwareStatus = AUDIO_HW_GET_INPUT_BUFFER_SIZE;
- audio_config_t config, proposed;
- memset(&proposed, 0, sizeof(proposed));
- proposed.sample_rate = sampleRate;
- proposed.channel_mask = channelMask;
- proposed.format = format;
sp<DeviceHalInterface> dev = mPrimaryHardwareDev->hwDevice();
- size_t frames;
- for (;;) {
- // Note: config is currently a const parameter for get_input_buffer_size()
- // but we use a copy from proposed in case config changes from the call.
- config = proposed;
- status_t result = dev->getInputBufferSize(&config, &frames);
- if (result == OK && frames != 0) {
- break; // hal success, config is the result
- }
- // change one parameter of the configuration each iteration to a more "common" value
- // to see if the device will support it.
- if (proposed.format != AUDIO_FORMAT_PCM_16_BIT) {
- proposed.format = AUDIO_FORMAT_PCM_16_BIT;
- } else if (proposed.sample_rate != 44100) { // 44.1 is claimed as must in CDD as well as
- proposed.sample_rate = 44100; // legacy AudioRecord.java. TODO: Query hw?
- } else {
- ALOGW("getInputBufferSize failed with minimum buffer size sampleRate %u, "
- "format %#x, channelMask 0x%X",
- sampleRate, format, channelMask);
- break; // retries failed, break out of loop with frames == 0.
- }
- }
+ std::vector<audio_channel_mask_t> channelMasks = {channelMask};
+ if (channelMask != AUDIO_CHANNEL_IN_MONO)
+ channelMasks.push_back(AUDIO_CHANNEL_IN_MONO);
+ if (channelMask != AUDIO_CHANNEL_IN_STEREO)
+ channelMasks.push_back(AUDIO_CHANNEL_IN_STEREO);
+
+ std::vector<audio_format_t> formats = {format};
+ if (format != AUDIO_FORMAT_PCM_16_BIT)
+ formats.push_back(AUDIO_FORMAT_PCM_16_BIT);
+
+ std::vector<uint32_t> sampleRates = {sampleRate};
+ static const uint32_t SR_44100 = 44100;
+ static const uint32_t SR_48000 = 48000;
+
+ if (sampleRate != SR_48000)
+ sampleRates.push_back(SR_48000);
+ if (sampleRate != SR_44100)
+ sampleRates.push_back(SR_44100);
+
mHardwareStatus = AUDIO_HW_IDLE;
- if (frames > 0 && config.sample_rate != sampleRate) {
- frames = destinationFramesPossible(frames, sampleRate, config.sample_rate);
+
+ // Change parameters of the configuration each iteration until we find a
+ // configuration that the device will support.
+ audio_config_t config = AUDIO_CONFIG_INITIALIZER;
+ for (auto testChannelMask : channelMasks) {
+ config.channel_mask = testChannelMask;
+ for (auto testFormat : formats) {
+ config.format = testFormat;
+ for (auto testSampleRate : sampleRates) {
+ config.sample_rate = testSampleRate;
+
+ size_t bytes = 0;
+ status_t result = dev->getInputBufferSize(&config, &bytes);
+ if (result != OK || bytes == 0) {
+ continue;
+ }
+
+ if (config.sample_rate != sampleRate || config.channel_mask != channelMask ||
+ config.format != format) {
+ uint32_t dstChannelCount = audio_channel_count_from_in_mask(channelMask);
+ uint32_t srcChannelCount =
+ audio_channel_count_from_in_mask(config.channel_mask);
+ size_t srcFrames =
+ bytes / audio_bytes_per_frame(srcChannelCount, config.format);
+ size_t dstFrames = destinationFramesPossible(
+ srcFrames, config.sample_rate, sampleRate);
+ bytes = dstFrames * audio_bytes_per_frame(dstChannelCount, format);
+ }
+ return bytes;
+ }
+ }
}
- return frames; // may be converted to bytes at the Java level.
+
+ ALOGW("getInputBufferSize failed with minimum buffer size sampleRate %u, "
+ "format %#x, channelMask %#x",sampleRate, format, channelMask);
+ return 0;
}
uint32_t AudioFlinger::getInputFramesLost(audio_io_handle_t ioHandle) const
@@ -1651,13 +1743,16 @@
return;
}
pid_t pid = IPCThreadState::self()->getCallingPid();
+ const uid_t uid = IPCThreadState::self()->getCallingUid();
{
Mutex::Autolock _cl(mClientLock);
if (mNotificationClients.indexOfKey(pid) < 0) {
sp<NotificationClient> notificationClient = new NotificationClient(this,
client,
- pid);
- ALOGV("registerClient() client %p, pid %d", notificationClient.get(), pid);
+ pid,
+ uid);
+ ALOGV("registerClient() client %p, pid %d, uid %u",
+ notificationClient.get(), pid, uid);
mNotificationClients.add(pid, notificationClient);
@@ -1797,8 +1892,9 @@
AudioFlinger::NotificationClient::NotificationClient(const sp<AudioFlinger>& audioFlinger,
const sp<IAudioFlingerClient>& client,
- pid_t pid)
- : mAudioFlinger(audioFlinger), mPid(pid), mAudioFlingerClient(client)
+ pid_t pid,
+ uid_t uid)
+ : mAudioFlinger(audioFlinger), mPid(pid), mUid(uid), mAudioFlingerClient(client)
{
}
@@ -2301,13 +2397,13 @@
sp<AudioFlinger::ThreadBase> AudioFlinger::openOutput_l(audio_module_handle_t module,
- audio_io_handle_t *output,
- audio_config_t *config,
- audio_devices_t devices,
- const String8& address,
- audio_output_flags_t flags)
+ audio_io_handle_t *output,
+ audio_config_t *config,
+ audio_devices_t deviceType,
+ const String8& address,
+ audio_output_flags_t flags)
{
- AudioHwDevice *outHwDev = findSuitableHwDev_l(module, devices);
+ AudioHwDevice *outHwDev = findSuitableHwDev_l(module, deviceType);
if (outHwDev == NULL) {
return 0;
}
@@ -2348,7 +2444,7 @@
status_t status = outHwDev->openOutputStream(
&outputStream,
*output,
- devices,
+ deviceType,
flags,
config,
address.string());
@@ -2358,8 +2454,7 @@
if (status == NO_ERROR) {
if (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
sp<MmapPlaybackThread> thread =
- new MmapPlaybackThread(this, *output, outHwDev, outputStream,
- devices, AUDIO_DEVICE_NONE, mSystemReady);
+ new MmapPlaybackThread(this, *output, outHwDev, outputStream, mSystemReady);
mMmapThreads.add(*output, thread);
ALOGV("openOutput_l() created mmap playback thread: ID %d thread %p",
*output, thread.get());
@@ -2367,17 +2462,17 @@
} else {
sp<PlaybackThread> thread;
if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
- thread = new OffloadThread(this, outputStream, *output, devices, mSystemReady);
+ thread = new OffloadThread(this, outputStream, *output, mSystemReady);
ALOGV("openOutput_l() created offload output: ID %d thread %p",
*output, thread.get());
} else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT)
|| !isValidPcmSinkFormat(config->format)
|| !isValidPcmSinkChannelMask(config->channel_mask)) {
- thread = new DirectOutputThread(this, outputStream, *output, devices, mSystemReady);
+ thread = new DirectOutputThread(this, outputStream, *output, mSystemReady);
ALOGV("openOutput_l() created direct output: ID %d thread %p",
*output, thread.get());
} else {
- thread = new MixerThread(this, outputStream, *output, devices, mSystemReady);
+ thread = new MixerThread(this, outputStream, *output, mSystemReady);
ALOGV("openOutput_l() created mixer output: ID %d thread %p",
*output, thread.get());
}
@@ -2393,27 +2488,29 @@
status_t AudioFlinger::openOutput(audio_module_handle_t module,
audio_io_handle_t *output,
audio_config_t *config,
- audio_devices_t *devices,
- const String8& address,
+ const sp<DeviceDescriptorBase>& device,
uint32_t *latencyMs,
audio_output_flags_t flags)
{
- ALOGI("openOutput() this %p, module %d Device %#x, SamplingRate %d, Format %#08x, "
+ ALOGI("openOutput() this %p, module %d Device %s, SamplingRate %d, Format %#08x, "
"Channels %#x, flags %#x",
this, module,
- (devices != NULL) ? *devices : 0,
+ device->toString().c_str(),
config->sample_rate,
config->format,
config->channel_mask,
flags);
- if (devices == NULL || *devices == AUDIO_DEVICE_NONE) {
+ audio_devices_t deviceType = device->type();
+ const String8 address = String8(device->address().c_str());
+
+ if (deviceType == AUDIO_DEVICE_NONE) {
return BAD_VALUE;
}
Mutex::Autolock _l(mLock);
- sp<ThreadBase> thread = openOutput_l(module, output, config, *devices, address, flags);
+ sp<ThreadBase> thread = openOutput_l(module, output, config, deviceType, address, flags);
if (thread != 0) {
if ((flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) == 0) {
PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
@@ -2629,9 +2726,6 @@
return 0;
}
- // Some flags are specific to framework and must not leak to the HAL.
- flags = static_cast<audio_input_flags_t>(flags & ~AUDIO_INPUT_FRAMEWORK_FLAGS);
-
// Audio Policy can request a specific handle for hardware hotword.
// The goal here is not to re-open an already opened input.
// It is to use a pre-assigned I/O handle.
@@ -2683,9 +2777,7 @@
AudioStreamIn *inputStream = new AudioStreamIn(inHwDev, inStream, flags);
if ((flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0) {
sp<MmapCaptureThread> thread =
- new MmapCaptureThread(this, *input,
- inHwDev, inputStream,
- primaryOutputDevice_l(), devices, mSystemReady);
+ new MmapCaptureThread(this, *input, inHwDev, inputStream, mSystemReady);
mMmapThreads.add(*input, thread);
ALOGV("openInput_l() created mmap capture thread: ID %d thread %p", *input,
thread.get());
@@ -2694,13 +2786,7 @@
// Start record thread
// RecordThread requires both input and output device indication to forward to audio
// pre processing modules
- sp<RecordThread> thread = new RecordThread(this,
- inputStream,
- *input,
- primaryOutputDevice_l(),
- devices,
- mSystemReady
- );
+ sp<RecordThread> thread = new RecordThread(this, inputStream, *input, mSystemReady);
mRecordThreads.add(*input, thread);
ALOGV("openInput_l() created record thread: ID %d thread %p", *input, thread.get());
return thread;
@@ -2835,14 +2921,18 @@
return nextUniqueId(use);
}
-void AudioFlinger::acquireAudioSessionId(audio_session_t audioSession, pid_t pid)
+void AudioFlinger::acquireAudioSessionId(
+ audio_session_t audioSession, pid_t pid, uid_t uid)
{
Mutex::Autolock _l(mLock);
pid_t caller = IPCThreadState::self()->getCallingPid();
ALOGV("acquiring %d from %d, for %d", audioSession, caller, pid);
const uid_t callerUid = IPCThreadState::self()->getCallingUid();
- if (pid != -1 && isAudioServerUid(callerUid)) { // check must match releaseAudioSessionId()
- caller = pid;
+ if (pid != (pid_t)-1 && isAudioServerOrMediaServerUid(callerUid)) {
+ caller = pid; // check must match releaseAudioSessionId()
+ }
+ if (uid == (uid_t)-1 || !isAudioServerOrMediaServerUid(callerUid)) {
+ uid = callerUid;
}
{
@@ -2866,7 +2956,7 @@
return;
}
}
- mAudioSessionRefs.push(new AudioSessionRef(audioSession, caller));
+ mAudioSessionRefs.push(new AudioSessionRef(audioSession, caller, uid));
ALOGV(" added new entry for %d", audioSession);
}
@@ -2878,8 +2968,8 @@
pid_t caller = IPCThreadState::self()->getCallingPid();
ALOGV("releasing %d from %d for %d", audioSession, caller, pid);
const uid_t callerUid = IPCThreadState::self()->getCallingUid();
- if (pid != -1 && isAudioServerUid(callerUid)) { // check must match acquireAudioSessionId()
- caller = pid;
+ if (pid != (pid_t)-1 && isAudioServerOrMediaServerUid(callerUid)) {
+ caller = pid; // check must match acquireAudioSessionId()
}
size_t num = mAudioSessionRefs.size();
for (size_t i = 0; i < num; i++) {
@@ -2932,7 +3022,7 @@
Mutex::Autolock _l(t->mLock);
for (size_t j = 0; j < t->mEffectChains.size(); j++) {
sp<EffectChain> ec = t->mEffectChains[j];
- if (ec->sessionId() > AUDIO_SESSION_OUTPUT_MIX) {
+ if (!audio_is_global_session(ec->sessionId())) {
chains.push(ec);
}
}
@@ -2959,7 +3049,7 @@
for (size_t i = 0; i < chains.size(); i++) {
sp<EffectChain> ec = chains[i];
int sessionid = ec->sessionId();
- sp<ThreadBase> t = ec->mThread.promote();
+ sp<ThreadBase> t = ec->thread().promote();
if (t == 0) {
continue;
}
@@ -2982,7 +3072,7 @@
effect->unPin();
t->removeEffect_l(effect, /*release*/ true);
if (effect->purgeHandles()) {
- t->checkSuspendOnEffectEnabled_l(effect, false, effect->sessionId());
+ effect->checkSuspendOnEffectEnabled(false, true /*threadLocked*/);
}
removedEffects.push_back(effect);
}
@@ -3116,15 +3206,15 @@
return NULL;
}
-audio_devices_t AudioFlinger::primaryOutputDevice_l() const
+DeviceTypeSet AudioFlinger::primaryOutputDevice_l() const
{
PlaybackThread *thread = primaryPlaybackThread_l();
if (thread == NULL) {
- return 0;
+ return DeviceTypeSet();
}
- return thread->outDevice();
+ return thread->outDeviceTypes();
}
AudioFlinger::PlaybackThread *AudioFlinger::fastPlaybackThread_l() const
@@ -3282,8 +3372,10 @@
int32_t priority,
audio_io_handle_t io,
audio_session_t sessionId,
+ const AudioDeviceTypeAddr& device,
const String16& opPackageName,
pid_t pid,
+ bool probe,
status_t *status,
int *id,
int *enabled)
@@ -3334,6 +3426,17 @@
lStatus = BAD_VALUE;
goto Exit;
}
+ } else if (sessionId == AUDIO_SESSION_DEVICE) {
+ if (!modifyDefaultAudioEffectsAllowed(pid, callingUid)) {
+ ALOGE("%s: device effect permission denied for uid %d", __func__, callingUid);
+ lStatus = PERMISSION_DENIED;
+ goto Exit;
+ }
+ if (io != AUDIO_IO_HANDLE_NONE) {
+ ALOGE("%s: io handle should not be specified for device effect", __func__);
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
} else {
// general sessionId.
@@ -3369,7 +3472,7 @@
// check recording permission for visualizer
if ((memcmp(&desc.type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0) &&
// TODO: Do we need to start/stop op - i.e. is there recording being performed?
- !recordingAllowed(opPackageName, pid, IPCThreadState::self()->getCallingUid())) {
+ !recordingAllowed(opPackageName, pid, callingUid)) {
lStatus = PERMISSION_DENIED;
goto Exit;
}
@@ -3386,6 +3489,23 @@
Mutex::Autolock _l(mLock);
+ if (sessionId == AUDIO_SESSION_DEVICE) {
+ sp<Client> client = registerPid(pid);
+ ALOGV("%s device type %#x address %s", __func__, device.mType, device.getAddress());
+ handle = mDeviceEffectManager.createEffect_l(
+ &desc, device, client, effectClient, mPatchPanel.patches_l(),
+ enabled, &lStatus, probe);
+ if (lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) {
+ // remove local strong reference to Client with mClientLock held
+ Mutex::Autolock _cl(mClientLock);
+ client.clear();
+ } else {
+ // handle must be valid here, but check again to be safe.
+ if (handle.get() != nullptr && id != nullptr) *id = handle->id();
+ }
+ goto Register;
+ }
+
// If output is not specified try to find a matching audio session ID in one of the
// output threads.
// If output is 0 here, sessionId is neither SESSION_OUTPUT_STAGE nor SESSION_OUTPUT_MIX
@@ -3467,9 +3587,9 @@
sp<Client> client = registerPid(pid);
// create effect on selected output thread
- bool pinned = (sessionId > AUDIO_SESSION_OUTPUT_MIX) && isSessionAcquired_l(sessionId);
+ bool pinned = !audio_is_global_session(sessionId) && isSessionAcquired_l(sessionId);
handle = thread->createEffect_l(client, effectClient, priority, sessionId,
- &desc, enabled, &lStatus, pinned);
+ &desc, enabled, &lStatus, pinned, probe);
if (lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) {
// remove local strong reference to Client with mClientLock held
Mutex::Autolock _cl(mClientLock);
@@ -3480,9 +3600,10 @@
}
}
- if (lStatus == NO_ERROR || lStatus == ALREADY_EXISTS) {
+Register:
+ if (!probe && (lStatus == NO_ERROR || lStatus == ALREADY_EXISTS)) {
// Check CPU and memory usage
- sp<EffectModule> effect = handle->effect().promote();
+ sp<EffectBase> effect = handle->effect().promote();
if (effect != nullptr) {
status_t rStatus = effect->updatePolicyState();
if (rStatus != NO_ERROR) {
@@ -3592,7 +3713,7 @@
// if the move request is not received from audio policy manager, the effect must be
// re-registered with the new strategy and output
if (dstChain == 0) {
- dstChain = effect->chain().promote();
+ dstChain = effect->callback()->chain().promote();
if (dstChain == 0) {
ALOGW("moveEffectChain_l() cannot get chain from effect %p", effect.get());
status = NO_INIT;
@@ -3642,7 +3763,7 @@
goto Exit;
}
- dstChain = effect->chain().promote();
+ dstChain = effect->callback()->chain().promote();
if (dstChain == 0) {
thread->addEffect_l(effect);
status = INVALID_OPERATION;
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 72e669a..40519b0 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -33,6 +33,7 @@
#include <sys/types.h>
#include <limits.h>
+#include <android/media/IAudioTrackCallback.h>
#include <android/os/BnExternalVibrationController.h>
#include <android-base/macros.h>
@@ -65,13 +66,17 @@
#include <media/audiohal/EffectBufferHalInterface.h>
#include <media/audiohal/StreamHalInterface.h>
#include <media/AudioBufferProvider.h>
+#include <media/AudioContainers.h>
+#include <media/AudioDeviceTypeAddr.h>
#include <media/AudioMixer.h>
+#include <media/DeviceDescriptorBase.h>
#include <media/ExtendedAudioBufferProvider.h>
-#include <media/LinearMap.h>
#include <media/VolumeShaper.h>
+#include <mediautils/ServiceUtilities.h>
#include <audio_utils/clock.h>
#include <audio_utils/FdToString.h>
+#include <audio_utils/LinearMap.h>
#include <audio_utils/SimpleLog.h>
#include <audio_utils/TimestampVerifier.h>
@@ -100,6 +105,7 @@
class AudioBuffer;
class AudioResampler;
class DeviceHalInterface;
+class DevicesFactoryHalCallback;
class DevicesFactoryHalInterface;
class EffectsFactoryHalInterface;
class FastMixer;
@@ -162,7 +168,7 @@
virtual status_t setMicMute(bool state);
virtual bool getMicMute() const;
- virtual void setRecordSilenced(uid_t uid, bool silenced);
+ virtual void setRecordSilenced(audio_port_handle_t portId, bool silenced);
virtual status_t setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs);
virtual String8 getParameters(audio_io_handle_t ioHandle, const String8& keys) const;
@@ -175,8 +181,7 @@
virtual status_t openOutput(audio_module_handle_t module,
audio_io_handle_t *output,
audio_config_t *config,
- audio_devices_t *devices,
- const String8& address,
+ const sp<DeviceDescriptorBase>& device,
uint32_t *latencyMs,
audio_output_flags_t flags);
@@ -211,7 +216,7 @@
// This is the binder API. For the internal API see nextUniqueId().
virtual audio_unique_id_t newAudioUniqueId(audio_unique_id_use_t use);
- virtual void acquireAudioSessionId(audio_session_t audioSession, pid_t pid);
+ void acquireAudioSessionId(audio_session_t audioSession, pid_t pid, uid_t uid) override;
virtual void releaseAudioSessionId(audio_session_t audioSession, pid_t pid);
@@ -230,8 +235,10 @@
int32_t priority,
audio_io_handle_t io,
audio_session_t sessionId,
+ const AudioDeviceTypeAddr& device,
const String16& opPackageName,
pid_t pid,
+ bool probe,
status_t *status /*non-NULL*/,
int *id,
int *enabled);
@@ -279,6 +286,8 @@
virtual status_t getMicrophones(std::vector<media::MicrophoneInfo> *microphones);
+ virtual status_t setAudioHalPids(const std::vector<pid_t>& pids);
+
virtual status_t onTransact(
uint32_t code,
const Parcel& data,
@@ -303,6 +312,12 @@
static int onExternalVibrationStart(const sp<os::ExternalVibration>& externalVibration);
static void onExternalVibrationStop(const sp<os::ExternalVibration>& externalVibration);
+
+ status_t addEffectToHal(audio_port_handle_t deviceId,
+ audio_module_handle_t hwModuleId, sp<EffectHalInterface> effect);
+ status_t removeEffectFromHal(audio_port_handle_t deviceId,
+ audio_module_handle_t hwModuleId, sp<EffectHalInterface> effect);
+
private:
// FIXME The 400 is temporarily too high until a leak of writers in media.log is fixed.
static const size_t kLogMemorySize = 400 * 1024;
@@ -331,7 +346,10 @@
virtual ~SyncEvent() {}
- void trigger() { Mutex::Autolock _l(mLock); if (mCallback) mCallback(this); }
+ void trigger() {
+ Mutex::Autolock _l(mLock);
+ if (mCallback) mCallback(wp<SyncEvent>(this));
+ }
bool isCancelled() const { Mutex::Autolock _l(mLock); return (mCallback == NULL); }
void cancel() { Mutex::Autolock _l(mLock); mCallback = NULL; }
AudioSystem::sync_event_t type() const { return mType; }
@@ -372,7 +390,7 @@
virtual void onFirstRef();
AudioHwDevice* findSuitableHwDev_l(audio_module_handle_t module,
- audio_devices_t devices);
+ audio_devices_t deviceType);
// Set kEnableExtendedChannels to true to enable greater than stereo output
// for the MixerThread and device sink. Number of channels allowed is
@@ -469,10 +487,13 @@
public:
NotificationClient(const sp<AudioFlinger>& audioFlinger,
const sp<IAudioFlingerClient>& client,
- pid_t pid);
+ pid_t pid,
+ uid_t uid);
virtual ~NotificationClient();
sp<IAudioFlingerClient> audioFlingerClient() const { return mAudioFlingerClient; }
+ pid_t getPid() const { return mPid; }
+ uid_t getUid() const { return mUid; }
// IBinder::DeathRecipient
virtual void binderDied(const wp<IBinder>& who);
@@ -482,6 +503,7 @@
const sp<AudioFlinger> mAudioFlinger;
const pid_t mPid;
+ const uid_t mUid;
const sp<IAudioFlingerClient> mAudioFlingerClient;
};
@@ -528,9 +550,14 @@
class AsyncCallbackThread;
class Track;
class RecordTrack;
+ class EffectBase;
class EffectModule;
class EffectHandle;
class EffectChain;
+ class DeviceEffectProxy;
+ class DeviceEffectManager;
+ class PatchPanel;
+ class DeviceEffectManagerCallback;
struct AudioStreamIn;
struct TeePatch;
@@ -547,6 +574,16 @@
bool mute;
};
+ // Abstraction for the Audio Source for the RecordThread (HAL or PassthruPatchRecord).
+ struct Source
+ {
+ virtual ~Source() = default;
+ // The following methods have the same signatures as in StreamHalInterface.
+ virtual status_t read(void *buffer, size_t bytes, size_t *read) = 0;
+ virtual status_t getCapturePosition(int64_t *frames, int64_t *time) = 0;
+ virtual status_t standby() = 0;
+ };
+
// --- PlaybackThread ---
#ifdef FLOAT_EFFECT_CHAIN
#define EFFECT_BUFFER_FORMAT AUDIO_FORMAT_PCM_FLOAT
@@ -558,9 +595,11 @@
#include "Threads.h"
+#include "PatchPanel.h"
+
#include "Effects.h"
-#include "PatchPanel.h"
+#include "DeviceEffectManager.h"
// Find io handle by session id.
// Preference is given to an io handle with a matching effect chain to session id.
@@ -668,11 +707,11 @@
audio_devices_t outputDevice,
const String8& outputDeviceAddress);
sp<ThreadBase> openOutput_l(audio_module_handle_t module,
- audio_io_handle_t *output,
- audio_config_t *config,
- audio_devices_t devices,
- const String8& address,
- audio_output_flags_t flags);
+ audio_io_handle_t *output,
+ audio_config_t *config,
+ audio_devices_t deviceType,
+ const String8& address,
+ audio_output_flags_t flags);
void closeOutputFinish(const sp<PlaybackThread>& thread);
void closeInputFinish(const sp<RecordThread>& thread);
@@ -707,7 +746,7 @@
// return thread associated with primary hardware device, or NULL
PlaybackThread *primaryPlaybackThread_l() const;
- audio_devices_t primaryOutputDevice_l() const;
+ DeviceTypeSet primaryOutputDevice_l() const;
// return the playback thread with smallest HAL buffer size, and prefer fast
PlaybackThread *fastPlaybackThread_l() const;
@@ -741,6 +780,7 @@
std::vector< sp<EffectModule> > purgeStaleEffects_l();
void broacastParametersToRecordThreads_l(const String8& keyValuePairs);
+ void updateOutDevicesForRecordThreads_l(const DeviceDescriptorBaseVector& devices);
void forwardParametersToDownstreamPatches_l(
audio_io_handle_t upStream, const String8& keyValuePairs,
std::function<bool(const sp<PlaybackThread>&)> useThread = nullptr);
@@ -749,7 +789,7 @@
// For emphasis, we could also make all pointers to them be "const *",
// but that would clutter the code unnecessarily.
- struct AudioStreamIn {
+ struct AudioStreamIn : public Source {
AudioHwDevice* const audioHwDev;
sp<StreamInHalInterface> stream;
audio_input_flags_t flags;
@@ -758,6 +798,13 @@
AudioStreamIn(AudioHwDevice *dev, sp<StreamInHalInterface> in, audio_input_flags_t flags) :
audioHwDev(dev), stream(in), flags(flags) {}
+ status_t read(void *buffer, size_t bytes, size_t *read) override {
+ return stream->read(buffer, bytes, read);
+ }
+ status_t getCapturePosition(int64_t *frames, int64_t *time) override {
+ return stream->getCapturePosition(frames, time);
+ }
+ status_t standby() override { return stream->standby(); }
};
struct TeePatch {
@@ -767,10 +814,11 @@
// for mAudioSessionRefs only
struct AudioSessionRef {
- AudioSessionRef(audio_session_t sessionid, pid_t pid) :
- mSessionid(sessionid), mPid(pid), mCnt(1) {}
+ AudioSessionRef(audio_session_t sessionid, pid_t pid, uid_t uid) :
+ mSessionid(sessionid), mPid(pid), mUid(uid), mCnt(1) {}
const audio_session_t mSessionid;
const pid_t mPid;
+ const uid_t mUid;
int mCnt;
};
@@ -791,6 +839,7 @@
DefaultKeyedVector<audio_module_handle_t, AudioHwDevice*> mAudioHwDevs;
sp<DevicesFactoryHalInterface> mDevicesFactoryHal;
+ sp<DevicesFactoryHalCallback> mDevicesFactoryHalCallback;
// for dump, indicates which hardware operation is currently in progress (but not stream ops)
enum hardware_call_state {
@@ -898,11 +947,17 @@
PatchPanel mPatchPanel;
sp<EffectsFactoryHalInterface> mEffectsFactoryHal;
+ DeviceEffectManager mDeviceEffectManager;
+
bool mSystemReady;
+ mediautils::UidInfo mUidInfo;
+
SimpleLog mRejectedSetParameterLog;
SimpleLog mAppSetParameterLog;
SimpleLog mSystemSetParameterLog;
+
+ static inline constexpr const char *mMetricsId = AMEDIAMETRICS_KEY_AUDIO_FLINGER;
};
#undef INCLUDING_FROM_AUDIOFLINGER_H
diff --git a/services/audioflinger/AudioHwDevice.cpp b/services/audioflinger/AudioHwDevice.cpp
index b109d06..dda164c 100644
--- a/services/audioflinger/AudioHwDevice.cpp
+++ b/services/audioflinger/AudioHwDevice.cpp
@@ -34,7 +34,7 @@
status_t AudioHwDevice::openOutputStream(
AudioStreamOut **ppStreamOut,
audio_io_handle_t handle,
- audio_devices_t devices,
+ audio_devices_t deviceType,
audio_output_flags_t flags,
struct audio_config *config,
const char *address)
@@ -50,7 +50,7 @@
config->sample_rate,
config->format,
config->channel_mask);
- status_t status = outputStream->open(handle, devices, config, address);
+ status_t status = outputStream->open(handle, deviceType, config, address);
if (status != NO_ERROR) {
delete outputStream;
@@ -75,7 +75,7 @@
if (wrapperNeeded) {
if (SPDIFEncoder::isFormatSupported(originalConfig.format)) {
outputStream = new SpdifStreamOut(this, flags, originalConfig.format);
- status = outputStream->open(handle, devices, &originalConfig, address);
+ status = outputStream->open(handle, deviceType, &originalConfig, address);
if (status != NO_ERROR) {
ALOGE("ERROR - openOutputStream(), SPDIF open returned %d",
status);
diff --git a/services/audioflinger/AudioHwDevice.h b/services/audioflinger/AudioHwDevice.h
index d4299b0..6709d17 100644
--- a/services/audioflinger/AudioHwDevice.h
+++ b/services/audioflinger/AudioHwDevice.h
@@ -76,7 +76,7 @@
status_t openOutputStream(
AudioStreamOut **ppStreamOut,
audio_io_handle_t handle,
- audio_devices_t devices,
+ audio_devices_t deviceType,
audio_output_flags_t flags,
struct audio_config *config,
const char *address);
diff --git a/services/audioflinger/AudioStreamOut.cpp b/services/audioflinger/AudioStreamOut.cpp
index a60a5f2..d13cb8f 100644
--- a/services/audioflinger/AudioStreamOut.cpp
+++ b/services/audioflinger/AudioStreamOut.cpp
@@ -118,7 +118,7 @@
status_t AudioStreamOut::open(
audio_io_handle_t handle,
- audio_devices_t devices,
+ audio_devices_t deviceType,
struct audio_config *config,
const char *address)
{
@@ -130,7 +130,7 @@
int status = hwDev()->openOutputStream(
handle,
- devices,
+ deviceType,
customFlags,
config,
address,
@@ -152,7 +152,7 @@
status = hwDev()->openOutputStream(
handle,
- devices,
+ deviceType,
customFlags,
&customConfig,
address,
diff --git a/services/audioflinger/AudioStreamOut.h b/services/audioflinger/AudioStreamOut.h
index b16b1af..16fbcf2 100644
--- a/services/audioflinger/AudioStreamOut.h
+++ b/services/audioflinger/AudioStreamOut.h
@@ -47,7 +47,7 @@
virtual status_t open(
audio_io_handle_t handle,
- audio_devices_t devices,
+ audio_devices_t deviceType,
struct audio_config *config,
const char *address);
diff --git a/services/audioflinger/DeviceEffectManager.cpp b/services/audioflinger/DeviceEffectManager.cpp
new file mode 100644
index 0000000..a3c3b84
--- /dev/null
+++ b/services/audioflinger/DeviceEffectManager.cpp
@@ -0,0 +1,278 @@
+/*
+**
+** Copyright 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.
+*/
+
+
+#define LOG_TAG "AudioFlinger::DeviceEffectManager"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <audio_utils/primitives.h>
+
+#include "AudioFlinger.h"
+#include <media/audiohal/EffectsFactoryHalInterface.h>
+
+// ----------------------------------------------------------------------------
+
+
+namespace android {
+
+void AudioFlinger::DeviceEffectManager::createAudioPatch(audio_patch_handle_t handle,
+ const PatchPanel::Patch& patch) {
+ ALOGV("%s handle %d mHalHandle %d num sinks %d device sink %08x",
+ __func__, handle, patch.mHalHandle,
+ patch.mAudioPatch.num_sinks,
+ patch.mAudioPatch.num_sinks > 0 ? patch.mAudioPatch.sinks[0].ext.device.type : 0);
+
+ mCommandThread->createAudioPatchCommand(handle, patch);
+}
+
+void AudioFlinger::DeviceEffectManager::onCreateAudioPatch(audio_patch_handle_t handle,
+ const PatchPanel::Patch& patch) {
+ ALOGV("%s handle %d mHalHandle %d device sink %08x",
+ __func__, handle, patch.mHalHandle,
+ patch.mAudioPatch.num_sinks > 0 ? patch.mAudioPatch.sinks[0].ext.device.type : 0);
+ Mutex::Autolock _l(mLock);
+ for (auto& effect : mDeviceEffects) {
+ status_t status = effect.second->onCreatePatch(handle, patch);
+ ALOGV("%s Effect onCreatePatch status %d", __func__, status);
+ ALOGW_IF(status == BAD_VALUE, "%s onCreatePatch error %d", __func__, status);
+ }
+}
+
+void AudioFlinger::DeviceEffectManager::releaseAudioPatch(audio_patch_handle_t handle) {
+ ALOGV("%s", __func__);
+ mCommandThread->releaseAudioPatchCommand(handle);
+}
+
+void AudioFlinger::DeviceEffectManager::onReleaseAudioPatch(audio_patch_handle_t handle) {
+ ALOGV("%s", __func__);
+ Mutex::Autolock _l(mLock);
+ for (auto& effect : mDeviceEffects) {
+ effect.second->onReleasePatch(handle);
+ }
+}
+
+// DeviceEffectManager::createEffect_l() must be called with AudioFlinger::mLock held
+sp<AudioFlinger::EffectHandle> AudioFlinger::DeviceEffectManager::createEffect_l(
+ effect_descriptor_t *descriptor,
+ const AudioDeviceTypeAddr& device,
+ const sp<AudioFlinger::Client>& client,
+ const sp<IEffectClient>& effectClient,
+ const std::map<audio_patch_handle_t, PatchPanel::Patch>& patches,
+ int *enabled,
+ status_t *status,
+ bool probe) {
+ sp<DeviceEffectProxy> effect;
+ sp<EffectHandle> handle;
+ status_t lStatus;
+
+ lStatus = checkEffectCompatibility(descriptor);
+ if (probe || lStatus != NO_ERROR) {
+ *status = lStatus;
+ return handle;
+ }
+
+ {
+ Mutex::Autolock _l(mLock);
+ auto iter = mDeviceEffects.find(device);
+ if (iter != mDeviceEffects.end()) {
+ effect = iter->second;
+ } else {
+ effect = new DeviceEffectProxy(device, mMyCallback,
+ descriptor, mAudioFlinger.nextUniqueId(AUDIO_UNIQUE_ID_USE_EFFECT));
+ }
+ // create effect handle and connect it to effect module
+ handle = new EffectHandle(effect, client, effectClient, 0 /*priority*/);
+ lStatus = handle->initCheck();
+ if (lStatus == NO_ERROR) {
+ lStatus = effect->addHandle(handle.get());
+ if (lStatus == NO_ERROR) {
+ effect->init(patches);
+ mDeviceEffects.emplace(device, effect);
+ }
+ }
+ }
+ if (enabled != NULL) {
+ *enabled = (int)effect->isEnabled();
+ }
+ *status = lStatus;
+ return handle;
+}
+
+status_t AudioFlinger::DeviceEffectManager::checkEffectCompatibility(
+ const effect_descriptor_t *desc) {
+
+ if ((desc->flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_PRE_PROC
+ && (desc->flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_POST_PROC) {
+ ALOGW("%s() non pre/post processing device effect %s", __func__, desc->name);
+ return BAD_VALUE;
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::DeviceEffectManager::createEffectHal(
+ const effect_uuid_t *pEffectUuid, int32_t sessionId, int32_t deviceId,
+ sp<EffectHalInterface> *effect) {
+ status_t status = NO_INIT;
+ sp<EffectsFactoryHalInterface> effectsFactory = mAudioFlinger.getEffectsFactory();
+ if (effectsFactory != 0) {
+ status = effectsFactory->createEffect(
+ pEffectUuid, sessionId, AUDIO_IO_HANDLE_NONE, deviceId, effect);
+ }
+ return status;
+}
+
+void AudioFlinger::DeviceEffectManager::dump(int fd) {
+ const bool locked = dumpTryLock(mLock);
+ if (!locked) {
+ String8 result("DeviceEffectManager may be deadlocked\n");
+ write(fd, result.string(), result.size());
+ }
+
+ write(fd, "\nDevice Effects:\n", sizeof("\nDevice Effects:\n"));
+ for (const auto& iter : mDeviceEffects) {
+ String8 outStr;
+ outStr.appendFormat("%*sEffect for device %s address %s:\n", 2, "",
+ ::android::toString(iter.first.mType).c_str(), iter.first.getAddress());
+ write(fd, outStr.string(), outStr.size());
+ iter.second->dump(fd, 4);
+ }
+
+ if (locked) {
+ mLock.unlock();
+ }
+}
+
+
+size_t AudioFlinger::DeviceEffectManager::removeEffect(const sp<DeviceEffectProxy>& effect)
+{
+ Mutex::Autolock _l(mLock);
+ mDeviceEffects.erase(effect->device());
+ return mDeviceEffects.size();
+}
+
+bool AudioFlinger::DeviceEffectManagerCallback::disconnectEffectHandle(
+ EffectHandle *handle, bool unpinIfLast) {
+ sp<EffectBase> effectBase = handle->effect().promote();
+ if (effectBase == nullptr) {
+ return false;
+ }
+
+ sp<DeviceEffectProxy> effect = effectBase->asDeviceEffectProxy();
+ if (effect == nullptr) {
+ return false;
+ }
+ // restore suspended effects if the disconnected handle was enabled and the last one.
+ bool remove = (effect->removeHandle(handle) == 0) && (!effect->isPinned() || unpinIfLast);
+ if (remove) {
+ mManager.removeEffect(effect);
+ if (handle->enabled()) {
+ effectBase->checkSuspendOnEffectEnabled(false, false /*threadLocked*/);
+ }
+ }
+ return true;
+}
+
+// ----------- DeviceEffectManager::CommandThread implementation ----------
+
+
+AudioFlinger::DeviceEffectManager::CommandThread::~CommandThread()
+{
+ Mutex::Autolock _l(mLock);
+ mCommands.clear();
+}
+
+void AudioFlinger::DeviceEffectManager::CommandThread::onFirstRef()
+{
+ run("DeviceEffectManage_CommandThread", ANDROID_PRIORITY_AUDIO);
+}
+
+bool AudioFlinger::DeviceEffectManager::CommandThread::threadLoop()
+{
+ mLock.lock();
+ while (!exitPending())
+ {
+ while (!mCommands.empty() && !exitPending()) {
+ sp<Command> command = mCommands.front();
+ mCommands.pop_front();
+ mLock.unlock();
+
+ switch (command->mCommand) {
+ case CREATE_AUDIO_PATCH: {
+ CreateAudioPatchData *data = (CreateAudioPatchData *)command->mData.get();
+ ALOGV("CommandThread() processing create audio patch handle %d", data->mHandle);
+ mManager.onCreateAudioPatch(data->mHandle, data->mPatch);
+ } break;
+ case RELEASE_AUDIO_PATCH: {
+ ReleaseAudioPatchData *data = (ReleaseAudioPatchData *)command->mData.get();
+ ALOGV("CommandThread() processing release audio patch handle %d", data->mHandle);
+ mManager.onReleaseAudioPatch(data->mHandle);
+ } break;
+ default:
+ ALOGW("CommandThread() unknown command %d", command->mCommand);
+ }
+ mLock.lock();
+ }
+
+ // At this stage we have either an empty command queue or the first command in the queue
+ // has a finite delay. So unless we are exiting it is safe to wait.
+ if (!exitPending()) {
+ ALOGV("CommandThread() going to sleep");
+ mWaitWorkCV.wait(mLock);
+ }
+ }
+ mLock.unlock();
+ return false;
+}
+
+void AudioFlinger::DeviceEffectManager::CommandThread::sendCommand(sp<Command> command) {
+ Mutex::Autolock _l(mLock);
+ mCommands.push_back(command);
+ mWaitWorkCV.signal();
+}
+
+void AudioFlinger::DeviceEffectManager::CommandThread::createAudioPatchCommand(
+ audio_patch_handle_t handle, const PatchPanel::Patch& patch)
+{
+ sp<Command> command = new Command(CREATE_AUDIO_PATCH, new CreateAudioPatchData(handle, patch));
+ ALOGV("CommandThread() adding create patch handle %d mHalHandle %d.", handle, patch.mHalHandle);
+ sendCommand(command);
+}
+
+void AudioFlinger::DeviceEffectManager::CommandThread::releaseAudioPatchCommand(
+ audio_patch_handle_t handle)
+{
+ sp<Command> command = new Command(RELEASE_AUDIO_PATCH, new ReleaseAudioPatchData(handle));
+ ALOGV("CommandThread() adding release patch");
+ sendCommand(command);
+}
+
+void AudioFlinger::DeviceEffectManager::CommandThread::exit()
+{
+ ALOGV("CommandThread::exit");
+ {
+ AutoMutex _l(mLock);
+ requestExit();
+ mWaitWorkCV.signal();
+ }
+ // Note that we can call it from the thread loop if all other references have been released
+ // but it will safely return WOULD_BLOCK in this case
+ requestExitAndWait();
+}
+
+} // namespace android
diff --git a/services/audioflinger/DeviceEffectManager.h b/services/audioflinger/DeviceEffectManager.h
new file mode 100644
index 0000000..81e6065
--- /dev/null
+++ b/services/audioflinger/DeviceEffectManager.h
@@ -0,0 +1,204 @@
+/*
+**
+** Copyright 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.
+*/
+
+#ifndef INCLUDING_FROM_AUDIOFLINGER_H
+ #error This header file should only be included from AudioFlinger.h
+#endif
+
+// DeviceEffectManager is concealed within AudioFlinger, their lifetimes are the same.
+class DeviceEffectManager {
+public:
+ explicit DeviceEffectManager(AudioFlinger* audioFlinger)
+ : mCommandThread(new CommandThread(*this)), mAudioFlinger(*audioFlinger),
+ mMyCallback(new DeviceEffectManagerCallback(this)) {}
+
+ ~DeviceEffectManager() {
+ mCommandThread->exit();
+ }
+
+ sp<EffectHandle> createEffect_l(effect_descriptor_t *descriptor,
+ const AudioDeviceTypeAddr& device,
+ const sp<AudioFlinger::Client>& client,
+ const sp<IEffectClient>& effectClient,
+ const std::map<audio_patch_handle_t, PatchPanel::Patch>& patches,
+ int *enabled,
+ status_t *status,
+ bool probe);
+ void createAudioPatch(audio_patch_handle_t handle, const PatchPanel::Patch& patch);
+ void releaseAudioPatch(audio_patch_handle_t handle);
+
+ size_t removeEffect(const sp<DeviceEffectProxy>& effect);
+ status_t createEffectHal(const effect_uuid_t *pEffectUuid,
+ int32_t sessionId, int32_t deviceId,
+ sp<EffectHalInterface> *effect);
+ status_t addEffectToHal(audio_port_handle_t deviceId, audio_module_handle_t hwModuleId,
+ sp<EffectHalInterface> effect) {
+ return mAudioFlinger.addEffectToHal(deviceId, hwModuleId, effect);
+ };
+ status_t removeEffectFromHal(audio_port_handle_t deviceId, audio_module_handle_t hwModuleId,
+ sp<EffectHalInterface> effect) {
+ return mAudioFlinger.removeEffectFromHal(deviceId, hwModuleId, effect);
+ };
+
+ AudioFlinger& audioFlinger() const { return mAudioFlinger; }
+
+ void dump(int fd);
+
+private:
+
+ // Thread to execute create and release patch commands asynchronously. This is needed because
+ // PatchPanel::createAudioPatch and releaseAudioPatch are executed from audio policy service
+ // with mutex locked and effect management requires to call back into audio policy service
+ class Command;
+ class CommandThread : public Thread {
+ public:
+
+ enum {
+ CREATE_AUDIO_PATCH,
+ RELEASE_AUDIO_PATCH,
+ };
+
+ CommandThread(DeviceEffectManager& manager)
+ : Thread(false), mManager(manager) {}
+ ~CommandThread() override;
+
+ // Thread virtuals
+ void onFirstRef() override;
+ bool threadLoop() override;
+
+ void exit();
+
+ void createAudioPatchCommand(audio_patch_handle_t handle,
+ const PatchPanel::Patch& patch);
+ void releaseAudioPatchCommand(audio_patch_handle_t handle);
+
+ private:
+ class CommandData;
+
+ // descriptor for requested tone playback event
+ class Command: public RefBase {
+ public:
+ Command() = default;
+ Command(int command, sp<CommandData> data)
+ : mCommand(command), mData(data) {}
+
+ int mCommand = -1;
+ sp<CommandData> mData;
+ };
+
+ class CommandData: public RefBase {
+ public:
+ virtual ~CommandData() = default;
+ };
+
+ class CreateAudioPatchData : public CommandData {
+ public:
+ CreateAudioPatchData(audio_patch_handle_t handle, const PatchPanel::Patch& patch)
+ : mHandle(handle), mPatch(patch) {}
+
+ audio_patch_handle_t mHandle;
+ const PatchPanel::Patch mPatch;
+ };
+
+ class ReleaseAudioPatchData : public CommandData {
+ public:
+ ReleaseAudioPatchData(audio_patch_handle_t handle)
+ : mHandle(handle) {}
+
+ audio_patch_handle_t mHandle;
+ };
+
+ void sendCommand(sp<Command> command);
+
+ Mutex mLock;
+ Condition mWaitWorkCV;
+ std::deque <sp<Command>> mCommands; // list of pending commands
+ DeviceEffectManager& mManager;
+ };
+
+ void onCreateAudioPatch(audio_patch_handle_t handle, const PatchPanel::Patch& patch);
+ void onReleaseAudioPatch(audio_patch_handle_t handle);
+
+ status_t checkEffectCompatibility(const effect_descriptor_t *desc);
+
+ Mutex mLock;
+ sp<CommandThread> mCommandThread;
+ AudioFlinger &mAudioFlinger;
+ const sp<DeviceEffectManagerCallback> mMyCallback;
+ std::map<AudioDeviceTypeAddr, sp<DeviceEffectProxy>> mDeviceEffects;
+};
+
+class DeviceEffectManagerCallback : public EffectCallbackInterface {
+public:
+ DeviceEffectManagerCallback(DeviceEffectManager *manager)
+ : mManager(*manager) {}
+
+ status_t createEffectHal(const effect_uuid_t *pEffectUuid,
+ int32_t sessionId, int32_t deviceId,
+ sp<EffectHalInterface> *effect) override {
+ return mManager.createEffectHal(pEffectUuid, sessionId, deviceId, effect);
+ }
+ status_t allocateHalBuffer(size_t size __unused,
+ sp<EffectBufferHalInterface>* buffer __unused) override { return NO_ERROR; }
+ bool updateOrphanEffectChains(const sp<EffectBase>& effect __unused) override { return false; }
+
+ audio_io_handle_t io() const override { return AUDIO_IO_HANDLE_NONE; }
+ bool isOutput() const override { return false; }
+ bool isOffload() const override { return false; }
+ bool isOffloadOrDirect() const override { return false; }
+ bool isOffloadOrMmap() const override { return false; }
+
+ uint32_t sampleRate() const override { return 0; }
+ audio_channel_mask_t channelMask() const override { return AUDIO_CHANNEL_NONE; }
+ uint32_t channelCount() const override { return 0; }
+ size_t frameCount() const override { return 0; }
+ uint32_t latency() const override { return 0; }
+
+ status_t addEffectToHal(sp<EffectHalInterface> effect __unused) override {
+ return NO_ERROR;
+ }
+ status_t removeEffectFromHal(sp<EffectHalInterface> effect __unused) override {
+ return NO_ERROR;
+ }
+
+ bool disconnectEffectHandle(EffectHandle *handle, bool unpinIfLast) override;
+ void setVolumeForOutput(float left __unused, float right __unused) const override {}
+
+ // check if effects should be suspended or restored when a given effect is enable or disabled
+ void checkSuspendOnEffectEnabled(const sp<EffectBase>& effect __unused,
+ bool enabled __unused, bool threadLocked __unused) override {}
+ void resetVolume() override {}
+ uint32_t strategy() const override { return 0; }
+ int32_t activeTrackCnt() const override { return 0; }
+ void onEffectEnable(const sp<EffectBase>& effect __unused) override {}
+ void onEffectDisable(const sp<EffectBase>& effect __unused) override {}
+
+ wp<EffectChain> chain() const override { return nullptr; }
+
+ int newEffectId() { return mManager.audioFlinger().nextUniqueId(AUDIO_UNIQUE_ID_USE_EFFECT); }
+
+ status_t addEffectToHal(audio_port_handle_t deviceId,
+ audio_module_handle_t hwModuleId, sp<EffectHalInterface> effect) {
+ return mManager.addEffectToHal(deviceId, hwModuleId, effect);
+ }
+ status_t removeEffectFromHal(audio_port_handle_t deviceId,
+ audio_module_handle_t hwModuleId, sp<EffectHalInterface> effect) {
+ return mManager.removeEffectFromHal(deviceId, hwModuleId, effect);
+ }
+private:
+ DeviceEffectManager& mManager;
+};
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 13152d0..8a65122 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -29,7 +29,9 @@
#include <system/audio_effects/effect_visualizer.h>
#include <audio_utils/channels.h>
#include <audio_utils/primitives.h>
+#include <media/AudioContainers.h>
#include <media/AudioEffect.h>
+#include <media/AudioDeviceTypeAddr.h>
#include <media/audiohal/EffectHalInterface.h>
#include <media/audiohal/EffectsFactoryHalInterface.h>
#include <mediautils/ServiceUtilities.h>
@@ -56,81 +58,115 @@
namespace android {
// ----------------------------------------------------------------------------
-// EffectModule implementation
+// EffectBase implementation
// ----------------------------------------------------------------------------
#undef LOG_TAG
-#define LOG_TAG "AudioFlinger::EffectModule"
+#define LOG_TAG "AudioFlinger::EffectBase"
-AudioFlinger::EffectModule::EffectModule(ThreadBase *thread,
- const wp<AudioFlinger::EffectChain>& chain,
+AudioFlinger::EffectBase::EffectBase(const sp<AudioFlinger::EffectCallbackInterface>& callback,
effect_descriptor_t *desc,
int id,
audio_session_t sessionId,
bool pinned)
: mPinned(pinned),
- mThread(thread), mChain(chain), mId(id), mSessionId(sessionId),
- mDescriptor(*desc),
- // clear mConfig to ensure consistent initial value of buffer framecount
- // in case buffers are associated by setInBuffer() or setOutBuffer()
- // prior to configure().
- mConfig{{}, {}},
- mStatus(NO_INIT), mState(IDLE),
- mMaxDisableWaitCnt(1), // set by configure(), should be >= 1
- mDisableWaitCnt(0), // set by process() and updateState()
- mSuspended(false),
- mOffloaded(false),
- mAudioFlinger(thread->mAudioFlinger)
-#ifdef FLOAT_EFFECT_CHAIN
- , mSupportsFloat(false)
-#endif
+ mCallback(callback), mId(id), mSessionId(sessionId),
+ mDescriptor(*desc)
{
- ALOGV("Constructor %p pinned %d", this, pinned);
- int lStatus;
+}
- // create effect engine from effect factory
- mStatus = -ENODEV;
- sp<AudioFlinger> audioFlinger = mAudioFlinger.promote();
- if (audioFlinger != 0) {
- sp<EffectsFactoryHalInterface> effectsFactory = audioFlinger->getEffectsFactory();
- if (effectsFactory != 0) {
- mStatus = effectsFactory->createEffect(
- &desc->uuid, sessionId, thread->id(), &mEffectInterface);
+// must be called with EffectModule::mLock held
+status_t AudioFlinger::EffectBase::setEnabled_l(bool enabled)
+{
+
+ ALOGV("setEnabled %p enabled %d", this, enabled);
+
+ if (enabled != isEnabled()) {
+ switch (mState) {
+ // going from disabled to enabled
+ case IDLE:
+ mState = STARTING;
+ break;
+ case STOPPED:
+ mState = RESTART;
+ break;
+ case STOPPING:
+ mState = ACTIVE;
+ break;
+
+ // going from enabled to disabled
+ case RESTART:
+ mState = STOPPED;
+ break;
+ case STARTING:
+ mState = IDLE;
+ break;
+ case ACTIVE:
+ mState = STOPPING;
+ break;
+ case DESTROYED:
+ return NO_ERROR; // simply ignore as we are being destroyed
+ }
+ for (size_t i = 1; i < mHandles.size(); i++) {
+ EffectHandle *h = mHandles[i];
+ if (h != NULL && !h->disconnected()) {
+ h->setEnabled(enabled);
+ }
}
}
-
- if (mStatus != NO_ERROR) {
- return;
- }
- lStatus = init();
- if (lStatus < 0) {
- mStatus = lStatus;
- goto Error;
- }
-
- setOffloaded(thread->type() == ThreadBase::OFFLOAD, thread->id());
- ALOGV("Constructor success name %s, Interface %p", mDescriptor.name, mEffectInterface.get());
-
- return;
-Error:
- mEffectInterface.clear();
- ALOGV("Constructor Error %d", mStatus);
+ return NO_ERROR;
}
-AudioFlinger::EffectModule::~EffectModule()
+status_t AudioFlinger::EffectBase::setEnabled(bool enabled, bool fromHandle)
{
- ALOGV("Destructor %p", this);
- if (mEffectInterface != 0) {
- char uuidStr[64];
- AudioEffect::guidToString(&mDescriptor.uuid, uuidStr, sizeof(uuidStr));
- ALOGW("EffectModule %p destructor called with unreleased interface, effect %s",
- this, uuidStr);
- release_l();
+ status_t status;
+ {
+ Mutex::Autolock _l(mLock);
+ status = setEnabled_l(enabled);
}
-
+ if (fromHandle) {
+ if (enabled) {
+ if (status != NO_ERROR) {
+ mCallback->checkSuspendOnEffectEnabled(this, false, false /*threadLocked*/);
+ } else {
+ mCallback->onEffectEnable(this);
+ }
+ } else {
+ mCallback->onEffectDisable(this);
+ }
+ }
+ return status;
}
-status_t AudioFlinger::EffectModule::addHandle(EffectHandle *handle)
+bool AudioFlinger::EffectBase::isEnabled() const
+{
+ switch (mState) {
+ case RESTART:
+ case STARTING:
+ case ACTIVE:
+ return true;
+ case IDLE:
+ case STOPPING:
+ case STOPPED:
+ case DESTROYED:
+ default:
+ return false;
+ }
+}
+
+void AudioFlinger::EffectBase::setSuspended(bool suspended)
+{
+ Mutex::Autolock _l(mLock);
+ mSuspended = suspended;
+}
+
+bool AudioFlinger::EffectBase::suspended() const
+{
+ Mutex::Autolock _l(mLock);
+ return mSuspended;
+}
+
+status_t AudioFlinger::EffectBase::addHandle(EffectHandle *handle)
{
status_t status;
@@ -169,7 +205,7 @@
return status;
}
-status_t AudioFlinger::EffectModule::updatePolicyState()
+status_t AudioFlinger::EffectBase::updatePolicyState()
{
status_t status = NO_ERROR;
bool doRegister = false;
@@ -186,14 +222,8 @@
doRegister = true;
mPolicyRegistered = mHandles.size() > 0;
if (mPolicyRegistered) {
- sp <EffectChain> chain = mChain.promote();
- sp <ThreadBase> thread = mThread.promote();
-
- if (thread == nullptr || chain == nullptr) {
- return INVALID_OPERATION;
- }
- io = thread->id();
- strategy = chain->strategy();
+ io = mCallback->io();
+ strategy = mCallback->strategy();
}
}
// enable effect when registered according to enable state requested by controlling handle
@@ -231,13 +261,13 @@
}
-ssize_t AudioFlinger::EffectModule::removeHandle(EffectHandle *handle)
+ssize_t AudioFlinger::EffectBase::removeHandle(EffectHandle *handle)
{
Mutex::Autolock _l(mLock);
return removeHandle_l(handle);
}
-ssize_t AudioFlinger::EffectModule::removeHandle_l(EffectHandle *handle)
+ssize_t AudioFlinger::EffectBase::removeHandle_l(EffectHandle *handle)
{
size_t size = mHandles.size();
size_t i;
@@ -261,19 +291,15 @@
}
}
- // Prevent calls to process() and other functions on effect interface from now on.
- // The effect engine will be released by the destructor when the last strong reference on
- // this object is released which can happen after next process is called.
if (mHandles.size() == 0 && !mPinned) {
mState = DESTROYED;
- mEffectInterface->close();
}
return mHandles.size();
}
// must be called with EffectModule::mLock held
-AudioFlinger::EffectHandle *AudioFlinger::EffectModule::controlHandle_l()
+AudioFlinger::EffectHandle *AudioFlinger::EffectBase::controlHandle_l()
{
// the first valid handle in the list has control over the module
for (size_t i = 0; i < mHandles.size(); i++) {
@@ -287,22 +313,271 @@
}
// unsafe method called when the effect parent thread has been destroyed
-ssize_t AudioFlinger::EffectModule::disconnectHandle(EffectHandle *handle, bool unpinIfLast)
+ssize_t AudioFlinger::EffectBase::disconnectHandle(EffectHandle *handle, bool unpinIfLast)
{
ALOGV("disconnect() %p handle %p", this, handle);
+ if (mCallback->disconnectEffectHandle(handle, unpinIfLast)) {
+ return mHandles.size();
+ }
+
Mutex::Autolock _l(mLock);
ssize_t numHandles = removeHandle_l(handle);
if ((numHandles == 0) && (!mPinned || unpinIfLast)) {
- sp<AudioFlinger> af = mAudioFlinger.promote();
- if (af != 0) {
- mLock.unlock();
- af->updateOrphanEffectChains(this);
- mLock.lock();
- }
+ mLock.unlock();
+ mCallback->updateOrphanEffectChains(this);
+ mLock.lock();
}
return numHandles;
}
+bool AudioFlinger::EffectBase::purgeHandles()
+{
+ bool enabled = false;
+ Mutex::Autolock _l(mLock);
+ EffectHandle *handle = controlHandle_l();
+ if (handle != NULL) {
+ enabled = handle->enabled();
+ }
+ mHandles.clear();
+ return enabled;
+}
+
+void AudioFlinger::EffectBase::checkSuspendOnEffectEnabled(bool enabled, bool threadLocked) {
+ mCallback->checkSuspendOnEffectEnabled(this, enabled, threadLocked);
+}
+
+static String8 effectFlagsToString(uint32_t flags) {
+ String8 s;
+
+ s.append("conn. mode: ");
+ switch (flags & EFFECT_FLAG_TYPE_MASK) {
+ case EFFECT_FLAG_TYPE_INSERT: s.append("insert"); break;
+ case EFFECT_FLAG_TYPE_AUXILIARY: s.append("auxiliary"); break;
+ case EFFECT_FLAG_TYPE_REPLACE: s.append("replace"); break;
+ case EFFECT_FLAG_TYPE_PRE_PROC: s.append("preproc"); break;
+ case EFFECT_FLAG_TYPE_POST_PROC: s.append("postproc"); break;
+ default: s.append("unknown/reserved"); break;
+ }
+ s.append(", ");
+
+ s.append("insert pref: ");
+ switch (flags & EFFECT_FLAG_INSERT_MASK) {
+ case EFFECT_FLAG_INSERT_ANY: s.append("any"); break;
+ case EFFECT_FLAG_INSERT_FIRST: s.append("first"); break;
+ case EFFECT_FLAG_INSERT_LAST: s.append("last"); break;
+ case EFFECT_FLAG_INSERT_EXCLUSIVE: s.append("exclusive"); break;
+ default: s.append("unknown/reserved"); break;
+ }
+ s.append(", ");
+
+ s.append("volume mgmt: ");
+ switch (flags & EFFECT_FLAG_VOLUME_MASK) {
+ case EFFECT_FLAG_VOLUME_NONE: s.append("none"); break;
+ case EFFECT_FLAG_VOLUME_CTRL: s.append("implements control"); break;
+ case EFFECT_FLAG_VOLUME_IND: s.append("requires indication"); break;
+ case EFFECT_FLAG_VOLUME_MONITOR: s.append("monitors volume"); break;
+ default: s.append("unknown/reserved"); break;
+ }
+ s.append(", ");
+
+ uint32_t devind = flags & EFFECT_FLAG_DEVICE_MASK;
+ if (devind) {
+ s.append("device indication: ");
+ switch (devind) {
+ case EFFECT_FLAG_DEVICE_IND: s.append("requires updates"); break;
+ default: s.append("unknown/reserved"); break;
+ }
+ s.append(", ");
+ }
+
+ s.append("input mode: ");
+ switch (flags & EFFECT_FLAG_INPUT_MASK) {
+ case EFFECT_FLAG_INPUT_DIRECT: s.append("direct"); break;
+ case EFFECT_FLAG_INPUT_PROVIDER: s.append("provider"); break;
+ case EFFECT_FLAG_INPUT_BOTH: s.append("direct+provider"); break;
+ default: s.append("not set"); break;
+ }
+ s.append(", ");
+
+ s.append("output mode: ");
+ switch (flags & EFFECT_FLAG_OUTPUT_MASK) {
+ case EFFECT_FLAG_OUTPUT_DIRECT: s.append("direct"); break;
+ case EFFECT_FLAG_OUTPUT_PROVIDER: s.append("provider"); break;
+ case EFFECT_FLAG_OUTPUT_BOTH: s.append("direct+provider"); break;
+ default: s.append("not set"); break;
+ }
+ s.append(", ");
+
+ uint32_t accel = flags & EFFECT_FLAG_HW_ACC_MASK;
+ if (accel) {
+ s.append("hardware acceleration: ");
+ switch (accel) {
+ case EFFECT_FLAG_HW_ACC_SIMPLE: s.append("non-tunneled"); break;
+ case EFFECT_FLAG_HW_ACC_TUNNEL: s.append("tunneled"); break;
+ default: s.append("unknown/reserved"); break;
+ }
+ s.append(", ");
+ }
+
+ uint32_t modeind = flags & EFFECT_FLAG_AUDIO_MODE_MASK;
+ if (modeind) {
+ s.append("mode indication: ");
+ switch (modeind) {
+ case EFFECT_FLAG_AUDIO_MODE_IND: s.append("required"); break;
+ default: s.append("unknown/reserved"); break;
+ }
+ s.append(", ");
+ }
+
+ uint32_t srcind = flags & EFFECT_FLAG_AUDIO_SOURCE_MASK;
+ if (srcind) {
+ s.append("source indication: ");
+ switch (srcind) {
+ case EFFECT_FLAG_AUDIO_SOURCE_IND: s.append("required"); break;
+ default: s.append("unknown/reserved"); break;
+ }
+ s.append(", ");
+ }
+
+ if (flags & EFFECT_FLAG_OFFLOAD_MASK) {
+ s.append("offloadable, ");
+ }
+
+ int len = s.length();
+ if (s.length() > 2) {
+ (void) s.lockBuffer(len);
+ s.unlockBuffer(len - 2);
+ }
+ return s;
+}
+
+void AudioFlinger::EffectBase::dump(int fd, const Vector<String16>& args __unused)
+{
+ String8 result;
+
+ result.appendFormat("\tEffect ID %d:\n", mId);
+
+ bool locked = AudioFlinger::dumpTryLock(mLock);
+ // failed to lock - AudioFlinger is probably deadlocked
+ if (!locked) {
+ result.append("\t\tCould not lock Fx mutex:\n");
+ }
+
+ result.append("\t\tSession State Registered Enabled Suspended:\n");
+ result.appendFormat("\t\t%05d %03d %s %s %s\n",
+ mSessionId, mState, mPolicyRegistered ? "y" : "n",
+ mPolicyEnabled ? "y" : "n", mSuspended ? "y" : "n");
+
+ result.append("\t\tDescriptor:\n");
+ char uuidStr[64];
+ AudioEffect::guidToString(&mDescriptor.uuid, uuidStr, sizeof(uuidStr));
+ result.appendFormat("\t\t- UUID: %s\n", uuidStr);
+ AudioEffect::guidToString(&mDescriptor.type, uuidStr, sizeof(uuidStr));
+ result.appendFormat("\t\t- TYPE: %s\n", uuidStr);
+ result.appendFormat("\t\t- apiVersion: %08X\n\t\t- flags: %08X (%s)\n",
+ mDescriptor.apiVersion,
+ mDescriptor.flags,
+ effectFlagsToString(mDescriptor.flags).string());
+ result.appendFormat("\t\t- name: %s\n",
+ mDescriptor.name);
+
+ result.appendFormat("\t\t- implementor: %s\n",
+ mDescriptor.implementor);
+
+ result.appendFormat("\t\t%zu Clients:\n", mHandles.size());
+ result.append("\t\t\t Pid Priority Ctrl Locked client server\n");
+ char buffer[256];
+ for (size_t i = 0; i < mHandles.size(); ++i) {
+ EffectHandle *handle = mHandles[i];
+ if (handle != NULL && !handle->disconnected()) {
+ handle->dumpToBuffer(buffer, sizeof(buffer));
+ result.append(buffer);
+ }
+ }
+ if (locked) {
+ mLock.unlock();
+ }
+
+ write(fd, result.string(), result.length());
+}
+
+// ----------------------------------------------------------------------------
+// EffectModule implementation
+// ----------------------------------------------------------------------------
+
+#undef LOG_TAG
+#define LOG_TAG "AudioFlinger::EffectModule"
+
+AudioFlinger::EffectModule::EffectModule(const sp<AudioFlinger::EffectCallbackInterface>& callback,
+ effect_descriptor_t *desc,
+ int id,
+ audio_session_t sessionId,
+ bool pinned,
+ audio_port_handle_t deviceId)
+ : EffectBase(callback, desc, id, sessionId, pinned),
+ // clear mConfig to ensure consistent initial value of buffer framecount
+ // in case buffers are associated by setInBuffer() or setOutBuffer()
+ // prior to configure().
+ mConfig{{}, {}},
+ mStatus(NO_INIT),
+ mMaxDisableWaitCnt(1), // set by configure(), should be >= 1
+ mDisableWaitCnt(0), // set by process() and updateState()
+ mOffloaded(false)
+#ifdef FLOAT_EFFECT_CHAIN
+ , mSupportsFloat(false)
+#endif
+{
+ ALOGV("Constructor %p pinned %d", this, pinned);
+ int lStatus;
+
+ // create effect engine from effect factory
+ mStatus = callback->createEffectHal(
+ &desc->uuid, sessionId, deviceId, &mEffectInterface);
+ if (mStatus != NO_ERROR) {
+ return;
+ }
+ lStatus = init();
+ if (lStatus < 0) {
+ mStatus = lStatus;
+ goto Error;
+ }
+
+ setOffloaded(callback->isOffload(), callback->io());
+ ALOGV("Constructor success name %s, Interface %p", mDescriptor.name, mEffectInterface.get());
+
+ return;
+Error:
+ mEffectInterface.clear();
+ ALOGV("Constructor Error %d", mStatus);
+}
+
+AudioFlinger::EffectModule::~EffectModule()
+{
+ ALOGV("Destructor %p", this);
+ if (mEffectInterface != 0) {
+ char uuidStr[64];
+ AudioEffect::guidToString(&mDescriptor.uuid, uuidStr, sizeof(uuidStr));
+ ALOGW("EffectModule %p destructor called with unreleased interface, effect %s",
+ this, uuidStr);
+ release_l();
+ }
+
+}
+
+ssize_t AudioFlinger::EffectModule::removeHandle_l(EffectHandle *handle)
+{
+ ssize_t status = EffectBase::removeHandle_l(handle);
+
+ // Prevent calls to process() and other functions on effect interface from now on.
+ // The effect engine will be released by the destructor when the last strong reference on
+ // this object is released which can happen after next process is called.
+ if (status == 0 && !mPinned) {
+ mEffectInterface->close();
+ }
+
+ return status;
+}
+
bool AudioFlinger::EffectModule::updateState() {
Mutex::Autolock _l(mLock);
@@ -462,7 +737,7 @@
}
if (!mSupportsFloat) { // convert input to int16_t as effect doesn't support float.
if (!auxType) {
- if (mInConversionBuffer.get() == nullptr) {
+ if (mInConversionBuffer == nullptr) {
ALOGW("%s: mInConversionBuffer is null, bypassing", __func__);
goto data_bypass;
}
@@ -473,7 +748,7 @@
inBuffer = mInConversionBuffer;
}
if (mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
- if (mOutConversionBuffer.get() == nullptr) {
+ if (mOutConversionBuffer == nullptr) {
ALOGW("%s: mOutConversionBuffer is null, bypassing", __func__);
goto data_bypass;
}
@@ -540,8 +815,7 @@
mConfig.inputCfg.buffer.raw != mConfig.outputCfg.buffer.raw) {
// If an insert effect is idle and input buffer is different from output buffer,
// accumulate input onto output
- sp<EffectChain> chain = mChain.promote();
- if (chain.get() != nullptr && chain->activeTrackCnt() != 0) {
+ if (mCallback->activeTrackCnt() != 0) {
// similar handling with data_bypass above.
if (mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
accumulateInputToOutput();
@@ -564,7 +838,6 @@
{
ALOGVV("configure() started");
status_t status;
- sp<ThreadBase> thread;
uint32_t size;
audio_channel_mask_t channelMask;
@@ -573,17 +846,11 @@
goto exit;
}
- thread = mThread.promote();
- if (thread == 0) {
- status = DEAD_OBJECT;
- goto exit;
- }
-
// TODO: handle configuration of effects replacing track process
// TODO: handle configuration of input (record) SW effects above the HAL,
// similar to output EFFECT_FLAG_TYPE_INSERT/REPLACE,
// in which case input channel masks should be used here.
- channelMask = thread->channelMask();
+ channelMask = mCallback->channelMask();
mConfig.inputCfg.channels = channelMask;
mConfig.outputCfg.channels = channelMask;
@@ -620,11 +887,11 @@
mConfig.outputCfg.format = EFFECT_BUFFER_FORMAT;
// Don't use sample rate for thread if effect isn't offloadable.
- if ((thread->type() == ThreadBase::OFFLOAD) && !isOffloaded()) {
+ if (mCallback->isOffloadOrDirect() && !isOffloaded()) {
mConfig.inputCfg.samplingRate = DEFAULT_OUTPUT_SAMPLE_RATE;
ALOGV("Overriding effect input as 48kHz");
} else {
- mConfig.inputCfg.samplingRate = thread->sampleRate();
+ mConfig.inputCfg.samplingRate = mCallback->sampleRate();
}
mConfig.outputCfg.samplingRate = mConfig.inputCfg.samplingRate;
mConfig.inputCfg.bufferProvider.cookie = NULL;
@@ -635,7 +902,7 @@
mConfig.outputCfg.bufferProvider.releaseBuffer = NULL;
mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
// Insert effect:
- // - in session AUDIO_SESSION_OUTPUT_MIX or AUDIO_SESSION_OUTPUT_STAGE,
+ // - in global sessions (e.g AUDIO_SESSION_OUTPUT_MIX),
// always overwrites output buffer: input buffer == output buffer
// - in other sessions:
// last effect in the chain accumulates in output buffer: input buffer != output buffer
@@ -650,11 +917,12 @@
}
mConfig.inputCfg.mask = EFFECT_CONFIG_ALL;
mConfig.outputCfg.mask = EFFECT_CONFIG_ALL;
- mConfig.inputCfg.buffer.frameCount = thread->frameCount();
+ mConfig.inputCfg.buffer.frameCount = mCallback->frameCount();
mConfig.outputCfg.buffer.frameCount = mConfig.inputCfg.buffer.frameCount;
- ALOGV("configure() %p thread %p buffer %p framecount %zu",
- this, thread.get(), mConfig.inputCfg.buffer.raw, mConfig.inputCfg.buffer.frameCount);
+ ALOGV("configure() %p chain %p buffer %p framecount %zu",
+ this, mCallback->chain().promote().get(),
+ mConfig.inputCfg.buffer.raw, mConfig.inputCfg.buffer.frameCount);
status_t cmdStatus;
size = sizeof(int);
@@ -669,7 +937,7 @@
#ifdef MULTICHANNEL_EFFECT_CHAIN
if (status != NO_ERROR &&
- thread->isOutput() &&
+ mCallback->isOutput() &&
(mConfig.inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO
|| mConfig.outputCfg.channels != AUDIO_CHANNEL_OUT_STEREO)) {
// Older effects may require exact STEREO position mask.
@@ -736,11 +1004,7 @@
size = sizeof(int);
*(int32_t *)p->data = VISUALIZER_PARAM_LATENCY;
- uint32_t latency = 0;
- PlaybackThread *pbt = thread->mAudioFlinger->checkPlaybackThread_l(thread->mId);
- if (pbt != NULL) {
- latency = pbt->latency_l();
- }
+ uint32_t latency = mCallback->latency();
*((int32_t *)p->data + 1)= latency;
mEffectInterface->command(EFFECT_CMD_SET_PARAM,
@@ -787,31 +1051,20 @@
{
if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC ||
(mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC) {
- sp<ThreadBase> thread = mThread.promote();
- if (thread != 0) {
- sp<StreamHalInterface> stream = thread->stream();
- if (stream != 0) {
- status_t result = stream->addEffect(mEffectInterface);
- ALOGE_IF(result != OK, "Error when adding effect: %d", result);
- }
- }
+ (void)mCallback->addEffectToHal(mEffectInterface);
}
}
// start() must be called with PlaybackThread::mLock or EffectChain::mLock held
status_t AudioFlinger::EffectModule::start()
{
- sp<EffectChain> chain;
status_t status;
{
Mutex::Autolock _l(mLock);
status = start_l();
- if (status == NO_ERROR) {
- chain = mChain.promote();
- }
}
- if (chain != 0) {
- chain->resetVolume_l();
+ if (status == NO_ERROR) {
+ mCallback->resetVolume();
}
return status;
}
@@ -858,11 +1111,10 @@
uint32_t size = sizeof(status_t);
if (isVolumeControl() && isOffloadedOrDirect()) {
- sp<EffectChain>chain = mChain.promote();
// We have the EffectChain and EffectModule lock, permit a reentrant call to setVolume:
// resetVolume_l --> setVolume_l --> EffectModule::setVolume
mSetVolumeReentrantTid = gettid();
- chain->resetVolume_l();
+ mCallback->resetVolume();
mSetVolumeReentrantTid = INVALID_PID;
}
@@ -875,7 +1127,7 @@
status = cmdStatus;
}
if (status == NO_ERROR) {
- status = remove_effect_from_hal_l();
+ status = removeEffectFromHal_l();
}
return status;
}
@@ -884,25 +1136,18 @@
void AudioFlinger::EffectModule::release_l()
{
if (mEffectInterface != 0) {
- remove_effect_from_hal_l();
+ removeEffectFromHal_l();
// release effect engine
mEffectInterface->close();
mEffectInterface.clear();
}
}
-status_t AudioFlinger::EffectModule::remove_effect_from_hal_l()
+status_t AudioFlinger::EffectModule::removeEffectFromHal_l()
{
if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC ||
(mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC) {
- sp<ThreadBase> thread = mThread.promote();
- if (thread != 0) {
- sp<StreamHalInterface> stream = thread->stream();
- if (stream != 0) {
- status_t result = stream->removeEffect(mEffectInterface);
- ALOGE_IF(result != OK, "Error when removing effect: %d", result);
- }
- }
+ mCallback->removeEffectFromHal(mEffectInterface);
}
return NO_ERROR;
}
@@ -992,70 +1237,6 @@
return status;
}
-status_t AudioFlinger::EffectModule::setEnabled(bool enabled)
-{
- Mutex::Autolock _l(mLock);
- return setEnabled_l(enabled);
-}
-
-// must be called with EffectModule::mLock held
-status_t AudioFlinger::EffectModule::setEnabled_l(bool enabled)
-{
-
- ALOGV("setEnabled %p enabled %d", this, enabled);
-
- if (enabled != isEnabled()) {
- switch (mState) {
- // going from disabled to enabled
- case IDLE:
- mState = STARTING;
- break;
- case STOPPED:
- mState = RESTART;
- break;
- case STOPPING:
- mState = ACTIVE;
- break;
-
- // going from enabled to disabled
- case RESTART:
- mState = STOPPED;
- break;
- case STARTING:
- mState = IDLE;
- break;
- case ACTIVE:
- mState = STOPPING;
- break;
- case DESTROYED:
- return NO_ERROR; // simply ignore as we are being destroyed
- }
- for (size_t i = 1; i < mHandles.size(); i++) {
- EffectHandle *h = mHandles[i];
- if (h != NULL && !h->disconnected()) {
- h->setEnabled(enabled);
- }
- }
- }
- return NO_ERROR;
-}
-
-bool AudioFlinger::EffectModule::isEnabled() const
-{
- switch (mState) {
- case RESTART:
- case STARTING:
- case ACTIVE:
- return true;
- case IDLE:
- case STOPPING:
- case STOPPED:
- case DESTROYED:
- default:
- return false;
- }
-}
-
bool AudioFlinger::EffectModule::isProcessEnabled() const
{
if (mStatus != NO_ERROR) {
@@ -1078,7 +1259,7 @@
bool AudioFlinger::EffectModule::isOffloadedOrDirect() const
{
- return (mThreadType == ThreadBase::OFFLOAD || mThreadType == ThreadBase::DIRECT);
+ return mCallback->isOffloadOrDirect();
}
bool AudioFlinger::EffectModule::isVolumeControlEnabled() const
@@ -1108,7 +1289,7 @@
const uint32_t inChannelCount =
audio_channel_count_from_out_mask(mConfig.inputCfg.channels);
const bool formatMismatch = !mSupportsFloat || mInChannelCountRequested != inChannelCount;
- if (!auxType && formatMismatch && mInBuffer.get() != nullptr) {
+ if (!auxType && formatMismatch && mInBuffer != nullptr) {
// we need to translate - create hidl shared buffer and intercept
const size_t inFrameCount = mConfig.inputCfg.buffer.frameCount;
// Use FCC_2 in case mInChannelCountRequested is mono and the effect is stereo.
@@ -1118,15 +1299,13 @@
ALOGV("%s: setInBuffer updating for inChannels:%d inFrameCount:%zu total size:%zu",
__func__, inChannels, inFrameCount, size);
- if (size > 0 && (mInConversionBuffer.get() == nullptr
+ if (size > 0 && (mInConversionBuffer == nullptr
|| size > mInConversionBuffer->getSize())) {
mInConversionBuffer.clear();
ALOGV("%s: allocating mInConversionBuffer %zu", __func__, size);
- sp<AudioFlinger> audioFlinger = mAudioFlinger.promote();
- LOG_ALWAYS_FATAL_IF(audioFlinger == nullptr, "EM could not retrieved audioFlinger");
- (void)audioFlinger->mEffectsFactoryHal->allocateBuffer(size, &mInConversionBuffer);
+ (void)mCallback->allocateHalBuffer(size, &mInConversionBuffer);
}
- if (mInConversionBuffer.get() != nullptr) {
+ if (mInConversionBuffer != nullptr) {
mInConversionBuffer->setFrameCount(inFrameCount);
mEffectInterface->setInBuffer(mInConversionBuffer);
} else if (size > 0) {
@@ -1155,7 +1334,7 @@
const uint32_t outChannelCount =
audio_channel_count_from_out_mask(mConfig.outputCfg.channels);
const bool formatMismatch = !mSupportsFloat || mOutChannelCountRequested != outChannelCount;
- if (formatMismatch && mOutBuffer.get() != nullptr) {
+ if (formatMismatch && mOutBuffer != nullptr) {
const size_t outFrameCount = mConfig.outputCfg.buffer.frameCount;
// Use FCC_2 in case mOutChannelCountRequested is mono and the effect is stereo.
const uint32_t outChannels = std::max((uint32_t)FCC_2, mOutChannelCountRequested);
@@ -1164,15 +1343,13 @@
ALOGV("%s: setOutBuffer updating for outChannels:%d outFrameCount:%zu total size:%zu",
__func__, outChannels, outFrameCount, size);
- if (size > 0 && (mOutConversionBuffer.get() == nullptr
+ if (size > 0 && (mOutConversionBuffer == nullptr
|| size > mOutConversionBuffer->getSize())) {
mOutConversionBuffer.clear();
ALOGV("%s: allocating mOutConversionBuffer %zu", __func__, size);
- sp<AudioFlinger> audioFlinger = mAudioFlinger.promote();
- LOG_ALWAYS_FATAL_IF(audioFlinger == nullptr, "EM could not retrieved audioFlinger");
- (void)audioFlinger->mEffectsFactoryHal->allocateBuffer(size, &mOutConversionBuffer);
+ (void)mCallback->allocateHalBuffer(size, &mOutConversionBuffer);
}
- if (mOutConversionBuffer.get() != nullptr) {
+ if (mOutConversionBuffer != nullptr) {
mOutConversionBuffer->setFrameCount(outFrameCount);
mEffectInterface->setOutBuffer(mOutConversionBuffer);
} else if (size > 0) {
@@ -1218,20 +1395,22 @@
void AudioFlinger::EffectChain::setVolumeForOutput_l(uint32_t left, uint32_t right)
{
- sp<ThreadBase> thread = mThread.promote();
- if (thread != 0 &&
- (thread->type() == ThreadBase::OFFLOAD || thread->type() == ThreadBase::DIRECT) &&
- !isNonOffloadableEnabled_l()) {
- PlaybackThread *t = (PlaybackThread *)thread.get();
+ // for offload or direct thread, if the effect chain has non-offloadable
+ // effect and any effect module within the chain has volume control, then
+ // volume control is delegated to effect, otherwise, set volume to hal.
+ if (mEffectCallback->isOffloadOrDirect() &&
+ !(isNonOffloadableEnabled_l() && hasVolumeControlEnabled_l())) {
float vol_l = (float)left / (1 << 24);
float vol_r = (float)right / (1 << 24);
- t->setVolumeForOutput_l(vol_l, vol_r);
+ mEffectCallback->setVolumeForOutput(vol_l, vol_r);
}
}
-status_t AudioFlinger::EffectModule::setDevice(audio_devices_t device)
+status_t AudioFlinger::EffectModule::sendSetAudioDevicesCommand(
+ const AudioDeviceTypeAddrVector &devices, uint32_t cmdCode)
{
- if (device == AUDIO_DEVICE_NONE) {
+ audio_devices_t deviceType = deviceTypesToBitMask(getAudioDeviceTypes(devices));
+ if (deviceType == AUDIO_DEVICE_NONE) {
return NO_ERROR;
}
@@ -1243,17 +1422,26 @@
if ((mDescriptor.flags & EFFECT_FLAG_DEVICE_MASK) == EFFECT_FLAG_DEVICE_IND) {
status_t cmdStatus;
uint32_t size = sizeof(status_t);
- uint32_t cmd = audio_is_output_devices(device) ? EFFECT_CMD_SET_DEVICE :
- EFFECT_CMD_SET_INPUT_DEVICE;
- status = mEffectInterface->command(cmd,
+ // FIXME: use audio device types and addresses when the hal interface is ready.
+ status = mEffectInterface->command(cmdCode,
sizeof(uint32_t),
- &device,
+ &deviceType,
&size,
&cmdStatus);
}
return status;
}
+status_t AudioFlinger::EffectModule::setDevices(const AudioDeviceTypeAddrVector &devices)
+{
+ return sendSetAudioDevicesCommand(devices, EFFECT_CMD_SET_DEVICE);
+}
+
+status_t AudioFlinger::EffectModule::setInputDevice(const AudioDeviceTypeAddr &device)
+{
+ return sendSetAudioDevicesCommand({device}, EFFECT_CMD_SET_INPUT_DEVICE);
+}
+
status_t AudioFlinger::EffectModule::setMode(audio_mode_t mode)
{
Mutex::Autolock _l(mLock);
@@ -1294,30 +1482,6 @@
return status;
}
-void AudioFlinger::EffectModule::setSuspended(bool suspended)
-{
- Mutex::Autolock _l(mLock);
- mSuspended = suspended;
-}
-
-bool AudioFlinger::EffectModule::suspended() const
-{
- Mutex::Autolock _l(mLock);
- return mSuspended;
-}
-
-bool AudioFlinger::EffectModule::purgeHandles()
-{
- bool enabled = false;
- Mutex::Autolock _l(mLock);
- EffectHandle *handle = controlHandle_l();
- if (handle != NULL) {
- enabled = handle->enabled();
- }
- mHandles.clear();
- return enabled;
-}
-
status_t AudioFlinger::EffectModule::setOffloaded(bool offloaded, audio_io_handle_t io)
{
Mutex::Autolock _l(mLock);
@@ -1357,115 +1521,10 @@
return mOffloaded;
}
-String8 effectFlagsToString(uint32_t flags) {
- String8 s;
-
- s.append("conn. mode: ");
- switch (flags & EFFECT_FLAG_TYPE_MASK) {
- case EFFECT_FLAG_TYPE_INSERT: s.append("insert"); break;
- case EFFECT_FLAG_TYPE_AUXILIARY: s.append("auxiliary"); break;
- case EFFECT_FLAG_TYPE_REPLACE: s.append("replace"); break;
- case EFFECT_FLAG_TYPE_PRE_PROC: s.append("preproc"); break;
- case EFFECT_FLAG_TYPE_POST_PROC: s.append("postproc"); break;
- default: s.append("unknown/reserved"); break;
- }
- s.append(", ");
-
- s.append("insert pref: ");
- switch (flags & EFFECT_FLAG_INSERT_MASK) {
- case EFFECT_FLAG_INSERT_ANY: s.append("any"); break;
- case EFFECT_FLAG_INSERT_FIRST: s.append("first"); break;
- case EFFECT_FLAG_INSERT_LAST: s.append("last"); break;
- case EFFECT_FLAG_INSERT_EXCLUSIVE: s.append("exclusive"); break;
- default: s.append("unknown/reserved"); break;
- }
- s.append(", ");
-
- s.append("volume mgmt: ");
- switch (flags & EFFECT_FLAG_VOLUME_MASK) {
- case EFFECT_FLAG_VOLUME_NONE: s.append("none"); break;
- case EFFECT_FLAG_VOLUME_CTRL: s.append("implements control"); break;
- case EFFECT_FLAG_VOLUME_IND: s.append("requires indication"); break;
- case EFFECT_FLAG_VOLUME_MONITOR: s.append("monitors volume"); break;
- default: s.append("unknown/reserved"); break;
- }
- s.append(", ");
-
- uint32_t devind = flags & EFFECT_FLAG_DEVICE_MASK;
- if (devind) {
- s.append("device indication: ");
- switch (devind) {
- case EFFECT_FLAG_DEVICE_IND: s.append("requires updates"); break;
- default: s.append("unknown/reserved"); break;
- }
- s.append(", ");
- }
-
- s.append("input mode: ");
- switch (flags & EFFECT_FLAG_INPUT_MASK) {
- case EFFECT_FLAG_INPUT_DIRECT: s.append("direct"); break;
- case EFFECT_FLAG_INPUT_PROVIDER: s.append("provider"); break;
- case EFFECT_FLAG_INPUT_BOTH: s.append("direct+provider"); break;
- default: s.append("not set"); break;
- }
- s.append(", ");
-
- s.append("output mode: ");
- switch (flags & EFFECT_FLAG_OUTPUT_MASK) {
- case EFFECT_FLAG_OUTPUT_DIRECT: s.append("direct"); break;
- case EFFECT_FLAG_OUTPUT_PROVIDER: s.append("provider"); break;
- case EFFECT_FLAG_OUTPUT_BOTH: s.append("direct+provider"); break;
- default: s.append("not set"); break;
- }
- s.append(", ");
-
- uint32_t accel = flags & EFFECT_FLAG_HW_ACC_MASK;
- if (accel) {
- s.append("hardware acceleration: ");
- switch (accel) {
- case EFFECT_FLAG_HW_ACC_SIMPLE: s.append("non-tunneled"); break;
- case EFFECT_FLAG_HW_ACC_TUNNEL: s.append("tunneled"); break;
- default: s.append("unknown/reserved"); break;
- }
- s.append(", ");
- }
-
- uint32_t modeind = flags & EFFECT_FLAG_AUDIO_MODE_MASK;
- if (modeind) {
- s.append("mode indication: ");
- switch (modeind) {
- case EFFECT_FLAG_AUDIO_MODE_IND: s.append("required"); break;
- default: s.append("unknown/reserved"); break;
- }
- s.append(", ");
- }
-
- uint32_t srcind = flags & EFFECT_FLAG_AUDIO_SOURCE_MASK;
- if (srcind) {
- s.append("source indication: ");
- switch (srcind) {
- case EFFECT_FLAG_AUDIO_SOURCE_IND: s.append("required"); break;
- default: s.append("unknown/reserved"); break;
- }
- s.append(", ");
- }
-
- if (flags & EFFECT_FLAG_OFFLOAD_MASK) {
- s.append("offloadable, ");
- }
-
- int len = s.length();
- if (s.length() > 2) {
- (void) s.lockBuffer(len);
- s.unlockBuffer(len - 2);
- }
- return s;
-}
-
static std::string dumpInOutBuffer(bool isInput, const sp<EffectBufferHalInterface> &buffer) {
std::stringstream ss;
- if (buffer.get() == nullptr) {
+ if (buffer == nullptr) {
return "nullptr"; // make different than below
} else if (buffer->externalData() != nullptr) {
ss << (isInput ? buffer->externalData() : buffer->audioBuffer()->raw)
@@ -1477,38 +1536,16 @@
return ss.str();
}
-void AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args __unused)
+void AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args)
{
+ EffectBase::dump(fd, args);
+
String8 result;
-
- result.appendFormat("\tEffect ID %d:\n", mId);
-
bool locked = AudioFlinger::dumpTryLock(mLock);
- // failed to lock - AudioFlinger is probably deadlocked
- if (!locked) {
- result.append("\t\tCould not lock Fx mutex:\n");
- }
- result.append("\t\tSession Status State Registered Enabled Suspended Engine:\n");
- result.appendFormat("\t\t%05d %03d %03d %s %s %s %p\n",
- mSessionId, mStatus, mState, mPolicyRegistered ? "y" : "n", mPolicyEnabled ? "y" : "n",
- mSuspended ? "y" : "n", mEffectInterface.get());
-
- result.append("\t\tDescriptor:\n");
- char uuidStr[64];
- AudioEffect::guidToString(&mDescriptor.uuid, uuidStr, sizeof(uuidStr));
- result.appendFormat("\t\t- UUID: %s\n", uuidStr);
- AudioEffect::guidToString(&mDescriptor.type, uuidStr, sizeof(uuidStr));
- result.appendFormat("\t\t- TYPE: %s\n", uuidStr);
- result.appendFormat("\t\t- apiVersion: %08X\n\t\t- flags: %08X (%s)\n",
- mDescriptor.apiVersion,
- mDescriptor.flags,
- effectFlagsToString(mDescriptor.flags).string());
- result.appendFormat("\t\t- name: %s\n",
- mDescriptor.name);
-
- result.appendFormat("\t\t- implementor: %s\n",
- mDescriptor.implementor);
+ result.append("\t\tStatus Engine:\n");
+ result.appendFormat("\t\t%03d %p\n",
+ mStatus, mEffectInterface.get());
result.appendFormat("\t\t- data: %s\n", mSupportsFloat ? "float" : "int16");
@@ -1542,17 +1579,6 @@
dumpInOutBuffer(false /* isInput */, mOutConversionBuffer).c_str());
#endif
- result.appendFormat("\t\t%zu Clients:\n", mHandles.size());
- result.append("\t\t\t Pid Priority Ctrl Locked client server\n");
- char buffer[256];
- for (size_t i = 0; i < mHandles.size(); ++i) {
- EffectHandle *handle = mHandles[i];
- if (handle != NULL && !handle->disconnected()) {
- handle->dumpToBuffer(buffer, sizeof(buffer));
- result.append(buffer);
- }
- }
-
write(fd, result.string(), result.length());
if (mEffectInterface != 0) {
@@ -1572,7 +1598,7 @@
#undef LOG_TAG
#define LOG_TAG "AudioFlinger::EffectHandle"
-AudioFlinger::EffectHandle::EffectHandle(const sp<EffectModule>& effect,
+AudioFlinger::EffectHandle::EffectHandle(const sp<EffectBase>& effect,
const sp<AudioFlinger::Client>& client,
const sp<IEffectClient>& effectClient,
int32_t priority)
@@ -1580,7 +1606,7 @@
mEffect(effect), mEffectClient(effectClient), mClient(client), mCblk(NULL),
mPriority(priority), mHasControl(false), mEnabled(false), mDisconnected(false)
{
- ALOGV("constructor %p", this);
+ ALOGV("constructor %p client %p", this, client.get());
if (client == 0) {
return;
@@ -1588,7 +1614,7 @@
int bufOffset = ((sizeof(effect_param_cblk_t) - 1) / sizeof(int) + 1) * sizeof(int);
mCblkMemory = client->heap()->allocate(EFFECT_PARAM_BUFFER_SIZE + bufOffset);
if (mCblkMemory == 0 ||
- (mCblk = static_cast<effect_param_cblk_t *>(mCblkMemory->pointer())) == NULL) {
+ (mCblk = static_cast<effect_param_cblk_t *>(mCblkMemory->unsecurePointer())) == NULL) {
ALOGE("not enough memory for Effect size=%zu", EFFECT_PARAM_BUFFER_SIZE +
sizeof(effect_param_cblk_t));
mCblkMemory.clear();
@@ -1613,7 +1639,7 @@
{
AutoMutex _l(mLock);
ALOGV("enable %p", this);
- sp<EffectModule> effect = mEffect.promote();
+ sp<EffectBase> effect = mEffect.promote();
if (effect == 0 || mDisconnected) {
return DEAD_OBJECT;
}
@@ -1633,38 +1659,16 @@
return status;
}
- sp<ThreadBase> thread = effect->thread().promote();
- if (thread != 0) {
- thread->checkSuspendOnEffectEnabled(effect, true, effect->sessionId());
- }
+ effect->checkSuspendOnEffectEnabled(true, false /*threadLocked*/);
// checkSuspendOnEffectEnabled() can suspend this same effect when enabled
if (effect->suspended()) {
return NO_ERROR;
}
- status = effect->setEnabled(true);
+ status = effect->setEnabled(true, true /*fromHandle*/);
if (status != NO_ERROR) {
- if (thread != 0) {
- thread->checkSuspendOnEffectEnabled(effect, false, effect->sessionId());
- }
mEnabled = false;
- } else {
- if (thread != 0) {
- if (thread->type() == ThreadBase::OFFLOAD || thread->type() == ThreadBase::MMAP) {
- Mutex::Autolock _l(thread->mLock);
- thread->broadcast_l();
- }
- if (!effect->isOffloadable()) {
- if (thread->type() == ThreadBase::OFFLOAD) {
- PlaybackThread *t = (PlaybackThread *)thread.get();
- t->invalidateTracks(AUDIO_STREAM_MUSIC);
- }
- if (effect->sessionId() == AUDIO_SESSION_OUTPUT_MIX) {
- thread->mAudioFlinger->onNonOffloadableGlobalEffectEnable();
- }
- }
- }
}
return status;
}
@@ -1673,7 +1677,7 @@
{
ALOGV("disable %p", this);
AutoMutex _l(mLock);
- sp<EffectModule> effect = mEffect.promote();
+ sp<EffectBase> effect = mEffect.promote();
if (effect == 0 || mDisconnected) {
return DEAD_OBJECT;
}
@@ -1692,17 +1696,7 @@
return NO_ERROR;
}
- status_t status = effect->setEnabled(false);
-
- sp<ThreadBase> thread = effect->thread().promote();
- if (thread != 0) {
- thread->checkSuspendOnEffectEnabled(effect, false, effect->sessionId());
- if (thread->type() == ThreadBase::OFFLOAD || thread->type() == ThreadBase::MMAP) {
- Mutex::Autolock _l(thread->mLock);
- thread->broadcast_l();
- }
- }
-
+ status_t status = effect->setEnabled(false, true /*fromHandle*/);
return status;
}
@@ -1724,12 +1718,9 @@
}
mDisconnected = true;
{
- sp<EffectModule> effect = mEffect.promote();
+ sp<EffectBase> effect = mEffect.promote();
if (effect != 0) {
- sp<ThreadBase> thread = effect->thread().promote();
- if (thread != 0) {
- thread->disconnectEffectHandle(this, unpinIfLast);
- } else if (effect->disconnectHandle(this, unpinIfLast) > 0) {
+ if (effect->disconnectHandle(this, unpinIfLast) > 0) {
ALOGW("%s Effect handle %p disconnected after thread destruction",
__func__, this);
}
@@ -1795,7 +1786,7 @@
}
AutoMutex _l(mLock);
- sp<EffectModule> effect = mEffect.promote();
+ sp<EffectBase> effect = mEffect.promote();
if (effect == 0 || mDisconnected) {
return DEAD_OBJECT;
}
@@ -1803,12 +1794,13 @@
if (!mHasControl && cmdCode != EFFECT_CMD_GET_PARAM) {
return INVALID_OPERATION;
}
- if (mClient == 0) {
- return INVALID_OPERATION;
- }
// handle commands that are not forwarded transparently to effect engine
if (cmdCode == EFFECT_CMD_SET_PARAM_COMMIT) {
+ if (mClient == 0) {
+ return INVALID_OPERATION;
+ }
+
if (*replySize < sizeof(int)) {
android_errorWriteLog(0x534e4554, "32095713");
return BAD_VALUE;
@@ -1843,12 +1835,13 @@
}
// copy to local memory in case of client corruption b/32220769
- param = (effect_param_t *)realloc(param, size);
- if (param == NULL) {
+ auto *newParam = (effect_param_t *)realloc(param, size);
+ if (newParam == NULL) {
ALOGW("command(): out of memory");
status = NO_MEMORY;
break;
}
+ param = newParam;
memcpy(param, p, size);
int reply = 0;
@@ -1947,18 +1940,20 @@
#undef LOG_TAG
#define LOG_TAG "AudioFlinger::EffectChain"
-AudioFlinger::EffectChain::EffectChain(ThreadBase *thread,
- audio_session_t sessionId)
- : mThread(thread), mSessionId(sessionId), mActiveTrackCnt(0), mTrackCnt(0), mTailBufferCount(0),
+AudioFlinger::EffectChain::EffectChain(const wp<ThreadBase>& thread,
+ audio_session_t sessionId)
+ : mSessionId(sessionId), mActiveTrackCnt(0), mTrackCnt(0), mTailBufferCount(0),
mVolumeCtrlIdx(-1), mLeftVolume(UINT_MAX), mRightVolume(UINT_MAX),
- mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX)
+ mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX),
+ mEffectCallback(new EffectCallback(wp<EffectChain>(this), thread))
{
mStrategy = AudioSystem::getStrategyForStream(AUDIO_STREAM_MUSIC);
- if (thread == NULL) {
+ sp<ThreadBase> p = thread.promote();
+ if (p == nullptr) {
return;
}
- mMaxTailBuffers = ((kProcessTailDurationMs * thread->sampleRate()) / 1000) /
- thread->frameCount();
+ mMaxTailBuffers = ((kProcessTailDurationMs * p->sampleRate()) / 1000) /
+ p->frameCount();
}
AudioFlinger::EffectChain::~EffectChain()
@@ -2020,43 +2015,30 @@
void AudioFlinger::EffectChain::clearInputBuffer()
{
Mutex::Autolock _l(mLock);
- sp<ThreadBase> thread = mThread.promote();
- if (thread == 0) {
- ALOGW("clearInputBuffer(): cannot promote mixer thread");
- return;
- }
- clearInputBuffer_l(thread);
+ clearInputBuffer_l();
}
// Must be called with EffectChain::mLock locked
-void AudioFlinger::EffectChain::clearInputBuffer_l(const sp<ThreadBase>& thread)
+void AudioFlinger::EffectChain::clearInputBuffer_l()
{
if (mInBuffer == NULL) {
return;
}
const size_t frameSize =
- audio_bytes_per_sample(EFFECT_BUFFER_FORMAT) * thread->channelCount();
+ audio_bytes_per_sample(EFFECT_BUFFER_FORMAT) * mEffectCallback->channelCount();
- memset(mInBuffer->audioBuffer()->raw, 0, thread->frameCount() * frameSize);
+ memset(mInBuffer->audioBuffer()->raw, 0, mEffectCallback->frameCount() * frameSize);
mInBuffer->commit();
}
// Must be called with EffectChain::mLock locked
void AudioFlinger::EffectChain::process_l()
{
- sp<ThreadBase> thread = mThread.promote();
- if (thread == 0) {
- ALOGW("process_l(): cannot promote mixer thread");
- return;
- }
- bool isGlobalSession = (mSessionId == AUDIO_SESSION_OUTPUT_MIX) ||
- (mSessionId == AUDIO_SESSION_OUTPUT_STAGE);
// never process effects when:
// - on an OFFLOAD thread
// - no more tracks are on the session and the effect tail has been rendered
- bool doProcess = (thread->type() != ThreadBase::OFFLOAD)
- && (thread->type() != ThreadBase::MMAP);
- if (!isGlobalSession) {
+ bool doProcess = !mEffectCallback->isOffloadOrMmap();
+ if (!audio_is_global_session(mSessionId)) {
bool tracksOnSession = (trackCnt() != 0);
if (!tracksOnSession && mTailBufferCount == 0) {
@@ -2067,7 +2049,7 @@
// if no track is active and the effect tail has not been rendered,
// the input buffer must be cleared here as the mixer process will not do it
if (tracksOnSession || mTailBufferCount > 0) {
- clearInputBuffer_l(thread);
+ clearInputBuffer_l();
if (mTailBufferCount > 0) {
mTailBufferCount--;
}
@@ -2103,14 +2085,13 @@
// createEffect_l() must be called with ThreadBase::mLock held
status_t AudioFlinger::EffectChain::createEffect_l(sp<EffectModule>& effect,
- ThreadBase *thread,
effect_descriptor_t *desc,
int id,
audio_session_t sessionId,
bool pinned)
{
Mutex::Autolock _l(mLock);
- effect = new EffectModule(thread, this, desc, id, sessionId, pinned);
+ effect = new EffectModule(mEffectCallback, desc, id, sessionId, pinned, AUDIO_PORT_HANDLE_NONE);
status_t lStatus = effect->status();
if (lStatus == NO_ERROR) {
lStatus = addEffect_ll(effect);
@@ -2133,12 +2114,7 @@
effect_descriptor_t desc = effect->desc();
uint32_t insertPref = desc.flags & EFFECT_FLAG_INSERT_MASK;
- effect->setChain(this);
- sp<ThreadBase> thread = mThread.promote();
- if (thread == 0) {
- return NO_INIT;
- }
- effect->setThread(thread);
+ effect->setCallback(mEffectCallback);
if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
// Auxiliary effects are inserted at the beginning of mEffects vector as
@@ -2149,13 +2125,13 @@
// 32 bit format. This is to avoid saturation in AudoMixer
// accumulation stage. Saturation is done in EffectModule::process() before
// calling the process in effect engine
- size_t numSamples = thread->frameCount();
+ size_t numSamples = mEffectCallback->frameCount();
sp<EffectBufferHalInterface> halBuffer;
#ifdef FLOAT_EFFECT_CHAIN
- status_t result = thread->mAudioFlinger->mEffectsFactoryHal->allocateBuffer(
+ status_t result = mEffectCallback->allocateHalBuffer(
numSamples * sizeof(float), &halBuffer);
#else
- status_t result = thread->mAudioFlinger->mEffectsFactoryHal->allocateBuffer(
+ status_t result = mEffectCallback->allocateHalBuffer(
numSamples * sizeof(int32_t), &halBuffer);
#endif
if (result != OK) return result;
@@ -2288,12 +2264,21 @@
return mEffects.size();
}
-// setDevice_l() must be called with ThreadBase::mLock held
-void AudioFlinger::EffectChain::setDevice_l(audio_devices_t device)
+// setDevices_l() must be called with ThreadBase::mLock held
+void AudioFlinger::EffectChain::setDevices_l(const AudioDeviceTypeAddrVector &devices)
{
size_t size = mEffects.size();
for (size_t i = 0; i < size; i++) {
- mEffects[i]->setDevice(device);
+ mEffects[i]->setDevices(devices);
+ }
+}
+
+// setInputDevice_l() must be called with ThreadBase::mLock held
+void AudioFlinger::EffectChain::setInputDevice_l(const AudioDeviceTypeAddr &device)
+{
+ size_t size = mEffects.size();
+ for (size_t i = 0; i < size; i++) {
+ mEffects[i]->setInputDevice(device);
}
}
@@ -2315,6 +2300,13 @@
}
}
+bool AudioFlinger::EffectChain::hasVolumeControlEnabled_l() const {
+ for (const auto &effect : mEffects) {
+ if (effect->isVolumeControlEnabled()) return true;
+ }
+ return false;
+}
+
// setVolume_l() must be called with ThreadBase::mLock or EffectChain::mLock held
bool AudioFlinger::EffectChain::setVolume_l(uint32_t *left, uint32_t *right, bool force)
{
@@ -2464,7 +2456,7 @@
if (effect != 0) {
desc->mEffect = effect;
effect->setSuspended(true);
- effect->setEnabled(false);
+ effect->setEnabled(false, false /*fromHandle*/);
}
}
} else {
@@ -2622,7 +2614,7 @@
// if effect is requested to suspended but was not yet enabled, suspend it now.
if (desc->mEffect == 0) {
desc->mEffect = effect;
- effect->setEnabled(false);
+ effect->setEnabled(false, false /*fromHandle*/);
effect->setSuspended(true);
}
} else {
@@ -2657,10 +2649,7 @@
void AudioFlinger::EffectChain::setThread(const sp<ThreadBase>& thread)
{
Mutex::Autolock _l(mLock);
- mThread = thread;
- for (size_t i = 0; i < mEffects.size(); i++) {
- mEffects[i]->setThread(thread);
- }
+ mEffectCallback->setThread(thread);
}
void AudioFlinger::EffectChain::checkOutputFlagCompatibility(audio_output_flags_t *flags) const
@@ -2720,4 +2709,549 @@
return true;
}
+// EffectCallbackInterface implementation
+status_t AudioFlinger::EffectChain::EffectCallback::createEffectHal(
+ const effect_uuid_t *pEffectUuid, int32_t sessionId, int32_t deviceId,
+ sp<EffectHalInterface> *effect) {
+ status_t status = NO_INIT;
+ sp<AudioFlinger> af = mAudioFlinger.promote();
+ if (af == nullptr) {
+ return status;
+ }
+ sp<EffectsFactoryHalInterface> effectsFactory = af->getEffectsFactory();
+ if (effectsFactory != 0) {
+ status = effectsFactory->createEffect(pEffectUuid, sessionId, io(), deviceId, effect);
+ }
+ return status;
+}
+
+bool AudioFlinger::EffectChain::EffectCallback::updateOrphanEffectChains(
+ const sp<AudioFlinger::EffectBase>& effect) {
+ sp<AudioFlinger> af = mAudioFlinger.promote();
+ if (af == nullptr) {
+ return false;
+ }
+ // in EffectChain context, an EffectBase is always from an EffectModule so static cast is safe
+ return af->updateOrphanEffectChains(effect->asEffectModule());
+}
+
+status_t AudioFlinger::EffectChain::EffectCallback::allocateHalBuffer(
+ size_t size, sp<EffectBufferHalInterface>* buffer) {
+ sp<AudioFlinger> af = mAudioFlinger.promote();
+ LOG_ALWAYS_FATAL_IF(af == nullptr, "allocateHalBuffer() could not retrieved audio flinger");
+ return af->mEffectsFactoryHal->allocateBuffer(size, buffer);
+}
+
+status_t AudioFlinger::EffectChain::EffectCallback::addEffectToHal(
+ sp<EffectHalInterface> effect) {
+ status_t result = NO_INIT;
+ sp<ThreadBase> t = mThread.promote();
+ if (t == nullptr) {
+ return result;
+ }
+ sp <StreamHalInterface> st = t->stream();
+ if (st == nullptr) {
+ return result;
+ }
+ result = st->addEffect(effect);
+ ALOGE_IF(result != OK, "Error when adding effect: %d", result);
+ return result;
+}
+
+status_t AudioFlinger::EffectChain::EffectCallback::removeEffectFromHal(
+ sp<EffectHalInterface> effect) {
+ status_t result = NO_INIT;
+ sp<ThreadBase> t = mThread.promote();
+ if (t == nullptr) {
+ return result;
+ }
+ sp <StreamHalInterface> st = t->stream();
+ if (st == nullptr) {
+ return result;
+ }
+ result = st->removeEffect(effect);
+ ALOGE_IF(result != OK, "Error when removing effect: %d", result);
+ return result;
+}
+
+audio_io_handle_t AudioFlinger::EffectChain::EffectCallback::io() const {
+ sp<ThreadBase> t = mThread.promote();
+ if (t == nullptr) {
+ return AUDIO_IO_HANDLE_NONE;
+ }
+ return t->id();
+}
+
+bool AudioFlinger::EffectChain::EffectCallback::isOutput() const {
+ sp<ThreadBase> t = mThread.promote();
+ if (t == nullptr) {
+ return true;
+ }
+ return t->isOutput();
+}
+
+bool AudioFlinger::EffectChain::EffectCallback::isOffload() const {
+ sp<ThreadBase> t = mThread.promote();
+ if (t == nullptr) {
+ return false;
+ }
+ return t->type() == ThreadBase::OFFLOAD;
+}
+
+bool AudioFlinger::EffectChain::EffectCallback::isOffloadOrDirect() const {
+ sp<ThreadBase> t = mThread.promote();
+ if (t == nullptr) {
+ return false;
+ }
+ return t->type() == ThreadBase::OFFLOAD || t->type() == ThreadBase::DIRECT;
+}
+
+bool AudioFlinger::EffectChain::EffectCallback::isOffloadOrMmap() const {
+ sp<ThreadBase> t = mThread.promote();
+ if (t == nullptr) {
+ return false;
+ }
+ return t->type() == ThreadBase::OFFLOAD || t->type() == ThreadBase::MMAP;
+}
+
+uint32_t AudioFlinger::EffectChain::EffectCallback::sampleRate() const {
+ sp<ThreadBase> t = mThread.promote();
+ if (t == nullptr) {
+ return 0;
+ }
+ return t->sampleRate();
+}
+
+audio_channel_mask_t AudioFlinger::EffectChain::EffectCallback::channelMask() const {
+ sp<ThreadBase> t = mThread.promote();
+ if (t == nullptr) {
+ return AUDIO_CHANNEL_NONE;
+ }
+ return t->channelMask();
+}
+
+uint32_t AudioFlinger::EffectChain::EffectCallback::channelCount() const {
+ sp<ThreadBase> t = mThread.promote();
+ if (t == nullptr) {
+ return 0;
+ }
+ return t->channelCount();
+}
+
+size_t AudioFlinger::EffectChain::EffectCallback::frameCount() const {
+ sp<ThreadBase> t = mThread.promote();
+ if (t == nullptr) {
+ return 0;
+ }
+ return t->frameCount();
+}
+
+uint32_t AudioFlinger::EffectChain::EffectCallback::latency() const {
+ sp<ThreadBase> t = mThread.promote();
+ if (t == nullptr) {
+ return 0;
+ }
+ return t->latency_l();
+}
+
+void AudioFlinger::EffectChain::EffectCallback::setVolumeForOutput(float left, float right) const {
+ sp<ThreadBase> t = mThread.promote();
+ if (t == nullptr) {
+ return;
+ }
+ t->setVolumeForOutput_l(left, right);
+}
+
+void AudioFlinger::EffectChain::EffectCallback::checkSuspendOnEffectEnabled(
+ const sp<EffectBase>& effect, bool enabled, bool threadLocked) {
+ sp<ThreadBase> t = mThread.promote();
+ if (t == nullptr) {
+ return;
+ }
+ t->checkSuspendOnEffectEnabled(enabled, effect->sessionId(), threadLocked);
+
+ sp<EffectChain> c = mChain.promote();
+ if (c == nullptr) {
+ return;
+ }
+ // in EffectChain context, an EffectBase is always from an EffectModule so static cast is safe
+ c->checkSuspendOnEffectEnabled(effect->asEffectModule(), enabled);
+}
+
+void AudioFlinger::EffectChain::EffectCallback::onEffectEnable(const sp<EffectBase>& effect) {
+ sp<ThreadBase> t = mThread.promote();
+ if (t == nullptr) {
+ return;
+ }
+ // in EffectChain context, an EffectBase is always from an EffectModule so static cast is safe
+ t->onEffectEnable(effect->asEffectModule());
+}
+
+void AudioFlinger::EffectChain::EffectCallback::onEffectDisable(const sp<EffectBase>& effect) {
+ checkSuspendOnEffectEnabled(effect, false, false /*threadLocked*/);
+
+ sp<ThreadBase> t = mThread.promote();
+ if (t == nullptr) {
+ return;
+ }
+ t->onEffectDisable();
+}
+
+bool AudioFlinger::EffectChain::EffectCallback::disconnectEffectHandle(EffectHandle *handle,
+ bool unpinIfLast) {
+ sp<ThreadBase> t = mThread.promote();
+ if (t == nullptr) {
+ return false;
+ }
+ t->disconnectEffectHandle(handle, unpinIfLast);
+ return true;
+}
+
+void AudioFlinger::EffectChain::EffectCallback::resetVolume() {
+ sp<EffectChain> c = mChain.promote();
+ if (c == nullptr) {
+ return;
+ }
+ c->resetVolume_l();
+
+}
+
+uint32_t AudioFlinger::EffectChain::EffectCallback::strategy() const {
+ sp<EffectChain> c = mChain.promote();
+ if (c == nullptr) {
+ return PRODUCT_STRATEGY_NONE;
+ }
+ return c->strategy();
+}
+
+int32_t AudioFlinger::EffectChain::EffectCallback::activeTrackCnt() const {
+ sp<EffectChain> c = mChain.promote();
+ if (c == nullptr) {
+ return 0;
+ }
+ return c->activeTrackCnt();
+}
+
+
+#undef LOG_TAG
+#define LOG_TAG "AudioFlinger::DeviceEffectProxy"
+
+status_t AudioFlinger::DeviceEffectProxy::setEnabled(bool enabled, bool fromHandle)
+{
+ status_t status = EffectBase::setEnabled(enabled, fromHandle);
+ Mutex::Autolock _l(mProxyLock);
+ if (status == NO_ERROR) {
+ for (auto& handle : mEffectHandles) {
+ if (enabled) {
+ status = handle.second->enable();
+ } else {
+ status = handle.second->disable();
+ }
+ }
+ }
+ ALOGV("%s enable %d status %d", __func__, enabled, status);
+ return status;
+}
+
+status_t AudioFlinger::DeviceEffectProxy::init(
+ const std::map <audio_patch_handle_t, PatchPanel::Patch>& patches) {
+//For all audio patches
+//If src or sink device match
+//If the effect is HW accelerated
+// if no corresponding effect module
+// Create EffectModule: mHalEffect
+//Create and attach EffectHandle
+//If the effect is not HW accelerated and the patch sink or src is a mixer port
+// Create Effect on patch input or output thread on session -1
+//Add EffectHandle to EffectHandle map of Effect Proxy:
+ ALOGV("%s device type %d address %s", __func__, mDevice.mType, mDevice.getAddress());
+ status_t status = NO_ERROR;
+ for (auto &patch : patches) {
+ status = onCreatePatch(patch.first, patch.second);
+ ALOGV("%s onCreatePatch status %d", __func__, status);
+ if (status == BAD_VALUE) {
+ return status;
+ }
+ }
+ return status;
+}
+
+status_t AudioFlinger::DeviceEffectProxy::onCreatePatch(
+ audio_patch_handle_t patchHandle, const AudioFlinger::PatchPanel::Patch& patch) {
+ status_t status = NAME_NOT_FOUND;
+ sp<EffectHandle> handle;
+ // only consider source[0] as this is the only "true" source of a patch
+ status = checkPort(patch, &patch.mAudioPatch.sources[0], &handle);
+ ALOGV("%s source checkPort status %d", __func__, status);
+ for (uint32_t i = 0; i < patch.mAudioPatch.num_sinks && status == NAME_NOT_FOUND; i++) {
+ status = checkPort(patch, &patch.mAudioPatch.sinks[i], &handle);
+ ALOGV("%s sink %d checkPort status %d", __func__, i, status);
+ }
+ if (status == NO_ERROR || status == ALREADY_EXISTS) {
+ Mutex::Autolock _l(mProxyLock);
+ mEffectHandles.emplace(patchHandle, handle);
+ }
+ ALOGW_IF(status == BAD_VALUE,
+ "%s cannot attach effect %s on patch %d", __func__, mDescriptor.name, patchHandle);
+
+ return status;
+}
+
+status_t AudioFlinger::DeviceEffectProxy::checkPort(const PatchPanel::Patch& patch,
+ const struct audio_port_config *port, sp <EffectHandle> *handle) {
+
+ ALOGV("%s type %d device type %d address %s device ID %d patch.isSoftware() %d",
+ __func__, port->type, port->ext.device.type,
+ port->ext.device.address, port->id, patch.isSoftware());
+ if (port->type != AUDIO_PORT_TYPE_DEVICE || port->ext.device.type != mDevice.mType
+ || port->ext.device.address != mDevice.mAddress) {
+ return NAME_NOT_FOUND;
+ }
+ status_t status = NAME_NOT_FOUND;
+
+ if (mDescriptor.flags & EFFECT_FLAG_HW_ACC_TUNNEL) {
+ Mutex::Autolock _l(mProxyLock);
+ mDevicePort = *port;
+ mHalEffect = new EffectModule(mMyCallback,
+ const_cast<effect_descriptor_t *>(&mDescriptor),
+ mMyCallback->newEffectId(), AUDIO_SESSION_DEVICE,
+ false /* pinned */, port->id);
+ if (audio_is_input_device(mDevice.mType)) {
+ mHalEffect->setInputDevice(mDevice);
+ } else {
+ mHalEffect->setDevices({mDevice});
+ }
+ *handle = new EffectHandle(mHalEffect, nullptr, nullptr, 0 /*priority*/);
+ status = (*handle)->initCheck();
+ if (status == OK) {
+ status = mHalEffect->addHandle((*handle).get());
+ } else {
+ mHalEffect.clear();
+ mDevicePort.id = AUDIO_PORT_HANDLE_NONE;
+ }
+ } else if (patch.isSoftware() || patch.thread().promote() != nullptr) {
+ sp <ThreadBase> thread;
+ if (audio_port_config_has_input_direction(port)) {
+ if (patch.isSoftware()) {
+ thread = patch.mRecord.thread();
+ } else {
+ thread = patch.thread().promote();
+ }
+ } else {
+ if (patch.isSoftware()) {
+ thread = patch.mPlayback.thread();
+ } else {
+ thread = patch.thread().promote();
+ }
+ }
+ int enabled;
+ *handle = thread->createEffect_l(nullptr, nullptr, 0, AUDIO_SESSION_DEVICE,
+ const_cast<effect_descriptor_t *>(&mDescriptor),
+ &enabled, &status, false, false /*probe*/);
+ ALOGV("%s thread->createEffect_l status %d", __func__, status);
+ } else {
+ status = BAD_VALUE;
+ }
+ if (status == NO_ERROR || status == ALREADY_EXISTS) {
+ if (isEnabled()) {
+ (*handle)->enable();
+ } else {
+ (*handle)->disable();
+ }
+ }
+ return status;
+}
+
+void AudioFlinger::DeviceEffectProxy::onReleasePatch(audio_patch_handle_t patchHandle) {
+ Mutex::Autolock _l(mProxyLock);
+ mEffectHandles.erase(patchHandle);
+}
+
+
+size_t AudioFlinger::DeviceEffectProxy::removeEffect(const sp<EffectModule>& effect)
+{
+ Mutex::Autolock _l(mProxyLock);
+ if (effect == mHalEffect) {
+ mHalEffect.clear();
+ mDevicePort.id = AUDIO_PORT_HANDLE_NONE;
+ }
+ return mHalEffect == nullptr ? 0 : 1;
+}
+
+status_t AudioFlinger::DeviceEffectProxy::addEffectToHal(
+ sp<EffectHalInterface> effect) {
+ if (mHalEffect == nullptr) {
+ return NO_INIT;
+ }
+ return mManagerCallback->addEffectToHal(
+ mDevicePort.id, mDevicePort.ext.device.hw_module, effect);
+}
+
+status_t AudioFlinger::DeviceEffectProxy::removeEffectFromHal(
+ sp<EffectHalInterface> effect) {
+ if (mHalEffect == nullptr) {
+ return NO_INIT;
+ }
+ return mManagerCallback->removeEffectFromHal(
+ mDevicePort.id, mDevicePort.ext.device.hw_module, effect);
+}
+
+bool AudioFlinger::DeviceEffectProxy::isOutput() const {
+ if (mDevicePort.id != AUDIO_PORT_HANDLE_NONE) {
+ return mDevicePort.role == AUDIO_PORT_ROLE_SINK;
+ }
+ return true;
+}
+
+uint32_t AudioFlinger::DeviceEffectProxy::sampleRate() const {
+ if (mDevicePort.id != AUDIO_PORT_HANDLE_NONE &&
+ (mDevicePort.config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) != 0) {
+ return mDevicePort.sample_rate;
+ }
+ return DEFAULT_OUTPUT_SAMPLE_RATE;
+}
+
+audio_channel_mask_t AudioFlinger::DeviceEffectProxy::channelMask() const {
+ if (mDevicePort.id != AUDIO_PORT_HANDLE_NONE &&
+ (mDevicePort.config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) != 0) {
+ return mDevicePort.channel_mask;
+ }
+ return AUDIO_CHANNEL_OUT_STEREO;
+}
+
+uint32_t AudioFlinger::DeviceEffectProxy::channelCount() const {
+ if (isOutput()) {
+ return audio_channel_count_from_out_mask(channelMask());
+ }
+ return audio_channel_count_from_in_mask(channelMask());
+}
+
+void AudioFlinger::DeviceEffectProxy::dump(int fd, int spaces) {
+ const Vector<String16> args;
+ EffectBase::dump(fd, args);
+
+ const bool locked = dumpTryLock(mProxyLock);
+ if (!locked) {
+ String8 result("DeviceEffectProxy may be deadlocked\n");
+ write(fd, result.string(), result.size());
+ }
+
+ String8 outStr;
+ if (mHalEffect != nullptr) {
+ outStr.appendFormat("%*sHAL Effect Id: %d\n", spaces, "", mHalEffect->id());
+ } else {
+ outStr.appendFormat("%*sNO HAL Effect\n", spaces, "");
+ }
+ write(fd, outStr.string(), outStr.size());
+ outStr.clear();
+
+ outStr.appendFormat("%*sSub Effects:\n", spaces, "");
+ write(fd, outStr.string(), outStr.size());
+ outStr.clear();
+
+ for (const auto& iter : mEffectHandles) {
+ outStr.appendFormat("%*sEffect for patch handle %d:\n", spaces + 2, "", iter.first);
+ write(fd, outStr.string(), outStr.size());
+ outStr.clear();
+ sp<EffectBase> effect = iter.second->effect().promote();
+ if (effect != nullptr) {
+ effect->dump(fd, args);
+ }
+ }
+
+ if (locked) {
+ mLock.unlock();
+ }
+}
+
+#undef LOG_TAG
+#define LOG_TAG "AudioFlinger::DeviceEffectProxy::ProxyCallback"
+
+int AudioFlinger::DeviceEffectProxy::ProxyCallback::newEffectId() {
+ return mManagerCallback->newEffectId();
+}
+
+
+bool AudioFlinger::DeviceEffectProxy::ProxyCallback::disconnectEffectHandle(
+ EffectHandle *handle, bool unpinIfLast) {
+ sp<EffectBase> effectBase = handle->effect().promote();
+ if (effectBase == nullptr) {
+ return false;
+ }
+
+ sp<EffectModule> effect = effectBase->asEffectModule();
+ if (effect == nullptr) {
+ return false;
+ }
+
+ // restore suspended effects if the disconnected handle was enabled and the last one.
+ bool remove = (effect->removeHandle(handle) == 0) && (!effect->isPinned() || unpinIfLast);
+ if (remove) {
+ sp<DeviceEffectProxy> proxy = mProxy.promote();
+ if (proxy != nullptr) {
+ proxy->removeEffect(effect);
+ }
+ if (handle->enabled()) {
+ effectBase->checkSuspendOnEffectEnabled(false, false /*threadLocked*/);
+ }
+ }
+ return true;
+}
+
+status_t AudioFlinger::DeviceEffectProxy::ProxyCallback::createEffectHal(
+ const effect_uuid_t *pEffectUuid, int32_t sessionId, int32_t deviceId,
+ sp<EffectHalInterface> *effect) {
+ return mManagerCallback->createEffectHal(pEffectUuid, sessionId, deviceId, effect);
+}
+
+status_t AudioFlinger::DeviceEffectProxy::ProxyCallback::addEffectToHal(
+ sp<EffectHalInterface> effect) {
+ sp<DeviceEffectProxy> proxy = mProxy.promote();
+ if (proxy == nullptr) {
+ return NO_INIT;
+ }
+ return proxy->addEffectToHal(effect);
+}
+
+status_t AudioFlinger::DeviceEffectProxy::ProxyCallback::removeEffectFromHal(
+ sp<EffectHalInterface> effect) {
+ sp<DeviceEffectProxy> proxy = mProxy.promote();
+ if (proxy == nullptr) {
+ return NO_INIT;
+ }
+ return proxy->addEffectToHal(effect);
+}
+
+bool AudioFlinger::DeviceEffectProxy::ProxyCallback::isOutput() const {
+ sp<DeviceEffectProxy> proxy = mProxy.promote();
+ if (proxy == nullptr) {
+ return true;
+ }
+ return proxy->isOutput();
+}
+
+uint32_t AudioFlinger::DeviceEffectProxy::ProxyCallback::sampleRate() const {
+ sp<DeviceEffectProxy> proxy = mProxy.promote();
+ if (proxy == nullptr) {
+ return DEFAULT_OUTPUT_SAMPLE_RATE;
+ }
+ return proxy->sampleRate();
+}
+
+audio_channel_mask_t AudioFlinger::DeviceEffectProxy::ProxyCallback::channelMask() const {
+ sp<DeviceEffectProxy> proxy = mProxy.promote();
+ if (proxy == nullptr) {
+ return AUDIO_CHANNEL_OUT_STEREO;
+ }
+ return proxy->channelMask();
+}
+
+uint32_t AudioFlinger::DeviceEffectProxy::ProxyCallback::channelCount() const {
+ sp<DeviceEffectProxy> proxy = mProxy.promote();
+ if (proxy == nullptr) {
+ return 2;
+ }
+ return proxy->channelCount();
+}
+
} // namespace android
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index 220874d..2826297 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -21,34 +21,78 @@
//--- Audio Effect Management
-// EffectModule and EffectChain classes both have their own mutex to protect
+// Interface implemented by the EffectModule parent or owner (e.g an EffectChain) to abstract
+// interactions between the EffectModule and the reset of the audio framework.
+class EffectCallbackInterface : public RefBase {
+public:
+ ~EffectCallbackInterface() override = default;
+
+ // Trivial methods usually implemented with help from ThreadBase
+ virtual audio_io_handle_t io() const = 0;
+ virtual bool isOutput() const = 0;
+ virtual bool isOffload() const = 0;
+ virtual bool isOffloadOrDirect() const = 0;
+ virtual bool isOffloadOrMmap() const = 0;
+ virtual uint32_t sampleRate() const = 0;
+ virtual audio_channel_mask_t channelMask() const = 0;
+ virtual uint32_t channelCount() const = 0;
+ virtual size_t frameCount() const = 0;
+
+ // Non trivial methods usually implemented with help from ThreadBase:
+ // pay attention to mutex locking order
+ virtual uint32_t latency() const { return 0; }
+ virtual status_t addEffectToHal(sp<EffectHalInterface> effect) = 0;
+ virtual status_t removeEffectFromHal(sp<EffectHalInterface> effect) = 0;
+ virtual void setVolumeForOutput(float left, float right) const = 0;
+ virtual bool disconnectEffectHandle(EffectHandle *handle, bool unpinIfLast) = 0;
+ virtual void checkSuspendOnEffectEnabled(const sp<EffectBase>& effect,
+ bool enabled,
+ bool threadLocked) = 0;
+ virtual void onEffectEnable(const sp<EffectBase>& effect) = 0;
+ virtual void onEffectDisable(const sp<EffectBase>& effect) = 0;
+
+ // Methods usually implemented with help from AudioFlinger: pay attention to mutex locking order
+ virtual status_t createEffectHal(const effect_uuid_t *pEffectUuid,
+ int32_t sessionId, int32_t deviceId, sp<EffectHalInterface> *effect) = 0;
+ virtual status_t allocateHalBuffer(size_t size, sp<EffectBufferHalInterface>* buffer) = 0;
+ virtual bool updateOrphanEffectChains(const sp<EffectBase>& effect) = 0;
+
+ // Methods usually implemented with help from EffectChain: pay attention to mutex locking order
+ virtual uint32_t strategy() const = 0;
+ virtual int32_t activeTrackCnt() const = 0;
+ virtual void resetVolume() = 0;
+
+ virtual wp<EffectChain> chain() const = 0;
+};
+
+// EffectBase(EffectModule) and EffectChain classes both have their own mutex to protect
// state changes or resource modifications. Always respect the following order
// if multiple mutexes must be acquired to avoid cross deadlock:
-// AudioFlinger -> ThreadBase -> EffectChain -> EffectModule
-// AudioHandle -> ThreadBase -> EffectChain -> EffectModule
+// AudioFlinger -> ThreadBase -> EffectChain -> EffectBase(EffectModule)
+// AudioHandle -> ThreadBase -> EffectChain -> EffectBase(EffectModule)
+
+// NOTE: When implementing the EffectCallbackInterface, in an EffectChain or other, it is important
+// to pay attention to this locking order as some callback methods can be called from a state where
+// EffectModule and/or EffectChain mutexes are held.
+
// In addition, methods that lock the AudioPolicyService mutex (getOutputForEffect(),
// startOutput(), getInputForAttr(), releaseInput()...) should never be called with AudioFlinger or
// Threadbase mutex locked to avoid cross deadlock with other clients calling AudioPolicyService
// methods that in turn call AudioFlinger thus locking the same mutexes in the reverse order.
-// The EffectModule class is a wrapper object controlling the effect engine implementation
-// in the effect library. It prevents concurrent calls to process() and command() functions
-// from different client threads. It keeps a list of EffectHandle objects corresponding
-// to all client applications using this effect and notifies applications of effect state,
-// control or parameter changes. It manages the activation state machine to send appropriate
-// reset, enable, disable commands to effect engine and provide volume
-// ramping when effects are activated/deactivated.
-// When controlling an auxiliary effect, the EffectModule also provides an input buffer used by
-// the attached track(s) to accumulate their auxiliary channel.
-class EffectModule : public RefBase {
+
+// The EffectBase class contains common properties, state and behavior for and EffectModule or
+// other derived classes managing an audio effect instance within the effect framework.
+// It also contains the class mutex (see comment on locking order above).
+class EffectBase : public RefBase {
public:
- EffectModule(ThreadBase *thread,
- const wp<AudioFlinger::EffectChain>& chain,
- effect_descriptor_t *desc,
- int id,
- audio_session_t sessionId,
- bool pinned);
- virtual ~EffectModule();
+ EffectBase(const sp<EffectCallbackInterface>& callback,
+ effect_descriptor_t *desc,
+ int id,
+ audio_session_t sessionId,
+ bool pinned);
+
+ ~EffectBase() override = default;
enum effect_state {
IDLE,
@@ -60,71 +104,14 @@
DESTROYED
};
- int id() const { return mId; }
- void process();
- bool updateState();
- status_t command(uint32_t cmdCode,
- uint32_t cmdSize,
- void *pCmdData,
- uint32_t *replySize,
- void *pReplyData);
-
- void reset_l();
- status_t configure();
- status_t init();
+ int id() const { return mId; }
effect_state state() const {
return mState;
}
- uint32_t status() {
- return mStatus;
- }
audio_session_t sessionId() const {
return mSessionId;
}
- status_t setEnabled(bool enabled);
- status_t setEnabled_l(bool enabled);
- bool isEnabled() const;
- bool isProcessEnabled() const;
- bool isOffloadedOrDirect() const;
- bool isVolumeControlEnabled() const;
-
- void setInBuffer(const sp<EffectBufferHalInterface>& buffer);
- int16_t *inBuffer() const {
- return mInBuffer != 0 ? reinterpret_cast<int16_t*>(mInBuffer->ptr()) : NULL;
- }
- void setOutBuffer(const sp<EffectBufferHalInterface>& buffer);
- int16_t *outBuffer() const {
- return mOutBuffer != 0 ? reinterpret_cast<int16_t*>(mOutBuffer->ptr()) : NULL;
- }
- void setChain(const wp<EffectChain>& chain) { mChain = chain; }
- void setThread(const wp<ThreadBase>& thread)
- { mThread = thread; mThreadType = thread.promote()->type(); }
- const wp<ThreadBase>& thread() { return mThread; }
-
- status_t addHandle(EffectHandle *handle);
- ssize_t disconnectHandle(EffectHandle *handle, bool unpinIfLast);
- ssize_t removeHandle(EffectHandle *handle);
- ssize_t removeHandle_l(EffectHandle *handle);
-
const effect_descriptor_t& desc() const { return mDescriptor; }
- wp<EffectChain>& chain() { return mChain; }
-
- status_t setDevice(audio_devices_t device);
- status_t setVolume(uint32_t *left, uint32_t *right, bool controller);
- status_t setMode(audio_mode_t mode);
- status_t setAudioSource(audio_source_t source);
- status_t start();
- status_t stop();
- void setSuspended(bool suspended);
- bool suspended() const;
-
- EffectHandle* controlHandle_l();
-
- bool isPinned() const { return mPinned; }
- void unPin() { mPinned = false; }
- bool purgeHandles();
- void lock() { mLock.lock(); }
- void unlock() { mLock.unlock(); }
bool isOffloadable() const
{ return (mDescriptor.flags & EFFECT_FLAG_OFFLOAD_SUPPORTED) != 0; }
bool isImplementationSoftware() const
@@ -137,18 +124,143 @@
bool isVolumeMonitor() const
{ return (mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK)
== EFFECT_FLAG_VOLUME_MONITOR; }
- status_t setOffloaded(bool offloaded, audio_io_handle_t io);
- bool isOffloaded() const;
- void addEffectToHal_l();
- void release_l();
+
+ virtual status_t setEnabled(bool enabled, bool fromHandle);
+ status_t setEnabled_l(bool enabled);
+ bool isEnabled() const;
+
+ void setSuspended(bool suspended);
+ bool suspended() const;
+
+ virtual status_t command(uint32_t cmdCode __unused,
+ uint32_t cmdSize __unused,
+ void *pCmdData __unused,
+ uint32_t *replySize __unused,
+ void *pReplyData __unused) { return NO_ERROR; };
+
+ void setCallback(const sp<EffectCallbackInterface>& callback) { mCallback = callback; }
+ sp<EffectCallbackInterface>& callback() { return mCallback; }
+
+ status_t addHandle(EffectHandle *handle);
+ ssize_t disconnectHandle(EffectHandle *handle, bool unpinIfLast);
+ ssize_t removeHandle(EffectHandle *handle);
+ virtual ssize_t removeHandle_l(EffectHandle *handle);
+ EffectHandle* controlHandle_l();
+ bool purgeHandles();
+
+ void checkSuspendOnEffectEnabled(bool enabled, bool threadLocked);
+
+ bool isPinned() const { return mPinned; }
+ void unPin() { mPinned = false; }
+
+ void lock() { mLock.lock(); }
+ void unlock() { mLock.unlock(); }
status_t updatePolicyState();
+ virtual sp<EffectModule> asEffectModule() { return nullptr; }
+ virtual sp<DeviceEffectProxy> asDeviceEffectProxy() { return nullptr; }
+
void dump(int fd, const Vector<String16>& args);
private:
friend class AudioFlinger; // for mHandles
- bool mPinned;
+ bool mPinned = false;
+
+ DISALLOW_COPY_AND_ASSIGN(EffectBase);
+
+mutable Mutex mLock; // mutex for process, commands and handles list protection
+ sp<EffectCallbackInterface> mCallback; // parent effect chain
+ const int mId; // this instance unique ID
+ const audio_session_t mSessionId; // audio session ID
+ const effect_descriptor_t mDescriptor;// effect descriptor received from effect engine
+ effect_state mState = IDLE; // current activation state
+ // effect is suspended: temporarily disabled by framework
+ bool mSuspended = false;
+
+ Vector<EffectHandle *> mHandles; // list of client handles
+ // First handle in mHandles has highest priority and controls the effect module
+
+ // Audio policy effect state management
+ // Mutex protecting transactions with audio policy manager as mLock cannot
+ // be held to avoid cross deadlocks with audio policy mutex
+ Mutex mPolicyLock;
+ // Effect is registered in APM or not
+ bool mPolicyRegistered = false;
+ // Effect enabled state communicated to APM. Enabled state corresponds to
+ // state requested by the EffectHandle with control
+ bool mPolicyEnabled = false;
+};
+
+// The EffectModule class is a wrapper object controlling the effect engine implementation
+// in the effect library. It prevents concurrent calls to process() and command() functions
+// from different client threads. It keeps a list of EffectHandle objects corresponding
+// to all client applications using this effect and notifies applications of effect state,
+// control or parameter changes. It manages the activation state machine to send appropriate
+// reset, enable, disable commands to effect engine and provide volume
+// ramping when effects are activated/deactivated.
+// When controlling an auxiliary effect, the EffectModule also provides an input buffer used by
+// the attached track(s) to accumulate their auxiliary channel.
+class EffectModule : public EffectBase {
+public:
+ EffectModule(const sp<EffectCallbackInterface>& callabck,
+ effect_descriptor_t *desc,
+ int id,
+ audio_session_t sessionId,
+ bool pinned,
+ audio_port_handle_t deviceId);
+ virtual ~EffectModule();
+
+ void process();
+ bool updateState();
+ status_t command(uint32_t cmdCode,
+ uint32_t cmdSize,
+ void *pCmdData,
+ uint32_t *replySize,
+ void *pReplyData) override;
+
+ void reset_l();
+ status_t configure();
+ status_t init();
+
+ uint32_t status() {
+ return mStatus;
+ }
+
+ bool isProcessEnabled() const;
+ bool isOffloadedOrDirect() const;
+ bool isVolumeControlEnabled() const;
+
+ void setInBuffer(const sp<EffectBufferHalInterface>& buffer);
+ int16_t *inBuffer() const {
+ return mInBuffer != 0 ? reinterpret_cast<int16_t*>(mInBuffer->ptr()) : NULL;
+ }
+ void setOutBuffer(const sp<EffectBufferHalInterface>& buffer);
+ int16_t *outBuffer() const {
+ return mOutBuffer != 0 ? reinterpret_cast<int16_t*>(mOutBuffer->ptr()) : NULL;
+ }
+
+ ssize_t removeHandle_l(EffectHandle *handle) override;
+
+ status_t setDevices(const AudioDeviceTypeAddrVector &devices);
+ status_t setInputDevice(const AudioDeviceTypeAddr &device);
+ status_t setVolume(uint32_t *left, uint32_t *right, bool controller);
+ status_t setMode(audio_mode_t mode);
+ status_t setAudioSource(audio_source_t source);
+ status_t start();
+ status_t stop();
+
+ status_t setOffloaded(bool offloaded, audio_io_handle_t io);
+ bool isOffloaded() const;
+ void addEffectToHal_l();
+ void release_l();
+
+ sp<EffectModule> asEffectModule() override { return this; }
+
+ void dump(int fd, const Vector<String16>& args);
+
+private:
+ friend class AudioFlinger; // for mHandles
// Maximum time allocated to effect engines to complete the turn off sequence
static const uint32_t MAX_DISABLE_TIME_MS = 10000;
@@ -157,29 +269,19 @@
status_t start_l();
status_t stop_l();
- status_t remove_effect_from_hal_l();
+ status_t removeEffectFromHal_l();
+ status_t sendSetAudioDevicesCommand(const AudioDeviceTypeAddrVector &devices, uint32_t cmdCode);
-mutable Mutex mLock; // mutex for process, commands and handles list protection
- wp<ThreadBase> mThread; // parent thread
- ThreadBase::type_t mThreadType; // parent thread type
- wp<EffectChain> mChain; // parent effect chain
- const int mId; // this instance unique ID
- const audio_session_t mSessionId; // audio session ID
- const effect_descriptor_t mDescriptor;// effect descriptor received from effect engine
effect_config_t mConfig; // input and output audio configuration
sp<EffectHalInterface> mEffectInterface; // Effect module HAL
sp<EffectBufferHalInterface> mInBuffer; // Buffers for interacting with HAL
sp<EffectBufferHalInterface> mOutBuffer;
status_t mStatus; // initialization status
- effect_state mState; // current activation state
- Vector<EffectHandle *> mHandles; // list of client handles
// First handle in mHandles has highest priority and controls the effect module
uint32_t mMaxDisableWaitCnt; // maximum grace period before forcing an effect off after
// sending disable command.
uint32_t mDisableWaitCnt; // current process() calls count during disable period.
- bool mSuspended; // effect is suspended: temporarily disabled by framework
bool mOffloaded; // effect is currently offloaded to the audio DSP
- wp<AudioFlinger> mAudioFlinger;
#ifdef FLOAT_EFFECT_CHAIN
bool mSupportsFloat; // effect supports float processing
@@ -206,16 +308,6 @@
static constexpr pid_t INVALID_PID = (pid_t)-1;
// this tid is allowed to call setVolume() without acquiring the mutex.
pid_t mSetVolumeReentrantTid = INVALID_PID;
-
- // Audio policy effect state management
- // Mutex protecting transactions with audio policy manager as mLock cannot
- // be held to avoid cross deadlocks with audio policy mutex
- Mutex mPolicyLock;
- // Effect is registered in APM or not
- bool mPolicyRegistered = false;
- // Effect enabled state communicated to APM. Enabled state corresponds to
- // state requested by the EffectHandle with control
- bool mPolicyEnabled = false;
};
// The EffectHandle class implements the IEffect interface. It provides resources
@@ -227,7 +319,7 @@
class EffectHandle: public android::BnEffect {
public:
- EffectHandle(const sp<EffectModule>& effect,
+ EffectHandle(const sp<EffectBase>& effect,
const sp<AudioFlinger::Client>& client,
const sp<IEffectClient>& effectClient,
int32_t priority);
@@ -265,9 +357,9 @@
bool enabled() const { return mEnabled; }
// Getters
- wp<EffectModule> effect() const { return mEffect; }
+ wp<EffectBase> effect() const { return mEffect; }
int id() const {
- sp<EffectModule> effect = mEffect.promote();
+ sp<EffectBase> effect = mEffect.promote();
if (effect == 0) {
return 0;
}
@@ -284,7 +376,7 @@
DISALLOW_COPY_AND_ASSIGN(EffectHandle);
Mutex mLock; // protects IEffect method calls
- wp<EffectModule> mEffect; // pointer to controlled EffectModule
+ wp<EffectBase> mEffect; // pointer to controlled EffectModule
sp<IEffectClient> mEffectClient; // callback interface for client notifications
/*const*/ sp<Client> mClient; // client for shared memory allocation, see disconnect()
sp<IMemory> mCblkMemory; // shared memory for control block
@@ -310,7 +402,6 @@
class EffectChain : public RefBase {
public:
EffectChain(const wp<ThreadBase>& wThread, audio_session_t sessionId);
- EffectChain(ThreadBase *thread, audio_session_t sessionId);
virtual ~EffectChain();
// special key used for an entry in mSuspendedEffects keyed vector
@@ -331,7 +422,6 @@
}
status_t createEffect_l(sp<EffectModule>& effect,
- ThreadBase *thread,
effect_descriptor_t *desc,
int id,
audio_session_t sessionId,
@@ -350,7 +440,8 @@
// FIXME use float to improve the dynamic range
bool setVolume_l(uint32_t *left, uint32_t *right, bool force = false);
void resetVolume_l();
- void setDevice_l(audio_devices_t device);
+ void setDevices_l(const AudioDeviceTypeAddrVector &devices);
+ void setInputDevice_l(const AudioDeviceTypeAddr &device);
void setMode_l(audio_mode_t mode);
void setAudioSource_l(audio_source_t source);
@@ -386,9 +477,8 @@
bool suspend);
// suspend all eligible effects
void setEffectSuspendedAll_l(bool suspend);
- // check if effects should be suspend or restored when a given effect is enable or disabled
- void checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
- bool enabled);
+ // check if effects should be suspended or restored when a given effect is enable or disabled
+ void checkSuspendOnEffectEnabled(const sp<EffectModule>& effect, bool enabled);
void clearInputBuffer();
@@ -413,9 +503,70 @@
// isCompatibleWithThread_l() must be called with thread->mLock held
bool isCompatibleWithThread_l(const sp<ThreadBase>& thread) const;
+ sp<EffectCallbackInterface> effectCallback() const { return mEffectCallback; }
+ wp<ThreadBase> thread() const { return mEffectCallback->thread(); }
+
void dump(int fd, const Vector<String16>& args);
private:
+
+ class EffectCallback : public EffectCallbackInterface {
+ public:
+ // Note: ctors taking a weak pointer to their owner must not promote it
+ // during construction (but may keep a reference for later promotion).
+ EffectCallback(const wp<EffectChain>& owner,
+ const wp<ThreadBase>& thread)
+ : mChain(owner) {
+ setThread(thread);
+ }
+
+ status_t createEffectHal(const effect_uuid_t *pEffectUuid,
+ int32_t sessionId, int32_t deviceId, sp<EffectHalInterface> *effect) override;
+ status_t allocateHalBuffer(size_t size, sp<EffectBufferHalInterface>* buffer) override;
+ bool updateOrphanEffectChains(const sp<EffectBase>& effect) override;
+
+ audio_io_handle_t io() const override;
+ bool isOutput() const override;
+ bool isOffload() const override;
+ bool isOffloadOrDirect() const override;
+ bool isOffloadOrMmap() const override;
+
+ uint32_t sampleRate() const override;
+ audio_channel_mask_t channelMask() const override;
+ uint32_t channelCount() const override;
+ size_t frameCount() const override;
+ uint32_t latency() const override;
+
+ status_t addEffectToHal(sp<EffectHalInterface> effect) override;
+ status_t removeEffectFromHal(sp<EffectHalInterface> effect) override;
+ bool disconnectEffectHandle(EffectHandle *handle, bool unpinIfLast) override;
+ void setVolumeForOutput(float left, float right) const override;
+
+ // check if effects should be suspended/restored when a given effect is enable/disabled
+ void checkSuspendOnEffectEnabled(const sp<EffectBase>& effect,
+ bool enabled, bool threadLocked) override;
+ void resetVolume() override;
+ uint32_t strategy() const override;
+ int32_t activeTrackCnt() const override;
+ void onEffectEnable(const sp<EffectBase>& effect) override;
+ void onEffectDisable(const sp<EffectBase>& effect) override;
+
+ wp<EffectChain> chain() const override { return mChain; }
+
+ wp<ThreadBase> thread() { return mThread; }
+
+ void setThread(const wp<ThreadBase>& thread) {
+ mThread = thread;
+ sp<ThreadBase> p = thread.promote();
+ mAudioFlinger = p ? p->mAudioFlinger : nullptr;
+ }
+
+ private:
+ wp<EffectChain> mChain;
+ wp<ThreadBase> mThread;
+ wp<AudioFlinger> mAudioFlinger;
+ };
+
friend class AudioFlinger; // for mThread, mEffects
DISALLOW_COPY_AND_ASSIGN(EffectChain);
@@ -441,13 +592,15 @@
static bool isEffectEligibleForBtNrecSuspend(const effect_uuid_t *type);
- void clearInputBuffer_l(const sp<ThreadBase>& thread);
+ void clearInputBuffer_l();
void setThread(const sp<ThreadBase>& thread);
+ // true if any effect module within the chain has volume control
+ bool hasVolumeControlEnabled_l() const;
+
void setVolumeForOutput_l(uint32_t left, uint32_t right);
- wp<ThreadBase> mThread; // parent mixer thread
mutable Mutex mLock; // mutex protecting effect list
Vector< sp<EffectModule> > mEffects; // list of effect modules
audio_session_t mSessionId; // audio session ID
@@ -471,4 +624,102 @@
// timeLow fields among effect type UUIDs.
// Updated by setEffectSuspended_l() and setEffectSuspendedAll_l() only.
KeyedVector< int, sp<SuspendedEffectDesc> > mSuspendedEffects;
+
+ const sp<EffectCallback> mEffectCallback;
+};
+
+class DeviceEffectProxy : public EffectBase {
+public:
+ DeviceEffectProxy (const AudioDeviceTypeAddr& device,
+ const sp<DeviceEffectManagerCallback>& callback,
+ effect_descriptor_t *desc, int id)
+ : EffectBase(callback, desc, id, AUDIO_SESSION_DEVICE, false),
+ mDevice(device), mManagerCallback(callback),
+ mMyCallback(new ProxyCallback(wp<DeviceEffectProxy>(this),
+ callback)) {}
+
+ status_t setEnabled(bool enabled, bool fromHandle) override;
+ sp<DeviceEffectProxy> asDeviceEffectProxy() override { return this; }
+
+ status_t init(const std::map<audio_patch_handle_t, PatchPanel::Patch>& patches);
+ status_t onCreatePatch(audio_patch_handle_t patchHandle, const PatchPanel::Patch& patch);
+ void onReleasePatch(audio_patch_handle_t patchHandle);
+
+ size_t removeEffect(const sp<EffectModule>& effect);
+
+ status_t addEffectToHal(sp<EffectHalInterface> effect);
+ status_t removeEffectFromHal(sp<EffectHalInterface> effect);
+
+ const AudioDeviceTypeAddr& device() { return mDevice; };
+ bool isOutput() const;
+ uint32_t sampleRate() const;
+ audio_channel_mask_t channelMask() const;
+ uint32_t channelCount() const;
+
+ void dump(int fd, int spaces);
+
+private:
+
+ class ProxyCallback : public EffectCallbackInterface {
+ public:
+ // Note: ctors taking a weak pointer to their owner must not promote it
+ // during construction (but may keep a reference for later promotion).
+ ProxyCallback(const wp<DeviceEffectProxy>& owner,
+ const sp<DeviceEffectManagerCallback>& callback)
+ : mProxy(owner), mManagerCallback(callback) {}
+
+ status_t createEffectHal(const effect_uuid_t *pEffectUuid,
+ int32_t sessionId, int32_t deviceId, sp<EffectHalInterface> *effect) override;
+ status_t allocateHalBuffer(size_t size __unused,
+ sp<EffectBufferHalInterface>* buffer __unused) override { return NO_ERROR; }
+ bool updateOrphanEffectChains(const sp<EffectBase>& effect __unused) override {
+ return false;
+ }
+
+ audio_io_handle_t io() const override { return AUDIO_IO_HANDLE_NONE; }
+ bool isOutput() const override;
+ bool isOffload() const override { return false; }
+ bool isOffloadOrDirect() const override { return false; }
+ bool isOffloadOrMmap() const override { return false; }
+
+ uint32_t sampleRate() const override;
+ audio_channel_mask_t channelMask() const override;
+ uint32_t channelCount() const override;
+ size_t frameCount() const override { return 0; }
+ uint32_t latency() const override { return 0; }
+
+ status_t addEffectToHal(sp<EffectHalInterface> effect) override;
+ status_t removeEffectFromHal(sp<EffectHalInterface> effect) override;
+
+ bool disconnectEffectHandle(EffectHandle *handle, bool unpinIfLast) override;
+ void setVolumeForOutput(float left __unused, float right __unused) const override {}
+
+ void checkSuspendOnEffectEnabled(const sp<EffectBase>& effect __unused,
+ bool enabled __unused, bool threadLocked __unused) override {}
+ void resetVolume() override {}
+ uint32_t strategy() const override { return 0; }
+ int32_t activeTrackCnt() const override { return 0; }
+ void onEffectEnable(const sp<EffectBase>& effect __unused) override {}
+ void onEffectDisable(const sp<EffectBase>& effect __unused) override {}
+
+ wp<EffectChain> chain() const override { return nullptr; }
+
+ int newEffectId();
+
+ private:
+ const wp<DeviceEffectProxy> mProxy;
+ const sp<DeviceEffectManagerCallback> mManagerCallback;
+ };
+
+ status_t checkPort(const PatchPanel::Patch& patch, const struct audio_port_config *port,
+ sp<EffectHandle> *handle);
+
+ const AudioDeviceTypeAddr mDevice;
+ const sp<DeviceEffectManagerCallback> mManagerCallback;
+ const sp<ProxyCallback> mMyCallback;
+
+ Mutex mProxyLock;
+ std::map<audio_patch_handle_t, sp<EffectHandle>> mEffectHandles; // protected by mProxyLock
+ sp<EffectModule> mHalEffect; // protected by mProxyLock
+ struct audio_port_config mDevicePort = { .id = AUDIO_PORT_HANDLE_NONE };
};
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index c5b9953..3eacc8c 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -105,13 +105,8 @@
return mSQ.poll();
}
-void FastMixer::setNBLogWriter(NBLog::Writer *logWriter)
+void FastMixer::setNBLogWriter(NBLog::Writer *logWriter __unused)
{
- // FIXME If mMixer is set or changed prior to this, we don't inform correctly.
- // Should cache logWriter and re-apply it at the assignment to mMixer.
- if (mMixer != NULL) {
- mMixer->setNBLogWriter(logWriter);
- }
}
void FastMixer::onIdle()
diff --git a/services/audioflinger/FastThread.cpp b/services/audioflinger/FastThread.cpp
index 04b32c2..8b7a124 100644
--- a/services/audioflinger/FastThread.cpp
+++ b/services/audioflinger/FastThread.cpp
@@ -124,7 +124,7 @@
mDumpState = next->mDumpState != NULL ? next->mDumpState : mDummyDumpState;
tlNBLogWriter = next->mNBLogWriter != NULL ?
next->mNBLogWriter : mDummyNBLogWriter.get();
- setNBLogWriter(tlNBLogWriter); // FastMixer informs its AudioMixer, FastCapture ignores
+ setNBLogWriter(tlNBLogWriter); // This is used for debugging only
// We want to always have a valid reference to the previous (non-idle) state.
// However, the state queue only guarantees access to current and previous states.
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index edb331d..b58fd8b 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -25,6 +25,7 @@
#include "AudioFlinger.h"
#include <media/AudioParameter.h>
+#include <media/DeviceDescriptorBase.h>
#include <media/PatchBuilder.h>
#include <mediautils/ServiceUtilities.h>
@@ -167,9 +168,9 @@
if (hwDevice != 0) {
hwDevice->releaseAudioPatch(removedPatch.mHalHandle);
}
+ halHandle = removedPatch.mHalHandle;
}
- mPatches.erase(iter);
- removeSoftwarePatchFromInsertedModules(*handle);
+ erasePatch(*handle);
}
}
@@ -324,10 +325,14 @@
}
}
status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
+ if (status == NO_ERROR) {
+ newPatch.setThread(thread);
+ }
+
// remove stale audio patch with same input as sink if any
for (auto& iter : mPatches) {
if (iter.second.mAudioPatch.sinks[0].ext.mix.handle == thread->id()) {
- mPatches.erase(iter.first);
+ erasePatch(iter.first);
break;
}
}
@@ -351,7 +356,7 @@
goto exit;
}
// limit to connections between devices and output streams
- audio_devices_t type = AUDIO_DEVICE_NONE;
+ DeviceDescriptorBaseVector devices;
for (unsigned int i = 0; i < patch->num_sinks; i++) {
if (patch->sinks[i].type != AUDIO_PORT_TYPE_DEVICE) {
ALOGW("%s() invalid sink type %d for mix source",
@@ -364,7 +369,11 @@
status = BAD_VALUE;
goto exit;
}
- type |= patch->sinks[i].ext.device.type;
+ sp<DeviceDescriptorBase> device = new DeviceDescriptorBase(
+ patch->sinks[i].ext.device.type);
+ device->setAddress(patch->sinks[i].ext.device.address);
+ device->applyAudioPortConfig(&patch->sinks[i]);
+ devices.push_back(device);
}
sp<ThreadBase> thread =
mAudioFlinger.checkPlaybackThread_l(patch->sources[0].ext.mix.handle);
@@ -378,18 +387,18 @@
}
}
if (thread == mAudioFlinger.primaryPlaybackThread_l()) {
- AudioParameter param = AudioParameter();
- param.addInt(String8(AudioParameter::keyRouting), (int)type);
-
- mAudioFlinger.broacastParametersToRecordThreads_l(param.toString());
+ mAudioFlinger.updateOutDevicesForRecordThreads_l(devices);
}
status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
+ if (status == NO_ERROR) {
+ newPatch.setThread(thread);
+ }
// remove stale audio patch with same output as source if any
for (auto& iter : mPatches) {
if (iter.second.mAudioPatch.sources[0].ext.mix.handle == thread->id()) {
- mPatches.erase(iter.first);
+ erasePatch(iter.first);
break;
}
}
@@ -403,11 +412,11 @@
if (status == NO_ERROR) {
*handle = (audio_patch_handle_t) mAudioFlinger.nextUniqueId(AUDIO_UNIQUE_ID_USE_PATCH);
newPatch.mHalHandle = halHandle;
+ mAudioFlinger.mDeviceEffectManager.createAudioPatch(*handle, newPatch);
mPatches.insert(std::make_pair(*handle, std::move(newPatch)));
if (insertedModule != AUDIO_MODULE_HANDLE_NONE) {
addSoftwarePatchToInsertedModules(insertedModule, *handle);
}
- ALOGV("%s() added new patch handle %d halHandle %d", __func__, *handle, halHandle);
} else {
newPatch.clearConnections(this);
}
@@ -445,18 +454,6 @@
*mPlayback.handlePtr() = AUDIO_PATCH_HANDLE_NONE;
}
- // use a pseudo LCM between input and output framecount
- size_t playbackFrameCount = mPlayback.thread()->frameCount();
- int playbackShift = __builtin_ctz(playbackFrameCount);
- size_t recordFrameCount = mRecord.thread()->frameCount();
- int shift = __builtin_ctz(recordFrameCount);
- if (playbackShift < shift) {
- shift = playbackShift;
- }
- size_t frameCount = (playbackFrameCount * recordFrameCount) >> shift;
- ALOGV("%s() playframeCount %zu recordFrameCount %zu frameCount %zu",
- __func__, playbackFrameCount, recordFrameCount, frameCount);
-
// create a special record track to capture from record thread
uint32_t channelCount = mPlayback.thread()->channelCount();
audio_channel_mask_t inChannelMask = audio_channel_in_mask_from_count(channelCount);
@@ -483,19 +480,6 @@
// Fast mode is not available in this case.
inputFlags = (audio_input_flags_t) (inputFlags & ~AUDIO_INPUT_FLAG_FAST);
}
- sp<RecordThread::PatchRecord> tempRecordTrack = new (std::nothrow) RecordThread::PatchRecord(
- mRecord.thread().get(),
- sampleRate,
- inChannelMask,
- format,
- frameCount,
- NULL,
- (size_t)0 /* bufferSize */,
- inputFlags);
- status = mRecord.checkTrack(tempRecordTrack.get());
- if (status != NO_ERROR) {
- return status;
- }
audio_output_flags_t outputFlags = mAudioPatch.sinks[0].config_mask & AUDIO_PORT_CONFIG_FLAGS ?
mAudioPatch.sinks[0].flags.output : AUDIO_OUTPUT_FLAG_NONE;
@@ -512,9 +496,54 @@
outputFlags = (audio_output_flags_t) (outputFlags & ~AUDIO_OUTPUT_FLAG_FAST);
}
+ sp<RecordThread::PatchRecord> tempRecordTrack;
+ const bool usePassthruPatchRecord =
+ (inputFlags & AUDIO_INPUT_FLAG_DIRECT) && (outputFlags & AUDIO_OUTPUT_FLAG_DIRECT);
+ const size_t playbackFrameCount = mPlayback.thread()->frameCount();
+ const size_t recordFrameCount = mRecord.thread()->frameCount();
+ size_t frameCount = 0;
+ if (usePassthruPatchRecord) {
+ // PassthruPatchRecord producesBufferOnDemand, so use
+ // maximum of playback and record thread framecounts
+ frameCount = std::max(playbackFrameCount, recordFrameCount);
+ ALOGV("%s() playframeCount %zu recordFrameCount %zu frameCount %zu",
+ __func__, playbackFrameCount, recordFrameCount, frameCount);
+ tempRecordTrack = new RecordThread::PassthruPatchRecord(
+ mRecord.thread().get(),
+ sampleRate,
+ inChannelMask,
+ format,
+ frameCount,
+ inputFlags);
+ } else {
+ // use a pseudo LCM between input and output framecount
+ int playbackShift = __builtin_ctz(playbackFrameCount);
+ int shift = __builtin_ctz(recordFrameCount);
+ if (playbackShift < shift) {
+ shift = playbackShift;
+ }
+ frameCount = (playbackFrameCount * recordFrameCount) >> shift;
+ ALOGV("%s() playframeCount %zu recordFrameCount %zu frameCount %zu",
+ __func__, playbackFrameCount, recordFrameCount, frameCount);
+
+ tempRecordTrack = new RecordThread::PatchRecord(
+ mRecord.thread().get(),
+ sampleRate,
+ inChannelMask,
+ format,
+ frameCount,
+ nullptr,
+ (size_t)0 /* bufferSize */,
+ inputFlags);
+ }
+ status = mRecord.checkTrack(tempRecordTrack.get());
+ if (status != NO_ERROR) {
+ return status;
+ }
+
// create a special playback track to render to playback thread.
// this track is given the same buffer as the PatchRecord buffer
- sp<PlaybackThread::PatchTrack> tempPatchTrack = new (std::nothrow) PlaybackThread::PatchTrack(
+ sp<PlaybackThread::PatchTrack> tempPatchTrack = new PlaybackThread::PatchTrack(
mPlayback.thread().get(),
streamType,
sampleRate,
@@ -530,8 +559,14 @@
}
// tie playback and record tracks together
- mRecord.setTrackAndPeer(tempRecordTrack, tempPatchTrack);
- mPlayback.setTrackAndPeer(tempPatchTrack, tempRecordTrack);
+ // In the case of PassthruPatchRecord no I/O activity happens on RecordThread,
+ // everything is driven from PlaybackThread. Thus AudioBufferProvider methods
+ // of PassthruPatchRecord can only be called if the corresponding PatchTrack
+ // is alive. There is no need to hold a reference, and there is no need
+ // to clear it. In fact, since playback stopping is asynchronous, there is
+ // no proper time when clearing could be done.
+ mRecord.setTrackAndPeer(tempRecordTrack, tempPatchTrack, !usePassthruPatchRecord);
+ mPlayback.setTrackAndPeer(tempPatchTrack, tempRecordTrack, true /*holdReference*/);
// start capture and playback
mRecord.track()->start(AudioSystem::SYNC_EVENT_NONE, AUDIO_SESSION_NONE);
@@ -613,8 +648,21 @@
String8 AudioFlinger::PatchPanel::Patch::dump(audio_patch_handle_t myHandle) const
{
// TODO: Consider table dump form for patches, just like tracks.
- String8 result = String8::format("Patch %d: thread %p => thread %p",
- myHandle, mRecord.const_thread().get(), mPlayback.const_thread().get());
+ String8 result = String8::format("Patch %d: %s (thread %p => thread %p)",
+ myHandle, isSoftware() ? "Software bridge between" : "No software bridge",
+ mRecord.const_thread().get(), mPlayback.const_thread().get());
+
+ bool hasSinkDevice =
+ mAudioPatch.num_sinks > 0 && mAudioPatch.sinks[0].type == AUDIO_PORT_TYPE_DEVICE;
+ bool hasSourceDevice =
+ mAudioPatch.num_sources > 0 && mAudioPatch.sources[0].type == AUDIO_PORT_TYPE_DEVICE;
+ result.appendFormat(" thread %p %s (%d) first device type %08x", mThread.unsafe_get(),
+ hasSinkDevice ? "num sinks" :
+ (hasSourceDevice ? "num sources" : "no devices"),
+ hasSinkDevice ? mAudioPatch.num_sinks :
+ (hasSourceDevice ? mAudioPatch.num_sources : 0),
+ hasSinkDevice ? mAudioPatch.sinks[0].ext.device.type :
+ (hasSourceDevice ? mAudioPatch.sources[0].ext.device.type : 0));
// add latency if it exists
double latencyMs;
@@ -690,11 +738,16 @@
status = BAD_VALUE;
}
- mPatches.erase(iter);
- removeSoftwarePatchFromInsertedModules(handle);
+ erasePatch(handle);
return status;
}
+void AudioFlinger::PatchPanel::erasePatch(audio_patch_handle_t handle) {
+ mPatches.erase(handle);
+ removeSoftwarePatchFromInsertedModules(handle);
+ mAudioFlinger.mDeviceEffectManager.releaseAudioPatch(handle);
+}
+
/* List connected audio ports and they attributes */
status_t AudioFlinger::PatchPanel::listAudioPatches(unsigned int *num_patches __unused,
struct audio_patch *patches __unused)
@@ -778,16 +831,13 @@
String8 patchPanelDump;
const char *indent = " ";
- // Only dump software patches.
bool headerPrinted = false;
for (const auto& iter : mPatches) {
- if (iter.second.isSoftware()) {
- if (!headerPrinted) {
- patchPanelDump += "\nSoftware patches:\n";
- headerPrinted = true;
- }
- patchPanelDump.appendFormat("%s%s\n", indent, iter.second.dump(iter.first).string());
+ if (!headerPrinted) {
+ patchPanelDump += "\nPatches:\n";
+ headerPrinted = true;
}
+ patchPanelDump.appendFormat("%s%s\n", indent, iter.second.dump(iter.first).string());
}
headerPrinted = false;
diff --git a/services/audioflinger/PatchPanel.h b/services/audioflinger/PatchPanel.h
index 181e27c..89d4eb1 100644
--- a/services/audioflinger/PatchPanel.h
+++ b/services/audioflinger/PatchPanel.h
@@ -76,13 +76,18 @@
void dump(int fd) const;
-private:
template<typename ThreadType, typename TrackType>
- class Endpoint {
+ class Endpoint final {
public:
Endpoint() = default;
Endpoint(const Endpoint&) = delete;
- Endpoint& operator=(const Endpoint&) = delete;
+ Endpoint& operator=(const Endpoint& other) noexcept {
+ mThread = other.mThread;
+ mCloseThread = other.mCloseThread;
+ mHandle = other.mHandle;
+ mTrack = other.mTrack;
+ return *this;
+ }
Endpoint(Endpoint&& other) noexcept { swap(other); }
Endpoint& operator=(Endpoint&& other) noexcept {
swap(other);
@@ -98,8 +103,8 @@
return trackOrNull->initCheck();
}
audio_patch_handle_t handle() const { return mHandle; }
- sp<ThreadType> thread() { return mThread; }
- sp<TrackType> track() { return mTrack; }
+ sp<ThreadType> thread() const { return mThread; }
+ sp<TrackType> track() const { return mTrack; }
sp<const ThreadType> const_thread() const { return mThread; }
sp<const TrackType> const_track() const { return mTrack; }
@@ -123,18 +128,20 @@
mCloseThread = closeThread;
}
template <typename T>
- void setTrackAndPeer(const sp<TrackType>& track, const sp<T> &peer) {
+ void setTrackAndPeer(const sp<TrackType>& track, const sp<T> &peer, bool holdReference) {
mTrack = track;
mThread->addPatchTrack(mTrack);
- mTrack->setPeerProxy(peer, true /* holdReference */);
+ mTrack->setPeerProxy(peer, holdReference);
+ mClearPeerProxy = holdReference;
}
- void clearTrackPeer() { if (mTrack) mTrack->clearPeerProxy(); }
+ void clearTrackPeer() { if (mClearPeerProxy && mTrack) mTrack->clearPeerProxy(); }
void stopTrack() { if (mTrack) mTrack->stop(); }
void swap(Endpoint &other) noexcept {
using std::swap;
swap(mThread, other.mThread);
swap(mCloseThread, other.mCloseThread);
+ swap(mClearPeerProxy, other.mClearPeerProxy);
swap(mHandle, other.mHandle);
swap(mTrack, other.mTrack);
}
@@ -146,18 +153,41 @@
private:
sp<ThreadType> mThread;
bool mCloseThread = true;
+ bool mClearPeerProxy = true;
audio_patch_handle_t mHandle = AUDIO_PATCH_HANDLE_NONE;
sp<TrackType> mTrack;
};
- class Patch {
+ class Patch final {
public:
explicit Patch(const struct audio_patch &patch) : mAudioPatch(patch) {}
+ Patch() = default;
~Patch();
- Patch(const Patch&) = delete;
- Patch(Patch&&) = default;
- Patch& operator=(const Patch&) = delete;
- Patch& operator=(Patch&&) = default;
+ Patch(const Patch& other) noexcept {
+ mAudioPatch = other.mAudioPatch;
+ mHalHandle = other.mHalHandle;
+ mPlayback = other.mPlayback;
+ mRecord = other.mRecord;
+ mThread = other.mThread;
+ }
+ Patch(Patch&& other) noexcept { swap(other); }
+ Patch& operator=(Patch&& other) noexcept {
+ swap(other);
+ return *this;
+ }
+
+ void swap(Patch &other) noexcept {
+ using std::swap;
+ swap(mAudioPatch, other.mAudioPatch);
+ swap(mHalHandle, other.mHalHandle);
+ swap(mPlayback, other.mPlayback);
+ swap(mRecord, other.mRecord);
+ swap(mThread, other.mThread);
+ }
+
+ friend void swap(Patch &a, Patch &b) noexcept {
+ a.swap(b);
+ }
status_t createConnections(PatchPanel *panel);
void clearConnections(PatchPanel *panel);
@@ -165,6 +195,9 @@
return mRecord.handle() != AUDIO_PATCH_HANDLE_NONE ||
mPlayback.handle() != AUDIO_PATCH_HANDLE_NONE; }
+ void setThread(sp<ThreadBase> thread) { mThread = thread; }
+ wp<ThreadBase> thread() const { return mThread; }
+
// returns the latency of the patch (from record to playback).
status_t getLatencyMs(double *latencyMs) const;
@@ -182,13 +215,20 @@
Endpoint<PlaybackThread, PlaybackThread::PatchTrack> mPlayback;
// connects source device to record thread input
Endpoint<RecordThread, RecordThread::PatchRecord> mRecord;
+
+ wp<ThreadBase> mThread;
};
+ // Call with AudioFlinger mLock held
+ std::map<audio_patch_handle_t, Patch>& patches_l() { return mPatches; }
+
+private:
AudioHwDevice* findAudioHwDeviceByModule(audio_module_handle_t module);
sp<DeviceHalInterface> findHwDeviceByModule(audio_module_handle_t module);
void addSoftwarePatchToInsertedModules(
audio_module_handle_t module, audio_patch_handle_t handle);
void removeSoftwarePatchFromInsertedModules(audio_patch_handle_t handle);
+ void erasePatch(audio_patch_handle_t handle);
AudioFlinger &mAudioFlinger;
std::map<audio_patch_handle_t, Patch> mPatches;
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 17adba5..1ff03c4 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -271,8 +271,6 @@
private:
void interceptBuffer(const AudioBufferProvider::Buffer& buffer);
- /** Write the source data in the buffer provider. @return written frame count. */
- size_t writeFrames(AudioBufferProvider* dest, const void* src, size_t frameCount);
template <class F>
void forEachTeePatchTrack(F f) {
for (auto& tp : mTeePatches) { f(tp.patchTrack); }
@@ -396,6 +394,8 @@
* even if it might glitch. */);
virtual ~PatchTrack();
+ size_t framesReady() const override;
+
virtual status_t start(AudioSystem::sync_event_t event =
AudioSystem::SYNC_EVENT_NONE,
audio_session_t triggerSession = AUDIO_SESSION_NONE);
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index c8397cd..d87239d 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -25,7 +25,8 @@
~OpRecordAudioMonitor() override;
bool hasOpRecordAudio() const;
- static sp<OpRecordAudioMonitor> createIfNeeded(uid_t uid, const String16& opPackageName);
+ static sp<OpRecordAudioMonitor> createIfNeeded
+ (uid_t uid, const audio_attributes_t& attr, const String16& opPackageName);
private:
OpRecordAudioMonitor(uid_t uid, const String16& opPackageName);
@@ -167,6 +168,8 @@
const Timeout& timeout = {});
virtual ~PatchRecord();
+ virtual Source* getSource() { return nullptr; }
+
// AudioBufferProvider interface
virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
@@ -175,4 +178,71 @@
virtual status_t obtainBuffer(Proxy::Buffer *buffer,
const struct timespec *timeOut = NULL);
virtual void releaseBuffer(Proxy::Buffer *buffer);
+
+ size_t writeFrames(const void* src, size_t frameCount, size_t frameSize) {
+ return writeFrames(this, src, frameCount, frameSize);
+ }
+
+protected:
+ /** Write the source data into the buffer provider. @return written frame count. */
+ static size_t writeFrames(AudioBufferProvider* dest, const void* src,
+ size_t frameCount, size_t frameSize);
+
}; // end of PatchRecord
+
+class PassthruPatchRecord : public PatchRecord, public Source {
+public:
+ PassthruPatchRecord(RecordThread *recordThread,
+ uint32_t sampleRate,
+ audio_channel_mask_t channelMask,
+ audio_format_t format,
+ size_t frameCount,
+ audio_input_flags_t flags);
+
+ Source* getSource() override { return static_cast<Source*>(this); }
+
+ // Source interface
+ status_t read(void *buffer, size_t bytes, size_t *read) override;
+ status_t getCapturePosition(int64_t *frames, int64_t *time) override;
+ status_t standby() override;
+
+ // AudioBufferProvider interface
+ // This interface is used by RecordThread to pass the data obtained
+ // from HAL or other source to the client. PassthruPatchRecord receives
+ // the data in 'obtainBuffer' so these calls are stubbed out.
+ status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) override;
+ void releaseBuffer(AudioBufferProvider::Buffer* buffer) override;
+
+ // PatchProxyBufferProvider interface
+ // This interface is used from DirectOutputThread to acquire data from HAL.
+ bool producesBufferOnDemand() const override { return true; }
+ status_t obtainBuffer(Proxy::Buffer *buffer, const struct timespec *timeOut = nullptr) override;
+ void releaseBuffer(Proxy::Buffer *buffer) override;
+
+private:
+ // This is to use with PatchRecord::writeFrames
+ struct PatchRecordAudioBufferProvider : public AudioBufferProvider {
+ explicit PatchRecordAudioBufferProvider(PassthruPatchRecord& passthru) :
+ mPassthru(passthru) {}
+ status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) override {
+ return mPassthru.PatchRecord::getNextBuffer(buffer);
+ }
+ void releaseBuffer(AudioBufferProvider::Buffer* buffer) override {
+ return mPassthru.PatchRecord::releaseBuffer(buffer);
+ }
+ private:
+ PassthruPatchRecord& mPassthru;
+ };
+
+ sp<StreamInHalInterface> obtainStream(sp<ThreadBase>* thread);
+
+ PatchRecordAudioBufferProvider mPatchRecordAudioBufferProvider;
+ std::unique_ptr<void, decltype(free)*> mSinkBuffer; // frame size aligned continuous buffer
+ std::unique_ptr<void, decltype(free)*> mStubBuffer; // buffer used for AudioBufferProvider
+ size_t mUnconsumedFrames = 0;
+ std::mutex mReadLock;
+ std::condition_variable mReadCV;
+ size_t mReadBytes = 0; // GUARDED_BY(mReadLock)
+ status_t mReadError = NO_ERROR; // GUARDED_BY(mReadLock)
+ int64_t mLastReadFrames = 0; // accessed on RecordThread only
+};
diff --git a/services/audioflinger/SpdifStreamOut.cpp b/services/audioflinger/SpdifStreamOut.cpp
index a44ab2a..c7aba79 100644
--- a/services/audioflinger/SpdifStreamOut.cpp
+++ b/services/audioflinger/SpdifStreamOut.cpp
@@ -59,6 +59,7 @@
// TODO Move this into the audio_utils as a static method.
switch(config->format) {
case AUDIO_FORMAT_E_AC3:
+ case AUDIO_FORMAT_E_AC3_JOC:
mRateMultiplier = 4;
break;
case AUDIO_FORMAT_AC3:
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index bd9bf7b..dc39b62 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -24,11 +24,14 @@
#include <math.h>
#include <fcntl.h>
#include <memory>
+#include <sstream>
#include <string>
#include <linux/futex.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <cutils/properties.h>
+#include <media/AudioContainers.h>
+#include <media/AudioDeviceTypeAddr.h>
#include <media/AudioParameter.h>
#include <media/AudioResamplerPublic.h>
#include <media/RecordBufferConverter.h>
@@ -39,6 +42,7 @@
#include <private/media/AudioTrackShared.h>
#include <private/android_filesystem_config.h>
#include <audio_utils/Balance.h>
+#include <audio_utils/Metadata.h>
#include <audio_utils/channels.h>
#include <audio_utils/mono_blend.h>
#include <audio_utils/primitives.h>
@@ -210,6 +214,28 @@
// ----------------------------------------------------------------------------
+// TODO: move all toString helpers to audio.h
+// under #ifdef __cplusplus #endif
+static std::string patchSinksToString(const struct audio_patch *patch)
+{
+ std::stringstream ss;
+ for (size_t i = 0; i < patch->num_sinks; ++i) {
+ ss << "(" << toString(patch->sinks[i].ext.device.type)
+ << ", " << patch->sinks[i].ext.device.address << ")";
+ }
+ return ss.str();
+}
+
+static std::string patchSourcesToString(const struct audio_patch *patch)
+{
+ std::stringstream ss;
+ for (size_t i = 0; i < patch->num_sources; ++i) {
+ ss << "(" << toString(patch->sources[i].ext.device.type)
+ << ", " << patch->sources[i].ext.device.address << ")";
+ }
+ return ss.str();
+}
+
static pthread_once_t sFastTrackMultiplierOnce = PTHREAD_ONCE_INIT;
static void sFastTrackMultiplierInit()
@@ -460,22 +486,29 @@
}
AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
- audio_devices_t outDevice, audio_devices_t inDevice, type_t type, bool systemReady)
+ type_t type, bool systemReady)
: Thread(false /*canCallJava*/),
mType(type),
mAudioFlinger(audioFlinger),
+ mMetricsId(std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(id)),
// mSampleRate, mFrameCount, mChannelMask, mChannelCount, mFrameSize, mFormat, mBufferSize
// are set by PlaybackThread::readOutputParameters_l() or
// RecordThread::readInputParameters_l()
//FIXME: mStandby should be true here. Is this some kind of hack?
- mStandby(false), mOutDevice(outDevice), mInDevice(inDevice),
- mPrevOutDevice(AUDIO_DEVICE_NONE), mPrevInDevice(AUDIO_DEVICE_NONE),
+ mStandby(false),
mAudioSource(AUDIO_SOURCE_DEFAULT), mId(id),
// mName will be set by concrete (non-virtual) subclass
mDeathRecipient(new PMDeathRecipient(this)),
mSystemReady(systemReady),
mSignalPending(false)
{
+ mediametrics::LogItem(mMetricsId)
+ .setPid(getpid())
+ .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR)
+ .set(AMEDIAMETRICS_PROP_TYPE, threadTypeToString(type))
+ .set(AMEDIAMETRICS_PROP_THREADID, id)
+ .record();
+
memset(&mPatch, 0, sizeof(struct audio_patch));
}
@@ -492,6 +525,10 @@
}
sendStatistics(true /* force */);
+
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_DTOR)
+ .record();
}
status_t AudioFlinger::ThreadBase::readyToRun()
@@ -646,6 +683,18 @@
return sendConfigEvent_l(configEvent);
}
+status_t AudioFlinger::ThreadBase::sendUpdateOutDeviceConfigEvent(
+ const DeviceDescriptorBaseVector& outDevices)
+{
+ if (type() != RECORD) {
+ // The update out device operation is only for record thread.
+ return INVALID_OPERATION;
+ }
+ Mutex::Autolock _l(mLock);
+ sp<ConfigEvent> configEvent = (ConfigEvent *)new UpdateOutDevicesConfigEvent(outDevices);
+ return sendConfigEvent_l(configEvent);
+}
+
// post condition: mConfigEvents.isEmpty()
void AudioFlinger::ThreadBase::processConfigEvents_l()
@@ -680,24 +729,29 @@
}
} break;
case CFG_EVENT_CREATE_AUDIO_PATCH: {
- const audio_devices_t oldDevice = getDevice();
+ const DeviceTypeSet oldDevices = getDeviceTypes();
CreateAudioPatchConfigEventData *data =
(CreateAudioPatchConfigEventData *)event->mData.get();
event->mStatus = createAudioPatch_l(&data->mPatch, &data->mHandle);
- const audio_devices_t newDevice = getDevice();
- mLocalLog.log("CFG_EVENT_CREATE_AUDIO_PATCH: old device %#x (%s) new device %#x (%s)",
- (unsigned)oldDevice, toString(oldDevice).c_str(),
- (unsigned)newDevice, toString(newDevice).c_str());
+ const DeviceTypeSet newDevices = getDeviceTypes();
+ mLocalLog.log("CFG_EVENT_CREATE_AUDIO_PATCH: old device %s (%s) new device %s (%s)",
+ dumpDeviceTypes(oldDevices).c_str(), toString(oldDevices).c_str(),
+ dumpDeviceTypes(newDevices).c_str(), toString(newDevices).c_str());
} break;
case CFG_EVENT_RELEASE_AUDIO_PATCH: {
- const audio_devices_t oldDevice = getDevice();
+ const DeviceTypeSet oldDevices = getDeviceTypes();
ReleaseAudioPatchConfigEventData *data =
(ReleaseAudioPatchConfigEventData *)event->mData.get();
event->mStatus = releaseAudioPatch_l(data->mHandle);
- const audio_devices_t newDevice = getDevice();
- mLocalLog.log("CFG_EVENT_RELEASE_AUDIO_PATCH: old device %#x (%s) new device %#x (%s)",
- (unsigned)oldDevice, toString(oldDevice).c_str(),
- (unsigned)newDevice, toString(newDevice).c_str());
+ const DeviceTypeSet newDevices = getDeviceTypes();
+ mLocalLog.log("CFG_EVENT_RELEASE_AUDIO_PATCH: old device %s (%s) new device %s (%s)",
+ dumpDeviceTypes(oldDevices).c_str(), toString(oldDevices).c_str(),
+ dumpDeviceTypes(newDevices).c_str(), toString(newDevices).c_str());
+ } break;
+ case CFG_EVENT_UPDATE_OUT_DEVICE: {
+ UpdateOutDevicesConfigEventData *data =
+ (UpdateOutDevicesConfigEventData *)event->mData.get();
+ updateOutDevices(data->mOutDevices);
} break;
default:
ALOG_ASSERT(false, "processConfigEvents_l() unknown event type %d", event->mType);
@@ -840,8 +894,10 @@
dprintf(fd, " none\n");
}
// Note: output device may be used by capture threads for effects such as AEC.
- dprintf(fd, " Output device: %#x (%s)\n", mOutDevice, toString(mOutDevice).c_str());
- dprintf(fd, " Input device: %#x (%s)\n", mInDevice, toString(mInDevice).c_str());
+ dprintf(fd, " Output devices: %s (%s)\n",
+ dumpDeviceTypes(outDeviceTypes()).c_str(), toString(outDeviceTypes()).c_str());
+ dprintf(fd, " Input device: %#x (%s)\n",
+ inDeviceType(), toString(inDeviceType()).c_str());
dprintf(fd, " Audio source: %d (%s)\n", mAudioSource, toString(mAudioSource).c_str());
// Dump timestamp statistics for the Thread types that support it.
@@ -1011,6 +1067,12 @@
mPowerManager.clear();
}
+void AudioFlinger::ThreadBase::updateOutDevices(
+ const DeviceDescriptorBaseVector& outDevices __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();
@@ -1120,32 +1182,26 @@
}
}
-void AudioFlinger::ThreadBase::checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
- bool enabled,
- audio_session_t sessionId)
-{
- Mutex::Autolock _l(mLock);
- checkSuspendOnEffectEnabled_l(effect, enabled, sessionId);
-}
+void AudioFlinger::ThreadBase::checkSuspendOnEffectEnabled(bool enabled,
+ audio_session_t sessionId,
+ bool threadLocked) {
+ if (!threadLocked) {
+ mLock.lock();
+ }
-void AudioFlinger::ThreadBase::checkSuspendOnEffectEnabled_l(const sp<EffectModule>& effect,
- bool enabled,
- audio_session_t sessionId)
-{
if (mType != RECORD) {
// suspend all effects in AUDIO_SESSION_OUTPUT_MIX when enabling any effect on
// another session. This gives the priority to well behaved effect control panels
// and applications not using global effects.
// Enabling post processing in AUDIO_SESSION_OUTPUT_STAGE session does not affect
// global effects
- if ((sessionId != AUDIO_SESSION_OUTPUT_MIX) && (sessionId != AUDIO_SESSION_OUTPUT_STAGE)) {
+ if (!audio_is_global_session(sessionId)) {
setEffectSuspended_l(NULL, enabled, AUDIO_SESSION_OUTPUT_MIX);
}
}
- sp<EffectChain> chain = getEffectChain_l(sessionId);
- if (chain != 0) {
- chain->checkSuspendOnEffectEnabled(effect, enabled);
+ if (!threadLocked) {
+ mLock.unlock();
}
}
@@ -1153,8 +1209,9 @@
status_t AudioFlinger::RecordThread::checkEffectCompatibility_l(
const effect_descriptor_t *desc, audio_session_t sessionId)
{
- // No global effect sessions on record threads
- if (sessionId == AUDIO_SESSION_OUTPUT_MIX || sessionId == AUDIO_SESSION_OUTPUT_STAGE) {
+ // No global output effect sessions on record threads
+ if (sessionId == AUDIO_SESSION_OUTPUT_MIX
+ || sessionId == AUDIO_SESSION_OUTPUT_STAGE) {
ALOGW("checkEffectCompatibility_l(): global effect %s on record thread %s",
desc->name, mThreadName);
return BAD_VALUE;
@@ -1228,6 +1285,13 @@
" on output stage session", desc->name);
return BAD_VALUE;
}
+ } else if (sessionId == AUDIO_SESSION_DEVICE) {
+ // only post processing on output stage session
+ if ((desc->flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_POST_PROC) {
+ ALOGW("checkEffectCompatibility_l(): non post processing effect %s not allowed"
+ " on device session", desc->name);
+ return BAD_VALUE;
+ }
} else {
// no restriction on effects applied on non fast tracks
if ((hasAudioSession_l(sessionId) & ThreadBase::FAST_SESSION) == 0) {
@@ -1269,7 +1333,7 @@
return BAD_VALUE;
}
#endif
- if ((sessionId == AUDIO_SESSION_OUTPUT_STAGE) || (sessionId == AUDIO_SESSION_OUTPUT_MIX)) {
+ if (audio_is_global_session(sessionId)) {
ALOGW("checkEffectCompatibility_l(): global effect %s on DUPLICATING"
" thread %s", desc->name, mThreadName);
return BAD_VALUE;
@@ -1301,7 +1365,8 @@
effect_descriptor_t *desc,
int *enabled,
status_t *status,
- bool pinned)
+ bool pinned,
+ bool probe)
{
sp<EffectModule> effect;
sp<EffectHandle> handle;
@@ -1323,7 +1388,7 @@
Mutex::Autolock _l(mLock);
lStatus = checkEffectCompatibility_l(desc, sessionId);
- if (lStatus != NO_ERROR) {
+ if (probe || lStatus != NO_ERROR) {
goto Exit;
}
@@ -1345,14 +1410,15 @@
if (effect == 0) {
effectId = mAudioFlinger->nextUniqueId(AUDIO_UNIQUE_ID_USE_EFFECT);
// create a new effect module if none present in the chain
- lStatus = chain->createEffect_l(effect, this, desc, effectId, sessionId, pinned);
+ lStatus = chain->createEffect_l(effect, desc, effectId, sessionId, pinned);
if (lStatus != NO_ERROR) {
goto Exit;
}
effectCreated = true;
- effect->setDevice(mOutDevice);
- effect->setDevice(mInDevice);
+ // FIXME: use vector of device and address when effect interface is ready.
+ effect->setDevices(outDeviceTypeAddrs());
+ effect->setInputDevice(inDeviceTypeAddr());
effect->setMode(mAudioFlinger->getMode());
effect->setAudioSource(mAudioSource);
}
@@ -1368,7 +1434,7 @@
}
Exit:
- if (lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) {
+ if (!probe && lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) {
Mutex::Autolock _l(mLock);
if (effectCreated) {
chain->removeEffect_l(effect);
@@ -1390,9 +1456,12 @@
sp<EffectModule> effect;
{
Mutex::Autolock _l(mLock);
-
- effect = handle->effect().promote();
- if (effect == 0) {
+ sp<EffectBase> effectBase = handle->effect().promote();
+ if (effectBase == nullptr) {
+ return;
+ }
+ effect = effectBase->asEffectModule();
+ if (effect == nullptr) {
return;
}
// restore suspended effects if the disconnected handle was enabled and the last one.
@@ -1404,11 +1473,34 @@
if (remove) {
mAudioFlinger->updateOrphanEffectChains(effect);
if (handle->enabled()) {
- checkSuspendOnEffectEnabled(effect, false, effect->sessionId());
+ effect->checkSuspendOnEffectEnabled(false, false /*threadLocked*/);
}
}
}
+void AudioFlinger::ThreadBase::onEffectEnable(const sp<EffectModule>& effect) {
+ if (mType == OFFLOAD || mType == MMAP) {
+ Mutex::Autolock _l(mLock);
+ broadcast_l();
+ }
+ if (!effect->isOffloadable()) {
+ if (mType == ThreadBase::OFFLOAD) {
+ PlaybackThread *t = (PlaybackThread *)this;
+ t->invalidateTracks(AUDIO_STREAM_MUSIC);
+ }
+ if (effect->sessionId() == AUDIO_SESSION_OUTPUT_MIX) {
+ mAudioFlinger->onNonOffloadableGlobalEffectEnable();
+ }
+ }
+}
+
+void AudioFlinger::ThreadBase::onEffectDisable() {
+ if (mType == OFFLOAD || mType == MMAP) {
+ Mutex::Autolock _l(mLock);
+ broadcast_l();
+ }
+}
+
sp<AudioFlinger::EffectModule> AudioFlinger::ThreadBase::getEffect(audio_session_t sessionId,
int effectId)
{
@@ -1468,8 +1560,8 @@
return status;
}
- effect->setDevice(mOutDevice);
- effect->setDevice(mInDevice);
+ effect->setDevices(outDeviceTypeAddrs());
+ effect->setInputDevice(inDeviceTypeAddr());
effect->setMode(mAudioFlinger->getMode());
effect->setAudioSource(mAudioSource);
@@ -1484,7 +1576,7 @@
detachAuxEffect_l(effect->id());
}
- sp<EffectChain> chain = effect->chain().promote();
+ sp<EffectChain> chain = effect->callback()->chain().promote();
if (chain != 0) {
// remove effect chain if removing last effect
if (chain->removeEffect_l(effect, release) == 0) {
@@ -1690,7 +1782,7 @@
mLastRecordedTimestampVerifierN = mTimestampVerifier.getN();
mLastRecordedTimeNs = timeNs;
- std::unique_ptr<MediaAnalyticsItem> item(MediaAnalyticsItem::create("audiothread"));
+ std::unique_ptr<mediametrics::Item> item(mediametrics::Item::create("audiothread"));
#define MM_PREFIX "android.media.audiothread." // avoid cut-n-paste errors.
@@ -1702,8 +1794,8 @@
item->setInt64(MM_PREFIX "channelMask", (int64_t)mChannelMask);
item->setCString(MM_PREFIX "encoding", toString(mFormat).c_str());
item->setInt32(MM_PREFIX "frameCount", (int32_t)mFrameCount);
- item->setCString(MM_PREFIX "outDevice", toString(mOutDevice).c_str());
- item->setCString(MM_PREFIX "inDevice", toString(mInDevice).c_str());
+ item->setCString(MM_PREFIX "outDevice", toString(outDeviceTypes()).c_str());
+ item->setCString(MM_PREFIX "inDevice", toString(inDeviceType()).c_str());
// thread statistics
if (mIoJitterMs.getN() > 0) {
@@ -1734,10 +1826,9 @@
AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger,
AudioStreamOut* output,
audio_io_handle_t id,
- audio_devices_t device,
type_t type,
bool systemReady)
- : ThreadBase(audioFlinger, id, device, AUDIO_DEVICE_NONE, type, systemReady),
+ : ThreadBase(audioFlinger, id, type, systemReady),
mNormalFrameCount(0), mSinkBuffer(NULL),
mMixerBufferEnabled(AudioFlinger::kEnableExtendedPrecision),
mMixerBuffer(NULL),
@@ -1783,7 +1874,7 @@
// and the mute set to false).
mMasterVolume = audioFlinger->masterVolume_l();
mMasterMute = audioFlinger->masterMute_l();
- if (mOutput && mOutput->audioHwDev) {
+ if (mOutput->audioHwDev) {
if (mOutput->audioHwDev->canSetMasterVolume()) {
mMasterVolume = 1.0;
}
@@ -1799,9 +1890,10 @@
// TODO: We may also match on address as well as device type for
// AUDIO_DEVICE_OUT_BUS, AUDIO_DEVICE_OUT_ALL_A2DP, AUDIO_DEVICE_OUT_REMOTE_SUBMIX
- if (type == MIXER || type == DIRECT) {
- mTimestampCorrectedDevices = (audio_devices_t)property_get_int64(
- "audio.timestamp.corrected_output_devices",
+ if (type == MIXER || type == DIRECT || type == OFFLOAD) {
+ // TODO: This property should be ensure that only contains one single device type.
+ mTimestampCorrectedDevice = (audio_devices_t)property_get_int64(
+ "audio.timestamp.corrected_output_device",
(int64_t)(mIsMsdDevice ? AUDIO_DEVICE_OUT_BUS // turn on by default for MSD
: AUDIO_DEVICE_NONE));
}
@@ -1812,9 +1904,11 @@
mStreamTypes[stream].volume = 0.0f;
mStreamTypes[stream].mute = mAudioFlinger->streamMute_l(stream);
}
- // Audio patch volume is always max
+ // Audio patch and call assistant volume are always max
mStreamTypes[AUDIO_STREAM_PATCH].volume = 1.0f;
mStreamTypes[AUDIO_STREAM_PATCH].mute = false;
+ mStreamTypes[AUDIO_STREAM_CALL_ASSISTANT].volume = 1.0f;
+ mStreamTypes[AUDIO_STREAM_CALL_ASSISTANT].mute = false;
}
AudioFlinger::PlaybackThread::~PlaybackThread()
@@ -1829,6 +1923,16 @@
void AudioFlinger::PlaybackThread::onFirstRef()
{
+ if (mOutput == nullptr || mOutput->stream == nullptr) {
+ ALOGE("The stream is not open yet"); // This should not happen.
+ } else {
+ // setEventCallback will need a strong pointer as a parameter. Calling it
+ // here instead of constructor of PlaybackThread so that the onFirstRef
+ // callback would not be made on an incompletely constructed object.
+ if (mOutput->stream->setEventCallback(this) != OK) {
+ ALOGE("Failed to add event callback");
+ }
+ }
run(mThreadName, ANDROID_PRIORITY_URGENT_AUDIO);
}
@@ -1958,7 +2062,8 @@
pid_t tid,
uid_t uid,
status_t *status,
- audio_port_handle_t portId)
+ audio_port_handle_t portId,
+ const sp<media::IAudioTrackCallback>& callback)
{
size_t frameCount = *pFrameCount;
size_t notificationFrameCount = *pNotificationFrameCount;
@@ -2024,6 +2129,7 @@
{ // scope for mLock
Mutex::Autolock _l(mLock);
for (audio_session_t session : {
+ AUDIO_SESSION_DEVICE,
AUDIO_SESSION_OUTPUT_STAGE,
AUDIO_SESSION_OUTPUT_MIX,
sessionId,
@@ -2079,9 +2185,9 @@
// More than 2 channels does not require stronger alignment than stereo
alignment <<= 1;
}
- if (((uintptr_t)sharedBuffer->pointer() & (alignment - 1)) != 0) {
+ if (((uintptr_t)sharedBuffer->unsecurePointer() & (alignment - 1)) != 0) {
ALOGE("Invalid buffer alignment: address %p, channel count %u",
- sharedBuffer->pointer(), channelCount);
+ sharedBuffer->unsecurePointer(), channelCount);
lStatus = BAD_VALUE;
goto Exit;
}
@@ -2247,6 +2353,12 @@
goto Exit;
}
mTracks.add(track);
+ {
+ Mutex::Autolock _atCbL(mAudioTrackCbLock);
+ if (callback.get() != nullptr) {
+ mAudioTrackCallbacks.emplace(callback);
+ }
+ }
sp<EffectChain> chain = getEffectChain_l(sessionId);
if (chain != 0) {
@@ -2549,6 +2661,29 @@
mCallbackThread->setAsyncError();
}
+void AudioFlinger::PlaybackThread::onCodecFormatChanged(
+ const std::basic_string<uint8_t>& metadataBs)
+{
+ std::thread([this, metadataBs]() {
+ audio_utils::metadata::Data metadata =
+ audio_utils::metadata::dataFromByteString(metadataBs);
+ if (metadata.empty()) {
+ ALOGW("Can not transform the buffer to audio metadata, %s, %d",
+ reinterpret_cast<char*>(const_cast<uint8_t*>(metadataBs.data())),
+ (int)metadataBs.size());
+ return;
+ }
+
+ audio_utils::metadata::ByteString metaDataStr =
+ audio_utils::metadata::byteStringFromData(metadata);
+ std::vector metadataVec(metaDataStr.begin(), metaDataStr.end());
+ Mutex::Autolock _l(mAudioTrackCbLock);
+ for (const auto& callback : mAudioTrackCallbacks) {
+ callback->onCodecFormatChanged(metadataVec);
+ }
+ }).detach();
+}
+
void AudioFlinger::PlaybackThread::resetWriteBlocked(uint32_t sequence)
{
Mutex::Autolock _l(mLock);
@@ -2609,7 +2744,7 @@
LOG_ALWAYS_FATAL_IF(result != OK,
"Error when retrieving output stream buffer size: %d", result);
mFrameCount = mBufferSize / mFrameSize;
- if (mFrameCount & 15) {
+ if ((mType == MIXER || mType == DUPLICATING) && (mFrameCount & 15)) {
ALOGW("HAL output buffer size is %zu frames but AudioMixer requires multiples of 16 frames",
mFrameCount);
}
@@ -2738,6 +2873,30 @@
mAudioFlinger->moveEffectChain_l(effectChains[i]->sessionId(),
this/* srcThread */, this/* dstThread */);
}
+
+ audio_output_flags_t flags = mOutput->flags;
+ mediametrics::LogItem item(mMetricsId);
+ item.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_READPARAMETERS)
+ .set(AMEDIAMETRICS_PROP_ENCODING, formatToString(mFormat).c_str())
+ .set(AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)mSampleRate)
+ .set(AMEDIAMETRICS_PROP_CHANNELMASK, (int32_t)mChannelMask)
+ .set(AMEDIAMETRICS_PROP_CHANNELCOUNT, (int32_t)mChannelCount)
+ .set(AMEDIAMETRICS_PROP_FRAMECOUNT, (int32_t)mNormalFrameCount)
+ .set(AMEDIAMETRICS_PROP_FLAGS, toString(flags).c_str())
+ .set(AMEDIAMETRICS_PROP_PREFIX_HAPTIC AMEDIAMETRICS_PROP_CHANNELMASK,
+ (int32_t)mHapticChannelMask)
+ .set(AMEDIAMETRICS_PROP_PREFIX_HAPTIC AMEDIAMETRICS_PROP_CHANNELCOUNT,
+ (int32_t)mHapticChannelCount)
+ .set(AMEDIAMETRICS_PROP_PREFIX_HAL AMEDIAMETRICS_PROP_ENCODING,
+ formatToString(mHALFormat).c_str())
+ .set(AMEDIAMETRICS_PROP_PREFIX_HAL AMEDIAMETRICS_PROP_FRAMECOUNT,
+ (int32_t)mFrameCount) // sic - added HAL
+ ;
+ uint32_t latencyMs;
+ if (mOutput->stream->getLatency(&latencyMs) == NO_ERROR) {
+ item.set(AMEDIAMETRICS_PROP_PREFIX_HAL AMEDIAMETRICS_PROP_LATENCYMS, (double)latencyMs);
+ }
+ item.record();
}
void AudioFlinger::PlaybackThread::updateMetadata_l()
@@ -2891,7 +3050,7 @@
{
if (!mMasterMute) {
char value[PROPERTY_VALUE_MAX];
- if (mOutDevice == AUDIO_DEVICE_OUT_REMOTE_SUBMIX) {
+ if (isSingleDeviceType(outDeviceTypes(), AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) {
ALOGD("ro.audio.silent will be ignored for threads on AUDIO_DEVICE_OUT_REMOTE_SUBMIX");
return;
}
@@ -2953,9 +3112,11 @@
ALOG_ASSERT(mCallbackThread != 0);
mCallbackThread->setWriteBlocked(mWriteAckSequence);
}
+ ATRACE_BEGIN("write");
// FIXME We should have an implementation of timestamps for direct output threads.
// They are used e.g for multichannel PCM playback over HDMI.
bytesWritten = mOutput->write((char *)mSinkBuffer + offset, mBytesRemaining);
+ ATRACE_END();
if (mUseAsyncWrite &&
((bytesWritten < 0) || (bytesWritten == (ssize_t)mBytesRemaining))) {
@@ -3033,7 +3194,7 @@
// make sure standby delay is not too short when connected to an A2DP sink to avoid
// truncating audio when going to standby.
mStandbyDelayNs = AudioFlinger::mStandbyTimeInNsecs;
- if ((mOutDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != 0) {
+ if (!Intersection(outDeviceTypes(), getAudioDeviceOutAllA2dpSet()).empty()) {
if (mStandbyDelayNs < kDefaultStandbyTimeInNsecs) {
mStandbyDelayNs = kDefaultStandbyTimeInNsecs;
}
@@ -3074,7 +3235,7 @@
halOutBuffer = halInBuffer;
effect_buffer_t *buffer = reinterpret_cast<effect_buffer_t*>(halInBuffer->externalData());
ALOGV("addEffectChain_l() %p on thread %p for session %d", chain.get(), this, session);
- if (session > AUDIO_SESSION_OUTPUT_MIX) {
+ if (!audio_is_global_session(session)) {
// Only one effect chain can be present in direct output thread and it uses
// the sink buffer as input
if (mType != DIRECT) {
@@ -3114,8 +3275,11 @@
chain->setThread(this);
chain->setInBuffer(halInBuffer);
chain->setOutBuffer(halOutBuffer);
- // Effect chain for session AUDIO_SESSION_OUTPUT_STAGE is inserted at end of effect
- // chains list in order to be processed last as it contains output stage effects.
+ // Effect chain for session AUDIO_SESSION_DEVICE is inserted at end of effect
+ // chains list in order to be processed last as it contains output device effects.
+ // Effect chain for session AUDIO_SESSION_OUTPUT_STAGE is inserted just before to apply post
+ // processing effects specific to an output stream before effects applied to all streams
+ // routed to a given device.
// Effect chain for session AUDIO_SESSION_OUTPUT_MIX is inserted before
// session AUDIO_SESSION_OUTPUT_STAGE to be processed
// after track specific effects and before output stage.
@@ -3125,7 +3289,8 @@
// chains list to be processed before output mix effects. Relative order between other
// sessions is not important.
static_assert(AUDIO_SESSION_OUTPUT_MIX == 0 &&
- AUDIO_SESSION_OUTPUT_STAGE < AUDIO_SESSION_OUTPUT_MIX,
+ AUDIO_SESSION_OUTPUT_STAGE < AUDIO_SESSION_OUTPUT_MIX &&
+ AUDIO_SESSION_DEVICE < AUDIO_SESSION_OUTPUT_STAGE,
"audio_session_t constants misdefined");
size_t size = mEffectChains.size();
size_t i = 0;
@@ -3281,8 +3446,8 @@
// If the device is AUDIO_DEVICE_OUT_BUS, check for downstream latency.
//
- // Note: we access outDevice() outside of mLock.
- if (isMsdDevice() && (outDevice() & AUDIO_DEVICE_OUT_BUS) != 0) {
+ // Note: we access outDeviceTypes() outside of mLock.
+ if (isMsdDevice() && outDeviceTypes().count(AUDIO_DEVICE_OUT_BUS) != 0) {
// Here, we try for the AF lock, but do not block on it as the latency
// is more informational.
if (mAudioFlinger->mLock.tryLock() == NO_ERROR) {
@@ -3587,7 +3752,13 @@
// Tally underrun frames as we are inserting 0s here.
for (const auto& track : activeTracks) {
- if (track->mFillingUpStatus == Track::FS_ACTIVE) {
+ if (track->mFillingUpStatus == Track::FS_ACTIVE
+ && !track->isStopped()
+ && !track->isPaused()
+ && !track->isTerminated()) {
+ ALOGV("%s: track(%d) %s underrun due to thread sleep of %zu frames",
+ __func__, track->id(), track->getTrackStateAsString(),
+ mNormalFrameCount);
track->mAudioTrackServerProxy->tallyUnderrunFrames(mNormalFrameCount);
}
}
@@ -3802,6 +3973,11 @@
const int32_t throttleMs = (int32_t)mHalfBufferMs - deltaMs;
if ((signed)mHalfBufferMs >= throttleMs && throttleMs > 0) {
+ mediametrics::LogItem(mMetricsId)
+ // ms units always double
+ .set(AMEDIAMETRICS_PROP_THROTTLEMS, (double)throttleMs)
+ .record();
+
usleep(throttleMs * 1000);
// notify of throttle start on verbose log
ALOGV_IF(mThreadThrottleEndMs == mThreadThrottleTimeMs,
@@ -3818,8 +3994,10 @@
if (diff > 0) {
// notify of throttle end on debug log
// but prevent spamming for bluetooth
- ALOGD_IF(!audio_is_a2dp_out_device(outDevice()) &&
- !audio_is_hearing_aid_out_device(outDevice()),
+ ALOGD_IF(!isSingleDeviceType(
+ outDeviceTypes(), audio_is_a2dp_out_device) &&
+ !isSingleDeviceType(
+ outDeviceTypes(), audio_is_hearing_aid_out_device),
"mixer(%p) throttle end: throttle time(%u)", this, diff);
mThreadThrottleEndMs = mThreadThrottleTimeMs;
}
@@ -4004,25 +4182,31 @@
// store new device and send to effects
audio_devices_t type = AUDIO_DEVICE_NONE;
+ AudioDeviceTypeAddrVector deviceTypeAddrs;
for (unsigned int i = 0; i < patch->num_sinks; i++) {
+ LOG_ALWAYS_FATAL_IF(popcount(patch->sinks[i].ext.device.type) > 1
+ && !mOutput->audioHwDev->supportsAudioPatches(),
+ "Enumerated device type(%#x) must not be used "
+ "as it does not support audio patches",
+ patch->sinks[i].ext.device.type);
type |= patch->sinks[i].ext.device.type;
+ deviceTypeAddrs.push_back(AudioDeviceTypeAddr(patch->sinks[i].ext.device.type,
+ patch->sinks[i].ext.device.address));
}
audio_port_handle_t sinkPortId = patch->sinks[0].id;
#ifdef ADD_BATTERY_DATA
// when changing the audio output device, call addBatteryData to notify
// the change
- if (mOutDevice != type) {
+ if (outDeviceTypes() != deviceTypes) {
uint32_t params = 0;
// check whether speaker is on
- if (type & AUDIO_DEVICE_OUT_SPEAKER) {
+ if (deviceTypes.count(AUDIO_DEVICE_OUT_SPEAKER) > 0) {
params |= IMediaPlayerService::kBatteryDataSpeakerOn;
}
- audio_devices_t deviceWithoutSpeaker
- = AUDIO_DEVICE_OUT_ALL & ~AUDIO_DEVICE_OUT_SPEAKER;
// check if any other device (except speaker) is on
- if (type & deviceWithoutSpeaker) {
+ if (!isSingleDeviceType(deviceTypes, AUDIO_DEVICE_OUT_SPEAKER)) {
params |= IMediaPlayerService::kBatteryDataOtherAudioDeviceOn;
}
@@ -4033,14 +4217,15 @@
#endif
for (size_t i = 0; i < mEffectChains.size(); i++) {
- mEffectChains[i]->setDevice_l(type);
+ mEffectChains[i]->setDevices_l(deviceTypeAddrs);
}
- // mPrevOutDevice is the latest device set by createAudioPatch_l(). It is not set when
- // the thread is created so that the first patch creation triggers an ioConfigChanged callback
- bool configChanged = (mPrevOutDevice != type) || (mDeviceId != sinkPortId);
- mOutDevice = type;
+ // mPatch.num_sinks is not set when the thread is created so that
+ // the first patch creation triggers an ioConfigChanged callback
+ bool configChanged = (mPatch.num_sinks == 0) ||
+ (mPatch.sinks[0].id != sinkPortId);
mPatch = *patch;
+ mOutDeviceTypeAddrs = deviceTypeAddrs;
if (mOutput->audioHwDev->supportsAudioPatches()) {
sp<DeviceHalInterface> hwDevice = mOutput->audioHwDev->hwDevice();
@@ -4065,9 +4250,12 @@
status = mOutput->stream->setParameters(param.toString());
*handle = AUDIO_PATCH_HANDLE_NONE;
}
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATEAUDIOPATCH)
+ .set(AMEDIAMETRICS_PROP_OUTPUTDEVICES, patchSinksToString(patch).c_str())
+ .record();
+
if (configChanged) {
- mPrevOutDevice = type;
- mDeviceId = sinkPortId;
sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
}
return status;
@@ -4091,7 +4279,8 @@
{
status_t status = NO_ERROR;
- mOutDevice = AUDIO_DEVICE_NONE;
+ mPatch = audio_patch{};
+ mOutDeviceTypeAddrs.clear();
if (mOutput->audioHwDev->supportsAudioPatches()) {
sp<DeviceHalInterface> hwDevice = mOutput->audioHwDev->hwDevice();
@@ -4131,8 +4320,8 @@
// ----------------------------------------------------------------------------
AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
- audio_io_handle_t id, audio_devices_t device, bool systemReady, type_t type)
- : PlaybackThread(audioFlinger, output, id, device, type, systemReady),
+ audio_io_handle_t id, bool systemReady, type_t type)
+ : PlaybackThread(audioFlinger, output, id, type, systemReady),
// mAudioMixer below
// mFastMixer below
mFastMixerFutex(0),
@@ -4142,7 +4331,7 @@
// mNormalSink below
{
setMasterBalance(audioFlinger->getMasterBalance_l());
- ALOGV("MixerThread() id=%d device=%#x type=%d", id, device, type);
+ ALOGV("MixerThread() id=%d type=%d", id, type);
ALOGV("mSampleRate=%u, mChannelMask=%#x, mChannelCount=%u, mFormat=%#x, mFrameSize=%zu, "
"mFrameCount=%zu, mNormalFrameCount=%zu",
mSampleRate, mChannelMask, mChannelCount, mFormat, mFrameSize, mFrameCount,
@@ -4184,7 +4373,7 @@
// scheduled reliably with CFS. However, the BT A2DP HAL is
// bursty (does not pull at a regular rate) and so cannot operate with FastMixer.
initFastMixer = mFrameCount < mNormalFrameCount
- && (mOutDevice & AUDIO_DEVICE_OUT_ALL_A2DP) == 0;
+ && Intersection(outDeviceTypes(), getAudioDeviceOutAllA2dpSet()).empty();
break;
}
ALOGW_IF(initFastMixer == false && mFrameCount < mNormalFrameCount,
@@ -4607,19 +4796,29 @@
// DeferredOperations handles statistics after setting mixerStatus.
class DeferredOperations {
public:
- DeferredOperations(mixer_state *mixerStatus)
- : mMixerStatus(mixerStatus) { }
+ DeferredOperations(mixer_state *mixerStatus, const std::string &metricsId)
+ : mMixerStatus(mixerStatus)
+ , mMetricsId(metricsId) {}
// when leaving scope, tally frames properly.
~DeferredOperations() {
// Tally underrun frames only if we are actually mixing (MIXER_TRACKS_READY)
// because that is when the underrun occurs.
// We do not distinguish between FastTracks and NormalTracks here.
- if (*mMixerStatus == MIXER_TRACKS_READY) {
+ if (*mMixerStatus == MIXER_TRACKS_READY && mUnderrunFrames.size() > 0) {
+ mediametrics::LogItem item(mMetricsId);
+
+ item.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_UNDERRUN);
for (const auto &underrun : mUnderrunFrames) {
underrun.first->mAudioTrackServerProxy->tallyUnderrunFrames(
underrun.second);
+
+ item.set(std::string("[" AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
+ + std::to_string(underrun.first->portId())
+ + "]" AMEDIAMETRICS_PROP_UNDERRUN,
+ (int32_t)underrun.second);
}
+ item.record();
}
}
@@ -4632,8 +4831,10 @@
private:
const mixer_state * const mMixerStatus;
+ const std::string& mMetricsId;
std::vector<std::pair<sp<Track>, size_t>> mUnderrunFrames;
- } deferredOperations(&mixerStatus); // implicit nested scope for variable capture
+ } deferredOperations(&mixerStatus, mMetricsId);
+ // implicit nested scope for variable capture
bool noFastHapticTrack = true;
for (size_t i=0 ; i<count ; i++) {
@@ -5111,11 +5312,20 @@
mixerStatus != MIXER_TRACKS_ENABLED) {
mixerStatus = MIXER_TRACKS_READY;
}
+
+ // Enable the next few lines to instrument a test for underrun log handling.
+ // TODO: Remove when we have a better way of testing the underrun log.
+#if 0
+ static int i;
+ if ((++i & 0xf) == 0) {
+ deferredOperations.tallyUnderrunFrames(track, 10 /* underrunFrames */);
+ }
+#endif
} else {
size_t underrunFrames = 0;
if (framesReady < desiredFrames && !track->isStopped() && !track->isPaused()) {
- ALOGV("track(%d) underrun, framesReady(%zu) < framesDesired(%zd)",
- trackId, framesReady, desiredFrames);
+ ALOGV("track(%d) underrun, track state %s framesReady(%zu) < framesDesired(%zd)",
+ trackId, track->getTrackStateAsString(), framesReady, desiredFrames);
underrunFrames = desiredFrames;
}
deferredOperations.tallyUnderrunFrames(track, underrunFrames);
@@ -5301,11 +5511,11 @@
return false;
}
// Check validity as we don't call AudioMixer::create() here.
- if (!AudioMixer::isValidFormat(format)) {
+ if (!mAudioMixer->isValidFormat(format)) {
ALOGW("%s: invalid format: %#x", __func__, format);
return false;
}
- if (!AudioMixer::isValidChannelMask(channelMask)) {
+ if (!mAudioMixer->isValidChannelMask(channelMask)) {
ALOGW("%s: invalid channelMask: %#x", __func__, channelMask);
return false;
}
@@ -5355,39 +5565,7 @@
}
}
if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
-#ifdef ADD_BATTERY_DATA
- // when changing the audio output device, call addBatteryData to notify
- // the change
- if (mOutDevice != value) {
- uint32_t params = 0;
- // check whether speaker is on
- if (value & AUDIO_DEVICE_OUT_SPEAKER) {
- params |= IMediaPlayerService::kBatteryDataSpeakerOn;
- }
-
- audio_devices_t deviceWithoutSpeaker
- = AUDIO_DEVICE_OUT_ALL & ~AUDIO_DEVICE_OUT_SPEAKER;
- // check if any other device (except speaker) is on
- if (value & deviceWithoutSpeaker) {
- params |= IMediaPlayerService::kBatteryDataOtherAudioDeviceOn;
- }
-
- if (params != 0) {
- addBatteryData(params);
- }
- }
-#endif
-
- // forward device change to effects that have requested to be
- // aware of attached audio device.
- if (value != AUDIO_DEVICE_NONE) {
- a2dpDeviceChanged =
- (mOutDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != (value & AUDIO_DEVICE_OUT_ALL_A2DP);
- mOutDevice = value;
- for (size_t i = 0; i < mEffectChains.size(); i++) {
- mEffectChains[i]->setDevice_l(mOutDevice);
- }
- }
+ LOG_FATAL("Should not set routing device in MixerThread");
}
if (status == NO_ERROR) {
@@ -5488,9 +5666,8 @@
// ----------------------------------------------------------------------------
AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger,
- AudioStreamOut* output, audio_io_handle_t id, audio_devices_t device,
- ThreadBase::type_t type, bool systemReady)
- : PlaybackThread(audioFlinger, output, id, device, type, systemReady)
+ AudioStreamOut* output, audio_io_handle_t id, ThreadBase::type_t type, bool systemReady)
+ : PlaybackThread(audioFlinger, output, id, type, systemReady)
{
setMasterBalance(audioFlinger->getMasterBalance_l());
}
@@ -5658,10 +5835,17 @@
minFrames = 1;
}
- if ((track->framesReady() >= minFrames) && track->isReady() && !track->isPaused() &&
+ const size_t framesReady = track->framesReady();
+ const int trackId = track->id();
+ if (ATRACE_ENABLED()) {
+ std::string traceName("nRdy");
+ traceName += std::to_string(trackId);
+ ATRACE_INT(traceName.c_str(), framesReady);
+ }
+ if ((framesReady >= minFrames) && track->isReady() && !track->isPaused() &&
!track->isStopping_2() && !track->isStopped())
{
- ALOGVV("track(%d) s=%08x [OK]", track->id(), cblk->mServer);
+ ALOGVV("track(%d) s=%08x [OK]", trackId, cblk->mServer);
if (track->mFillingUpStatus == Track::FS_FILLED) {
track->mFillingUpStatus = Track::FS_ACTIVE;
@@ -5724,7 +5908,7 @@
int64_t framesWritten = mBytesWritten / mFrameSize;
if (mStandby || !last ||
track->presentationComplete(framesWritten, audioHALFrames) ||
- track->isPaused()) {
+ track->isPaused() || mHwPaused) {
if (track->isStopping_2()) {
track->mState = TrackBase::STOPPED;
}
@@ -5738,7 +5922,7 @@
// fill a buffer, then remove it from active list.
// Only consider last track started for mixer state control
if (--(track->mRetryCount) <= 0) {
- ALOGV("BUFFER TIMEOUT: remove track(%d) from active list", track->id());
+ ALOGV("BUFFER TIMEOUT: remove track(%d) from active list", trackId);
tracksToRemove->add(track);
// indicate to client process that the track was disabled because of underrun;
// it will then automatically call start() when data is available
@@ -5746,7 +5930,7 @@
} else if (last) {
ALOGW("pause because of UNDERRUN, framesReady = %zu,"
"minFrames = %u, mFormat = %#x",
- track->framesReady(), minFrames, mFormat);
+ framesReady, minFrames, mFormat);
mixerStatus = MIXER_TRACKS_ENABLED;
if (mHwSupportsPause && !mHwPaused && !mStandby) {
doHwPause = true;
@@ -5885,16 +6069,7 @@
AudioParameter param = AudioParameter(keyValuePair);
int value;
if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
- // forward device change to effects that have requested to be
- // aware of attached audio device.
- if (value != AUDIO_DEVICE_NONE) {
- a2dpDeviceChanged =
- (mOutDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != (value & AUDIO_DEVICE_OUT_ALL_A2DP);
- mOutDevice = value;
- for (size_t i = 0; i < mEffectChains.size(); i++) {
- mEffectChains[i]->setDevice_l(mOutDevice);
- }
- }
+ LOG_FATAL("Should not set routing device in DirectOutputThread");
}
if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
// do not accept frame count changes if tracks are open as the track buffer
@@ -5978,6 +6153,7 @@
mHwPaused = false;
mFlushPending = false;
mTimestampVerifier.discontinuity(); // DIRECT and OFFLOADED flush resets frame count.
+ mTimestamp.clear();
}
int64_t AudioFlinger::DirectOutputThread::computeWaitTimeNs_l() const {
@@ -6106,8 +6282,8 @@
// ----------------------------------------------------------------------------
AudioFlinger::OffloadThread::OffloadThread(const sp<AudioFlinger>& audioFlinger,
- AudioStreamOut* output, audio_io_handle_t id, uint32_t device, bool systemReady)
- : DirectOutputThread(audioFlinger, output, id, device, OFFLOAD, systemReady),
+ AudioStreamOut* output, audio_io_handle_t id, bool systemReady)
+ : DirectOutputThread(audioFlinger, output, id, OFFLOAD, systemReady),
mPausedWriteLength(0), mPausedBytesRemaining(0), mKeepWakeLock(true),
mOffloadUnderrunPosition(~0LL)
{
@@ -6354,7 +6530,9 @@
}
}
// compute volume for this track
- processVolume_l(track, last);
+ if (track->isReady()) { // check ready to prevent premature start.
+ processVolume_l(track, last);
+ }
}
// make sure the pause/flush/resume sequence is executed in the right order.
@@ -6430,7 +6608,7 @@
AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger,
AudioFlinger::MixerThread* mainThread, audio_io_handle_t id, bool systemReady)
- : MixerThread(audioFlinger, mainThread->getOutput(), id, mainThread->outDevice(),
+ : MixerThread(audioFlinger, mainThread->getOutput(), id,
systemReady, DUPLICATING),
mWaitTimeMs(UINT_MAX)
{
@@ -6662,12 +6840,11 @@
AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger,
AudioStreamIn *input,
audio_io_handle_t id,
- audio_devices_t outDevice,
- audio_devices_t inDevice,
bool systemReady
) :
- ThreadBase(audioFlinger, id, outDevice, inDevice, RECORD, systemReady),
+ ThreadBase(audioFlinger, id, RECORD, systemReady),
mInput(input),
+ mSource(mInput),
mActiveTracks(&this->mLocalLog),
mRsmpInBuffer(NULL),
// mRsmpInFrames, mRsmpInFramesP2, and mRsmpInFramesOA are set by readInputParameters_l()
@@ -6697,8 +6874,9 @@
// TODO: We may also match on address as well as device type for
// AUDIO_DEVICE_IN_BUS, AUDIO_DEVICE_IN_BLUETOOTH_A2DP, AUDIO_DEVICE_IN_REMOTE_SUBMIX
- mTimestampCorrectedDevices = (audio_devices_t)property_get_int64(
- "audio.timestamp.corrected_input_devices",
+ // TODO: This property should be ensure that only contains one single device type.
+ mTimestampCorrectedDevice = (audio_devices_t)property_get_int64(
+ "audio.timestamp.corrected_input_device",
(int64_t)(mIsMsdDevice ? AUDIO_DEVICE_IN_BUS // turn on by default for MSD
: AUDIO_DEVICE_NONE));
@@ -6745,7 +6923,7 @@
sp<IMemory> pipeMemory;
if ((roHeap == 0) ||
(pipeMemory = roHeap->allocate(pipeSize)) == 0 ||
- (pipeBuffer = pipeMemory->pointer()) == nullptr) {
+ (pipeBuffer = pipeMemory->unsecurePointer()) == nullptr) {
ALOGE("not enough memory for pipe buffer size=%zu; "
"roHeap=%p, pipeMemory=%p, pipeBuffer=%p; roHeapSize: %lld",
pipeSize, roHeap.get(), pipeMemory.get(), pipeBuffer,
@@ -7120,7 +7298,7 @@
} else {
ATRACE_BEGIN("read");
size_t bytesRead;
- status_t result = mInput->stream->read(
+ status_t result = mSource->read(
(uint8_t*)mRsmpInBuffer + rear * mFrameSize, mBufferSize, &bytesRead);
ATRACE_END();
if (result < 0) {
@@ -7142,7 +7320,7 @@
int64_t position, time;
if (mStandby) {
mTimestampVerifier.discontinuity();
- } else if (mInput->stream->getCapturePosition(&position, &time) == NO_ERROR
+ } else if (mSource->getCapturePosition(&position, &time) == NO_ERROR
&& time > mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL]) {
mTimestampVerifier.add(position, time, mSampleRate);
@@ -7423,7 +7601,7 @@
sq->end(false /*didModify*/);
}
}
- status_t result = mInput->stream->standby();
+ status_t result = mSource->standby();
ALOGE_IF(result != OK, "Error when putting input stream into standby: %d", result);
// If going into standby, flush the pipe source.
@@ -7923,12 +8101,12 @@
write(fd, result.string(), result.size());
}
-void AudioFlinger::RecordThread::setRecordSilenced(uid_t uid, bool silenced)
+void AudioFlinger::RecordThread::setRecordSilenced(audio_port_handle_t portId, bool silenced)
{
Mutex::Autolock _l(mLock);
for (size_t i = 0; i < mTracks.size() ; i++) {
sp<RecordTrack> track = mTracks[i];
- if (track != 0 && track->uid() == uid) {
+ if (track != 0 && track->portId() == portId) {
track->setSilenced(silenced);
}
}
@@ -8042,7 +8220,7 @@
{
// disable AEC and NS if the device is a BT SCO headset supporting those
// pre processings
- bool suspend = audio_is_bluetooth_sco_device(mInDevice) &&
+ bool suspend = audio_is_bluetooth_sco_device(inDeviceType()) &&
mAudioFlinger->btNrecIsOff();
if (mBtNrecSuspended.exchange(suspend) != suspend) {
for (size_t i = 0; i < mEffectChains.size(); i++) {
@@ -8107,34 +8285,11 @@
}
}
if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
- // forward device change to effects that have requested to be
- // aware of attached audio device.
- for (size_t i = 0; i < mEffectChains.size(); i++) {
- mEffectChains[i]->setDevice_l(value);
- }
-
- // store input device and output device but do not forward output device to audio HAL.
- // Note that status is ignored by the caller for output device
- // (see AudioFlinger::setParameters()
- if (audio_is_output_devices(value)) {
- mOutDevice = value;
- status = BAD_VALUE;
- } else {
- mInDevice = value;
- if (value != AUDIO_DEVICE_NONE) {
- mPrevInDevice = value;
- }
- checkBtNrec_l();
- }
+ LOG_FATAL("Should not set routing device in RecordThread");
}
if (param.getInt(String8(AudioParameter::keyInputSource), value) == NO_ERROR &&
mAudioSource != (audio_source_t)value) {
- // forward device change to effects that have requested to be
- // aware of attached audio device.
- for (size_t i = 0; i < mEffectChains.size(); i++) {
- mEffectChains[i]->setAudioSource_l((audio_source_t)value);
- }
- mAudioSource = (audio_source_t)value;
+ LOG_FATAL("Should not set audio source in RecordThread");
}
if (status == NO_ERROR) {
@@ -8336,11 +8491,11 @@
status_t status = NO_ERROR;
// store new device and send to effects
- mInDevice = patch->sources[0].ext.device.type;
+ mInDeviceTypeAddr.mType = patch->sources[0].ext.device.type;
+ mInDeviceTypeAddr.mAddress = patch->sources[0].ext.device.address;
audio_port_handle_t deviceId = patch->sources[0].id;
- mPatch = *patch;
for (size_t i = 0; i < mEffectChains.size(); i++) {
- mEffectChains[i]->setDevice_l(mInDevice);
+ mEffectChains[i]->setInputDevice_l(inDeviceTypeAddr());
}
checkBtNrec_l();
@@ -8379,12 +8534,17 @@
*handle = AUDIO_PATCH_HANDLE_NONE;
}
- if ((mInDevice != mPrevInDevice) || (mDeviceId != deviceId)) {
+ if ((mPatch.num_sources == 0) || (mPatch.sources[0].id != deviceId)) {
sendIoConfigEvent_l(AUDIO_INPUT_CONFIG_CHANGED);
- mPrevInDevice = mInDevice;
- mDeviceId = deviceId;
+ mPatch = *patch;
}
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATEAUDIOPATCH)
+ .set(AMEDIAMETRICS_PROP_INPUTDEVICES, patchSourcesToString(patch).c_str())
+ .set(AMEDIAMETRICS_PROP_SOURCE, toString(mAudioSource).c_str())
+ .record();
+
return status;
}
@@ -8392,7 +8552,8 @@
{
status_t status = NO_ERROR;
- mInDevice = AUDIO_DEVICE_NONE;
+ mPatch = audio_patch{};
+ mInDeviceTypeAddr.reset();
if (mInput->audioHwDev->supportsAudioPatches()) {
sp<DeviceHalInterface> hwDevice = mInput->audioHwDev->hwDevice();
@@ -8405,15 +8566,30 @@
return status;
}
+void AudioFlinger::RecordThread::updateOutDevices(const DeviceDescriptorBaseVector& outDevices)
+{
+ mOutDevices = outDevices;
+ mOutDeviceTypeAddrs = deviceTypeAddrsFromDescriptors(mOutDevices);
+ for (size_t i = 0; i < mEffectChains.size(); i++) {
+ mEffectChains[i]->setDevices_l(outDeviceTypeAddrs());
+ }
+}
+
void AudioFlinger::RecordThread::addPatchTrack(const sp<PatchRecord>& record)
{
Mutex::Autolock _l(mLock);
mTracks.add(record);
+ if (record->getSource()) {
+ mSource = record->getSource();
+ }
}
void AudioFlinger::RecordThread::deletePatchTrack(const sp<PatchRecord>& record)
{
Mutex::Autolock _l(mLock);
+ if (mSource == record->getSource()) {
+ mSource = mInput;
+ }
destroyTrack_l(record);
}
@@ -8475,9 +8651,8 @@
AudioFlinger::MmapThread::MmapThread(
const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
- AudioHwDevice *hwDev, sp<StreamHalInterface> stream,
- audio_devices_t outDevice, audio_devices_t inDevice, bool systemReady)
- : ThreadBase(audioFlinger, id, outDevice, inDevice, MMAP, systemReady),
+ AudioHwDevice *hwDev, sp<StreamHalInterface> stream, bool systemReady)
+ : ThreadBase(audioFlinger, id, MMAP, systemReady),
mSessionId(AUDIO_SESSION_NONE),
mPortId(AUDIO_PORT_HANDLE_NONE),
mHalStream(stream), mHalDevice(hwDev->hwDevice()), mAudioHwDev(hwDev),
@@ -8598,6 +8773,7 @@
&stream,
client.clientPid,
client.clientUid,
+ client.packageName,
&config,
flags,
&deviceId,
@@ -8843,26 +9019,7 @@
int value;
bool sendToHal = true;
if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
- audio_devices_t device = (audio_devices_t)value;
- // forward device change to effects that have requested to be
- // aware of attached audio device.
- if (device != AUDIO_DEVICE_NONE) {
- for (size_t i = 0; i < mEffectChains.size(); i++) {
- mEffectChains[i]->setDevice_l(device);
- }
- }
- if (audio_is_output_devices(device)) {
- mOutDevice = device;
- if (!isOutput()) {
- sendToHal = false;
- }
- } else {
- mInDevice = device;
- if (device != AUDIO_DEVICE_NONE) {
- mPrevInDevice = value;
- }
- // TODO: implement and call checkBtNrec_l();
- }
+ LOG_FATAL("Should not happen set routing device in MmapThread");
}
if (sendToHal) {
status = mHalStream->setParameters(keyValuePair);
@@ -8921,24 +9078,39 @@
// store new device and send to effects
audio_devices_t type = AUDIO_DEVICE_NONE;
audio_port_handle_t deviceId;
+ AudioDeviceTypeAddrVector sinkDeviceTypeAddrs;
+ AudioDeviceTypeAddr sourceDeviceTypeAddr;
+ uint32_t numDevices = 0;
if (isOutput()) {
for (unsigned int i = 0; i < patch->num_sinks; i++) {
+ LOG_ALWAYS_FATAL_IF(popcount(patch->sinks[i].ext.device.type) > 1
+ && !mAudioHwDev->supportsAudioPatches(),
+ "Enumerated device type(%#x) must not be used "
+ "as it does not support audio patches",
+ patch->sinks[i].ext.device.type);
type |= patch->sinks[i].ext.device.type;
+ sinkDeviceTypeAddrs.push_back(AudioDeviceTypeAddr(patch->sinks[i].ext.device.type,
+ patch->sinks[i].ext.device.address));
}
deviceId = patch->sinks[0].id;
+ numDevices = mPatch.num_sinks;
} else {
type = patch->sources[0].ext.device.type;
deviceId = patch->sources[0].id;
+ numDevices = mPatch.num_sources;
+ sourceDeviceTypeAddr.mType = patch->sources[0].ext.device.type;
+ sourceDeviceTypeAddr.mAddress = patch->sources[0].ext.device.address;
}
for (size_t i = 0; i < mEffectChains.size(); i++) {
- mEffectChains[i]->setDevice_l(type);
+ if (isOutput()) {
+ mEffectChains[i]->setDevices_l(sinkDeviceTypeAddrs);
+ } else {
+ mEffectChains[i]->setInputDevice_l(sourceDeviceTypeAddr);
+ }
}
- if (isOutput()) {
- mOutDevice = type;
- } else {
- mInDevice = type;
+ if (!isOutput()) {
// store new source and send to effects
if (mAudioSource != patch->sinks[0].ext.mix.usecase.source) {
mAudioSource = patch->sinks[0].ext.mix.usecase.source;
@@ -8975,26 +9147,21 @@
*handle = AUDIO_PATCH_HANDLE_NONE;
}
- if (isOutput() && (mPrevOutDevice != mOutDevice || mDeviceId != deviceId)) {
- mPrevOutDevice = type;
- sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
+ if (numDevices == 0 || mDeviceId != deviceId) {
+ if (isOutput()) {
+ sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
+ mOutDeviceTypeAddrs = sinkDeviceTypeAddrs;
+ } else {
+ sendIoConfigEvent_l(AUDIO_INPUT_CONFIG_CHANGED);
+ mInDeviceTypeAddr = sourceDeviceTypeAddr;
+ }
sp<MmapStreamCallback> callback = mCallback.promote();
if (mDeviceId != deviceId && callback != 0) {
mLock.unlock();
callback->onRoutingChanged(deviceId);
mLock.lock();
}
- mDeviceId = deviceId;
- }
- if (!isOutput() && (mPrevInDevice != mInDevice || mDeviceId != deviceId)) {
- mPrevInDevice = type;
- sendIoConfigEvent_l(AUDIO_INPUT_CONFIG_CHANGED);
- sp<MmapStreamCallback> callback = mCallback.promote();
- if (mDeviceId != deviceId && callback != 0) {
- mLock.unlock();
- callback->onRoutingChanged(deviceId);
- mLock.lock();
- }
+ mPatch = *patch;
mDeviceId = deviceId;
}
return status;
@@ -9004,7 +9171,9 @@
{
status_t status = NO_ERROR;
- mInDevice = AUDIO_DEVICE_NONE;
+ mPatch = audio_patch{};
+ mOutDeviceTypeAddrs.clear();
+ mInDeviceTypeAddr.reset();
bool supportsAudioPatches = mHalDevice->supportsAudioPatches(&supportsAudioPatches) == OK ?
supportsAudioPatches : false;
@@ -9105,8 +9274,8 @@
const effect_descriptor_t *desc, audio_session_t sessionId)
{
// No global effect sessions on mmap threads
- if (sessionId == AUDIO_SESSION_OUTPUT_MIX || sessionId == AUDIO_SESSION_OUTPUT_STAGE) {
- ALOGW("checkEffectCompatibility_l(): global effect %s on record thread %s",
+ if (audio_is_global_session(sessionId)) {
+ ALOGW("checkEffectCompatibility_l(): global effect %s on MMAP thread %s",
desc->name, mThreadName);
return BAD_VALUE;
}
@@ -9128,7 +9297,6 @@
}
return NO_ERROR;
-
}
void AudioFlinger::MmapThread::checkInvalidTracks_l()
@@ -9180,9 +9348,8 @@
AudioFlinger::MmapPlaybackThread::MmapPlaybackThread(
const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
- AudioHwDevice *hwDev, AudioStreamOut *output,
- audio_devices_t outDevice, audio_devices_t inDevice, bool systemReady)
- : MmapThread(audioFlinger, id, hwDev, output->stream, outDevice, inDevice, systemReady),
+ AudioHwDevice *hwDev, AudioStreamOut *output, bool systemReady)
+ : MmapThread(audioFlinger, id, hwDev, output->stream, systemReady),
mStreamType(AUDIO_STREAM_MUSIC),
mStreamVolume(1.0),
mStreamMute(false),
@@ -9392,9 +9559,8 @@
AudioFlinger::MmapCaptureThread::MmapCaptureThread(
const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
- AudioHwDevice *hwDev, AudioStreamIn *input,
- audio_devices_t outDevice, audio_devices_t inDevice, bool systemReady)
- : MmapThread(audioFlinger, id, hwDev, input->stream, outDevice, inDevice, systemReady),
+ AudioHwDevice *hwDev, AudioStreamIn *input, bool systemReady)
+ : MmapThread(audioFlinger, id, hwDev, input->stream, systemReady),
mInput(input)
{
snprintf(mThreadName, kThreadNameLength, "AudioMmapIn_%X", id);
@@ -9466,11 +9632,11 @@
mInput->stream->updateSinkMetadata(metadata);
}
-void AudioFlinger::MmapCaptureThread::setRecordSilenced(uid_t uid, bool silenced)
+void AudioFlinger::MmapCaptureThread::setRecordSilenced(audio_port_handle_t portId, bool silenced)
{
Mutex::Autolock _l(mLock);
for (size_t i = 0; i < mActiveTracks.size() ; i++) {
- if (mActiveTracks[i]->uid() == uid) {
+ if (mActiveTracks[i]->portId() == portId) {
mActiveTracks[i]->setSilenced_l(silenced);
broadcast_l();
}
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 87bebf3..8149e95 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -37,8 +37,7 @@
static const char *threadTypeToString(type_t type);
ThreadBase(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
- audio_devices_t outDevice, audio_devices_t inDevice, type_t type,
- bool systemReady);
+ type_t type, bool systemReady);
virtual ~ThreadBase();
virtual status_t readyToRun();
@@ -52,6 +51,7 @@
CFG_EVENT_SET_PARAMETER,
CFG_EVENT_CREATE_AUDIO_PATCH,
CFG_EVENT_RELEASE_AUDIO_PATCH,
+ CFG_EVENT_UPDATE_OUT_DEVICE,
};
class ConfigEventData: public RefBase {
@@ -219,6 +219,28 @@
virtual ~ReleaseAudioPatchConfigEvent() {}
};
+ class UpdateOutDevicesConfigEventData : public ConfigEventData {
+ public:
+ explicit UpdateOutDevicesConfigEventData(const DeviceDescriptorBaseVector& outDevices) :
+ mOutDevices(outDevices) {}
+
+ virtual void dump(char *buffer, size_t size) {
+ snprintf(buffer, size, "Devices: %s", android::toString(mOutDevices).c_str());
+ }
+
+ DeviceDescriptorBaseVector mOutDevices;
+ };
+
+ class UpdateOutDevicesConfigEvent : public ConfigEvent {
+ public:
+ explicit UpdateOutDevicesConfigEvent(const DeviceDescriptorBaseVector& outDevices) :
+ ConfigEvent(CFG_EVENT_UPDATE_OUT_DEVICE) {
+ mData = new UpdateOutDevicesConfigEventData(outDevices);
+ }
+
+ virtual ~UpdateOutDevicesConfigEvent();
+ };
+
class PMDeathRecipient : public IBinder::DeathRecipient {
public:
explicit PMDeathRecipient(const wp<ThreadBase>& thread) : mThread(thread) {}
@@ -249,6 +271,8 @@
// Called by AudioFlinger::frameCount(audio_io_handle_t output) and effects,
// and returns the [normal mix] buffer's frame count.
virtual size_t frameCount() const = 0;
+ virtual uint32_t latency_l() const { return 0; }
+ virtual void setVolumeForOutput_l(float left __unused, float right __unused) const {}
// Return's the HAL's frame count i.e. fast mixer buffer size.
size_t frameCountHAL() const { return mFrameCount; }
@@ -278,19 +302,33 @@
status_t sendCreateAudioPatchConfigEvent(const struct audio_patch *patch,
audio_patch_handle_t *handle);
status_t sendReleaseAudioPatchConfigEvent(audio_patch_handle_t handle);
+ status_t sendUpdateOutDeviceConfigEvent(
+ const DeviceDescriptorBaseVector& outDevices);
void processConfigEvents_l();
virtual void cacheParameters_l() = 0;
virtual status_t createAudioPatch_l(const struct audio_patch *patch,
audio_patch_handle_t *handle) = 0;
virtual status_t releaseAudioPatch_l(const audio_patch_handle_t handle) = 0;
+ virtual void updateOutDevices(const DeviceDescriptorBaseVector& outDevices);
virtual void toAudioPortConfig(struct audio_port_config *config) = 0;
// see note at declaration of mStandby, mOutDevice and mInDevice
bool standby() const { return mStandby; }
- audio_devices_t outDevice() const { return mOutDevice; }
- audio_devices_t inDevice() const { return mInDevice; }
- audio_devices_t getDevice() const { return isOutput() ? mOutDevice : mInDevice; }
+ const DeviceTypeSet outDeviceTypes() const {
+ return getAudioDeviceTypes(mOutDeviceTypeAddrs);
+ }
+ audio_devices_t inDeviceType() const { return mInDeviceTypeAddr.mType; }
+ DeviceTypeSet getDeviceTypes() const {
+ return isOutput() ? outDeviceTypes() : DeviceTypeSet({inDeviceType()});
+ }
+
+ const AudioDeviceTypeAddrVector& outDeviceTypeAddrs() const {
+ return mOutDeviceTypeAddrs;
+ }
+ const AudioDeviceTypeAddr& inDeviceTypeAddr() const {
+ return mInDeviceTypeAddr;
+ }
virtual bool isOutput() const = 0;
@@ -304,7 +342,8 @@
effect_descriptor_t *desc,
int *enabled,
status_t *status /*non-NULL*/,
- bool pinned);
+ bool pinned,
+ bool probe);
// return values for hasAudioSession (bit field)
enum effect_state {
@@ -388,14 +427,9 @@
// check if some effects must be suspended/restored when an effect is enabled
// or disabled
- void checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
- bool enabled,
- audio_session_t sessionId =
- AUDIO_SESSION_OUTPUT_MIX);
- void checkSuspendOnEffectEnabled_l(const sp<EffectModule>& effect,
- bool enabled,
- audio_session_t sessionId =
- AUDIO_SESSION_OUTPUT_MIX);
+ void checkSuspendOnEffectEnabled(bool enabled,
+ audio_session_t sessionId,
+ bool threadLocked);
virtual status_t setSyncEvent(const sp<SyncEvent>& event) = 0;
virtual bool isValidSyncEvent(const sp<SyncEvent>& event) const = 0;
@@ -429,6 +463,9 @@
mutable Mutex mLock;
+ void onEffectEnable(const sp<EffectModule>& effect);
+ void onEffectDisable();
+
protected:
// entry describing an effect being suspended in mSuspendedSessions keyed vector
@@ -487,6 +524,7 @@
Condition mWaitWorkCV;
const sp<AudioFlinger> mAudioFlinger;
+ const std::string mMetricsId;
// updated by PlaybackThread::readOutputParameters_l() or
// RecordThread::readInputParameters_l()
@@ -502,26 +540,21 @@
// HAL format if Fastmixer is used.
audio_format_t mHALFormat;
size_t mBufferSize; // HAL buffer size for read() or write()
-
+ AudioDeviceTypeAddrVector mOutDeviceTypeAddrs; // output device types and addresses
+ AudioDeviceTypeAddr mInDeviceTypeAddr; // input device type and address
Vector< sp<ConfigEvent> > mConfigEvents;
Vector< sp<ConfigEvent> > mPendingConfigEvents; // events awaiting system ready
// These fields are written and read by thread itself without lock or barrier,
- // and read by other threads without lock or barrier via standby(), outDevice()
- // and inDevice().
+ // and read by other threads without lock or barrier via standby(), outDeviceTypes()
+ // and inDeviceType().
// Because of the absence of a lock or barrier, any other thread that reads
// these fields must use the information in isolation, or be prepared to deal
// with possibility that it might be inconsistent with other information.
bool mStandby; // Whether thread is currently in standby.
- audio_devices_t mOutDevice; // output device
- audio_devices_t mInDevice; // input device
- audio_devices_t mPrevOutDevice; // previous output device
- audio_devices_t mPrevInDevice; // previous input device
+
struct audio_patch mPatch;
- /**
- * @brief mDeviceId current device port unique identifier
- */
- audio_port_handle_t mDeviceId = AUDIO_PORT_HANDLE_NONE;
+
audio_source_t mAudioSource;
const audio_io_handle_t mId;
@@ -544,7 +577,8 @@
ExtendedTimestamp mTimestamp;
TimestampVerifier< // For timestamp statistics.
int64_t /* frame count */, int64_t /* time ns */> mTimestampVerifier;
- audio_devices_t mTimestampCorrectedDevices = AUDIO_DEVICE_NONE;
+ // Timestamp corrected device should be a single device.
+ audio_devices_t mTimestampCorrectedDevice = AUDIO_DEVICE_NONE;
// ThreadLoop statistics per iteration.
int64_t mLastIoBeginNs = -1;
@@ -687,7 +721,7 @@
// --- PlaybackThread ---
class PlaybackThread : public ThreadBase, public StreamOutHalInterfaceCallback,
- public VolumeInterface {
+ public VolumeInterface, public StreamOutHalInterfaceEventCallback {
public:
#include "PlaybackTracks.h"
@@ -719,7 +753,7 @@
static const nsecs_t kMaxNextBufferDelayNs = 100000000;
PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
- audio_io_handle_t id, audio_devices_t device, type_t type, bool systemReady);
+ audio_io_handle_t id, type_t type, bool systemReady);
virtual ~PlaybackThread();
// Thread virtuals
@@ -763,6 +797,10 @@
virtual void onAddNewTrack_l();
void onAsyncError(); // error reported by AsyncCallbackThread
+ // StreamHalInterfaceCodecFormatCallback implementation
+ void onCodecFormatChanged(
+ const std::basic_string<uint8_t>& metadataBs) override;
+
// ThreadBase virtuals
virtual void preExit();
@@ -782,7 +820,7 @@
// return estimated latency in milliseconds, as reported by HAL
uint32_t latency() const;
// same, but lock must already be held
- uint32_t latency_l() const;
+ uint32_t latency_l() const override;
// VolumeInterface
virtual void setMasterVolume(float value);
@@ -792,7 +830,7 @@
virtual void setStreamMute(audio_stream_type_t stream, bool muted);
virtual float streamVolume(audio_stream_type_t stream) const;
- void setVolumeForOutput_l(float left, float right) const;
+ void setVolumeForOutput_l(float left, float right) const override;
sp<Track> createTrack_l(
const sp<AudioFlinger::Client>& client,
@@ -812,7 +850,8 @@
pid_t tid,
uid_t uid,
status_t *status /*non-NULL*/,
- audio_port_handle_t portId);
+ audio_port_handle_t portId,
+ const sp<media::IAudioTrackCallback>& callback);
AudioStreamOut* getOutput() const;
AudioStreamOut* clearOutput();
@@ -886,10 +925,10 @@
}
bool isTimestampCorrectionEnabled() const override {
- const audio_devices_t device =
- mOutDevice & mTimestampCorrectedDevices;
- return audio_is_output_devices(device) && popcount(device) > 0;
+ return audio_is_output_devices(mTimestampCorrectedDevice)
+ && outDeviceTypes().count(mTimestampCorrectedDevice) != 0;
}
+
protected:
// updated by readOutputParameters_l()
size_t mNormalFrameCount; // normal mixer and effects
@@ -1135,6 +1174,10 @@
uint32_t mDrainSequence;
sp<AsyncCallbackThread> mCallbackThread;
+ Mutex mAudioTrackCbLock;
+ // Record of IAudioTrackCallback
+ std::set<sp<media::IAudioTrackCallback>> mAudioTrackCallbacks;
+
private:
// The HAL output sink is treated as non-blocking, but current implementation is blocking
sp<NBAIO_Sink> mOutputSink;
@@ -1171,7 +1214,6 @@
MixerThread(const sp<AudioFlinger>& audioFlinger,
AudioStreamOut* output,
audio_io_handle_t id,
- audio_devices_t device,
bool systemReady,
type_t type = MIXER);
virtual ~MixerThread();
@@ -1269,8 +1311,8 @@
public:
DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
- audio_io_handle_t id, audio_devices_t device, bool systemReady)
- : DirectOutputThread(audioFlinger, output, id, device, DIRECT, systemReady) { }
+ audio_io_handle_t id, bool systemReady)
+ : DirectOutputThread(audioFlinger, output, id, DIRECT, systemReady) { }
virtual ~DirectOutputThread();
@@ -1305,8 +1347,7 @@
bool mVolumeShaperActive = false;
DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
- audio_io_handle_t id, audio_devices_t device, ThreadBase::type_t type,
- bool systemReady);
+ audio_io_handle_t id, ThreadBase::type_t type, bool systemReady);
void processVolume_l(Track *track, bool lastTrack);
// prepareTracks_l() tells threadLoop_mix() the name of the single active track
@@ -1345,7 +1386,7 @@
public:
OffloadThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
- audio_io_handle_t id, uint32_t device, bool systemReady);
+ audio_io_handle_t id, bool systemReady);
virtual ~OffloadThread() {};
virtual void flushHw_l();
@@ -1516,8 +1557,6 @@
RecordThread(const sp<AudioFlinger>& audioFlinger,
AudioStreamIn *input,
audio_io_handle_t id,
- audio_devices_t outDevice,
- audio_devices_t inDevice,
bool systemReady
);
virtual ~RecordThread();
@@ -1577,6 +1616,7 @@
virtual status_t createAudioPatch_l(const struct audio_patch *patch,
audio_patch_handle_t *handle);
virtual status_t releaseAudioPatch_l(const audio_patch_handle_t handle);
+ void updateOutDevices(const DeviceDescriptorBaseVector& outDevices) override;
void addPatchTrack(const sp<PatchRecord>& record);
void deletePatchTrack(const sp<PatchRecord>& record);
@@ -1616,7 +1656,7 @@
void checkBtNrec();
// Sets the UID records silence
- void setRecordSilenced(uid_t uid, bool silenced);
+ void setRecordSilenced(audio_port_handle_t portId, bool silenced);
status_t getActiveMicrophones(std::vector<media::MicrophoneInfo>* activeMicrophones);
@@ -1629,8 +1669,8 @@
bool isTimestampCorrectionEnabled() const override {
// checks popcount for exactly one device.
- return audio_is_input_device(
- mInDevice & mTimestampCorrectedDevices);
+ return audio_is_input_device(mTimestampCorrectedDevice)
+ && inDeviceType() == mTimestampCorrectedDevice;
}
protected:
@@ -1647,6 +1687,7 @@
void checkBtNrec_l();
AudioStreamIn *mInput;
+ Source *mSource;
SortedVector < sp<RecordTrack> > mTracks;
// mActiveTracks has dual roles: it indicates the current active track(s), and
// is used together with mStartStopCond to indicate start()/stop() progress
@@ -1708,6 +1749,8 @@
std::atomic_bool mBtNrecSuspended;
int64_t mFramesRead = 0; // continuous running counter.
+
+ DeviceDescriptorBaseVector mOutDevices;
};
class MmapThread : public ThreadBase
@@ -1717,8 +1760,7 @@
#include "MmapTracks.h"
MmapThread(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
- AudioHwDevice *hwDev, sp<StreamHalInterface> stream,
- audio_devices_t outDevice, audio_devices_t inDevice, bool systemReady);
+ AudioHwDevice *hwDev, sp<StreamHalInterface> stream, bool systemReady);
virtual ~MmapThread();
virtual void configure(const audio_attributes_t *attr,
@@ -1785,12 +1827,18 @@
virtual void invalidateTracks(audio_stream_type_t streamType __unused) {}
// Sets the UID records silence
- virtual void setRecordSilenced(uid_t uid __unused, bool silenced __unused) {}
+ virtual void setRecordSilenced(audio_port_handle_t portId __unused,
+ bool silenced __unused) {}
protected:
void dumpInternals_l(int fd, const Vector<String16>& args) override;
void dumpTracks_l(int fd, const Vector<String16>& args) override;
+ /**
+ * @brief mDeviceId current device port unique identifier
+ */
+ audio_port_handle_t mDeviceId = AUDIO_PORT_HANDLE_NONE;
+
audio_attributes_t mAttr;
audio_session_t mSessionId;
audio_port_handle_t mPortId;
@@ -1811,8 +1859,7 @@
public:
MmapPlaybackThread(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
- AudioHwDevice *hwDev, AudioStreamOut *output,
- audio_devices_t outDevice, audio_devices_t inDevice, bool systemReady);
+ AudioHwDevice *hwDev, AudioStreamOut *output, bool systemReady);
virtual ~MmapPlaybackThread() {}
virtual void configure(const audio_attributes_t *attr,
@@ -1861,8 +1908,7 @@
public:
MmapCaptureThread(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
- AudioHwDevice *hwDev, AudioStreamIn *input,
- audio_devices_t outDevice, audio_devices_t inDevice, bool systemReady);
+ AudioHwDevice *hwDev, AudioStreamIn *input, bool systemReady);
virtual ~MmapCaptureThread() {}
AudioStreamIn* clearInput();
@@ -1872,7 +1918,8 @@
void updateMetadata_l() override;
void processVolume_l() override;
- void setRecordSilenced(uid_t uid, bool silenced) override;
+ void setRecordSilenced(audio_port_handle_t portId,
+ bool silenced) override;
virtual void toAudioPortConfig(struct audio_port_config *config);
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 65589e2..e39b944 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -69,7 +69,8 @@
bool isOut,
alloc_type alloc = ALLOC_CBLK,
track_type type = TYPE_DEFAULT,
- audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE);
+ audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE,
+ std::string metricsId = {});
virtual ~TrackBase();
virtual status_t initCheck() const;
@@ -94,7 +95,14 @@
bool isPatchTrack() const { return (mType == TYPE_PATCH); }
bool isExternalTrack() const { return !isOutputTrack() && !isPatchTrack(); }
- virtual void invalidate() { mIsInvalid = true; }
+ virtual void invalidate() {
+ if (mIsInvalid) return;
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT,
+ AMEDIAMETRICS_PROP_EVENT_VALUE_INVALIDATE)
+ .record();
+ mIsInvalid = true;
+ }
bool isInvalid() const { return mIsInvalid; }
void terminate() { mTerminated = true; }
@@ -202,9 +210,51 @@
audio_format_t format() const { return mFormat; }
int id() const { return mId; }
+ const char *getTrackStateAsString() const {
+ if (isTerminated()) {
+ return "TERMINATED";
+ }
+ switch (mState) {
+ case IDLE:
+ return "IDLE";
+ case STOPPING_1: // for Fast and Offload
+ return "STOPPING_1";
+ case STOPPING_2: // for Fast and Offload
+ return "STOPPING_2";
+ case STOPPED:
+ return "STOPPED";
+ case RESUMING:
+ return "RESUMING";
+ case ACTIVE:
+ return "ACTIVE";
+ case PAUSING:
+ return "PAUSING";
+ case PAUSED:
+ return "PAUSED";
+ case FLUSHED:
+ return "FLUSHED";
+ case STARTING_1: // for RecordTrack
+ return "STARTING_1";
+ case STARTING_2: // for RecordTrack
+ return "STARTING_2";
+ default:
+ return "UNKNOWN";
+ }
+ }
+
protected:
DISALLOW_COPY_AND_ASSIGN(TrackBase);
+ void releaseCblk() {
+ if (mCblk != nullptr) {
+ mCblk->~audio_track_cblk_t(); // destroy our shared-structure.
+ if (mClient == 0) {
+ free(mCblk);
+ }
+ mCblk = nullptr;
+ }
+ }
+
// AudioBufferProvider interface
virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) = 0;
virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
@@ -238,7 +288,7 @@
// Upper case characters are final states.
// Lower case characters are transitory.
- const char *getTrackStateString() const {
+ const char *getTrackStateAsCodedString() const {
if (isTerminated()) {
return "T ";
}
@@ -311,6 +361,14 @@
audio_port_handle_t mPortId; // unique ID for this track used by audio policy
bool mIsInvalid; // non-resettable latch, set by invalidate()
+ // It typically takes 5 threadloop mix iterations for latency to stabilize.
+ static inline constexpr int32_t LOG_START_COUNTDOWN = 8;
+ int32_t mLogStartCountdown = 0;
+ int64_t mLogStartTimeNs = 0;
+ int64_t mLogStartFrames = 0;
+
+ const std::string mMetricsId;
+
bool mServerLatencySupported = false;
std::atomic<bool> mServerLatencyFromTrack{}; // latency from track or server timestamp.
std::atomic<double> mServerLatencyMs{}; // last latency pushed from server thread.
@@ -327,6 +385,7 @@
virtual ~PatchProxyBufferProvider() {}
+ virtual bool producesBufferOnDemand() const = 0;
virtual status_t obtainBuffer(Proxy::Buffer* buffer,
const struct timespec *requested = NULL) = 0;
virtual void releaseBuffer(Proxy::Buffer* buffer) = 0;
@@ -349,6 +408,8 @@
mPeerProxy = nullptr;
}
+ bool producesBufferOnDemand() const override { return false; }
+
protected:
const sp<ClientProxy> mProxy;
sp<RefBase> mPeerReferenceHold; // keeps mPeerProxy alive during access.
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 51e57b5..23d8329 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -18,12 +18,14 @@
#define LOG_TAG "AudioFlinger"
//#define LOG_NDEBUG 0
+#define ATRACE_TAG ATRACE_TAG_AUDIO
#include "Configuration.h"
#include <linux/futex.h>
#include <math.h>
#include <sys/syscall.h>
#include <utils/Log.h>
+#include <utils/Trace.h>
#include <private/media/AudioTrackShared.h>
@@ -78,7 +80,8 @@
bool isOut,
alloc_type alloc,
track_type type,
- audio_port_handle_t portId)
+ audio_port_handle_t portId,
+ std::string metricsId)
: RefBase(),
mThread(thread),
mClient(client),
@@ -103,6 +106,7 @@
mThreadIoHandle(thread ? thread->id() : AUDIO_IO_HANDLE_NONE),
mPortId(portId),
mIsInvalid(false),
+ mMetricsId(std::move(metricsId)),
mCreatorPid(creatorPid)
{
const uid_t callingUid = IPCThreadState::self()->getCallingUid();
@@ -148,7 +152,7 @@
if (client != 0) {
mCblkMemory = client->heap()->allocate(size);
if (mCblkMemory == 0 ||
- (mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer())) == NULL) {
+ (mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->unsecurePointer())) == NULL) {
ALOGE("%s(%d): not enough memory for AudioTrack size=%zu", __func__, mId, size);
client->heap()->dump("AudioTrack");
mCblkMemory.clear();
@@ -170,7 +174,7 @@
const sp<MemoryDealer> roHeap(thread->readOnlyHeap());
if (roHeap == 0 ||
(mBufferMemory = roHeap->allocate(bufferSize)) == 0 ||
- (mBuffer = mBufferMemory->pointer()) == NULL) {
+ (mBuffer = mBufferMemory->unsecurePointer()) == NULL) {
ALOGE("%s(%d): not enough memory for read-only buffer size=%zu",
__func__, mId, bufferSize);
if (roHeap != 0) {
@@ -185,7 +189,7 @@
case ALLOC_PIPE:
mBufferMemory = thread->pipeMemory();
// mBuffer is the virtual address as seen from current process (mediaserver),
- // and should normally be coming from mBufferMemory->pointer().
+ // and should normally be coming from mBufferMemory->unsecurePointer().
// However in this case the TrackBase does not reference the buffer directly.
// It should references the buffer via the pipe.
// Therefore, to detect incorrect usage of the buffer, we set mBuffer to NULL.
@@ -237,12 +241,7 @@
{
// delete the proxy before deleting the shared memory it refers to, to avoid dangling reference
mServerProxy.clear();
- if (mCblk != NULL) {
- mCblk->~audio_track_cblk_t(); // destroy our shared-structure.
- if (mClient == 0) {
- free(mCblk);
- }
- }
+ releaseCblk();
mCblkMemory.clear(); // free the shared memory before releasing the heap it belongs to
if (mClient != 0) {
// Client destructor must run with AudioFlinger client mutex locked
@@ -514,11 +513,17 @@
audio_port_handle_t portId,
size_t frameCountToBeReady)
: TrackBase(thread, client, attr, sampleRate, format, channelMask, frameCount,
- (sharedBuffer != 0) ? sharedBuffer->pointer() : buffer,
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
+ (sharedBuffer != 0) ? sharedBuffer->unsecurePointer() : buffer,
(sharedBuffer != 0) ? sharedBuffer->size() : bufferSize,
sessionId, creatorPid, uid, true /*isOut*/,
(type == TYPE_PATCH) ? ( buffer == NULL ? ALLOC_LOCAL : ALLOC_NONE) : ALLOC_CBLK,
- type, portId),
+ type,
+ portId,
+ std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK) + std::to_string(portId)),
mFillingUpStatus(FS_INVALID),
// mRetryCount initialized later when needed
mSharedBuffer(sharedBuffer),
@@ -545,25 +550,27 @@
ALOG_ASSERT(!(client == 0 && sharedBuffer != 0));
ALOGV_IF(sharedBuffer != 0, "%s(%d): sharedBuffer: %p, size: %zu",
- __func__, mId, sharedBuffer->pointer(), sharedBuffer->size());
+ __func__, mId, sharedBuffer->unsecurePointer(), sharedBuffer->size());
if (mCblk == NULL) {
return;
}
+ if (!thread->isTrackAllowed_l(channelMask, format, sessionId, uid)) {
+ ALOGE("%s(%d): no more tracks available", __func__, mId);
+ releaseCblk(); // this makes the track invalid.
+ return;
+ }
+
if (sharedBuffer == 0) {
mAudioTrackServerProxy = new AudioTrackServerProxy(mCblk, mBuffer, frameCount,
mFrameSize, !isExternalTrack(), sampleRate);
} else {
mAudioTrackServerProxy = new StaticAudioTrackServerProxy(mCblk, mBuffer, frameCount,
- mFrameSize);
+ mFrameSize, sampleRate);
}
mServerProxy = mAudioTrackServerProxy;
- if (!thread->isTrackAllowed_l(channelMask, format, sessionId, uid)) {
- ALOGE("%s(%d): no more tracks available", __func__, mId);
- return;
- }
// only allocate a fast track index if we were able to allocate a normal track name
if (flags & AUDIO_OUTPUT_FLAG_FAST) {
// FIXME: Not calling framesReadyIsCalledByMultipleThreads() exposes a potential
@@ -593,6 +600,14 @@
mExternalVibration = new os::ExternalVibration(
mUid, "" /* pkg */, mAttr, mAudioVibrationController);
}
+
+ // Once this item is logged by the server, the client can add properties.
+ mediametrics::LogItem(mMetricsId)
+ .setPid(creatorPid)
+ .setUid(uid)
+ .set(AMEDIAMETRICS_PROP_EVENT,
+ AMEDIAMETRICS_PROP_PREFIX_SERVER AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR)
+ .record();
}
AudioFlinger::PlaybackThread::Track::~Track()
@@ -740,7 +755,7 @@
(mClient == 0) ? getpid() : mClient->pid(),
mSessionId,
mPortId,
- getTrackStateString(),
+ getTrackStateAsCodedString(),
mCblk->mFlags,
mFormat,
@@ -822,16 +837,9 @@
}
for (auto& teePatch : mTeePatches) {
RecordThread::PatchRecord* patchRecord = teePatch.patchRecord.get();
-
- size_t framesWritten = writeFrames(patchRecord, sourceBuffer.i8, frameCount);
- // On buffer wrap, the buffer frame count will be less than requested,
- // when this happens a second buffer needs to be used to write the leftover audio
- size_t framesLeft = frameCount - framesWritten;
- if (framesWritten != 0 && framesLeft != 0) {
- framesWritten +=
- writeFrames(patchRecord, sourceBuffer.i8 + framesWritten * mFrameSize, framesLeft);
- framesLeft = frameCount - framesWritten;
- }
+ const size_t framesWritten = patchRecord->writeFrames(
+ sourceBuffer.i8, frameCount, mFrameSize);
+ const size_t framesLeft = frameCount - framesWritten;
ALOGW_IF(framesLeft != 0, "%s(%d) PatchRecord %d can not provide big enough "
"buffer %zu/%zu, dropping %zu frames", __func__, mId, patchRecord->mId,
framesWritten, frameCount, framesLeft);
@@ -843,26 +851,6 @@
spent.count(), mTeePatches.size());
}
-size_t AudioFlinger::PlaybackThread::Track::writeFrames(AudioBufferProvider* dest,
- const void* src,
- size_t frameCount) {
- AudioBufferProvider::Buffer patchBuffer;
- patchBuffer.frameCount = frameCount;
- auto status = dest->getNextBuffer(&patchBuffer);
- if (status != NO_ERROR) {
- ALOGW("%s PathRecord getNextBuffer failed with error %d: %s",
- __func__, status, strerror(-status));
- return 0;
- }
- ALOG_ASSERT(patchBuffer.frameCount <= frameCount);
- memcpy(patchBuffer.raw, src, patchBuffer.frameCount * mFrameSize);
- auto framesWritten = patchBuffer.frameCount;
- dest->releaseBuffer(&patchBuffer);
- return framesWritten;
-}
-
-// releaseBuffer() is not overridden
-
// ExtendedAudioBufferProvider interface
// framesReady() may return an approximation of the number of frames if called
@@ -990,6 +978,14 @@
}
}
+ // Audio timing metrics are computed a few mix cycles after starting.
+ {
+ mLogStartCountdown = LOG_START_COUNTDOWN;
+ mLogStartTimeNs = systemTime();
+ mLogStartFrames = mAudioTrackServerProxy->getTimestamp()
+ .mPosition[ExtendedTimestamp::LOCATION_SERVER];
+ }
+
if (status == NO_ERROR || status == ALREADY_EXISTS) {
// for streaming tracks, remove the buffer read stop limit.
mAudioTrackServerProxy->start();
@@ -1521,6 +1517,28 @@
mServerLatencyFromTrack.store(useTrackTimestamp);
mServerLatencyMs.store(latencyMs);
+
+ if (mLogStartCountdown > 0) {
+ if (--mLogStartCountdown == 0) {
+ // startup is the difference in times for the current timestamp and our start
+ double startUpMs =
+ (local.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] - mLogStartTimeNs) * 1e-6;
+ // adjust for frames played.
+ startUpMs -= (local.mPosition[ExtendedTimestamp::LOCATION_SERVER] - mLogStartFrames)
+ * 1e3 / mSampleRate;
+ ALOGV("%s: logging localTime:%lld, startTime:%lld"
+ " localPosition:%lld, startPosition:%lld",
+ __func__,
+ (long long)local.mTimeNs[ExtendedTimestamp::LOCATION_SERVER],
+ (long long)mLogStartTimeNs,
+ (long long)local.mPosition[ExtendedTimestamp::LOCATION_SERVER],
+ (long long)mLogStartFrames);
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_LATENCYMS, latencyMs)
+ .set(AMEDIAMETRICS_PROP_STARTUPMS, startUpMs)
+ .record();
+ }
+ }
}
binder::Status AudioFlinger::PlaybackThread::Track::AudioVibrationController::mute(
@@ -1819,6 +1837,15 @@
ALOGV("%s(%d)", __func__, mId);
}
+size_t AudioFlinger::PlaybackThread::PatchTrack::framesReady() const
+{
+ if (mPeerProxy && mPeerProxy->producesBufferOnDemand()) {
+ return std::numeric_limits<size_t>::max();
+ } else {
+ return Track::framesReady();
+ }
+}
+
status_t AudioFlinger::PlaybackThread::PatchTrack::start(AudioSystem::sync_event_t event,
audio_session_t triggerSession)
{
@@ -1837,9 +1864,19 @@
ALOG_ASSERT(mPeerProxy != 0, "%s(%d): called without peer proxy", __func__, mId);
Proxy::Buffer buf;
buf.mFrameCount = buffer->frameCount;
+ if (ATRACE_ENABLED()) {
+ std::string traceName("PTnReq");
+ traceName += std::to_string(id());
+ ATRACE_INT(traceName.c_str(), buf.mFrameCount);
+ }
status_t status = mPeerProxy->obtainBuffer(&buf, &mPeerTimeout);
ALOGV_IF(status != NO_ERROR, "%s(%d): getNextBuffer status %d", __func__, mId, status);
buffer->frameCount = buf.mFrameCount;
+ if (ATRACE_ENABLED()) {
+ std::string traceName("PTnObt");
+ traceName += std::to_string(id());
+ ATRACE_INT(traceName.c_str(), buf.mFrameCount);
+ }
if (buf.mFrameCount == 0) {
return WOULD_BLOCK;
}
@@ -1903,7 +1940,7 @@
// static
sp<AudioFlinger::RecordThread::OpRecordAudioMonitor>
AudioFlinger::RecordThread::OpRecordAudioMonitor::createIfNeeded(
- uid_t uid, const String16& opPackageName)
+ uid_t uid, const audio_attributes_t& attr, const String16& opPackageName)
{
if (isServiceUid(uid)) {
ALOGV("not silencing record for service uid:%d pack:%s",
@@ -1911,6 +1948,13 @@
return nullptr;
}
+ // Capturing from FM TUNER output is not controlled by OP_RECORD_AUDIO
+ // because it does not affect users privacy as does capturing from an actual microphone.
+ if (attr.source == AUDIO_SOURCE_FM_TUNER) {
+ ALOGV("not muting FM TUNER capture for uid %d", uid);
+ return nullptr;
+ }
+
if (opPackageName.size() == 0) {
Vector<String16> packages;
// no package name, happens with SL ES clients
@@ -2069,14 +2113,15 @@
(type == TYPE_DEFAULT) ?
((flags & AUDIO_INPUT_FLAG_FAST) ? ALLOC_PIPE : ALLOC_CBLK) :
((buffer == NULL) ? ALLOC_LOCAL : ALLOC_NONE),
- type, portId),
+ type, portId,
+ std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD) + std::to_string(portId)),
mOverflow(false),
mFramesToDrop(0),
mResamplerBufferProvider(NULL), // initialize in case of early constructor exit
mRecordBufferConverter(NULL),
mFlags(flags),
mSilenced(false),
- mOpRecordAudioMonitor(OpRecordAudioMonitor::createIfNeeded(uid, opPackageName))
+ mOpRecordAudioMonitor(OpRecordAudioMonitor::createIfNeeded(uid, attr, opPackageName))
{
if (mCblk == NULL) {
return;
@@ -2115,6 +2160,13 @@
+ "_" + std::to_string(mId)
+ "_R");
#endif
+
+ // Once this item is logged by the server, the client can add properties.
+ mediametrics::LogItem(mMetricsId)
+ .setPid(creatorPid)
+ .setUid(uid)
+ .set(AMEDIAMETRICS_PROP_EVENT, "server." AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR)
+ .record();
}
AudioFlinger::RecordThread::RecordTrack::~RecordTrack()
@@ -2239,7 +2291,7 @@
(mClient == 0) ? getpid() : mClient->pid(),
mSessionId,
mPortId,
- getTrackStateString(),
+ getTrackStateAsCodedString(),
mCblk->mFlags,
mFormat,
@@ -2400,6 +2452,39 @@
ALOGV("%s(%d)", __func__, mId);
}
+static size_t writeFramesHelper(
+ AudioBufferProvider* dest, const void* src, size_t frameCount, size_t frameSize)
+{
+ AudioBufferProvider::Buffer patchBuffer;
+ patchBuffer.frameCount = frameCount;
+ auto status = dest->getNextBuffer(&patchBuffer);
+ if (status != NO_ERROR) {
+ ALOGW("%s PathRecord getNextBuffer failed with error %d: %s",
+ __func__, status, strerror(-status));
+ return 0;
+ }
+ ALOG_ASSERT(patchBuffer.frameCount <= frameCount);
+ memcpy(patchBuffer.raw, src, patchBuffer.frameCount * frameSize);
+ size_t framesWritten = patchBuffer.frameCount;
+ dest->releaseBuffer(&patchBuffer);
+ return framesWritten;
+}
+
+// static
+size_t AudioFlinger::RecordThread::PatchRecord::writeFrames(
+ AudioBufferProvider* dest, const void* src, size_t frameCount, size_t frameSize)
+{
+ size_t framesWritten = writeFramesHelper(dest, src, frameCount, frameSize);
+ // On buffer wrap, the buffer frame count will be less than requested,
+ // when this happens a second buffer needs to be used to write the leftover audio
+ const size_t framesLeft = frameCount - framesWritten;
+ if (framesWritten != 0 && framesLeft != 0) {
+ framesWritten += writeFramesHelper(dest, (const char*)src + framesWritten * frameSize,
+ framesLeft, frameSize);
+ }
+ return framesWritten;
+}
+
// AudioBufferProvider interface
status_t AudioFlinger::RecordThread::PatchRecord::getNextBuffer(
AudioBufferProvider::Buffer* buffer)
@@ -2411,6 +2496,11 @@
ALOGV_IF(status != NO_ERROR,
"%s(%d): mPeerProxy->obtainBuffer status %d", __func__, mId, status);
buffer->frameCount = buf.mFrameCount;
+ if (ATRACE_ENABLED()) {
+ std::string traceName("PRnObt");
+ traceName += std::to_string(id());
+ ATRACE_INT(traceName.c_str(), buf.mFrameCount);
+ }
if (buf.mFrameCount == 0) {
return WOULD_BLOCK;
}
@@ -2439,6 +2529,180 @@
mProxy->releaseBuffer(buffer);
}
+#undef LOG_TAG
+#define LOG_TAG "AF::PthrPatchRecord"
+
+static std::unique_ptr<void, decltype(free)*> allocAligned(size_t alignment, size_t size)
+{
+ void *ptr = nullptr;
+ (void)posix_memalign(&ptr, alignment, size);
+ return std::unique_ptr<void, decltype(free)*>(ptr, free);
+}
+
+AudioFlinger::RecordThread::PassthruPatchRecord::PassthruPatchRecord(
+ RecordThread *recordThread,
+ uint32_t sampleRate,
+ audio_channel_mask_t channelMask,
+ audio_format_t format,
+ size_t frameCount,
+ audio_input_flags_t flags)
+ : PatchRecord(recordThread, sampleRate, channelMask, format, frameCount,
+ nullptr /*buffer*/, 0 /*bufferSize*/, flags),
+ mPatchRecordAudioBufferProvider(*this),
+ mSinkBuffer(allocAligned(32, mFrameCount * mFrameSize)),
+ mStubBuffer(allocAligned(32, mFrameCount * mFrameSize))
+{
+ memset(mStubBuffer.get(), 0, mFrameCount * mFrameSize);
+}
+
+sp<StreamInHalInterface> AudioFlinger::RecordThread::PassthruPatchRecord::obtainStream(
+ sp<ThreadBase>* thread)
+{
+ *thread = mThread.promote();
+ if (!*thread) return nullptr;
+ RecordThread *recordThread = static_cast<RecordThread*>((*thread).get());
+ Mutex::Autolock _l(recordThread->mLock);
+ return recordThread->mInput ? recordThread->mInput->stream : nullptr;
+}
+
+// PatchProxyBufferProvider methods are called on DirectOutputThread
+status_t AudioFlinger::RecordThread::PassthruPatchRecord::obtainBuffer(
+ Proxy::Buffer* buffer, const struct timespec* timeOut)
+{
+ if (mUnconsumedFrames) {
+ buffer->mFrameCount = std::min(buffer->mFrameCount, mUnconsumedFrames);
+ // mUnconsumedFrames is decreased in releaseBuffer to use actual frame consumption figure.
+ return PatchRecord::obtainBuffer(buffer, timeOut);
+ }
+
+ // Otherwise, execute a read from HAL and write into the buffer.
+ nsecs_t startTimeNs = 0;
+ if (timeOut && (timeOut->tv_sec != 0 || timeOut->tv_nsec != 0) && timeOut->tv_sec != INT_MAX) {
+ // Will need to correct timeOut by elapsed time.
+ startTimeNs = systemTime();
+ }
+ const size_t framesToRead = std::min(buffer->mFrameCount, mFrameCount);
+ buffer->mFrameCount = 0;
+ buffer->mRaw = nullptr;
+ sp<ThreadBase> thread;
+ sp<StreamInHalInterface> stream = obtainStream(&thread);
+ if (!stream) return NO_INIT; // If there is no stream, RecordThread is not reading.
+
+ status_t result = NO_ERROR;
+ size_t bytesRead = 0;
+ {
+ ATRACE_NAME("read");
+ result = stream->read(mSinkBuffer.get(), framesToRead * mFrameSize, &bytesRead);
+ if (result != NO_ERROR) goto stream_error;
+ if (bytesRead == 0) return NO_ERROR;
+ }
+
+ {
+ std::lock_guard<std::mutex> lock(mReadLock);
+ mReadBytes += bytesRead;
+ mReadError = NO_ERROR;
+ }
+ mReadCV.notify_one();
+ // writeFrames handles wraparound and should write all the provided frames.
+ // If it couldn't, there is something wrong with the client/server buffer of the software patch.
+ buffer->mFrameCount = writeFrames(
+ &mPatchRecordAudioBufferProvider,
+ mSinkBuffer.get(), bytesRead / mFrameSize, mFrameSize);
+ ALOGW_IF(buffer->mFrameCount < bytesRead / mFrameSize,
+ "Lost %zu frames obtained from HAL", bytesRead / mFrameSize - buffer->mFrameCount);
+ mUnconsumedFrames = buffer->mFrameCount;
+ struct timespec newTimeOut;
+ if (startTimeNs) {
+ // Correct the timeout by elapsed time.
+ nsecs_t newTimeOutNs = audio_utils_ns_from_timespec(timeOut) - (systemTime() - startTimeNs);
+ if (newTimeOutNs < 0) newTimeOutNs = 0;
+ newTimeOut.tv_sec = newTimeOutNs / NANOS_PER_SECOND;
+ newTimeOut.tv_nsec = newTimeOutNs - newTimeOut.tv_sec * NANOS_PER_SECOND;
+ timeOut = &newTimeOut;
+ }
+ return PatchRecord::obtainBuffer(buffer, timeOut);
+
+stream_error:
+ stream->standby();
+ {
+ std::lock_guard<std::mutex> lock(mReadLock);
+ mReadError = result;
+ }
+ mReadCV.notify_one();
+ return result;
+}
+
+void AudioFlinger::RecordThread::PassthruPatchRecord::releaseBuffer(Proxy::Buffer* buffer)
+{
+ if (buffer->mFrameCount <= mUnconsumedFrames) {
+ mUnconsumedFrames -= buffer->mFrameCount;
+ } else {
+ ALOGW("Write side has consumed more frames than we had: %zu > %zu",
+ buffer->mFrameCount, mUnconsumedFrames);
+ mUnconsumedFrames = 0;
+ }
+ PatchRecord::releaseBuffer(buffer);
+}
+
+// AudioBufferProvider and Source methods are called on RecordThread
+// 'read' emulates actual audio data with 0's. This is OK as 'getNextBuffer'
+// and 'releaseBuffer' are stubbed out and ignore their input.
+// It's not possible to retrieve actual data here w/o blocking 'obtainBuffer'
+// until we copy it.
+status_t AudioFlinger::RecordThread::PassthruPatchRecord::read(
+ void* buffer, size_t bytes, size_t* read)
+{
+ bytes = std::min(bytes, mFrameCount * mFrameSize);
+ {
+ std::unique_lock<std::mutex> lock(mReadLock);
+ mReadCV.wait(lock, [&]{ return mReadError != NO_ERROR || mReadBytes != 0; });
+ if (mReadError != NO_ERROR) {
+ mLastReadFrames = 0;
+ return mReadError;
+ }
+ *read = std::min(bytes, mReadBytes);
+ mReadBytes -= *read;
+ }
+ mLastReadFrames = *read / mFrameSize;
+ memset(buffer, 0, *read);
+ return 0;
+}
+
+status_t AudioFlinger::RecordThread::PassthruPatchRecord::getCapturePosition(
+ int64_t* frames, int64_t* time)
+{
+ sp<ThreadBase> thread;
+ sp<StreamInHalInterface> stream = obtainStream(&thread);
+ return stream ? stream->getCapturePosition(frames, time) : NO_INIT;
+}
+
+status_t AudioFlinger::RecordThread::PassthruPatchRecord::standby()
+{
+ // RecordThread issues 'standby' command in two major cases:
+ // 1. Error on read--this case is handled in 'obtainBuffer'.
+ // 2. Track is stopping--as PassthruPatchRecord assumes continuous
+ // output, this can only happen when the software patch
+ // is being torn down. In this case, the RecordThread
+ // will terminate and close the HAL stream.
+ return 0;
+}
+
+// As the buffer gets filled in obtainBuffer, here we only simulate data consumption.
+status_t AudioFlinger::RecordThread::PassthruPatchRecord::getNextBuffer(
+ AudioBufferProvider::Buffer* buffer)
+{
+ buffer->frameCount = mLastReadFrames;
+ buffer->raw = buffer->frameCount != 0 ? mStubBuffer.get() : nullptr;
+ return NO_ERROR;
+}
+
+void AudioFlinger::RecordThread::PassthruPatchRecord::releaseBuffer(
+ AudioBufferProvider::Buffer* buffer)
+{
+ buffer->frameCount = 0;
+ buffer->raw = nullptr;
+}
+
// ----------------------------------------------------------------------------
#undef LOG_TAG
#define LOG_TAG "AF::MmapTrack"
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 30f29d6..8d0e5db 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -17,8 +17,10 @@
#ifndef ANDROID_AUDIOPOLICY_INTERFACE_H
#define ANDROID_AUDIOPOLICY_INTERFACE_H
+#include <media/AudioDeviceTypeAddr.h>
#include <media/AudioSystem.h>
#include <media/AudioPolicy.h>
+#include <media/DeviceDescriptorBase.h>
#include <utils/String8.h>
namespace android {
@@ -67,12 +69,24 @@
API_INPUT_TELEPHONY_RX, // used for capture from telephony RX path
} input_type_t;
+ typedef enum {
+ API_OUTPUT_INVALID = -1,
+ API_OUTPUT_LEGACY = 0,// e.g. audio playing to speaker
+ API_OUT_MIX_PLAYBACK, // used for "remote submix" playback of audio from remote source
+ // to local capture
+ API_OUTPUT_TELEPHONY_TX, // used for playback to telephony TX path
+ } output_type_t;
+
public:
virtual ~AudioPolicyInterface() {}
//
// configuration functions
//
+ // Informs APM that new HAL modules are available. This typically happens
+ // due to registration of an audio HAL service.
+ virtual void onNewAudioModulesAvailable() = 0;
+
// indicate a change in device connection status
virtual status_t setDeviceConnectionState(audio_devices_t device,
audio_policy_dev_state_t state,
@@ -113,7 +127,8 @@
audio_output_flags_t *flags,
audio_port_handle_t *selectedDeviceId,
audio_port_handle_t *portId,
- std::vector<audio_io_handle_t> *secondaryOutputs) = 0;
+ std::vector<audio_io_handle_t> *secondaryOutputs,
+ output_type_t *outputType) = 0;
// indicates to the audio policy manager that the output starts being used by corresponding stream.
virtual status_t startOutput(audio_port_handle_t portId) = 0;
// indicates to the audio policy manager that the output stops being used by corresponding stream.
@@ -181,6 +196,10 @@
// return the enabled output devices for the given stream type
virtual audio_devices_t getDevicesForStream(audio_stream_type_t stream) = 0;
+ // retrieves the list of enabled output devices for the given audio attributes
+ virtual status_t getDevicesForAttributes(const audio_attributes_t &attr,
+ AudioDeviceTypeAddrVector *devices) = 0;
+
// Audio effect management
virtual audio_io_handle_t getOutputForEffect(const effect_descriptor_t *desc) = 0;
virtual status_t registerEffect(const effect_descriptor_t *desc,
@@ -235,6 +254,10 @@
= 0;
virtual status_t removeUidDeviceAffinities(uid_t uid) = 0;
+ virtual status_t setUserIdDeviceAffinities(int userId,
+ const Vector<AudioDeviceTypeAddr>& devices) = 0;
+ virtual status_t removeUserIdDeviceAffinities(int userId) = 0;
+
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
audio_port_handle_t *portId,
@@ -258,7 +281,7 @@
virtual status_t getHwOffloadEncodingFormatsSupportedForA2DP(
std::vector<audio_format_t> *formats) = 0;
- virtual void setAppState(uid_t uid, app_state_t state) = 0;
+ virtual void setAppState(audio_port_handle_t portId, app_state_t state) = 0;
virtual status_t listAudioProductStrategies(AudioProductStrategyVector &strategies) = 0;
@@ -269,6 +292,16 @@
virtual status_t getVolumeGroupFromAudioAttributes(const AudioAttributes &aa,
volume_group_t &volumeGroup) = 0;
+
+ virtual bool isCallScreenModeSupported() = 0;
+
+ virtual status_t setPreferredDeviceForStrategy(product_strategy_t strategy,
+ const AudioDeviceTypeAddr &device) = 0;
+
+ virtual status_t removePreferredDeviceForStrategy(product_strategy_t strategy) = 0;
+
+ virtual status_t getPreferredDeviceForStrategy(product_strategy_t strategy,
+ AudioDeviceTypeAddr &device) = 0;
};
@@ -296,8 +329,7 @@
virtual status_t openOutput(audio_module_handle_t module,
audio_io_handle_t *output,
audio_config_t *config,
- audio_devices_t *devices,
- const String8& address,
+ const sp<DeviceDescriptorBase>& device,
uint32_t *latencyMs,
audio_output_flags_t flags) = 0;
// creates a special output that is duplicated to the two outputs passed as arguments. The duplication is performed by
@@ -383,6 +415,12 @@
std::vector<effect_descriptor_t> effects,
audio_patch_handle_t patchHandle,
audio_source_t source) = 0;
+
+ // Used to notify the sound trigger module that an audio capture is about to
+ // take place. This should typically result in any active recognition
+ // sessions to be preempted on modules that do not support sound trigger
+ // recognition concurrently with audio capture.
+ virtual void setSoundTriggerCaptureState(bool active) = 0;
};
extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface);
diff --git a/services/audiopolicy/TEST_MAPPING b/services/audiopolicy/TEST_MAPPING
index a94fd87..eb6c19e 100644
--- a/services/audiopolicy/TEST_MAPPING
+++ b/services/audiopolicy/TEST_MAPPING
@@ -2,9 +2,6 @@
"presubmit": [
{
"name": "audiopolicy_tests"
- },
- {
- "name": "systemaudio_tests"
}
]
}
diff --git a/services/audiopolicy/audio_policy.conf b/services/audiopolicy/audio_policy.conf
deleted file mode 100644
index 9b83fef..0000000
--- a/services/audiopolicy/audio_policy.conf
+++ /dev/null
@@ -1,145 +0,0 @@
-#
-# Template audio policy configuration file
-#
-
-# Global configuration section:
-# - before audio HAL version 3.0:
-# lists input and output devices always present on the device
-# as well as the output device selected by default.
-# Devices are designated by a string that corresponds to the enum in audio.h
-#
-# global_configuration {
-# attached_output_devices AUDIO_DEVICE_OUT_SPEAKER
-# default_output_device AUDIO_DEVICE_OUT_SPEAKER
-# attached_input_devices AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_REMOTE_SUBMIX
-# }
-#
-# - after and including audio HAL 3.0 the global_configuration section is included in each
-# hardware module section.
-# it also includes the audio HAL version of this hw module:
-# global_configuration {
-# ...
-# audio_hal_version <major.minor> # audio HAL version in e.g. 3.0
-# }
-# other attributes (attached devices, default device) have to be included in the
-# global_configuration section of each hardware module
-
-
-# audio hardware module section: contains descriptors for all audio hw modules present on the
-# device. Each hw module node is named after the corresponding hw module library base name.
-# For instance, "primary" corresponds to audio.primary.<device>.so.
-# The "primary" module is mandatory and must include at least one output with
-# AUDIO_OUTPUT_FLAG_PRIMARY flag.
-# Each module descriptor contains one or more output profile descriptors and zero or more
-# input profile descriptors. Each profile lists all the parameters supported by a given output
-# or input stream category.
-# The "channel_masks", "formats", "devices" and "flags" are specified using strings corresponding
-# to enums in audio.h and audio_policy.h. They are concatenated by use of "|" without space or "\n".
-#
-# For audio HAL version posterior to 3.0 the following sections or sub sections can be present in
-# a hw module section:
-# - A "global_configuration" section: see above
-# - Optionally a "devices" section:
-# This section contains descriptors for audio devices with attributes like an address or a
-# gain controller. The syntax for the devices section and device descriptor is as follows:
-# devices {
-# <device name> { # <device name>: any string without space
-# type <device type> # <device type> e.g. AUDIO_DEVICE_OUT_SPEAKER
-# address <address> # optional: device address, char string less than 64 in length
-# }
-# }
-# - one or more "gains" sections can be present in a device descriptor section.
-# If present, they describe the capabilities of gain controllers attached to this input or
-# output device. e.g. :
-# <device name> { # <device name>: any string without space
-# type <device type> # <device type> e.g. AUDIO_DEVICE_OUT_SPEAKER
-# address <address> # optional: device address, char string less than 64 in length
-# gains {
-# <gain name> {
-# mode <gain modes supported> # e.g. AUDIO_GAIN_MODE_CHANNELS
-# channel_mask <controlled channels> # needed if mode AUDIO_GAIN_MODE_CHANNELS
-# min_value_mB <min value in millibel>
-# max_value_mB <max value in millibel>
-# default_value_mB <default value in millibel>
-# step_value_mB <step value in millibel>
-# min_ramp_ms <min duration in ms> # needed if mode AUDIO_GAIN_MODE_RAMP
-# max_ramp_ms <max duration ms> # needed if mode AUDIO_GAIN_MODE_RAMP
-# }
-# }
-# }
-# - when a device descriptor is present, output and input profiles can refer to this device by
-# its name in their "devices" section instead of specifying a device type. e.g. :
-# outputs {
-# primary {
-# sampling_rates 44100
-# channel_masks AUDIO_CHANNEL_OUT_STEREO
-# formats AUDIO_FORMAT_PCM_16_BIT
-# devices <device name>
-# flags AUDIO_OUTPUT_FLAG_PRIMARY
-# }
-# }
-# sample audio_policy.conf file below
-
-audio_hw_modules {
- primary {
- global_configuration {
- attached_output_devices AUDIO_DEVICE_OUT_SPEAKER
- default_output_device AUDIO_DEVICE_OUT_SPEAKER
- attached_input_devices AUDIO_DEVICE_IN_BUILTIN_MIC
- audio_hal_version 3.0
- }
- devices {
- speaker {
- type AUDIO_DEVICE_OUT_SPEAKER
- gains {
- gain_1 {
- mode AUDIO_GAIN_MODE_JOINT
- min_value_mB -8400
- max_value_mB 4000
- default_value_mB 0
- step_value_mB 100
- }
- }
- }
- }
- outputs {
- primary {
- sampling_rates 48000
- channel_masks AUDIO_CHANNEL_OUT_STEREO
- formats AUDIO_FORMAT_PCM_16_BIT
- devices speaker
- flags AUDIO_OUTPUT_FLAG_PRIMARY
- }
- }
- inputs {
- primary {
- sampling_rates 8000|16000
- channel_masks AUDIO_CHANNEL_IN_MONO
- formats AUDIO_FORMAT_PCM_16_BIT
- devices AUDIO_DEVICE_IN_BUILTIN_MIC
- }
- }
- }
- r_submix {
- global_configuration {
- attached_input_devices AUDIO_DEVICE_IN_REMOTE_SUBMIX
- audio_hal_version 2.0
- }
- outputs {
- submix {
- sampling_rates 48000
- channel_masks AUDIO_CHANNEL_OUT_STEREO
- formats AUDIO_FORMAT_PCM_16_BIT
- devices AUDIO_DEVICE_OUT_REMOTE_SUBMIX
- }
- }
- inputs {
- submix {
- sampling_rates 48000
- channel_masks AUDIO_CHANNEL_IN_STEREO
- formats AUDIO_FORMAT_PCM_16_BIT
- devices AUDIO_DEVICE_IN_REMOTE_SUBMIX
- }
- }
- }
-}
diff --git a/services/audiopolicy/common/Android.bp b/services/audiopolicy/common/Android.bp
index a925b9a..6e0d2f6 100644
--- a/services/audiopolicy/common/Android.bp
+++ b/services/audiopolicy/common/Android.bp
@@ -1,4 +1,7 @@
cc_library_headers {
name: "libaudiopolicycommon",
+ header_libs: [
+ "libaudiofoundation_headers",
+ ],
export_include_dirs: ["include"],
}
diff --git a/services/audiopolicy/common/include/Volume.h b/services/audiopolicy/common/include/Volume.h
index 1dbd1eb..7c8ce83 100644
--- a/services/audiopolicy/common/include/Volume.h
+++ b/services/audiopolicy/common/include/Volume.h
@@ -17,10 +17,13 @@
#pragma once
#include <media/AudioCommonTypes.h>
+#include <media/AudioContainers.h>
#include <system/audio.h>
#include <utils/Log.h>
#include <math.h>
+#include "policy.h"
+
namespace android {
/**
@@ -82,43 +85,26 @@
*
* @return subset of device required to limit the number of volume category per device
*/
- static audio_devices_t getDeviceForVolume(audio_devices_t device)
+ static audio_devices_t getDeviceForVolume(const android::DeviceTypeSet& deviceTypes)
{
- if (device == AUDIO_DEVICE_NONE) {
+ if (deviceTypes.empty()) {
// this happens when forcing a route update and no track is active on an output.
// In this case the returned category is not important.
- device = AUDIO_DEVICE_OUT_SPEAKER;
- } else if (popcount(device) > 1) {
- // Multiple device selection is either:
- // - speaker + one other device: give priority to speaker in this case.
- // - one A2DP device + another device: happens with duplicated output. In this case
- // retain the device on the A2DP output as the other must not correspond to an active
- // selection if not the speaker.
- // - HDMI-CEC system audio mode only output: give priority to available item in order.
- if (device & AUDIO_DEVICE_OUT_SPEAKER) {
- device = AUDIO_DEVICE_OUT_SPEAKER;
- } else if (device & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
- device = AUDIO_DEVICE_OUT_SPEAKER_SAFE;
- } else if (device & AUDIO_DEVICE_OUT_HDMI_ARC) {
- device = AUDIO_DEVICE_OUT_HDMI_ARC;
- } else if (device & AUDIO_DEVICE_OUT_AUX_LINE) {
- device = AUDIO_DEVICE_OUT_AUX_LINE;
- } else if (device & AUDIO_DEVICE_OUT_SPDIF) {
- device = AUDIO_DEVICE_OUT_SPDIF;
- } else {
- device = (audio_devices_t)(device & AUDIO_DEVICE_OUT_ALL_A2DP);
- }
+ return AUDIO_DEVICE_OUT_SPEAKER;
}
+ audio_devices_t deviceType = apm_extract_one_audio_device(deviceTypes);
+
/*SPEAKER_SAFE is an alias of SPEAKER for purposes of volume control*/
- if (device == AUDIO_DEVICE_OUT_SPEAKER_SAFE)
- device = AUDIO_DEVICE_OUT_SPEAKER;
+ if (deviceType == AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
+ deviceType = AUDIO_DEVICE_OUT_SPEAKER;
+ }
- ALOGW_IF(popcount(device) != 1,
- "getDeviceForVolume() invalid device combination: %08x",
- device);
+ ALOGW_IF(deviceType == AUDIO_DEVICE_NONE,
+ "getDeviceForVolume() invalid device combination: %s, returning AUDIO_DEVICE_NONE",
+ android::dumpDeviceTypes(deviceTypes).c_str());
- return device;
+ return deviceType;
}
/**
@@ -128,9 +114,9 @@
*
* @return device category.
*/
- static device_category getDeviceCategory(audio_devices_t device)
+ static device_category getDeviceCategory(const android::DeviceTypeSet& deviceTypes)
{
- switch(getDeviceForVolume(device)) {
+ switch(getDeviceForVolume(deviceTypes)) {
case AUDIO_DEVICE_OUT_EARPIECE:
return DEVICE_CATEGORY_EARPIECE;
case AUDIO_DEVICE_OUT_WIRED_HEADSET:
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index 605fc1c..0537365 100644
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -19,6 +19,8 @@
#include <system/audio.h>
#include <vector>
+#include <media/AudioContainers.h>
+
namespace android {
using StreamTypeVector = std::vector<audio_stream_type_t>;
@@ -43,14 +45,6 @@
#define MAX_MIXER_CHANNEL_COUNT FCC_8
/**
- * A device mask for all audio input and output devices where matching inputs/outputs on device
- * type alone is not enough: the address must match too
- */
-#define APM_AUDIO_DEVICE_OUT_MATCH_ADDRESS_ALL (AUDIO_DEVICE_OUT_REMOTE_SUBMIX|AUDIO_DEVICE_OUT_BUS)
-
-#define APM_AUDIO_DEVICE_IN_MATCH_ADDRESS_ALL (AUDIO_DEVICE_IN_REMOTE_SUBMIX|AUDIO_DEVICE_IN_BUS)
-
-/**
* Alias to AUDIO_DEVICE_OUT_DEFAULT defined for clarification when this value is used by volume
* control APIs (e.g setStreamVolumeIndex().
*/
@@ -71,6 +65,34 @@
}
/**
+ * Check whether the output device type is one
+ * where addresses are used to distinguish between one connected device and another
+ *
+ * @param[in] device to consider
+ *
+ * @return true if the device needs distinguish on address, false otherwise..
+ */
+static inline bool apm_audio_out_device_distinguishes_on_address(audio_devices_t device)
+{
+ return device == AUDIO_DEVICE_OUT_REMOTE_SUBMIX ||
+ device == AUDIO_DEVICE_OUT_BUS;
+}
+
+/**
+ * Check whether the input device type is one
+ * where addresses are used to distinguish between one connected device and another
+ *
+ * @param[in] device to consider
+ *
+ * @return true if the device needs distinguish on address, false otherwise..
+ */
+static inline bool apm_audio_in_device_distinguishes_on_address(audio_devices_t device)
+{
+ return device == AUDIO_DEVICE_IN_REMOTE_SUBMIX ||
+ device == AUDIO_DEVICE_IN_BUS;
+}
+
+/**
* Check whether the device type is one
* where addresses are used to distinguish between one connected device and another
*
@@ -80,10 +102,8 @@
*/
static inline bool device_distinguishes_on_address(audio_devices_t device)
{
- return (((device & AUDIO_DEVICE_BIT_IN) != 0) &&
- ((~AUDIO_DEVICE_BIT_IN & device & APM_AUDIO_DEVICE_IN_MATCH_ADDRESS_ALL) != 0)) ||
- (((device & AUDIO_DEVICE_BIT_IN) == 0) &&
- ((device & APM_AUDIO_DEVICE_OUT_MATCH_ADDRESS_ALL) != 0));
+ return apm_audio_in_device_distinguishes_on_address(device) ||
+ apm_audio_out_device_distinguishes_on_address(device);
}
/**
@@ -95,10 +115,7 @@
*/
static inline bool device_has_encoding_capability(audio_devices_t device)
{
- if (device & AUDIO_DEVICE_OUT_ALL_A2DP) {
- return true;
- }
- return false;
+ return audio_is_a2dp_out_device(device);
}
/**
@@ -184,3 +201,43 @@
{
return hasStream(streams, AUDIO_STREAM_VOICE_CALL);
}
+
+/**
+ * @brief extract one device relevant from multiple device selection
+ * @param deviceTypes collection of audio device type
+ * @return the device type that is selected
+ */
+static inline audio_devices_t apm_extract_one_audio_device(
+ const android::DeviceTypeSet& deviceTypes) {
+ if (deviceTypes.empty()) {
+ return AUDIO_DEVICE_NONE;
+ } else if (deviceTypes.size() == 1) {
+ return *(deviceTypes.begin());
+ } else {
+ // Multiple device selection is either:
+ // - speaker + one other device: give priority to speaker in this case.
+ // - one A2DP device + another device: happens with duplicated output. In this case
+ // retain the device on the A2DP output as the other must not correspond to an active
+ // selection if not the speaker.
+ // - HDMI-CEC system audio mode only output: give priority to available item in order.
+ if (deviceTypes.count(AUDIO_DEVICE_OUT_SPEAKER) != 0) {
+ return AUDIO_DEVICE_OUT_SPEAKER;
+ } else if (deviceTypes.count(AUDIO_DEVICE_OUT_SPEAKER_SAFE) != 0) {
+ return AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+ } else if (deviceTypes.count(AUDIO_DEVICE_OUT_HDMI_ARC) != 0) {
+ return AUDIO_DEVICE_OUT_HDMI_ARC;
+ } else if (deviceTypes.count(AUDIO_DEVICE_OUT_AUX_LINE) != 0) {
+ return AUDIO_DEVICE_OUT_AUX_LINE;
+ } else if (deviceTypes.count(AUDIO_DEVICE_OUT_SPDIF) != 0) {
+ return AUDIO_DEVICE_OUT_SPDIF;
+ } else {
+ std::vector<audio_devices_t> a2dpDevices = android::Intersection(
+ deviceTypes, android::getAudioDeviceOutAllA2dpSet());
+ if (a2dpDevices.empty() || a2dpDevices.size() > 1) {
+ ALOGW("%s invalid device combination: %s",
+ __func__, android::dumpDeviceTypes(deviceTypes).c_str());
+ }
+ return a2dpDevices.empty() ? AUDIO_DEVICE_NONE : a2dpDevices[0];
+ }
+ }
+}
\ No newline at end of file
diff --git a/services/audiopolicy/common/managerdefinitions/Android.bp b/services/audiopolicy/common/managerdefinitions/Android.bp
index f02f3cf..fad3c5b 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.bp
+++ b/services/audiopolicy/common/managerdefinitions/Android.bp
@@ -3,24 +3,24 @@
srcs: [
"src/AudioCollections.cpp",
- "src/AudioGain.cpp",
"src/AudioInputDescriptor.cpp",
"src/AudioOutputDescriptor.cpp",
"src/AudioPatch.cpp",
"src/AudioPolicyMix.cpp",
- "src/AudioPort.cpp",
- "src/AudioProfile.cpp",
+ "src/AudioProfileVectorHelper.cpp",
"src/AudioRoute.cpp",
"src/ClientDescriptor.cpp",
"src/DeviceDescriptor.cpp",
"src/EffectDescriptor.cpp",
"src/HwModule.cpp",
"src/IOProfile.cpp",
+ "src/PolicyAudioPort.cpp",
"src/Serializer.cpp",
"src/SoundTriggerSession.cpp",
"src/TypeConverter.cpp",
],
shared_libs: [
+ "libaudiofoundation",
"libcutils",
"libhidlbase",
"liblog",
@@ -28,7 +28,10 @@
"libutils",
"libxml2",
],
- export_shared_lib_headers: ["libmedia"],
+ export_shared_lib_headers: [
+ "libaudiofoundation",
+ "libmedia",
+ ],
static_libs: [
"libaudioutils",
],
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h b/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h
index a948ea9..b692592 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h
@@ -25,20 +25,15 @@
namespace android {
-class AudioPort;
+class PolicyAudioPort;
class AudioRoute;
-class AudioPortVector : public Vector<sp<AudioPort> >
-{
-public:
- sp<AudioPort> findByTagName(const String8 &tagName) const;
-};
+using PolicyAudioPortVector = Vector<sp<PolicyAudioPort>>;
+using AudioRouteVector = Vector<sp<AudioRoute>>;
+sp<PolicyAudioPort> findByTagName(const PolicyAudioPortVector& policyAudioPortVector,
+ const std::string &tagName);
-class AudioRouteVector : public Vector<sp<AudioRoute> >
-{
-public:
- void dump(String8 *dst, int spaces) const;
-};
+void dumpAudioRouteVector(const AudioRouteVector& audioRouteVector, String8 *dst, int spaces);
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioGain.h b/services/audiopolicy/common/managerdefinitions/include/AudioGain.h
deleted file mode 100644
index 4af93e1..0000000
--- a/services/audiopolicy/common/managerdefinitions/include/AudioGain.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-#include <utils/String8.h>
-#include <system/audio.h>
-#include <vector>
-
-namespace android {
-
-class AudioGain: public RefBase
-{
-public:
- AudioGain(int index, bool useInChannelMask);
- virtual ~AudioGain() {}
-
- void setMode(audio_gain_mode_t mode) { mGain.mode = mode; }
- const audio_gain_mode_t &getMode() const { return mGain.mode; }
-
- void setChannelMask(audio_channel_mask_t mask) { mGain.channel_mask = mask; }
- const audio_channel_mask_t &getChannelMask() const { return mGain.channel_mask; }
-
- void setMinValueInMb(int minValue) { mGain.min_value = minValue; }
- int getMinValueInMb() const { return mGain.min_value; }
-
- void setMaxValueInMb(int maxValue) { mGain.max_value = maxValue; }
- int getMaxValueInMb() const { return mGain.max_value; }
-
- void setDefaultValueInMb(int defaultValue) { mGain.default_value = defaultValue; }
- int getDefaultValueInMb() const { return mGain.default_value; }
-
- void setStepValueInMb(uint32_t stepValue) { mGain.step_value = stepValue; }
- int getStepValueInMb() const { return mGain.step_value; }
-
- void setMinRampInMs(uint32_t minRamp) { mGain.min_ramp_ms = minRamp; }
- int getMinRampInMs() const { return mGain.min_ramp_ms; }
-
- void setMaxRampInMs(uint32_t maxRamp) { mGain.max_ramp_ms = maxRamp; }
- int getMaxRampInMs() const { return mGain.max_ramp_ms; }
-
- // TODO: remove dump from here (split serialization)
- void dump(String8 *dst, int spaces, int index) const;
-
- void getDefaultConfig(struct audio_gain_config *config);
- status_t checkConfig(const struct audio_gain_config *config);
-
- void setUseForVolume(bool canUseForVolume) { mUseForVolume = canUseForVolume; }
- bool canUseForVolume() const { return mUseForVolume; }
-
- const struct audio_gain &getGain() const { return mGain; }
-
-private:
- int mIndex;
- struct audio_gain mGain;
- bool mUseInChannelMask;
- bool mUseForVolume = false;
-};
-
-class AudioGains : public std::vector<sp<AudioGain> >
-{
-public:
- bool canUseForVolume() const
- {
- for (const auto &gain: *this) {
- if (gain->canUseForVolume()) {
- return true;
- }
- }
- return false;
- }
-
- int32_t add(const sp<AudioGain> gain)
- {
- push_back(gain);
- return 0;
- }
-};
-
-} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index 37f9d14..c67a006 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -21,11 +21,11 @@
#include <utils/SortedVector.h>
#include <utils/KeyedVector.h>
#include "AudioIODescriptorInterface.h"
-#include "AudioPort.h"
#include "ClientDescriptor.h"
#include "DeviceDescriptor.h"
#include "EffectDescriptor.h"
#include "IOProfile.h"
+#include "PolicyAudioPort.h"
namespace android {
@@ -34,13 +34,17 @@
// descriptor for audio inputs. Used to maintain current configuration of each opened audio input
// and keep track of the usage of this input.
-class AudioInputDescriptor: public AudioPortConfig, public AudioIODescriptorInterface
- , public ClientMapHandler<RecordClientDescriptor>
+class AudioInputDescriptor: public AudioPortConfig,
+ public PolicyAudioPortConfig,
+ public AudioIODescriptorInterface,
+ public ClientMapHandler<RecordClientDescriptor>
{
public:
- explicit AudioInputDescriptor(const sp<IOProfile>& profile,
- AudioPolicyClientInterface *clientInterface);
- audio_port_handle_t getId() const;
+ AudioInputDescriptor(const sp<IOProfile>& profile,
+ AudioPolicyClientInterface *clientInterface);
+
+ virtual ~AudioInputDescriptor() = default;
+
audio_module_handle_t getModuleHandle() const;
audio_devices_t getDeviceType() const { return (mDevice != nullptr) ?
@@ -56,9 +60,18 @@
wp<AudioPolicyMix> mPolicyMix; // non NULL when used by a dynamic policy
const sp<IOProfile> mProfile; // I/O profile this output derives from
+ // PolicyAudioPortConfig
+ virtual sp<PolicyAudioPort> getPolicyAudioPort() const {
+ return mProfile;
+ }
+
+ // AudioPortConfig
+ virtual status_t applyAudioPortConfig(const struct audio_port_config *config,
+ struct audio_port_config *backupConfig = NULL);
virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
const struct audio_port_config *srcConfig = NULL) const;
virtual sp<AudioPort> getAudioPort() const { return mProfile; }
+
void toAudioPort(struct audio_port *port) const;
void setPreemptedSessions(const SortedVector<audio_session_t>& sessions);
SortedVector<audio_session_t> getPreemptedSessions() const;
@@ -97,7 +110,7 @@
RecordClientVector clientsList(bool activeOnly = false,
audio_source_t source = AUDIO_SOURCE_DEFAULT, bool preferredDeviceOnly = false) const;
- void setAppState(uid_t uid, app_state_t state);
+ void setAppState(audio_port_handle_t portId, app_state_t state);
// implementation of ClientMapHandler<RecordClientDescriptor>
void addClient(const sp<RecordClientDescriptor> &client) override;
@@ -111,7 +124,6 @@
void updateClientRecordingConfiguration(int event, const sp<RecordClientDescriptor>& client);
audio_patch_handle_t mPatchHandle = AUDIO_PATCH_HANDLE_NONE;
- audio_port_handle_t mId = AUDIO_PORT_HANDLE_NONE;
sp<DeviceDescriptor> mDevice = nullptr; /**< current device this input is routed to */
// Because a preemptible capture session can preempt another one, we end up in an endless loop
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index cd54085..41f7dfc 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -21,14 +21,15 @@
#include <sys/types.h>
+#include <media/AudioContainers.h>
#include <utils/Errors.h>
#include <utils/Timers.h>
#include <utils/KeyedVector.h>
#include <system/audio.h>
#include "AudioIODescriptorInterface.h"
-#include "AudioPort.h"
#include "ClientDescriptor.h"
#include "DeviceDescriptor.h"
+#include "PolicyAudioPort.h"
#include <vector>
namespace android {
@@ -138,27 +139,28 @@
// descriptor for audio outputs. Used to maintain current configuration of each opened audio output
// and keep track of the usage of this output by each audio stream type.
-class AudioOutputDescriptor: public AudioPortConfig, public AudioIODescriptorInterface
- , public ClientMapHandler<TrackClientDescriptor>
+class AudioOutputDescriptor: public AudioPortConfig,
+ public PolicyAudioPortConfig,
+ public AudioIODescriptorInterface,
+ public ClientMapHandler<TrackClientDescriptor>
{
public:
- AudioOutputDescriptor(const sp<AudioPort>& port,
+ AudioOutputDescriptor(const sp<PolicyAudioPort>& policyAudioPort,
AudioPolicyClientInterface *clientInterface);
virtual ~AudioOutputDescriptor() {}
void dump(String8 *dst) const override;
void log(const char* indent);
- audio_port_handle_t getId() const;
virtual DeviceVector devices() const { return mDevices; }
bool sharesHwModuleWith(const sp<AudioOutputDescriptor>& outputDesc);
virtual DeviceVector supportedDevices() const { return mDevices; }
virtual bool isDuplicated() const { return false; }
virtual uint32_t latency() { return 0; }
- virtual bool isFixedVolume(audio_devices_t device);
+ virtual bool isFixedVolume(const DeviceTypeSet& deviceTypes);
virtual bool setVolume(float volumeDb,
VolumeSource volumeSource, const StreamTypeVector &streams,
- audio_devices_t device,
+ const DeviceTypeSet& deviceTypes,
uint32_t delayMs,
bool force);
@@ -245,9 +247,19 @@
mRoutingActivities[ps].setMutedByDevice(isMuted);
}
+ // PolicyAudioPortConfig
+ virtual sp<PolicyAudioPort> getPolicyAudioPort() const
+ {
+ return mPolicyAudioPort;
+ }
+
+ // AudioPortConfig
+ virtual status_t applyAudioPortConfig(const struct audio_port_config *config,
+ struct audio_port_config *backupConfig = NULL);
virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
const struct audio_port_config *srcConfig = NULL) const;
- virtual sp<AudioPort> getAudioPort() const { return mPort; }
+ virtual sp<AudioPort> getAudioPort() const { return mPolicyAudioPort->asAudioPort(); }
+
virtual void toAudioPort(struct audio_port *port) const;
audio_module_handle_t getModuleHandle() const;
@@ -289,11 +301,10 @@
wp<AudioPolicyMix> mPolicyMix; // non NULL when used by a dynamic policy
protected:
- const sp<AudioPort> mPort;
+ const sp<PolicyAudioPort> mPolicyAudioPort;
AudioPolicyClientInterface * const mClientInterface;
uint32_t mGlobalActiveCount = 0; // non-client-specific active count
audio_patch_handle_t mPatchHandle = AUDIO_PATCH_HANDLE_NONE;
- audio_port_handle_t mId = AUDIO_PORT_HANDLE_NONE;
// The ActiveClients shows the clients that contribute to the @VolumeSource counts
// and may include upstream clients from a duplicating thread.
@@ -319,10 +330,10 @@
void setDevices(const DeviceVector &devices) { mDevices = devices; }
bool sharesHwModuleWith(const sp<SwAudioOutputDescriptor>& outputDesc);
virtual DeviceVector supportedDevices() const;
- virtual bool deviceSupportsEncodedFormats(audio_devices_t device);
+ virtual bool devicesSupportEncodedFormats(const DeviceTypeSet& deviceTypes);
virtual uint32_t latency();
virtual bool isDuplicated() const { return (mOutput1 != NULL && mOutput2 != NULL); }
- virtual bool isFixedVolume(audio_devices_t device);
+ virtual bool isFixedVolume(const DeviceTypeSet& deviceTypes);
sp<SwAudioOutputDescriptor> subOutput1() { return mOutput1; }
sp<SwAudioOutputDescriptor> subOutput2() { return mOutput2; }
void setClientActive(const sp<TrackClientDescriptor>& client, bool active) override;
@@ -334,7 +345,7 @@
}
virtual bool setVolume(float volumeDb,
VolumeSource volumeSource, const StreamTypeVector &streams,
- audio_devices_t device,
+ const DeviceTypeSet& device,
uint32_t delayMs,
bool force);
@@ -408,7 +419,7 @@
virtual bool setVolume(float volumeDb,
VolumeSource volumeSource, const StreamTypeVector &streams,
- audio_devices_t device,
+ const DeviceTypeSet& deviceTypes,
uint32_t delayMs,
bool force);
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPatch.h b/services/audiopolicy/common/managerdefinitions/include/AudioPatch.h
index 0843fea..a5de655 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPatch.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPatch.h
@@ -31,12 +31,24 @@
public:
AudioPatch(const struct audio_patch *patch, uid_t uid);
+ audio_patch_handle_t getHandle() const { return mHandle; }
+
+ audio_patch_handle_t getAfHandle() const { return mAfPatchHandle; }
+
+ void setAfHandle(audio_patch_handle_t afHandle) { mAfPatchHandle = afHandle; }
+
+ uid_t getUid() const { return mUid; }
+
+ void setUid(uid_t uid) { mUid = uid; }
+
void dump(String8 *dst, int spaces, int index) const;
- audio_patch_handle_t mHandle;
struct audio_patch mPatch;
+
+private:
+ const audio_patch_handle_t mHandle;
uid_t mUid;
- audio_patch_handle_t mAfPatchHandle;
+ audio_patch_handle_t mAfPatchHandle = AUDIO_PATCH_HANDLE_NONE;
};
class AudioPatchCollection : public DefaultKeyedVector<audio_patch_handle_t, sp<AudioPatch> >
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
index 2264d8f..395bc70 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
@@ -19,17 +19,17 @@
#include <unordered_map>
#include <unordered_set>
-#include <AudioGain.h>
-#include <AudioPort.h>
#include <AudioPatch.h>
#include <DeviceDescriptor.h>
#include <IOProfile.h>
#include <HwModule.h>
+#include <PolicyAudioPort.h>
#include <AudioInputDescriptor.h>
#include <AudioOutputDescriptor.h>
#include <AudioPolicyMix.h>
#include <EffectDescriptor.h>
#include <SoundTriggerSession.h>
+#include <media/AudioProfile.h>
namespace android {
@@ -37,14 +37,16 @@
{
public:
AudioPolicyConfig(HwModuleCollection &hwModules,
- DeviceVector &availableOutputDevices,
- DeviceVector &availableInputDevices,
+ DeviceVector &outputDevices,
+ DeviceVector &inputDevices,
sp<DeviceDescriptor> &defaultOutputDevice)
- : mHwModules(hwModules),
- mAvailableOutputDevices(availableOutputDevices),
- mAvailableInputDevices(availableInputDevices),
+ : mEngineLibraryNameSuffix(kDefaultEngineLibraryNameSuffix),
+ mHwModules(hwModules),
+ mOutputDevices(outputDevices),
+ mInputDevices(inputDevices),
mDefaultOutputDevice(defaultOutputDevice),
- mIsSpeakerDrcEnabled(false)
+ mIsSpeakerDrcEnabled(false),
+ mIsCallScreenModeSupported(false)
{}
const std::string& getSource() const {
@@ -55,28 +57,36 @@
mSource = file;
}
+ const std::string& getEngineLibraryNameSuffix() const {
+ return mEngineLibraryNameSuffix;
+ }
+
+ void setEngineLibraryNameSuffix(const std::string& suffix) {
+ mEngineLibraryNameSuffix = suffix;
+ }
+
void setHwModules(const HwModuleCollection &hwModules)
{
mHwModules = hwModules;
}
- void addAvailableDevice(const sp<DeviceDescriptor> &availableDevice)
+ void addDevice(const sp<DeviceDescriptor> &device)
{
- if (audio_is_output_device(availableDevice->type())) {
- mAvailableOutputDevices.add(availableDevice);
- } else if (audio_is_input_device(availableDevice->type())) {
- mAvailableInputDevices.add(availableDevice);
+ if (audio_is_output_device(device->type())) {
+ mOutputDevices.add(device);
+ } else if (audio_is_input_device(device->type())) {
+ mInputDevices.add(device);
}
}
- void addAvailableInputDevices(const DeviceVector &availableInputDevices)
+ void addInputDevices(const DeviceVector &inputDevices)
{
- mAvailableInputDevices.add(availableInputDevices);
+ mInputDevices.add(inputDevices);
}
- void addAvailableOutputDevices(const DeviceVector &availableOutputDevices)
+ void addOutputDevices(const DeviceVector &outputDevices)
{
- mAvailableOutputDevices.add(availableOutputDevices);
+ mOutputDevices.add(outputDevices);
}
bool isSpeakerDrcEnabled() const { return mIsSpeakerDrcEnabled; }
@@ -86,16 +96,24 @@
mIsSpeakerDrcEnabled = isSpeakerDrcEnabled;
}
- const HwModuleCollection getHwModules() const { return mHwModules; }
+ bool isCallScreenModeSupported() const { return mIsCallScreenModeSupported; }
- const DeviceVector &getAvailableInputDevices() const
+ void setCallScreenModeSupported(bool isCallScreenModeSupported)
{
- return mAvailableInputDevices;
+ mIsCallScreenModeSupported = isCallScreenModeSupported;
}
- const DeviceVector &getAvailableOutputDevices() const
+
+ const HwModuleCollection getHwModules() const { return mHwModules; }
+
+ const DeviceVector &getInputDevices() const
{
- return mAvailableOutputDevices;
+ return mInputDevices;
+ }
+
+ const DeviceVector &getOutputDevices() const
+ {
+ return mOutputDevices;
}
void setDefaultOutputDevice(const sp<DeviceDescriptor> &defaultDevice)
@@ -108,29 +126,28 @@
void setDefault(void)
{
mSource = "AudioPolicyConfig::setDefault";
+ mEngineLibraryNameSuffix = kDefaultEngineLibraryNameSuffix;
mDefaultOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPEAKER);
- mDefaultOutputDevice->addAudioProfile(AudioProfile::createFullDynamic());
+ mDefaultOutputDevice->addAudioProfile(AudioProfile::createFullDynamic(gDynamicFormat));
sp<DeviceDescriptor> defaultInputDevice = new DeviceDescriptor(AUDIO_DEVICE_IN_BUILTIN_MIC);
- defaultInputDevice->addAudioProfile(AudioProfile::createFullDynamic());
+ defaultInputDevice->addAudioProfile(AudioProfile::createFullDynamic(gDynamicFormat));
sp<AudioProfile> micProfile = new AudioProfile(
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO, 8000);
defaultInputDevice->addAudioProfile(micProfile);
- mAvailableOutputDevices.add(mDefaultOutputDevice);
- mAvailableInputDevices.add(defaultInputDevice);
+ mOutputDevices.add(mDefaultOutputDevice);
+ mInputDevices.add(defaultInputDevice);
sp<HwModule> module = new HwModule(AUDIO_HARDWARE_MODULE_ID_PRIMARY, 2 /*halVersionMajor*/);
mHwModules.add(module);
- mDefaultOutputDevice->attach(module);
- defaultInputDevice->attach(module);
- sp<OutputProfile> outProfile = new OutputProfile(String8("primary"));
+ sp<OutputProfile> outProfile = new OutputProfile("primary");
outProfile->addAudioProfile(
new AudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 44100));
outProfile->addSupportedDevice(mDefaultOutputDevice);
outProfile->setFlags(AUDIO_OUTPUT_FLAG_PRIMARY);
module->addOutputProfile(outProfile);
- sp<InputProfile> inProfile = new InputProfile(String8("primary"));
+ sp<InputProfile> inProfile = new InputProfile("primary");
inProfile->addAudioProfile(micProfile);
inProfile->addSupportedDevice(defaultInputDevice);
module->addInputProfile(inProfile);
@@ -167,15 +184,19 @@
}
private:
+ static const constexpr char* const kDefaultEngineLibraryNameSuffix = "default";
+
std::string mSource;
+ std::string mEngineLibraryNameSuffix;
HwModuleCollection &mHwModules; /**< Collection of Module, with Profiles, i.e. Mix Ports. */
- DeviceVector &mAvailableOutputDevices;
- DeviceVector &mAvailableInputDevices;
+ DeviceVector &mOutputDevices;
+ DeviceVector &mInputDevices;
sp<DeviceDescriptor> &mDefaultOutputDevice;
// TODO: remove when legacy conf file is removed. true on devices that use DRC on the
// DEVICE_CATEGORY_SPEAKER path to boost soft sounds, used to adjust volume curves accordingly.
// Note: remove also speaker_drc_enabled from global configuration of XML config file.
bool mIsSpeakerDrcEnabled;
+ bool mIsCallScreenModeSupported;
SurroundFormats mSurroundFormats;
};
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
index 094f506..a757551 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
@@ -18,6 +18,7 @@
#include "DeviceDescriptor.h"
#include <utils/RefBase.h>
+#include <media/AudioDeviceTypeAddr.h>
#include <media/AudioPolicy.h>
#include <utils/Vector.h>
#include <system/audio.h>
@@ -104,12 +105,27 @@
status_t removeUidDeviceAffinities(uid_t uid);
status_t getDevicesForUid(uid_t uid, Vector<AudioDeviceTypeAddr>& devices) const;
+ /**
+ * Updates the mix rules in order to make streams associated with the given user
+ * be routed to the given audio devices.
+ * @param userId the userId for which the device affinity is set
+ * @param devices the vector of devices that this userId may be routed to. A typical
+ * use is to pass the devices associated with a given zone in a multi-zone setup.
+ * @return NO_ERROR if the update was successful, INVALID_OPERATION otherwise.
+ * An example of failure is when there are already rules in place to restrict
+ * a mix to the given userId (i.e. when a MATCH_USERID rule was set for it).
+ */
+ status_t setUserIdDeviceAffinities(int userId, const Vector<AudioDeviceTypeAddr>& devices);
+ status_t removeUserIdDeviceAffinities(int userId);
+ status_t getDevicesForUserId(int userId, Vector<AudioDeviceTypeAddr>& devices) const;
+
void dump(String8 *dst) const;
private:
enum class MixMatchStatus { MATCH, NO_MATCH, INVALID_MIX };
MixMatchStatus mixMatch(const AudioMix* mix, size_t mixIndex,
- const audio_attributes_t& attributes, uid_t uid);
+ const audio_attributes_t& attributes,
+ uid_t uid);
};
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
deleted file mode 100644
index d906f11..0000000
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "AudioCollections.h"
-#include "AudioProfile.h"
-#include "AudioGain.h"
-#include "HandleGenerator.h"
-#include <utils/String8.h>
-#include <utils/Vector.h>
-#include <utils/RefBase.h>
-#include <utils/Errors.h>
-#include <system/audio.h>
-#include <cutils/config_utils.h>
-
-namespace android {
-
-class HwModule;
-class AudioRoute;
-
-class AudioPort : public virtual RefBase, private HandleGenerator<audio_port_handle_t>
-{
-public:
- AudioPort(const String8& name, audio_port_type_t type, audio_port_role_t role) :
- mName(name), mType(type), mRole(role), mFlags(AUDIO_OUTPUT_FLAG_NONE) {}
-
- virtual ~AudioPort() {}
-
- void setName(const String8 &name) { mName = name; }
- const String8 &getName() const { return mName; }
-
- audio_port_type_t getType() const { return mType; }
- audio_port_role_t getRole() const { return mRole; }
-
- virtual const String8 getTagName() const = 0;
-
- void setGains(const AudioGains &gains) { mGains = gains; }
- const AudioGains &getGains() const { return mGains; }
-
- virtual void setFlags(uint32_t flags)
- {
- //force direct flag if offload flag is set: offloading implies a direct output stream
- // and all common behaviors are driven by checking only the direct flag
- // this should normally be set appropriately in the policy configuration file
- if (mRole == AUDIO_PORT_ROLE_SOURCE && (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
- flags |= AUDIO_OUTPUT_FLAG_DIRECT;
- }
- mFlags = flags;
- }
- uint32_t getFlags() const { return mFlags; }
-
- virtual void attach(const sp<HwModule>& module);
- virtual void detach();
- bool isAttached() { return mModule != 0; }
-
- // Audio port IDs are in a different namespace than AudioFlinger unique IDs
- static audio_port_handle_t getNextUniqueId();
-
- virtual void toAudioPort(struct audio_port *port) const;
-
- virtual void importAudioPort(const sp<AudioPort>& port, bool force = false);
-
- void addAudioProfile(const sp<AudioProfile> &profile) { mProfiles.add(profile); }
-
- void setAudioProfiles(const AudioProfileVector &profiles) { mProfiles = profiles; }
- AudioProfileVector &getAudioProfiles() { return mProfiles; }
-
- bool hasValidAudioProfile() const { return mProfiles.hasValidProfile(); }
-
- bool hasDynamicAudioProfile() const { return mProfiles.hasDynamicProfile(); }
-
- // searches for an exact match
- virtual status_t checkExactAudioProfile(const struct audio_port_config *config) const;
-
- // searches for a compatible match, currently implemented for input
- // parameters are input|output, returned value is the best match.
- status_t checkCompatibleAudioProfile(uint32_t &samplingRate,
- audio_channel_mask_t &channelMask,
- audio_format_t &format) const
- {
- return mProfiles.checkCompatibleProfile(samplingRate, channelMask, format, mType, mRole);
- }
-
- void clearAudioProfiles() { return mProfiles.clearProfiles(); }
-
- status_t checkGain(const struct audio_gain_config *gainConfig, int index) const;
-
- void pickAudioProfile(uint32_t &samplingRate,
- audio_channel_mask_t &channelMask,
- audio_format_t &format) const;
-
- static const audio_format_t sPcmFormatCompareTable[];
-
- static int compareFormats(audio_format_t format1, audio_format_t format2);
-
- // Used to select an audio HAL output stream with a sample format providing the
- // less degradation for a given AudioTrack sample format.
- static bool isBetterFormatMatch(audio_format_t newFormat,
- audio_format_t currentFormat,
- audio_format_t targetFormat);
- static uint32_t formatDistance(audio_format_t format1,
- audio_format_t format2);
- static const uint32_t kFormatDistanceMax = 4;
-
- audio_module_handle_t getModuleHandle() const;
- uint32_t getModuleVersionMajor() const;
- const char *getModuleName() const;
- sp<HwModule> getModule() const { return mModule; }
-
- bool useInputChannelMask() const
- {
- return ((mType == AUDIO_PORT_TYPE_DEVICE) && (mRole == AUDIO_PORT_ROLE_SOURCE)) ||
- ((mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SINK));
- }
-
- inline bool isDirectOutput() const
- {
- return (mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SOURCE) &&
- (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD));
- }
-
- void addRoute(const sp<AudioRoute> &route) { mRoutes.add(route); }
- const AudioRouteVector &getRoutes() const { return mRoutes; }
-
- void dump(String8 *dst, int spaces, bool verbose = true) const;
-
- void log(const char* indent) const;
-
- AudioGains mGains; // gain controllers
-
-private:
- void pickChannelMask(audio_channel_mask_t &channelMask, const ChannelsVector &channelMasks) const;
- void pickSamplingRate(uint32_t &rate,const SampleRateVector &samplingRates) const;
-
- sp<HwModule> mModule; // audio HW module exposing this I/O stream
- String8 mName;
- audio_port_type_t mType;
- audio_port_role_t mRole;
- uint32_t mFlags; // attribute flags mask (e.g primary output, direct output...).
- AudioProfileVector mProfiles; // AudioProfiles supported by this port (format, Rates, Channels)
- AudioRouteVector mRoutes; // Routes involving this port
-};
-
-class AudioPortConfig : public virtual RefBase
-{
-public:
- status_t applyAudioPortConfig(const struct audio_port_config *config,
- struct audio_port_config *backupConfig = NULL);
- virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
- const struct audio_port_config *srcConfig = NULL) const = 0;
- virtual sp<AudioPort> getAudioPort() const = 0;
- virtual bool hasSameHwModuleAs(const sp<AudioPortConfig>& other) const {
- return (other != 0) && (other->getAudioPort() != 0) && (getAudioPort() != 0) &&
- (other->getAudioPort()->getModuleHandle() == getAudioPort()->getModuleHandle());
- }
- bool hasGainController(bool canUseForVolume = false) const;
-
- unsigned int mSamplingRate = 0u;
- audio_format_t mFormat = AUDIO_FORMAT_INVALID;
- audio_channel_mask_t mChannelMask = AUDIO_CHANNEL_NONE;
- struct audio_gain_config mGain = { .index = -1 };
- union audio_io_flags mFlags = { AUDIO_INPUT_FLAG_NONE };
-};
-
-} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h b/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
deleted file mode 100644
index b588d57..0000000
--- a/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <vector>
-
-#include <system/audio.h>
-#include <utils/RefBase.h>
-#include <utils/SortedVector.h>
-#include <utils/String8.h>
-
-#include "policy.h"
-
-namespace android {
-
-typedef SortedVector<uint32_t> SampleRateVector;
-typedef Vector<audio_format_t> FormatVector;
-
-template <typename T>
-bool operator== (const SortedVector<T> &left, const SortedVector<T> &right)
-{
- if (left.size() != right.size()) {
- return false;
- }
- for (size_t index = 0; index < right.size(); index++) {
- if (left[index] != right[index]) {
- return false;
- }
- }
- return true;
-}
-
-template <typename T>
-bool operator!= (const SortedVector<T> &left, const SortedVector<T> &right)
-{
- return !(left == right);
-}
-
-class ChannelsVector : public SortedVector<audio_channel_mask_t>
-{
-public:
- ChannelsVector() = default;
- ChannelsVector(const ChannelsVector&) = default;
- ChannelsVector(const SortedVector<audio_channel_mask_t>& sv) :
- SortedVector<audio_channel_mask_t>(sv) {}
- ChannelsVector& operator=(const ChannelsVector&) = default;
-
- // Applies audio_channel_mask_out_to_in to all elements and returns the result.
- ChannelsVector asInMask() const;
- // Applies audio_channel_mask_in_to_out to all elements and returns the result.
- ChannelsVector asOutMask() const;
-};
-
-class AudioProfile : public virtual RefBase
-{
-public:
- static sp<AudioProfile> createFullDynamic();
-
- AudioProfile(audio_format_t format, audio_channel_mask_t channelMasks, uint32_t samplingRate);
- AudioProfile(audio_format_t format,
- const ChannelsVector &channelMasks,
- const SampleRateVector &samplingRateCollection);
-
- audio_format_t getFormat() const { return mFormat; }
- const ChannelsVector &getChannels() const { return mChannelMasks; }
- const SampleRateVector &getSampleRates() const { return mSamplingRates; }
- void setChannels(const ChannelsVector &channelMasks);
- void setSampleRates(const SampleRateVector &sampleRates);
-
- void clear();
- bool isValid() const { return hasValidFormat() && hasValidRates() && hasValidChannels(); }
- bool supportsChannels(audio_channel_mask_t channels) const
- {
- return mChannelMasks.indexOf(channels) >= 0;
- }
- bool supportsRate(uint32_t rate) const { return mSamplingRates.indexOf(rate) >= 0; }
-
- status_t checkExact(uint32_t rate, audio_channel_mask_t channels, audio_format_t format) const;
- status_t checkCompatibleChannelMask(audio_channel_mask_t channelMask,
- audio_channel_mask_t &updatedChannelMask,
- audio_port_type_t portType,
- audio_port_role_t portRole) const;
- status_t checkCompatibleSamplingRate(uint32_t samplingRate,
- uint32_t &updatedSamplingRate) const;
-
- bool hasValidFormat() const { return mFormat != AUDIO_FORMAT_DEFAULT; }
- bool hasValidRates() const { return !mSamplingRates.isEmpty(); }
- bool hasValidChannels() const { return !mChannelMasks.isEmpty(); }
-
- void setDynamicChannels(bool dynamic) { mIsDynamicChannels = dynamic; }
- bool isDynamicChannels() const { return mIsDynamicChannels; }
-
- void setDynamicRate(bool dynamic) { mIsDynamicRate = dynamic; }
- bool isDynamicRate() const { return mIsDynamicRate; }
-
- void setDynamicFormat(bool dynamic) { mIsDynamicFormat = dynamic; }
- bool isDynamicFormat() const { return mIsDynamicFormat; }
-
- bool isDynamic() { return mIsDynamicFormat || mIsDynamicChannels || mIsDynamicRate; }
-
- void dump(String8 *dst, int spaces) const;
-
-private:
- String8 mName;
- audio_format_t mFormat;
- ChannelsVector mChannelMasks;
- SampleRateVector mSamplingRates;
-
- bool mIsDynamicFormat = false;
- bool mIsDynamicChannels = false;
- bool mIsDynamicRate = false;
-};
-
-
-class AudioProfileVector : public Vector<sp<AudioProfile> >
-{
-public:
- ssize_t add(const sp<AudioProfile> &profile);
- // This API is intended to be used by the policy manager once retrieving capabilities
- // for a profile with dynamic format, rate and channels attributes
- ssize_t addProfileFromHal(const sp<AudioProfile> &profileToAdd);
-
- status_t checkExactProfile(uint32_t samplingRate, audio_channel_mask_t channelMask,
- audio_format_t format) const;
- status_t checkCompatibleProfile(uint32_t &samplingRate, audio_channel_mask_t &channelMask,
- audio_format_t &format,
- audio_port_type_t portType,
- audio_port_role_t portRole) const;
- void clearProfiles();
- // Assuming that this profile vector contains input profiles,
- // find the best matching config from 'outputProfiles', according to
- // the given preferences for audio formats and channel masks.
- // Note: std::vectors are used because specialized containers for formats
- // and channels can be sorted and use their own ordering.
- status_t findBestMatchingOutputConfig(const AudioProfileVector& outputProfiles,
- const std::vector<audio_format_t>& preferredFormats, // order: most pref -> least pref
- const std::vector<audio_channel_mask_t>& preferredOutputChannels,
- bool preferHigherSamplingRates,
- audio_config_base *bestOutputConfig) const;
-
- sp<AudioProfile> getFirstValidProfile() const;
- sp<AudioProfile> getFirstValidProfileFor(audio_format_t format) const;
- bool hasValidProfile() const { return getFirstValidProfile() != 0; }
-
- FormatVector getSupportedFormats() const;
- bool hasDynamicChannelsFor(audio_format_t format) const;
- bool hasDynamicFormat() const { return getProfileFor(gDynamicFormat) != 0; }
- bool hasDynamicProfile() const;
- bool hasDynamicRateFor(audio_format_t format) const;
-
- // One audio profile will be added for each format supported by Audio HAL
- void setFormats(const FormatVector &formats);
-
- void dump(String8 *dst, int spaces) const;
-
-private:
- sp<AudioProfile> getProfileFor(audio_format_t format) const;
- void setSampleRatesFor(const SampleRateVector &sampleRates, audio_format_t format);
- void setChannelsFor(const ChannelsVector &channelMasks, audio_format_t format);
-
- static int compareFormats(const sp<AudioProfile> *profile1, const sp<AudioProfile> *profile2);
-};
-
-bool operator == (const AudioProfile &left, const AudioProfile &right);
-
-} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioProfileVectorHelper.h b/services/audiopolicy/common/managerdefinitions/include/AudioProfileVectorHelper.h
new file mode 100644
index 0000000..f84bda7
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioProfileVectorHelper.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <media/AudioProfile.h>
+#include <system/audio.h>
+
+namespace android {
+
+void sortAudioProfiles(AudioProfileVector &audioProfileVector);
+
+ssize_t addAudioProfileAndSort(AudioProfileVector &audioProfileVector,
+ const sp<AudioProfile> &profile);
+
+// One audio profile will be added for each format supported by Audio HAL
+void addProfilesForFormats(AudioProfileVector &audioProfileVector,
+ const FormatVector &formatVector);
+
+// This API is intended to be used by the policy manager once retrieving capabilities
+// for a profile with dynamic format, rate and channels attributes
+void addDynamicAudioProfileAndSort(AudioProfileVector &audioProfileVector,
+ const sp<AudioProfile> &profileToAdd);
+
+void appendAudioProfiles(AudioProfileVector &audioProfileVector,
+ const AudioProfileVector &audioProfileVectorToAppend);
+
+status_t checkExactProfile(const AudioProfileVector &audioProfileVector,
+ const uint32_t samplingRate,
+ audio_channel_mask_t channelMask,
+ audio_format_t format);
+
+status_t checkCompatibleProfile(const AudioProfileVector &audioProfileVector,
+ uint32_t &samplingRate,
+ audio_channel_mask_t &channelMask,
+ audio_format_t &format,
+ audio_port_type_t portType,
+ audio_port_role_t portRole);
+
+// Assuming that this profile vector contains input profiles,
+// find the best matching config from 'outputProfiles', according to
+// the given preferences for audio formats and channel masks.
+// Note: std::vectors are used because specialized containers for formats
+// and channels can be sorted and use their own ordering.
+status_t findBestMatchingOutputConfig(
+ const AudioProfileVector &audioProfileVector,
+ const AudioProfileVector &outputProfileVector,
+ const std::vector<audio_format_t> &preferredFormatVector, // order: most pref -> least pref
+ const std::vector<audio_channel_mask_t> &preferredOutputChannelVector,
+ bool preferHigherSamplingRates,
+ audio_config_base &bestOutputConfig);
+
+
+} // namespace android
\ No newline at end of file
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h b/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h
index 0357ff4..a7def3e 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h
@@ -25,7 +25,7 @@
namespace android
{
-class AudioPort;
+class PolicyAudioPort;
class DeviceDescriptor;
typedef enum {
@@ -38,11 +38,11 @@
public:
explicit AudioRoute(audio_route_type_t type) : mType(type) {}
- void setSources(const AudioPortVector &sources) { mSources = sources; }
- const AudioPortVector &getSources() const { return mSources; }
+ void setSources(const PolicyAudioPortVector &sources) { mSources = sources; }
+ const PolicyAudioPortVector &getSources() const { return mSources; }
- void setSink(const sp<AudioPort> &sink) { mSink = sink; }
- const sp<AudioPort> &getSink() const { return mSink; }
+ void setSink(const sp<PolicyAudioPort> &sink) { mSink = sink; }
+ const sp<PolicyAudioPort> &getSink() const { return mSink; }
audio_route_type_t getType() const { return mType; }
@@ -57,13 +57,14 @@
* @return true if the audio route supports the connection between the sink and the source,
* false otherwise
*/
- bool supportsPatch(const sp<AudioPort> &srcPort, const sp<AudioPort> &dstPort) const;
+ bool supportsPatch(const sp<PolicyAudioPort> &srcPort,
+ const sp<PolicyAudioPort> &dstPort) const;
void dump(String8 *dst, int spaces) const;
private:
- AudioPortVector mSources;
- sp<AudioPort> mSink;
+ PolicyAudioPortVector mSources;
+ sp<PolicyAudioPort> mSink;
audio_route_type_t mType;
};
diff --git a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
index 0d05a63..0c5d1d0 100644
--- a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
@@ -183,13 +183,17 @@
{
public:
SourceClientDescriptor(audio_port_handle_t portId, uid_t uid, audio_attributes_t attributes,
- const sp<AudioPatch>& patchDesc, const sp<DeviceDescriptor>& srcDevice,
+ const struct audio_port_config &config,
+ const sp<DeviceDescriptor>& srcDevice,
audio_stream_type_t stream, product_strategy_t strategy,
VolumeSource volumeSource);
+
~SourceClientDescriptor() override = default;
- sp<AudioPatch> patchDesc() const { return mPatchDesc; }
- sp<DeviceDescriptor> srcDevice() const { return mSrcDevice; };
+ audio_patch_handle_t getPatchHandle() const { return mPatchHandle; }
+ void setPatchHandle(audio_patch_handle_t patchHandle) { mPatchHandle = patchHandle; }
+
+ sp<DeviceDescriptor> srcDevice() const { return mSrcDevice; }
wp<SwAudioOutputDescriptor> swOutput() const { return mSwOutput; }
void setSwOutput(const sp<SwAudioOutputDescriptor>& swOutput);
wp<HwAudioOutputDescriptor> hwOutput() const { return mHwOutput; }
@@ -199,7 +203,7 @@
void dump(String8 *dst, int spaces, int index) const override;
private:
- const sp<AudioPatch> mPatchDesc;
+ audio_patch_handle_t mPatchHandle = AUDIO_PATCH_HANDLE_NONE;
const sp<DeviceDescriptor> mSrcDevice;
wp<SwAudioOutputDescriptor> mSwOutput;
wp<HwAudioOutputDescriptor> mHwOutput;
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index 33e506f..a6562d7 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -16,7 +16,9 @@
#pragma once
-#include "AudioPort.h"
+#include "PolicyAudioPort.h"
+#include <media/AudioContainers.h>
+#include <media/DeviceDescriptorBase.h>
#include <utils/Errors.h>
#include <utils/String8.h>
#include <utils/SortedVector.h>
@@ -26,21 +28,26 @@
namespace android {
-class DeviceDescriptor : public AudioPort, public AudioPortConfig
+class DeviceDescriptor : public DeviceDescriptorBase,
+ public PolicyAudioPort, public PolicyAudioPortConfig
{
public:
// Note that empty name refers by convention to a generic device.
- explicit DeviceDescriptor(audio_devices_t type, const String8 &tagName = String8(""));
- DeviceDescriptor(audio_devices_t type, const FormatVector &encodedFormats,
- const String8 &tagName = String8(""));
+ explicit DeviceDescriptor(audio_devices_t type);
+ DeviceDescriptor(audio_devices_t type, const std::string &tagName,
+ const FormatVector &encodedFormats = FormatVector{});
+ DeviceDescriptor(audio_devices_t type, const std::string &tagName,
+ const std::string &address, const FormatVector &encodedFormats = FormatVector{});
+ DeviceDescriptor(const AudioDeviceTypeAddr &deviceTypeAddr, const std::string &tagName = "",
+ const FormatVector &encodedFormats = FormatVector{});
virtual ~DeviceDescriptor() {}
- virtual const String8 getTagName() const { return mTagName; }
+ virtual void addAudioProfile(const sp<AudioProfile> &profile) {
+ addAudioProfileAndSort(mProfiles, profile);
+ }
- audio_devices_t type() const { return mDeviceType; }
- String8 address() const { return mAddress; }
- void setAddress(const String8 &address) { mAddress = address; }
+ virtual const std::string getTagName() const { return mTagName; }
const FormatVector& encodedFormats() const { return mEncodedFormats; }
@@ -56,36 +63,42 @@
bool supportsFormat(audio_format_t format);
+ // PolicyAudioPortConfig
+ virtual sp<PolicyAudioPort> getPolicyAudioPort() const {
+ return static_cast<PolicyAudioPort*>(const_cast<DeviceDescriptor*>(this));
+ }
+
// AudioPortConfig
- virtual sp<AudioPort> getAudioPort() const { return (AudioPort*) this; }
+ virtual status_t applyAudioPortConfig(const struct audio_port_config *config,
+ struct audio_port_config *backupConfig = NULL);
virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
const struct audio_port_config *srcConfig = NULL) const;
- // AudioPort
+ // PolicyAudioPort
+ virtual sp<AudioPort> asAudioPort() const {
+ return static_cast<AudioPort*>(const_cast<DeviceDescriptor*>(this));
+ }
virtual void attach(const sp<HwModule>& module);
virtual void detach();
+ // AudioPort
virtual void toAudioPort(struct audio_port *port) const;
- virtual void importAudioPort(const sp<AudioPort>& port, bool force = false);
- audio_port_handle_t getId() const;
+ void importAudioPortAndPickAudioProfile(const sp<PolicyAudioPort>& policyPort,
+ bool force = false);
+
void dump(String8 *dst, int spaces, int index, bool verbose = true) const;
- void log() const;
- std::string toString() const;
private:
- String8 mAddress{""};
- String8 mTagName; // Unique human readable identifier for a device port found in conf file.
- audio_devices_t mDeviceType;
+ std::string mTagName; // Unique human readable identifier for a device port found in conf file.
FormatVector mEncodedFormats;
- audio_port_handle_t mId = AUDIO_PORT_HANDLE_NONE;
audio_format_t mCurrentEncodedFormat;
};
class DeviceVector : public SortedVector<sp<DeviceDescriptor> >
{
public:
- DeviceVector() : SortedVector(), mDeviceTypes(AUDIO_DEVICE_NONE) {}
+ DeviceVector() : SortedVector() {}
explicit DeviceVector(const sp<DeviceDescriptor>& item) : DeviceVector()
{
add(item);
@@ -97,13 +110,16 @@
void remove(const DeviceVector &devices);
ssize_t indexOf(const sp<DeviceDescriptor>& item) const;
- audio_devices_t types() const { return mDeviceTypes; }
+ DeviceTypeSet types() const { return mDeviceTypes; }
// If 'address' is empty and 'codec' is AUDIO_FORMAT_DEFAULT, a device with a non-empty
// address may be returned if there is no device with the specified 'type' and empty address.
sp<DeviceDescriptor> getDevice(audio_devices_t type, const String8 &address,
audio_format_t codec) const;
- DeviceVector getDevicesFromTypeMask(audio_devices_t types) const;
+ DeviceVector getDevicesFromTypes(const DeviceTypeSet& types) const;
+ DeviceVector getDevicesFromType(audio_devices_t type) const {
+ return getDevicesFromTypes({type});
+ }
/**
* @brief getDeviceFromId
@@ -112,9 +128,35 @@
* equal to AUDIO_PORT_HANDLE_NONE, it also returns a nullptr.
*/
sp<DeviceDescriptor> getDeviceFromId(audio_port_handle_t id) const;
- sp<DeviceDescriptor> getDeviceFromTagName(const String8 &tagName) const;
+ sp<DeviceDescriptor> getDeviceFromTagName(const std::string &tagName) const;
DeviceVector getDevicesFromHwModule(audio_module_handle_t moduleHandle) const;
- audio_devices_t getDeviceTypesFromHwModule(audio_module_handle_t moduleHandle) const;
+
+ DeviceVector getFirstDevicesFromTypes(std::vector<audio_devices_t> orderedTypes) const;
+ sp<DeviceDescriptor> getFirstExistingDevice(std::vector<audio_devices_t> orderedTypes) const;
+
+ // Return device descriptor that is used to open an input/output stream.
+ // Null pointer will be returned if
+ // 1) this collection is empty
+ // 2) the device descriptors are not the same category(input or output)
+ // 3) there are more than one device type for input case
+ // 4) the combination of all devices is invalid for selection
+ sp<DeviceDescriptor> getDeviceForOpening() const;
+
+ // If there are devices with the given type and the devices to add is not empty,
+ // remove all the devices with the given type and add all the devices to add.
+ void replaceDevicesByType(audio_devices_t typeToRemove, const DeviceVector &devicesToAdd);
+
+ bool containsDeviceAmongTypes(const DeviceTypeSet& deviceTypes) const {
+ return !Intersection(mDeviceTypes, deviceTypes).empty();
+ }
+
+ bool containsDeviceWithType(audio_devices_t deviceType) const {
+ return containsDeviceAmongTypes({deviceType});
+ }
+
+ bool onlyContainsDevicesWithType(audio_devices_t deviceType) const {
+ return isSingleDeviceType(mDeviceTypes, deviceType);
+ }
bool contains(const sp<DeviceDescriptor>& item) const { return indexOf(item) >= 0; }
@@ -196,7 +238,7 @@
{
for (const auto &device : *this) {
if (device->address() != "") {
- return device->address();
+ return String8(device->address().c_str());
}
}
return String8("");
@@ -208,7 +250,7 @@
private:
void refreshTypes();
- audio_devices_t mDeviceTypes;
+ DeviceTypeSet mDeviceTypes;
};
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/HwModule.h b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
index eb34da4..23f0c9a 100644
--- a/services/audiopolicy/common/managerdefinitions/include/HwModule.h
+++ b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
@@ -82,19 +82,19 @@
status_t addInputProfile(const sp<IOProfile> &profile);
status_t addProfile(const sp<IOProfile> &profile);
- status_t addOutputProfile(const String8& name, const audio_config_t *config,
+ status_t addOutputProfile(const std::string& name, const audio_config_t *config,
audio_devices_t device, const String8& address);
- status_t removeOutputProfile(const String8& name);
- status_t addInputProfile(const String8& name, const audio_config_t *config,
+ status_t removeOutputProfile(const std::string& name);
+ status_t addInputProfile(const std::string& name, const audio_config_t *config,
audio_devices_t device, const String8& address);
- status_t removeInputProfile(const String8& name);
+ status_t removeInputProfile(const std::string& name);
audio_module_handle_t getHandle() const { return mHandle; }
void setHandle(audio_module_handle_t handle);
- sp<AudioPort> findPortByTagName(const String8 &tagName) const
+ sp<PolicyAudioPort> findPortByTagName(const std::string &tagName) const
{
- return mPorts.findByTagName(tagName);
+ return findByTagName(mPorts, tagName);
}
/**
@@ -106,7 +106,8 @@
* @return true if the HwModule supports the connection between the sink and the source,
* false otherwise
*/
- bool supportsPatch(const sp<AudioPort> &srcPort, const sp<AudioPort> &dstPort) const;
+ bool supportsPatch(const sp<PolicyAudioPort> &srcPort,
+ const sp<PolicyAudioPort> &dstPort) const;
// TODO remove from here (split serialization)
void dump(String8 *dst) const;
@@ -122,7 +123,7 @@
DeviceVector mDeclaredDevices; // devices declared in audio_policy configuration file.
DeviceVector mDynamicDevices; /**< devices that can be added/removed at runtime (e.g. rsbumix)*/
AudioRouteVector mRoutes;
- AudioPortVector mPorts;
+ PolicyAudioPortVector mPorts;
};
class HwModuleCollection : public Vector<sp<HwModule> >
@@ -130,8 +131,8 @@
public:
sp<HwModule> getModuleFromName(const char *name) const;
- sp<HwModule> getModuleForDeviceTypes(audio_devices_t device,
- audio_format_t encodedFormat) const;
+ sp<HwModule> getModuleForDeviceType(audio_devices_t device,
+ audio_format_t encodedFormat) const;
sp<HwModule> getModuleForDevice(const sp<DeviceDescriptor> &device,
audio_format_t encodedFormat) const;
diff --git a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
index e0b56d4..5f551d5 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
@@ -16,8 +16,10 @@
#pragma once
-#include "AudioPort.h"
#include "DeviceDescriptor.h"
+#include "PolicyAudioPort.h"
+#include "policy.h"
+#include <media/AudioContainers.h>
#include <utils/String8.h>
#include <system/audio.h>
@@ -30,18 +32,28 @@
// It is used by the policy manager to determine if an output or input is suitable for
// a given use case, open/close it accordingly and connect/disconnect audio tracks
// to/from it.
-class IOProfile : public AudioPort
+class IOProfile : public AudioPort, public PolicyAudioPort
{
public:
- IOProfile(const String8 &name, audio_port_role_t role)
+ IOProfile(const std::string &name, audio_port_role_t role)
: AudioPort(name, AUDIO_PORT_TYPE_MIX, role),
maxOpenCount(1),
curOpenCount(0),
maxActiveCount(1),
curActiveCount(0) {}
+ virtual ~IOProfile() = default;
+
// For a Profile aka MixPort, tag name and name are equivalent.
- virtual const String8 getTagName() const { return getName(); }
+ virtual const std::string getTagName() const { return getName(); }
+
+ virtual void addAudioProfile(const sp<AudioProfile> &profile) {
+ addAudioProfileAndSort(mProfiles, profile);
+ }
+
+ virtual sp<AudioPort> asAudioPort() const {
+ return static_cast<AudioPort*>(const_cast<IOProfile*>(this));
+ }
// FIXME: this is needed because shared MMAP stream clients use the same audio session.
// Once capture clients are tracked individually and not per session this can be removed
@@ -51,7 +63,7 @@
// flags are parsed before maxActiveCount by the serializer.
void setFlags(uint32_t flags) override
{
- AudioPort::setFlags(flags);
+ PolicyAudioPort::setFlags(flags);
if (getRole() == AUDIO_PORT_ROLE_SINK && (flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0) {
maxActiveCount = 0;
}
@@ -91,15 +103,12 @@
bool hasSupportedDevices() const { return !mSupportedDevices.isEmpty(); }
- bool supportsDeviceTypes(audio_devices_t device) const
+ bool supportsDeviceTypes(const DeviceTypeSet& deviceTypes) const
{
- if (audio_is_output_devices(device)) {
- if (deviceSupportsEncodedFormats(device)) {
- return mSupportedDevices.types() & device;
- }
- return false;
- }
- return mSupportedDevices.types() & (device & ~AUDIO_DEVICE_BIT_IN);
+ const bool areOutputDevices = Intersection(deviceTypes, getAudioDeviceInAllSet()).empty();
+ const bool devicesSupported = !mSupportedDevices.getDevicesFromTypes(deviceTypes).empty();
+ return devicesSupported &&
+ (!areOutputDevices || devicesSupportEncodedFormats(deviceTypes));
}
/**
@@ -114,20 +123,22 @@
bool supportsDevice(const sp<DeviceDescriptor> &device, bool forceCheckOnAddress = false) const
{
if (!device_distinguishes_on_address(device->type()) && !forceCheckOnAddress) {
- return supportsDeviceTypes(device->type());
+ return supportsDeviceTypes(DeviceTypeSet({device->type()}));
}
return mSupportedDevices.contains(device);
}
- bool deviceSupportsEncodedFormats(audio_devices_t device) const
+ bool devicesSupportEncodedFormats(DeviceTypeSet deviceTypes) const
{
- if (device == AUDIO_DEVICE_NONE) {
+ if (deviceTypes.empty()) {
return true; // required for isOffloadSupported() check
}
DeviceVector deviceList =
- mSupportedDevices.getDevicesFromTypeMask(device);
- if (!deviceList.empty()) {
- return deviceList.itemAt(0)->hasCurrentEncodedFormat();
+ mSupportedDevices.getDevicesFromTypes(deviceTypes);
+ for (const auto& device : deviceList) {
+ if (device->hasCurrentEncodedFormat()) {
+ return true;
+ }
}
return false;
}
@@ -183,13 +194,13 @@
class InputProfile : public IOProfile
{
public:
- explicit InputProfile(const String8 &name) : IOProfile(name, AUDIO_PORT_ROLE_SINK) {}
+ explicit InputProfile(const std::string &name) : IOProfile(name, AUDIO_PORT_ROLE_SINK) {}
};
class OutputProfile : public IOProfile
{
public:
- explicit OutputProfile(const String8 &name) : IOProfile(name, AUDIO_PORT_ROLE_SOURCE) {}
+ explicit OutputProfile(const std::string &name) : IOProfile(name, AUDIO_PORT_ROLE_SOURCE) {}
};
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h
index d408446..fd8b81a 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h
@@ -16,8 +16,9 @@
#pragma once
-#include <system/audio.h>
#include <Volume.h>
+#include <media/AudioContainers.h>
+#include <system/audio.h>
#include <utils/Errors.h>
#include <utils/String8.h>
#include <vector>
@@ -33,7 +34,7 @@
virtual void addCurrentVolumeIndex(audio_devices_t device, int index) = 0;
virtual bool canBeMuted() const = 0;
virtual int getVolumeIndexMin() const = 0;
- virtual int getVolumeIndex(audio_devices_t device) const = 0;
+ virtual int getVolumeIndex(const DeviceTypeSet& device) const = 0;
virtual int getVolumeIndexMax() const = 0;
virtual float volIndexToDb(device_category device, int indexInUi) const = 0;
virtual bool hasVolumeIndexForDevice(audio_devices_t device) const = 0;
diff --git a/services/audiopolicy/common/managerdefinitions/include/PolicyAudioPort.h b/services/audiopolicy/common/managerdefinitions/include/PolicyAudioPort.h
new file mode 100644
index 0000000..99df3c0
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/PolicyAudioPort.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "AudioCollections.h"
+#include "AudioProfileVectorHelper.h"
+#include "HandleGenerator.h"
+#include <media/AudioGain.h>
+#include <media/AudioPort.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <system/audio.h>
+#include <cutils/config_utils.h>
+
+namespace android {
+
+class HwModule;
+class AudioRoute;
+
+class PolicyAudioPort : public virtual RefBase, private HandleGenerator<audio_port_handle_t>
+{
+public:
+ PolicyAudioPort() : mFlags(AUDIO_OUTPUT_FLAG_NONE) {}
+
+ virtual ~PolicyAudioPort() = default;
+
+ virtual const std::string getTagName() const = 0;
+
+ virtual sp<AudioPort> asAudioPort() const = 0;
+
+ virtual void setFlags(uint32_t flags)
+ {
+ //force direct flag if offload flag is set: offloading implies a direct output stream
+ // and all common behaviors are driven by checking only the direct flag
+ // this should normally be set appropriately in the policy configuration file
+ if (asAudioPort()->getRole() == AUDIO_PORT_ROLE_SOURCE &&
+ (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
+ flags |= AUDIO_OUTPUT_FLAG_DIRECT;
+ }
+ mFlags = flags;
+ }
+ uint32_t getFlags() const { return mFlags; }
+
+ virtual void attach(const sp<HwModule>& module);
+ virtual void detach();
+ bool isAttached() { return mModule != 0; }
+
+ // Audio port IDs are in a different namespace than AudioFlinger unique IDs
+ static audio_port_handle_t getNextUniqueId();
+
+ // searches for an exact match
+ virtual status_t checkExactAudioProfile(const struct audio_port_config *config) const;
+
+ // searches for a compatible match, currently implemented for input
+ // parameters are input|output, returned value is the best match.
+ status_t checkCompatibleAudioProfile(uint32_t &samplingRate,
+ audio_channel_mask_t &channelMask,
+ audio_format_t &format) const
+ {
+ return checkCompatibleProfile(
+ asAudioPort()->getAudioProfiles(), samplingRate, channelMask, format,
+ asAudioPort()->getType(), asAudioPort()->getRole());
+ }
+
+ void pickAudioProfile(uint32_t &samplingRate,
+ audio_channel_mask_t &channelMask,
+ audio_format_t &format) const;
+
+ static const audio_format_t sPcmFormatCompareTable[];
+
+ static int compareFormats(audio_format_t format1, audio_format_t format2);
+
+ // Used to select an audio HAL output stream with a sample format providing the
+ // less degradation for a given AudioTrack sample format.
+ static bool isBetterFormatMatch(audio_format_t newFormat,
+ audio_format_t currentFormat,
+ audio_format_t targetFormat);
+ static uint32_t formatDistance(audio_format_t format1,
+ audio_format_t format2);
+ static const uint32_t kFormatDistanceMax = 4;
+
+ audio_module_handle_t getModuleHandle() const;
+ uint32_t getModuleVersionMajor() const;
+ const char *getModuleName() const;
+ sp<HwModule> getModule() const { return mModule; }
+
+ inline bool isDirectOutput() const
+ {
+ return (asAudioPort()->getType() == AUDIO_PORT_TYPE_MIX) &&
+ (asAudioPort()->getRole() == AUDIO_PORT_ROLE_SOURCE) &&
+ (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD));
+ }
+
+ void addRoute(const sp<AudioRoute> &route) { mRoutes.add(route); }
+ const AudioRouteVector &getRoutes() const { return mRoutes; }
+
+private:
+ void pickChannelMask(audio_channel_mask_t &channelMask,
+ const ChannelMaskSet &channelMasks) const;
+ void pickSamplingRate(uint32_t &rate, const SampleRateSet &samplingRates) const;
+
+ uint32_t mFlags; // attribute flags mask (e.g primary output, direct output...).
+ sp<HwModule> mModule; // audio HW module exposing this I/O stream
+ AudioRouteVector mRoutes; // Routes involving this port
+};
+
+class PolicyAudioPortConfig : public virtual RefBase
+{
+public:
+ virtual ~PolicyAudioPortConfig() = default;
+
+ virtual sp<PolicyAudioPort> getPolicyAudioPort() const = 0;
+
+ status_t validationBeforeApplyConfig(const struct audio_port_config *config) const;
+
+ void applyPolicyAudioPortConfig(const struct audio_port_config *config) {
+ if (config->config_mask & AUDIO_PORT_CONFIG_FLAGS) {
+ mFlags = config->flags;
+ }
+ }
+
+ void toPolicyAudioPortConfig(
+ struct audio_port_config *dstConfig,
+ const struct audio_port_config *srcConfig = NULL) const;
+
+
+ virtual bool hasSameHwModuleAs(const sp<PolicyAudioPortConfig>& other) const {
+ return (other.get() != nullptr) && (other->getPolicyAudioPort().get() != nullptr) &&
+ (getPolicyAudioPort().get() != nullptr) &&
+ (other->getPolicyAudioPort()->getModuleHandle() ==
+ getPolicyAudioPort()->getModuleHandle());
+ }
+
+ union audio_io_flags mFlags = { AUDIO_INPUT_FLAG_NONE };
+};
+
+} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/audio_policy_conf.h b/services/audiopolicy/common/managerdefinitions/include/audio_policy_conf.h
deleted file mode 100644
index 0a27947..0000000
--- a/services/audiopolicy/common/managerdefinitions/include/audio_policy_conf.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-
-/////////////////////////////////////////////////
-// Definitions for audio policy configuration file (audio_policy.conf)
-/////////////////////////////////////////////////
-
-#define AUDIO_HARDWARE_MODULE_ID_MAX_LEN 32
-
-#define AUDIO_POLICY_CONFIG_FILE "/system/etc/audio_policy.conf"
-#define AUDIO_POLICY_VENDOR_CONFIG_FILE "/vendor/etc/audio_policy.conf"
-
-// global configuration
-#define GLOBAL_CONFIG_TAG "global_configuration"
-
-#define ATTACHED_OUTPUT_DEVICES_TAG "attached_output_devices"
-#define DEFAULT_OUTPUT_DEVICE_TAG "default_output_device"
-#define ATTACHED_INPUT_DEVICES_TAG "attached_input_devices"
-#define SPEAKER_DRC_ENABLED_TAG "speaker_drc_enabled"
-#define AUDIO_HAL_VERSION_TAG "audio_hal_version"
-
-// hw modules descriptions
-#define AUDIO_HW_MODULE_TAG "audio_hw_modules"
-
-#define OUTPUTS_TAG "outputs"
-#define INPUTS_TAG "inputs"
-
-#define SAMPLING_RATES_TAG "sampling_rates"
-#define FORMATS_TAG "formats"
-#define CHANNELS_TAG "channel_masks"
-#define DEVICES_TAG "devices"
-#define FLAGS_TAG "flags"
-
-#define APM_DEVICES_TAG "devices"
-#define APM_DEVICE_TYPE "type"
-#define APM_DEVICE_ADDRESS "address"
-
-#define MIXERS_TAG "mixers"
-#define MIXER_TYPE "type"
-#define MIXER_TYPE_MUX "mux"
-#define MIXER_TYPE_MIX "mix"
-
-#define GAINS_TAG "gains"
-#define GAIN_MODE "mode"
-#define GAIN_CHANNELS "channel_mask"
-#define GAIN_MIN_VALUE "min_value_mB"
-#define GAIN_MAX_VALUE "max_value_mB"
-#define GAIN_DEFAULT_VALUE "default_value_mB"
-#define GAIN_STEP_VALUE "step_value_mB"
-#define GAIN_MIN_RAMP_MS "min_ramp_ms"
-#define GAIN_MAX_RAMP_MS "max_ramp_ms"
-
-#define DYNAMIC_VALUE_TAG "dynamic" // special value for "channel_masks", "sampling_rates" and
- // "formats" in outputs descriptors indicating that supported
- // values should be queried after opening the output.
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp
index c90a582..cd10010 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp
@@ -18,16 +18,16 @@
//#define LOG_NDEBUG 0
#include "AudioCollections.h"
-#include "AudioPort.h"
#include "AudioRoute.h"
#include "HwModule.h"
-#include "AudioGain.h"
+#include "PolicyAudioPort.h"
namespace android {
-sp<AudioPort> AudioPortVector::findByTagName(const String8 &tagName) const
+sp<PolicyAudioPort> findByTagName(const PolicyAudioPortVector& policyAudioPortVector,
+ const std::string &tagName)
{
- for (const auto& port : *this) {
+ for (const auto& port : policyAudioPortVector) {
if (port->getTagName() == tagName) {
return port;
}
@@ -35,15 +35,15 @@
return nullptr;
}
-void AudioRouteVector::dump(String8 *dst, int spaces) const
+void dumpAudioRouteVector(const AudioRouteVector& audioRouteVector, String8 *dst, int spaces)
{
- if (isEmpty()) {
+ if (audioRouteVector.isEmpty()) {
return;
}
- dst->appendFormat("\n%*sAudio Routes (%zu):\n", spaces, "", size());
- for (size_t i = 0; i < size(); i++) {
+ dst->appendFormat("\n%*sAudio Routes (%zu):\n", spaces, "", audioRouteVector.size());
+ for (size_t i = 0; i < audioRouteVector.size(); i++) {
dst->appendFormat("%*s- Route %zu:\n", spaces, "", i + 1);
- itemAt(i)->dump(dst, 4);
+ audioRouteVector.itemAt(i)->dump(dst, 4);
}
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp
deleted file mode 100644
index 2725870..0000000
--- a/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "APM::AudioGain"
-//#define LOG_NDEBUG 0
-
-//#define VERY_VERBOSE_LOGGING
-#ifdef VERY_VERBOSE_LOGGING
-#define ALOGVV ALOGV
-#else
-#define ALOGVV(a...) do { } while(0)
-#endif
-
-#include "AudioGain.h"
-#include <utils/Log.h>
-#include <utils/String8.h>
-
-#include <math.h>
-
-namespace android {
-
-AudioGain::AudioGain(int index, bool useInChannelMask)
-{
- mIndex = index;
- mUseInChannelMask = useInChannelMask;
- memset(&mGain, 0, sizeof(struct audio_gain));
-}
-
-void AudioGain::getDefaultConfig(struct audio_gain_config *config)
-{
- config->index = mIndex;
- config->mode = mGain.mode;
- config->channel_mask = mGain.channel_mask;
- if ((mGain.mode & AUDIO_GAIN_MODE_JOINT) == AUDIO_GAIN_MODE_JOINT) {
- config->values[0] = mGain.default_value;
- } else {
- uint32_t numValues;
- if (mUseInChannelMask) {
- numValues = audio_channel_count_from_in_mask(mGain.channel_mask);
- } else {
- numValues = audio_channel_count_from_out_mask(mGain.channel_mask);
- }
- for (size_t i = 0; i < numValues; i++) {
- config->values[i] = mGain.default_value;
- }
- }
- if ((mGain.mode & AUDIO_GAIN_MODE_RAMP) == AUDIO_GAIN_MODE_RAMP) {
- config->ramp_duration_ms = mGain.min_ramp_ms;
- }
-}
-
-status_t AudioGain::checkConfig(const struct audio_gain_config *config)
-{
- if ((config->mode & ~mGain.mode) != 0) {
- return BAD_VALUE;
- }
- if ((config->mode & AUDIO_GAIN_MODE_JOINT) == AUDIO_GAIN_MODE_JOINT) {
- if ((config->values[0] < mGain.min_value) ||
- (config->values[0] > mGain.max_value)) {
- return BAD_VALUE;
- }
- } else {
- if ((config->channel_mask & ~mGain.channel_mask) != 0) {
- return BAD_VALUE;
- }
- uint32_t numValues;
- if (mUseInChannelMask) {
- numValues = audio_channel_count_from_in_mask(config->channel_mask);
- } else {
- numValues = audio_channel_count_from_out_mask(config->channel_mask);
- }
- for (size_t i = 0; i < numValues; i++) {
- if ((config->values[i] < mGain.min_value) ||
- (config->values[i] > mGain.max_value)) {
- return BAD_VALUE;
- }
- }
- }
- if ((config->mode & AUDIO_GAIN_MODE_RAMP) == AUDIO_GAIN_MODE_RAMP) {
- if ((config->ramp_duration_ms < mGain.min_ramp_ms) ||
- (config->ramp_duration_ms > mGain.max_ramp_ms)) {
- return BAD_VALUE;
- }
- }
- return NO_ERROR;
-}
-
-void AudioGain::dump(String8 *dst, int spaces, int index) const
-{
- dst->appendFormat("%*sGain %d:\n", spaces, "", index+1);
- dst->appendFormat("%*s- mode: %08x\n", spaces, "", mGain.mode);
- dst->appendFormat("%*s- channel_mask: %08x\n", spaces, "", mGain.channel_mask);
- dst->appendFormat("%*s- min_value: %d mB\n", spaces, "", mGain.min_value);
- dst->appendFormat("%*s- max_value: %d mB\n", spaces, "", mGain.max_value);
- dst->appendFormat("%*s- default_value: %d mB\n", spaces, "", mGain.default_value);
- dst->appendFormat("%*s- step_value: %d mB\n", spaces, "", mGain.step_value);
- dst->appendFormat("%*s- min_ramp_ms: %d ms\n", spaces, "", mGain.min_ramp_ms);
- dst->appendFormat("%*s- max_ramp_ms: %d ms\n", spaces, "", mGain.max_ramp_ms);
-}
-
-} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index a096e8f..b963121 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -22,7 +22,6 @@
#include <policy.h>
#include <AudioPolicyInterface.h>
#include "AudioInputDescriptor.h"
-#include "AudioGain.h"
#include "AudioPolicyMix.h"
#include "HwModule.h"
@@ -35,8 +34,8 @@
{
if (profile != NULL) {
profile->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
- if (profile->mGains.size() > 0) {
- profile->mGains[0]->getDefaultConfig(&mGain);
+ if (profile->getGains().size() > 0) {
+ profile->getGains()[0]->getDefaultConfig(&mGain);
}
}
}
@@ -49,16 +48,29 @@
return mProfile->getModuleHandle();
}
-audio_port_handle_t AudioInputDescriptor::getId() const
-{
- return mId;
-}
-
audio_source_t AudioInputDescriptor::source() const
{
return getHighestPriorityAttributes().source;
}
+status_t AudioInputDescriptor::applyAudioPortConfig(const struct audio_port_config *config,
+ audio_port_config *backupConfig)
+{
+ struct audio_port_config localBackupConfig = { .config_mask = config->config_mask };
+ status_t status = NO_ERROR;
+
+ toAudioPortConfig(&localBackupConfig);
+ if ((status = validationBeforeApplyConfig(config)) == NO_ERROR) {
+ AudioPortConfig::applyAudioPortConfig(config, backupConfig);
+ applyPolicyAudioPortConfig(config);
+ }
+
+ if (backupConfig != NULL) {
+ *backupConfig = localBackupConfig;
+ }
+ return status;
+}
+
void AudioInputDescriptor::toAudioPortConfig(struct audio_port_config *dstConfig,
const struct audio_port_config *srcConfig) const
{
@@ -71,8 +83,8 @@
}
AudioPortConfig::toAudioPortConfig(dstConfig, srcConfig);
+ toPolicyAudioPortConfig(dstConfig, srcConfig);
- dstConfig->id = mId;
dstConfig->role = AUDIO_PORT_ROLE_SINK;
dstConfig->type = AUDIO_PORT_TYPE_MIX;
dstConfig->ext.mix.hw_module = getModuleHandle();
@@ -213,7 +225,7 @@
mDevice = device;
ALOGV("opening input for device %s profile %p name %s",
- mDevice->toString().c_str(), mProfile.get(), mProfile->getName().string());
+ mDevice->toString().c_str(), mProfile.get(), mProfile->getName().c_str());
audio_devices_t deviceType = mDevice->type();
@@ -221,7 +233,7 @@
input,
&lConfig,
&deviceType,
- mDevice->address(),
+ String8(mDevice->address().c_str()),
source,
flags);
LOG_ALWAYS_FATAL_IF(mDevice->type() != deviceType,
@@ -235,7 +247,7 @@
mSamplingRate = lConfig.sample_rate;
mChannelMask = lConfig.channel_mask;
mFormat = lConfig.format;
- mId = AudioPort::getNextUniqueId();
+ mId = PolicyAudioPort::getNextUniqueId();
mIoHandle = *input;
mProfile->curOpenCount++;
}
@@ -451,13 +463,13 @@
return enabledEffects;
}
-void AudioInputDescriptor::setAppState(uid_t uid, app_state_t state)
+void AudioInputDescriptor::setAppState(audio_port_handle_t portId, app_state_t state)
{
RecordClientVector clients = clientsList(false /*activeOnly*/);
RecordClientVector updatedClients;
for (const auto& client : clients) {
- if (uid == client->uid()) {
+ if (portId == client->portId()) {
bool wasSilenced = client->isSilenced();
client->setAppState(state);
if (client->active() && wasSilenced != client->isSilenced()) {
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 8a60cf2..aaa28bc 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -21,27 +21,31 @@
#include "AudioOutputDescriptor.h"
#include "AudioPolicyMix.h"
#include "IOProfile.h"
-#include "AudioGain.h"
#include "Volume.h"
#include "HwModule.h"
#include "TypeConverter.h"
+#include <media/AudioGain.h>
#include <media/AudioParameter.h>
#include <media/AudioPolicy.h>
// A device mask for all audio output devices that are considered "remote" when evaluating
// active output devices in isStreamActiveRemotely()
-#define APM_AUDIO_OUT_DEVICE_REMOTE_ALL AUDIO_DEVICE_OUT_REMOTE_SUBMIX
namespace android {
-AudioOutputDescriptor::AudioOutputDescriptor(const sp<AudioPort>& port,
+static const DeviceTypeSet& getAllOutRemoteDevices() {
+ static const DeviceTypeSet allOutRemoteDevices = {AUDIO_DEVICE_OUT_REMOTE_SUBMIX};
+ return allOutRemoteDevices;
+}
+
+AudioOutputDescriptor::AudioOutputDescriptor(const sp<PolicyAudioPort>& policyAudioPort,
AudioPolicyClientInterface *clientInterface)
- : mPort(port), mClientInterface(clientInterface)
+ : mPolicyAudioPort(policyAudioPort), mClientInterface(clientInterface)
{
- if (mPort.get() != nullptr) {
- mPort->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
- if (mPort->mGains.size() > 0) {
- mPort->mGains[0]->getDefaultConfig(&mGain);
+ if (mPolicyAudioPort.get() != nullptr) {
+ mPolicyAudioPort->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
+ if (mPolicyAudioPort->asAudioPort()->getGains().size() > 0) {
+ mPolicyAudioPort->asAudioPort()->getGains()[0]->getDefaultConfig(&mGain);
}
}
}
@@ -55,7 +59,8 @@
audio_module_handle_t AudioOutputDescriptor::getModuleHandle() const
{
- return mPort.get() != nullptr ? mPort->getModuleHandle() : AUDIO_MODULE_HANDLE_NONE;
+ return mPolicyAudioPort.get() != nullptr ?
+ mPolicyAudioPort->getModuleHandle() : AUDIO_MODULE_HANDLE_NONE;
}
audio_patch_handle_t AudioOutputDescriptor::getPatchHandle() const
@@ -68,11 +73,6 @@
mPatchHandle = handle;
}
-audio_port_handle_t AudioOutputDescriptor::getId() const
-{
- return mId;
-}
-
bool AudioOutputDescriptor::sharesHwModuleWith(
const sp<AudioOutputDescriptor>& outputDesc)
{
@@ -144,7 +144,7 @@
return false;
}
-bool AudioOutputDescriptor::isFixedVolume(audio_devices_t device __unused)
+bool AudioOutputDescriptor::isFixedVolume(const DeviceTypeSet& deviceTypes __unused)
{
return false;
}
@@ -152,7 +152,7 @@
bool AudioOutputDescriptor::setVolume(float volumeDb,
VolumeSource volumeSource,
const StreamTypeVector &/*streams*/,
- audio_devices_t /*device*/,
+ const DeviceTypeSet& /*deviceTypes*/,
uint32_t delayMs,
bool force)
{
@@ -167,9 +167,27 @@
return false;
}
-void AudioOutputDescriptor::toAudioPortConfig(
- struct audio_port_config *dstConfig,
- const struct audio_port_config *srcConfig) const
+status_t AudioOutputDescriptor::applyAudioPortConfig(const struct audio_port_config *config,
+ audio_port_config *backupConfig)
+{
+ struct audio_port_config localBackupConfig = { .config_mask = config->config_mask };
+ status_t status = NO_ERROR;
+
+ toAudioPortConfig(&localBackupConfig);
+ if ((status = validationBeforeApplyConfig(config)) == NO_ERROR) {
+ AudioPortConfig::applyAudioPortConfig(config, backupConfig);
+ applyPolicyAudioPortConfig(config);
+ }
+
+ if (backupConfig != NULL) {
+ *backupConfig = localBackupConfig;
+ }
+ return status;
+}
+
+
+void AudioOutputDescriptor::toAudioPortConfig(struct audio_port_config *dstConfig,
+ const struct audio_port_config *srcConfig) const
{
dstConfig->config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE|AUDIO_PORT_CONFIG_CHANNEL_MASK|
AUDIO_PORT_CONFIG_FORMAT|AUDIO_PORT_CONFIG_GAIN;
@@ -177,8 +195,8 @@
dstConfig->config_mask |= srcConfig->config_mask;
}
AudioPortConfig::toAudioPortConfig(dstConfig, srcConfig);
+ toPolicyAudioPortConfig(dstConfig, srcConfig);
- dstConfig->id = mId;
dstConfig->role = AUDIO_PORT_ROLE_SOURCE;
dstConfig->type = AUDIO_PORT_TYPE_MIX;
dstConfig->ext.mix.hw_module = getModuleHandle();
@@ -188,7 +206,7 @@
void AudioOutputDescriptor::toAudioPort(struct audio_port *port) const
{
// Should not be called for duplicated ports, see SwAudioOutputDescriptor::toAudioPortConfig.
- mPort->toAudioPort(port);
+ mPolicyAudioPort->asAudioPort()->toAudioPort(port);
port->id = mId;
port->ext.mix.hw_module = getModuleHandle();
}
@@ -320,13 +338,13 @@
return filteredDevices.filter(devices);
}
-bool SwAudioOutputDescriptor::deviceSupportsEncodedFormats(audio_devices_t device)
+bool SwAudioOutputDescriptor::devicesSupportEncodedFormats(const DeviceTypeSet& deviceTypes)
{
if (isDuplicated()) {
- return (mOutput1->deviceSupportsEncodedFormats(device)
- || mOutput2->deviceSupportsEncodedFormats(device));
+ return (mOutput1->devicesSupportEncodedFormats(deviceTypes)
+ || mOutput2->devicesSupportEncodedFormats(deviceTypes));
} else {
- return mProfile->deviceSupportsEncodedFormats(device);
+ return mProfile->devicesSupportEncodedFormats(deviceTypes);
}
}
@@ -349,16 +367,16 @@
AudioOutputDescriptor::setClientActive(client, active);
}
-bool SwAudioOutputDescriptor::isFixedVolume(audio_devices_t device)
+bool SwAudioOutputDescriptor::isFixedVolume(const DeviceTypeSet& deviceTypes)
{
// unit gain if rerouting to external policy
- if (device == AUDIO_DEVICE_OUT_REMOTE_SUBMIX) {
+ if (isSingleDeviceType(deviceTypes, AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) {
if (mPolicyMix != NULL) {
ALOGV("max gain when rerouting for output=%d", mIoHandle);
return true;
}
}
- if (device == AUDIO_DEVICE_OUT_TELEPHONY_TX) {
+ if (isSingleDeviceType(deviceTypes, AUDIO_DEVICE_OUT_TELEPHONY_TX)) {
ALOGV("max gain when output device is telephony tx");
return true;
}
@@ -391,12 +409,12 @@
bool SwAudioOutputDescriptor::setVolume(float volumeDb,
VolumeSource vs, const StreamTypeVector &streamTypes,
- audio_devices_t device,
+ const DeviceTypeSet& deviceTypes,
uint32_t delayMs,
bool force)
{
StreamTypeVector streams = streamTypes;
- if (!AudioOutputDescriptor::setVolume(volumeDb, vs, streamTypes, device, delayMs, force)) {
+ if (!AudioOutputDescriptor::setVolume(volumeDb, vs, streamTypes, deviceTypes, delayMs, force)) {
return false;
}
if (streams.empty()) {
@@ -406,7 +424,7 @@
// APM loops on all group, so filter on active group to set the port gain,
// let the other groups set the stream volume as per legacy
// TODO: Pass in the device address and check against it.
- if (device == devicePort->type() &&
+ if (isSingleDeviceType(deviceTypes, devicePort->type()) &&
devicePort->hasGainController(true) && isActive(vs)) {
ALOGV("%s: device %s has gain controller", __func__, devicePort->toString().c_str());
// @todo: here we might be in trouble if the SwOutput has several active clients with
@@ -452,8 +470,11 @@
audio_io_handle_t *output)
{
mDevices = devices;
- const String8& address = devices.getFirstValidAddress();
- audio_devices_t device = devices.types();
+ sp<DeviceDescriptor> device = devices.getDeviceForOpening();
+ LOG_ALWAYS_FATAL_IF(device == nullptr,
+ "%s failed to get device descriptor for opening "
+ "with the requested devices, all device types: %s",
+ __func__, dumpDeviceTypes(devices.types()).c_str());
audio_config_t lConfig;
if (config == nullptr) {
@@ -483,27 +504,25 @@
mFlags = (audio_output_flags_t)(mFlags | flags);
ALOGV("opening output for device %s profile %p name %s",
- mDevices.toString().c_str(), mProfile.get(), mProfile->getName().string());
+ mDevices.toString().c_str(), mProfile.get(), mProfile->getName().c_str());
status_t status = mClientInterface->openOutput(mProfile->getModuleHandle(),
output,
&lConfig,
- &device,
- address,
+ device,
&mLatency,
mFlags);
- LOG_ALWAYS_FATAL_IF(mDevices.types() != device,
- "%s openOutput returned device %08x when given device %08x",
- __FUNCTION__, mDevices.types(), device);
if (status == NO_ERROR) {
LOG_ALWAYS_FATAL_IF(*output == AUDIO_IO_HANDLE_NONE,
- "%s openOutput returned output handle %d for device %08x",
- __FUNCTION__, *output, device);
+ "%s openOutput returned output handle %d for device %s, "
+ "selected device %s for opening",
+ __FUNCTION__, *output, devices.toString().c_str(),
+ device->toString().c_str());
mSamplingRate = lConfig.sample_rate;
mChannelMask = lConfig.channel_mask;
mFormat = lConfig.format;
- mId = AudioPort::getNextUniqueId();
+ mId = PolicyAudioPort::getNextUniqueId();
mIoHandle = *output;
mProfile->curOpenCount++;
}
@@ -589,7 +608,7 @@
return INVALID_OPERATION;
}
- mId = AudioPort::getNextUniqueId();
+ mId = PolicyAudioPort::getNextUniqueId();
mIoHandle = *ioHandle;
mOutput1 = output1;
mOutput2 = output2;
@@ -632,12 +651,12 @@
bool HwAudioOutputDescriptor::setVolume(float volumeDb,
VolumeSource volumeSource, const StreamTypeVector &streams,
- audio_devices_t device,
+ const DeviceTypeSet& deviceTypes,
uint32_t delayMs,
bool force)
{
- bool changed =
- AudioOutputDescriptor::setVolume(volumeDb, volumeSource, streams, device, delayMs, force);
+ bool changed = AudioOutputDescriptor::setVolume(
+ volumeDb, volumeSource, streams, deviceTypes, delayMs, force);
if (changed) {
// TODO: use gain controller on source device if any to adjust volume
@@ -664,7 +683,8 @@
for (size_t i = 0; i < this->size(); i++) {
const sp<SwAudioOutputDescriptor> outputDesc = this->valueAt(i);
if (outputDesc->isActive(volumeSource, inPastMs, sysTime)
- && ((outputDesc->devices().types() & APM_AUDIO_OUT_DEVICE_REMOTE_ALL) == 0)) {
+ && (!(outputDesc->devices()
+ .containsDeviceAmongTypes(getAllOutRemoteDevices())))) {
return true;
}
}
@@ -676,7 +696,7 @@
nsecs_t sysTime = systemTime();
for (size_t i = 0; i < size(); i++) {
const sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
- if (((outputDesc->devices().types() & APM_AUDIO_OUT_DEVICE_REMOTE_ALL) != 0) &&
+ if (outputDesc->devices().containsDeviceAmongTypes(getAllOutRemoteDevices()) &&
outputDesc->isActive(volumeSource, inPastMs, sysTime)) {
// do not consider re routing (when the output is going to a dynamic policy)
// as "remote playback"
@@ -707,9 +727,8 @@
for (size_t i = 0; i < size(); i++) {
sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
if (!outputDesc->isDuplicated() &&
- outputDesc->devices().types() & AUDIO_DEVICE_OUT_ALL_A2DP &&
- outputDesc->deviceSupportsEncodedFormats(
- AUDIO_DEVICE_OUT_BLUETOOTH_A2DP)) {
+ outputDesc->devices().containsDeviceAmongTypes(getAudioDeviceOutAllA2dpSet()) &&
+ outputDesc->devicesSupportEncodedFormats(getAudioDeviceOutAllA2dpSet())) {
return this->keyAt(i);
}
}
@@ -725,7 +744,7 @@
sp<HwModule> primaryHwModule = primaryOutput->mProfile->getModule();
for (const auto &outputProfile : primaryHwModule->getOutputProfiles()) {
- if (outputProfile->supportsDeviceTypes(AUDIO_DEVICE_OUT_ALL_A2DP)) {
+ if (outputProfile->supportsDeviceTypes(getAudioDeviceOutAllA2dpSet())) {
return true;
}
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
index 3a4db90..d79110a 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
@@ -18,7 +18,6 @@
//#define LOG_NDEBUG 0
#include "AudioPatch.h"
-#include "AudioGain.h"
#include "TypeConverter.h"
#include <log/log.h>
@@ -27,10 +26,9 @@
namespace android {
AudioPatch::AudioPatch(const struct audio_patch *patch, uid_t uid) :
- mHandle(HandleGenerator<audio_patch_handle_t>::getNextHandle()),
mPatch(*patch),
- mUid(uid),
- mAfPatchHandle(AUDIO_PATCH_HANDLE_NONE)
+ mHandle(HandleGenerator<audio_patch_handle_t>::getNextHandle()),
+ mUid(uid)
{
}
@@ -69,7 +67,7 @@
add(handle, patch);
ALOGV("addAudioPatch() handle %d af handle %d num_sources %d num_sinks %d source handle %d"
"sink handle %d",
- handle, patch->mAfPatchHandle, patch->mPatch.num_sources, patch->mPatch.num_sinks,
+ handle, patch->getAfHandle(), patch->mPatch.num_sources, patch->mPatch.num_sinks,
patch->mPatch.sources[0].id, patch->mPatch.sinks[0].id);
return NO_ERROR;
}
@@ -82,7 +80,7 @@
ALOGW("removeAudioPatch() patch %d not in", handle);
return ALREADY_EXISTS;
}
- ALOGV("removeAudioPatch() handle %d af handle %d", handle, valueAt(index)->mAfPatchHandle);
+ ALOGV("removeAudioPatch() handle %d af handle %d", handle, valueAt(index)->getAfHandle());
removeItemsAt(index);
return NO_ERROR;
}
@@ -124,7 +122,7 @@
}
if (patchesWritten < patchesMax) {
patches[patchesWritten] = patch->mPatch;
- patches[patchesWritten++].id = patch->mHandle;
+ patches[patchesWritten++].id = patch->getHandle();
}
(*num_patches)++;
ALOGV("listAudioPatches() patch %zu num_sources %d num_sinks %d",
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index c42923a..ed51389 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -20,9 +20,8 @@
#include "AudioPolicyMix.h"
#include "TypeConverter.h"
#include "HwModule.h"
-#include "AudioPort.h"
+#include "PolicyAudioPort.h"
#include "IOProfile.h"
-#include "AudioGain.h"
#include <AudioOutputDescriptor.h>
namespace android {
@@ -61,6 +60,9 @@
case RULE_MATCH_UID:
ruleValue = std::to_string(criterion.mValue.mUid);
break;
+ case RULE_MATCH_USERID:
+ ruleValue = std::to_string(criterion.mValue.mUserId);
+ break;
default:
unknownRule = true;
}
@@ -198,7 +200,9 @@
ALOGV("%s: Mix %zu ignored as secondaryOutput because not opened yet", __func__, i);
} else {
ALOGV("%s: Add a secondary desc %zu", __func__, i);
- secondaryDescs->push_back(policyDesc);
+ if (secondaryDescs != nullptr) {
+ secondaryDescs->push_back(policyDesc);
+ }
}
}
}
@@ -220,12 +224,20 @@
hasFlag(attributes.flags, AUDIO_FLAG_NO_MEDIA_PROJECTION)) {
return MixMatchStatus::NO_MATCH;
}
+ if (attributes.usage == AUDIO_USAGE_VOICE_COMMUNICATION &&
+ !mix->mVoiceCommunicationCaptureAllowed) {
+ return MixMatchStatus::NO_MATCH;
+ }
if (!(attributes.usage == AUDIO_USAGE_UNKNOWN ||
attributes.usage == AUDIO_USAGE_MEDIA ||
- attributes.usage == AUDIO_USAGE_GAME)) {
+ attributes.usage == AUDIO_USAGE_GAME ||
+ attributes.usage == AUDIO_USAGE_VOICE_COMMUNICATION)) {
return MixMatchStatus::NO_MATCH;
}
}
+
+ int userId = (int) multiuser_get_user_id(uid);
+
// TODO if adding more player rules (currently only 2), make rule handling "generic"
// as there is no difference in the treatment of usage- or uid-based rules
bool hasUsageMatchRules = false;
@@ -238,6 +250,12 @@
bool uidMatchFound = false;
bool uidExclusionFound = false;
+ bool hasUserIdExcludeRules = false;
+ bool userIdExclusionFound = false;
+ bool hasUserIdMatchRules = false;
+ bool userIdMatchFound = false;
+
+
bool hasAddrMatch = false;
// iterate over all mix criteria to list what rules this mix contains
@@ -289,6 +307,24 @@
uidExclusionFound = true;
}
break;
+ case RULE_MATCH_USERID:
+ ALOGV("\tmix has RULE_MATCH_USERID for userId %d",
+ mix->mCriteria[j].mValue.mUserId);
+ hasUserIdMatchRules = true;
+ if (mix->mCriteria[j].mValue.mUserId == userId) {
+ // found one userId match against all allowed userIds
+ userIdMatchFound = true;
+ }
+ break;
+ case RULE_EXCLUDE_USERID:
+ ALOGV("\tmix has RULE_EXCLUDE_USERID for userId %d",
+ mix->mCriteria[j].mValue.mUserId);
+ hasUserIdExcludeRules = true;
+ if (mix->mCriteria[j].mValue.mUserId == userId) {
+ // found this userId is to be excluded
+ userIdExclusionFound = true;
+ }
+ break;
default:
break;
}
@@ -305,12 +341,17 @@
" and RULE_EXCLUDE_UID in mix %zu", mixIndex);
return MixMatchStatus::INVALID_MIX;
}
-
- if ((hasUsageExcludeRules && usageExclusionFound)
- || (hasUidExcludeRules && uidExclusionFound)) {
- break; // stop iterating on criteria because an exclusion was found (will fail)
+ if (hasUserIdMatchRules && hasUserIdExcludeRules) {
+ ALOGE("getOutputForAttr: invalid combination of RULE_MATCH_USERID"
+ " and RULE_EXCLUDE_USERID in mix %zu", mixIndex);
+ return MixMatchStatus::INVALID_MIX;
}
+ if ((hasUsageExcludeRules && usageExclusionFound)
+ || (hasUidExcludeRules && uidExclusionFound)
+ || (hasUserIdExcludeRules && userIdExclusionFound)) {
+ break; // stop iterating on criteria because an exclusion was found (will fail)
+ }
}//iterate on mix criteria
// determine if exiting on success (or implicit failure as desc is 0)
@@ -318,7 +359,9 @@
!((hasUsageExcludeRules && usageExclusionFound) ||
(hasUsageMatchRules && !usageMatchFound) ||
(hasUidExcludeRules && uidExclusionFound) ||
- (hasUidMatchRules && !uidMatchFound))) {
+ (hasUidMatchRules && !uidMatchFound) ||
+ (hasUserIdExcludeRules && userIdExclusionFound) ||
+ (hasUserIdMatchRules && !userIdMatchFound))) {
ALOGV("\tgetOutputForAttr will use mix %zu", mixIndex);
return MixMatchStatus::MATCH;
}
@@ -456,9 +499,9 @@
}
// check if this mix goes to a device in the list of devices
bool deviceMatch = false;
+ const AudioDeviceTypeAddr mixDevice(mix->mDeviceType, mix->mDeviceAddress.string());
for (size_t j = 0; j < devices.size(); j++) {
- if (devices[j].mType == mix->mDeviceType
- && devices[j].mAddress == mix->mDeviceAddress) {
+ if (mixDevice.equals(devices[j])) {
deviceMatch = true;
break;
}
@@ -523,7 +566,110 @@
}
}
if (ruleAllowsUid) {
- devices.add(AudioDeviceTypeAddr(mix->mDeviceType, mix->mDeviceAddress));
+ devices.add(AudioDeviceTypeAddr(mix->mDeviceType, mix->mDeviceAddress.string()));
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t AudioPolicyMixCollection::setUserIdDeviceAffinities(int userId,
+ const Vector<AudioDeviceTypeAddr>& devices) {
+ // verify feasibility: for each player mix: if it already contains a
+ // "match userId" rule for this userId, return an error
+ // (adding a userId-device affinity would result in contradictory rules)
+ for (size_t i = 0; i < size(); i++) {
+ const AudioPolicyMix* mix = itemAt(i).get();
+ if (!mix->isDeviceAffinityCompatible()) {
+ continue;
+ }
+ if (mix->hasUserIdRule(true /*match*/, userId)) {
+ return INVALID_OPERATION;
+ }
+ }
+
+ // remove existing rules for this userId
+ removeUserIdDeviceAffinities(userId);
+
+ // for each player mix:
+ // IF device is not a target for the mix,
+ // AND it doesn't have a "match userId" rule
+ // THEN add a rule to exclude the userId
+ for (size_t i = 0; i < size(); i++) {
+ const AudioPolicyMix *mix = itemAt(i).get();
+ if (!mix->isDeviceAffinityCompatible()) {
+ continue;
+ }
+ // check if this mix goes to a device in the list of devices
+ bool deviceMatch = false;
+ const AudioDeviceTypeAddr mixDevice(mix->mDeviceType, mix->mDeviceAddress.string());
+ for (size_t j = 0; j < devices.size(); j++) {
+ if (mixDevice.equals(devices[j])) {
+ deviceMatch = true;
+ break;
+ }
+ }
+ if (!deviceMatch && !mix->hasMatchUserIdRule()) {
+ // this mix doesn't go to one of the listed devices for the given userId,
+ // and it's not already restricting the mix on a userId,
+ // modify its rules to exclude the userId
+ if (!mix->hasUserIdRule(false /*match*/, userId)) {
+ // no need to do it again if userId is already excluded
+ mix->setExcludeUserId(userId);
+ }
+ }
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioPolicyMixCollection::removeUserIdDeviceAffinities(int userId) {
+ // for each player mix: remove existing rules that match or exclude this userId
+ for (size_t i = 0; i < size(); i++) {
+ bool foundUserIdRule = false;
+ const AudioPolicyMix *mix = itemAt(i).get();
+ if (!mix->isDeviceAffinityCompatible()) {
+ continue;
+ }
+ std::vector<size_t> criteriaToRemove;
+ for (size_t j = 0; j < mix->mCriteria.size(); j++) {
+ const uint32_t rule = mix->mCriteria[j].mRule;
+ // is this rule excluding the userId? (not considering userId match rules
+ // as those are not used for userId-device affinity)
+ if (rule == RULE_EXCLUDE_USERID
+ && userId == mix->mCriteria[j].mValue.mUserId) {
+ foundUserIdRule = true;
+ criteriaToRemove.insert(criteriaToRemove.begin(), j);
+ }
+ }
+ if (foundUserIdRule) {
+ for (size_t j = 0; j < criteriaToRemove.size(); j++) {
+ mix->mCriteria.removeAt(criteriaToRemove[j]);
+ }
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t AudioPolicyMixCollection::getDevicesForUserId(int userId,
+ Vector<AudioDeviceTypeAddr>& devices) const {
+ // for each player mix:
+ // find rules that don't exclude this userId, and add the device to the list
+ for (size_t i = 0; i < size(); i++) {
+ bool ruleAllowsUserId = true;
+ const AudioPolicyMix *mix = itemAt(i).get();
+ if (mix->mMixType != MIX_TYPE_PLAYERS) {
+ continue;
+ }
+ for (size_t j = 0; j < mix->mCriteria.size(); j++) {
+ const uint32_t rule = mix->mCriteria[j].mRule;
+ if (rule == RULE_EXCLUDE_USERID
+ && userId == mix->mCriteria[j].mValue.mUserId) {
+ ruleAllowsUserId = false;
+ break;
+ }
+ }
+ if (ruleAllowsUserId) {
+ devices.add(AudioDeviceTypeAddr(mix->mDeviceType, mix->mDeviceAddress.string()));
}
}
return NO_ERROR;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
deleted file mode 100644
index c11490a..0000000
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
+++ /dev/null
@@ -1,487 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "APM::AudioPort"
-//#define LOG_NDEBUG 0
-#include "TypeConverter.h"
-#include "AudioPort.h"
-#include "HwModule.h"
-#include "AudioGain.h"
-#include <policy.h>
-
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-#endif
-
-namespace android {
-
-// --- AudioPort class implementation
-void AudioPort::attach(const sp<HwModule>& module)
-{
- ALOGV("%s: attaching module %s to port %s", __FUNCTION__, getModuleName(), mName.string());
- mModule = module;
-}
-
-void AudioPort::detach()
-{
- mModule = nullptr;
-}
-
-// Note that is a different namespace than AudioFlinger unique IDs
-audio_port_handle_t AudioPort::getNextUniqueId()
-{
- return getNextHandle();
-}
-
-audio_module_handle_t AudioPort::getModuleHandle() const
-{
- return mModule != 0 ? mModule->getHandle() : AUDIO_MODULE_HANDLE_NONE;
-}
-
-uint32_t AudioPort::getModuleVersionMajor() const
-{
- return mModule != 0 ? mModule->getHalVersionMajor() : 0;
-}
-
-const char *AudioPort::getModuleName() const
-{
- return mModule != 0 ? mModule->getName() : "invalid module";
-}
-
-void AudioPort::toAudioPort(struct audio_port *port) const
-{
- // TODO: update this function once audio_port structure reflects the new profile definition.
- // For compatibility reason: flatening the AudioProfile into audio_port structure.
- SortedVector<audio_format_t> flatenedFormats;
- SampleRateVector flatenedRates;
- ChannelsVector flatenedChannels;
- for (const auto& profile : mProfiles) {
- if (profile->isValid()) {
- audio_format_t formatToExport = profile->getFormat();
- const SampleRateVector &ratesToExport = profile->getSampleRates();
- const ChannelsVector &channelsToExport = profile->getChannels();
-
- if (flatenedFormats.indexOf(formatToExport) < 0) {
- flatenedFormats.add(formatToExport);
- }
- for (size_t rateIndex = 0; rateIndex < ratesToExport.size(); rateIndex++) {
- uint32_t rate = ratesToExport[rateIndex];
- if (flatenedRates.indexOf(rate) < 0) {
- flatenedRates.add(rate);
- }
- }
- for (size_t chanIndex = 0; chanIndex < channelsToExport.size(); chanIndex++) {
- audio_channel_mask_t channels = channelsToExport[chanIndex];
- if (flatenedChannels.indexOf(channels) < 0) {
- flatenedChannels.add(channels);
- }
- }
- if (flatenedRates.size() > AUDIO_PORT_MAX_SAMPLING_RATES ||
- flatenedChannels.size() > AUDIO_PORT_MAX_CHANNEL_MASKS ||
- flatenedFormats.size() > AUDIO_PORT_MAX_FORMATS) {
- ALOGE("%s: bailing out: cannot export profiles to port config", __FUNCTION__);
- return;
- }
- }
- }
- port->role = mRole;
- port->type = mType;
- strlcpy(port->name, mName, AUDIO_PORT_MAX_NAME_LEN);
- port->num_sample_rates = flatenedRates.size();
- port->num_channel_masks = flatenedChannels.size();
- port->num_formats = flatenedFormats.size();
- for (size_t i = 0; i < flatenedRates.size(); i++) {
- port->sample_rates[i] = flatenedRates[i];
- }
- for (size_t i = 0; i < flatenedChannels.size(); i++) {
- port->channel_masks[i] = flatenedChannels[i];
- }
- for (size_t i = 0; i < flatenedFormats.size(); i++) {
- port->formats[i] = flatenedFormats[i];
- }
-
- ALOGV("AudioPort::toAudioPort() num gains %zu", mGains.size());
-
- uint32_t i;
- for (i = 0; i < mGains.size() && i < AUDIO_PORT_MAX_GAINS; i++) {
- port->gains[i] = mGains[i]->getGain();
- }
- port->num_gains = i;
-}
-
-void AudioPort::importAudioPort(const sp<AudioPort>& port, bool force __unused)
-{
- for (const auto& profileToImport : port->mProfiles) {
- if (profileToImport->isValid()) {
- // Import only valid port, i.e. valid format, non empty rates and channels masks
- bool hasSameProfile = false;
- for (const auto& profile : mProfiles) {
- if (*profile == *profileToImport) {
- // never import a profile twice
- hasSameProfile = true;
- break;
- }
- }
- if (hasSameProfile) { // never import a same profile twice
- continue;
- }
- addAudioProfile(profileToImport);
- }
- }
-}
-
-status_t AudioPort::checkExactAudioProfile(const struct audio_port_config *config) const
-{
- status_t status = NO_ERROR;
- auto config_mask = config->config_mask;
- if (config_mask & AUDIO_PORT_CONFIG_GAIN) {
- config_mask &= ~AUDIO_PORT_CONFIG_GAIN;
- status = checkGain(&config->gain, config->gain.index);
- if (status != NO_ERROR) {
- return status;
- }
- }
- if (config_mask != 0) {
- // TODO should we check sample_rate / channel_mask / format separately?
- status = mProfiles.checkExactProfile(config->sample_rate,
- config->channel_mask,
- config->format);
- }
- return status;
-}
-
-void AudioPort::pickSamplingRate(uint32_t &pickedRate,const SampleRateVector &samplingRates) const
-{
- pickedRate = 0;
- // For direct outputs, pick minimum sampling rate: this helps ensuring that the
- // channel count / sampling rate combination chosen will be supported by the connected
- // sink
- if (isDirectOutput()) {
- uint32_t samplingRate = UINT_MAX;
- for (size_t i = 0; i < samplingRates.size(); i ++) {
- if ((samplingRates[i] < samplingRate) && (samplingRates[i] > 0)) {
- samplingRate = samplingRates[i];
- }
- }
- pickedRate = (samplingRate == UINT_MAX) ? 0 : samplingRate;
- } else {
- uint32_t maxRate = SAMPLE_RATE_HZ_MAX;
-
- // For mixed output and inputs, use max mixer sampling rates. Do not
- // limit sampling rate otherwise
- // For inputs, also see checkCompatibleSamplingRate().
- if (mType != AUDIO_PORT_TYPE_MIX) {
- maxRate = UINT_MAX;
- }
- // TODO: should mSamplingRates[] be ordered in terms of our preference
- // and we return the first (and hence most preferred) match? This is of concern if
- // we want to choose 96kHz over 192kHz for USB driver stability or resource constraints.
- for (size_t i = 0; i < samplingRates.size(); i ++) {
- if ((samplingRates[i] > pickedRate) && (samplingRates[i] <= maxRate)) {
- pickedRate = samplingRates[i];
- }
- }
- }
-}
-
-void AudioPort::pickChannelMask(audio_channel_mask_t &pickedChannelMask,
- const ChannelsVector &channelMasks) const
-{
- pickedChannelMask = AUDIO_CHANNEL_NONE;
- // For direct outputs, pick minimum channel count: this helps ensuring that the
- // channel count / sampling rate combination chosen will be supported by the connected
- // sink
- if (isDirectOutput()) {
- uint32_t channelCount = UINT_MAX;
- for (size_t i = 0; i < channelMasks.size(); i ++) {
- uint32_t cnlCount;
- if (useInputChannelMask()) {
- cnlCount = audio_channel_count_from_in_mask(channelMasks[i]);
- } else {
- cnlCount = audio_channel_count_from_out_mask(channelMasks[i]);
- }
- if ((cnlCount < channelCount) && (cnlCount > 0)) {
- pickedChannelMask = channelMasks[i];
- channelCount = cnlCount;
- }
- }
- } else {
- uint32_t channelCount = 0;
- uint32_t maxCount = MAX_MIXER_CHANNEL_COUNT;
-
- // For mixed output and inputs, use max mixer channel count. Do not
- // limit channel count otherwise
- if (mType != AUDIO_PORT_TYPE_MIX) {
- maxCount = UINT_MAX;
- }
- for (size_t i = 0; i < channelMasks.size(); i ++) {
- uint32_t cnlCount;
- if (useInputChannelMask()) {
- cnlCount = audio_channel_count_from_in_mask(channelMasks[i]);
- } else {
- cnlCount = audio_channel_count_from_out_mask(channelMasks[i]);
- }
- if ((cnlCount > channelCount) && (cnlCount <= maxCount)) {
- pickedChannelMask = channelMasks[i];
- channelCount = cnlCount;
- }
- }
- }
-}
-
-/* format in order of increasing preference */
-const audio_format_t AudioPort::sPcmFormatCompareTable[] = {
- AUDIO_FORMAT_DEFAULT,
- AUDIO_FORMAT_PCM_16_BIT,
- AUDIO_FORMAT_PCM_8_24_BIT,
- AUDIO_FORMAT_PCM_24_BIT_PACKED,
- AUDIO_FORMAT_PCM_32_BIT,
- AUDIO_FORMAT_PCM_FLOAT,
-};
-
-int AudioPort::compareFormats(audio_format_t format1, audio_format_t format2)
-{
- // NOTE: AUDIO_FORMAT_INVALID is also considered not PCM and will be compared equal to any
- // compressed format and better than any PCM format. This is by design of pickFormat()
- if (!audio_is_linear_pcm(format1)) {
- if (!audio_is_linear_pcm(format2)) {
- return 0;
- }
- return 1;
- }
- if (!audio_is_linear_pcm(format2)) {
- return -1;
- }
-
- int index1 = -1, index2 = -1;
- for (size_t i = 0;
- (i < ARRAY_SIZE(sPcmFormatCompareTable)) && ((index1 == -1) || (index2 == -1));
- i ++) {
- if (sPcmFormatCompareTable[i] == format1) {
- index1 = i;
- }
- if (sPcmFormatCompareTable[i] == format2) {
- index2 = i;
- }
- }
- // format1 not found => index1 < 0 => format2 > format1
- // format2 not found => index2 < 0 => format2 < format1
- return index1 - index2;
-}
-
-uint32_t AudioPort::formatDistance(audio_format_t format1, audio_format_t format2)
-{
- if (format1 == format2) {
- return 0;
- }
- if (format1 == AUDIO_FORMAT_INVALID || format2 == AUDIO_FORMAT_INVALID) {
- return kFormatDistanceMax;
- }
- int diffBytes = (int)audio_bytes_per_sample(format1) -
- audio_bytes_per_sample(format2);
-
- return abs(diffBytes);
-}
-
-bool AudioPort::isBetterFormatMatch(audio_format_t newFormat,
- audio_format_t currentFormat,
- audio_format_t targetFormat)
-{
- return formatDistance(newFormat, targetFormat) < formatDistance(currentFormat, targetFormat);
-}
-
-void AudioPort::pickAudioProfile(uint32_t &samplingRate,
- audio_channel_mask_t &channelMask,
- audio_format_t &format) const
-{
- format = AUDIO_FORMAT_DEFAULT;
- samplingRate = 0;
- channelMask = AUDIO_CHANNEL_NONE;
-
- // special case for uninitialized dynamic profile
- if (!mProfiles.hasValidProfile()) {
- return;
- }
- audio_format_t bestFormat = sPcmFormatCompareTable[ARRAY_SIZE(sPcmFormatCompareTable) - 1];
- // For mixed output and inputs, use best mixer output format.
- // Do not limit format otherwise
- if ((mType != AUDIO_PORT_TYPE_MIX) || isDirectOutput()) {
- bestFormat = AUDIO_FORMAT_INVALID;
- }
-
- for (size_t i = 0; i < mProfiles.size(); i ++) {
- if (!mProfiles[i]->isValid()) {
- continue;
- }
- audio_format_t formatToCompare = mProfiles[i]->getFormat();
- if ((compareFormats(formatToCompare, format) > 0) &&
- (compareFormats(formatToCompare, bestFormat) <= 0)) {
- uint32_t pickedSamplingRate = 0;
- audio_channel_mask_t pickedChannelMask = AUDIO_CHANNEL_NONE;
- pickChannelMask(pickedChannelMask, mProfiles[i]->getChannels());
- pickSamplingRate(pickedSamplingRate, mProfiles[i]->getSampleRates());
-
- if (formatToCompare != AUDIO_FORMAT_DEFAULT && pickedChannelMask != AUDIO_CHANNEL_NONE
- && pickedSamplingRate != 0) {
- format = formatToCompare;
- channelMask = pickedChannelMask;
- samplingRate = pickedSamplingRate;
- // TODO: shall we return on the first one or still trying to pick a better Profile?
- }
- }
- }
- ALOGV("%s Port[nm:%s] profile rate=%d, format=%d, channels=%d", __FUNCTION__, mName.string(),
- samplingRate, channelMask, format);
-}
-
-status_t AudioPort::checkGain(const struct audio_gain_config *gainConfig, int index) const
-{
- if (index < 0 || (size_t)index >= mGains.size()) {
- return BAD_VALUE;
- }
- return mGains[index]->checkConfig(gainConfig);
-}
-
-void AudioPort::dump(String8 *dst, int spaces, bool verbose) const
-{
- if (!mName.isEmpty()) {
- dst->appendFormat("%*s- name: %s\n", spaces, "", mName.string());
- }
- if (verbose) {
- mProfiles.dump(dst, spaces);
-
- if (mGains.size() != 0) {
- dst->appendFormat("%*s- gains:\n", spaces, "");
- for (size_t i = 0; i < mGains.size(); i++) {
- mGains[i]->dump(dst, spaces + 2, i);
- }
- }
- }
-}
-
-void AudioPort::log(const char* indent) const
-{
- ALOGI("%s Port[nm:%s, type:%d, role:%d]", indent, mName.string(), mType, mRole);
-}
-
-// --- AudioPortConfig class implementation
-
-status_t AudioPortConfig::applyAudioPortConfig(const struct audio_port_config *config,
- struct audio_port_config *backupConfig)
-{
- struct audio_port_config localBackupConfig = { .config_mask = config->config_mask };
- status_t status = NO_ERROR;
-
- toAudioPortConfig(&localBackupConfig);
-
- sp<AudioPort> audioport = getAudioPort();
- if (audioport == 0) {
- status = NO_INIT;
- goto exit;
- }
- status = audioport->checkExactAudioProfile(config);
- if (status != NO_ERROR) {
- goto exit;
- }
- if (config->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
- mSamplingRate = config->sample_rate;
- }
- if (config->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
- mChannelMask = config->channel_mask;
- }
- if (config->config_mask & AUDIO_PORT_CONFIG_FORMAT) {
- mFormat = config->format;
- }
- if (config->config_mask & AUDIO_PORT_CONFIG_GAIN) {
- mGain = config->gain;
- }
- if (config->config_mask & AUDIO_PORT_CONFIG_FLAGS) {
- mFlags = config->flags;
- }
-
-exit:
- if (status != NO_ERROR) {
- applyAudioPortConfig(&localBackupConfig);
- }
- if (backupConfig != NULL) {
- *backupConfig = localBackupConfig;
- }
- return status;
-}
-
-namespace {
-
-template<typename T>
-void updateField(
- const T& portConfigField, T audio_port_config::*port_config_field,
- struct audio_port_config *dstConfig, const struct audio_port_config *srcConfig,
- unsigned int configMask, T defaultValue)
-{
- if (dstConfig->config_mask & configMask) {
- if ((srcConfig != nullptr) && (srcConfig->config_mask & configMask)) {
- dstConfig->*port_config_field = srcConfig->*port_config_field;
- } else {
- dstConfig->*port_config_field = portConfigField;
- }
- } else {
- dstConfig->*port_config_field = defaultValue;
- }
-}
-
-} // namespace
-
-void AudioPortConfig::toAudioPortConfig(struct audio_port_config *dstConfig,
- const struct audio_port_config *srcConfig) const
-{
- updateField(mSamplingRate, &audio_port_config::sample_rate,
- dstConfig, srcConfig, AUDIO_PORT_CONFIG_SAMPLE_RATE, 0u);
- updateField(mChannelMask, &audio_port_config::channel_mask,
- dstConfig, srcConfig, AUDIO_PORT_CONFIG_CHANNEL_MASK,
- (audio_channel_mask_t)AUDIO_CHANNEL_NONE);
- updateField(mFormat, &audio_port_config::format,
- dstConfig, srcConfig, AUDIO_PORT_CONFIG_FORMAT, AUDIO_FORMAT_INVALID);
-
- sp<AudioPort> audioport = getAudioPort();
- if ((dstConfig->config_mask & AUDIO_PORT_CONFIG_GAIN) && audioport != NULL) {
- dstConfig->gain = mGain;
- if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_GAIN)
- && audioport->checkGain(&srcConfig->gain, srcConfig->gain.index) == OK) {
- dstConfig->gain = srcConfig->gain;
- }
- } else {
- dstConfig->gain.index = -1;
- }
- if (dstConfig->gain.index != -1) {
- dstConfig->config_mask |= AUDIO_PORT_CONFIG_GAIN;
- } else {
- dstConfig->config_mask &= ~AUDIO_PORT_CONFIG_GAIN;
- }
-
- updateField(mFlags, &audio_port_config::flags,
- dstConfig, srcConfig, AUDIO_PORT_CONFIG_FLAGS, { AUDIO_INPUT_FLAG_NONE });
-}
-
-bool AudioPortConfig::hasGainController(bool canUseForVolume) const
-{
- sp<AudioPort> audioport = getAudioPort();
- if (audioport == nullptr) {
- return false;
- }
- return canUseForVolume ? audioport->getGains().canUseForVolume()
- : audioport->getGains().size() > 0;
-}
-
-} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
deleted file mode 100644
index 69d6b0c..0000000
--- a/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
+++ /dev/null
@@ -1,621 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <algorithm>
-#include <set>
-#include <string>
-
-#define LOG_TAG "APM::AudioProfile"
-//#define LOG_NDEBUG 0
-
-#include <media/AudioResamplerPublic.h>
-#include <utils/Errors.h>
-
-#include "AudioGain.h"
-#include "AudioPort.h"
-#include "AudioProfile.h"
-#include "HwModule.h"
-#include "TypeConverter.h"
-
-namespace android {
-
-ChannelsVector ChannelsVector::asInMask() const
-{
- ChannelsVector inMaskVector;
- for (const auto& channel : *this) {
- if (audio_channel_mask_out_to_in(channel) != AUDIO_CHANNEL_INVALID) {
- inMaskVector.add(audio_channel_mask_out_to_in(channel));
- }
- }
- return inMaskVector;
-}
-
-ChannelsVector ChannelsVector::asOutMask() const
-{
- ChannelsVector outMaskVector;
- for (const auto& channel : *this) {
- if (audio_channel_mask_in_to_out(channel) != AUDIO_CHANNEL_INVALID) {
- outMaskVector.add(audio_channel_mask_in_to_out(channel));
- }
- }
- return outMaskVector;
-}
-
-bool operator == (const AudioProfile &left, const AudioProfile &compareTo)
-{
- return (left.getFormat() == compareTo.getFormat()) &&
- (left.getChannels() == compareTo.getChannels()) &&
- (left.getSampleRates() == compareTo.getSampleRates());
-}
-
-static AudioProfile* createFullDynamicImpl()
-{
- AudioProfile* dynamicProfile = new AudioProfile(gDynamicFormat,
- ChannelsVector(), SampleRateVector());
- dynamicProfile->setDynamicFormat(true);
- dynamicProfile->setDynamicChannels(true);
- dynamicProfile->setDynamicRate(true);
- return dynamicProfile;
-}
-
-// static
-sp<AudioProfile> AudioProfile::createFullDynamic()
-{
- static sp<AudioProfile> dynamicProfile = createFullDynamicImpl();
- return dynamicProfile;
-}
-
-AudioProfile::AudioProfile(audio_format_t format,
- audio_channel_mask_t channelMasks,
- uint32_t samplingRate) :
- mName(String8("")),
- mFormat(format)
-{
- mChannelMasks.add(channelMasks);
- mSamplingRates.add(samplingRate);
-}
-
-AudioProfile::AudioProfile(audio_format_t format,
- const ChannelsVector &channelMasks,
- const SampleRateVector &samplingRateCollection) :
- mName(String8("")),
- mFormat(format),
- mChannelMasks(channelMasks),
- mSamplingRates(samplingRateCollection) {}
-
-void AudioProfile::setChannels(const ChannelsVector &channelMasks)
-{
- if (mIsDynamicChannels) {
- mChannelMasks = channelMasks;
- }
-}
-
-void AudioProfile::setSampleRates(const SampleRateVector &sampleRates)
-{
- if (mIsDynamicRate) {
- mSamplingRates = sampleRates;
- }
-}
-
-void AudioProfile::clear()
-{
- if (mIsDynamicChannels) {
- mChannelMasks.clear();
- }
- if (mIsDynamicRate) {
- mSamplingRates.clear();
- }
-}
-
-status_t AudioProfile::checkExact(uint32_t samplingRate, audio_channel_mask_t channelMask,
- audio_format_t format) const
-{
- if (audio_formats_match(format, mFormat) &&
- supportsChannels(channelMask) &&
- supportsRate(samplingRate)) {
- return NO_ERROR;
- }
- return BAD_VALUE;
-}
-
-status_t AudioProfile::checkCompatibleSamplingRate(uint32_t samplingRate,
- uint32_t &updatedSamplingRate) const
-{
- ALOG_ASSERT(samplingRate > 0);
-
- if (mSamplingRates.isEmpty()) {
- updatedSamplingRate = samplingRate;
- return NO_ERROR;
- }
-
- // Search for the closest supported sampling rate that is above (preferred)
- // or below (acceptable) the desired sampling rate, within a permitted ratio.
- // The sampling rates are sorted in ascending order.
- size_t orderOfDesiredRate = mSamplingRates.orderOf(samplingRate);
-
- // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
- if (orderOfDesiredRate < mSamplingRates.size()) {
- uint32_t candidate = mSamplingRates[orderOfDesiredRate];
- if (candidate / AUDIO_RESAMPLER_DOWN_RATIO_MAX <= samplingRate) {
- updatedSamplingRate = candidate;
- return NO_ERROR;
- }
- }
- // But if we have to up-sample from a lower sampling rate, that's OK.
- if (orderOfDesiredRate != 0) {
- uint32_t candidate = mSamplingRates[orderOfDesiredRate - 1];
- if (candidate * AUDIO_RESAMPLER_UP_RATIO_MAX >= samplingRate) {
- updatedSamplingRate = candidate;
- return NO_ERROR;
- }
- }
- // leave updatedSamplingRate unmodified
- return BAD_VALUE;
-}
-
-status_t AudioProfile::checkCompatibleChannelMask(audio_channel_mask_t channelMask,
- audio_channel_mask_t &updatedChannelMask,
- audio_port_type_t portType,
- audio_port_role_t portRole) const
-{
- if (mChannelMasks.isEmpty()) {
- updatedChannelMask = channelMask;
- return NO_ERROR;
- }
- const bool isRecordThread = portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK;
- const bool isIndex = audio_channel_mask_get_representation(channelMask)
- == AUDIO_CHANNEL_REPRESENTATION_INDEX;
- const uint32_t channelCount = audio_channel_count_from_in_mask(channelMask);
- int bestMatch = 0;
- for (size_t i = 0; i < mChannelMasks.size(); i ++) {
- audio_channel_mask_t supported = mChannelMasks[i];
- if (supported == channelMask) {
- // Exact matches always taken.
- updatedChannelMask = channelMask;
- return NO_ERROR;
- }
-
- // AUDIO_CHANNEL_NONE (value: 0) is used for dynamic channel support
- if (isRecordThread && supported != AUDIO_CHANNEL_NONE) {
- // Approximate (best) match:
- // The match score measures how well the supported channel mask matches the
- // desired mask, where increasing-is-better.
- //
- // TODO: Some tweaks may be needed.
- // Should be a static function of the data processing library.
- //
- // In priority:
- // match score = 1000 if legacy channel conversion equivalent (always prefer this)
- // OR
- // match score += 100 if the channel mask representations match
- // match score += number of channels matched.
- // match score += 100 if the channel mask representations DO NOT match
- // but the profile has positional channel mask and less than 2 channels.
- // This is for audio HAL convention to not list index masks for less than 2 channels
- //
- // If there are no matched channels, the mask may still be accepted
- // but the playback or record will be silent.
- const bool isSupportedIndex = (audio_channel_mask_get_representation(supported)
- == AUDIO_CHANNEL_REPRESENTATION_INDEX);
- const uint32_t supportedChannelCount = audio_channel_count_from_in_mask(supported);
- int match;
- if (isIndex && isSupportedIndex) {
- // index equivalence
- match = 100 + __builtin_popcount(
- audio_channel_mask_get_bits(channelMask)
- & audio_channel_mask_get_bits(supported));
- } else if (isIndex && !isSupportedIndex) {
- const uint32_t equivalentBits = (1 << supportedChannelCount) - 1 ;
- match = __builtin_popcount(
- audio_channel_mask_get_bits(channelMask) & equivalentBits);
- if (supportedChannelCount <= FCC_2) {
- match += 100;
- }
- } else if (!isIndex && isSupportedIndex) {
- const uint32_t equivalentBits = (1 << channelCount) - 1;
- match = __builtin_popcount(
- equivalentBits & audio_channel_mask_get_bits(supported));
- } else {
- // positional equivalence
- match = 100 + __builtin_popcount(
- audio_channel_mask_get_bits(channelMask)
- & audio_channel_mask_get_bits(supported));
- switch (supported) {
- case AUDIO_CHANNEL_IN_FRONT_BACK:
- case AUDIO_CHANNEL_IN_STEREO:
- if (channelMask == AUDIO_CHANNEL_IN_MONO) {
- match = 1000;
- }
- break;
- case AUDIO_CHANNEL_IN_MONO:
- if (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK
- || channelMask == AUDIO_CHANNEL_IN_STEREO) {
- match = 1000;
- }
- break;
- default:
- break;
- }
- }
- if (match > bestMatch) {
- bestMatch = match;
- updatedChannelMask = supported;
- }
- }
- }
- return bestMatch > 0 ? NO_ERROR : BAD_VALUE;
-}
-
-void AudioProfile::dump(String8 *dst, int spaces) const
-{
- dst->appendFormat("%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "",
- mIsDynamicChannels ? "[dynamic channels]" : "",
- mIsDynamicRate ? "[dynamic rates]" : "");
- if (mName.length() != 0) {
- dst->appendFormat("%*s- name: %s\n", spaces, "", mName.string());
- }
- std::string formatLiteral;
- if (FormatConverter::toString(mFormat, formatLiteral)) {
- dst->appendFormat("%*s- format: %s\n", spaces, "", formatLiteral.c_str());
- }
- if (!mSamplingRates.isEmpty()) {
- dst->appendFormat("%*s- sampling rates:", spaces, "");
- for (size_t i = 0; i < mSamplingRates.size(); i++) {
- dst->appendFormat("%d", mSamplingRates[i]);
- dst->append(i == (mSamplingRates.size() - 1) ? "" : ", ");
- }
- dst->append("\n");
- }
-
- if (!mChannelMasks.isEmpty()) {
- dst->appendFormat("%*s- channel masks:", spaces, "");
- for (size_t i = 0; i < mChannelMasks.size(); i++) {
- dst->appendFormat("0x%04x", mChannelMasks[i]);
- dst->append(i == (mChannelMasks.size() - 1) ? "" : ", ");
- }
- dst->append("\n");
- }
-}
-
-ssize_t AudioProfileVector::add(const sp<AudioProfile> &profile)
-{
- ssize_t index = Vector::add(profile);
- // we sort from worst to best, so that AUDIO_FORMAT_DEFAULT is always the first entry.
- // TODO: compareFormats could be a lambda to convert between pointer-to-format to format:
- // [](const audio_format_t *format1, const audio_format_t *format2) {
- // return compareFormats(*format1, *format2);
- // }
- sort(compareFormats);
- return index;
-}
-
-ssize_t AudioProfileVector::addProfileFromHal(const sp<AudioProfile> &profileToAdd)
-{
- // Check valid profile to add:
- if (!profileToAdd->hasValidFormat()) {
- return -1;
- }
- if (!profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
- FormatVector formats;
- formats.add(profileToAdd->getFormat());
- setFormats(FormatVector(formats));
- return 0;
- }
- if (!profileToAdd->hasValidChannels() && profileToAdd->hasValidRates()) {
- setSampleRatesFor(profileToAdd->getSampleRates(), profileToAdd->getFormat());
- return 0;
- }
- if (profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
- setChannelsFor(profileToAdd->getChannels(), profileToAdd->getFormat());
- return 0;
- }
- // Go through the list of profile to avoid duplicates
- for (size_t profileIndex = 0; profileIndex < size(); profileIndex++) {
- const sp<AudioProfile> &profile = itemAt(profileIndex);
- if (profile->isValid() && profile == profileToAdd) {
- // Nothing to do
- return profileIndex;
- }
- }
- profileToAdd->setDynamicFormat(true); // set the format as dynamic to allow removal
- return add(profileToAdd);
-}
-
-status_t AudioProfileVector::checkExactProfile(uint32_t samplingRate,
- audio_channel_mask_t channelMask,
- audio_format_t format) const
-{
- if (isEmpty()) {
- return NO_ERROR;
- }
-
- for (const auto& profile : *this) {
- if (profile->checkExact(samplingRate, channelMask, format) == NO_ERROR) {
- return NO_ERROR;
- }
- }
- return BAD_VALUE;
-}
-
-status_t AudioProfileVector::checkCompatibleProfile(uint32_t &samplingRate,
- audio_channel_mask_t &channelMask,
- audio_format_t &format,
- audio_port_type_t portType,
- audio_port_role_t portRole) const
-{
- if (isEmpty()) {
- return NO_ERROR;
- }
-
- const bool checkInexact = // when port is input and format is linear pcm
- portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK
- && audio_is_linear_pcm(format);
-
- // iterate from best format to worst format (reverse order)
- for (ssize_t i = size() - 1; i >= 0 ; --i) {
- const sp<AudioProfile> profile = itemAt(i);
- audio_format_t formatToCompare = profile->getFormat();
- if (formatToCompare == format ||
- (checkInexact
- && formatToCompare != AUDIO_FORMAT_DEFAULT
- && audio_is_linear_pcm(formatToCompare))) {
- // Compatible profile has been found, checks if this profile has compatible
- // rate and channels as well
- audio_channel_mask_t updatedChannels;
- uint32_t updatedRate;
- if (profile->checkCompatibleChannelMask(channelMask, updatedChannels,
- portType, portRole) == NO_ERROR &&
- profile->checkCompatibleSamplingRate(samplingRate, updatedRate) == NO_ERROR) {
- // for inexact checks we take the first linear pcm format due to sorting.
- format = formatToCompare;
- channelMask = updatedChannels;
- samplingRate = updatedRate;
- return NO_ERROR;
- }
- }
- }
- return BAD_VALUE;
-}
-
-void AudioProfileVector::clearProfiles()
-{
- for (size_t i = size(); i != 0; ) {
- sp<AudioProfile> profile = itemAt(--i);
- if (profile->isDynamicFormat() && profile->hasValidFormat()) {
- removeAt(i);
- continue;
- }
- profile->clear();
- }
-}
-
-// Returns an intersection between two possibly unsorted vectors and the contents of 'order'.
-// The result is ordered according to 'order'.
-template<typename T, typename Order>
-std::vector<typename T::value_type> intersectFilterAndOrder(
- const T& input1, const T& input2, const Order& order)
-{
- std::set<typename T::value_type> set1{input1.begin(), input1.end()};
- std::set<typename T::value_type> set2{input2.begin(), input2.end()};
- std::set<typename T::value_type> common;
- std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(),
- std::inserter(common, common.begin()));
- std::vector<typename T::value_type> result;
- for (const auto& e : order) {
- if (common.find(e) != common.end()) result.push_back(e);
- }
- return result;
-}
-
-// Intersect two possibly unsorted vectors, return common elements according to 'comp' ordering.
-// 'comp' is a comparator function.
-template<typename T, typename Compare>
-std::vector<typename T::value_type> intersectAndOrder(
- const T& input1, const T& input2, Compare comp)
-{
- std::set<typename T::value_type, Compare> set1{input1.begin(), input1.end(), comp};
- std::set<typename T::value_type, Compare> set2{input2.begin(), input2.end(), comp};
- std::vector<typename T::value_type> result;
- std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(),
- std::back_inserter(result), comp);
- return result;
-}
-
-status_t AudioProfileVector::findBestMatchingOutputConfig(const AudioProfileVector& outputProfiles,
- const std::vector<audio_format_t>& preferredFormats,
- const std::vector<audio_channel_mask_t>& preferredOutputChannels,
- bool preferHigherSamplingRates,
- audio_config_base *bestOutputConfig) const
-{
- auto formats = intersectFilterAndOrder(getSupportedFormats(),
- outputProfiles.getSupportedFormats(), preferredFormats);
- // Pick the best compatible profile.
- for (const auto& f : formats) {
- sp<AudioProfile> inputProfile = getFirstValidProfileFor(f);
- sp<AudioProfile> outputProfile = outputProfiles.getFirstValidProfileFor(f);
- if (inputProfile == nullptr || outputProfile == nullptr) {
- continue;
- }
- auto channels = intersectFilterAndOrder(inputProfile->getChannels().asOutMask(),
- outputProfile->getChannels(), preferredOutputChannels);
- if (channels.empty()) {
- continue;
- }
- auto sampleRates = preferHigherSamplingRates ?
- intersectAndOrder(inputProfile->getSampleRates(), outputProfile->getSampleRates(),
- std::greater<typename SampleRateVector::value_type>()) :
- intersectAndOrder(inputProfile->getSampleRates(), outputProfile->getSampleRates(),
- std::less<typename SampleRateVector::value_type>());
- if (sampleRates.empty()) {
- continue;
- }
- ALOGD("%s() found channel mask %#x and sample rate %d for format %#x.",
- __func__, *channels.begin(), *sampleRates.begin(), f);
- bestOutputConfig->format = f;
- bestOutputConfig->sample_rate = *sampleRates.begin();
- bestOutputConfig->channel_mask = *channels.begin();
- return NO_ERROR;
- }
- return BAD_VALUE;
-}
-
-sp<AudioProfile> AudioProfileVector::getFirstValidProfile() const
-{
- for (size_t i = 0; i < size(); i++) {
- if (itemAt(i)->isValid()) {
- return itemAt(i);
- }
- }
- return 0;
-}
-
-sp<AudioProfile> AudioProfileVector::getFirstValidProfileFor(audio_format_t format) const
-{
- for (size_t i = 0; i < size(); i++) {
- if (itemAt(i)->isValid() && itemAt(i)->getFormat() == format) {
- return itemAt(i);
- }
- }
- return 0;
-}
-
-FormatVector AudioProfileVector::getSupportedFormats() const
-{
- FormatVector supportedFormats;
- for (size_t i = 0; i < size(); i++) {
- if (itemAt(i)->hasValidFormat()) {
- supportedFormats.add(itemAt(i)->getFormat());
- }
- }
- return supportedFormats;
-}
-
-bool AudioProfileVector::hasDynamicChannelsFor(audio_format_t format) const
-{
- for (size_t i = 0; i < size(); i++) {
- sp<AudioProfile> profile = itemAt(i);
- if (profile->getFormat() == format && profile->isDynamicChannels()) {
- return true;
- }
- }
- return false;
-}
-
-bool AudioProfileVector::hasDynamicProfile() const
-{
- for (size_t i = 0; i < size(); i++) {
- if (itemAt(i)->isDynamic()) {
- return true;
- }
- }
- return false;
-}
-
-bool AudioProfileVector::hasDynamicRateFor(audio_format_t format) const
-{
- for (size_t i = 0; i < size(); i++) {
- sp<AudioProfile> profile = itemAt(i);
- if (profile->getFormat() == format && profile->isDynamicRate()) {
- return true;
- }
- }
- return false;
-}
-
-void AudioProfileVector::setFormats(const FormatVector &formats)
-{
- // Only allow to change the format of dynamic profile
- sp<AudioProfile> dynamicFormatProfile = getProfileFor(gDynamicFormat);
- if (dynamicFormatProfile == 0) {
- return;
- }
- for (size_t i = 0; i < formats.size(); i++) {
- sp<AudioProfile> profile = new AudioProfile(formats[i],
- dynamicFormatProfile->getChannels(),
- dynamicFormatProfile->getSampleRates());
- profile->setDynamicFormat(true);
- profile->setDynamicChannels(dynamicFormatProfile->isDynamicChannels());
- profile->setDynamicRate(dynamicFormatProfile->isDynamicRate());
- add(profile);
- }
-}
-
-void AudioProfileVector::dump(String8 *dst, int spaces) const
-{
- dst->appendFormat("%*s- Profiles:\n", spaces, "");
- for (size_t i = 0; i < size(); i++) {
- dst->appendFormat("%*sProfile %zu:", spaces + 4, "", i);
- itemAt(i)->dump(dst, spaces + 8);
- }
-}
-
-sp<AudioProfile> AudioProfileVector::getProfileFor(audio_format_t format) const
-{
- for (size_t i = 0; i < size(); i++) {
- if (itemAt(i)->getFormat() == format) {
- return itemAt(i);
- }
- }
- return 0;
-}
-
-void AudioProfileVector::setSampleRatesFor(
- const SampleRateVector &sampleRates, audio_format_t format)
-{
- for (size_t i = 0; i < size(); i++) {
- sp<AudioProfile> profile = itemAt(i);
- if (profile->getFormat() == format && profile->isDynamicRate()) {
- if (profile->hasValidRates()) {
- // Need to create a new profile with same format
- sp<AudioProfile> profileToAdd = new AudioProfile(format, profile->getChannels(),
- sampleRates);
- profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
- add(profileToAdd);
- } else {
- profile->setSampleRates(sampleRates);
- }
- return;
- }
- }
-}
-
-void AudioProfileVector::setChannelsFor(const ChannelsVector &channelMasks, audio_format_t format)
-{
- for (size_t i = 0; i < size(); i++) {
- sp<AudioProfile> profile = itemAt(i);
- if (profile->getFormat() == format && profile->isDynamicChannels()) {
- if (profile->hasValidChannels()) {
- // Need to create a new profile with same format
- sp<AudioProfile> profileToAdd = new AudioProfile(format, channelMasks,
- profile->getSampleRates());
- profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
- add(profileToAdd);
- } else {
- profile->setChannels(channelMasks);
- }
- return;
- }
- }
-}
-
-// static
-int AudioProfileVector::compareFormats(const sp<AudioProfile> *profile1,
- const sp<AudioProfile> *profile2)
-{
- return AudioPort::compareFormats((*profile1)->getFormat(), (*profile2)->getFormat());
-}
-
-} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioProfileVectorHelper.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioProfileVectorHelper.cpp
new file mode 100644
index 0000000..8ccb8b9
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioProfileVectorHelper.cpp
@@ -0,0 +1,439 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+#include <set>
+#include <string>
+
+#define LOG_TAG "APM::AudioProfileVectorHelper"
+//#define LOG_NDEBUG 0
+
+#include <media/AudioContainers.h>
+#include <media/AudioResamplerPublic.h>
+#include <utils/Errors.h>
+
+#include "AudioProfileVectorHelper.h"
+#include "HwModule.h"
+#include "PolicyAudioPort.h"
+#include "policy.h"
+
+namespace android {
+
+void sortAudioProfiles(AudioProfileVector &audioProfileVector) {
+ std::sort(audioProfileVector.begin(), audioProfileVector.end(),
+ [](const sp<AudioProfile> & a, const sp<AudioProfile> & b)
+ {
+ return PolicyAudioPort::compareFormats(a->getFormat(), b->getFormat()) < 0;
+ });
+}
+
+ssize_t addAudioProfileAndSort(AudioProfileVector &audioProfileVector,
+ const sp<AudioProfile> &profile)
+{
+ ssize_t ret = audioProfileVector.add(profile);
+ // we sort from worst to best, so that AUDIO_FORMAT_DEFAULT is always the first entry.
+ sortAudioProfiles(audioProfileVector);
+ return ret;
+}
+
+sp<AudioProfile> getAudioProfileForFormat(const AudioProfileVector &audioProfileVector,
+ audio_format_t format)
+{
+ for (const auto &profile : audioProfileVector) {
+ if (profile->getFormat() == format) {
+ return profile;
+ }
+ }
+ return nullptr;
+}
+
+void setSampleRatesForAudioProfiles(AudioProfileVector &audioProfileVector,
+ const SampleRateSet &sampleRateSet,
+ audio_format_t format)
+{
+ for (const auto &profile : audioProfileVector) {
+ if (profile->getFormat() == format && profile->isDynamicRate()) {
+ if (profile->hasValidRates()) {
+ // Need to create a new profile with same format
+ sp<AudioProfile> profileToAdd = new AudioProfile(
+ format, profile->getChannels(), sampleRateSet);
+ profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
+ addAudioProfileAndSort(audioProfileVector, profileToAdd);
+ } else {
+ profile->setSampleRates(sampleRateSet);
+ }
+ return;
+ }
+ }
+}
+
+void setChannelsForAudioProfiles(AudioProfileVector &audioProfileVector,
+ const ChannelMaskSet &channelMaskSet,
+ audio_format_t format)
+{
+ for (const auto &profile : audioProfileVector) {
+ if (profile->getFormat() == format && profile->isDynamicChannels()) {
+ if (profile->hasValidChannels()) {
+ // Need to create a new profile with same format
+ sp<AudioProfile> profileToAdd = new AudioProfile(format, channelMaskSet,
+ profile->getSampleRates());
+ profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
+ addAudioProfileAndSort(audioProfileVector, profileToAdd);
+ } else {
+ profile->setChannels(channelMaskSet);
+ }
+ return;
+ }
+ }
+}
+
+void addProfilesForFormats(AudioProfileVector &audioProfileVector, const FormatVector &formatVector)
+{
+ // Only allow to change the format of dynamic profile
+ sp<AudioProfile> dynamicFormatProfile = getAudioProfileForFormat(
+ audioProfileVector, gDynamicFormat);
+ if (!dynamicFormatProfile) {
+ return;
+ }
+ for (const auto &format : formatVector) {
+ sp<AudioProfile> profile = new AudioProfile(format,
+ dynamicFormatProfile->getChannels(),
+ dynamicFormatProfile->getSampleRates());
+ profile->setDynamicFormat(true);
+ profile->setDynamicChannels(dynamicFormatProfile->isDynamicChannels());
+ profile->setDynamicRate(dynamicFormatProfile->isDynamicRate());
+ addAudioProfileAndSort(audioProfileVector, profile);
+ }
+}
+
+void addDynamicAudioProfileAndSort(AudioProfileVector &audioProfileVector,
+ const sp<AudioProfile> &profileToAdd)
+{
+ // Check valid profile to add:
+ if (!profileToAdd->hasValidFormat()) {
+ ALOGW("Adding dynamic audio profile without valid format");
+ return;
+ }
+ if (!profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
+ FormatVector formats;
+ formats.push_back(profileToAdd->getFormat());
+ addProfilesForFormats(audioProfileVector, FormatVector(formats));
+ return;
+ }
+ if (!profileToAdd->hasValidChannels() && profileToAdd->hasValidRates()) {
+ setSampleRatesForAudioProfiles(
+ audioProfileVector, profileToAdd->getSampleRates(), profileToAdd->getFormat());
+ return;
+ }
+ if (profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
+ setChannelsForAudioProfiles(
+ audioProfileVector, profileToAdd->getChannels(), profileToAdd->getFormat());
+ return;
+ }
+ // Go through the list of profile to avoid duplicates
+ for (size_t profileIndex = 0; profileIndex < audioProfileVector.size(); profileIndex++) {
+ const sp<AudioProfile> &profile = audioProfileVector.at(profileIndex);
+ if (profile->isValid() && profile == profileToAdd) {
+ // Nothing to do
+ return;
+ }
+ }
+ profileToAdd->setDynamicFormat(true); // set the format as dynamic to allow removal
+ addAudioProfileAndSort(audioProfileVector, profileToAdd);
+}
+
+void appendAudioProfiles(AudioProfileVector &audioProfileVector,
+ const AudioProfileVector &audioProfileVectorToAppend)
+{
+ audioProfileVector.insert(audioProfileVector.end(),
+ audioProfileVectorToAppend.begin(),
+ audioProfileVectorToAppend.end());
+}
+
+status_t checkExact(const sp<AudioProfile> &audioProfile,
+ uint32_t samplingRate,
+ audio_channel_mask_t channelMask,
+ audio_format_t format)
+{
+ if (audio_formats_match(format, audioProfile->getFormat()) &&
+ audioProfile->supportsChannels(channelMask) &&
+ audioProfile->supportsRate(samplingRate)) {
+ return NO_ERROR;
+ }
+ return BAD_VALUE;
+}
+
+status_t checkCompatibleSamplingRate(const sp<AudioProfile> &audioProfile,
+ uint32_t samplingRate,
+ uint32_t &updatedSamplingRate)
+{
+ ALOG_ASSERT(samplingRate > 0);
+
+ const SampleRateSet sampleRates = audioProfile->getSampleRates();
+ if (sampleRates.empty()) {
+ updatedSamplingRate = samplingRate;
+ return NO_ERROR;
+ }
+
+ // Search for the closest supported sampling rate that is above (preferred)
+ // or below (acceptable) the desired sampling rate, within a permitted ratio.
+ // The sampling rates are sorted in ascending order.
+ auto desiredRate = sampleRates.lower_bound(samplingRate);
+
+ // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
+ if (desiredRate != sampleRates.end()) {
+ if (*desiredRate / AUDIO_RESAMPLER_DOWN_RATIO_MAX <= samplingRate) {
+ updatedSamplingRate = *desiredRate;
+ return NO_ERROR;
+ }
+ }
+ // But if we have to up-sample from a lower sampling rate, that's OK.
+ if (desiredRate != sampleRates.begin()) {
+ uint32_t candidate = *(--desiredRate);
+ if (candidate * AUDIO_RESAMPLER_UP_RATIO_MAX >= samplingRate) {
+ updatedSamplingRate = candidate;
+ return NO_ERROR;
+ }
+ }
+ // leave updatedSamplingRate unmodified
+ return BAD_VALUE;
+}
+
+status_t checkCompatibleChannelMask(const sp<AudioProfile> &audioProfile,
+ audio_channel_mask_t channelMask,
+ audio_channel_mask_t &updatedChannelMask,
+ audio_port_type_t portType,
+ audio_port_role_t portRole)
+{
+ const ChannelMaskSet channelMasks = audioProfile->getChannels();
+ if (channelMasks.empty()) {
+ updatedChannelMask = channelMask;
+ return NO_ERROR;
+ }
+ const bool isRecordThread = portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK;
+ const bool isIndex = audio_channel_mask_get_representation(channelMask)
+ == AUDIO_CHANNEL_REPRESENTATION_INDEX;
+ const uint32_t channelCount = audio_channel_count_from_in_mask(channelMask);
+ int bestMatch = 0;
+ for (const auto &supported : channelMasks) {
+ if (supported == channelMask) {
+ // Exact matches always taken.
+ updatedChannelMask = channelMask;
+ return NO_ERROR;
+ }
+
+ // AUDIO_CHANNEL_NONE (value: 0) is used for dynamic channel support
+ if (isRecordThread && supported != AUDIO_CHANNEL_NONE) {
+ // Approximate (best) match:
+ // The match score measures how well the supported channel mask matches the
+ // desired mask, where increasing-is-better.
+ //
+ // TODO: Some tweaks may be needed.
+ // Should be a static function of the data processing library.
+ //
+ // In priority:
+ // match score = 1000 if legacy channel conversion equivalent (always prefer this)
+ // OR
+ // match score += 100 if the channel mask representations match
+ // match score += number of channels matched.
+ // match score += 100 if the channel mask representations DO NOT match
+ // but the profile has positional channel mask and less than 2 channels.
+ // This is for audio HAL convention to not list index masks for less than 2 channels
+ //
+ // If there are no matched channels, the mask may still be accepted
+ // but the playback or record will be silent.
+ const bool isSupportedIndex = (audio_channel_mask_get_representation(supported)
+ == AUDIO_CHANNEL_REPRESENTATION_INDEX);
+ const uint32_t supportedChannelCount = audio_channel_count_from_in_mask(supported);
+ int match;
+ if (isIndex && isSupportedIndex) {
+ // index equivalence
+ match = 100 + __builtin_popcount(
+ audio_channel_mask_get_bits(channelMask)
+ & audio_channel_mask_get_bits(supported));
+ } else if (isIndex && !isSupportedIndex) {
+ const uint32_t equivalentBits = (1 << supportedChannelCount) - 1 ;
+ match = __builtin_popcount(
+ audio_channel_mask_get_bits(channelMask) & equivalentBits);
+ if (supportedChannelCount <= FCC_2) {
+ match += 100;
+ }
+ } else if (!isIndex && isSupportedIndex) {
+ const uint32_t equivalentBits = (1 << channelCount) - 1;
+ match = __builtin_popcount(
+ equivalentBits & audio_channel_mask_get_bits(supported));
+ } else {
+ // positional equivalence
+ match = 100 + __builtin_popcount(
+ audio_channel_mask_get_bits(channelMask)
+ & audio_channel_mask_get_bits(supported));
+ switch (supported) {
+ case AUDIO_CHANNEL_IN_FRONT_BACK:
+ case AUDIO_CHANNEL_IN_STEREO:
+ if (channelMask == AUDIO_CHANNEL_IN_MONO) {
+ match = 1000;
+ }
+ break;
+ case AUDIO_CHANNEL_IN_MONO:
+ if (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK
+ || channelMask == AUDIO_CHANNEL_IN_STEREO) {
+ match = 1000;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ if (match > bestMatch) {
+ bestMatch = match;
+ updatedChannelMask = supported;
+ }
+ }
+ }
+ return bestMatch > 0 ? NO_ERROR : BAD_VALUE;
+}
+
+status_t checkExactProfile(const AudioProfileVector& audioProfileVector,
+ const uint32_t samplingRate,
+ audio_channel_mask_t channelMask,
+ audio_format_t format)
+{
+ if (audioProfileVector.empty()) {
+ return NO_ERROR;
+ }
+
+ for (const auto& profile : audioProfileVector) {
+ if (checkExact(profile, samplingRate, channelMask, format) == NO_ERROR) {
+ return NO_ERROR;
+ }
+ }
+ return BAD_VALUE;
+}
+
+status_t checkCompatibleProfile(const AudioProfileVector &audioProfileVector,
+ uint32_t &samplingRate,
+ audio_channel_mask_t &channelMask,
+ audio_format_t &format,
+ audio_port_type_t portType,
+ audio_port_role_t portRole)
+{
+ if (audioProfileVector.empty()) {
+ return NO_ERROR;
+ }
+
+ const bool checkInexact = // when port is input and format is linear pcm
+ portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK
+ && audio_is_linear_pcm(format);
+
+ // iterate from best format to worst format (reverse order)
+ for (ssize_t i = audioProfileVector.size() - 1; i >= 0 ; --i) {
+ const sp<AudioProfile> profile = audioProfileVector.at(i);
+ audio_format_t formatToCompare = profile->getFormat();
+ if (formatToCompare == format ||
+ (checkInexact
+ && formatToCompare != AUDIO_FORMAT_DEFAULT
+ && audio_is_linear_pcm(formatToCompare))) {
+ // Compatible profile has been found, checks if this profile has compatible
+ // rate and channels as well
+ audio_channel_mask_t updatedChannels;
+ uint32_t updatedRate;
+ if (checkCompatibleChannelMask(profile, channelMask, updatedChannels,
+ portType, portRole) == NO_ERROR &&
+ checkCompatibleSamplingRate(profile, samplingRate, updatedRate) == NO_ERROR) {
+ // for inexact checks we take the first linear pcm format due to sorting.
+ format = formatToCompare;
+ channelMask = updatedChannels;
+ samplingRate = updatedRate;
+ return NO_ERROR;
+ }
+ }
+ }
+ return BAD_VALUE;
+}
+
+// Returns an intersection between two possibly unsorted vectors and the contents of 'order'.
+// The result is ordered according to 'order'.
+template<typename T, typename Order>
+std::vector<typename T::value_type> intersectFilterAndOrder(
+ const T& input1, const T& input2, const Order& order)
+{
+ std::set<typename T::value_type> set1{input1.begin(), input1.end()};
+ std::set<typename T::value_type> set2{input2.begin(), input2.end()};
+ std::set<typename T::value_type> common;
+ std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(),
+ std::inserter(common, common.begin()));
+ std::vector<typename T::value_type> result;
+ for (const auto& e : order) {
+ if (common.find(e) != common.end()) result.push_back(e);
+ }
+ return result;
+}
+
+// Intersect two possibly unsorted vectors, return common elements according to 'comp' ordering.
+// 'comp' is a comparator function.
+template<typename T, typename Compare>
+std::vector<typename T::value_type> intersectAndOrder(
+ const T& input1, const T& input2, Compare comp)
+{
+ std::set<typename T::value_type, Compare> set1{input1.begin(), input1.end(), comp};
+ std::set<typename T::value_type, Compare> set2{input2.begin(), input2.end(), comp};
+ std::vector<typename T::value_type> result;
+ std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(),
+ std::back_inserter(result), comp);
+ return result;
+}
+
+status_t findBestMatchingOutputConfig(
+ const AudioProfileVector &audioProfileVector,
+ const AudioProfileVector &outputProfileVector,
+ const std::vector<audio_format_t> &preferredFormatVector, // order: most pref -> least pref
+ const std::vector<audio_channel_mask_t> &preferredOutputChannelVector,
+ bool preferHigherSamplingRates,
+ audio_config_base &bestOutputConfig)
+{
+ auto formats = intersectFilterAndOrder(audioProfileVector.getSupportedFormats(),
+ outputProfileVector.getSupportedFormats(), preferredFormatVector);
+ // Pick the best compatible profile.
+ for (const auto& f : formats) {
+ sp<AudioProfile> inputProfile = audioProfileVector.getFirstValidProfileFor(f);
+ sp<AudioProfile> outputProfile = outputProfileVector.getFirstValidProfileFor(f);
+ if (inputProfile == nullptr || outputProfile == nullptr) {
+ continue;
+ }
+ auto channels = intersectFilterAndOrder(asOutMask(inputProfile->getChannels()),
+ outputProfile->getChannels(), preferredOutputChannelVector);
+ if (channels.empty()) {
+ continue;
+ }
+ auto sampleRates = preferHigherSamplingRates ?
+ intersectAndOrder(inputProfile->getSampleRates(), outputProfile->getSampleRates(),
+ std::greater<typename SampleRateSet::value_type>()) :
+ intersectAndOrder(inputProfile->getSampleRates(), outputProfile->getSampleRates(),
+ std::less<typename SampleRateSet::value_type>());
+ if (sampleRates.empty()) {
+ continue;
+ }
+ ALOGD("%s() found channel mask %#x and sample rate %d for format %#x.",
+ __func__, *channels.begin(), *sampleRates.begin(), f);
+ bestOutputConfig.format = f;
+ bestOutputConfig.sample_rate = *sampleRates.begin();
+ bestOutputConfig.channel_mask = *channels.begin();
+ return NO_ERROR;
+ }
+ return BAD_VALUE;
+}
+
+} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
index 79f0919..2a18f19 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
@@ -19,7 +19,6 @@
#include "AudioRoute.h"
#include "HwModule.h"
-#include "AudioGain.h"
namespace android
{
@@ -27,25 +26,26 @@
void AudioRoute::dump(String8 *dst, int spaces) const
{
dst->appendFormat("%*s- Type: %s\n", spaces, "", mType == AUDIO_ROUTE_MUX ? "Mux" : "Mix");
- dst->appendFormat("%*s- Sink: %s\n", spaces, "", mSink->getTagName().string());
+ dst->appendFormat("%*s- Sink: %s\n", spaces, "", mSink->getTagName().c_str());
if (mSources.size() != 0) {
dst->appendFormat("%*s- Sources: \n", spaces, "");
for (size_t i = 0; i < mSources.size(); i++) {
- dst->appendFormat("%*s%s \n", spaces + 4, "", mSources[i]->getTagName().string());
+ dst->appendFormat("%*s%s \n", spaces + 4, "", mSources[i]->getTagName().c_str());
}
}
dst->append("\n");
}
-bool AudioRoute::supportsPatch(const sp<AudioPort> &srcPort, const sp<AudioPort> &dstPort) const
+bool AudioRoute::supportsPatch(const sp<PolicyAudioPort> &srcPort,
+ const sp<PolicyAudioPort> &dstPort) const
{
if (mSink == 0 || dstPort == 0 || dstPort != mSink) {
return false;
}
- ALOGV("%s: sinks %s matching", __FUNCTION__, mSink->getTagName().string());
+ ALOGV("%s: sinks %s matching", __FUNCTION__, mSink->getTagName().c_str());
for (const auto &sourcePort : mSources) {
if (sourcePort == srcPort) {
- ALOGV("%s: sources %s matching", __FUNCTION__, sourcePort->getTagName().string());
+ ALOGV("%s: sources %s matching", __FUNCTION__, sourcePort->getTagName().c_str());
return true;
}
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
index ad07ab1..95822b9 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
@@ -21,7 +21,6 @@
#include <utils/Log.h>
#include <utils/String8.h>
#include <TypeConverter.h>
-#include "AudioGain.h"
#include "AudioOutputDescriptor.h"
#include "AudioPatch.h"
#include "ClientDescriptor.h"
@@ -83,14 +82,13 @@
}
SourceClientDescriptor::SourceClientDescriptor(audio_port_handle_t portId, uid_t uid,
- audio_attributes_t attributes, const sp<AudioPatch>& patchDesc,
+ audio_attributes_t attributes, const struct audio_port_config &config,
const sp<DeviceDescriptor>& srcDevice, audio_stream_type_t stream,
product_strategy_t strategy, VolumeSource volumeSource) :
TrackClientDescriptor::TrackClientDescriptor(portId, uid, AUDIO_SESSION_NONE, attributes,
- AUDIO_CONFIG_BASE_INITIALIZER, AUDIO_PORT_HANDLE_NONE,
+ {config.sample_rate, config.channel_mask, config.format}, AUDIO_PORT_HANDLE_NONE,
stream, strategy, volumeSource, AUDIO_OUTPUT_FLAG_NONE, false,
- {} /* Sources do not support secondary outputs*/),
- mPatchDesc(patchDesc), mSrcDevice(srcDevice)
+ {} /* Sources do not support secondary outputs*/), mSrcDevice(srcDevice)
{
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index ecd5b34..86dbba8 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -22,52 +22,56 @@
#include <set>
#include "DeviceDescriptor.h"
#include "TypeConverter.h"
-#include "AudioGain.h"
#include "HwModule.h"
namespace android {
-DeviceDescriptor::DeviceDescriptor(audio_devices_t type, const String8 &tagName) :
- DeviceDescriptor(type, FormatVector{}, tagName)
+DeviceDescriptor::DeviceDescriptor(audio_devices_t type) :
+ DeviceDescriptor(type, "" /*tagName*/)
{
}
-DeviceDescriptor::DeviceDescriptor(audio_devices_t type, const FormatVector &encodedFormats,
- const String8 &tagName) :
- AudioPort(String8(""), AUDIO_PORT_TYPE_DEVICE,
- audio_is_output_device(type) ? AUDIO_PORT_ROLE_SINK :
- AUDIO_PORT_ROLE_SOURCE),
- mTagName(tagName), mDeviceType(type), mEncodedFormats(encodedFormats)
+DeviceDescriptor::DeviceDescriptor(audio_devices_t type,
+ const std::string &tagName,
+ const FormatVector &encodedFormats) :
+ DeviceDescriptor(type, tagName, "" /*address*/, encodedFormats)
+{
+}
+
+DeviceDescriptor::DeviceDescriptor(audio_devices_t type,
+ const std::string &tagName,
+ const std::string &address,
+ const FormatVector &encodedFormats) :
+ DeviceDescriptor(AudioDeviceTypeAddr(type, address), tagName, encodedFormats)
+{
+}
+
+DeviceDescriptor::DeviceDescriptor(const AudioDeviceTypeAddr &deviceTypeAddr,
+ const std::string &tagName,
+ const FormatVector &encodedFormats) :
+ DeviceDescriptorBase(deviceTypeAddr), mTagName(tagName), mEncodedFormats(encodedFormats)
{
mCurrentEncodedFormat = AUDIO_FORMAT_DEFAULT;
- if (audio_is_remote_submix_device(type)) {
- mAddress = String8("0");
- }
/* If framework runs against a pre 5.0 Audio HAL, encoded formats are absent from the config.
* FIXME: APM should know the version of the HAL and don't add the formats for V5.0.
* For now, the workaround to remove AC3 and IEC61937 support on HDMI is to declare
* something like 'encodedFormats="AUDIO_FORMAT_PCM_16_BIT"' on the HDMI devicePort.
*/
- if (type == AUDIO_DEVICE_OUT_HDMI && mEncodedFormats.isEmpty()) {
- mEncodedFormats.add(AUDIO_FORMAT_AC3);
- mEncodedFormats.add(AUDIO_FORMAT_IEC61937);
+ if (mDeviceTypeAddr.mType == AUDIO_DEVICE_OUT_HDMI && mEncodedFormats.empty()) {
+ mEncodedFormats.push_back(AUDIO_FORMAT_AC3);
+ mEncodedFormats.push_back(AUDIO_FORMAT_IEC61937);
}
}
-audio_port_handle_t DeviceDescriptor::getId() const
-{
- return mId;
-}
-
void DeviceDescriptor::attach(const sp<HwModule>& module)
{
- AudioPort::attach(module);
+ PolicyAudioPort::attach(module);
mId = getNextUniqueId();
}
void DeviceDescriptor::detach() {
mId = AUDIO_PORT_HANDLE_NONE;
- AudioPort::detach();
+ PolicyAudioPort::detach();
}
template<typename T>
@@ -88,7 +92,7 @@
return false;
}
- return (mDeviceType == other->mDeviceType) && (mAddress == other->mAddress) &&
+ return mDeviceTypeAddr.equals(other->mDeviceTypeAddr) &&
checkEqual(mEncodedFormats, other->mEncodedFormats);
}
@@ -97,7 +101,7 @@
if (!device_has_encoding_capability(type())) {
return true;
}
- if (mEncodedFormats.isEmpty()) {
+ if (mEncodedFormats.empty()) {
return true;
}
@@ -106,7 +110,7 @@
bool DeviceDescriptor::supportsFormat(audio_format_t format)
{
- if (mEncodedFormats.isEmpty()) {
+ if (mEncodedFormats.empty()) {
return true;
}
@@ -118,13 +122,69 @@
return false;
}
+status_t DeviceDescriptor::applyAudioPortConfig(const struct audio_port_config *config,
+ audio_port_config *backupConfig)
+{
+ struct audio_port_config localBackupConfig = { .config_mask = config->config_mask };
+ status_t status = NO_ERROR;
+
+ toAudioPortConfig(&localBackupConfig);
+ if ((status = validationBeforeApplyConfig(config)) == NO_ERROR) {
+ AudioPortConfig::applyAudioPortConfig(config, backupConfig);
+ applyPolicyAudioPortConfig(config);
+ }
+
+ if (backupConfig != NULL) {
+ *backupConfig = localBackupConfig;
+ }
+ return status;
+}
+
+void DeviceDescriptor::toAudioPortConfig(struct audio_port_config *dstConfig,
+ const struct audio_port_config *srcConfig) const
+{
+ DeviceDescriptorBase::toAudioPortConfig(dstConfig, srcConfig);
+ toPolicyAudioPortConfig(dstConfig, srcConfig);
+
+ dstConfig->ext.device.hw_module = getModuleHandle();
+}
+
+void DeviceDescriptor::toAudioPort(struct audio_port *port) const
+{
+ ALOGV("DeviceDescriptor::toAudioPort() handle %d type %08x", mId, mDeviceTypeAddr.mType);
+ DeviceDescriptorBase::toAudioPort(port);
+ port->ext.device.hw_module = getModuleHandle();
+}
+
+void DeviceDescriptor::importAudioPortAndPickAudioProfile(
+ const sp<PolicyAudioPort>& policyPort, bool force) {
+ if (!force && !policyPort->asAudioPort()->hasDynamicAudioProfile()) {
+ return;
+ }
+ AudioPort::importAudioPort(policyPort->asAudioPort());
+ policyPort->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
+}
+
+void DeviceDescriptor::dump(String8 *dst, int spaces, int index, bool verbose) const
+{
+ String8 extraInfo;
+ if (!mTagName.empty()) {
+ extraInfo.appendFormat("%*s- tag name: %s\n", spaces, "", mTagName.c_str());
+ }
+
+ std::string descBaseDumpStr;
+ DeviceDescriptorBase::dump(&descBaseDumpStr, spaces, index, extraInfo.string(), verbose);
+ dst->append(descBaseDumpStr.c_str());
+}
+
+
void DeviceVector::refreshTypes()
{
- mDeviceTypes = AUDIO_DEVICE_NONE;
+ mDeviceTypes.clear();
for (size_t i = 0; i < size(); i++) {
- mDeviceTypes |= itemAt(i)->type();
+ mDeviceTypes.insert(itemAt(i)->type());
}
- ALOGV("DeviceVector::refreshTypes() mDeviceTypes %08x", mDeviceTypes);
+ ALOGV("DeviceVector::refreshTypes() mDeviceTypes %s", dumpDeviceTypes(mDeviceTypes).c_str());
}
ssize_t DeviceVector::indexOf(const sp<DeviceDescriptor>& item) const
@@ -199,17 +259,6 @@
return devices;
}
-audio_devices_t DeviceVector::getDeviceTypesFromHwModule(audio_module_handle_t moduleHandle) const
-{
- audio_devices_t deviceTypes = AUDIO_DEVICE_NONE;
- for (const auto& device : *this) {
- if (device->getModuleHandle() == moduleHandle) {
- deviceTypes |= device->type();
- }
- }
- return deviceTypes;
-}
-
sp<DeviceDescriptor> DeviceVector::getDevice(audio_devices_t type, const String8& address,
audio_format_t format) const
{
@@ -219,11 +268,11 @@
// If format is specified, match it and ignore address
// Otherwise if address is specified match it
// Otherwise always match
- if (((address == "" || itemAt(i)->address() == address) &&
+ if (((address == "" || (itemAt(i)->address().compare(address.c_str()) == 0)) &&
format == AUDIO_FORMAT_DEFAULT) ||
(itemAt(i)->supportsFormat(format) && format != AUDIO_FORMAT_DEFAULT)) {
device = itemAt(i);
- if (itemAt(i)->address() == address) {
+ if (itemAt(i)->address().compare(address.c_str()) == 0) {
break;
}
}
@@ -246,17 +295,15 @@
return nullptr;
}
-DeviceVector DeviceVector::getDevicesFromTypeMask(audio_devices_t type) const
+DeviceVector DeviceVector::getDevicesFromTypes(const DeviceTypeSet& types) const
{
DeviceVector devices;
- bool isOutput = audio_is_output_devices(type);
- type &= ~AUDIO_DEVICE_BIT_IN;
- for (size_t i = 0; (i < size()) && (type != AUDIO_DEVICE_NONE); i++) {
- bool curIsOutput = audio_is_output_devices(itemAt(i)->type());
- audio_devices_t curType = itemAt(i)->type() & ~AUDIO_DEVICE_BIT_IN;
- if ((isOutput == curIsOutput) && ((type & curType) != 0)) {
+ if (types.empty()) {
+ return devices;
+ }
+ for (size_t i = 0; i < size(); i++) {
+ if (types.count(itemAt(i)->type()) != 0) {
devices.add(itemAt(i));
- type &= ~curType;
ALOGV("DeviceVector::%s() for type %08x found %p",
__func__, itemAt(i)->type(), itemAt(i).get());
}
@@ -264,7 +311,7 @@
return devices;
}
-sp<DeviceDescriptor> DeviceVector::getDeviceFromTagName(const String8 &tagName) const
+sp<DeviceDescriptor> DeviceVector::getDeviceFromTagName(const std::string &tagName) const
{
for (const auto& device : *this) {
if (device->getTagName() == tagName) {
@@ -274,6 +321,56 @@
return nullptr;
}
+DeviceVector DeviceVector::getFirstDevicesFromTypes(
+ std::vector<audio_devices_t> orderedTypes) const
+{
+ DeviceVector devices;
+ for (auto deviceType : orderedTypes) {
+ if (!(devices = getDevicesFromType(deviceType)).isEmpty()) {
+ break;
+ }
+ }
+ return devices;
+}
+
+sp<DeviceDescriptor> DeviceVector::getFirstExistingDevice(
+ std::vector<audio_devices_t> orderedTypes) const {
+ sp<DeviceDescriptor> device;
+ for (auto deviceType : orderedTypes) {
+ if ((device = getDevice(deviceType, String8(""), AUDIO_FORMAT_DEFAULT)) != nullptr) {
+ break;
+ }
+ }
+ return device;
+}
+
+sp<DeviceDescriptor> DeviceVector::getDeviceForOpening() const
+{
+ if (isEmpty()) {
+ // Return nullptr if this collection is empty.
+ return nullptr;
+ } else if (areAllOfSameDeviceType(types(), audio_is_input_device)) {
+ // For input case, return the first one when there is only one device.
+ return size() > 1 ? nullptr : *begin();
+ } else if (areAllOfSameDeviceType(types(), audio_is_output_device)) {
+ // For output case, return the device descriptor according to apm strategy.
+ audio_devices_t deviceType = apm_extract_one_audio_device(types());
+ return deviceType == AUDIO_DEVICE_NONE ? nullptr :
+ getDevice(deviceType, String8(""), AUDIO_FORMAT_DEFAULT);
+ }
+ // Return null pointer if the devices are not all input/output device.
+ return nullptr;
+}
+
+void DeviceVector::replaceDevicesByType(
+ audio_devices_t typeToRemove, const DeviceVector &devicesToAdd) {
+ DeviceVector devicesToRemove = getDevicesFromType(typeToRemove);
+ if (!devicesToRemove.isEmpty() && !devicesToAdd.isEmpty()) {
+ remove(devicesToRemove);
+ add(devicesToAdd);
+ }
+}
+
void DeviceVector::dump(String8 *dst, const String8 &tag, int spaces, bool verbose) const
{
if (isEmpty()) {
@@ -285,84 +382,6 @@
}
}
-void DeviceDescriptor::toAudioPortConfig(struct audio_port_config *dstConfig,
- const struct audio_port_config *srcConfig) const
-{
- dstConfig->config_mask = AUDIO_PORT_CONFIG_GAIN;
- if (mSamplingRate != 0) {
- dstConfig->config_mask |= AUDIO_PORT_CONFIG_SAMPLE_RATE;
- }
- if (mChannelMask != AUDIO_CHANNEL_NONE) {
- dstConfig->config_mask |= AUDIO_PORT_CONFIG_CHANNEL_MASK;
- }
- if (mFormat != AUDIO_FORMAT_INVALID) {
- dstConfig->config_mask |= AUDIO_PORT_CONFIG_FORMAT;
- }
-
- if (srcConfig != NULL) {
- dstConfig->config_mask |= srcConfig->config_mask;
- }
-
- AudioPortConfig::toAudioPortConfig(dstConfig, srcConfig);
-
- dstConfig->id = mId;
- dstConfig->role = audio_is_output_device(mDeviceType) ?
- AUDIO_PORT_ROLE_SINK : AUDIO_PORT_ROLE_SOURCE;
- dstConfig->type = AUDIO_PORT_TYPE_DEVICE;
- dstConfig->ext.device.type = mDeviceType;
-
- //TODO Understand why this test is necessary. i.e. why at boot time does it crash
- // without the test?
- // This has been demonstrated to NOT be true (at start up)
- // ALOG_ASSERT(mModule != NULL);
- dstConfig->ext.device.hw_module = getModuleHandle();
- (void)audio_utils_strlcpy_zerofill(dstConfig->ext.device.address, mAddress.string());
-}
-
-void DeviceDescriptor::toAudioPort(struct audio_port *port) const
-{
- ALOGV("DeviceDescriptor::toAudioPort() handle %d type %08x", mId, mDeviceType);
- AudioPort::toAudioPort(port);
- port->id = mId;
- toAudioPortConfig(&port->active_config);
- port->ext.device.type = mDeviceType;
- port->ext.device.hw_module = getModuleHandle();
- (void)audio_utils_strlcpy_zerofill(port->ext.device.address, mAddress.string());
-}
-
-void DeviceDescriptor::importAudioPort(const sp<AudioPort>& port, bool force) {
- if (!force && !port->hasDynamicAudioProfile()) {
- return;
- }
- AudioPort::importAudioPort(port);
- port->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
-}
-
-void DeviceDescriptor::dump(String8 *dst, int spaces, int index, bool verbose) const
-{
- dst->appendFormat("%*sDevice %d:\n", spaces, "", index + 1);
- if (mId != 0) {
- dst->appendFormat("%*s- id: %2d\n", spaces, "", mId);
- }
- if (!mTagName.isEmpty()) {
- dst->appendFormat("%*s- tag name: %s\n", spaces, "", mTagName.string());
- }
-
- dst->appendFormat("%*s- type: %-48s\n", spaces, "", ::android::toString(mDeviceType).c_str());
-
- if (mAddress.size() != 0) {
- dst->appendFormat("%*s- address: %-32s\n", spaces, "", mAddress.string());
- }
- AudioPort::dump(dst, spaces, verbose);
-}
-
-std::string DeviceDescriptor::toString() const
-{
- std::stringstream sstream;
- sstream << "type:0x" << std::hex << type() << ",@:" << mAddress;
- return sstream.str();
-}
-
std::string DeviceVector::toString() const
{
if (isEmpty()) {
@@ -411,13 +430,4 @@
return filteredDevices;
}
-void DeviceDescriptor::log() const
-{
- ALOGI("Device id:%d type:0x%08X:%s, addr:%s", mId, mDeviceType,
- ::android::toString(mDeviceType).c_str(),
- mAddress.string());
-
- AudioPort::log(" ");
-}
-
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index 1f9b725..886e4c9 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -19,7 +19,6 @@
#include "HwModule.h"
#include "IOProfile.h"
-#include "AudioGain.h"
#include <policy.h>
#include <system/audio.h>
@@ -42,7 +41,7 @@
}
}
-status_t HwModule::addOutputProfile(const String8& name, const audio_config_t *config,
+status_t HwModule::addOutputProfile(const std::string& name, const audio_config_t *config,
audio_devices_t device, const String8& address)
{
sp<IOProfile> profile = new OutputProfile(name);
@@ -50,8 +49,7 @@
profile->addAudioProfile(new AudioProfile(config->format, config->channel_mask,
config->sample_rate));
- sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
- devDesc->setAddress(address);
+ sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device, "" /*tagName*/, address.string());
addDynamicDevice(devDesc);
// Reciprocally attach the device to the module
devDesc->attach(this);
@@ -96,7 +94,7 @@
}
}
-status_t HwModule::removeOutputProfile(const String8& name)
+status_t HwModule::removeOutputProfile(const std::string& name)
{
for (size_t i = 0; i < mOutputProfiles.size(); i++) {
if (mOutputProfiles[i]->getName() == name) {
@@ -111,27 +109,26 @@
return NO_ERROR;
}
-status_t HwModule::addInputProfile(const String8& name, const audio_config_t *config,
+status_t HwModule::addInputProfile(const std::string& name, const audio_config_t *config,
audio_devices_t device, const String8& address)
{
sp<IOProfile> profile = new InputProfile(name);
profile->addAudioProfile(new AudioProfile(config->format, config->channel_mask,
config->sample_rate));
- sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
- devDesc->setAddress(address);
+ sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device, "" /*tagName*/, address.string());
addDynamicDevice(devDesc);
// Reciprocally attach the device to the module
devDesc->attach(this);
profile->addSupportedDevice(devDesc);
ALOGV("addInputProfile() name %s rate %d mask 0x%08x",
- name.string(), config->sample_rate, config->channel_mask);
+ name.c_str(), config->sample_rate, config->channel_mask);
return addInputProfile(profile);
}
-status_t HwModule::removeInputProfile(const String8& name)
+status_t HwModule::removeInputProfile(const std::string& name)
{
for (size_t i = 0; i < mInputProfiles.size(); i++) {
if (mInputProfiles[i]->getName() == name) {
@@ -157,7 +154,7 @@
sp<DeviceDescriptor> HwModule::getRouteSinkDevice(const sp<AudioRoute> &route) const
{
sp<DeviceDescriptor> sinkDevice = 0;
- if (route->getSink()->getType() == AUDIO_PORT_TYPE_DEVICE) {
+ if (route->getSink()->asAudioPort()->getType() == AUDIO_PORT_TYPE_DEVICE) {
sinkDevice = mDeclaredDevices.getDeviceFromTagName(route->getSink()->getTagName());
}
return sinkDevice;
@@ -167,7 +164,7 @@
{
DeviceVector sourceDevices;
for (const auto& source : route->getSources()) {
- if (source->getType() == AUDIO_PORT_TYPE_DEVICE) {
+ if (source->asAudioPort()->getType() == AUDIO_PORT_TYPE_DEVICE) {
sourceDevices.add(mDeclaredDevices.getDeviceFromTagName(source->getTagName()));
}
}
@@ -187,20 +184,20 @@
for (const auto& stream : mInputProfiles) {
DeviceVector sourceDevices;
for (const auto& route : stream->getRoutes()) {
- sp<AudioPort> sink = route->getSink();
+ sp<PolicyAudioPort> sink = route->getSink();
if (sink == 0 || stream != sink) {
ALOGE("%s: Invalid route attached to input stream", __FUNCTION__);
continue;
}
DeviceVector sourceDevicesForRoute = getRouteSourceDevices(route);
if (sourceDevicesForRoute.isEmpty()) {
- ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().string());
+ ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().c_str());
continue;
}
sourceDevices.add(sourceDevicesForRoute);
}
if (sourceDevices.isEmpty()) {
- ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().string());
+ ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().c_str());
continue;
}
stream->setSupportedDevices(sourceDevices);
@@ -208,14 +205,14 @@
for (const auto& stream : mOutputProfiles) {
DeviceVector sinkDevices;
for (const auto& route : stream->getRoutes()) {
- sp<AudioPort> source = route->getSources().findByTagName(stream->getTagName());
+ sp<PolicyAudioPort> source = findByTagName(route->getSources(), stream->getTagName());
if (source == 0 || stream != source) {
ALOGE("%s: Invalid route attached to output stream", __FUNCTION__);
continue;
}
sp<DeviceDescriptor> sinkDevice = getRouteSinkDevice(route);
if (sinkDevice == 0) {
- ALOGE("%s: invalid sink device for %s", __FUNCTION__, stream->getName().string());
+ ALOGE("%s: invalid sink device for %s", __FUNCTION__, stream->getName().c_str());
continue;
}
sinkDevices.add(sinkDevice);
@@ -230,7 +227,8 @@
mHandle = handle;
}
-bool HwModule::supportsPatch(const sp<AudioPort> &srcPort, const sp<AudioPort> &dstPort) const {
+bool HwModule::supportsPatch(const sp<PolicyAudioPort> &srcPort,
+ const sp<PolicyAudioPort> &dstPort) const {
for (const auto &route : mRoutes) {
if (route->supportsPatch(srcPort, dstPort)) {
return true;
@@ -260,7 +258,7 @@
}
mDeclaredDevices.dump(dst, String8("Declared"), 2, true);
mDynamicDevices.dump(dst, String8("Dynamic"), 2, true);
- mRoutes.dump(dst, 2);
+ dumpAudioRouteVector(mRoutes, dst, 2);
}
sp <HwModule> HwModuleCollection::getModuleFromName(const char *name) const
@@ -273,14 +271,14 @@
return nullptr;
}
-sp <HwModule> HwModuleCollection::getModuleForDeviceTypes(audio_devices_t type,
- audio_format_t encodedFormat) const
+sp <HwModule> HwModuleCollection::getModuleForDeviceType(audio_devices_t type,
+ audio_format_t encodedFormat) const
{
for (const auto& module : *this) {
const auto& profiles = audio_is_output_device(type) ?
module->getOutputProfiles() : module->getInputProfiles();
for (const auto& profile : profiles) {
- if (profile->supportsDeviceTypes(type)) {
+ if (profile->supportsDeviceTypes({type})) {
if (encodedFormat != AUDIO_FORMAT_DEFAULT) {
DeviceVector declaredDevices = module->getDeclaredDevices();
sp <DeviceDescriptor> deviceDesc =
@@ -300,7 +298,7 @@
sp<HwModule> HwModuleCollection::getModuleForDevice(const sp<DeviceDescriptor> &device,
audio_format_t encodedFormat) const
{
- return getModuleForDeviceTypes(device->type(), encodedFormat);
+ return getModuleForDeviceType(device->type(), encodedFormat);
}
DeviceVector HwModuleCollection::getAvailableDevicesFromModuleName(
@@ -335,8 +333,8 @@
}
if (allowToCreate) {
moduleDevice->attach(hwModule);
- moduleDevice->setAddress(devAddress);
- moduleDevice->setName(String8(name));
+ moduleDevice->setAddress(devAddress.string());
+ moduleDevice->setName(name);
}
return moduleDevice;
}
@@ -354,15 +352,15 @@
const char *name,
const audio_format_t encodedFormat) const
{
- sp<HwModule> hwModule = getModuleForDeviceTypes(type, encodedFormat);
+ sp<HwModule> hwModule = getModuleForDeviceType(type, encodedFormat);
if (hwModule == 0) {
ALOGE("%s: could not find HW module for device %04x address %s", __FUNCTION__, type,
address);
return nullptr;
}
- sp<DeviceDescriptor> device = new DeviceDescriptor(type, String8(name));
- device->setName(String8(name));
- device->setAddress(String8(address));
+
+ sp<DeviceDescriptor> device = new DeviceDescriptor(type, name, address);
+ device->setName(name);
device->setEncodedFormat(encodedFormat);
// Add the device to the list of dynamic devices
@@ -382,7 +380,7 @@
// @todo quid of audio profile? import the profile from device of the same type?
const auto &isoTypeDeviceForProfile =
profile->getSupportedDevices().getDevice(type, String8(), AUDIO_FORMAT_DEFAULT);
- device->importAudioPort(isoTypeDeviceForProfile, true /* force */);
+ device->importAudioPortAndPickAudioProfile(isoTypeDeviceForProfile, true /* force */);
ALOGV("%s: adding device %s to profile %s", __FUNCTION__,
device->toString().c_str(), profile->getTagName().c_str());
diff --git a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
index fe2eaee..bf1a0f7 100644
--- a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
@@ -20,7 +20,6 @@
#include <system/audio-base.h>
#include "IOProfile.h"
#include "HwModule.h"
-#include "AudioGain.h"
#include "TypeConverter.h"
namespace android {
@@ -79,7 +78,10 @@
}
}
- if (isPlaybackThread && (getFlags() & flags) != flags) {
+ const uint32_t mustMatchOutputFlags =
+ AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_HW_AV_SYNC|AUDIO_OUTPUT_FLAG_MMAP_NOIRQ;
+ if (isPlaybackThread && (((getFlags() ^ flags) & mustMatchOutputFlags)
+ || (getFlags() & flags) != flags)) {
return false;
}
// The only input flag that is allowed to be different is the fast flag.
@@ -105,7 +107,9 @@
void IOProfile::dump(String8 *dst) const
{
- AudioPort::dump(dst, 4);
+ std::string portStr;
+ AudioPort::dump(&portStr, 4);
+ dst->append(portStr.c_str());
dst->appendFormat(" - flags: 0x%04x", getFlags());
std::string flagsLiteral;
diff --git a/services/audiopolicy/common/managerdefinitions/src/PolicyAudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/PolicyAudioPort.cpp
new file mode 100644
index 0000000..8c61b90
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/PolicyAudioPort.cpp
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "APM::PolicyAudioPort"
+//#define LOG_NDEBUG 0
+#include "TypeConverter.h"
+#include "PolicyAudioPort.h"
+#include "HwModule.h"
+#include <policy.h>
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#endif
+
+namespace android {
+
+// --- PolicyAudioPort class implementation
+void PolicyAudioPort::attach(const sp<HwModule>& module)
+{
+ ALOGV("%s: attaching module %s to port %s",
+ __FUNCTION__, getModuleName(), asAudioPort()->getName().c_str());
+ mModule = module;
+}
+
+void PolicyAudioPort::detach()
+{
+ mModule = nullptr;
+}
+
+// Note that is a different namespace than AudioFlinger unique IDs
+audio_port_handle_t PolicyAudioPort::getNextUniqueId()
+{
+ return getNextHandle();
+}
+
+audio_module_handle_t PolicyAudioPort::getModuleHandle() const
+{
+ return mModule != 0 ? mModule->getHandle() : AUDIO_MODULE_HANDLE_NONE;
+}
+
+uint32_t PolicyAudioPort::getModuleVersionMajor() const
+{
+ return mModule != 0 ? mModule->getHalVersionMajor() : 0;
+}
+
+const char *PolicyAudioPort::getModuleName() const
+{
+ return mModule != 0 ? mModule->getName() : "invalid module";
+}
+
+status_t PolicyAudioPort::checkExactAudioProfile(const struct audio_port_config *config) const
+{
+ status_t status = NO_ERROR;
+ auto config_mask = config->config_mask;
+ if (config_mask & AUDIO_PORT_CONFIG_GAIN) {
+ config_mask &= ~AUDIO_PORT_CONFIG_GAIN;
+ status = asAudioPort()->checkGain(&config->gain, config->gain.index);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ }
+ if (config_mask != 0) {
+ // TODO should we check sample_rate / channel_mask / format separately?
+ status = checkExactProfile(asAudioPort()->getAudioProfiles(), config->sample_rate,
+ config->channel_mask, config->format);
+ }
+ return status;
+}
+
+void PolicyAudioPort::pickSamplingRate(uint32_t &pickedRate,
+ const SampleRateSet &samplingRates) const
+{
+ pickedRate = 0;
+ // For direct outputs, pick minimum sampling rate: this helps ensuring that the
+ // channel count / sampling rate combination chosen will be supported by the connected
+ // sink
+ if (isDirectOutput()) {
+ uint32_t samplingRate = UINT_MAX;
+ for (const auto rate : samplingRates) {
+ if ((rate < samplingRate) && (rate > 0)) {
+ samplingRate = rate;
+ }
+ }
+ pickedRate = (samplingRate == UINT_MAX) ? 0 : samplingRate;
+ } else {
+ uint32_t maxRate = SAMPLE_RATE_HZ_MAX;
+
+ // For mixed output and inputs, use max mixer sampling rates. Do not
+ // limit sampling rate otherwise
+ // For inputs, also see checkCompatibleSamplingRate().
+ if (asAudioPort()->getType() == AUDIO_PORT_TYPE_MIX) {
+ maxRate = UINT_MAX;
+ }
+ // TODO: should mSamplingRates[] be ordered in terms of our preference
+ // and we return the first (and hence most preferred) match? This is of concern if
+ // we want to choose 96kHz over 192kHz for USB driver stability or resource constraints.
+ for (const auto rate : samplingRates) {
+ if ((rate > pickedRate) && (rate <= maxRate)) {
+ pickedRate = rate;
+ }
+ }
+ }
+}
+
+void PolicyAudioPort::pickChannelMask(audio_channel_mask_t &pickedChannelMask,
+ const ChannelMaskSet &channelMasks) const
+{
+ pickedChannelMask = AUDIO_CHANNEL_NONE;
+ // For direct outputs, pick minimum channel count: this helps ensuring that the
+ // channel count / sampling rate combination chosen will be supported by the connected
+ // sink
+ if (isDirectOutput()) {
+ uint32_t channelCount = UINT_MAX;
+ for (const auto channelMask : channelMasks) {
+ uint32_t cnlCount;
+ if (asAudioPort()->useInputChannelMask()) {
+ cnlCount = audio_channel_count_from_in_mask(channelMask);
+ } else {
+ cnlCount = audio_channel_count_from_out_mask(channelMask);
+ }
+ if ((cnlCount < channelCount) && (cnlCount > 0)) {
+ pickedChannelMask = channelMask;
+ channelCount = cnlCount;
+ }
+ }
+ } else {
+ uint32_t channelCount = 0;
+ uint32_t maxCount = MAX_MIXER_CHANNEL_COUNT;
+
+ // For mixed output and inputs, use max mixer channel count. Do not
+ // limit channel count otherwise
+ if (asAudioPort()->getType() != AUDIO_PORT_TYPE_MIX) {
+ maxCount = UINT_MAX;
+ }
+ for (const auto channelMask : channelMasks) {
+ uint32_t cnlCount;
+ if (asAudioPort()->useInputChannelMask()) {
+ cnlCount = audio_channel_count_from_in_mask(channelMask);
+ } else {
+ cnlCount = audio_channel_count_from_out_mask(channelMask);
+ }
+ if ((cnlCount > channelCount) && (cnlCount <= maxCount)) {
+ pickedChannelMask = channelMask;
+ channelCount = cnlCount;
+ }
+ }
+ }
+}
+
+/* format in order of increasing preference */
+const audio_format_t PolicyAudioPort::sPcmFormatCompareTable[] = {
+ AUDIO_FORMAT_DEFAULT,
+ AUDIO_FORMAT_PCM_16_BIT,
+ AUDIO_FORMAT_PCM_8_24_BIT,
+ AUDIO_FORMAT_PCM_24_BIT_PACKED,
+ AUDIO_FORMAT_PCM_32_BIT,
+ AUDIO_FORMAT_PCM_FLOAT,
+};
+
+int PolicyAudioPort::compareFormats(audio_format_t format1, audio_format_t format2)
+{
+ // NOTE: AUDIO_FORMAT_INVALID is also considered not PCM and will be compared equal to any
+ // compressed format and better than any PCM format. This is by design of pickFormat()
+ if (!audio_is_linear_pcm(format1)) {
+ if (!audio_is_linear_pcm(format2)) {
+ return 0;
+ }
+ return 1;
+ }
+ if (!audio_is_linear_pcm(format2)) {
+ return -1;
+ }
+
+ int index1 = -1, index2 = -1;
+ for (size_t i = 0;
+ (i < ARRAY_SIZE(sPcmFormatCompareTable)) && ((index1 == -1) || (index2 == -1));
+ i ++) {
+ if (sPcmFormatCompareTable[i] == format1) {
+ index1 = i;
+ }
+ if (sPcmFormatCompareTable[i] == format2) {
+ index2 = i;
+ }
+ }
+ // format1 not found => index1 < 0 => format2 > format1
+ // format2 not found => index2 < 0 => format2 < format1
+ return index1 - index2;
+}
+
+uint32_t PolicyAudioPort::formatDistance(audio_format_t format1, audio_format_t format2)
+{
+ if (format1 == format2) {
+ return 0;
+ }
+ if (format1 == AUDIO_FORMAT_INVALID || format2 == AUDIO_FORMAT_INVALID) {
+ return kFormatDistanceMax;
+ }
+ int diffBytes = (int)audio_bytes_per_sample(format1) -
+ audio_bytes_per_sample(format2);
+
+ return abs(diffBytes);
+}
+
+bool PolicyAudioPort::isBetterFormatMatch(audio_format_t newFormat,
+ audio_format_t currentFormat,
+ audio_format_t targetFormat)
+{
+ return formatDistance(newFormat, targetFormat) < formatDistance(currentFormat, targetFormat);
+}
+
+void PolicyAudioPort::pickAudioProfile(uint32_t &samplingRate,
+ audio_channel_mask_t &channelMask,
+ audio_format_t &format) const
+{
+ format = AUDIO_FORMAT_DEFAULT;
+ samplingRate = 0;
+ channelMask = AUDIO_CHANNEL_NONE;
+
+ // special case for uninitialized dynamic profile
+ if (!asAudioPort()->hasValidAudioProfile()) {
+ return;
+ }
+ audio_format_t bestFormat = sPcmFormatCompareTable[ARRAY_SIZE(sPcmFormatCompareTable) - 1];
+ // For mixed output and inputs, use best mixer output format.
+ // Do not limit format otherwise
+ if ((asAudioPort()->getType() != AUDIO_PORT_TYPE_MIX) || isDirectOutput()) {
+ bestFormat = AUDIO_FORMAT_INVALID;
+ }
+
+ const AudioProfileVector& audioProfiles = asAudioPort()->getAudioProfiles();
+ for (size_t i = 0; i < audioProfiles.size(); i ++) {
+ if (!audioProfiles[i]->isValid()) {
+ continue;
+ }
+ audio_format_t formatToCompare = audioProfiles[i]->getFormat();
+ if ((compareFormats(formatToCompare, format) > 0) &&
+ (compareFormats(formatToCompare, bestFormat) <= 0)) {
+ uint32_t pickedSamplingRate = 0;
+ audio_channel_mask_t pickedChannelMask = AUDIO_CHANNEL_NONE;
+ pickChannelMask(pickedChannelMask, audioProfiles[i]->getChannels());
+ pickSamplingRate(pickedSamplingRate, audioProfiles[i]->getSampleRates());
+
+ if (formatToCompare != AUDIO_FORMAT_DEFAULT && pickedChannelMask != AUDIO_CHANNEL_NONE
+ && pickedSamplingRate != 0) {
+ format = formatToCompare;
+ channelMask = pickedChannelMask;
+ samplingRate = pickedSamplingRate;
+ // TODO: shall we return on the first one or still trying to pick a better Profile?
+ }
+ }
+ }
+ ALOGV("%s Port[nm:%s] profile rate=%d, format=%d, channels=%d", __FUNCTION__,
+ asAudioPort()->getName().c_str(), samplingRate, channelMask, format);
+}
+
+// --- PolicyAudioPortConfig class implementation
+
+status_t PolicyAudioPortConfig::validationBeforeApplyConfig(
+ const struct audio_port_config *config) const
+{
+ sp<PolicyAudioPort> policyAudioPort = getPolicyAudioPort();
+ return policyAudioPort ? policyAudioPort->checkExactAudioProfile(config) : NO_INIT;
+}
+
+void PolicyAudioPortConfig::toPolicyAudioPortConfig(struct audio_port_config *dstConfig,
+ const struct audio_port_config *srcConfig) const
+{
+ if (dstConfig->config_mask & AUDIO_PORT_CONFIG_FLAGS) {
+ if ((srcConfig != nullptr) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_FLAGS)) {
+ dstConfig->flags = srcConfig->flags;
+ } else {
+ dstConfig->flags = mFlags;
+ }
+ } else {
+ dstConfig->flags = { AUDIO_INPUT_FLAG_NONE };
+ }
+}
+
+
+
+} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index 5f820c2..883e713 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -199,6 +199,8 @@
struct Attributes
{
static constexpr const char *speakerDrcEnabled = "speaker_drc_enabled";
+ static constexpr const char *callScreenModeSupported= "call_screen_mode_supported";
+ static constexpr const char *engineLibrarySuffix = "engine_library";
};
static status_t deserialize(const xmlNode *root, AudioPolicyConfig *config);
@@ -406,8 +408,8 @@
samplingRatesFromString(samplingRates, ","));
profile->setDynamicFormat(profile->getFormat() == gDynamicFormat);
- profile->setDynamicChannels(profile->getChannels().isEmpty());
- profile->setDynamicRate(profile->getSampleRates().isEmpty());
+ profile->setDynamicChannels(profile->getChannels().empty());
+ profile->setDynamicRate(profile->getSampleRates().empty());
return profile;
}
@@ -430,16 +432,19 @@
audio_port_role_t portRole = (role == Attributes::roleSource) ?
AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
- Element mixPort = new IOProfile(String8(name.c_str()), portRole);
+ Element mixPort = new IOProfile(name, portRole);
AudioProfileTraits::Collection profiles;
status_t status = deserializeCollection<AudioProfileTraits>(child, &profiles, NULL);
if (status != NO_ERROR) {
return Status::fromStatusT(status);
}
- if (profiles.isEmpty()) {
- profiles.add(AudioProfile::createFullDynamic());
+ if (profiles.empty()) {
+ profiles.add(AudioProfile::createFullDynamic(gDynamicFormat));
}
+ // The audio profiles are in order of listed in audio policy configuration file.
+ // Sort audio profiles accroding to the format.
+ sortAudioProfiles(profiles);
mixPort->setAudioProfiles(profiles);
std::string flags = getXmlAttribute(child, Attributes::flags);
@@ -508,22 +513,20 @@
if (!encodedFormatsLiteral.empty()) {
encodedFormats = formatsFromString(encodedFormatsLiteral, " ");
}
- Element deviceDesc = new DeviceDescriptor(type, encodedFormats, String8(name.c_str()));
-
std::string address = getXmlAttribute(cur, Attributes::address);
- if (!address.empty()) {
- ALOGV("%s: address=%s for %s", __func__, address.c_str(), name.c_str());
- deviceDesc->setAddress(String8(address.c_str()));
- }
+ Element deviceDesc = new DeviceDescriptor(type, name, address, encodedFormats);
AudioProfileTraits::Collection profiles;
status_t status = deserializeCollection<AudioProfileTraits>(cur, &profiles, NULL);
if (status != NO_ERROR) {
return Status::fromStatusT(status);
}
- if (profiles.isEmpty()) {
- profiles.add(AudioProfile::createFullDynamic());
+ if (profiles.empty()) {
+ profiles.add(AudioProfile::createFullDynamic(gDynamicFormat));
}
+ // The audio profiles are in order of listed in audio policy configuration file.
+ // Sort audio profiles accroding to the format.
+ sortAudioProfiles(profiles);
deviceDesc->setAudioProfiles(profiles);
// Deserialize AudioGain children
@@ -532,7 +535,7 @@
return Status::fromStatusT(status);
}
ALOGV("%s: adding device tag %s type %08x address %s", __func__,
- deviceDesc->getName().string(), type, deviceDesc->address().string());
+ deviceDesc->getName().c_str(), type, deviceDesc->address().c_str());
return deviceDesc;
}
@@ -555,7 +558,7 @@
return Status::fromStatusT(BAD_VALUE);
}
// Convert Sink name to port pointer
- sp<AudioPort> sink = ctx->findPortByTagName(String8(sinkAttr.c_str()));
+ sp<PolicyAudioPort> sink = ctx->findPortByTagName(sinkAttr);
if (sink == NULL) {
ALOGE("%s: no sink found with name=%s", __func__, sinkAttr.c_str());
return Status::fromStatusT(BAD_VALUE);
@@ -568,13 +571,13 @@
return Status::fromStatusT(BAD_VALUE);
}
// Tokenize and Convert Sources name to port pointer
- AudioPortVector sources;
+ PolicyAudioPortVector sources;
std::unique_ptr<char[]> sourcesLiteral{strndup(
sourcesAttr.c_str(), strlen(sourcesAttr.c_str()))};
char *devTag = strtok(sourcesLiteral.get(), ",");
while (devTag != NULL) {
if (strlen(devTag) != 0) {
- sp<AudioPort> source = ctx->findPortByTagName(String8(devTag));
+ sp<PolicyAudioPort> source = ctx->findPortByTagName(devTag);
if (source == NULL) {
ALOGE("%s: no source found with name=%s", __func__, devTag);
return Status::fromStatusT(BAD_VALUE);
@@ -586,7 +589,7 @@
sink->addRoute(route);
for (size_t i = 0; i < sources.size(); i++) {
- sp<AudioPort> source = sources.itemAt(i);
+ sp<PolicyAudioPort> source = sources.itemAt(i);
source->addRoute(route);
}
route->setSources(sources);
@@ -648,9 +651,9 @@
ALOGV("%s: %s %s=%s", __func__, tag, childAttachedDeviceTag,
reinterpret_cast<const char*>(attachedDevice.get()));
sp<DeviceDescriptor> device = module->getDeclaredDevices().
- getDeviceFromTagName(String8(reinterpret_cast<const char*>(
+ getDeviceFromTagName(std::string(reinterpret_cast<const char*>(
attachedDevice.get())));
- ctx->addAvailableDevice(device);
+ ctx->addDevice(device);
}
}
}
@@ -663,7 +666,7 @@
ALOGV("%s: %s %s=%s", __func__, tag, childDefaultOutputDeviceTag,
reinterpret_cast<const char*>(defaultOutputDevice.get()));
sp<DeviceDescriptor> device = module->getDeclaredDevices().getDeviceFromTagName(
- String8(reinterpret_cast<const char*>(defaultOutputDevice.get())));
+ std::string(reinterpret_cast<const char*>(defaultOutputDevice.get())));
if (device != 0 && ctx->getDefaultOutputDevice() == 0) {
ctx->setDefaultOutputDevice(device);
ALOGV("%s: default is %08x",
@@ -679,12 +682,20 @@
{
for (const xmlNode *cur = root->xmlChildrenNode; cur != NULL; cur = cur->next) {
if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(tag))) {
- std::string speakerDrcEnabled =
- getXmlAttribute(cur, Attributes::speakerDrcEnabled);
- bool isSpeakerDrcEnabled;
- if (!speakerDrcEnabled.empty() &&
- convertTo<std::string, bool>(speakerDrcEnabled, isSpeakerDrcEnabled)) {
- config->setSpeakerDrcEnabled(isSpeakerDrcEnabled);
+ bool value;
+ std::string attr = getXmlAttribute(cur, Attributes::speakerDrcEnabled);
+ if (!attr.empty() &&
+ convertTo<std::string, bool>(attr, value)) {
+ config->setSpeakerDrcEnabled(value);
+ }
+ attr = getXmlAttribute(cur, Attributes::callScreenModeSupported);
+ if (!attr.empty() &&
+ convertTo<std::string, bool>(attr, value)) {
+ config->setCallScreenModeSupported(value);
+ }
+ std::string engineLibrarySuffix = getXmlAttribute(cur, Attributes::engineLibrarySuffix);
+ if (!engineLibrarySuffix.empty()) {
+ config->setEngineLibraryNameSuffix(engineLibrarySuffix);
}
return NO_ERROR;
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp b/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp
index 2b5455e..c5b3546 100644
--- a/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp
@@ -55,9 +55,11 @@
MAKE_STRING_FROM_ENUM(RULE_MATCH_ATTRIBUTE_USAGE),
MAKE_STRING_FROM_ENUM(RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET),
MAKE_STRING_FROM_ENUM(RULE_MATCH_UID),
+ MAKE_STRING_FROM_ENUM(RULE_MATCH_USERID),
MAKE_STRING_FROM_ENUM(RULE_EXCLUDE_ATTRIBUTE_USAGE),
MAKE_STRING_FROM_ENUM(RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET),
MAKE_STRING_FROM_ENUM(RULE_EXCLUDE_UID),
+ MAKE_STRING_FROM_ENUM(RULE_EXCLUDE_USERID),
TERMINATOR
};
diff --git a/services/audiopolicy/config/Android.bp b/services/audiopolicy/config/Android.bp
new file mode 100644
index 0000000..f4610bb
--- /dev/null
+++ b/services/audiopolicy/config/Android.bp
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+soong_namespace {
+}
+
+prebuilt_etc {
+ name: "a2dp_in_audio_policy_configuration.xml",
+ vendor: true,
+ src: ":a2dp_in_audio_policy_configuration",
+}
+prebuilt_etc {
+ name: "a2dp_audio_policy_configuration.xml",
+ vendor: true,
+ src: ":a2dp_audio_policy_configuration",
+}
+prebuilt_etc {
+ name: "audio_policy_configuration.xml",
+ vendor: true,
+ src: ":audio_policy_configuration_generic",
+}
+prebuilt_etc {
+ name: "r_submix_audio_policy_configuration.xml",
+ vendor: true,
+ src: ":r_submix_audio_policy_configuration",
+}
+prebuilt_etc {
+ name: "audio_policy_volumes.xml",
+ vendor: true,
+ src: ":audio_policy_volumes",
+}
+prebuilt_etc {
+ name: "default_volume_tables.xml",
+ vendor: true,
+ src: ":default_volume_tables",
+}
+prebuilt_etc {
+ name: "surround_sound_configuration_5_0.xml",
+ vendor: true,
+ src: ":surround_sound_configuration_5_0",
+}
+prebuilt_etc {
+ name: "usb_audio_policy_configuration.xml",
+ vendor: true,
+ src: ":usb_audio_policy_configuration",
+}
+prebuilt_etc {
+ name: "primary_audio_policy_configuration.xml",
+ src: ":primary_audio_policy_configuration",
+ vendor: true,
+}
+
+filegroup {
+ name: "a2dp_in_audio_policy_configuration",
+ srcs: ["a2dp_in_audio_policy_configuration.xml"],
+}
+filegroup {
+ name: "a2dp_audio_policy_configuration",
+ srcs: ["a2dp_audio_policy_configuration.xml"],
+}
+filegroup {
+ name: "primary_audio_policy_configuration",
+ srcs: ["primary_audio_policy_configuration.xml"],
+}
+filegroup {
+ name: "surround_sound_configuration_5_0",
+ srcs: ["surround_sound_configuration_5_0.xml"],
+}
+filegroup {
+ name: "default_volume_tables",
+ srcs: ["default_volume_tables.xml"],
+}
+filegroup {
+ name: "audio_policy_volumes",
+ srcs: ["audio_policy_volumes.xml"],
+}
+filegroup {
+ name: "audio_policy_configuration_generic",
+ srcs: ["audio_policy_configuration_generic.xml"],
+}
+filegroup {
+ name: "audio_policy_configuration_generic_configurable",
+ srcs: ["audio_policy_configuration_generic_configurable.xml"],
+}
+filegroup {
+ name: "usb_audio_policy_configuration",
+ srcs: ["usb_audio_policy_configuration.xml"],
+}
+filegroup {
+ name: "r_submix_audio_policy_configuration",
+ srcs: ["r_submix_audio_policy_configuration.xml"],
+}
diff --git a/services/audiopolicy/config/audio_policy_configuration_generic_configurable.xml b/services/audiopolicy/config/audio_policy_configuration_generic_configurable.xml
new file mode 100644
index 0000000..fbe4f7f
--- /dev/null
+++ b/services/audiopolicy/config/audio_policy_configuration_generic_configurable.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <!-- version section contains a “version” tag in the form “major.minor” e.g version=”1.0” -->
+
+ <!-- Global configuration Decalaration -->
+ <globalConfiguration speaker_drc_enabled="false" engine_library="configurable"/>
+
+ <modules>
+ <!-- Primary Audio HAL -->
+ <xi:include href="primary_audio_policy_configuration.xml"/>
+
+ <!-- Remote Submix Audio HAL -->
+ <xi:include href="r_submix_audio_policy_configuration.xml"/>
+
+ </modules>
+ <!-- End of Modules section -->
+
+ <!-- Volume section:
+ IMPORTANT NOTE: Volume tables have been moved to engine configuration.
+ Keep it here for legacy.
+ Engine will fallback on these files if none are provided by engine.
+ -->
+
+ <xi:include href="audio_policy_volumes.xml"/>
+ <xi:include href="default_volume_tables.xml"/>
+
+ <!-- End of Volume section -->
+
+ <!-- Surround Sound configuration -->
+
+ <xi:include href="surround_sound_configuration_5_0.xml"/>
+
+ <!-- End of Surround Sound configuration -->
+
+</audioPolicyConfiguration>
diff --git a/services/audiopolicy/config/audio_policy_volumes.xml b/services/audiopolicy/config/audio_policy_volumes.xml
index ec64a7c..1dec6f4 100644
--- a/services/audiopolicy/config/audio_policy_volumes.xml
+++ b/services/audiopolicy/config/audio_policy_volumes.xml
@@ -44,7 +44,7 @@
<volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
<volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_HEARING_AID"
- ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
+ ref="DEFAULT_NON_MUTABLE_HEARING_AID_VOLUME_CURVE"/>
<volume stream="AUDIO_STREAM_SYSTEM" deviceCategory="DEVICE_CATEGORY_HEADSET">
<point>1,-3000</point>
<point>33,-2600</point>
@@ -181,6 +181,16 @@
ref="DEFAULT_NON_MUTABLE_VOLUME_CURVE"/>
<volume stream="AUDIO_STREAM_ACCESSIBILITY" deviceCategory="DEVICE_CATEGORY_HEARING_AID"
ref="DEFAULT_NON_MUTABLE_HEARING_AID_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_ASSISTANT" deviceCategory="DEVICE_CATEGORY_HEADSET"
+ ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_ASSISTANT" deviceCategory="DEVICE_CATEGORY_SPEAKER"
+ ref="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_ASSISTANT" deviceCategory="DEVICE_CATEGORY_EARPIECE"
+ ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_ASSISTANT" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
+ ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_ASSISTANT" deviceCategory="DEVICE_CATEGORY_HEARING_AID"
+ ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
<volume stream="AUDIO_STREAM_REROUTING" deviceCategory="DEVICE_CATEGORY_HEADSET"
ref="FULL_SCALE_VOLUME_CURVE"/>
<volume stream="AUDIO_STREAM_REROUTING" deviceCategory="DEVICE_CATEGORY_SPEAKER"
diff --git a/services/audiopolicy/config/msd_audio_policy_configuration.xml b/services/audiopolicy/config/msd_audio_policy_configuration.xml
index db17bc6..305cbe6 100644
--- a/services/audiopolicy/config/msd_audio_policy_configuration.xml
+++ b/services/audiopolicy/config/msd_audio_policy_configuration.xml
@@ -40,7 +40,7 @@
channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_7POINT1"/>
</mixPort>
<!-- The HW AV Sync flag is not required, but is recommended -->
- <mixPort name="ms12 output" role="sink" flags="AUDIO_INPUT_FLAG_HW_AV_SYNC">
+ <mixPort name="ms12 output" role="sink" flags="AUDIO_INPUT_FLAG_HW_AV_SYNC|AUDIO_INPUT_FLAG_DIRECT">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
<profile name="" format="AUDIO_FORMAT_AC3"
diff --git a/services/audiopolicy/engine/common/Android.bp b/services/audiopolicy/engine/common/Android.bp
old mode 100644
new mode 100755
index d0775ad..a1c69f2
--- a/services/audiopolicy/engine/common/Android.bp
+++ b/services/audiopolicy/engine/common/Android.bp
@@ -25,6 +25,7 @@
"src/ProductStrategy.cpp",
"src/VolumeCurve.cpp",
"src/VolumeGroup.cpp",
+ "src/LastRemovableMediaDevices.cpp",
],
cflags: [
"-Wall",
@@ -44,4 +45,7 @@
"libaudiopolicycomponents",
"libaudiopolicyengine_config",
],
+ shared_libs: [
+ "libaudiofoundation",
+ ],
}
diff --git a/services/audiopolicy/engine/common/include/EngineBase.h b/services/audiopolicy/engine/common/include/EngineBase.h
old mode 100644
new mode 100755
index cedc78f..7f339dc
--- a/services/audiopolicy/engine/common/include/EngineBase.h
+++ b/services/audiopolicy/engine/common/include/EngineBase.h
@@ -17,18 +17,19 @@
#pragma once
#include <EngineConfig.h>
-#include <AudioPolicyManagerInterface.h>
+#include <EngineInterface.h>
#include <ProductStrategy.h>
#include <VolumeGroup.h>
+#include <LastRemovableMediaDevices.h>
namespace android {
namespace audio_policy {
-class EngineBase : public AudioPolicyManagerInterface
+class EngineBase : public EngineInterface
{
public:
///
- /// from AudioPolicyManagerInterface
+ /// from EngineInterface
///
android::status_t initCheck() override;
@@ -49,10 +50,8 @@
return mForceUse[usage];
}
android::status_t setDeviceConnectionState(const sp<DeviceDescriptor> /*devDesc*/,
- audio_policy_dev_state_t /*state*/) override
- {
- return NO_ERROR;
- }
+ audio_policy_dev_state_t /*state*/) override;
+
product_strategy_t getProductStrategyForAttributes(
const audio_attributes_t &attr) const override;
@@ -86,8 +85,21 @@
status_t listAudioVolumeGroups(AudioVolumeGroupVector &groups) const override;
+ std::vector<audio_devices_t> getLastRemovableMediaDevices(
+ device_out_group_t group = GROUP_NONE) const
+ {
+ return mLastRemovableMediaDevices.getLastRemovableMediaDevices(group);
+ }
+
void dump(String8 *dst) const override;
+ status_t setPreferredDeviceForStrategy(product_strategy_t strategy,
+ const AudioDeviceTypeAddr &device) override;
+
+ status_t removePreferredDeviceForStrategy(product_strategy_t strategy) override;
+
+ status_t getPreferredDeviceForStrategy(product_strategy_t strategy,
+ AudioDeviceTypeAddr &device) const override;
engineConfig::ParsingResult loadAudioPolicyEngineConfig();
@@ -115,11 +127,13 @@
status_t restoreOriginVolumeCurve(audio_stream_type_t stream);
- private:
+private:
AudioPolicyManagerObserver *mApmObserver = nullptr;
ProductStrategyMap mProductStrategies;
+ ProductStrategyPreferredRoutingMap mProductStrategyPreferredDevices;
VolumeGroupMap mVolumeGroups;
+ LastRemovableMediaDevices mLastRemovableMediaDevices;
audio_mode_t mPhoneState = AUDIO_MODE_NORMAL; /**< current phone state. */
/** current forced use configuration. */
diff --git a/services/audiopolicy/engine/common/include/LastRemovableMediaDevices.h b/services/audiopolicy/engine/common/include/LastRemovableMediaDevices.h
new file mode 100755
index 0000000..a3053a4
--- /dev/null
+++ b/services/audiopolicy/engine/common/include/LastRemovableMediaDevices.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_LAST_REMOVABLE_MEDIA_DEVICES_H
+#define ANDROID_LAST_REMOVABLE_MEDIA_DEVICES_H
+
+#include <vector>
+#include <HwModule.h>
+#include <system/audio_policy.h>
+
+namespace android {
+
+typedef enum {
+ GROUP_NONE = -1,
+ GROUP_WIRED,
+ GROUP_BT_A2DP,
+ NUM_GROUP
+} device_out_group_t;
+
+class LastRemovableMediaDevices
+{
+public:
+ void setRemovableMediaDevices(sp<DeviceDescriptor> desc, audio_policy_dev_state_t state);
+ std::vector<audio_devices_t> getLastRemovableMediaDevices(
+ device_out_group_t group = GROUP_NONE) const;
+
+private:
+ struct DeviceGroupDescriptor {
+ sp<DeviceDescriptor> desc;
+ device_out_group_t group;
+ };
+ std::vector<DeviceGroupDescriptor> mMediaDevices;
+
+ device_out_group_t getDeviceOutGroup(audio_devices_t device) const;
+};
+
+} // namespace android
+
+#endif // ANDROID_LAST_REMOVABLE_MEDIA_DEVICES_H
diff --git a/services/audiopolicy/engine/common/include/ProductStrategy.h b/services/audiopolicy/engine/common/include/ProductStrategy.h
index 1a2a198..3ebe7d1 100644
--- a/services/audiopolicy/engine/common/include/ProductStrategy.h
+++ b/services/audiopolicy/engine/common/include/ProductStrategy.h
@@ -19,7 +19,6 @@
#include "VolumeGroup.h"
#include <system/audio.h>
-#include <AudioPolicyManagerInterface.h>
#include <utils/RefBase.h>
#include <HandleGenerator.h>
#include <string>
@@ -27,6 +26,9 @@
#include <map>
#include <utils/Errors.h>
#include <utils/String8.h>
+#include <media/AudioAttributes.h>
+#include <media/AudioContainers.h>
+#include <media/AudioPolicy.h>
namespace android {
@@ -77,12 +79,12 @@
std::string getDeviceAddress() const { return mDeviceAddress; }
- void setDeviceTypes(audio_devices_t devices)
+ void setDeviceTypes(const DeviceTypeSet& devices)
{
mApplicableDevices = devices;
}
- audio_devices_t getDeviceTypes() const { return mApplicableDevices; }
+ DeviceTypeSet getDeviceTypes() const { return mApplicableDevices; }
audio_attributes_t getAttributesForStreamType(audio_stream_type_t stream) const;
audio_stream_type_t getStreamTypeForAttributes(const audio_attributes_t &attr) const;
@@ -109,7 +111,7 @@
/**
* Applicable device(s) type mask for this strategy.
*/
- audio_devices_t mApplicableDevices = AUDIO_DEVICE_NONE;
+ DeviceTypeSet mApplicableDevices;
};
class ProductStrategyMap : public std::map<product_strategy_t, sp<ProductStrategy> >
@@ -144,7 +146,7 @@
*/
audio_attributes_t getAttributesForProductStrategy(product_strategy_t strategy) const;
- audio_devices_t getDeviceTypesForProductStrategy(product_strategy_t strategy) const;
+ DeviceTypeSet getDeviceTypesForProductStrategy(product_strategy_t strategy) const;
std::string getDeviceAddressForProductStrategy(product_strategy_t strategy) const;
@@ -162,4 +164,10 @@
product_strategy_t mDefaultStrategy = PRODUCT_STRATEGY_NONE;
};
+class ProductStrategyPreferredRoutingMap : public std::map<product_strategy_t, AudioDeviceTypeAddr>
+{
+public:
+ void dump(String8 *dst, int spaces = 0) const;
+};
+
} // namespace android
diff --git a/services/audiopolicy/engine/common/include/VolumeCurve.h b/services/audiopolicy/engine/common/include/VolumeCurve.h
index 54314e3..2e75ff1 100644
--- a/services/audiopolicy/engine/common/include/VolumeCurve.h
+++ b/services/audiopolicy/engine/common/include/VolumeCurve.h
@@ -18,7 +18,6 @@
#include "IVolumeCurves.h"
#include <policy.h>
-#include <AudioPolicyManagerInterface.h>
#include <utils/RefBase.h>
#include <HandleGenerator.h>
#include <utils/String8.h>
@@ -92,9 +91,9 @@
return valueFor(device);
}
- virtual int getVolumeIndex(audio_devices_t device) const
+ virtual int getVolumeIndex(const DeviceTypeSet& deviceTypes) const
{
- device = Volume::getDeviceForVolume(device);
+ audio_devices_t device = Volume::getDeviceForVolume(deviceTypes);
// there is always a valid entry for AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME
if (mIndexCur.find(device) == end(mIndexCur)) {
device = AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME;
@@ -115,7 +114,7 @@
bool hasVolumeIndexForDevice(audio_devices_t device) const
{
- device = Volume::getDeviceForVolume(device);
+ device = Volume::getDeviceForVolume({device});
return mIndexCur.find(device) != end(mIndexCur);
}
diff --git a/services/audiopolicy/engine/common/include/VolumeGroup.h b/services/audiopolicy/engine/common/include/VolumeGroup.h
index c34b406..5378f64 100644
--- a/services/audiopolicy/engine/common/include/VolumeGroup.h
+++ b/services/audiopolicy/engine/common/include/VolumeGroup.h
@@ -16,7 +16,6 @@
#pragma once
-#include <AudioPolicyManagerInterface.h>
#include <VolumeCurve.h>
#include <system/audio.h>
#include <utils/RefBase.h>
diff --git a/services/audiopolicy/engine/common/src/EngineBase.cpp b/services/audiopolicy/engine/common/src/EngineBase.cpp
index 07a7e65..1bc7fe3 100644
--- a/services/audiopolicy/engine/common/src/EngineBase.cpp
+++ b/services/audiopolicy/engine/common/src/EngineBase.cpp
@@ -39,7 +39,7 @@
{
ALOGV("setPhoneState() state %d", state);
- if (state < 0 || state >= AUDIO_MODE_CNT) {
+ if (state < 0 || uint32_t(state) >= AUDIO_MODE_CNT) {
ALOGW("setPhoneState() invalid state %d", state);
return BAD_VALUE;
}
@@ -63,6 +63,17 @@
return NO_ERROR;
}
+status_t EngineBase::setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
+ audio_policy_dev_state_t state)
+{
+ audio_devices_t deviceType = devDesc->type();
+ if ((deviceType != AUDIO_DEVICE_NONE) && audio_is_output_device(deviceType)) {
+ mLastRemovableMediaDevices.setRemovableMediaDevices(devDesc, state);
+ }
+
+ return NO_ERROR;
+}
+
product_strategy_t EngineBase::getProductStrategyForAttributes(const audio_attributes_t &attr) const
{
return mProductStrategies.getProductStrategyForAttributes(attr);
@@ -95,48 +106,48 @@
engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig()
{
- auto loadProductStrategies =
- [](auto& strategyConfigs, auto& productStrategies, auto& volumeGroups) {
- for (auto& strategyConfig : strategyConfigs) {
- sp<ProductStrategy> strategy = new ProductStrategy(strategyConfig.name);
- for (const auto &group : strategyConfig.attributesGroups) {
- const auto &iter = std::find_if(begin(volumeGroups), end(volumeGroups),
- [&group](const auto &volumeGroup) {
- return group.volumeGroup == volumeGroup.second->getName(); });
- ALOG_ASSERT(iter != end(volumeGroups), "Invalid Volume Group Name %s",
- group.volumeGroup.c_str());
- if (group.stream != AUDIO_STREAM_DEFAULT) {
- iter->second->addSupportedStream(group.stream);
- }
- for (const auto &attr : group.attributesVect) {
- strategy->addAttributes({group.stream, iter->second->getId(), attr});
- iter->second->addSupportedAttributes(attr);
- }
- }
- product_strategy_t strategyId = strategy->getId();
- productStrategies[strategyId] = strategy;
- }
- };
- auto loadVolumeGroups = [](auto &volumeConfigs, auto &volumeGroups) {
- for (auto &volumeConfig : volumeConfigs) {
- sp<VolumeGroup> volumeGroup = new VolumeGroup(volumeConfig.name, volumeConfig.indexMin,
- volumeConfig.indexMax);
- volumeGroups[volumeGroup->getId()] = volumeGroup;
+ auto loadVolumeConfig = [](auto &volumeGroups, auto &volumeConfig) {
+ // Ensure name unicity to prevent duplicate
+ LOG_ALWAYS_FATAL_IF(std::any_of(std::begin(volumeGroups), std::end(volumeGroups),
+ [&volumeConfig](const auto &volumeGroup) {
+ return volumeConfig.name == volumeGroup.second->getName(); }),
+ "group name %s defined twice, review the configuration",
+ volumeConfig.name.c_str());
- for (auto &configCurve : volumeConfig.volumeCurves) {
- device_category deviceCat = DEVICE_CATEGORY_SPEAKER;
- if (!DeviceCategoryConverter::fromString(configCurve.deviceCategory, deviceCat)) {
- ALOGE("%s: Invalid %s", __FUNCTION__, configCurve.deviceCategory.c_str());
- continue;
- }
- sp<VolumeCurve> curve = new VolumeCurve(deviceCat);
- for (auto &point : configCurve.curvePoints) {
- curve->add({point.index, point.attenuationInMb});
- }
- volumeGroup->add(curve);
+ sp<VolumeGroup> volumeGroup = new VolumeGroup(volumeConfig.name, volumeConfig.indexMin,
+ volumeConfig.indexMax);
+ volumeGroups[volumeGroup->getId()] = volumeGroup;
+
+ for (auto &configCurve : volumeConfig.volumeCurves) {
+ device_category deviceCat = DEVICE_CATEGORY_SPEAKER;
+ if (!DeviceCategoryConverter::fromString(configCurve.deviceCategory, deviceCat)) {
+ ALOGE("%s: Invalid %s", __FUNCTION__, configCurve.deviceCategory.c_str());
+ continue;
}
+ sp<VolumeCurve> curve = new VolumeCurve(deviceCat);
+ for (auto &point : configCurve.curvePoints) {
+ curve->add({point.index, point.attenuationInMb});
+ }
+ volumeGroup->add(curve);
+ }
+ return volumeGroup;
+ };
+ auto addSupportedAttributesToGroup = [](auto &group, auto &volumeGroup, auto &strategy) {
+ for (const auto &attr : group.attributesVect) {
+ strategy->addAttributes({group.stream, volumeGroup->getId(), attr});
+ volumeGroup->addSupportedAttributes(attr);
}
};
+ auto checkStreamForGroups = [](auto streamType, const auto &volumeGroups) {
+ const auto &iter = std::find_if(std::begin(volumeGroups), std::end(volumeGroups),
+ [&streamType](const auto &volumeGroup) {
+ const auto& streams = volumeGroup.second->getStreamTypes();
+ return std::find(std::begin(streams), std::end(streams), streamType) !=
+ std::end(streams);
+ });
+ return iter != end(volumeGroups);
+ };
+
auto result = engineConfig::parse();
if (result.parsedConfig == nullptr) {
ALOGW("%s: No configuration found, using default matching phone experience.", __FUNCTION__);
@@ -144,11 +155,67 @@
android::status_t ret = engineConfig::parseLegacyVolumes(config.volumeGroups);
result = {std::make_unique<engineConfig::Config>(config),
static_cast<size_t>(ret == NO_ERROR ? 0 : 1)};
+ } else {
+ // Append for internal use only volume groups (e.g. rerouting/patch)
+ result.parsedConfig->volumeGroups.insert(
+ std::end(result.parsedConfig->volumeGroups),
+ std::begin(gSystemVolumeGroups), std::end(gSystemVolumeGroups));
}
+ // Append for internal use only strategies (e.g. rerouting/patch)
+ result.parsedConfig->productStrategies.insert(
+ std::end(result.parsedConfig->productStrategies),
+ std::begin(gOrderedSystemStrategies), std::end(gOrderedSystemStrategies));
+
+
ALOGE_IF(result.nbSkippedElement != 0, "skipped %zu elements", result.nbSkippedElement);
- loadVolumeGroups(result.parsedConfig->volumeGroups, mVolumeGroups);
- loadProductStrategies(result.parsedConfig->productStrategies, mProductStrategies,
- mVolumeGroups);
+
+ engineConfig::VolumeGroup defaultVolumeConfig;
+ engineConfig::VolumeGroup defaultSystemVolumeConfig;
+ for (auto &volumeConfig : result.parsedConfig->volumeGroups) {
+ // save default volume config for streams not defined in configuration
+ if (volumeConfig.name.compare("AUDIO_STREAM_MUSIC") == 0) {
+ defaultVolumeConfig = volumeConfig;
+ }
+ if (volumeConfig.name.compare("AUDIO_STREAM_PATCH") == 0) {
+ defaultSystemVolumeConfig = volumeConfig;
+ }
+ loadVolumeConfig(mVolumeGroups, volumeConfig);
+ }
+ for (auto& strategyConfig : result.parsedConfig->productStrategies) {
+ sp<ProductStrategy> strategy = new ProductStrategy(strategyConfig.name);
+ for (const auto &group : strategyConfig.attributesGroups) {
+ const auto &iter = std::find_if(begin(mVolumeGroups), end(mVolumeGroups),
+ [&group](const auto &volumeGroup) {
+ return group.volumeGroup == volumeGroup.second->getName(); });
+ sp<VolumeGroup> volumeGroup = nullptr;
+ // If no volume group provided for this strategy, creates a new one using
+ // Music Volume Group configuration (considered as the default)
+ if (iter == end(mVolumeGroups)) {
+ engineConfig::VolumeGroup volumeConfig;
+ if (group.stream >= AUDIO_STREAM_PUBLIC_CNT) {
+ volumeConfig = defaultSystemVolumeConfig;
+ } else {
+ volumeConfig = defaultVolumeConfig;
+ }
+ ALOGW("%s: No configuration of %s found, using default volume configuration"
+ , __FUNCTION__, group.volumeGroup.c_str());
+ volumeConfig.name = group.volumeGroup;
+ volumeGroup = loadVolumeConfig(mVolumeGroups, volumeConfig);
+ } else {
+ volumeGroup = iter->second;
+ }
+ if (group.stream != AUDIO_STREAM_DEFAULT) {
+ // A legacy stream can be assigned once to a volume group
+ LOG_ALWAYS_FATAL_IF(checkStreamForGroups(group.stream, mVolumeGroups),
+ "stream %s already assigned to a volume group, "
+ "review the configuration", toString(group.stream).c_str());
+ volumeGroup->addSupportedStream(group.stream);
+ }
+ addSupportedAttributesToGroup(group, volumeGroup, strategy);
+ }
+ product_strategy_t strategyId = strategy->getId();
+ mProductStrategies[strategyId] = strategy;
+ }
mProductStrategies.initialize();
return result;
}
@@ -272,9 +339,57 @@
return NO_ERROR;
}
+status_t EngineBase::setPreferredDeviceForStrategy(product_strategy_t strategy,
+ const AudioDeviceTypeAddr &device)
+{
+ // verify strategy exists
+ if (mProductStrategies.find(strategy) == mProductStrategies.end()) {
+ ALOGE("%s invalid strategy %u", __func__, strategy);
+ return BAD_VALUE;
+ }
+
+ mProductStrategyPreferredDevices[strategy] = device;
+ return NO_ERROR;
+}
+
+status_t EngineBase::removePreferredDeviceForStrategy(product_strategy_t strategy)
+{
+ // verify strategy exists
+ if (mProductStrategies.find(strategy) == mProductStrategies.end()) {
+ ALOGE("%s invalid strategy %u", __func__, strategy);
+ return BAD_VALUE;
+ }
+
+ if (mProductStrategyPreferredDevices.erase(strategy) == 0) {
+ // no preferred device was set
+ return NAME_NOT_FOUND;
+ }
+ return NO_ERROR;
+}
+
+status_t EngineBase::getPreferredDeviceForStrategy(product_strategy_t strategy,
+ AudioDeviceTypeAddr &device) const
+{
+ // verify strategy exists
+ if (mProductStrategies.find(strategy) == mProductStrategies.end()) {
+ ALOGE("%s unknown strategy %u", __func__, strategy);
+ return BAD_VALUE;
+ }
+ // preferred device for this strategy?
+ auto devIt = mProductStrategyPreferredDevices.find(strategy);
+ if (devIt == mProductStrategyPreferredDevices.end()) {
+ ALOGV("%s no preferred device for strategy %u", __func__, strategy);
+ return NAME_NOT_FOUND;
+ }
+
+ device = devIt->second;
+ return NO_ERROR;
+}
+
void EngineBase::dump(String8 *dst) const
{
mProductStrategies.dump(dst, 2);
+ mProductStrategyPreferredDevices.dump(dst, 2);
mVolumeGroups.dump(dst, 2);
}
diff --git a/services/audiopolicy/engine/common/src/EngineDefaultConfig.h b/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
index fede0d9..981582e 100644
--- a/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
+++ b/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
@@ -81,6 +81,10 @@
},
{"STRATEGY_MEDIA",
{
+ {"assistant", AUDIO_STREAM_ASSISTANT, "AUDIO_STREAM_ASSISTANT",
+ {{AUDIO_CONTENT_TYPE_SPEECH, AUDIO_USAGE_ASSISTANT,
+ AUDIO_SOURCE_DEFAULT, 0, ""}}
+ },
{"music", AUDIO_STREAM_MUSIC, "AUDIO_STREAM_MUSIC",
{
{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_MEDIA, AUDIO_SOURCE_DEFAULT, 0, ""},
@@ -107,6 +111,13 @@
}
},
},
+ {"STRATEGY_CALL_ASSISTANT",
+ {
+ {"", AUDIO_STREAM_CALL_ASSISTANT, "AUDIO_STREAM_CALL_ASSISTANT",
+ {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_CALL_ASSISTANT, AUDIO_SOURCE_DEFAULT, 0, ""}}
+ }
+ },
+ },
{"STRATEGY_TRANSMITTED_THROUGH_SPEAKER",
{
{"", AUDIO_STREAM_TTS, "AUDIO_STREAM_TTS",
@@ -114,15 +125,22 @@
AUDIO_FLAG_BEACON, ""}}
}
},
- },
- {"STRATEGY_REROUTING",
+ }
+};
+
+/**
+ * For Internal use of respectively audio policy and audioflinger
+ * For compatibility reason why apm volume config file, volume group name is the stream type.
+ */
+const engineConfig::ProductStrategies gOrderedSystemStrategies = {
+ {"rerouting",
{
{"", AUDIO_STREAM_REROUTING, "AUDIO_STREAM_REROUTING",
{{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT, 0, ""}}
}
},
},
- {"STRATEGY_PATCH",
+ {"patch",
{
{"", AUDIO_STREAM_PATCH, "AUDIO_STREAM_PATCH",
{{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT, 0, ""}}
@@ -130,6 +148,28 @@
},
}
};
+const engineConfig::VolumeGroups gSystemVolumeGroups = {
+ {"AUDIO_STREAM_REROUTING", 0, 1,
+ {
+ {"DEVICE_CATEGORY_SPEAKER", {{0,0}, {100, 0}}},
+ {"DEVICE_CATEGORY_HEADSET", {{0,0}, {100, 0}}},
+ {"DEVICE_CATEGORY_EARPIECE", {{0,0}, {100, 0}}},
+ {"DEVICE_CATEGORY_EXT_MEDIA", {{0,0}, {100, 0}}},
+ {"DEVICE_CATEGORY_HEARING_AID", {{0,0}, {100, 0}}},
+
+ }
+ },
+ {"AUDIO_STREAM_PATCH", 0, 1,
+ {
+ {"DEVICE_CATEGORY_SPEAKER", {{0,0}, {100, 0}}},
+ {"DEVICE_CATEGORY_HEADSET", {{0,0}, {100, 0}}},
+ {"DEVICE_CATEGORY_EARPIECE", {{0,0}, {100, 0}}},
+ {"DEVICE_CATEGORY_EXT_MEDIA", {{0,0}, {100, 0}}},
+ {"DEVICE_CATEGORY_HEARING_AID", {{0,0}, {100, 0}}},
+
+ }
+ }
+};
const engineConfig::Config gDefaultEngineConfig = {
1.0,
diff --git a/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp b/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp
new file mode 100755
index 0000000..87b6aaf
--- /dev/null
+++ b/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "APM::AudioPolicyEngine/LastRemovableMediaDevices"
+//#define LOG_NDEBUG 0
+
+#include "LastRemovableMediaDevices.h"
+#include <log/log.h>
+
+namespace android {
+
+void LastRemovableMediaDevices::setRemovableMediaDevices(sp<DeviceDescriptor> desc,
+ audio_policy_dev_state_t state)
+{
+ if (desc == nullptr) {
+ return;
+ } else {
+ if ((state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) &&
+ (getDeviceOutGroup(desc->type()) != GROUP_NONE)) {
+ setRemovableMediaDevices(desc, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE);
+ mMediaDevices.insert(mMediaDevices.begin(), {desc, getDeviceOutGroup(desc->type())});
+ } else if (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) {
+ for (auto iter = mMediaDevices.begin(); iter != mMediaDevices.end(); ++iter) {
+ if ((iter->desc)->equals(desc)) {
+ mMediaDevices.erase(iter);
+ break;
+ }
+ }
+ }
+ }
+}
+
+std::vector<audio_devices_t> LastRemovableMediaDevices::getLastRemovableMediaDevices(
+ device_out_group_t group) const
+{
+ std::vector<audio_devices_t> ret;
+ for (auto iter = mMediaDevices.begin(); iter != mMediaDevices.end(); ++iter) {
+ if ((group == GROUP_NONE) || (group == getDeviceOutGroup((iter->desc)->type()))) {
+ ret.push_back((iter->desc)->type());
+ }
+ }
+ return ret;
+}
+
+device_out_group_t LastRemovableMediaDevices::getDeviceOutGroup(audio_devices_t device) const
+{
+ switch (device) {
+ case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
+ case AUDIO_DEVICE_OUT_LINE:
+ case AUDIO_DEVICE_OUT_WIRED_HEADSET:
+ case AUDIO_DEVICE_OUT_USB_HEADSET:
+ case AUDIO_DEVICE_OUT_USB_ACCESSORY:
+ case AUDIO_DEVICE_OUT_USB_DEVICE:
+ case AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET:
+ return GROUP_WIRED;
+ case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
+ return GROUP_BT_A2DP;
+ default:
+ return GROUP_NONE;
+ }
+}
+
+} // namespace android
diff --git a/services/audiopolicy/engine/common/src/ProductStrategy.cpp b/services/audiopolicy/engine/common/src/ProductStrategy.cpp
index f74f190..fe15ff6 100644
--- a/services/audiopolicy/engine/common/src/ProductStrategy.cpp
+++ b/services/audiopolicy/engine/common/src/ProductStrategy.cpp
@@ -19,6 +19,7 @@
#include "ProductStrategy.h"
+#include <media/AudioProductStrategy.h>
#include <media/TypeConverter.h>
#include <utils/String8.h>
#include <cstdint>
@@ -142,8 +143,9 @@
{
dst->appendFormat("\n%*s-%s (id: %d)\n", spaces, "", mName.c_str(), mId);
std::string deviceLiteral;
- if (!OutputDeviceConverter::toString(mApplicableDevices, deviceLiteral)) {
- ALOGE("%s: failed to convert device %d", __FUNCTION__, mApplicableDevices);
+ if (!deviceTypesToString(mApplicableDevices, deviceLiteral)) {
+ ALOGE("%s: failed to convert device %s",
+ __FUNCTION__, dumpDeviceTypes(mApplicableDevices).c_str());
}
dst->appendFormat("%*sSelected Device: {type:%s, @:%s}\n", spaces + 2, "",
deviceLiteral.c_str(), mDeviceAddress.c_str());
@@ -235,14 +237,14 @@
}
-audio_devices_t ProductStrategyMap::getDeviceTypesForProductStrategy(
+DeviceTypeSet ProductStrategyMap::getDeviceTypesForProductStrategy(
product_strategy_t strategy) const
{
if (find(strategy) == end()) {
ALOGE("Invalid %d strategy requested, returning device for default strategy", strategy);
product_strategy_t defaultStrategy = getDefault();
if (defaultStrategy == PRODUCT_STRATEGY_NONE) {
- return AUDIO_DEVICE_NONE;
+ return {AUDIO_DEVICE_NONE};
}
return at(getDefault())->getDeviceTypes();
}
@@ -308,5 +310,15 @@
}
}
+void ProductStrategyPreferredRoutingMap::dump(android::String8* dst, int spaces) const {
+ dst->appendFormat("\n%*sPreferred devices per product strategy dump:", spaces, "");
+ for (const auto& iter : *this) {
+ dst->appendFormat("\n%*sStrategy %u dev:%08x addr:%s",
+ spaces + 2, "",
+ (uint32_t) iter.first,
+ iter.second.mType, iter.second.mAddress.c_str());
+ }
+ dst->appendFormat("\n");
+}
}
diff --git a/services/audiopolicy/engine/config/Android.bp b/services/audiopolicy/engine/config/Android.bp
index 6e72f2a..ff840f9 100644
--- a/services/audiopolicy/engine/config/Android.bp
+++ b/services/audiopolicy/engine/config/Android.bp
@@ -1,9 +1,8 @@
-cc_library_static {
+cc_library {
name: "libaudiopolicyengine_config",
export_include_dirs: ["include"],
include_dirs: [
"external/libxml2/include",
- "external/icu/icu4c/source/common",
],
srcs: [
"src/EngineConfig.cpp",
@@ -15,17 +14,14 @@
],
shared_libs: [
"libmedia_helper",
- "libandroidicu",
"libxml2",
"libutils",
"liblog",
"libcutils",
],
- static_libs: [
- "libaudiopolicycomponents",
- ],
header_libs: [
"libaudio_system_headers",
- "libaudiopolicycommon",
+ "libmedia_headers",
+ "libaudioclient_headers",
],
}
diff --git a/services/audiopolicy/engine/config/src/EngineConfig.cpp b/services/audiopolicy/engine/config/src/EngineConfig.cpp
index 1ad7739..7f8cdd9 100644
--- a/services/audiopolicy/engine/config/src/EngineConfig.cpp
+++ b/services/audiopolicy/engine/config/src/EngineConfig.cpp
@@ -18,7 +18,6 @@
//#define LOG_NDEBUG 0
#include "EngineConfig.h"
-#include <policy.h>
#include <cutils/properties.h>
#include <media/TypeConverter.h>
#include <media/convert.h>
@@ -32,9 +31,9 @@
#include <istream>
#include <cstdint>
+#include <stdarg.h>
#include <string>
-
namespace android {
using utilities::convertTo;
@@ -603,7 +602,39 @@
return NO_ERROR;
}
+namespace {
+
+class XmlErrorHandler {
+public:
+ XmlErrorHandler() {
+ xmlSetGenericErrorFunc(this, &xmlErrorHandler);
+ }
+ XmlErrorHandler(const XmlErrorHandler&) = delete;
+ XmlErrorHandler(XmlErrorHandler&&) = delete;
+ XmlErrorHandler& operator=(const XmlErrorHandler&) = delete;
+ XmlErrorHandler& operator=(XmlErrorHandler&&) = delete;
+ ~XmlErrorHandler() {
+ xmlSetGenericErrorFunc(NULL, NULL);
+ if (!mErrorMessage.empty()) {
+ ALOG(LOG_ERROR, "libxml2", "%s", mErrorMessage.c_str());
+ }
+ }
+ static void xmlErrorHandler(void* ctx, const char* msg, ...) {
+ char buffer[256];
+ va_list args;
+ va_start(args, msg);
+ vsnprintf(buffer, sizeof(buffer), msg, args);
+ va_end(args);
+ static_cast<XmlErrorHandler*>(ctx)->mErrorMessage += buffer;
+ }
+private:
+ std::string mErrorMessage;
+};
+
+} // namespace
+
ParsingResult parse(const char* path) {
+ XmlErrorHandler errorHandler;
xmlDocPtr doc;
doc = xmlParseFile(path);
if (doc == NULL) {
@@ -641,6 +672,7 @@
}
android::status_t parseLegacyVolumeFile(const char* path, VolumeGroups &volumeGroups) {
+ XmlErrorHandler errorHandler;
xmlDocPtr doc;
doc = xmlParseFile(path);
if (doc == NULL) {
diff --git a/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h b/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h
deleted file mode 100644
index b7fd031..0000000
--- a/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <AudioPolicyManagerObserver.h>
-#include <media/AudioProductStrategy.h>
-#include <media/AudioVolumeGroup.h>
-#include <IVolumeCurves.h>
-#include <policy.h>
-#include <Volume.h>
-#include <HwModule.h>
-#include <DeviceDescriptor.h>
-#include <system/audio.h>
-#include <system/audio_policy.h>
-#include <utils/Errors.h>
-#include <utils/Vector.h>
-
-namespace android {
-
-using DeviceStrategyMap = std::map<product_strategy_t, DeviceVector>;
-using StrategyVector = std::vector<product_strategy_t>;
-using VolumeGroupVector = std::vector<volume_group_t>;
-
-/**
- * This interface is dedicated to the policy manager that a Policy Engine shall implement.
- */
-class AudioPolicyManagerInterface
-{
-public:
- /**
- * Checks if the engine was correctly initialized.
- *
- * @return NO_ERROR if initialization has been done correctly, error code otherwise..
- */
- virtual status_t initCheck() = 0;
-
- /**
- * Sets the Manager observer that allows the engine to retrieve information on collection
- * of devices, streams, HwModules, ...
- *
- * @param[in] observer handle on the manager.
- */
- virtual void setObserver(AudioPolicyManagerObserver *observer) = 0;
-
- /**
- * Set the Telephony Mode.
- *
- * @param[in] mode: Android Phone state (normal, ringtone, csv, in communication)
- *
- * @return NO_ERROR if Telephony Mode set correctly, error code otherwise.
- */
- virtual status_t setPhoneState(audio_mode_t mode) = 0;
-
- /**
- * Get the telephony Mode
- *
- * @return the current telephony mode
- */
- virtual audio_mode_t getPhoneState() const = 0;
-
- /**
- * Set Force Use config for a given usage.
- *
- * @param[in] usage for which a configuration shall be forced.
- * @param[in] config wished to be forced for the given usage.
- *
- * @return NO_ERROR if the Force Use config was set correctly, error code otherwise (e.g. config
- * not allowed a given usage...)
- */
- virtual status_t setForceUse(audio_policy_force_use_t usage,
- audio_policy_forced_cfg_t config) = 0;
-
- /**
- * Get Force Use config for a given usage.
- *
- * @param[in] usage for which a configuration shall be forced.
- *
- * @return config wished to be forced for the given usage.
- */
- virtual audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage) const = 0;
-
- /**
- * Set the connection state of device(s).
- *
- * @param[in] devDesc for which the state has changed.
- * @param[in] state of availability of this(these) device(s).
- *
- * @return NO_ERROR if devices criterion updated correctly, error code otherwise.
- */
- virtual status_t setDeviceConnectionState(const android::sp<android::DeviceDescriptor> devDesc,
- audio_policy_dev_state_t state) = 0;
-
- /**
- * Get the strategy selected for a given audio attributes.
- *
- * @param[in] audio attributes to get the selected @product_strategy_t followed by.
- *
- * @return @product_strategy_t to be followed.
- */
- virtual product_strategy_t getProductStrategyForAttributes(
- const audio_attributes_t &attr) const = 0;
-
- /**
- * @brief getOutputDevicesForAttributes retrieves the devices to be used for given
- * audio attributes.
- * @param attributes of the output requesting Device(s) selection
- * @param preferedDevice valid reference if a prefered device is requested, nullptr otherwise.
- * @param fromCache if true, the device is returned from internal cache,
- * otherwise it is determined by current state (device connected,phone state,
- * force use, a2dp output...)
- * @return vector of selected device descriptors.
- * Appropriate device for streams handled by the specified audio attributes according
- * to current phone state, forced states, connected devices...
- * if fromCache is true, the device is returned from internal cache,
- * otherwise it is determined by current state (device connected,phone state, force use,
- * a2dp output...)
- * This allows to:
- * 1 speed up process when the state is stable (when starting or stopping an output)
- * 2 access to either current device selection (fromCache == true) or
- * "future" device selection (fromCache == false) when called from a context
- * where conditions are changing (setDeviceConnectionState(), setPhoneState()...) AND
- * before manager updates its outputs.
- */
- virtual DeviceVector getOutputDevicesForAttributes(
- const audio_attributes_t &attributes,
- const sp<DeviceDescriptor> &preferedDevice = nullptr,
- bool fromCache = false) const = 0;
-
- /**
- * @brief getOutputDevicesForStream Legacy function retrieving devices from a stream type.
- * @param stream type of the output requesting Device(s) selection
- * @param fromCache if true, the device is returned from internal cache,
- * otherwise it is determined by current state (device connected,phone state,
- * force use, a2dp output...)
- * @return appropriate device for streams handled by the specified audio attributes according
- * to current phone state, forced states, connected devices...
- * if fromCache is true, the device is returned from internal cache,
- * otherwise it is determined by current state (device connected,phone state, force use,
- * a2dp output...)
- * This allows to:
- * 1 speed up process when the state is stable (when starting or stopping an output)
- * 2 access to either current device selection (fromCache == true) or
- * "future" device selection (fromCache == false) when called from a context
- * where conditions are changing (setDeviceConnectionState(), setPhoneState()...) AND
- * before manager updates its outputs.
- */
- virtual DeviceVector getOutputDevicesForStream(audio_stream_type_t stream,
- bool fromCache = false) const = 0;
-
- /**
- * Get the input device selected for given audio attributes.
- *
- * @param[in] attr audio attributes to consider
- * @param[out] mix to be used if a mix has been installed for the given audio attributes.
- * @return selected input device for the audio attributes, may be null if error.
- */
- virtual sp<DeviceDescriptor> getInputDeviceForAttributes(
- const audio_attributes_t &attr, sp<AudioPolicyMix> *mix = nullptr) const = 0;
-
- /**
- * Get the legacy stream type for a given audio attributes.
- *
- * @param[in] audio attributes to get the associated audio_stream_type_t.
- *
- * @return audio_stream_type_t associated to the attributes.
- */
- virtual audio_stream_type_t getStreamTypeForAttributes(
- const audio_attributes_t &attr) const = 0;
-
- /**
- * @brief getAttributesForStream get the audio attributes from legacy stream type
- * Attributes returned might only be used to check upon routing decision, not volume decisions.
- * @param stream to consider
- * @return audio attributes matching the legacy stream type
- */
- virtual audio_attributes_t getAttributesForStreamType(audio_stream_type_t stream) const = 0;
-
- /**
- * @brief getStreamTypesForProductStrategy retrieves the list of legacy stream type following
- * the given product strategy
- * @param ps product strategy to consider
- * @return associated legacy Stream Types vector of the given product strategy
- */
- virtual StreamTypeVector getStreamTypesForProductStrategy(product_strategy_t ps) const = 0;
-
- /**
- * @brief getAllAttributesForProductStrategy retrieves all the attributes following the given
- * product strategy. Any attributes that "matches" with this one will follow the product
- * strategy.
- * "matching" means the usage shall match if reference attributes has a defined usage, AND
- * content type shall match if reference attributes has a defined content type AND
- * flags shall match if reference attributes has defined flags AND
- * tags shall match if reference attributes has defined tags.
- * @param ps product strategy to consider
- * @return vector of product strategy ids, empty if unknown strategy.
- */
- virtual AttributesVector getAllAttributesForProductStrategy(product_strategy_t ps) const = 0;
-
- /**
- * @brief getOrderedAudioProductStrategies
- * @return priority ordered product strategies to help the AudioPolicyManager evaluating the
- * device selection per output according to the prioritized strategies.
- */
- virtual StrategyVector getOrderedProductStrategies() const = 0;
-
- /**
- * @brief updateDeviceSelectionCache. Device selection for AudioAttribute / Streams is cached
- * in the engine in order to speed up process when the audio system is stable.
- * When a device is connected, the android mode is changed, engine is notified and can update
- * the cache.
- * When starting / stopping an output with a stream that can affect notification, the engine
- * needs to update the cache upon this function call.
- */
- virtual void updateDeviceSelectionCache() = 0;
-
- /**
- * @brief listAudioProductStrategies. Introspection API to retrieve a collection of
- * AudioProductStrategyVector that allows to build AudioAttributes according to a
- * product_strategy which is just an index. It has also a human readable name to help the
- * Car/Oem/AudioManager identiying the use case.
- * @param strategies collection.
- * @return OK if the list has been retrieved, error code otherwise
- */
- virtual status_t listAudioProductStrategies(AudioProductStrategyVector &strategies) const = 0;
-
- /**
- * @brief getVolumeCurvesForAttributes retrieves the Volume Curves interface for the
- * requested Audio Attributes.
- * @param attr to be considered
- * @return IVolumeCurves interface pointer if found, nullptr otherwise
- */
- virtual IVolumeCurves *getVolumeCurvesForAttributes(const audio_attributes_t &attr) const = 0;
-
- /**
- * @brief getVolumeCurvesForStreamType retrieves the Volume Curves interface for the stream
- * @param stream to be considered
- * @return IVolumeCurves interface pointer if found, nullptr otherwise
- */
- virtual IVolumeCurves *getVolumeCurvesForStreamType(audio_stream_type_t stream) const = 0;
-
- /**
- * @brief getVolumeCurvesForVolumeGroup retrieves the Volume Curves interface for volume group
- * @param group to be considered
- * @return IVolumeCurves interface pointer if found, nullptr otherwise
- */
- virtual IVolumeCurves *getVolumeCurvesForVolumeGroup(volume_group_t group) const = 0;
-
- /**
- * @brief getVolumeGroups retrieves the collection of volume groups.
- * @return vector of volume groups
- */
- virtual VolumeGroupVector getVolumeGroups() const = 0;
-
- /**
- * @brief getVolumeGroupForAttributes gets the appropriate volume group to be used for a given
- * Audio Attributes.
- * @param attr to be considered
- * @return volume group associated to the given audio attributes, default group if none
- * applicable, VOLUME_GROUP_NONE if no default group defined.
- */
- virtual volume_group_t getVolumeGroupForAttributes(const audio_attributes_t &attr) const = 0;
-
- /**
- * @brief getVolumeGroupForStreamType gets the appropriate volume group to be used for a given
- * legacy stream type
- * @param stream type to be considered
- * @return volume group associated to the given stream type, default group if none applicable,
- * VOLUME_GROUP_NONE if no default group defined.
- */
- virtual volume_group_t getVolumeGroupForStreamType(audio_stream_type_t stream) const = 0;
-
- /**
- * @brief listAudioVolumeGroups introspection API to get the Audio Volume Groups, aka
- * former stream aliases in Audio Service, defining volume curves attached to one or more
- * Audio Attributes.
- * @param groups
- * @return NO_ERROR if the volume groups were retrieved successfully, error code otherwise
- */
- virtual status_t listAudioVolumeGroups(AudioVolumeGroupVector &groups) const = 0;
-
- virtual void dump(String8 *dst) const = 0;
-
-protected:
- virtual ~AudioPolicyManagerInterface() {}
-};
-
-} // namespace android
diff --git a/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h b/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h
index ebd82a7..349f969 100644
--- a/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h
+++ b/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h
@@ -16,8 +16,7 @@
#pragma once
-#include <AudioGain.h>
-#include <AudioPort.h>
+#include <PolicyAudioPort.h>
#include <AudioPatch.h>
#include <IOProfile.h>
#include <DeviceDescriptor.h>
diff --git a/services/audiopolicy/engine/interface/EngineInterface.h b/services/audiopolicy/engine/interface/EngineInterface.h
new file mode 100644
index 0000000..dfb20b5
--- /dev/null
+++ b/services/audiopolicy/engine/interface/EngineInterface.h
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <AudioPolicyManagerObserver.h>
+#include <media/AudioProductStrategy.h>
+#include <media/AudioVolumeGroup.h>
+#include <IVolumeCurves.h>
+#include <policy.h>
+#include <Volume.h>
+#include <HwModule.h>
+#include <DeviceDescriptor.h>
+#include <system/audio.h>
+#include <system/audio_policy.h>
+#include <utils/Errors.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+using DeviceStrategyMap = std::map<product_strategy_t, DeviceVector>;
+using StrategyVector = std::vector<product_strategy_t>;
+using VolumeGroupVector = std::vector<volume_group_t>;
+
+/**
+ * This interface is dedicated to the policy manager that a Policy Engine shall implement.
+ */
+class EngineInterface
+{
+public:
+ /**
+ * Checks if the engine was correctly initialized.
+ *
+ * @return NO_ERROR if initialization has been done correctly, error code otherwise..
+ */
+ virtual status_t initCheck() = 0;
+
+ /**
+ * Sets the Manager observer that allows the engine to retrieve information on collection
+ * of devices, streams, HwModules, ...
+ *
+ * @param[in] observer handle on the manager.
+ */
+ virtual void setObserver(AudioPolicyManagerObserver *observer) = 0;
+
+ /**
+ * Set the Telephony Mode.
+ *
+ * @param[in] mode: Android Phone state (normal, ringtone, csv, in communication)
+ *
+ * @return NO_ERROR if Telephony Mode set correctly, error code otherwise.
+ */
+ virtual status_t setPhoneState(audio_mode_t mode) = 0;
+
+ /**
+ * Get the telephony Mode
+ *
+ * @return the current telephony mode
+ */
+ virtual audio_mode_t getPhoneState() const = 0;
+
+ /**
+ * Set Force Use config for a given usage.
+ *
+ * @param[in] usage for which a configuration shall be forced.
+ * @param[in] config wished to be forced for the given usage.
+ *
+ * @return NO_ERROR if the Force Use config was set correctly, error code otherwise (e.g. config
+ * not allowed a given usage...)
+ */
+ virtual status_t setForceUse(audio_policy_force_use_t usage,
+ audio_policy_forced_cfg_t config) = 0;
+
+ /**
+ * Get Force Use config for a given usage.
+ *
+ * @param[in] usage for which a configuration shall be forced.
+ *
+ * @return config wished to be forced for the given usage.
+ */
+ virtual audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage) const = 0;
+
+ /**
+ * Set the connection state of device(s).
+ *
+ * @param[in] devDesc for which the state has changed.
+ * @param[in] state of availability of this(these) device(s).
+ *
+ * @return NO_ERROR if devices criterion updated correctly, error code otherwise.
+ */
+ virtual status_t setDeviceConnectionState(const android::sp<android::DeviceDescriptor> devDesc,
+ audio_policy_dev_state_t state) = 0;
+
+ /**
+ * Get the strategy selected for a given audio attributes.
+ *
+ * @param[in] audio attributes to get the selected @product_strategy_t followed by.
+ *
+ * @return @product_strategy_t to be followed.
+ */
+ virtual product_strategy_t getProductStrategyForAttributes(
+ const audio_attributes_t &attr) const = 0;
+
+ /**
+ * @brief getOutputDevicesForAttributes retrieves the devices to be used for given
+ * audio attributes.
+ * @param attributes of the output requesting Device(s) selection
+ * @param preferedDevice valid reference if a prefered device is requested, nullptr otherwise.
+ * @param fromCache if true, the device is returned from internal cache,
+ * otherwise it is determined by current state (device connected,phone state,
+ * force use, a2dp output...)
+ * @return vector of selected device descriptors.
+ * Appropriate device for streams handled by the specified audio attributes according
+ * to current phone state, forced states, connected devices...
+ * if fromCache is true, the device is returned from internal cache,
+ * otherwise it is determined by current state (device connected,phone state, force use,
+ * a2dp output...)
+ * This allows to:
+ * 1 speed up process when the state is stable (when starting or stopping an output)
+ * 2 access to either current device selection (fromCache == true) or
+ * "future" device selection (fromCache == false) when called from a context
+ * where conditions are changing (setDeviceConnectionState(), setPhoneState()...) AND
+ * before manager updates its outputs.
+ */
+ virtual DeviceVector getOutputDevicesForAttributes(
+ const audio_attributes_t &attributes,
+ const sp<DeviceDescriptor> &preferedDevice = nullptr,
+ bool fromCache = false) const = 0;
+
+ /**
+ * @brief getOutputDevicesForStream Legacy function retrieving devices from a stream type.
+ * @param stream type of the output requesting Device(s) selection
+ * @param fromCache if true, the device is returned from internal cache,
+ * otherwise it is determined by current state (device connected,phone state,
+ * force use, a2dp output...)
+ * @return appropriate device for streams handled by the specified audio attributes according
+ * to current phone state, forced states, connected devices...
+ * if fromCache is true, the device is returned from internal cache,
+ * otherwise it is determined by current state (device connected,phone state, force use,
+ * a2dp output...)
+ * This allows to:
+ * 1 speed up process when the state is stable (when starting or stopping an output)
+ * 2 access to either current device selection (fromCache == true) or
+ * "future" device selection (fromCache == false) when called from a context
+ * where conditions are changing (setDeviceConnectionState(), setPhoneState()...) AND
+ * before manager updates its outputs.
+ */
+ virtual DeviceVector getOutputDevicesForStream(audio_stream_type_t stream,
+ bool fromCache = false) const = 0;
+
+ /**
+ * Get the input device selected for given audio attributes.
+ *
+ * @param[in] attr audio attributes to consider
+ * @param[out] mix to be used if a mix has been installed for the given audio attributes.
+ * @return selected input device for the audio attributes, may be null if error.
+ */
+ virtual sp<DeviceDescriptor> getInputDeviceForAttributes(
+ const audio_attributes_t &attr, sp<AudioPolicyMix> *mix = nullptr) const = 0;
+
+ /**
+ * Get the legacy stream type for a given audio attributes.
+ *
+ * @param[in] audio attributes to get the associated audio_stream_type_t.
+ *
+ * @return audio_stream_type_t associated to the attributes.
+ */
+ virtual audio_stream_type_t getStreamTypeForAttributes(
+ const audio_attributes_t &attr) const = 0;
+
+ /**
+ * @brief getAttributesForStream get the audio attributes from legacy stream type
+ * Attributes returned might only be used to check upon routing decision, not volume decisions.
+ * @param stream to consider
+ * @return audio attributes matching the legacy stream type
+ */
+ virtual audio_attributes_t getAttributesForStreamType(audio_stream_type_t stream) const = 0;
+
+ /**
+ * @brief getStreamTypesForProductStrategy retrieves the list of legacy stream type following
+ * the given product strategy
+ * @param ps product strategy to consider
+ * @return associated legacy Stream Types vector of the given product strategy
+ */
+ virtual StreamTypeVector getStreamTypesForProductStrategy(product_strategy_t ps) const = 0;
+
+ /**
+ * @brief getAllAttributesForProductStrategy retrieves all the attributes following the given
+ * product strategy. Any attributes that "matches" with this one will follow the product
+ * strategy.
+ * "matching" means the usage shall match if reference attributes has a defined usage, AND
+ * content type shall match if reference attributes has a defined content type AND
+ * flags shall match if reference attributes has defined flags AND
+ * tags shall match if reference attributes has defined tags.
+ * @param ps product strategy to consider
+ * @return vector of product strategy ids, empty if unknown strategy.
+ */
+ virtual AttributesVector getAllAttributesForProductStrategy(product_strategy_t ps) const = 0;
+
+ /**
+ * @brief getOrderedAudioProductStrategies
+ * @return priority ordered product strategies to help the AudioPolicyManager evaluating the
+ * device selection per output according to the prioritized strategies.
+ */
+ virtual StrategyVector getOrderedProductStrategies() const = 0;
+
+ /**
+ * @brief updateDeviceSelectionCache. Device selection for AudioAttribute / Streams is cached
+ * in the engine in order to speed up process when the audio system is stable.
+ * When a device is connected, the android mode is changed, engine is notified and can update
+ * the cache.
+ * When starting / stopping an output with a stream that can affect notification, the engine
+ * needs to update the cache upon this function call.
+ */
+ virtual void updateDeviceSelectionCache() = 0;
+
+ /**
+ * @brief listAudioProductStrategies. Introspection API to retrieve a collection of
+ * AudioProductStrategyVector that allows to build AudioAttributes according to a
+ * product_strategy which is just an index. It has also a human readable name to help the
+ * Car/Oem/AudioManager identiying the use case.
+ * @param strategies collection.
+ * @return OK if the list has been retrieved, error code otherwise
+ */
+ virtual status_t listAudioProductStrategies(AudioProductStrategyVector &strategies) const = 0;
+
+ /**
+ * @brief getVolumeCurvesForAttributes retrieves the Volume Curves interface for the
+ * requested Audio Attributes.
+ * @param attr to be considered
+ * @return IVolumeCurves interface pointer if found, nullptr otherwise
+ */
+ virtual IVolumeCurves *getVolumeCurvesForAttributes(const audio_attributes_t &attr) const = 0;
+
+ /**
+ * @brief getVolumeCurvesForStreamType retrieves the Volume Curves interface for the stream
+ * @param stream to be considered
+ * @return IVolumeCurves interface pointer if found, nullptr otherwise
+ */
+ virtual IVolumeCurves *getVolumeCurvesForStreamType(audio_stream_type_t stream) const = 0;
+
+ /**
+ * @brief getVolumeCurvesForVolumeGroup retrieves the Volume Curves interface for volume group
+ * @param group to be considered
+ * @return IVolumeCurves interface pointer if found, nullptr otherwise
+ */
+ virtual IVolumeCurves *getVolumeCurvesForVolumeGroup(volume_group_t group) const = 0;
+
+ /**
+ * @brief getVolumeGroups retrieves the collection of volume groups.
+ * @return vector of volume groups
+ */
+ virtual VolumeGroupVector getVolumeGroups() const = 0;
+
+ /**
+ * @brief getVolumeGroupForAttributes gets the appropriate volume group to be used for a given
+ * Audio Attributes.
+ * @param attr to be considered
+ * @return volume group associated to the given audio attributes, default group if none
+ * applicable, VOLUME_GROUP_NONE if no default group defined.
+ */
+ virtual volume_group_t getVolumeGroupForAttributes(const audio_attributes_t &attr) const = 0;
+
+ /**
+ * @brief getVolumeGroupForStreamType gets the appropriate volume group to be used for a given
+ * legacy stream type
+ * @param stream type to be considered
+ * @return volume group associated to the given stream type, default group if none applicable,
+ * VOLUME_GROUP_NONE if no default group defined.
+ */
+ virtual volume_group_t getVolumeGroupForStreamType(audio_stream_type_t stream) const = 0;
+
+ /**
+ * @brief listAudioVolumeGroups introspection API to get the Audio Volume Groups, aka
+ * former stream aliases in Audio Service, defining volume curves attached to one or more
+ * Audio Attributes.
+ * @param groups
+ * @return NO_ERROR if the volume groups were retrieved successfully, error code otherwise
+ */
+ virtual status_t listAudioVolumeGroups(AudioVolumeGroupVector &groups) const = 0;
+
+ /**
+ * @brief setPreferredDeviceForStrategy sets the default device to be used for a
+ * strategy when available
+ * @param strategy the audio strategy whose routing will be affected
+ * @param device the audio device to route to when available
+ * @return BAD_VALUE if the strategy is invalid,
+ * or NO_ERROR if the preferred device was set
+ */
+ virtual status_t setPreferredDeviceForStrategy(product_strategy_t strategy,
+ const AudioDeviceTypeAddr &device) = 0;
+
+ /**
+ * @brief removePreferredDeviceForStrategy removes the preferred device previously set
+ * for the given strategy
+ * @param strategy the audio strategy whose routing will be affected
+ * @return BAD_VALUE if the strategy is invalid,
+ * or NO_ERROR if the preferred device was removed
+ */
+ virtual status_t removePreferredDeviceForStrategy(product_strategy_t strategy) = 0;
+
+ /**
+ * @brief getPreferredDeviceForStrategy queries which device is set as the
+ * preferred device for the given strategy
+ * @param strategy the strategy to query
+ * @param device returns configured as the preferred device if one was set
+ * @return BAD_VALUE if the strategy is invalid,
+ * or NAME_NOT_FOUND if no preferred device was set
+ * or NO_ERROR if the device parameter was initialized to the preferred device
+ */
+ virtual status_t getPreferredDeviceForStrategy(product_strategy_t strategy,
+ AudioDeviceTypeAddr &device) const = 0;
+
+
+ virtual void dump(String8 *dst) const = 0;
+
+protected:
+ virtual ~EngineInterface() {}
+};
+
+__attribute__((visibility("default")))
+extern "C" EngineInterface* createEngineInstance();
+
+__attribute__((visibility("default")))
+extern "C" void destroyEngineInstance(EngineInterface *engine);
+
+} // namespace android
diff --git a/services/audiopolicy/engineconfigurable/Android.bp b/services/audiopolicy/engineconfigurable/Android.bp
index c27dc88..8f522f0 100644
--- a/services/audiopolicy/engineconfigurable/Android.bp
+++ b/services/audiopolicy/engineconfigurable/Android.bp
@@ -33,6 +33,7 @@
],
shared_libs: [
+ "libaudiofoundation",
"liblog",
"libcutils",
"libutils",
diff --git a/services/audiopolicy/engineconfigurable/config/Android.bp b/services/audiopolicy/engineconfigurable/config/Android.bp
new file mode 100644
index 0000000..fe3eae0
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/config/Android.bp
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+// Root soong_namespace for common components
+
+prebuilt_etc {
+ name: "audio_policy_engine_criteria.xml",
+ vendor: true,
+ src: ":audio_policy_engine_criteria",
+}
+filegroup {
+ name: "audio_policy_engine_criterion_types_template",
+ srcs: ["example/common/audio_policy_engine_criterion_types.xml.in"],
+}
+filegroup {
+ name: "audio_policy_engine_criteria",
+ srcs: ["example/common/audio_policy_engine_criteria.xml"],
+}
diff --git a/services/audiopolicy/engineconfigurable/config/example/Android.mk b/services/audiopolicy/engineconfigurable/config/example/Android.mk
deleted file mode 100644
index a0f1a90..0000000
--- a/services/audiopolicy/engineconfigurable/config/example/Android.mk
+++ /dev/null
@@ -1,151 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-ifdef BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION
-
-TOOLS := frameworks/av/services/audiopolicy/engineconfigurable/tools
-PROVISION_CRITERION_TYPES := $(TOOLS)/provision_criterion_types_from_android_headers.mk
-
-##################################################################
-# CONFIGURATION TOP FILE
-##################################################################
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), phone_configurable)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_configuration.xml
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
-
-LOCAL_REQUIRED_MODULES := \
- audio_policy_engine_product_strategies.xml \
- audio_policy_engine_stream_volumes.xml \
- audio_policy_engine_default_stream_volumes.xml \
- audio_policy_engine_criteria.xml \
- audio_policy_engine_criterion_types.xml
-
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_product_strategies.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_stream_volumes.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_default_stream_volumes.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-endif # ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), phone_configurable)
-
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),automotive_configurable caremu_configurable))
-
-##################################################################
-# AUTOMOTIVE CONFIGURATION TOP FILE
-##################################################################
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_configuration.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := automotive/$(LOCAL_MODULE)
-
-LOCAL_REQUIRED_MODULES := \
- audio_policy_engine_product_strategies.xml \
- audio_policy_engine_criteria.xml \
- audio_policy_engine_criterion_types.xml \
- audio_policy_engine_volumes.xml
-
-include $(BUILD_PREBUILT)
-
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),automotive_configurable caremu_configurable))
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), automotive_configurable)
-
-##################################################################
-# CONFIGURATION FILES
-##################################################################
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_product_strategies.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := automotive/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_volumes.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := automotive/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), automotive_configurable)
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), caremu_configurable)
-
-##################################################################
-# CONFIGURATION FILES
-##################################################################
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_product_strategies.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := caremu/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_volumes.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := caremu/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), caremu_configurable)
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable caremu_configurable))
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_criteria.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := common/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_criterion_types.xml
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_VENDOR_ETC)/primary_audio_policy_configuration.xml
-ANDROID_AUDIO_BASE_HEADER_FILE := system/media/audio/include/system/audio-base.h
-AUDIO_POLICY_CONFIGURATION_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_configuration.xml
-CRITERION_TYPES_FILE := $(LOCAL_PATH)/common/$(LOCAL_MODULE).in
-
-include $(PROVISION_CRITERION_TYPES)
-
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable caremu_configurable))
-
-endif #ifdef BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION
diff --git a/services/audiopolicy/engineconfigurable/config/example/automotive/Android.bp b/services/audiopolicy/engineconfigurable/config/example/automotive/Android.bp
new file mode 100644
index 0000000..f913a14
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/config/example/automotive/Android.bp
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+// Import this namespace in order to use AOSP Automotive configuration example
+
+soong_namespace {
+ imports: [
+ "frameworks/av/services/audiopolicy/config",
+ ],
+}
+
+prebuilt_etc {
+ name: "audio_policy_engine_configuration.xml",
+ vendor: true,
+ src: ":audio_policy_engine_configuration",
+ required: [
+ ":audio_policy_engine_criterion_types.xml",
+ ":audio_policy_engine_criteria.xml",
+ ":audio_policy_engine_product_strategies.xml",
+ ":audio_policy_engine_volumes.xml",
+ ],
+}
+prebuilt_etc {
+ name: "audio_policy_engine_product_strategies.xml",
+ vendor: true,
+ src: "audio_policy_engine_product_strategies.xml",
+}
+prebuilt_etc {
+ name: "audio_policy_engine_volumes.xml",
+ vendor: true,
+ src: ":audio_policy_engine_volumes",
+}
+prebuilt_etc {
+ name: "audio_policy_engine_criterion_types.xml",
+ vendor: true,
+ src: ":audio_policy_engine_criterion_types",
+}
+
+//
+// Generate audio_policy_engine criterion type file => provides device addresses criterion type
+//
+genrule {
+ name: "audio_policy_engine_criterion_types",
+ defaults: ["buildpolicycriteriontypesrule"],
+ srcs: [
+ ":audio_policy_configuration_top_file",
+ ":audio_policy_configuration_files",
+ ],
+}
+filegroup {
+ name: "audio_policy_configuration_files",
+ srcs: [
+ ":r_submix_audio_policy_configuration",
+ ":default_volume_tables",
+ ":audio_policy_volumes",
+ ":surround_sound_configuration_5_0",
+ ":primary_audio_policy_configuration",
+ ],
+}
+filegroup {
+ name : "audio_policy_configuration_top_file",
+ srcs: [":audio_policy_configuration_generic"],
+}
+filegroup {
+ name: "audio_policy_engine_configuration",
+ srcs: ["audio_policy_engine_configuration.xml"],
+}
+filegroup {
+ name: "audio_policy_engine_volumes",
+ srcs: ["audio_policy_engine_volumes.xml"],
+}
+filegroup {
+ name: "audio_policy_engine_configuration_files",
+ srcs: [
+ ":audio_policy_engine_configuration",
+ "audio_policy_engine_product_strategies.xml",
+ ":audio_policy_engine_volumes",
+ ":audio_policy_engine_criterion_types",
+ ":audio_policy_engine_criteria",
+ ],
+}
diff --git a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_product_strategies.xml b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_product_strategies.xml
index 0ee83a2..f598cf2 100644
--- a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_product_strategies.xml
+++ b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_product_strategies.xml
@@ -84,7 +84,7 @@
</AttributesGroup>
</ProductStrategy>
<ProductStrategy name="voice_command">
- <AttributesGroup volumeGroup="speech">
+ <AttributesGroup volumeGroup="speech" streamType="AUDIO_STREAM_ASSISTANT">
<Attributes>
<ContentType value="AUDIO_CONTENT_TYPE_SPEECH"/>
<Usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/>
@@ -147,10 +147,6 @@
<ProductStrategy name="notification">
<AttributesGroup streamType="AUDIO_STREAM_NOTIFICATION" volumeGroup="ring">
<Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION"/> </Attributes>
- <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT"/> </Attributes>
- <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED"/> </Attributes>
- <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST"/> </Attributes>
- <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_EVENT"/> </Attributes>
</AttributesGroup>
</ProductStrategy>
<ProductStrategy name="system">
@@ -167,19 +163,5 @@
</AttributesGroup>
</ProductStrategy>
- <!-- Routing Strategy rerouting may be removed as following media??? -->
- <ProductStrategy name="rerouting">
- <AttributesGroup streamType="AUDIO_STREAM_REROUTING" volumeGroup="rerouting">
- <Attributes></Attributes>
- </AttributesGroup>
- </ProductStrategy>
-
- <!-- Patch stream needs full scale volume, define it otherwise switch to default... -->
- <ProductStrategy name="patch">
- <AttributesGroup streamType="AUDIO_STREAM_PATCH" volumeGroup="patch">
- <Attributes></Attributes>
- </AttributesGroup>
- </ProductStrategy>
-
</ProductStrategies>
diff --git a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml
index 6e72dc5..97a25a8 100644
--- a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml
+++ b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml
@@ -189,25 +189,5 @@
</volume>
</volumeGroup>
- <volumeGroup>
- <name>rerouting</name>
- <indexMin>0</indexMin>
- <indexMax>1</indexMax>
- <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
- <point>0,0</point>
- <point>100,0</point>
- </volume>
- </volumeGroup>
-
- <volumeGroup>
- <name>patch</name>
- <indexMin>0</indexMin>
- <indexMax>1</indexMax>
- <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
- <point>0,0</point>
- <point>100,0</point>
- </volume>
- </volumeGroup>
-
</volumeGroups>
diff --git a/services/audiopolicy/engineconfigurable/config/example/caremu/Android.bp b/services/audiopolicy/engineconfigurable/config/example/caremu/Android.bp
new file mode 100644
index 0000000..fae6b7b
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/config/example/caremu/Android.bp
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+// Import this namespace in order to use AOSP Car Emulator configuration example
+
+soong_namespace {
+ imports: [
+ "frameworks/av/services/audiopolicy/engineconfigurable/config/example/automotive",
+ "frameworks/av/services/audiopolicy/config",
+ ],
+}
+
+prebuilt_etc {
+ name: "audio_policy_engine_configuration.xml",
+ vendor: true,
+ src: ":audio_policy_engine_configuration",
+ required: [
+ "audio_policy_engine_criterion_types.xml",
+ "audio_policy_engine_criteria.xml",
+ "audio_policy_engine_product_strategies.xml",
+ ":audio_policy_engine_volumes.xml",
+ ],
+}
+prebuilt_etc {
+ name: "audio_policy_engine_product_strategies.xml",
+ vendor: true,
+ src: "audio_policy_engine_product_strategies.xml",
+}
+prebuilt_etc {
+ name: "audio_policy_engine_criterion_types.xml",
+ vendor: true,
+ src: ":audio_policy_engine_criterion_types",
+}
+
+//
+// Generate audio_policy_engine criterion type file => provides device addresses criterion type
+//
+genrule {
+ name: "audio_policy_engine_criterion_types",
+ defaults: ["buildpolicycriteriontypesrule"],
+ srcs: [
+ ":audio_policy_configuration_top_file",
+ ":audio_policy_configuration_files",
+ ],
+}
+filegroup {
+ name: "audio_policy_configuration_files",
+ srcs: [
+ ":r_submix_audio_policy_configuration",
+ ":default_volume_tables",
+ ":audio_policy_volumes",
+ ":surround_sound_configuration_5_0",
+ ":primary_audio_policy_configuration",
+ ],
+}
+filegroup {
+ name : "audio_policy_configuration_top_file",
+ srcs: [":audio_policy_configuration_generic"],
+}
+filegroup {
+ name: "audio_policy_engine_configuration_files",
+ srcs: [
+ ":audio_policy_engine_configuration",
+ "audio_policy_engine_product_strategies.xml",
+ ":audio_policy_engine_volumes",
+ ":audio_policy_engine_criterion_types",
+ ":audio_policy_engine_criteria",
+ ],
+}
diff --git a/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_product_strategies.xml b/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_product_strategies.xml
index adcbd83..f598cf2 100644
--- a/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_product_strategies.xml
+++ b/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_product_strategies.xml
@@ -84,7 +84,7 @@
</AttributesGroup>
</ProductStrategy>
<ProductStrategy name="voice_command">
- <AttributesGroup volumeGroup="speech">
+ <AttributesGroup volumeGroup="speech" streamType="AUDIO_STREAM_ASSISTANT">
<Attributes>
<ContentType value="AUDIO_CONTENT_TYPE_SPEECH"/>
<Usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/>
@@ -147,10 +147,6 @@
<ProductStrategy name="notification">
<AttributesGroup streamType="AUDIO_STREAM_NOTIFICATION" volumeGroup="ring">
<Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION"/> </Attributes>
- <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT"/> </Attributes>
- <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED"/> </Attributes>
- <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST"/> </Attributes>
- <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_EVENT"/> </Attributes>
</AttributesGroup>
</ProductStrategy>
<ProductStrategy name="system">
@@ -167,18 +163,5 @@
</AttributesGroup>
</ProductStrategy>
- <!-- Routing Strategy rerouting may be removed as following media??? -->
- <ProductStrategy name="rerouting">
- <AttributesGroup streamType="AUDIO_STREAM_REROUTING" volumeGroup="rerouting">
- <Attributes></Attributes>
- </AttributesGroup>
- </ProductStrategy>
-
- <!-- Patch stream needs full scale volume, define it otherwise switch to default... -->
- <ProductStrategy name="patch">
- <AttributesGroup streamType="AUDIO_STREAM_PATCH" volumeGroup="patch">
- <Attributes></Attributes>
- </AttributesGroup>
- </ProductStrategy>
</ProductStrategies>
diff --git a/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_volumes.xml b/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_volumes.xml
index 6e72dc5..97a25a8 100644
--- a/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_volumes.xml
+++ b/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_volumes.xml
@@ -189,25 +189,5 @@
</volume>
</volumeGroup>
- <volumeGroup>
- <name>rerouting</name>
- <indexMin>0</indexMin>
- <indexMax>1</indexMax>
- <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
- <point>0,0</point>
- <point>100,0</point>
- </volume>
- </volumeGroup>
-
- <volumeGroup>
- <name>patch</name>
- <indexMin>0</indexMin>
- <indexMax>1</indexMax>
- <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
- <point>0,0</point>
- <point>100,0</point>
- </volume>
- </volumeGroup>
-
</volumeGroups>
diff --git a/services/audiopolicy/engineconfigurable/config/example/common/audio_policy_engine_criterion_types.xml.in b/services/audiopolicy/engineconfigurable/config/example/common/audio_policy_engine_criterion_types.xml.in
index fe17369..e134c42 100644
--- a/services/audiopolicy/engineconfigurable/config/example/common/audio_policy_engine_criterion_types.xml.in
+++ b/services/audiopolicy/engineconfigurable/config/example/common/audio_policy_engine_criterion_types.xml.in
@@ -22,7 +22,12 @@
<value literal="0" numerical="1"/>
</values>
</criterion_type>
- <criterion_type name="InputDevicesAddressesType" type="inclusive"/>
+ <criterion_type name="InputDevicesAddressesType" type="inclusive">
+ <values>
+ <!-- legacy remote submix -->
+ <value literal="0" numerical="1"/>
+ </values>
+ </criterion_type>
<criterion_type name="AndroidModeType" type="exclusive"/>
<criterion_type name="BooleanType" type="exclusive">
<values>
diff --git a/services/audiopolicy/engineconfigurable/config/example/phone/Android.bp b/services/audiopolicy/engineconfigurable/config/example/phone/Android.bp
new file mode 100644
index 0000000..94d33bd
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/config/example/phone/Android.bp
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+// Import this namespace in order to use AOSP Phone configuration example
+
+soong_namespace {
+ imports: [
+ "frameworks/av/services/audiopolicy/config",
+ ],
+}
+
+prebuilt_etc {
+ name: "audio_policy_engine_configuration.xml",
+ vendor: true,
+ src: ":audio_policy_engine_configuration",
+ required: [
+ ":audio_policy_engine_criterion_types.xml",
+ ":audio_policy_engine_criteria.xml",
+ ":audio_policy_engine_product_strategies.xml",
+ ":audio_policy_engine_volumes.xml",
+ ],
+}
+prebuilt_etc {
+ name: "audio_policy_engine_product_strategies.xml",
+ vendor: true,
+ src: "audio_policy_engine_product_strategies.xml",
+}
+prebuilt_etc {
+ name: "audio_policy_engine_stream_volumes.xml",
+ vendor: true,
+ src: ":audio_policy_engine_stream_volumes",
+}
+prebuilt_etc {
+ name: "audio_policy_engine_default_stream_volumes.xml",
+ vendor: true,
+ src: ":audio_policy_engine_default_stream_volumes",
+}
+prebuilt_etc {
+ name: "audio_policy_engine_criterion_types.xml",
+ vendor: true,
+ src: ":audio_policy_engine_criterion_types",
+}
+
+//
+// Generate audio_policy_engine criterion type file => provides device addresses criterion type
+//
+genrule {
+ name: "audio_policy_engine_criterion_types",
+ defaults: ["buildpolicycriteriontypesrule"],
+ srcs: [
+ ":audio_policy_configuration_top_file",
+ ":audio_policy_configuration_files",
+ ],
+}
+filegroup {
+ name: "audio_policy_configuration_files",
+ srcs: [
+ ":r_submix_audio_policy_configuration",
+ ":default_volume_tables",
+ ":audio_policy_volumes",
+ ":surround_sound_configuration_5_0",
+ ":primary_audio_policy_configuration",
+ ],
+}
+filegroup {
+ name : "audio_policy_configuration_top_file",
+ srcs: [":audio_policy_configuration_generic"],
+}
+filegroup {
+ name: "audio_policy_engine_configuration",
+ srcs: ["audio_policy_engine_configuration.xml"],
+}
+filegroup {
+ name: "audio_policy_engine_stream_volumes",
+ srcs: ["audio_policy_engine_stream_volumes.xml"],
+}
+filegroup {
+ name: "audio_policy_engine_default_stream_volumes",
+ srcs: ["audio_policy_engine_default_stream_volumes.xml"],
+}
+filegroup {
+ name: "audio_policy_engine_configuration_files",
+ srcs: [
+ ":audio_policy_engine_configuration",
+ "audio_policy_engine_product_strategies.xml",
+ ":audio_policy_engine_stream_volumes",
+ ":audio_policy_engine_default_stream_volumes",
+ ":audio_policy_engine_criterion_types",
+ ":audio_policy_engine_criteria",
+ ],
+}
diff --git a/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_product_strategies.xml b/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_product_strategies.xml
index 9398743..a7388da 100644
--- a/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_product_strategies.xml
+++ b/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_product_strategies.xml
@@ -72,6 +72,12 @@
<Attributes> <Usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/> </Attributes>
<Attributes></Attributes>
</AttributesGroup>
+ <AttributesGroup streamType="AUDIO_STREAM_ASSISTANT" volumeGroup="assistant">
+ <Attributes>
+ <ContentType value="AUDIO_CONTENT_TYPE_SPEECH"/>
+ <Usage value="AUDIO_USAGE_ASSISTANT"/>
+ </Attributes>
+ </AttributesGroup>
<AttributesGroup streamType="AUDIO_STREAM_SYSTEM" volumeGroup="system">
<Attributes> <Usage value="AUDIO_USAGE_ASSISTANCE_SONIFICATION"/> </Attributes>
</AttributesGroup>
@@ -91,20 +97,5 @@
</AttributesGroup>
</ProductStrategy>
- <!-- Routing Strategy rerouting may be removed as following media??? -->
- <ProductStrategy name="STRATEGY_REROUTING">
- <AttributesGroup streamType="AUDIO_STREAM_REROUTING" volumeGroup="rerouting">
- <Attributes></Attributes>
- </AttributesGroup>
- </ProductStrategy>
-
- <!-- Default product strategy has empty attributes -->
- <ProductStrategy name="STRATEGY_PATCH">
- <AttributesGroup streamType="AUDIO_STREAM_PATCH" volumeGroup="patch">
- <Attributes></Attributes>
- </AttributesGroup>
- </ProductStrategy>
-
-
</ProductStrategies>
diff --git a/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_stream_volumes.xml b/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_stream_volumes.xml
index 707a184..8aa71ca 100644
--- a/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_stream_volumes.xml
+++ b/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_stream_volumes.xml
@@ -205,27 +205,16 @@
<volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_NON_MUTABLE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_NON_MUTABLE_HEARING_AID_VOLUME_CURVE"/>
</volumeGroup>
-
<volumeGroup>
- <name>rerouting</name>
+ <name>assistant</name>
<indexMin>0</indexMin>
- <indexMax>1</indexMax>
- <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="FULL_SCALE_VOLUME_CURVE"/>
- <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="FULL_SCALE_VOLUME_CURVE"/>
- <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="FULL_SCALE_VOLUME_CURVE"/>
- <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="FULL_SCALE_VOLUME_CURVE"/>
- <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="FULL_SCALE_VOLUME_CURVE"/>
+ <indexMax>15</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
</volumeGroup>
- <volumeGroup>
- <name>patch</name>
- <indexMin>0</indexMin>
- <indexMax>1</indexMax>
- <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="FULL_SCALE_VOLUME_CURVE"/>
- <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="FULL_SCALE_VOLUME_CURVE"/>
- <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="FULL_SCALE_VOLUME_CURVE"/>
- <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="FULL_SCALE_VOLUME_CURVE"/>
- <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="FULL_SCALE_VOLUME_CURVE"/>
- </volumeGroup>
</volumeGroups>
diff --git a/services/audiopolicy/engineconfigurable/include/AudioPolicyEngineInstance.h b/services/audiopolicy/engineconfigurable/include/AudioPolicyEngineInstance.h
index efc69da..f52de21 100644
--- a/services/audiopolicy/engineconfigurable/include/AudioPolicyEngineInstance.h
+++ b/services/audiopolicy/engineconfigurable/include/AudioPolicyEngineInstance.h
@@ -16,7 +16,7 @@
#pragma once
-class AudioPolicyManagerInterface;
+class EngineInterface;
class AudioPolicyPluginInterface;
namespace android {
@@ -69,7 +69,7 @@
* Compile time error will claim if invalid interface is requested.
*/
template <>
-AudioPolicyManagerInterface *EngineInstance::queryInterface() const;
+EngineInterface *EngineInstance::queryInterface() const;
template <>
AudioPolicyPluginInterface *EngineInstance::queryInterface() const;
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/Android.bp
new file mode 100644
index 0000000..90ebffd
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/Android.bp
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+// Root soong_namespace for common components
+
+prebuilt_etc {
+ name: "PolicyClass.xml",
+ vendor: true,
+ src: ":PolicyClass",
+ sub_dir: "parameter-framework/Structure/Policy",
+}
+prebuilt_etc {
+ name: "PolicySubsystem.xml",
+ vendor: true,
+ src: ":PolicySubsystem",
+ sub_dir: "parameter-framework/Structure/Policy",
+}
+prebuilt_etc {
+ name: "PolicySubsystem-CommonTypes.xml",
+ vendor: true,
+ src: ":buildcommontypesstructure_gen",
+ sub_dir: "parameter-framework/Structure/Policy",
+}
+genrule {
+ name: "buildcommontypesstructure_gen",
+ defaults: ["buildcommontypesstructurerule"],
+}
+
+filegroup {
+ name: "product_strategies_structure_template",
+ srcs: ["examples/common/Structure/ProductStrategies.xml.in"],
+}
+filegroup {
+ name: "PolicySubsystem",
+ srcs: ["examples/common/Structure/PolicySubsystem.xml"],
+}
+filegroup {
+ name: "PolicySubsystem-no-strategy",
+ srcs: ["examples/common/Structure/PolicySubsystem-no-strategy.xml"],
+}
+filegroup {
+ name: "common_types_structure_template",
+ srcs: ["examples/common/Structure/PolicySubsystem-CommonTypes.xml.in"],
+}
+filegroup {
+ name: "PolicyClass",
+ srcs: ["examples/common/Structure/PolicyClass.xml"],
+}
+filegroup {
+ name: "volumes.pfw",
+ srcs: ["examples/Settings/volumes.pfw"],
+}
+filegroup {
+ name: "device_for_input_source.pfw",
+ srcs: ["examples/Settings/device_for_input_source.pfw"],
+}
+filegroup {
+ name: "ParameterFrameworkConfigurationPolicy.userdebug.xml",
+ srcs: ["examples/ParameterFrameworkConfigurationPolicy.userdebug.xml"],
+}
+filegroup {
+ name: "ParameterFrameworkConfigurationPolicy.user.xml",
+ srcs: ["examples/ParameterFrameworkConfigurationPolicy.user.xml"],
+}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Android.mk
deleted file mode 100644
index 19f93b3..0000000
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Android.mk
+++ /dev/null
@@ -1,187 +0,0 @@
-################################################################################################
-#
-# @NOTE:
-# Audio Policy Engine configurable example for generic device build
-#
-# Any vendor shall have its own configuration within the corresponding device folder
-#
-################################################################################################
-
-LOCAL_PATH := $(call my-dir)
-
-ifdef BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable caremu_configurable no-output_configurable no-input_configurable))
-
-PFW_CORE := external/parameter-framework
-#@TODO: upstream new domain generator
-#BUILD_PFW_SETTINGS := $(PFW_CORE)/support/android/build_pfw_settings.mk
-PFW_DEFAULT_SCHEMAS_DIR := $(PFW_CORE)/upstream/schemas
-PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
-
-TOOLS := frameworks/av/services/audiopolicy/engineconfigurable/tools
-BUILD_PFW_SETTINGS := $(TOOLS)/build_audio_pfw_settings.mk
-
-PROVISION_STRATEGIES_STRUCTURE := $(TOOLS)/provision_strategies_structure.mk
-
-endif
-
-##################################################################
-# CONFIGURATION FILES
-##################################################################
-######### Policy PFW top level file #########
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable caremu_configurable))
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := ParameterFrameworkConfigurationPolicy.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework
-LOCAL_SRC_FILES := $(LOCAL_MODULE).in
-LOCAL_REQUIRED_MODULES := \
- PolicySubsystem.xml \
- PolicyClass.xml
-
-# external/parameter-framework prevents from using debug interface
-AUDIO_PATTERN = @TUNING_ALLOWED@
-ifeq ($(TARGET_BUILD_VARIANT),user)
-AUDIO_VALUE = false
-else
-AUDIO_VALUE = true
-endif
-
-LOCAL_POST_INSTALL_CMD := $(hide) sed -i -e 's|$(AUDIO_PATTERN)|$(AUDIO_VALUE)|g' $(TARGET_OUT_VENDOR_ETC)/$(LOCAL_MODULE_RELATIVE_PATH)/$(LOCAL_MODULE)
-
-include $(BUILD_PREBUILT)
-
-########## Policy PFW Common Structures #########
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := PolicySubsystem.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_REQUIRED_MODULES := \
- PolicySubsystem-CommonTypes.xml \
- ProductStrategies.xml
-
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
-LOCAL_SRC_FILES := common/Structure/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := PolicySubsystem-CommonTypes.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
-LOCAL_SRC_FILES := common/Structure/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := PolicyClass.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
-LOCAL_SRC_FILES := common/Structure/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := ProductStrategies.xml
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
-
-AUDIO_POLICY_ENGINE_CONFIGURATION_FILE := \
- $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_configuration.xml
-STRATEGIES_STRUCTURE_FILE := $(LOCAL_PATH)/common/Structure/$(LOCAL_MODULE).in
-
-include $(PROVISION_STRATEGIES_STRUCTURE)
-
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable caremu_configurable))
-
-########## Policy PFW Example Structures #########
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),no-output_configurable no-input_configurable))
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := PolicySubsystem.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_REQUIRED_MODULES := PolicySubsystem-CommonTypes.xml
-
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
-LOCAL_SRC_FILES := common/Structure/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := ParameterFrameworkConfigurationPolicy-no-strategy.xml
-LOCAL_MODULE_STEM := ParameterFrameworkConfigurationPolicy.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework
-LOCAL_SRC_FILES := $(LOCAL_MODULE).in
-LOCAL_REQUIRED_MODULES := \
- PolicySubsystem.xml \
- PolicyClass.xml
-AUDIO_VALUE = false
-LOCAL_POST_INSTALL_CMD := $(hide) sed -i -e 's|$(AUDIO_PATTERN)|$(AUDIO_VALUE)|g' $(TARGET_OUT_VENDOR_ETC)/$(LOCAL_MODULE_RELATIVE_PATH)/$(LOCAL_MODULE)
-
-include $(BUILD_PREBUILT)
-
-endif # ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),no-output_configurable no-input_configurable))
-
-######### Policy PFW Settings - No Output #########
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),no-output_configurable)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := parameter-framework.policy
-LOCAL_MODULE_STEM := PolicyConfigurableDomains-NoOutputDevice.xml
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Settings/Policy
-
-PFW_TOPLEVEL_FILE := $(TARGET_OUT_VENDOR_ETC)/parameter-framework/ParameterFrameworkConfigurationPolicy.xml
-PFW_CRITERION_TYPES_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criterion_types.xml
-PFW_CRITERIA_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criteria.xml
-PFW_EDD_FILES := \
- $(LOCAL_PATH)/SettingsNoOutput/device_for_strategies.pfw \
- $(LOCAL_PATH)/Settings/device_for_input_source.pfw \
- $(LOCAL_PATH)/Settings/volumes.pfw
-LOCAL_REQUIRED_MODULES := libpolicy-subsystem
-include $(BUILD_PFW_SETTINGS)
-
-endif # ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),no-output_configurable)
-######### Policy PFW Settings - No Input #########
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),no-input_configurable)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := parameter-framework.policy
-LOCAL_MODULE_STEM := PolicyConfigurableDomains-NoInputDevice.xml
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Settings/Policy
-
-PFW_TOPLEVEL_FILE := $(TARGET_OUT_VENDOR_ETC)/parameter-framework/ParameterFrameworkConfigurationPolicy.xml
-PFW_CRITERION_TYPES_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criterion_types.xml
-PFW_CRITERIA_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criteria.xml
-PFW_EDD_FILES := \
- $(LOCAL_PATH)/SettingsNoInput/device_for_input_source.pfw \
- $(LOCAL_PATH)/Settings/volumes.pfw
-LOCAL_REQUIRED_MODULES := libpolicy-subsystem
-include $(BUILD_PFW_SETTINGS)
-
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),no-input_configurable)
-#######################################################################
-# Recursive call sub-folder Android.mk
-#######################################################################
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
-
-endif #ifdef BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION
-
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.bp
new file mode 100644
index 0000000..82b1b6d
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.bp
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+// Import this namespace in order to use AOSP Automotive configuration example
+
+soong_namespace {
+ imports: [
+ "frameworks/av/services/audiopolicy/engineconfigurable/config/example/automotive",
+ "frameworks/av/services/audiopolicy/config",
+ ],
+}
+
+//
+// Generate Audio Policy Parameter Framework Product Strategies Structure file from template
+//
+prebuilt_etc {
+ name: "ProductStrategies.xml",
+ vendor: true,
+ src: ":buildstrategiesstructure_gen",
+ sub_dir: "parameter-framework/Structure/Policy",
+ required: ["libpolicy-subsystem"],
+}
+genrule {
+ name: "buildstrategiesstructure_gen",
+ defaults: ["buildstrategiesstructurerule"],
+ srcs: [
+ ":audio_policy_engine_configuration_files",
+ ],
+}
+
+//
+// Generate Audio Policy Parameter Framework Configurable Domains
+//
+prebuilt_etc {
+ name: "parameter-framework.policy",
+ filename_from_src: true,
+ vendor: true,
+ src: ":domaingeneratorpolicyrule_gen",
+ sub_dir: "parameter-framework/Settings/Policy",
+ required: [
+ "ProductStrategies.xml",
+ "PolicyClass.xml",
+ "PolicySubsystem.xml",
+ "PolicySubsystem-CommonTypes.xml",
+ ],
+}
+genrule {
+ name: "domaingeneratorpolicyrule_gen",
+ defaults: ["domaingeneratorpolicyrule"],
+ srcs: [
+ ":audio_policy_pfw_toplevel",
+ ":audio_policy_pfw_structure_files",
+ ":audio_policy_engine_criterion_types",
+ ":edd_files",
+ ],
+}
+filegroup {
+ name: "edd_files",
+ srcs: [
+ ":device_for_input_source.pfw",
+ ":volumes.pfw",
+ "Settings/device_for_product_strategies.pfw",
+ ],
+}
+// This is for Settings generation, must use socket port, so userdebug version is required
+filegroup {
+ name: "audio_policy_pfw_toplevel",
+ srcs: [":ParameterFrameworkConfigurationPolicy.userdebug.xml"],
+}
+filegroup {
+ name: "audio_policy_pfw_structure_files",
+ srcs: [
+ ":PolicyClass",
+ ":PolicySubsystem",
+ ":buildcommontypesstructure_gen",
+ ":buildstrategiesstructure_gen",
+ ],
+}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.mk
deleted file mode 100644
index 7304ec2..0000000
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.mk
+++ /dev/null
@@ -1,47 +0,0 @@
-################################################################################################
-#
-# @NOTE:
-# Audio Policy Engine configurable example for generic device build
-#
-# Any vendor shall have its own configuration within the corresponding device folder
-#
-################################################################################################
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), automotive_configurable)
-LOCAL_PATH := $(call my-dir)
-
-PFW_CORE := external/parameter-framework
-PFW_DEFAULT_SCHEMAS_DIR := $(PFW_CORE)/upstream/schemas
-PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
-
-TOOLS := frameworks/av/services/audiopolicy/engineconfigurable/tools
-BUILD_PFW_SETTINGS := $(TOOLS)/build_audio_pfw_settings.mk
-
-
-##################################################################
-# CONFIGURATION FILES
-##################################################################
-
-########## Policy PFW Structures #########
-######### Policy PFW Settings #########
-include $(CLEAR_VARS)
-LOCAL_MODULE := parameter-framework.policy
-LOCAL_MODULE_STEM := PolicyConfigurableDomains.xml
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Settings/Policy
-LOCAL_REQUIRED_MODULES := libpolicy-subsystem
-
-PFW_EDD_FILES := \
- $(LOCAL_PATH)/Settings/device_for_product_strategies.pfw \
- $(LOCAL_PATH)/../Settings/device_for_input_source.pfw \
- $(LOCAL_PATH)/../Settings/volumes.pfw
-
-PFW_CRITERION_TYPES_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criterion_types.xml
-PFW_CRITERIA_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criteria.xml
-PFW_TOPLEVEL_FILE := $(TARGET_OUT_VENDOR_ETC)/parameter-framework/ParameterFrameworkConfigurationPolicy.xml
-PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
-
-include $(BUILD_PFW_SETTINGS)
-
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), automotive_configurable)
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Settings/device_for_product_strategies.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Settings/device_for_product_strategies.pfw
index 57ad592..ddae356 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Settings/device_for_product_strategies.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Settings/device_for_product_strategies.pfw
@@ -14,7 +14,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -59,7 +59,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -106,7 +106,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -152,7 +152,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -205,7 +205,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -251,7 +251,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -304,7 +304,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -357,7 +357,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -411,7 +411,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -464,7 +464,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -517,7 +517,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -570,7 +570,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -623,7 +623,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -676,7 +676,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -729,7 +729,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.bp
new file mode 100644
index 0000000..e4605b2
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.bp
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+// Import this namespace in order to use AOSP Car Emulator configuration example
+
+soong_namespace {
+ imports: [
+ "frameworks/av/services/audiopolicy/engineconfigurable/config/example/caremu",
+ "frameworks/av/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car",
+ "frameworks/av/services/audiopolicy/config",
+ ],
+}
+
+//
+// Generate Audio Policy Parameter Framework Product Strategies Structure file from template
+//
+prebuilt_etc {
+ name: "ProductStrategies.xml",
+ vendor: true,
+ src: ":buildstrategiesstructure_gen",
+ sub_dir: "parameter-framework/Structure/Policy",
+ required: ["libpolicy-subsystem"],
+}
+genrule {
+ name: "buildstrategiesstructure_gen",
+ defaults: ["buildstrategiesstructurerule"],
+ srcs: [
+ ":audio_policy_engine_configuration_files",
+ ],
+}
+
+//
+// Generate Audio Policy Parameter Framework Configurable Domains
+//
+prebuilt_etc {
+ name: "parameter-framework.policy",
+ filename_from_src: true,
+ vendor: true,
+ src: ":domaingeneratorpolicyrule_gen",
+ sub_dir: "parameter-framework/Settings/Policy",
+ required: [
+ "ProductStrategies.xml",
+ "PolicyClass.xml",
+ "PolicySubsystem.xml",
+ "PolicySubsystem-CommonTypes.xml",
+ ],
+}
+genrule {
+ name: "domaingeneratorpolicyrule_gen",
+ defaults: ["domaingeneratorpolicyrule"],
+ srcs: [
+ ":audio_policy_pfw_toplevel",
+ ":audio_policy_pfw_structure_files",
+ ":audio_policy_engine_criterion_types",
+ ":edd_files",
+ ],
+}
+filegroup {
+ name: "edd_files",
+ srcs: [
+ ":device_for_input_source.pfw",
+ ":volumes.pfw",
+ "Settings/device_for_product_strategies.pfw",
+ ],
+}
+// This is for Settings generation, must use socket port, so userdebug version is required
+filegroup {
+ name: "audio_policy_pfw_toplevel",
+ srcs: [":ParameterFrameworkConfigurationPolicy.userdebug.xml"],
+}
+filegroup {
+ name: "audio_policy_pfw_structure_files",
+ srcs: [
+ ":PolicyClass",
+ ":PolicySubsystem",
+ ":buildcommontypesstructure_gen",
+ ":buildstrategiesstructure_gen",
+ ],
+}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.mk
deleted file mode 100644
index f5eb7d1..0000000
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.mk
+++ /dev/null
@@ -1,46 +0,0 @@
-################################################################################################
-#
-# @NOTE:
-# Audio Policy Engine configurable example for generic device build
-#
-# Any vendor shall have its own configuration within the corresponding device folder
-#
-################################################################################################
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), caremu_configurable)
-LOCAL_PATH := $(call my-dir)
-
-PFW_CORE := external/parameter-framework
-PFW_DEFAULT_SCHEMAS_DIR := $(PFW_CORE)/upstream/schemas
-PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
-
-TOOLS := frameworks/av/services/audiopolicy/engineconfigurable/tools
-BUILD_PFW_SETTINGS := $(TOOLS)/build_audio_pfw_settings.mk
-
-
-##################################################################
-# CONFIGURATION FILES
-##################################################################
-
-########## Policy PFW Structures #########
-######### Policy PFW Settings #########
-include $(CLEAR_VARS)
-LOCAL_MODULE := parameter-framework.policy
-LOCAL_MODULE_STEM := PolicyConfigurableDomains.xml
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Settings/Policy
-LOCAL_REQUIRED_MODULES := libpolicy-subsystem
-
-PFW_EDD_FILES := \
- $(LOCAL_PATH)/Settings/device_for_product_strategies.pfw \
- $(LOCAL_PATH)/../Settings/device_for_input_source.pfw \
- $(LOCAL_PATH)/../Settings/volumes.pfw
-PFW_CRITERION_TYPES_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criterion_types.xml
-PFW_CRITERIA_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criteria.xml
-PFW_TOPLEVEL_FILE := $(TARGET_OUT_VENDOR_ETC)/parameter-framework/ParameterFrameworkConfigurationPolicy.xml
-PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
-
-include $(BUILD_PFW_SETTINGS)
-
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), caremu_configurable)
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Settings/device_for_product_strategies.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Settings/device_for_product_strategies.pfw
index ca3464f..cc778df 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Settings/device_for_product_strategies.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Settings/device_for_product_strategies.pfw
@@ -14,7 +14,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -59,7 +59,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -106,7 +106,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -153,7 +153,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -198,7 +198,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -245,7 +245,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -291,7 +291,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -337,7 +337,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -384,7 +384,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -430,7 +430,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -476,7 +476,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -522,7 +522,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -568,7 +568,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -614,7 +614,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -659,7 +659,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.user.xml b/services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.user.xml
new file mode 100644
index 0000000..c5960cb
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.user.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ParameterFrameworkConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ SystemClassName="Policy" TuningAllowed="false">
+
+ <SubsystemPlugins>
+ <Location Folder="">
+ <Plugin Name="libpolicy-subsystem.so"/>
+ </Location>
+ </SubsystemPlugins>
+ <StructureDescriptionFileLocation Path="Structure/Policy/PolicyClass.xml"/>
+ <SettingsConfiguration>
+ <ConfigurableDomainsFileLocation Path="Settings/Policy/PolicyConfigurableDomains.xml"/>
+ </SettingsConfiguration>
+</ParameterFrameworkConfiguration>
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.userdebug.xml b/services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.userdebug.xml
new file mode 100644
index 0000000..1b7d7d8
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.userdebug.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ParameterFrameworkConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ SystemClassName="Policy" ServerPort="unix:///dev/socket/audioserver/policy_debug"
+ TuningAllowed="true">
+
+ <SubsystemPlugins>
+ <Location Folder="">
+ <Plugin Name="libpolicy-subsystem.so"/>
+ </Location>
+ </SubsystemPlugins>
+ <StructureDescriptionFileLocation Path="Structure/Policy/PolicyClass.xml"/>
+ <SettingsConfiguration>
+ <ConfigurableDomainsFileLocation Path="Settings/Policy/PolicyConfigurableDomains.xml"/>
+ </SettingsConfiguration>
+</ParameterFrameworkConfiguration>
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.xml.in b/services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.xml.in
deleted file mode 100644
index 1be67dd..0000000
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.xml.in
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ParameterFrameworkConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- SystemClassName="Policy" ServerPort="unix:///dev/socket/audioserver/policy_debug"
- TuningAllowed="@TUNING_ALLOWED@">
-
- <SubsystemPlugins>
- <Location Folder="">
- <Plugin Name="libpolicy-subsystem.so"/>
- </Location>
- </SubsystemPlugins>
- <StructureDescriptionFileLocation Path="Structure/Policy/PolicyClass.xml"/>
- <SettingsConfiguration>
- <ConfigurableDomainsFileLocation Path="Settings/Policy/PolicyConfigurableDomains.xml"/>
- </SettingsConfiguration>
-</ParameterFrameworkConfiguration>
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.bp
new file mode 100644
index 0000000..61b54cf
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.bp
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+// Import this namespace in order to use AOSP Phone configuration example
+
+soong_namespace {
+ imports: [
+ "frameworks/av/services/audiopolicy/engineconfigurable/config/example/phone",
+ "frameworks/av/services/audiopolicy/config",
+ ],
+}
+
+//
+// Generate Audio Policy Parameter Framework Product Strategies Structure file from template
+//
+prebuilt_etc {
+ name: "ProductStrategies.xml",
+ vendor: true,
+ src: ":buildstrategiesstructure_gen",
+ sub_dir: "parameter-framework/Structure/Policy",
+ required: ["libpolicy-subsystem"],
+}
+genrule {
+ name: "buildstrategiesstructure_gen",
+ defaults: ["buildstrategiesstructurerule"],
+ srcs: [
+ ":audio_policy_engine_configuration_files",
+ ],
+}
+
+//
+// Generate Audio Policy Parameter Framework Configurable Domains
+//
+prebuilt_etc {
+ name: "parameter-framework.policy",
+ filename_from_src: true,
+ vendor: true,
+ src: ":domaingeneratorpolicyrule_gen",
+ sub_dir: "parameter-framework/Settings/Policy",
+ required: [
+ "ProductStrategies.xml",
+ "PolicyClass.xml",
+ "PolicySubsystem.xml",
+ "PolicySubsystem-CommonTypes.xml",
+ ],
+}
+genrule {
+ name: "domaingeneratorpolicyrule_gen",
+ defaults: ["domaingeneratorpolicyrule"],
+ srcs: [
+ ":audio_policy_pfw_toplevel",
+ ":audio_policy_pfw_structure_files",
+ ":audio_policy_engine_criterion_types",
+ ":edd_files",
+ ],
+}
+filegroup {
+ name: "edd_files",
+ srcs: [
+ ":device_for_input_source.pfw",
+ ":volumes.pfw",
+ "Settings/device_for_product_strategy_media.pfw",
+ "Settings/device_for_product_strategy_accessibility.pfw",
+ "Settings/device_for_product_strategy_dtmf.pfw",
+ "Settings/device_for_product_strategy_enforced_audible.pfw",
+ "Settings/device_for_product_strategy_phone.pfw",
+ "Settings/device_for_product_strategy_sonification.pfw",
+ "Settings/device_for_product_strategy_sonification_respectful.pfw",
+ "Settings/device_for_product_strategy_transmitted_through_speaker.pfw",
+ "Settings/device_for_product_strategy_rerouting.pfw",
+ "Settings/device_for_product_strategy_patch.pfw",
+ ],
+}
+// This is for Settings generation, must use socket port, so userdebug version is required
+filegroup {
+ name: "audio_policy_pfw_toplevel",
+ srcs: [":ParameterFrameworkConfigurationPolicy.userdebug.xml"],
+}
+filegroup {
+ name: "audio_policy_pfw_structure_files",
+ srcs: [
+ ":PolicyClass",
+ ":PolicySubsystem",
+ ":buildcommontypesstructure_gen",
+ ":buildstrategiesstructure_gen",
+ ],
+}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.mk
deleted file mode 100644
index 0b20781..0000000
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.mk
+++ /dev/null
@@ -1,54 +0,0 @@
-################################################################################################
-#
-# @NOTE:
-# Audio Policy Engine configurable example for generic device build
-#
-# Any vendor shall have its own configuration within the corresponding device folder
-#
-################################################################################################
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), phone_configurable)
-
-LOCAL_PATH := $(call my-dir)
-
-PFW_CORE := external/parameter-framework
-PFW_DEFAULT_SCHEMAS_DIR := $(PFW_CORE)/upstream/schemas
-PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
-
-TOOLS := frameworks/av/services/audiopolicy/engineconfigurable/tools
-BUILD_PFW_SETTINGS := $(TOOLS)/build_audio_pfw_settings.mk
-
-##################################################################
-# CONFIGURATION FILES
-##################################################################
-########## Policy PFW Structures #########
-######### Policy PFW Settings #########
-include $(CLEAR_VARS)
-LOCAL_MODULE := parameter-framework.policy
-LOCAL_MODULE_STEM := PolicyConfigurableDomains.xml
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Settings/Policy
-LOCAL_REQUIRED_MODULES := libpolicy-subsystem
-
-PFW_EDD_FILES := \
- $(LOCAL_PATH)/../Settings/device_for_input_source.pfw \
- $(LOCAL_PATH)/../Settings/volumes.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_media.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_accessibility.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_dtmf.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_enforced_audible.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_phone.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_sonification.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_sonification_respectful.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_transmitted_through_speaker.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_rerouting.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_patch.pfw
-PFW_CRITERION_TYPES_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criterion_types.xml
-PFW_CRITERIA_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criteria.xml
-PFW_TOPLEVEL_FILE := $(TARGET_OUT_VENDOR_ETC)/parameter-framework/ParameterFrameworkConfigurationPolicy.xml
-PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
-
-include $(BUILD_PFW_SETTINGS)
-
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), phone_configurable)
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_accessibility.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_accessibility.pfw
index 53e93de..d16a904 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_accessibility.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_accessibility.pfw
@@ -45,7 +45,7 @@
wired_headset = 0
wired_headphone = 0
line = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -73,7 +73,7 @@
wired_headset = 0
wired_headphone = 0
line = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -101,7 +101,7 @@
wired_headset = 0
wired_headphone = 0
line = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -129,7 +129,7 @@
wired_headset = 0
wired_headphone = 0
line = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -157,7 +157,7 @@
wired_headset = 0
wired_headphone = 0
line = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -186,7 +186,7 @@
wired_headset = 0
wired_headphone = 0
line = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -215,7 +215,7 @@
wired_headset = 0
wired_headphone = 0
line = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -244,7 +244,7 @@
wired_headset = 0
wired_headphone = 0
line = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -281,7 +281,7 @@
wired_headset = 0
wired_headphone = 1
line = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -317,7 +317,7 @@
wired_headset = 0
wired_headphone = 0
line = 1
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -354,7 +354,7 @@
wired_headset = 1
wired_headphone = 0
line = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -394,7 +394,7 @@
wired_headset = 0
wired_headphone = 0
line = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 1
@@ -425,7 +425,7 @@
wired_headset = 0
wired_headphone = 0
line = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 1
usb_device = 0
@@ -455,7 +455,7 @@
wired_headset = 0
wired_headphone = 0
line = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 1
usb_accessory = 0
usb_device = 0
@@ -485,7 +485,7 @@
wired_headset = 0
wired_headphone = 0
line = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -517,7 +517,7 @@
wired_headset = 0
wired_headphone = 0
line = 0
- angl_dock_headset = 1
+ anlg_dock_headset = 1
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -546,7 +546,7 @@
wired_headset = 0
wired_headphone = 0
line = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -568,7 +568,7 @@
wired_headset = 0
wired_headphone = 0
line = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -588,7 +588,7 @@
wired_headset = 0
wired_headphone = 0
line = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_dtmf.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_dtmf.pfw
index b8426c6..414445d 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_dtmf.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_dtmf.pfw
@@ -34,7 +34,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -62,7 +62,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -90,7 +90,7 @@
bluetooth_a2dp_headphones = 1
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -118,7 +118,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 1
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -147,7 +147,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -176,7 +176,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -205,7 +205,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -242,7 +242,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -281,7 +281,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -318,7 +318,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -358,7 +358,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 1
@@ -389,7 +389,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 1
usb_device = 0
@@ -419,7 +419,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 1
usb_accessory = 0
usb_device = 0
@@ -449,7 +449,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 1
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -481,7 +481,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 1
+ anlg_dock_headset = 1
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -510,7 +510,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -548,7 +548,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -568,7 +568,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_enforced_audible.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_enforced_audible.pfw
index 2daa9ac..36b8f3c 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_enforced_audible.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_enforced_audible.pfw
@@ -77,7 +77,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -100,7 +100,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -123,7 +123,7 @@
bluetooth_a2dp_headphones = 1
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -146,7 +146,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 1
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -169,7 +169,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -192,7 +192,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -215,7 +215,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -238,7 +238,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 1
usb_device = 0
@@ -261,7 +261,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 1
@@ -284,7 +284,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 1
usb_accessory = 0
usb_device = 0
@@ -307,7 +307,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 1
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -331,7 +331,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 1
+ anlg_dock_headset = 1
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -351,7 +351,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_media.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_media.pfw
index d6d355c..6210a57 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_media.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_media.pfw
@@ -26,7 +26,7 @@
speaker = 0
hdmi = 0
dgtl_dock_headset = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
usb_device = 0
usb_accessory = 0
wired_headset = 0
@@ -46,7 +46,7 @@
speaker = 0
hdmi = 0
dgtl_dock_headset = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
usb_device = 0
usb_accessory = 0
wired_headset = 0
@@ -66,7 +66,7 @@
speaker = 0
hdmi = 0
dgtl_dock_headset = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
usb_device = 0
usb_accessory = 0
wired_headset = 0
@@ -86,7 +86,7 @@
speaker = 0
hdmi = 0
dgtl_dock_headset = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
usb_device = 0
usb_accessory = 0
wired_headset = 0
@@ -109,7 +109,7 @@
speaker = 1
hdmi = 0
dgtl_dock_headset = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
usb_device = 0
usb_accessory = 0
wired_headset = 0
@@ -127,7 +127,7 @@
speaker = 0
hdmi = 0
dgtl_dock_headset = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
usb_device = 0
usb_accessory = 0
wired_headset = 0
@@ -145,7 +145,7 @@
speaker = 0
hdmi = 0
dgtl_dock_headset = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
usb_device = 0
usb_accessory = 0
wired_headset = 0
@@ -163,7 +163,7 @@
speaker = 0
hdmi = 0
dgtl_dock_headset = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
usb_device = 0
usb_accessory = 0
wired_headset = 1
@@ -181,7 +181,7 @@
speaker = 0
hdmi = 0
dgtl_dock_headset = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
usb_device = 0
usb_accessory = 1
wired_headset = 0
@@ -199,7 +199,7 @@
speaker = 0
hdmi = 0
dgtl_dock_headset = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
usb_device = 1
usb_accessory = 0
wired_headset = 0
@@ -217,7 +217,7 @@
speaker = 0
hdmi = 0
dgtl_dock_headset = 1
- angl_dock_headset = 0
+ anlg_dock_headset = 0
usb_device = 0
usb_accessory = 0
wired_headset = 0
@@ -235,7 +235,7 @@
speaker = 0
hdmi = 1
dgtl_dock_headset = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
usb_device = 0
usb_accessory = 0
wired_headset = 0
@@ -254,7 +254,7 @@
speaker = 0
hdmi = 0
dgtl_dock_headset = 0
- angl_dock_headset = 1
+ anlg_dock_headset = 1
usb_device = 0
usb_accessory = 0
wired_headset = 0
@@ -277,7 +277,7 @@
speaker = 1
hdmi = 0
dgtl_dock_headset = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
usb_device = 0
usb_accessory = 0
wired_headset = 0
@@ -293,7 +293,7 @@
speaker = 0
hdmi = 0
dgtl_dock_headset = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
usb_device = 0
usb_accessory = 0
wired_headset = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_patch.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_patch.pfw
index d2cc090..feeeec6 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_patch.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_patch.pfw
@@ -14,7 +14,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_phone.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_phone.pfw
index 5693d4e..da2fc9b 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_phone.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_phone.pfw
@@ -32,7 +32,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -55,7 +55,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -78,7 +78,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -108,7 +108,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -138,7 +138,7 @@
bluetooth_a2dp_headphones = 1
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -168,7 +168,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 1
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -195,7 +195,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -222,7 +222,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -245,7 +245,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -283,7 +283,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 1
@@ -311,7 +311,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 1
@@ -339,7 +339,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 1
usb_accessory = 0
usb_device = 0
@@ -367,7 +367,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 1
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -395,7 +395,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 1
+ anlg_dock_headset = 1
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -422,7 +422,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -449,7 +449,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -472,7 +472,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_rerouting.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_rerouting.pfw
index 10f8814..3275cdf 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_rerouting.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_rerouting.pfw
@@ -14,7 +14,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_sonification.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_sonification.pfw
index c4edeeb..a60445b 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_sonification.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_sonification.pfw
@@ -69,7 +69,7 @@
bluetooth_a2dp = 1
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -95,7 +95,7 @@
bluetooth_a2dp = 0
bluetooth_a2dp_headphones = 1
bluetooth_a2dp_speaker = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -121,7 +121,7 @@
bluetooth_a2dp = 0
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 1
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -148,7 +148,7 @@
bluetooth_a2dp = 0
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -175,7 +175,7 @@
bluetooth_a2dp = 0
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -202,7 +202,7 @@
bluetooth_a2dp = 0
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -238,7 +238,7 @@
bluetooth_a2dp = 0
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -276,7 +276,7 @@
bluetooth_a2dp = 0
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -312,7 +312,7 @@
bluetooth_a2dp = 0
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -349,7 +349,7 @@
bluetooth_a2dp = 0
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 1
@@ -378,7 +378,7 @@
bluetooth_a2dp = 0
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 1
usb_device = 0
@@ -407,7 +407,7 @@
bluetooth_a2dp = 0
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 1
usb_accessory = 0
usb_device = 0
@@ -437,7 +437,7 @@
bluetooth_a2dp = 0
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
- angl_dock_headset = 1
+ anlg_dock_headset = 1
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -464,7 +464,7 @@
bluetooth_a2dp = 0
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -482,7 +482,7 @@
bluetooth_a2dp = 0
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_sonification_respectful.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_sonification_respectful.pfw
index 0a3dd5f..6b11e23 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_sonification_respectful.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_sonification_respectful.pfw
@@ -92,7 +92,7 @@
wired_headset = 0
wired_headphone = 0
line = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -119,7 +119,7 @@
wired_headset = 0
wired_headphone = 0
line = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -146,7 +146,7 @@
wired_headset = 0
wired_headphone = 0
line = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -173,7 +173,7 @@
wired_headset = 0
wired_headphone = 0
line = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -200,7 +200,7 @@
wired_headset = 0
wired_headphone = 0
line = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -227,7 +227,7 @@
wired_headset = 0
wired_headphone = 0
line = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -264,7 +264,7 @@
wired_headset = 0
wired_headphone = 1
line = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -305,7 +305,7 @@
wired_headset = 0
wired_headphone = 0
line = 1
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -342,7 +342,7 @@
wired_headset = 1
wired_headphone = 0
line = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -380,7 +380,7 @@
wired_headset = 0
wired_headphone = 0
line = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 1
@@ -410,7 +410,7 @@
wired_headset = 0
wired_headphone = 0
line = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 1
usb_device = 0
@@ -440,7 +440,7 @@
wired_headset = 0
wired_headphone = 0
line = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 1
usb_accessory = 0
usb_device = 0
@@ -470,7 +470,7 @@
wired_headset = 0
wired_headphone = 0
line = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -501,7 +501,7 @@
wired_headset = 0
wired_headphone = 0
line = 0
- angl_dock_headset = 1
+ anlg_dock_headset = 1
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -528,7 +528,7 @@
wired_headset = 0
wired_headphone = 0
line = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_transmitted_through_speaker.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_transmitted_through_speaker.pfw
index 3fc7670..418f3cc 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_transmitted_through_speaker.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_transmitted_through_speaker.pfw
@@ -19,7 +19,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/PolicyConfigurableDomains.xml b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/PolicyConfigurableDomains.xml
index 0710441..baffa81 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/PolicyConfigurableDomains.xml
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/PolicyConfigurableDomains.xml
@@ -145,7 +145,7 @@
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/speaker"/>
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/hdmi"/>
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset"/>
- <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset"/>
+ <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset"/>
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device"/>
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_accessory"/>
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/wired_headset"/>
@@ -167,8 +167,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device">
<BitParameter Name="usb_device">0</BitParameter>
@@ -208,8 +208,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device">
<BitParameter Name="usb_device">0</BitParameter>
@@ -249,8 +249,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device">
<BitParameter Name="usb_device">0</BitParameter>
@@ -290,8 +290,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device">
<BitParameter Name="usb_device">0</BitParameter>
@@ -331,8 +331,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device">
<BitParameter Name="usb_device">0</BitParameter>
@@ -372,8 +372,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device">
<BitParameter Name="usb_device">0</BitParameter>
@@ -413,8 +413,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device">
<BitParameter Name="usb_device">0</BitParameter>
@@ -454,8 +454,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device">
<BitParameter Name="usb_device">0</BitParameter>
@@ -495,8 +495,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device">
<BitParameter Name="usb_device">0</BitParameter>
@@ -536,8 +536,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device">
<BitParameter Name="usb_device">1</BitParameter>
@@ -577,8 +577,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">1</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device">
<BitParameter Name="usb_device">0</BitParameter>
@@ -618,8 +618,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device">
<BitParameter Name="usb_device">0</BitParameter>
@@ -659,8 +659,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">1</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">1</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device">
<BitParameter Name="usb_device">0</BitParameter>
@@ -700,8 +700,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device">
<BitParameter Name="usb_device">0</BitParameter>
@@ -741,8 +741,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device">
<BitParameter Name="usb_device">0</BitParameter>
@@ -1039,7 +1039,7 @@
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/bluetooth_a2dp_headphones"/>
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/bluetooth_a2dp_speaker"/>
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi"/>
- <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset"/>
+ <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset"/>
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset"/>
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/usb_accessory"/>
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/usb_device"/>
@@ -1079,8 +1079,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -1132,8 +1132,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -1185,8 +1185,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -1238,8 +1238,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -1291,8 +1291,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -1344,8 +1344,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -1397,8 +1397,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -1450,8 +1450,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -1503,8 +1503,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -1556,8 +1556,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -1609,8 +1609,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -1662,8 +1662,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">1</BitParameter>
@@ -1715,8 +1715,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">1</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -1768,8 +1768,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">1</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">1</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -1821,8 +1821,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -1874,8 +1874,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -1927,8 +1927,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -2228,7 +2228,7 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp"/>
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_headphones"/>
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker"/>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset"/>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset"/>
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset"/>
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/usb_accessory"/>
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/usb_device"/>
@@ -2264,8 +2264,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker">
<BitParameter Name="bluetooth_a2dp_speaker">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -2311,8 +2311,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker">
<BitParameter Name="bluetooth_a2dp_speaker">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -2358,8 +2358,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker">
<BitParameter Name="bluetooth_a2dp_speaker">1</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -2405,8 +2405,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker">
<BitParameter Name="bluetooth_a2dp_speaker">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -2452,8 +2452,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker">
<BitParameter Name="bluetooth_a2dp_speaker">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -2499,8 +2499,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker">
<BitParameter Name="bluetooth_a2dp_speaker">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -2546,8 +2546,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker">
<BitParameter Name="bluetooth_a2dp_speaker">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -2593,8 +2593,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker">
<BitParameter Name="bluetooth_a2dp_speaker">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -2640,8 +2640,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker">
<BitParameter Name="bluetooth_a2dp_speaker">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -2687,8 +2687,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker">
<BitParameter Name="bluetooth_a2dp_speaker">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -2734,8 +2734,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker">
<BitParameter Name="bluetooth_a2dp_speaker">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -2781,8 +2781,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker">
<BitParameter Name="bluetooth_a2dp_speaker">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">1</BitParameter>
@@ -2828,8 +2828,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker">
<BitParameter Name="bluetooth_a2dp_speaker">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">1</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">1</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -2875,8 +2875,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker">
<BitParameter Name="bluetooth_a2dp_speaker">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -2922,8 +2922,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker">
<BitParameter Name="bluetooth_a2dp_speaker">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -3246,7 +3246,7 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/wired_headset"/>
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/wired_headphone"/>
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line"/>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset"/>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset"/>
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset"/>
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/usb_accessory"/>
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/usb_device"/>
@@ -3284,8 +3284,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -3331,8 +3331,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -3378,8 +3378,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -3425,8 +3425,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -3472,8 +3472,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -3519,8 +3519,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -3566,8 +3566,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -3613,8 +3613,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line">
<BitParameter Name="line">1</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -3660,8 +3660,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -3707,8 +3707,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -3754,8 +3754,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -3801,8 +3801,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">1</BitParameter>
@@ -3848,8 +3848,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -3895,8 +3895,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">1</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">1</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -3942,8 +3942,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -4207,7 +4207,7 @@
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/bluetooth_a2dp_headphones"/>
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/bluetooth_a2dp_speaker"/>
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi"/>
- <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset"/>
+ <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset"/>
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset"/>
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/usb_accessory"/>
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/usb_device"/>
@@ -4247,8 +4247,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -4300,8 +4300,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -4353,8 +4353,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -4406,8 +4406,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -4459,8 +4459,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -4512,8 +4512,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -4565,8 +4565,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -4618,8 +4618,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -4671,8 +4671,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -4724,8 +4724,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -4777,8 +4777,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -4830,8 +4830,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -4883,8 +4883,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">1</BitParameter>
@@ -4936,8 +4936,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">1</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -4989,8 +4989,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">1</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">1</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -5042,8 +5042,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -5095,8 +5095,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -5148,8 +5148,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -5448,7 +5448,7 @@
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/bluetooth_a2dp_headphones"/>
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/bluetooth_a2dp_speaker"/>
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/hdmi"/>
- <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/angl_dock_headset"/>
+ <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/anlg_dock_headset"/>
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/dgtl_dock_headset"/>
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/usb_accessory"/>
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/usb_device"/>
@@ -5490,8 +5490,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -5543,8 +5543,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -5596,8 +5596,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -5649,8 +5649,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -5702,8 +5702,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -5755,8 +5755,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -5808,8 +5808,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -5861,8 +5861,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -5914,8 +5914,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -5967,8 +5967,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">1</BitParameter>
@@ -6020,8 +6020,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">1</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -6073,8 +6073,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">1</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">1</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -6126,8 +6126,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -6170,7 +6170,7 @@
<ConfigurableElement Path="/Policy/policy/strategies/transmitted_through_speaker/selected_output_devices/mask/bluetooth_a2dp_headphones"/>
<ConfigurableElement Path="/Policy/policy/strategies/transmitted_through_speaker/selected_output_devices/mask/bluetooth_a2dp_speaker"/>
<ConfigurableElement Path="/Policy/policy/strategies/transmitted_through_speaker/selected_output_devices/mask/hdmi"/>
- <ConfigurableElement Path="/Policy/policy/strategies/transmitted_through_speaker/selected_output_devices/mask/angl_dock_headset"/>
+ <ConfigurableElement Path="/Policy/policy/strategies/transmitted_through_speaker/selected_output_devices/mask/anlg_dock_headset"/>
<ConfigurableElement Path="/Policy/policy/strategies/transmitted_through_speaker/selected_output_devices/mask/dgtl_dock_headset"/>
<ConfigurableElement Path="/Policy/policy/strategies/transmitted_through_speaker/selected_output_devices/mask/usb_accessory"/>
<ConfigurableElement Path="/Policy/policy/strategies/transmitted_through_speaker/selected_output_devices/mask/usb_device"/>
@@ -6230,8 +6230,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/transmitted_through_speaker/selected_output_devices/mask/hdmi">
<BitParameter Name="hdmi">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/transmitted_through_speaker/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/transmitted_through_speaker/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/transmitted_through_speaker/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -6539,7 +6539,7 @@
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/wired_headset"/>
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/wired_headphone"/>
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line"/>
- <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset"/>
+ <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset"/>
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset"/>
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/usb_accessory"/>
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/usb_device"/>
@@ -6583,8 +6583,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -6636,8 +6636,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -6689,8 +6689,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -6742,8 +6742,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -6795,8 +6795,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -6848,8 +6848,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -6901,8 +6901,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -6954,8 +6954,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7007,8 +7007,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7060,8 +7060,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
<BitParameter Name="line">1</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7113,8 +7113,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7166,8 +7166,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7219,8 +7219,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7272,8 +7272,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">1</BitParameter>
@@ -7325,8 +7325,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7378,8 +7378,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">1</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">1</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7431,8 +7431,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7484,8 +7484,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7537,8 +7537,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7710,7 +7710,7 @@
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/wired_headset"/>
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/wired_headphone"/>
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line"/>
- <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset"/>
+ <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset"/>
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset"/>
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/usb_accessory"/>
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/usb_device"/>
@@ -7742,8 +7742,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7783,8 +7783,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7824,8 +7824,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7865,8 +7865,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7906,8 +7906,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7947,8 +7947,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7988,8 +7988,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line">
<BitParameter Name="line">1</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -8029,8 +8029,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -8070,8 +8070,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -8111,8 +8111,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -8152,8 +8152,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">1</BitParameter>
@@ -8193,8 +8193,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -8234,8 +8234,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">1</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">1</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -8275,8 +8275,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -8316,8 +8316,8 @@
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line">
<BitParameter Name="line">0</BitParameter>
</ConfigurableElement>
- <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset">
- <BitParameter Name="angl_dock_headset">0</BitParameter>
+ <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset">
+ <BitParameter Name="anlg_dock_headset">0</BitParameter>
</ConfigurableElement>
<ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset">
<BitParameter Name="dgtl_dock_headset">0</BitParameter>
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/device_for_input_source.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/device_for_input_source.pfw
index a990879..9e0957c 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/device_for_input_source.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/device_for_input_source.pfw
@@ -18,7 +18,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/mic/applicable_input_device/mask
communication = 0
ambient = 0
@@ -36,7 +35,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/voice_downlink/applicable_input_device/mask
communication = 0
ambient = 0
@@ -58,7 +56,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/voice_call/applicable_input_device/mask
communication = 0
ambient = 0
@@ -80,7 +77,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/voice_uplink/applicable_input_device/mask
communication = 0
ambient = 0
@@ -102,7 +98,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/camcorder/applicable_input_device/mask
communication = 0
ambient = 0
@@ -123,7 +118,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/voice_recognition/applicable_input_device/mask
communication = 0
ambient = 0
@@ -142,7 +136,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/voice_communication/applicable_input_device/mask
communication = 0
ambient = 0
@@ -160,7 +153,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/remote_submix/applicable_input_device/mask
communication = 0
ambient = 0
@@ -182,7 +174,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/hotword/applicable_input_device/mask
communication = 0
ambient = 0
@@ -201,7 +192,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/unprocessed/applicable_input_device/mask
communication = 0
ambient = 0
@@ -220,7 +210,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/fm_tuner/applicable_input_device/mask
communication = 0
ambient = 0
@@ -242,7 +231,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
domain: DefaultAndMic
conf: A2dp
@@ -255,12 +243,14 @@
usb_device = 0
builtin_mic = 0
bluetooth_sco_headset = 0
+ stub = 0
component: mic/applicable_input_device/mask/
bluetooth_a2dp = 1
wired_headset = 0
usb_device = 0
builtin_mic = 0
bluetooth_sco_headset = 0
+ stub = 0
conf: Sco
AvailableInputDevices Includes BluetoothScoHeadset
@@ -273,12 +263,14 @@
usb_device = 0
builtin_mic = 0
bluetooth_sco_headset = 1
+ stub = 0
component: mic/applicable_input_device/mask/
bluetooth_a2dp = 0
wired_headset = 0
usb_device = 0
builtin_mic = 0
bluetooth_sco_headset = 1
+ stub = 0
conf: WiredHeadset
AvailableInputDevices Includes WiredHeadset
@@ -290,12 +282,14 @@
usb_device = 0
builtin_mic = 0
bluetooth_sco_headset = 0
+ stub = 0
component: mic/applicable_input_device/mask/
bluetooth_a2dp = 0
wired_headset = 1
usb_device = 0
builtin_mic = 0
bluetooth_sco_headset = 0
+ stub = 0
conf: UsbDevice
AvailableInputDevices Includes UsbDevice
@@ -307,12 +301,14 @@
usb_device = 1
builtin_mic = 0
bluetooth_sco_headset = 0
+ stub = 0
component: mic/applicable_input_device/mask/
bluetooth_a2dp = 0
wired_headset = 0
usb_device = 1
builtin_mic = 0
bluetooth_sco_headset = 0
+ stub = 0
conf: BuiltinMic
AvailableInputDevices Includes BuiltinMic
@@ -324,12 +320,33 @@
usb_device = 0
builtin_mic = 1
bluetooth_sco_headset = 0
+ stub = 0
component: mic/applicable_input_device/mask/
bluetooth_a2dp = 0
wired_headset = 0
usb_device = 0
builtin_mic = 1
bluetooth_sco_headset = 0
+ stub = 0
+
+ conf: Stub
+ AvailableInputDevices Includes Default
+
+ component: /Policy/policy/input_sources
+ component: default/applicable_input_device/mask/
+ bluetooth_a2dp = 0
+ wired_headset = 0
+ usb_device = 0
+ builtin_mic = 0
+ bluetooth_sco_headset = 0
+ stub = 1
+ component: mic/applicable_input_device/mask/
+ bluetooth_a2dp = 0
+ wired_headset = 0
+ usb_device = 0
+ builtin_mic = 0
+ bluetooth_sco_headset = 0
+ stub = 1
conf: Default
component: /Policy/policy/input_sources
@@ -339,12 +356,14 @@
usb_device = 0
builtin_mic = 0
bluetooth_sco_headset = 0
+ stub = 0
component: mic/applicable_input_device/mask/
bluetooth_a2dp = 0
wired_headset = 0
usb_device = 0
builtin_mic = 0
bluetooth_sco_headset = 0
+ stub = 0
domain: VoiceUplinkAndVoiceDownlinkAndVoiceCall
conf: VoiceCall
@@ -354,12 +373,29 @@
voice_downlink/applicable_input_device/mask/telephony_rx = 1
voice_call/applicable_input_device/mask/telephony_rx = 1
voice_uplink/applicable_input_device/mask/telephony_rx = 1
+ voice_downlink/applicable_input_device/mask/stub = 0
+ voice_call/applicable_input_device/mask/stub = 0
+ voice_uplink/applicable_input_device/mask/stub = 0
+
+ conf: Stub
+ AvailableInputDevices Includes Default
+
+ component: /Policy/policy/input_sources
+ voice_downlink/applicable_input_device/mask/telephony_rx = 0
+ voice_call/applicable_input_device/mask/telephony_rx = 0
+ voice_uplink/applicable_input_device/mask/telephony_rx = 0
+ voice_downlink/applicable_input_device/mask/stub = 1
+ voice_call/applicable_input_device/mask/stub = 1
+ voice_uplink/applicable_input_device/mask/stub = 1
conf: Default
component: /Policy/policy/input_sources
voice_downlink/applicable_input_device/mask/telephony_rx = 0
voice_call/applicable_input_device/mask/telephony_rx = 0
voice_uplink/applicable_input_device/mask/telephony_rx = 0
+ voice_downlink/applicable_input_device/mask/stub = 0
+ voice_call/applicable_input_device/mask/stub = 0
+ voice_uplink/applicable_input_device/mask/stub = 0
domain: Camcorder
conf: BackMic
@@ -368,6 +404,7 @@
component: /Policy/policy/input_sources/camcorder/applicable_input_device/mask
back_mic = 1
builtin_mic = 0
+ stub = 0
conf: BuiltinMic
AvailableInputDevices Includes BuiltinMic
@@ -375,11 +412,21 @@
component: /Policy/policy/input_sources/camcorder/applicable_input_device/mask
back_mic = 0
builtin_mic = 1
+ stub = 0
+
+ conf: Stub
+ AvailableInputDevices Includes Default
+
+ component: /Policy/policy/input_sources/camcorder/applicable_input_device/mask
+ back_mic = 0
+ builtin_mic = 0
+ stub = 1
conf: Default
component: /Policy/policy/input_sources/camcorder/applicable_input_device/mask
back_mic = 0
builtin_mic = 0
+ stub = 0
domain: VoiceRecognitionAndUnprocessedAndHotword
conf: ScoHeadset
@@ -392,16 +439,19 @@
wired_headset = 0
usb_device = 0
builtin_mic = 0
+ stub = 0
component: unprocessed/applicable_input_device/mask
bluetooth_sco_headset = 1
wired_headset = 0
usb_device = 0
builtin_mic = 0
+ stub = 0
component: hotword/applicable_input_device/mask
bluetooth_sco_headset = 1
wired_headset = 0
usb_device = 0
builtin_mic = 0
+ stub = 0
conf: WiredHeadset
AvailableInputDevices Includes WiredHeadset
@@ -411,17 +461,20 @@
bluetooth_sco_headset = 0
wired_headset = 1
usb_device = 0
+ stub = 0
builtin_mic = 0
component: unprocessed/applicable_input_device/mask
bluetooth_sco_headset = 0
wired_headset = 1
usb_device = 0
builtin_mic = 0
+ stub = 0
component: hotword/applicable_input_device/mask
bluetooth_sco_headset = 0
wired_headset = 1
usb_device = 0
builtin_mic = 0
+ stub = 0
conf: UsbDevice
AvailableInputDevices Includes UsbDevice
@@ -432,16 +485,19 @@
wired_headset = 0
usb_device = 1
builtin_mic = 0
+ stub = 0
component: unprocessed/applicable_input_device/mask
bluetooth_sco_headset = 0
wired_headset = 0
usb_device = 1
builtin_mic = 0
+ stub = 0
component: hotword/applicable_input_device/mask
bluetooth_sco_headset = 0
wired_headset = 0
usb_device = 1
builtin_mic = 0
+ stub = 0
conf: BuiltinMic
AvailableInputDevices Includes BuiltinMic
@@ -452,17 +508,42 @@
wired_headset = 0
usb_device = 0
builtin_mic = 1
+ stub = 0
component: unprocessed/applicable_input_device/mask
bluetooth_sco_headset = 0
wired_headset = 0
usb_device = 0
builtin_mic = 1
+ stub = 0
component: hotword/applicable_input_device/mask
bluetooth_sco_headset = 0
wired_headset = 0
usb_device = 0
builtin_mic = 1
+ stub = 0
+ conf: Stub
+ AvailableInputDevices Includes Default
+
+ component: /Policy/policy/input_sources
+ component: voice_recognition/applicable_input_device/mask
+ bluetooth_sco_headset = 0
+ wired_headset = 0
+ usb_device = 0
+ builtin_mic = 0
+ stub = 1
+ component: unprocessed/applicable_input_device/mask
+ bluetooth_sco_headset = 0
+ wired_headset = 0
+ usb_device = 0
+ builtin_mic = 0
+ stub = 1
+ component: hotword/applicable_input_device/mask
+ bluetooth_sco_headset = 0
+ wired_headset = 0
+ usb_device = 0
+ builtin_mic = 0
+ stub = 1
conf: Default
component: /Policy/policy/input_sources
component: voice_recognition/applicable_input_device/mask
@@ -470,16 +551,19 @@
wired_headset = 0
usb_device = 0
builtin_mic = 0
+ stub = 0
component: unprocessed/applicable_input_device/mask
bluetooth_sco_headset = 0
wired_headset = 0
usb_device = 0
builtin_mic = 0
+ stub = 0
component: hotword/applicable_input_device/mask
bluetooth_sco_headset = 0
wired_headset = 0
usb_device = 0
builtin_mic = 0
+ stub = 0
domain: VoiceCommunication
conf: ScoHeadset
@@ -495,6 +579,7 @@
usb_device = 0
builtin_mic = 0
back_mic = 0
+ stub = 0
conf: WiredHeadset
ForceUseForCommunication Is ForceNone
@@ -506,6 +591,7 @@
usb_device = 0
builtin_mic = 0
back_mic = 0
+ stub = 0
conf: UsbDevice
ForceUseForCommunication Is ForceNone
@@ -517,6 +603,7 @@
usb_device = 1
builtin_mic = 0
back_mic = 0
+ stub = 0
conf: BuiltinMic
AvailableInputDevices Includes BuiltinMic
@@ -532,6 +619,7 @@
usb_device = 0
builtin_mic = 1
back_mic = 0
+ stub = 0
conf: BackMic
ForceUseForCommunication Is ForceSpeaker
@@ -543,6 +631,7 @@
usb_device = 0
builtin_mic = 0
back_mic = 1
+ stub = 0
conf: Default
#
@@ -554,6 +643,7 @@
usb_device = 0
builtin_mic = 1
back_mic = 0
+ stub = 0
domain: RemoteSubmix
conf: RemoteSubmix
@@ -561,10 +651,19 @@
component: /Policy/policy/input_sources/remote_submix/applicable_input_device/mask
remote_submix = 1
+ stub = 0
+
+ conf: Stub
+ AvailableInputDevices Includes Default
+
+ component: /Policy/policy/input_sources/remote_submix/applicable_input_device/mask
+ remote_submix = 0
+ stub = 1
conf: Default
component: /Policy/policy/input_sources/remote_submix/applicable_input_device/mask
remote_submix = 0
+ stub = 0
domain: FmTuner
conf: FmTuner
@@ -572,8 +671,29 @@
component: /Policy/policy/input_sources/fm_tuner/applicable_input_device/mask
fm_tuner = 1
+ stub = 0
+
+ conf: Stub
+ AvailableInputDevices Includes Default
+
+ component: /Policy/policy/input_sources/fm_tuner/applicable_input_device/mask
+ fm_tuner = 0
+ stub = 1
conf: Default
component: /Policy/policy/input_sources/fm_tuner/applicable_input_device/mask
fm_tuner = 0
+ stub = 0
+
+ domain: Voice
+ conf: Stub
+ AvailableInputDevices Includes Default
+
+ /Policy/policy/input_sources/echo_reference/applicable_input_device/mask/stub = 1
+ /Policy/policy/input_sources/voice_performance/applicable_input_device/mask/stub = 1
+
+ conf: Default
+ /Policy/policy/input_sources/echo_reference/applicable_input_device/mask/stub = 0
+ /Policy/policy/input_sources/voice_performance/applicable_input_device/mask/stub = 0
+
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/volumes.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/volumes.pfw
index 7db4537..cf1857e 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/volumes.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/volumes.pfw
@@ -11,6 +11,7 @@
/Policy/policy/streams/enforced_audible/applicable_volume_profile/volume_profile = enforced_audible
/Policy/policy/streams/tts/applicable_volume_profile/volume_profile = tts
/Policy/policy/streams/accessibility/applicable_volume_profile/volume_profile = accessibility
+ /Policy/policy/streams/assistant/applicable_volume_profile/volume_profile = assistant
/Policy/policy/streams/rerouting/applicable_volume_profile/volume_profile = rerouting
/Policy/policy/streams/patch/applicable_volume_profile/volume_profile = patch
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoInput/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoInput/Android.bp
new file mode 100644
index 0000000..9abcb70
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoInput/Android.bp
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+// Import this namespace in order to use AOSP No Input configuration example
+
+soong_namespace {
+ imports: [
+ "frameworks/av/services/audiopolicy/engineconfigurable/config/example/phone",
+ "frameworks/av/services/audiopolicy/config",
+ ],
+}
+
+prebuilt_etc {
+ name: "parameter-framework.policy",
+ filename_from_src: true,
+ vendor: true,
+ src: ":domaingeneratorpolicyrule_gen",
+ sub_dir: "parameter-framework/Settings/Policy",
+ required: [
+ "PolicyClass.xml",
+ "PolicySubsystem.xml",
+ "PolicySubsystem-CommonTypes.xml",
+ ],
+}
+
+genrule {
+ name: "domaingeneratorpolicyrule_gen",
+ defaults: ["domaingeneratorpolicyrule"],
+ srcs: [
+ ":audio_policy_pfw_toplevel",
+ ":audio_policy_pfw_structure_files",
+ ":audio_policy_engine_criterion_types",
+ ":edd_files",
+ ],
+}
+filegroup {
+ name: "audio_policy_pfw_toplevel",
+ srcs: [":ParameterFrameworkConfigurationPolicy.userdebug.xml"],
+}
+filegroup {
+ name: "audio_policy_pfw_structure_files",
+ srcs: [
+ ":PolicyClass",
+ ":PolicySubsystem",
+ ":buildcommontypesstructure_gen",
+ ],
+}
+filegroup {
+ name: "edd_files",
+ srcs: [
+ "device_for_input_source.pfw",
+ ":volumes.pfw",
+ ],
+}
+prebuilt_etc {
+ name: "PolicySubsystem.xml",
+ vendor: true,
+ src: ":PolicySubsystem-no-strategy",
+ sub_dir: "parameter-framework/Structure/Policy",
+}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoOutput/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoOutput/Android.bp
new file mode 100644
index 0000000..27172a4
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoOutput/Android.bp
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+// Import this namespace in order to use AOSP No output configuration example
+
+soong_namespace {
+ imports: [
+ "frameworks/av/services/audiopolicy/engineconfigurable/config/example/phone",
+ "frameworks/av/services/audiopolicy/config",
+ ],
+}
+
+prebuilt_etc {
+ name: "parameter-framework.policy",
+ filename_from_src: true,
+ vendor: true,
+ src: ":domaingeneratorpolicyrule_gen",
+ sub_dir: "parameter-framework/Settings/Policy",
+ required: [
+ "PolicyClass.xml",
+ "PolicySubsystem.xml",
+ "PolicySubsystem-CommonTypes.xml",
+ ],
+}
+genrule {
+ name: "domaingeneratorpolicyrule_gen",
+ defaults: ["domaingeneratorpolicyrule"],
+ srcs: [
+ ":audio_policy_pfw_toplevel",
+ ":audio_policy_pfw_structure_files",
+ ":audio_policy_engine_criterion_types",
+ ":edd_files",
+ ],
+}
+filegroup {
+ name: "audio_policy_pfw_toplevel",
+ srcs: [":ParameterFrameworkConfigurationPolicy.userdebug.xml"],
+}
+filegroup {
+ name: "audio_policy_pfw_structure_files",
+ srcs: [
+ ":PolicyClass",
+ ":PolicySubsystem",
+ ":buildcommontypesstructure_gen",
+ ],
+}
+filegroup {
+ name: "edd_files",
+ srcs: [
+ "device_for_strategies.pfw",
+ ":volumes.pfw",
+ ":device_for_input_source.pfw",
+ ],
+}
+prebuilt_etc {
+ name: "PolicySubsystem.xml",
+ vendor: true,
+ src: ":PolicySubsystem-no-strategy",
+ sub_dir: "parameter-framework/Structure/Policy",
+}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoOutput/device_for_strategies.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoOutput/device_for_strategies.pfw
index f923610..e259c00 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoOutput/device_for_strategies.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoOutput/device_for_strategies.pfw
@@ -13,7 +13,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -41,7 +41,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -69,7 +69,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -97,7 +97,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -125,7 +125,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -153,7 +153,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -181,7 +181,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -209,7 +209,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
@@ -237,7 +237,7 @@
bluetooth_a2dp_headphones = 0
bluetooth_a2dp_speaker = 0
hdmi = 0
- angl_dock_headset = 0
+ anlg_dock_headset = 0
dgtl_dock_headset = 0
usb_accessory = 0
usb_device = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-CommonTypes.xml b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-CommonTypes.xml
deleted file mode 100644
index d17c021..0000000
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-CommonTypes.xml
+++ /dev/null
@@ -1,186 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ComponentTypeSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:xi="http://www.w3.org/2001/XInclude"
- xsi:noNamespaceSchemaLocation="Schemas/ComponentTypeSet.xsd">
- <!-- Output devices definition as a bitfield for the supported devices per output
- profile. It must match with the output device enum parameter.
- -->
- <!--#################### GLOBAL COMPONENTS BEGIN ####################-->
-
- <!--#################### GLOBAL COMPONENTS END ####################-->
-
- <ComponentType Name="OutputDevicesMask" Description="32th bit is not allowed as dedicated
- for input devices detection">
- <BitParameterBlock Name="mask" Size="32">
- <BitParameter Name="earpiece" Size="1" Pos="0"/>
- <BitParameter Name="speaker" Size="1" Pos="1"/>
- <BitParameter Name="wired_headset" Size="1" Pos="2"/>
- <BitParameter Name="wired_headphone" Size="1" Pos="3"/>
- <BitParameter Name="bluetooth_sco" Size="1" Pos="4"/>
- <BitParameter Name="bluetooth_sco_headset" Size="1" Pos="5"/>
- <BitParameter Name="bluetooth_sco_carkit" Size="1" Pos="6"/>
- <BitParameter Name="bluetooth_a2dp" Size="1" Pos="7"/>
- <BitParameter Name="bluetooth_a2dp_headphones" Size="1" Pos="8"/>
- <BitParameter Name="bluetooth_a2dp_speaker" Size="1" Pos="9"/>
- <BitParameter Name="hdmi" Size="1" Pos="10"/>
- <BitParameter Name="angl_dock_headset" Size="1" Pos="11"/>
- <BitParameter Name="dgtl_dock_headset" Size="1" Pos="12"/>
- <BitParameter Name="usb_accessory" Size="1" Pos="13"/>
- <BitParameter Name="usb_device" Size="1" Pos="14"/>
- <BitParameter Name="remote_submix" Size="1" Pos="15"/>
- <BitParameter Name="telephony_tx" Size="1" Pos="16"/>
- <BitParameter Name="line" Size="1" Pos="17"/>
- <BitParameter Name="hdmi_arc" Size="1" Pos="18"/>
- <BitParameter Name="spdif" Size="1" Pos="19"/>
- <BitParameter Name="fm" Size="1" Pos="20"/>
- <BitParameter Name="aux_line" Size="1" Pos="21"/>
- <BitParameter Name="speaker_safe" Size="1" Pos="22"/>
- <BitParameter Name="ip" Size="1" Pos="23"/>
- <BitParameter Name="bus" Size="1" Pos="24"/>
- <BitParameter Name="proxy" Size="1" Pos="25"/>
- <BitParameter Name="usb_headset" Size="1" Pos="26"/>
- <BitParameter Name="hearing_aid" Size="1" Pos="27"/>
- <BitParameter Name="echo_canceller" Size="1" Pos="28"/>
- <BitParameter Name="stub" Size="1" Pos="30"/>
- </BitParameterBlock>
- </ComponentType>
-
- <!-- Input devices definition as a bitfield for the supported devices per Input
- profile. It must match with the Input device enum parameter.
- -->
- <ComponentType Name="InputDevicesMask">
- <BitParameterBlock Name="mask" Size="32">
- <BitParameter Name="communication" Size="1" Pos="0"/>
- <BitParameter Name="ambient" Size="1" Pos="1"/>
- <BitParameter Name="builtin_mic" Size="1" Pos="2"/>
- <BitParameter Name="bluetooth_sco_headset" Size="1" Pos="3"/>
- <BitParameter Name="wired_headset" Size="1" Pos="4"/>
- <BitParameter Name="hdmi" Size="1" Pos="5"/>
- <BitParameter Name="telephony_rx" Size="1" Pos="6"/>
- <BitParameter Name="back_mic" Size="1" Pos="7"/>
- <BitParameter Name="remote_submix" Size="1" Pos="8"/>
- <BitParameter Name="anlg_dock_headset" Size="1" Pos="9"/>
- <BitParameter Name="dgtl_dock_headset" Size="1" Pos="10"/>
- <BitParameter Name="usb_accessory" Size="1" Pos="11"/>
- <BitParameter Name="usb_device" Size="1" Pos="12"/>
- <BitParameter Name="fm_tuner" Size="1" Pos="13"/>
- <BitParameter Name="tv_tuner" Size="1" Pos="14"/>
- <BitParameter Name="line" Size="1" Pos="15"/>
- <BitParameter Name="spdif" Size="1" Pos="16"/>
- <BitParameter Name="bluetooth_a2dp" Size="1" Pos="17"/>
- <BitParameter Name="loopback" Size="1" Pos="18"/>
- <BitParameter Name="ip" Size="1" Pos="19"/>
- <BitParameter Name="bus" Size="1" Pos="20"/>
- <BitParameter Name="proxy" Size="1" Pos="21"/>
- <BitParameter Name="usb_headset" Size="1" Pos="22"/>
- <BitParameter Name="bluetooth_ble" Size="1" Pos="23"/>
- <BitParameter Name="hdmi_arc" Size="1" Pos="24"/>
- <BitParameter Name="echo_reference" Size="1" Pos="25"/>
- <BitParameter Name="stub" Size="1" Pos="30"/>
- </BitParameterBlock>
- </ComponentType>
-
- <ComponentType Name="OutputFlags"
- Description="the audio output flags serve two purposes:
- - when an AudioTrack is created they indicate a wish to be connected to an
- output stream with attributes corresponding to the specified flags.
- - when present in an output profile descriptor listed for a particular audio
- hardware module, they indicate that an output stream can be opened that
- supports the attributes indicated by the flags.
- The audio policy manager will try to match the flags in the request
- (when getOuput() is called) to an available output stream.">
- <BitParameterBlock Name="mask" Size="32">
- <BitParameter Name="direct" Size="1" Pos="0"/>
- <BitParameter Name="primary" Size="1" Pos="1"/>
- <BitParameter Name="fast" Size="1" Pos="2"/>
- <BitParameter Name="deep_buffer" Size="1" Pos="3"/>
- <BitParameter Name="compress_offload" Size="1" Pos="4"/>
- <BitParameter Name="non_blocking" Size="1" Pos="5"/>
- <BitParameter Name="hw_av_sync" Size="1" Pos="6"/>
- <BitParameter Name="tts" Size="1" Pos="7"/>
- <BitParameter Name="raw" Size="1" Pos="8"/>
- <BitParameter Name="sync" Size="1" Pos="9"/>
- <BitParameter Name="iec958_nonaudio" Size="1" Pos="10"/>
- </BitParameterBlock>
- </ComponentType>
-
- <ComponentType Name="InputFlags"
- Description="The audio input flags are analogous to audio output flags.
- Currently they are used only when an AudioRecord is created,
- to indicate a preference to be connected to an input stream with
- attributes corresponding to the specified flags.">
- <BitParameterBlock Name="mask" Size="32">
- <BitParameter Name="fast" Size="1" Pos="0"/>
- <BitParameter Name="hw_hotword" Size="1" Pos="2"/>
- <BitParameter Name="raw" Size="1" Pos="3"/>
- <BitParameter Name="sync" Size="1" Pos="4"/>
- </BitParameterBlock>
- </ComponentType>
-
- <ComponentType Name="InputSourcesMask" Description="The audio input source is also known
- as the use case.">
- <BitParameterBlock Name="mask" Size="32">
- <BitParameter Name="default" Size="1" Pos="0"/>
- <BitParameter Name="mic" Size="1" Pos="1"/>
- <BitParameter Name="voice_uplink" Size="1" Pos="2"/>
- <BitParameter Name="voice_downlink" Size="1" Pos="3"/>
- <BitParameter Name="voice_call" Size="1" Pos="4"/>
- <BitParameter Name="camcorder" Size="1" Pos="5"/>
- <BitParameter Name="voice_recognition" Size="1" Pos="6"/>
- <BitParameter Name="voice_communication" Size="1" Pos="7"/>
- <BitParameter Name="remote_submix" Size="1" Pos="8"/>
- <BitParameter Name="unprocessed" Size="1" Pos="9"/>
- <BitParameter Name="voice_performance" Size="1" Pos="10"/>
- <BitParameter Name="echo_reference" Size="1" Pos="11"/>
- <BitParameter Name="fm_tuner" Size="1" Pos="12"/>
- <BitParameter Name="hotword" Size="1" Pos="13"/>
- </BitParameterBlock>
- </ComponentType>
-
- <!--#################### STREAM COMMON TYPES BEGIN ####################-->
-
- <ComponentType Name="VolumeProfileType">
- <EnumParameter Name="volume_profile" Size="32">
- <ValuePair Literal="voice_call" Numerical="0"/>
- <ValuePair Literal="system" Numerical="1"/>
- <ValuePair Literal="ring" Numerical="2"/>
- <ValuePair Literal="music" Numerical="3"/>
- <ValuePair Literal="alarm" Numerical="4"/>
- <ValuePair Literal="notification" Numerical="5"/>
- <ValuePair Literal="bluetooth_sco" Numerical="6"/>
- <ValuePair Literal="enforced_audible" Numerical="7"/>
- <ValuePair Literal="dtmf" Numerical="8"/>
- <ValuePair Literal="tts" Numerical="9"/>
- <ValuePair Literal="accessibility" Numerical="10"/>
- <ValuePair Literal="rerouting" Numerical="11"/>
- <ValuePair Literal="patch" Numerical="12"/>
- </EnumParameter>
- </ComponentType>
-
- <ComponentType Name="Stream" Mapping="Stream">
- <Component Name="applicable_volume_profile" Type="VolumeProfileType"
- Description="Volume profile followed by a given stream type."/>
- </ComponentType>
-
- <!--#################### STREAM COMMON TYPES END ####################-->
-
- <!--#################### INPUT SOURCE COMMON TYPES BEGIN ####################-->
-
- <ComponentType Name="InputSource">
- <Component Name="applicable_input_device" Type="InputDevicesMask"
- Mapping="InputSource" Description="Selected Input device"/>
- </ComponentType>
-
- <!--#################### INPUT SOURCE COMMON TYPES END ####################-->
-
- <!--#################### PRODUCT STRATEGY COMMON TYPES BEGIN ####################-->
-
- <ComponentType Name="ProductStrategy" Mapping="ProductStrategy">
- <Component Name="selected_output_devices" Type="OutputDevicesMask"/>
- <StringParameter Name="device_address" MaxLength="256"
- Description="if any, device address associated"/>
- </ComponentType>
-
- <!--#################### PRODUCT STRATEGY COMMON TYPES END ####################-->
-
-</ComponentTypeSet>
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-CommonTypes.xml.in b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-CommonTypes.xml.in
new file mode 100644
index 0000000..2e9f37e
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-CommonTypes.xml.in
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ComponentTypeSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ xsi:noNamespaceSchemaLocation="Schemas/ComponentTypeSet.xsd">
+ <!-- Output devices definition as a bitfield for the supported devices per output
+ profile. It must match with the output device enum parameter.
+ -->
+ <!--#################### GLOBAL COMPONENTS BEGIN ####################-->
+
+ <!--#################### GLOBAL COMPONENTS END ####################-->
+
+ <!-- Automatically filled from audio-base.h file -->
+ <ComponentType Name="OutputDevicesMask" Description="32th bit is not allowed as dedicated for input devices detection">
+ <BitParameterBlock Name="mask" Size="32">
+ </BitParameterBlock>
+ </ComponentType>
+
+ <!-- Input devices definition as a bitfield for the supported devices per Input
+ profile. It must match with the Input device enum parameter.
+ -->
+ <!-- Automatically filled from audio-base.h file -->
+ <ComponentType Name="InputDevicesMask">
+ <BitParameterBlock Name="mask" Size="32">
+ </BitParameterBlock>
+ </ComponentType>
+
+ <!--#################### STREAM COMMON TYPES BEGIN ####################-->
+ <!-- Automatically filled from audio-base.h file. VolumeProfileType is associated to stream type -->
+ <ComponentType Name="VolumeProfileType">
+ <EnumParameter Name="volume_profile" Size="32">
+ </EnumParameter>
+ </ComponentType>
+
+ <ComponentType Name="Stream" Mapping="Stream">
+ <Component Name="applicable_volume_profile" Type="VolumeProfileType"
+ Description="Volume profile followed by a given stream type."/>
+ </ComponentType>
+
+ <!--#################### STREAM COMMON TYPES END ####################-->
+
+ <!--#################### INPUT SOURCE COMMON TYPES BEGIN ####################-->
+
+ <ComponentType Name="InputSource">
+ <Component Name="applicable_input_device" Type="InputDevicesMask"
+ Mapping="InputSource" Description="Selected Input device"/>
+ </ComponentType>
+
+ <!--#################### INPUT SOURCE COMMON TYPES END ####################-->
+
+ <!--#################### PRODUCT STRATEGY COMMON TYPES BEGIN ####################-->
+
+ <ComponentType Name="ProductStrategy" Mapping="ProductStrategy">
+ <Component Name="selected_output_devices" Type="OutputDevicesMask"/>
+ <StringParameter Name="device_address" MaxLength="256"
+ Description="if any, device address associated"/>
+ </ComponentType>
+
+ <!--#################### PRODUCT STRATEGY COMMON TYPES END ####################-->
+
+</ComponentTypeSet>
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-no-strategy.xml b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-no-strategy.xml
index a4e7537..ed349c8 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-no-strategy.xml
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-no-strategy.xml
@@ -28,6 +28,8 @@
Description="Transmitted Through Speaker. Plays over speaker only, silent on other devices"/>
<Component Name="accessibility" Type="Stream" Mapping="Name:AUDIO_STREAM_ACCESSIBILITY"
Description="For accessibility talk back prompts"/>
+ <Component Name="assistant" Type="Stream" Mapping="Name:AUDIO_STREAM_ASSISTANT"
+ Description="used by a virtual assistant like Google Assistant, Bixby, etc."/>
<Component Name="rerouting" Type="Stream" Mapping="Name:AUDIO_STREAM_REROUTING"
Description="For dynamic policy output mixes"/>
<Component Name="patch" Type="Stream" Mapping="Name:AUDIO_STREAM_PATCH"
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem.xml b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem.xml
index b55ce2c..7bbb57a 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem.xml
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem.xml
@@ -44,6 +44,8 @@
Description="Transmitted Through Speaker. Plays over speaker only, silent on other devices"/>
<Component Name="accessibility" Type="Stream" Mapping="Name:AUDIO_STREAM_ACCESSIBILITY"
Description="For accessibility talk back prompts"/>
+ <Component Name="assistant" Type="Stream" Mapping="Name:AUDIO_STREAM_ASSISTANT"
+ Description="used by a virtual assistant like Google Assistant, Bixby, etc."/>
<Component Name="rerouting" Type="Stream" Mapping="Name:AUDIO_STREAM_REROUTING"
Description="For dynamic policy output mixes"/>
<Component Name="patch" Type="Stream" Mapping="Name:AUDIO_STREAM_PATCH"
@@ -73,10 +75,13 @@
Mapping="Name:AUDIO_SOURCE_REMOTE_SUBMIX"/>
<Component Name="unprocessed" Type="InputSource"
Mapping="Name:AUDIO_SOURCE_UNPROCESSED"/>
+ <Component Name="voice_performance" Type="InputSource"
+ Mapping="Name:AUDIO_SOURCE_VOICE_PERFORMANCE"/>
+ <Component Name="echo_reference" Type="InputSource"
+ Mapping="Name:AUDIO_SOURCE_ECHO_REFERENCE"/>
<Component Name="fm_tuner" Type="InputSource" Mapping="Name:AUDIO_SOURCE_FM_TUNER"/>
<Component Name="hotword" Type="InputSource" Mapping="Name:AUDIO_SOURCE_HOTWORD"/>
</ComponentType>
-
<!--#################### INPUT SOURCE END ####################-->
</ComponentLibrary>
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.cpp b/services/audiopolicy/engineconfigurable/src/Engine.cpp
index cb45fcf..6d42fcf 100644
--- a/services/audiopolicy/engineconfigurable/src/Engine.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Engine.cpp
@@ -32,6 +32,9 @@
#include <policy.h>
#include <AudioIODescriptorInterface.h>
#include <ParameterManagerWrapper.h>
+#include <media/AudioContainers.h>
+
+#include <media/TypeConverter.h>
using std::string;
using std::map;
@@ -77,8 +80,9 @@
status_t Engine::initCheck()
{
- if (mPolicyParameterMgr == nullptr || mPolicyParameterMgr->start() != NO_ERROR) {
- ALOGE("%s: could not start Policy PFW", __FUNCTION__);
+ std::string error;
+ if (mPolicyParameterMgr == nullptr || mPolicyParameterMgr->start(error) != NO_ERROR) {
+ ALOGE("%s: could not start Policy PFW: %s", __FUNCTION__, error.c_str());
return NO_INIT;
}
return EngineBase::initCheck();
@@ -125,7 +129,7 @@
Element<Key> *element = getFromCollection<Key>(key);
if (element == NULL) {
ALOGE("%s: Element not found within collection", __FUNCTION__);
- return BAD_VALUE;
+ return false;
}
return element->template set<Property>(property) == NO_ERROR;
}
@@ -159,19 +163,21 @@
return mPolicyParameterMgr->getForceUse(usage);
}
-status_t Engine::setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
+status_t Engine::setDeviceConnectionState(const sp<DeviceDescriptor> device,
audio_policy_dev_state_t state)
{
- mPolicyParameterMgr->setDeviceConnectionState(devDesc, state);
-
- if (audio_is_output_device(devDesc->type())) {
+ mPolicyParameterMgr->setDeviceConnectionState(
+ device->type(), device->address().c_str(), state);
+ if (audio_is_output_device(device->type())) {
+ // FIXME: Use DeviceTypeSet when the interface is ready
return mPolicyParameterMgr->setAvailableOutputDevices(
- getApmObserver()->getAvailableOutputDevices().types());
- } else if (audio_is_input_device(devDesc->type())) {
+ deviceTypesToBitMask(getApmObserver()->getAvailableOutputDevices().types()));
+ } else if (audio_is_input_device(device->type())) {
+ // FIXME: Use DeviceTypeSet when the interface is ready
return mPolicyParameterMgr->setAvailableInputDevices(
- getApmObserver()->getAvailableInputDevices().types());
+ deviceTypesToBitMask(getApmObserver()->getAvailableInputDevices().types()));
}
- return BAD_TYPE;
+ return EngineBase::setDeviceConnectionState(device, state);
}
status_t Engine::loadAudioPolicyEngineConfig()
@@ -209,7 +215,7 @@
}
const DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
- uint32_t availableOutputDevicesType = availableOutputDevices.types();
+ DeviceTypeSet availableOutputDevicesTypes = availableOutputDevices.types();
/** This is the only case handled programmatically because the PFW is unable to know the
* activity of streams.
@@ -221,7 +227,7 @@
*
* -When media is not playing anymore, fall back on the sonification behavior
*/
- audio_devices_t devices = AUDIO_DEVICE_NONE;
+ DeviceTypeSet deviceTypes;
if (ps == getProductStrategyForStream(AUDIO_STREAM_NOTIFICATION) &&
!is_state_in_call(getPhoneState()) &&
!outputs.isActiveRemotely(toVolumeSource(AUDIO_STREAM_MUSIC),
@@ -230,7 +236,7 @@
SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
product_strategy_t strategyForMedia =
getProductStrategyForStream(AUDIO_STREAM_MUSIC);
- devices = productStrategies.getDeviceTypesForProductStrategy(strategyForMedia);
+ deviceTypes = productStrategies.getDeviceTypesForProductStrategy(strategyForMedia);
} else if (ps == getProductStrategyForStream(AUDIO_STREAM_ACCESSIBILITY) &&
(outputs.isActive(toVolumeSource(AUDIO_STREAM_RING)) ||
outputs.isActive(toVolumeSource(AUDIO_STREAM_ALARM)))) {
@@ -238,28 +244,37 @@
// compressed format as they would likely not be mixed and dropped.
// Device For Sonification conf file has HDMI, SPDIF and HDMI ARC unreacheable.
product_strategy_t strategyNotification = getProductStrategyForStream(AUDIO_STREAM_RING);
- devices = productStrategies.getDeviceTypesForProductStrategy(strategyNotification);
+ deviceTypes = productStrategies.getDeviceTypesForProductStrategy(strategyNotification);
} else {
- devices = productStrategies.getDeviceTypesForProductStrategy(ps);
+ deviceTypes = productStrategies.getDeviceTypesForProductStrategy(ps);
}
- if (devices == AUDIO_DEVICE_NONE ||
- (devices & availableOutputDevicesType) == AUDIO_DEVICE_NONE) {
- devices = getApmObserver()->getDefaultOutputDevice()->type();
- ALOGE_IF(devices == AUDIO_DEVICE_NONE, "%s: no valid default device defined", __FUNCTION__);
- return DeviceVector(getApmObserver()->getDefaultOutputDevice());
+ if (deviceTypes.empty() ||
+ Intersection(deviceTypes, availableOutputDevicesTypes).empty()) {
+ auto defaultDevice = getApmObserver()->getDefaultOutputDevice();
+ ALOG_ASSERT(defaultDevice != nullptr, "no valid default device defined");
+ return DeviceVector(defaultDevice);
}
- if (/*device_distinguishes_on_address(devices)*/ devices == AUDIO_DEVICE_OUT_BUS) {
+ if (/*device_distinguishes_on_address(*deviceTypes.begin())*/ isSingleDeviceType(
+ deviceTypes, AUDIO_DEVICE_OUT_BUS)) {
// We do expect only one device for these types of devices
// Criterion device address garantee this one is available
// If this criterion is not wished, need to ensure this device is available
const String8 address(productStrategies.getDeviceAddressForProductStrategy(ps).c_str());
- ALOGV("%s:device 0x%x %s %d", __FUNCTION__, devices, address.c_str(), ps);
- return DeviceVector(availableOutputDevices.getDevice(devices,
- address,
- AUDIO_FORMAT_DEFAULT));
+ ALOGV("%s:device %s %s %d",
+ __FUNCTION__, dumpDeviceTypes(deviceTypes).c_str(), address.c_str(), ps);
+ auto busDevice = availableOutputDevices.getDevice(
+ *deviceTypes.begin(), address, AUDIO_FORMAT_DEFAULT);
+ if (busDevice == nullptr) {
+ ALOGE("%s:unavailable device %s %s, fallback on default", __func__,
+ dumpDeviceTypes(deviceTypes).c_str(), address.c_str());
+ auto defaultDevice = getApmObserver()->getDefaultOutputDevice();
+ ALOG_ASSERT(defaultDevice != nullptr, "Default Output Device NOT available");
+ return DeviceVector(defaultDevice);
+ }
+ return DeviceVector(busDevice);
}
- ALOGV("%s:device 0x%x %d", __FUNCTION__, devices, ps);
- return availableOutputDevices.getDevicesFromTypeMask(devices);
+ ALOGV("%s:device %s %d", __FUNCTION__, dumpDeviceTypes(deviceTypes).c_str(), ps);
+ return availableOutputDevices.getDevicesFromTypes(deviceTypes);
}
DeviceVector Engine::getOutputDevicesForAttributes(const audio_attributes_t &attributes,
@@ -356,12 +371,13 @@
ALOGE("%s: set device %d on invalid strategy %d", __FUNCTION__, devices, strategy);
return false;
}
- getProductStrategies().at(strategy)->setDeviceTypes(devices);
+ // FIXME: stop using deviceTypesFromBitMask when the interface is ready
+ getProductStrategies().at(strategy)->setDeviceTypes(deviceTypesFromBitMask(devices));
return true;
}
template <>
-AudioPolicyManagerInterface *Engine::queryInterface()
+EngineInterface *Engine::queryInterface()
{
return this;
}
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.h b/services/audiopolicy/engineconfigurable/src/Engine.h
index 4662e7e..3b371d8 100644
--- a/services/audiopolicy/engineconfigurable/src/Engine.h
+++ b/services/audiopolicy/engineconfigurable/src/Engine.h
@@ -17,7 +17,7 @@
#pragma once
#include "EngineBase.h"
-#include <AudioPolicyManagerInterface.h>
+#include <EngineInterface.h>
#include <AudioPolicyPluginInterface.h>
#include "Collection.h"
diff --git a/services/audiopolicy/engineconfigurable/src/EngineInstance.cpp b/services/audiopolicy/engineconfigurable/src/EngineInstance.cpp
index 2442590..b127796 100644
--- a/services/audiopolicy/engineconfigurable/src/EngineInstance.cpp
+++ b/services/audiopolicy/engineconfigurable/src/EngineInstance.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <AudioPolicyManagerInterface.h>
+#include <EngineInterface.h>
#include <AudioPolicyPluginInterface.h>
#include "AudioPolicyEngineInstance.h"
#include "Engine.h"
@@ -45,9 +45,9 @@
}
template <>
-AudioPolicyManagerInterface *EngineInstance::queryInterface() const
+EngineInterface *EngineInstance::queryInterface() const
{
- return getEngine()->queryInterface<AudioPolicyManagerInterface>();
+ return getEngine()->queryInterface<EngineInterface>();
}
template <>
@@ -57,5 +57,16 @@
}
} // namespace audio_policy
+
+extern "C" EngineInterface* createEngineInstance()
+{
+ return audio_policy::EngineInstance::getInstance()->queryInterface<EngineInterface>();
+}
+
+extern "C" void destroyEngineInstance(EngineInterface*)
+{
+ // The engine is a singleton.
+}
+
} // namespace android
diff --git a/services/audiopolicy/engineconfigurable/src/InputSource.cpp b/services/audiopolicy/engineconfigurable/src/InputSource.cpp
index d252d3f..aa06ae3 100644
--- a/services/audiopolicy/engineconfigurable/src/InputSource.cpp
+++ b/services/audiopolicy/engineconfigurable/src/InputSource.cpp
@@ -30,7 +30,7 @@
return BAD_VALUE;
}
mIdentifier = identifier;
- ALOGD("%s: InputSource %s identifier 0x%X", __FUNCTION__, getName().c_str(), identifier);
+ ALOGV("%s: InputSource %s identifier 0x%X", __FUNCTION__, getName().c_str(), identifier);
return NO_ERROR;
}
@@ -46,15 +46,18 @@
template <>
status_t Element<audio_source_t>::set(audio_devices_t devices)
{
- if (devices != AUDIO_DEVICE_NONE) {
- devices |= AUDIO_DEVICE_BIT_IN;
+ if (devices == AUDIO_DEVICE_NONE) {
+ // Reset
+ mApplicableDevices = devices;
+ return NO_ERROR;
}
+ devices |= AUDIO_DEVICE_BIT_IN;
if (!audio_is_input_device(devices)) {
ALOGE("%s: trying to set an invalid device 0x%X for input source %s",
__FUNCTION__, devices, getName().c_str());
return BAD_VALUE;
}
- ALOGD("%s: 0x%X for input source %s", __FUNCTION__, devices, getName().c_str());
+ ALOGV("%s: 0x%X for input source %s", __FUNCTION__, devices, getName().c_str());
mApplicableDevices = devices;
return NO_ERROR;
}
diff --git a/services/audiopolicy/engineconfigurable/src/InputSource.h b/services/audiopolicy/engineconfigurable/src/InputSource.h
index e1865cc..d64a60a 100644
--- a/services/audiopolicy/engineconfigurable/src/InputSource.h
+++ b/services/audiopolicy/engineconfigurable/src/InputSource.h
@@ -73,10 +73,11 @@
Element(const Element &object);
Element &operator=(const Element &object);
- std::string mName; /**< Unique literal Identifier of a policy base element*/
- audio_source_t mIdentifier; /**< Unique numerical Identifier of a policy base element*/
-
- audio_devices_t mApplicableDevices; /**< Applicable input device for this input source. */
+ const std::string mName; /**< Unique literal Identifier of a policy base element*/
+ /** Unique numerical Identifier of a policy base element */
+ audio_source_t mIdentifier = AUDIO_SOURCE_DEFAULT;
+ /** Applicable input device for this input source. */
+ audio_devices_t mApplicableDevices = AUDIO_DEVICE_NONE;
};
typedef Element<audio_source_t> InputSource;
diff --git a/services/audiopolicy/engineconfigurable/src/Stream.cpp b/services/audiopolicy/engineconfigurable/src/Stream.cpp
index 297eb02..e64ba4b 100644
--- a/services/audiopolicy/engineconfigurable/src/Stream.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Stream.cpp
@@ -30,7 +30,7 @@
return BAD_VALUE;
}
mIdentifier = identifier;
- ALOGD("%s: Stream %s identifier 0x%X", __FUNCTION__, getName().c_str(), identifier);
+ ALOGV("%s: Stream %s identifier 0x%X", __FUNCTION__, getName().c_str(), identifier);
return NO_ERROR;
}
@@ -41,7 +41,7 @@
return BAD_VALUE;
}
mVolumeProfile = volumeProfile;
- ALOGD("%s: 0x%X for Stream %s", __FUNCTION__, mVolumeProfile, getName().c_str());
+ ALOGV("%s: 0x%X for Stream %s", __FUNCTION__, mVolumeProfile, getName().c_str());
return NO_ERROR;
}
diff --git a/services/audiopolicy/engineconfigurable/tools/Android.bp b/services/audiopolicy/engineconfigurable/tools/Android.bp
index 8c16972..3e47324 100644
--- a/services/audiopolicy/engineconfigurable/tools/Android.bp
+++ b/services/audiopolicy/engineconfigurable/tools/Android.bp
@@ -16,14 +16,17 @@
name: "tools_default",
version: {
py2: {
- enabled: true,
+ enabled: false,
},
py3: {
- enabled: false,
+ enabled: true,
},
},
}
+//##################################################################################################
+// Tools for audio policy engine criterion type configuration file
+//
python_binary_host {
name: "buildPolicyCriterionTypes.py",
main: "buildPolicyCriterionTypes.py",
@@ -33,6 +36,30 @@
defaults: ["tools_default"],
}
+genrule_defaults {
+ name: "buildpolicycriteriontypesrule",
+ tools: ["buildPolicyCriterionTypes.py"],
+ cmd: "cp $(locations :audio_policy_configuration_files) $(genDir)/. && " +
+ "cp $(location :audio_policy_configuration_top_file) $(genDir)/audio_policy_configuration.xml && " +
+ "$(location buildPolicyCriterionTypes.py) " +
+ // @todo update if 1428659 is merged "--androidaudiobaseheader $(location :android_audio_base_header_file) " +
+ " --androidaudiobaseheader system/media/audio/include/system/audio-base.h " +
+ "--audiopolicyconfigurationfile $(genDir)/audio_policy_configuration.xml " +
+ "--criteriontypes $(location :audio_policy_engine_criterion_types_template) " +
+ "--outputfile $(out)",
+ srcs: [
+ // The commented inputs must be provided to use this genrule_defaults
+ // @todo uncomment if 1428659 is merged":android_audio_base_header_file",
+ ":audio_policy_engine_criterion_types_template",
+ // ":audio_policy_configuration_top_file",
+ // ":audio_policy_configuration_files",
+ ],
+ out: ["audio_policy_engine_criterion_types.xml"],
+}
+
+//##################################################################################################
+// Tools for audio policy engine parameter framework configurable domains
+//
python_binary_host {
name: "domainGeneratorPolicy.py",
main: "domainGeneratorPolicy.py",
@@ -50,6 +77,38 @@
],
}
+genrule_defaults {
+ name: "domaingeneratorpolicyrule",
+ tools: [
+ "domainGeneratorPolicy.py",
+ "domainGeneratorConnector",
+ ],
+ cmd: "mkdir -p $(genDir)/Structure/Policy && " +
+ "cp $(locations :audio_policy_pfw_structure_files) $(genDir)/Structure/Policy && " +
+ "cp $(location :audio_policy_pfw_toplevel) $(genDir)/top_level && " +
+ "$(location domainGeneratorPolicy.py) " +
+ "--validate " +
+ "--domain-generator-tool $(location domainGeneratorConnector) " +
+ "--toplevel-config $(genDir)/top_level " +
+ "--criteria $(location :audio_policy_engine_criteria) " +
+ "--criteriontypes $(location :audio_policy_engine_criterion_types) " +
+ "--add-edds $(locations :edd_files) " +
+ "--schemas-dir external/parameter-framework/upstream/schemas " +
+ " > $(out)",
+ srcs: [
+ // The commented inputs must be provided to use this genrule_defaults
+ // ":audio_policy_pfw_toplevel",
+ // ":audio_policy_pfw_structure_files",
+ ":audio_policy_engine_criteria",
+ // ":audio_policy_engine_criterion_types",
+ // ":edd_files",
+ ],
+ out: ["PolicyConfigurableDomains.xml"],
+}
+
+//##################################################################################################
+// Tools for policy parameter-framework product strategies structure file generation
+//
python_binary_host {
name: "buildStrategiesStructureFile.py",
main: "buildStrategiesStructureFile.py",
@@ -58,3 +117,45 @@
],
defaults: ["tools_default"],
}
+
+genrule_defaults {
+ name: "buildstrategiesstructurerule",
+ tools: ["buildStrategiesStructureFile.py"],
+ cmd: "cp $(locations :audio_policy_engine_configuration_files) $(genDir) && ls -l $(genDir) &&"+
+ "$(location buildStrategiesStructureFile.py) " +
+ "--audiopolicyengineconfigurationfile $(genDir)/audio_policy_engine_configuration.xml "+
+ "--productstrategiesstructurefile $(location :product_strategies_structure_template) " +
+ "--outputfile $(out)",
+ srcs: [
+ // The commented inputs must be provided to use this genrule_defaults
+ // ":audio_policy_engine_configuration_files",
+ ":product_strategies_structure_template",
+ ],
+ out: ["ProductStrategies.xml"],
+}
+
+//##################################################################################################
+// Tools for policy parameter-framework common type structure file generation
+//
+python_binary_host {
+ name: "buildCommonTypesStructureFile.py",
+ main: "buildCommonTypesStructureFile.py",
+ srcs: [
+ "buildCommonTypesStructureFile.py",
+ ],
+ defaults: ["tools_default"],
+}
+
+genrule_defaults {
+ name: "buildcommontypesstructurerule",
+ tools: ["buildCommonTypesStructureFile.py"],
+ cmd: "$(location buildCommonTypesStructureFile.py) " +
+ "--androidaudiobaseheader $(location :libaudio_system_audio_base) " +
+ "--commontypesstructure $(location :common_types_structure_template) " +
+ "--outputfile $(out)",
+ srcs: [
+ ":common_types_structure_template",
+ ":libaudio_system_audio_base",
+ ],
+ out: ["PolicySubsystem-CommonTypes.xml"],
+}
diff --git a/services/audiopolicy/engineconfigurable/tools/buildCommonTypesStructureFile.py b/services/audiopolicy/engineconfigurable/tools/buildCommonTypesStructureFile.py
new file mode 100755
index 0000000..9a7fa8f
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/tools/buildCommonTypesStructureFile.py
@@ -0,0 +1,184 @@
+#! /usr/bin/python3
+#
+# pylint: disable=line-too-long, missing-docstring, logging-format-interpolation, invalid-name
+
+#
+# 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.
+
+import argparse
+import re
+import sys
+import os
+import logging
+import xml.etree.ElementTree as ET
+from collections import OrderedDict
+import xml.dom.minidom as MINIDOM
+
+def parseArgs():
+ argparser = argparse.ArgumentParser(description="Parameter-Framework XML \
+ structure file generator.\n\
+ Exit with the number of (recoverable or not) error that occured.")
+ argparser.add_argument('--androidaudiobaseheader',
+ help="Android Audio Base C header file, Mandatory.",
+ metavar="ANDROID_AUDIO_BASE_HEADER",
+ type=argparse.FileType('r'),
+ required=True)
+ argparser.add_argument('--commontypesstructure',
+ help="Structure XML base file. Mandatory.",
+ metavar="STRUCTURE_FILE_IN",
+ type=argparse.FileType('r'),
+ required=True)
+ argparser.add_argument('--outputfile',
+ help="Structure XML file. Mandatory.",
+ metavar="STRUCTURE_FILE_OUT",
+ type=argparse.FileType('w'),
+ required=True)
+ argparser.add_argument('--verbose',
+ action='store_true')
+
+ return argparser.parse_args()
+
+
+def findBitPos(decimal):
+ pos = 0
+ i = 1
+ while i != decimal:
+ i = i << 1
+ pos = pos + 1
+ if pos == 32:
+ return -1
+ return pos
+
+
+def generateXmlStructureFile(componentTypeDict, structureTypesFile, outputFile):
+
+ logging.info("Importing structureTypesFile {}".format(structureTypesFile))
+ component_types_in_tree = ET.parse(structureTypesFile)
+
+ component_types_root = component_types_in_tree.getroot()
+
+ for component_types_name, values_dict in componentTypeDict.items():
+ for component_type in component_types_root.findall('ComponentType'):
+ if component_type.get('Name') == component_types_name:
+ bitparameters_node = component_type.find("BitParameterBlock")
+ if bitparameters_node is not None:
+ ordered_values = OrderedDict(sorted(values_dict.items(), key=lambda x: x[1]))
+ for key, value in ordered_values.items():
+ value_node = ET.SubElement(bitparameters_node, "BitParameter")
+ value_node.set('Name', key)
+ value_node.set('Size', "1")
+ value_node.set('Pos', str(findBitPos(value)))
+
+ enum_parameter_node = component_type.find("EnumParameter")
+ if enum_parameter_node is not None:
+ ordered_values = OrderedDict(sorted(values_dict.items(), key=lambda x: x[1]))
+ for key, value in ordered_values.items():
+ value_node = ET.SubElement(enum_parameter_node, "ValuePair")
+ value_node.set('Literal', key)
+ value_node.set('Numerical', str(value))
+
+ xmlstr = ET.tostring(component_types_root, encoding='utf8', method='xml')
+ reparsed = MINIDOM.parseString(xmlstr)
+ prettyXmlStr = reparsed.toprettyxml(indent=" ", newl='\n')
+ prettyXmlStr = os.linesep.join([s for s in prettyXmlStr.splitlines() if s.strip()])
+ outputFile.write(prettyXmlStr)
+
+
+def capitalizeLine(line):
+ return ' '.join((w.capitalize() for w in line.split(' ')))
+
+def parseAndroidAudioFile(androidaudiobaseheaderFile):
+ #
+ # Adaptation table between Android Enumeration prefix and Audio PFW Criterion type names
+ #
+ component_type_mapping_table = {
+ 'AUDIO_STREAM' : "VolumeProfileType",
+ 'AUDIO_DEVICE_OUT' : "OutputDevicesMask",
+ 'AUDIO_DEVICE_IN' : "InputDevicesMask"}
+
+ all_component_types = {
+ 'VolumeProfileType' : {},
+ 'OutputDevicesMask' : {},
+ 'InputDevicesMask' : {}
+ }
+
+ #
+ # _CNT, _MAX, _ALL and _NONE are prohibited values as ther are just helpers for enum users.
+ #
+ ignored_values = ['CNT', 'MAX', 'ALL', 'NONE']
+
+ criteria_pattern = re.compile(
+ r"\s*(?P<type>(?:"+'|'.join(component_type_mapping_table.keys()) + "))_" \
+ r"(?P<literal>(?!" + '|'.join(ignored_values) + ")\w*)\s*=\s*" \
+ r"(?P<values>(?:0[xX])?[0-9a-fA-F]+)")
+
+ logging.info("Checking Android Header file {}".format(androidaudiobaseheaderFile))
+
+ for line_number, line in enumerate(androidaudiobaseheaderFile):
+ match = criteria_pattern.match(line)
+ if match:
+ logging.debug("The following line is VALID: {}:{}\n{}".format(
+ androidaudiobaseheaderFile.name, line_number, line))
+
+ component_type_name = component_type_mapping_table[match.groupdict()['type']]
+ component_type_literal = match.groupdict()['literal'].lower()
+
+ component_type_numerical_value = match.groupdict()['values']
+
+ # for AUDIO_DEVICE_IN: need to remove sign bit / rename default to stub
+ if component_type_name == "InputDevicesMask":
+ component_type_numerical_value = str(int(component_type_numerical_value, 0) & ~2147483648)
+ if component_type_literal == "default":
+ component_type_literal = "stub"
+
+ if component_type_name == "OutputDevicesMask":
+ if component_type_literal == "default":
+ component_type_literal = "stub"
+
+ # Remove duplicated numerical values
+ if int(component_type_numerical_value, 0) in all_component_types[component_type_name].values():
+ logging.info("The value {}:{} is duplicated for criterion {}, KEEPING LATEST".format(component_type_numerical_value, component_type_literal, component_type_name))
+ for key in list(all_component_types[component_type_name]):
+ if all_component_types[component_type_name][key] == int(component_type_numerical_value, 0):
+ del all_component_types[component_type_name][key]
+
+ all_component_types[component_type_name][component_type_literal] = int(component_type_numerical_value, 0)
+
+ logging.debug("type:{}, literal:{}, values:{}.".format(component_type_name, component_type_literal, component_type_numerical_value))
+
+ # Transform input source in inclusive criterion
+ shift = len(all_component_types['OutputDevicesMask'])
+ if shift > 32:
+ logging.critical("OutputDevicesMask incompatible with criterion representation on 32 bits")
+ logging.info("EXIT ON FAILURE")
+ exit(1)
+
+ for component_types in all_component_types:
+ values = ','.join('{}:{}'.format(value, key) for key, value in all_component_types[component_types].items())
+ logging.info("{}: <{}>".format(component_types, values))
+
+ return all_component_types
+
+
+def main():
+ logging.root.setLevel(logging.INFO)
+ args = parseArgs()
+ route_criteria = 0
+
+ all_component_types = parseAndroidAudioFile(args.androidaudiobaseheader)
+
+ generateXmlStructureFile(all_component_types, args.commontypesstructure, args.outputfile)
+
+# If this file is directly executed
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py b/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py
index a63c858..b8b60c1 100755
--- a/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py
+++ b/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
#
# Copyright 2018, The Android Open Source Project
@@ -19,10 +19,8 @@
import argparse
import re
import sys
-import tempfile
import os
import logging
-import subprocess
import xml.etree.ElementTree as ET
import xml.etree.ElementInclude as EI
import xml.dom.minidom as MINIDOM
@@ -49,33 +47,35 @@
def parseArgs():
argparser = argparse.ArgumentParser(description="Parameter-Framework XML \
- audio criterion type file generator.\n\
- Exit with the number of (recoverable or not) error that occured.")
+ audio criterion type file generator.\n\
+ Exit with the number of (recoverable or not) \
+ error that occured.")
argparser.add_argument('--androidaudiobaseheader',
- help="Android Audio Base C header file, Mandatory.",
- metavar="ANDROID_AUDIO_BASE_HEADER",
- type=argparse.FileType('r'),
- required=True)
+ help="Android Audio Base C header file, Mandatory.",
+ metavar="ANDROID_AUDIO_BASE_HEADER",
+ type=argparse.FileType('r'),
+ required=True)
argparser.add_argument('--audiopolicyconfigurationfile',
- help="Android Audio Policy Configuration file, Mandatory.",
- metavar="(AUDIO_POLICY_CONFIGURATION_FILE)",
- type=argparse.FileType('r'),
- required=True)
+ help="Android Audio Policy Configuration file, Mandatory.",
+ metavar="(AUDIO_POLICY_CONFIGURATION_FILE)",
+ type=argparse.FileType('r'),
+ required=True)
argparser.add_argument('--criteriontypes',
- help="Criterion types XML base file, in \
- '<criterion_types> \
- <criterion_type name="" type=<inclusive|exclusive> values=<value1,value2,...>/>' \
- format. Mandatory.",
- metavar="CRITERION_TYPE_FILE",
- type=argparse.FileType('r'),
- required=True)
+ help="Criterion types XML base file, in \
+ '<criterion_types> \
+ <criterion_type name="" type=<inclusive|exclusive> \
+ values=<value1,value2,...>/>' \
+ format. Mandatory.",
+ metavar="CRITERION_TYPE_FILE",
+ type=argparse.FileType('r'),
+ required=True)
argparser.add_argument('--outputfile',
- help="Criterion types outputfile file. Mandatory.",
- metavar="CRITERION_TYPE_OUTPUT_FILE",
- type=argparse.FileType('w'),
- required=True)
+ help="Criterion types outputfile file. Mandatory.",
+ metavar="CRITERION_TYPE_OUTPUT_FILE",
+ type=argparse.FileType('w'),
+ required=True)
argparser.add_argument('--verbose',
- action='store_true')
+ action='store_true')
return argparser.parse_args()
@@ -120,7 +120,7 @@
reparsed = MINIDOM.parseString(xmlstr)
prettyXmlStr = reparsed.toprettyxml(newl='\r\n')
prettyXmlStr = os.linesep.join([s for s in prettyXmlStr.splitlines() if s.strip()])
- outputFile.write(prettyXmlStr.encode('utf-8'))
+ outputFile.write(prettyXmlStr)
def capitalizeLine(line):
return ' '.join((w.capitalize() for w in line.split(' ')))
@@ -137,30 +137,30 @@
#
address_criteria_mapping_table = {
'sink' : "OutputDevicesAddressesType",
- 'source' : "InputDevicesAddressesType" }
+ 'source' : "InputDevicesAddressesType"}
address_criteria = {
'OutputDevicesAddressesType' : [],
- 'InputDevicesAddressesType' : [] }
+ 'InputDevicesAddressesType' : []}
- oldWorkingDir = os.getcwd()
- print "Current working directory %s" % oldWorkingDir
+ old_working_dir = os.getcwd()
+ print("Current working directory %s" % old_working_dir)
- newDir = os.path.join(oldWorkingDir , audiopolicyconfigurationfile.name)
+ new_dir = os.path.join(old_working_dir, audiopolicyconfigurationfile.name)
policy_in_tree = ET.parse(audiopolicyconfigurationfile)
- os.chdir(os.path.dirname(os.path.normpath(newDir)))
+ os.chdir(os.path.dirname(os.path.normpath(new_dir)))
- print "new working directory %s" % os.getcwd()
+ print("new working directory %s" % os.getcwd())
policy_root = policy_in_tree.getroot()
EI.include(policy_root)
- os.chdir(oldWorkingDir)
+ os.chdir(old_working_dir)
for device in policy_root.iter('devicePort'):
for key in address_criteria_mapping_table.keys():
- if device.get('role') == key and device.get('address') :
+ if device.get('role') == key and device.get('address'):
logging.info("{}: <{}>".format(key, device.get('address')))
address_criteria[address_criteria_mapping_table[key]].append(device.get('address'))
@@ -188,15 +188,15 @@
all_criteria = {
'AndroidModeType' : {},
'OutputDevicesMaskType' : {},
- 'InputDevicesMaskType' : {} }
+ 'InputDevicesMaskType' : {}}
#
# _CNT, _MAX, _ALL and _NONE are prohibited values as ther are just helpers for enum users.
#
- ignored_values = [ 'CNT', 'MAX', 'ALL', 'NONE' ]
+ ignored_values = ['CNT', 'MAX', 'ALL', 'NONE']
criteria_pattern = re.compile(
- r"\s*(?P<type>(?:"+'|'.join(criterion_mapping_table.keys()) + "))\_" \
+ r"\s*(?P<type>(?:"+'|'.join(criterion_mapping_table.keys()) + "))_" \
r"(?P<literal>(?!" + '|'.join(ignored_values) + ")\w*)\s*=\s*" \
r"(?P<values>(?:0[xX])?[0-9a-fA-F]+)")
@@ -221,7 +221,7 @@
logging.info("criterion {} duplicated values:".format(criterion_name))
logging.info("{}:{}".format(numerical_value, literal))
logging.info("KEEPING LATEST")
- for key in all_criteria[criterion_name].keys():
+ for key in list(all_criteria[criterion_name]):
if all_criteria[criterion_name][key] == int(numerical_value, 0):
del all_criteria[criterion_name][key]
diff --git a/services/audiopolicy/engineconfigurable/tools/buildStrategiesStructureFile.py b/services/audiopolicy/engineconfigurable/tools/buildStrategiesStructureFile.py
index af40602..f69d346 100755
--- a/services/audiopolicy/engineconfigurable/tools/buildStrategiesStructureFile.py
+++ b/services/audiopolicy/engineconfigurable/tools/buildStrategiesStructureFile.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
#
# Copyright 2019, The Android Open Source Project
@@ -17,16 +17,12 @@
#
import argparse
-import re
import sys
-import tempfile
import os
import logging
-import subprocess
import xml.etree.ElementTree as ET
import xml.etree.ElementInclude as EI
import xml.dom.minidom as MINIDOM
-from collections import OrderedDict
#
# Helper script that helps to feed at build time the XML Product Strategies Structure file file used
@@ -46,33 +42,34 @@
def parseArgs():
argparser = argparse.ArgumentParser(description="Parameter-Framework XML \
- product strategies structure file generator.\n\
- Exit with the number of (recoverable or not) error that occured.")
+ product strategies structure file generator.\n\
+ Exit with the number of (recoverable or not) \
+ error that occured.")
argparser.add_argument('--audiopolicyengineconfigurationfile',
- help="Android Audio Policy Engine Configuration file, Mandatory.",
- metavar="(AUDIO_POLICY_ENGINE_CONFIGURATION_FILE)",
- type=argparse.FileType('r'),
- required=True)
+ help="Android Audio Policy Engine Configuration file, Mandatory.",
+ metavar="(AUDIO_POLICY_ENGINE_CONFIGURATION_FILE)",
+ type=argparse.FileType('r'),
+ required=True)
argparser.add_argument('--productstrategiesstructurefile',
- help="Product Strategies Structure XML base file, Mandatory.",
- metavar="STRATEGIES_STRUCTURE_FILE",
- type=argparse.FileType('r'),
- required=True)
+ help="Product Strategies Structure XML base file, Mandatory.",
+ metavar="STRATEGIES_STRUCTURE_FILE",
+ type=argparse.FileType('r'),
+ required=True)
argparser.add_argument('--outputfile',
- help="Product Strategies Structure output file, Mandatory.",
- metavar="STRATEGIES_STRUCTURE_OUTPUT_FILE",
- type=argparse.FileType('w'),
- required=True)
+ help="Product Strategies Structure output file, Mandatory.",
+ metavar="STRATEGIES_STRUCTURE_OUTPUT_FILE",
+ type=argparse.FileType('w'),
+ required=True)
argparser.add_argument('--verbose',
- action='store_true')
+ action='store_true')
return argparser.parse_args()
-def generateXmlStructureFile(strategies, strategyStructureInFile, outputFile):
+def generateXmlStructureFile(strategies, strategy_structure_in_file, output_file):
- logging.info("Importing strategyStructureInFile {}".format(strategyStructureInFile))
- strategies_in_tree = ET.parse(strategyStructureInFile)
+ logging.info("Importing strategy_structure_in_file {}".format(strategy_structure_in_file))
+ strategies_in_tree = ET.parse(strategy_structure_in_file)
strategies_root = strategies_in_tree.getroot()
strategy_components = strategies_root.find('ComponentType')
@@ -80,13 +77,15 @@
for strategy_name in strategies:
context_mapping = "".join(map(str, ["Name:", strategy_name]))
strategy_pfw_name = strategy_name.replace('STRATEGY_', '').lower()
- strategy_component_node = ET.SubElement(strategy_components, "Component", Name=strategy_pfw_name, Type="ProductStrategy", Mapping=context_mapping)
+ ET.SubElement(strategy_components, "Component",
+ Name=strategy_pfw_name, Type="ProductStrategy",
+ Mapping=context_mapping)
xmlstr = ET.tostring(strategies_root, encoding='utf8', method='xml')
reparsed = MINIDOM.parseString(xmlstr)
prettyXmlStr = reparsed.toprettyxml(newl='\r\n')
prettyXmlStr = os.linesep.join([s for s in prettyXmlStr.splitlines() if s.strip()])
- outputFile.write(prettyXmlStr.encode('utf-8'))
+ output_file.write(prettyXmlStr)
def capitalizeLine(line):
return ' '.join((w.capitalize() for w in line.split(' ')))
@@ -97,26 +96,27 @@
#
def parseAndroidAudioPolicyEngineConfigurationFile(audiopolicyengineconfigurationfile):
- logging.info("Checking Audio Policy Engine Configuration file {}".format(audiopolicyengineconfigurationfile))
+ logging.info("Checking Audio Policy Engine Configuration file {}".format(
+ audiopolicyengineconfigurationfile))
#
# extract all product strategies name from audio policy engine configuration file
#
strategy_names = []
- oldWorkingDir = os.getcwd()
- print "Current working directory %s" % oldWorkingDir
+ old_working_dir = os.getcwd()
+ print("Current working directory %s" % old_working_dir)
- newDir = os.path.join(oldWorkingDir , audiopolicyengineconfigurationfile.name)
+ new_dir = os.path.join(old_working_dir, audiopolicyengineconfigurationfile.name)
policy_engine_in_tree = ET.parse(audiopolicyengineconfigurationfile)
- os.chdir(os.path.dirname(os.path.normpath(newDir)))
+ os.chdir(os.path.dirname(os.path.normpath(new_dir)))
- print "new working directory %s" % os.getcwd()
+ print("new working directory %s" % os.getcwd())
policy_engine_root = policy_engine_in_tree.getroot()
EI.include(policy_engine_root)
- os.chdir(oldWorkingDir)
+ os.chdir(old_working_dir)
for strategy in policy_engine_root.iter('ProductStrategy'):
strategy_names.append(strategy.get('name'))
@@ -128,7 +128,8 @@
logging.root.setLevel(logging.INFO)
args = parseArgs()
- strategies = parseAndroidAudioPolicyEngineConfigurationFile(args.audiopolicyengineconfigurationfile)
+ strategies = parseAndroidAudioPolicyEngineConfigurationFile(
+ args.audiopolicyengineconfigurationfile)
product_strategies_structure = args.productstrategiesstructurefile
diff --git a/services/audiopolicy/engineconfigurable/tools/build_audio_pfw_settings.mk b/services/audiopolicy/engineconfigurable/tools/build_audio_pfw_settings.mk
deleted file mode 100644
index ac60ef7..0000000
--- a/services/audiopolicy/engineconfigurable/tools/build_audio_pfw_settings.mk
+++ /dev/null
@@ -1,38 +0,0 @@
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_TAGS := optional
-LOCAL_ADDITIONAL_DEPENDENCIES += \
- $(HOST_OUT_EXECUTABLES)/domainGeneratorPolicy.py \
- $(PFW_TOPLEVEL_FILE) $(PFW_CRITERIA_FILE) $(PFW_CRITERION_TYPES_FILE)
-
-include $(BUILD_SYSTEM)/base_rules.mk
-
-$(LOCAL_BUILT_MODULE): MY_CRITERION_TYPES_FILE := $(PFW_CRITERION_TYPES_FILE)
-$(LOCAL_BUILT_MODULE): MY_TOOL := $(HOST_OUT_EXECUTABLES)/domainGeneratorPolicy.py
-$(LOCAL_BUILT_MODULE): MY_TOPLEVEL_FILE := $(PFW_TOPLEVEL_FILE)
-$(LOCAL_BUILT_MODULE): MY_CRITERIA_FILE := $(PFW_CRITERIA_FILE)
-$(LOCAL_BUILT_MODULE): MY_TUNING_FILE := $(PFW_TUNING_FILE)
-$(LOCAL_BUILT_MODULE): MY_EDD_FILES := $(PFW_EDD_FILES)
-$(LOCAL_BUILT_MODULE): MY_DOMAIN_FILES := $(PFW_DOMAIN_FILES)
-$(LOCAL_BUILT_MODULE): MY_SCHEMAS_DIR := $(PFW_SCHEMAS_DIR)
-$(LOCAL_BUILT_MODULE): MY_CRITERION_TYPES_FILE := $(PFW_CRITERION_TYPES_FILE)
-$(LOCAL_BUILT_MODULE): $(LOCAL_ADDITIONAL_DEPENDENCIES)
-
- "$(MY_TOOL)" --validate \
- --toplevel-config "$(MY_TOPLEVEL_FILE)" \
- --criteria "$(MY_CRITERIA_FILE)" \
- --criteriontypes "$(MY_CRITERION_TYPES_FILE)" \
- --initial-settings $(MY_TUNING_FILE) \
- --add-edds $(MY_EDD_FILES) \
- --add-domains $(MY_DOMAIN_FILES) \
- --schemas-dir $(MY_SCHEMAS_DIR) > "$@"
-
-
-# Clear variables for further use
-PFW_TOPLEVEL_FILE :=
-PFW_STRUCTURE_FILES :=
-PFW_CRITERIA_FILE :=
-PFW_CRITERION_TYPES_FILE :=
-PFW_TUNING_FILE :=
-PFW_EDD_FILES :=
-PFW_DOMAIN_FILES :=
-PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
diff --git a/services/audiopolicy/engineconfigurable/tools/domainGeneratorPolicy.py b/services/audiopolicy/engineconfigurable/tools/domainGeneratorPolicy.py
index 4dec9a2..b0c4b66 100755
--- a/services/audiopolicy/engineconfigurable/tools/domainGeneratorPolicy.py
+++ b/services/audiopolicy/engineconfigurable/tools/domainGeneratorPolicy.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
#
# Copyright 2018, The Android Open Source Project
@@ -16,12 +16,7 @@
# limitations under the License.
#
-import EddParser
-from PFWScriptGenerator import PfwScriptTranslator
-import hostConfig
-
import argparse
-import re
import sys
import tempfile
import os
@@ -29,6 +24,10 @@
import subprocess
import xml.etree.ElementTree as ET
+import EddParser
+from PFWScriptGenerator import PfwScriptTranslator
+import hostConfig
+
#
# In order to build the XML Settings file at build time, an instance of the parameter-framework
# shall be started and fed with all the criterion types/criteria that will be used by
@@ -39,61 +38,67 @@
def parseArgs():
argparser = argparse.ArgumentParser(description="Parameter-Framework XML \
- Settings file generator.\n\
- Exit with the number of (recoverable or not) error that occured.")
+ Settings file generator.\n\
+ Exit with the number of (recoverable or not) \
+ error that occured.")
+ argparser.add_argument('--domain-generator-tool',
+ help="ParameterFramework domain generator tool. Mandatory.",
+ metavar="PFW_DOMAIN_GENERATOR_TOOL",
+ required=True)
argparser.add_argument('--toplevel-config',
- help="Top-level parameter-framework configuration file. Mandatory.",
- metavar="TOPLEVEL_CONFIG_FILE",
- required=True)
+ help="Top-level parameter-framework configuration file. Mandatory.",
+ metavar="TOPLEVEL_CONFIG_FILE",
+ required=True)
argparser.add_argument('--criteria',
- help="Criteria file, in XML format: \
- in '<criteria> \
- <criterion name="" type=""/> \
- </criteria>' \
- format. Mandatory.",
- metavar="CRITERIA_FILE",
- type=argparse.FileType('r'),
- required=True)
+ help="Criteria file, in XML format: \
+ in '<criteria> \
+ <criterion name="" type=""/> \
+ </criteria>' \
+ format. Mandatory.",
+ metavar="CRITERIA_FILE",
+ type=argparse.FileType('r'),
+ required=True)
argparser.add_argument('--criteriontypes',
- help="Criterion types XML file, in \
- '<criterion_types> \
- <criterion_type name="" type=<inclusive|exclusive> values=<value1,value2,...>/> \
- </criterion_types>' \
- format. Mandatory.",
- metavar="CRITERION_TYPE_FILE",
- type=argparse.FileType('r'),
- required=False)
+ help="Criterion types XML file, in \
+ '<criterion_types> \
+ <criterion_type name="" type=<inclusive|exclusive> \
+ values=<value1,value2,...>/> \
+ </criterion_types>' \
+ format. Mandatory.",
+ metavar="CRITERION_TYPE_FILE",
+ type=argparse.FileType('r'),
+ required=False)
argparser.add_argument('--initial-settings',
- help="Initial XML settings file (containing a \
- <ConfigurableDomains> tag",
- nargs='?',
- default=None,
- metavar="XML_SETTINGS_FILE")
+ help="Initial XML settings file (containing a \
+ <ConfigurableDomains> tag",
+ nargs='?',
+ default=None,
+ metavar="XML_SETTINGS_FILE")
argparser.add_argument('--add-domains',
- help="List of single domain files (each containing a single \
- <ConfigurableDomain> tag",
- metavar="XML_DOMAIN_FILE",
- nargs='*',
- dest='xml_domain_files',
- default=[])
+ help="List of single domain files (each containing a single \
+ <ConfigurableDomain> tag",
+ metavar="XML_DOMAIN_FILE",
+ nargs='*',
+ dest='xml_domain_files',
+ default=[])
argparser.add_argument('--add-edds',
- help="List of files in EDD syntax (aka \".pfw\" files)",
- metavar="EDD_FILE",
- type=argparse.FileType('r'),
- nargs='*',
- default=[],
- dest='edd_files')
+ help="List of files in EDD syntax (aka \".pfw\" files)",
+ metavar="EDD_FILE",
+ type=argparse.FileType('r'),
+ nargs='*',
+ default=[],
+ dest='edd_files')
argparser.add_argument('--schemas-dir',
- help="Directory of parameter-framework XML Schemas for generation \
- validation",
- default=None)
+ help="Directory of parameter-framework XML Schemas for generation \
+ validation",
+ default=None)
argparser.add_argument('--target-schemas-dir',
- help="Ignored. Kept for retro-compatibility")
+ help="Ignored. Kept for retro-compatibility")
argparser.add_argument('--validate',
- help="Validate the settings against XML schemas",
- action='store_true')
+ help="Validate the settings against XML schemas",
+ action='store_true')
argparser.add_argument('--verbose',
- action='store_true')
+ action='store_true')
return argparser.parse_args()
@@ -112,7 +117,6 @@
logging.info("Importing criterionTypesFile {}".format(criterionTypesFile))
criteria_root = criteria_tree.getroot()
- criterion_types_root = criterion_types_tree.getroot()
all_criteria = []
for criterion in criteria_root.findall('criterion'):
@@ -165,7 +169,7 @@
try:
root.propagate()
- except EddParser.MyPropagationError, ex :
+ except EddParser.MyPropagationError as ex:
logging.critical(str(ex))
logging.info("EXIT ON FAILURE")
exit(1)
@@ -179,32 +183,32 @@
# It takes as input the collection of criteria, the domains and the simplified settings read from
# pfw.
#
-def generateDomainCommands(logging, all_criteria, initial_settings, xml_domain_files, parsed_edds):
- # create and inject all the criteria
- logging.info("Creating all criteria")
- for criterion in all_criteria:
- yield ["createSelectionCriterion", criterion['inclusive'],
- criterion['name']] + criterion['values']
+def generateDomainCommands(logger, all_criteria, initial_settings, xml_domain_files, parsed_edds):
+ # create and inject all the criteria
+ logger.info("Creating all criteria")
+ for criterion in all_criteria:
+ yield ["createSelectionCriterion", criterion['inclusive'],
+ criterion['name']] + criterion['values']
- yield ["start"]
+ yield ["start"]
- # Import initial settings file
- if initial_settings:
- logging.info("Importing initial settings file {}".format(initial_settings))
- yield ["importDomainsWithSettingsXML", initial_settings]
+ # Import initial settings file
+ if initial_settings:
+ logger.info("Importing initial settings file {}".format(initial_settings))
+ yield ["importDomainsWithSettingsXML", initial_settings]
- # Import each standalone domain files
- for domain_file in xml_domain_files:
- logging.info("Importing single domain file {}".format(domain_file))
- yield ["importDomainWithSettingsXML", domain_file]
+ # Import each standalone domain files
+ for domain_file in xml_domain_files:
+ logger.info("Importing single domain file {}".format(domain_file))
+ yield ["importDomainWithSettingsXML", domain_file]
- # Generate the script for each EDD file
- for filename, parsed_edd in parsed_edds:
- logging.info("Translating and injecting EDD file {}".format(filename))
- translator = PfwScriptTranslator()
- parsed_edd.translate(translator)
- for command in translator.getScript():
- yield command
+ # Generate the script for each EDD file
+ for filename, parsed_edd in parsed_edds:
+ logger.info("Translating and injecting EDD file {}".format(filename))
+ translator = PfwScriptTranslator()
+ parsed_edd.translate(translator)
+ for command in translator.getScript():
+ yield command
#
# Entry point of the domain generator.
@@ -232,30 +236,29 @@
prefix="TMPdomainGeneratorPFConfig_")
install_path = os.path.dirname(os.path.realpath(args.toplevel_config))
- hostConfig.configure(
- infile=args.toplevel_config,
- outfile=fake_toplevel_config,
- structPath=install_path)
+ hostConfig.configure(infile=args.toplevel_config,
+ outfile=fake_toplevel_config,
+ structPath=install_path)
fake_toplevel_config.close()
# Create the connector. Pipe its input to us in order to write commands;
# connect its output to stdout in order to have it dump the domains
# there; connect its error output to stderr.
- connector = subprocess.Popen(["domainGeneratorConnector",
- fake_toplevel_config.name,
- 'verbose' if args.verbose else 'no-verbose',
- 'validate' if args.validate else 'no-validate',
- args.schemas_dir],
- stdout=sys.stdout, stdin=subprocess.PIPE, stderr=sys.stderr)
+ connector = subprocess.Popen([args.domain_generator_tool,
+ fake_toplevel_config.name,
+ 'verbose' if args.verbose else 'no-verbose',
+ 'validate' if args.validate else 'no-validate',
+ args.schemas_dir],
+ stdout=sys.stdout, stdin=subprocess.PIPE, stderr=sys.stderr)
initial_settings = None
if args.initial_settings:
initial_settings = os.path.realpath(args.initial_settings)
for command in generateDomainCommands(logging, all_criteria, initial_settings,
- args.xml_domain_files, parsed_edds):
- connector.stdin.write('\0'.join(command))
- connector.stdin.write("\n")
+ args.xml_domain_files, parsed_edds):
+ connector.stdin.write('\0'.join(command).encode('utf-8'))
+ connector.stdin.write("\n".encode('utf-8'))
# Closing the connector's input triggers the domain generation
connector.stdin.close()
diff --git a/services/audiopolicy/engineconfigurable/tools/provision_criterion_types_from_android_headers.mk b/services/audiopolicy/engineconfigurable/tools/provision_criterion_types_from_android_headers.mk
deleted file mode 100644
index dab5a0f..0000000
--- a/services/audiopolicy/engineconfigurable/tools/provision_criterion_types_from_android_headers.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_TAGS := optional
-LOCAL_ADDITIONAL_DEPENDENCIES += \
- $(HOST_OUT_EXECUTABLES)/buildPolicyCriterionTypes.py \
- $(CRITERION_TYPES_FILE) $(AUDIO_POLICY_CONFIGURATION_FILE) \
- $(ANDROID_AUDIO_BASE_HEADER_FILE)
-
-include $(BUILD_SYSTEM)/base_rules.mk
-
-$(LOCAL_BUILT_MODULE): MY_CRITERION_TYPES_FILE := $(CRITERION_TYPES_FILE)
-$(LOCAL_BUILT_MODULE): MY_ANDROID_AUDIO_BASE_HEADER_FILE := $(ANDROID_AUDIO_BASE_HEADER_FILE)
-$(LOCAL_BUILT_MODULE): MY_AUDIO_POLICY_CONFIGURATION_FILE := $(AUDIO_POLICY_CONFIGURATION_FILE)
-$(LOCAL_BUILT_MODULE): MY_CRITERION_TOOL := $(HOST_OUT_EXECUTABLES)/buildPolicyCriterionTypes.py
-$(LOCAL_BUILT_MODULE): $(LOCAL_ADDITIONAL_DEPENDENCIES)
-
- "$(MY_CRITERION_TOOL)" \
- --androidaudiobaseheader "$(MY_ANDROID_AUDIO_BASE_HEADER_FILE)" \
- --audiopolicyconfigurationfile "$(MY_AUDIO_POLICY_CONFIGURATION_FILE)" \
- --criteriontypes "$(MY_CRITERION_TYPES_FILE)" \
- --outputfile "$(@)"
-
-# Clear variables for further use
-CRITERION_TYPES_FILE :=
-ANDROID_AUDIO_BASE_HEADER_FILE :=
-AUDIO_POLICY_CONFIGURATION_FILE :=
diff --git a/services/audiopolicy/engineconfigurable/tools/provision_strategies_structure.mk b/services/audiopolicy/engineconfigurable/tools/provision_strategies_structure.mk
deleted file mode 100644
index f2b1a19..0000000
--- a/services/audiopolicy/engineconfigurable/tools/provision_strategies_structure.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_TAGS := optional
-LOCAL_ADDITIONAL_DEPENDENCIES += \
- $(HOST_OUT_EXECUTABLES)/buildStrategiesStructureFile.py \
- $(STRATEGIES_STRUCTURE_FILE) $(AUDIO_POLICY_ENGINE_CONFIGURATION_FILE)
-
-include $(BUILD_SYSTEM)/base_rules.mk
-
-$(LOCAL_BUILT_MODULE): MY_STRATEGIES_STRUCTURE_FILE := $(STRATEGIES_STRUCTURE_FILE)
-$(LOCAL_BUILT_MODULE): MY_AUDIO_POLICY_ENGINE_CONFIGURATION_FILE := $(AUDIO_POLICY_ENGINE_CONFIGURATION_FILE)
-$(LOCAL_BUILT_MODULE): MY_PROVISION_TOOL := $(HOST_OUT_EXECUTABLES)/buildStrategiesStructureFile.py
-$(LOCAL_BUILT_MODULE): $(LOCAL_ADDITIONAL_DEPENDENCIES)
-
- "$(MY_PROVISION_TOOL)" \
- --audiopolicyengineconfigurationfile "$(MY_AUDIO_POLICY_ENGINE_CONFIGURATION_FILE)" \
- --productstrategiesstructurefile "$(MY_STRATEGIES_STRUCTURE_FILE)" \
- --outputfile "$(@)"
-
-# Clear variables for further use
-STRATEGIES_STRUCTURE_FILE :=
-AUDIO_POLICY_ENGINE_CONFIGURATION_FILE :=
diff --git a/services/audiopolicy/engineconfigurable/wrapper/Android.bp b/services/audiopolicy/engineconfigurable/wrapper/Android.bp
index 6f59487..301ecc0 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/Android.bp
+++ b/services/audiopolicy/engineconfigurable/wrapper/Android.bp
@@ -11,7 +11,6 @@
"libbase_headers",
"libaudiopolicycommon",
],
- static_libs: ["libaudiopolicycomponents"],
shared_libs: [
"liblog",
"libutils",
diff --git a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
index 4b57444..63990ac 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
+++ b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
@@ -92,7 +92,8 @@
template <>
struct ParameterManagerWrapper::parameterManagerElementSupported<ISelectionCriterionTypeInterface> {};
-ParameterManagerWrapper::ParameterManagerWrapper()
+ParameterManagerWrapper::ParameterManagerWrapper(bool enableSchemaVerification,
+ const std::string &schemaUri)
: mPfwConnectorLogger(new ParameterMgrPlatformConnectorLogger)
{
// Connector
@@ -104,6 +105,15 @@
// Logger
mPfwConnector->setLogger(mPfwConnectorLogger);
+
+ // Schema validation
+ std::string error;
+ bool ret = mPfwConnector->setValidateSchemasOnStart(enableSchemaVerification, error);
+ ALOGE_IF(!ret, "Failed to activate schema validation: %s", error.c_str());
+ if (enableSchemaVerification && ret && !schemaUri.empty()) {
+ ALOGE("Schema verification activated with schema URI: %s", schemaUri.c_str());
+ mPfwConnector->setSchemaUri(schemaUri);
+ }
}
status_t ParameterManagerWrapper::addCriterion(const std::string &name, bool isInclusive,
@@ -145,11 +155,10 @@
delete mPfwConnector;
}
-status_t ParameterManagerWrapper::start()
+status_t ParameterManagerWrapper::start(std::string &error)
{
ALOGD("%s: in", __FUNCTION__);
/// Start PFW
- std::string error;
if (!mPfwConnector->start(error)) {
ALOGE("%s: Policy PFW start error: %s", __FUNCTION__, error.c_str());
return NO_INIT;
@@ -253,13 +262,13 @@
return interface->getLiteralValue(valueToCheck, literalValue);
}
-status_t ParameterManagerWrapper::setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
- audio_policy_dev_state_t state)
+status_t ParameterManagerWrapper::setDeviceConnectionState(
+ audio_devices_t type, const std::string address, audio_policy_dev_state_t state)
{
- std::string criterionName = audio_is_output_device(devDesc->type()) ?
+ std::string criterionName = audio_is_output_device(type) ?
gOutputDeviceAddressCriterionName : gInputDeviceAddressCriterionName;
- ALOGV("%s: device with address %s %s", __FUNCTION__, devDesc->address().string(),
+ ALOGV("%s: device with address %s %s", __FUNCTION__, address.c_str(),
state != AUDIO_POLICY_DEVICE_STATE_AVAILABLE? "disconnected" : "connected");
ISelectionCriterionInterface *criterion =
getElement<ISelectionCriterionInterface>(criterionName, mPolicyCriteria);
@@ -271,8 +280,9 @@
auto criterionType = criterion->getCriterionType();
int deviceAddressId;
- if (not criterionType->getNumericalValue(devDesc->address().string(), deviceAddressId)) {
- ALOGW("%s: unknown device address reported (%s)", __FUNCTION__, devDesc->address().c_str());
+ if (not criterionType->getNumericalValue(address.c_str(), deviceAddressId)) {
+ ALOGW("%s: unknown device address reported (%s) for criterion %s", __FUNCTION__,
+ address.c_str(), criterionName.c_str());
return BAD_TYPE;
}
int currentValueMask = criterion->getCriterionState();
diff --git a/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h b/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
index 5bfad29..62b129a 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
+++ b/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
@@ -16,10 +16,6 @@
#pragma once
-#include <AudioGain.h>
-#include <AudioPort.h>
-#include <HwModule.h>
-#include <DeviceDescriptor.h>
#include <system/audio.h>
#include <system/audio_policy.h>
#include <utils/Errors.h>
@@ -48,16 +44,18 @@
using Criteria = std::map<std::string, ISelectionCriterionInterface *>;
public:
- ParameterManagerWrapper();
+ ParameterManagerWrapper(bool enableSchemaVerification = false,
+ const std::string &schemaUri = {});
~ParameterManagerWrapper();
/**
* Starts the platform state service.
* It starts the parameter framework policy instance.
+ * @param[out] contains human readable error if starts failed
*
- * @return NO_ERROR if success, error code otherwise.
+ * @return NO_ERROR if success, error code otherwise, and error is set to human readable string.
*/
- status_t start();
+ status_t start(std::string &error);
/**
* The following API wrap policy action to criteria
@@ -118,7 +116,15 @@
*/
status_t setAvailableOutputDevices(audio_devices_t outputDevices);
- status_t setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
+ /**
+ * @brief setDeviceConnectionState propagates a state event on a given device(s)
+ * @param type bit mask of the device whose state has changed
+ * @param address of the device whose state has changed
+ * @param state new state of the given device
+ * @return NO_ERROR if new state corretly propagated to Engine Parameter-Framework, error
+ * code otherwise.
+ */
+ status_t setDeviceConnectionState(audio_devices_t type, const std::string address,
audio_policy_dev_state_t state);
/**
diff --git a/services/audiopolicy/enginedefault/Android.bp b/services/audiopolicy/enginedefault/Android.bp
index 7b42c6a..aaf4158 100644
--- a/services/audiopolicy/enginedefault/Android.bp
+++ b/services/audiopolicy/enginedefault/Android.bp
@@ -1,16 +1,15 @@
cc_library_shared {
name: "libaudiopolicyenginedefault",
- export_include_dirs: ["include"],
srcs: [
"src/Engine.cpp",
"src/EngineInstance.cpp",
],
cflags: [
+ "-fvisibility=hidden",
"-Wall",
"-Werror",
"-Wextra",
],
- local_include_dirs: ["include"],
header_libs: [
"libbase_headers",
"libaudiopolicycommon",
@@ -22,6 +21,7 @@
"libaudiopolicyengine_config",
],
shared_libs: [
+ "libaudiofoundation",
"liblog",
"libcutils",
"libutils",
diff --git a/services/audiopolicy/enginedefault/config/example/Android.bp b/services/audiopolicy/enginedefault/config/example/Android.bp
new file mode 100644
index 0000000..0bfcaa1
--- /dev/null
+++ b/services/audiopolicy/enginedefault/config/example/Android.bp
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+// Import this namespace in order to use AOSP Phone with Default Engine configuration example
+
+soong_namespace {
+}
+
+prebuilt_etc {
+ name: "audio_policy_engine_configuration.xml",
+ vendor: true,
+ src: "phone/audio_policy_engine_configuration.xml",
+ required: [
+ ":audio_policy_engine_stream_volumes.xml",
+ ":audio_policy_engine_default_stream_volumes.xml",
+ ":audio_policy_engine_product_strategies.xml",
+ ],
+}
+prebuilt_etc {
+ name: "audio_policy_engine_product_strategies.xml",
+ vendor: true,
+ src: "phone/audio_policy_engine_product_strategies.xml",
+}
+prebuilt_etc {
+ name: "audio_policy_engine_stream_volumes.xml",
+ vendor: true,
+ src: "phone/audio_policy_engine_stream_volumes.xml",
+}
+prebuilt_etc {
+ name: "audio_policy_engine_default_stream_volumes.xml",
+ vendor: true,
+ src: "phone/audio_policy_engine_default_stream_volumes.xml",
+}
diff --git a/services/audiopolicy/enginedefault/config/example/Android.mk b/services/audiopolicy/enginedefault/config/example/Android.mk
deleted file mode 100644
index 0badac8..0000000
--- a/services/audiopolicy/enginedefault/config/example/Android.mk
+++ /dev/null
@@ -1,48 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-##################################################################
-# CONFIGURATION TOP FILE
-##################################################################
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), phone_default)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_configuration.xml
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
-
-LOCAL_REQUIRED_MODULES := \
- audio_policy_engine_product_strategies.xml \
- audio_policy_engine_stream_volumes.xml \
- audio_policy_engine_default_stream_volumes.xml
-
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_product_strategies.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_stream_volumes.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_default_stream_volumes.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-endif # ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), phone_default)
diff --git a/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_product_strategies.xml b/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_product_strategies.xml
index 9398743..a7388da 100644
--- a/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_product_strategies.xml
+++ b/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_product_strategies.xml
@@ -72,6 +72,12 @@
<Attributes> <Usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/> </Attributes>
<Attributes></Attributes>
</AttributesGroup>
+ <AttributesGroup streamType="AUDIO_STREAM_ASSISTANT" volumeGroup="assistant">
+ <Attributes>
+ <ContentType value="AUDIO_CONTENT_TYPE_SPEECH"/>
+ <Usage value="AUDIO_USAGE_ASSISTANT"/>
+ </Attributes>
+ </AttributesGroup>
<AttributesGroup streamType="AUDIO_STREAM_SYSTEM" volumeGroup="system">
<Attributes> <Usage value="AUDIO_USAGE_ASSISTANCE_SONIFICATION"/> </Attributes>
</AttributesGroup>
@@ -91,20 +97,5 @@
</AttributesGroup>
</ProductStrategy>
- <!-- Routing Strategy rerouting may be removed as following media??? -->
- <ProductStrategy name="STRATEGY_REROUTING">
- <AttributesGroup streamType="AUDIO_STREAM_REROUTING" volumeGroup="rerouting">
- <Attributes></Attributes>
- </AttributesGroup>
- </ProductStrategy>
-
- <!-- Default product strategy has empty attributes -->
- <ProductStrategy name="STRATEGY_PATCH">
- <AttributesGroup streamType="AUDIO_STREAM_PATCH" volumeGroup="patch">
- <Attributes></Attributes>
- </AttributesGroup>
- </ProductStrategy>
-
-
</ProductStrategies>
diff --git a/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_stream_volumes.xml b/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_stream_volumes.xml
index 707a184..d5c3896 100644
--- a/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_stream_volumes.xml
+++ b/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_stream_volumes.xml
@@ -207,25 +207,15 @@
</volumeGroup>
<volumeGroup>
- <name>rerouting</name>
+ <name>assistant</name>
<indexMin>0</indexMin>
- <indexMax>1</indexMax>
- <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="FULL_SCALE_VOLUME_CURVE"/>
- <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="FULL_SCALE_VOLUME_CURVE"/>
- <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="FULL_SCALE_VOLUME_CURVE"/>
- <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="FULL_SCALE_VOLUME_CURVE"/>
- <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="FULL_SCALE_VOLUME_CURVE"/>
+ <indexMax>15</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
</volumeGroup>
- <volumeGroup>
- <name>patch</name>
- <indexMin>0</indexMin>
- <indexMax>1</indexMax>
- <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="FULL_SCALE_VOLUME_CURVE"/>
- <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="FULL_SCALE_VOLUME_CURVE"/>
- <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="FULL_SCALE_VOLUME_CURVE"/>
- <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="FULL_SCALE_VOLUME_CURVE"/>
- <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="FULL_SCALE_VOLUME_CURVE"/>
- </volumeGroup>
</volumeGroups>
diff --git a/services/audiopolicy/enginedefault/include/AudioPolicyEngineInstance.h b/services/audiopolicy/enginedefault/include/AudioPolicyEngineInstance.h
deleted file mode 100644
index 1e329f0..0000000
--- a/services/audiopolicy/enginedefault/include/AudioPolicyEngineInstance.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-class AudioPolicyManagerInterface;
-
-namespace android
-{
-namespace audio_policy
-{
-
-class Engine;
-
-class EngineInstance
-{
-protected:
- EngineInstance();
-
-public:
- virtual ~EngineInstance();
-
- /**
- * Get Audio Policy Engine instance.
- *
- * @return pointer to Route Manager Instance object.
- */
- static EngineInstance *getInstance();
-
- /**
- * Interface query.
- * The first client of an interface of the policy engine will start the singleton.
- *
- * @tparam RequestedInterface: interface that the client is wishing to retrieve.
- *
- * @return interface handle.
- */
- template <class RequestedInterface>
- RequestedInterface *queryInterface() const;
-
-protected:
- /**
- * Get Audio Policy Engine instance.
- *
- * @return Audio Policy Engine singleton.
- */
- Engine *getEngine() const;
-
-private:
- /* Copy facilities are put private to disable copy. */
- EngineInstance(const EngineInstance &object);
- EngineInstance &operator=(const EngineInstance &object);
-};
-
-/**
- * Limit template instantation to supported type interfaces.
- * Compile time error will claim if invalid interface is requested.
- */
-template <>
-AudioPolicyManagerInterface *EngineInstance::queryInterface() const;
-
-} // namespace audio_policy
-} // namespace android
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
old mode 100644
new mode 100755
index 04170ac..b14d2bb
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -27,10 +27,11 @@
#include "Engine.h"
#include <android-base/macros.h>
#include <AudioPolicyManagerObserver.h>
-#include <AudioPort.h>
+#include <PolicyAudioPort.h>
#include <IOProfile.h>
#include <AudioIODescriptorInterface.h>
#include <policy.h>
+#include <media/AudioContainers.h>
#include <utils/String8.h>
#include <utils/Log.h>
@@ -40,19 +41,23 @@
{
struct legacy_strategy_map { const char *name; legacy_strategy id; };
-static const std::vector<legacy_strategy_map> gLegacyStrategy = {
- { "STRATEGY_NONE", STRATEGY_NONE },
- { "STRATEGY_MEDIA", STRATEGY_MEDIA },
- { "STRATEGY_PHONE", STRATEGY_PHONE },
- { "STRATEGY_SONIFICATION", STRATEGY_SONIFICATION },
- { "STRATEGY_SONIFICATION_RESPECTFUL", STRATEGY_SONIFICATION_RESPECTFUL },
- { "STRATEGY_DTMF", STRATEGY_DTMF },
- { "STRATEGY_ENFORCED_AUDIBLE", STRATEGY_ENFORCED_AUDIBLE },
- { "STRATEGY_TRANSMITTED_THROUGH_SPEAKER", STRATEGY_TRANSMITTED_THROUGH_SPEAKER },
- { "STRATEGY_ACCESSIBILITY", STRATEGY_ACCESSIBILITY },
- { "STRATEGY_REROUTING", STRATEGY_REROUTING },
- { "STRATEGY_PATCH", STRATEGY_REROUTING }, // boiler to manage stream patch volume
-};
+static const std::vector<legacy_strategy_map>& getLegacyStrategy() {
+ static const std::vector<legacy_strategy_map> legacyStrategy = {
+ { "STRATEGY_NONE", STRATEGY_NONE },
+ { "STRATEGY_MEDIA", STRATEGY_MEDIA },
+ { "STRATEGY_PHONE", STRATEGY_PHONE },
+ { "STRATEGY_SONIFICATION", STRATEGY_SONIFICATION },
+ { "STRATEGY_SONIFICATION_RESPECTFUL", STRATEGY_SONIFICATION_RESPECTFUL },
+ { "STRATEGY_DTMF", STRATEGY_DTMF },
+ { "STRATEGY_ENFORCED_AUDIBLE", STRATEGY_ENFORCED_AUDIBLE },
+ { "STRATEGY_TRANSMITTED_THROUGH_SPEAKER", STRATEGY_TRANSMITTED_THROUGH_SPEAKER },
+ { "STRATEGY_ACCESSIBILITY", STRATEGY_ACCESSIBILITY },
+ { "STRATEGY_REROUTING", STRATEGY_REROUTING },
+ { "STRATEGY_PATCH", STRATEGY_REROUTING }, // boiler to manage stream patch volume
+ { "STRATEGY_CALL_ASSISTANT", STRATEGY_CALL_ASSISTANT },
+ };
+ return legacyStrategy;
+}
Engine::Engine()
{
@@ -61,7 +66,8 @@
"Policy Engine configuration is partially invalid, skipped %zu elements",
result.nbSkippedElement);
- for (const auto &strategy : gLegacyStrategy) {
+ auto legacyStrategy = getLegacyStrategy();
+ for (const auto &strategy : legacyStrategy) {
mLegacyStrategyMap[getProductStrategyByName(strategy.name)] = strategy.id;
}
}
@@ -136,27 +142,23 @@
return EngineBase::setForceUse(usage, config);
}
-audio_devices_t Engine::getDeviceForStrategyInt(legacy_strategy strategy,
- DeviceVector availableOutputDevices,
- DeviceVector availableInputDevices,
- const SwAudioOutputCollection &outputs,
- uint32_t outputDeviceTypesToIgnore) const
+DeviceVector Engine::getDevicesForStrategyInt(legacy_strategy strategy,
+ DeviceVector availableOutputDevices,
+ DeviceVector availableInputDevices,
+ const SwAudioOutputCollection &outputs) const
{
- uint32_t device = AUDIO_DEVICE_NONE;
- uint32_t availableOutputDevicesType =
- availableOutputDevices.types() & ~outputDeviceTypesToIgnore;
+ DeviceVector devices;
switch (strategy) {
case STRATEGY_TRANSMITTED_THROUGH_SPEAKER:
- device = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
+ devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
break;
case STRATEGY_SONIFICATION_RESPECTFUL:
if (isInCall() || outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_VOICE_CALL))) {
- device = getDeviceForStrategyInt(
- STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs,
- outputDeviceTypesToIgnore);
+ devices = getDevicesForStrategyInt(
+ STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs);
} else {
bool media_active_locally =
outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_MUSIC),
@@ -165,17 +167,18 @@
toVolumeSource(AUDIO_STREAM_ACCESSIBILITY),
SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY);
// routing is same as media without the "remote" device
- device = getDeviceForStrategyInt(STRATEGY_MEDIA,
+ availableOutputDevices.remove(availableOutputDevices.getDevicesFromType(
+ AUDIO_DEVICE_OUT_REMOTE_SUBMIX));
+ devices = getDevicesForStrategyInt(STRATEGY_MEDIA,
availableOutputDevices,
- availableInputDevices, outputs,
- AUDIO_DEVICE_OUT_REMOTE_SUBMIX | outputDeviceTypesToIgnore);
+ availableInputDevices, outputs);
// if no media is playing on the device, check for mandatory use of "safe" speaker
// when media would have played on speaker, and the safe speaker path is available
- if (!media_active_locally
- && (device & AUDIO_DEVICE_OUT_SPEAKER)
- && (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
- device |= AUDIO_DEVICE_OUT_SPEAKER_SAFE;
- device &= ~AUDIO_DEVICE_OUT_SPEAKER;
+ if (!media_active_locally) {
+ devices.replaceDevicesByType(
+ AUDIO_DEVICE_OUT_SPEAKER,
+ availableOutputDevices.getDevicesFromType(
+ AUDIO_DEVICE_OUT_SPEAKER_SAFE));
}
}
break;
@@ -183,9 +186,8 @@
case STRATEGY_DTMF:
if (!isInCall()) {
// when off call, DTMF strategy follows the same rules as MEDIA strategy
- device = getDeviceForStrategyInt(
- STRATEGY_MEDIA, availableOutputDevices, availableInputDevices, outputs,
- outputDeviceTypesToIgnore);
+ devices = getDevicesForStrategyInt(
+ STRATEGY_MEDIA, availableOutputDevices, availableInputDevices, outputs);
break;
}
// when in call, DTMF and PHONE strategies follow the same rules
@@ -197,24 +199,28 @@
// - cannot route from voice call RX OR
// - audio HAL version is < 3.0 and TX device is on the primary HW module
if (getPhoneState() == AUDIO_MODE_IN_CALL) {
- audio_devices_t txDevice = getDeviceForInputSource(AUDIO_SOURCE_VOICE_COMMUNICATION);
+ audio_devices_t txDevice = getDeviceForInputSource(
+ AUDIO_SOURCE_VOICE_COMMUNICATION)->type();
sp<AudioOutputDescriptor> primaryOutput = outputs.getPrimaryOutput();
- audio_devices_t availPrimaryInputDevices =
- availableInputDevices.getDeviceTypesFromHwModule(primaryOutput->getModuleHandle());
+ LOG_ALWAYS_FATAL_IF(primaryOutput == nullptr, "Primary output not found");
+ DeviceVector availPrimaryInputDevices =
+ availableInputDevices.getDevicesFromHwModule(primaryOutput->getModuleHandle());
// TODO: getPrimaryOutput return only devices from first module in
// audio_policy_configuration.xml, hearing aid is not there, but it's
// a primary device
// FIXME: this is not the right way of solving this problem
- audio_devices_t availPrimaryOutputDevices =
- (primaryOutput->supportedDevices().types() | AUDIO_DEVICE_OUT_HEARING_AID) &
- availableOutputDevices.types();
+ DeviceVector availPrimaryOutputDevices = availableOutputDevices.getDevicesFromTypes(
+ primaryOutput->supportedDevices().types());
+ availPrimaryOutputDevices.add(
+ availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_HEARING_AID));
- if (((availableInputDevices.types() &
- AUDIO_DEVICE_IN_TELEPHONY_RX & ~AUDIO_DEVICE_BIT_IN) == 0) ||
- (((txDevice & availPrimaryInputDevices & ~AUDIO_DEVICE_BIT_IN) != 0) &&
- (primaryOutput->getAudioPort()->getModuleVersionMajor() < 3))) {
- availableOutputDevicesType = availPrimaryOutputDevices;
+ if ((availableInputDevices.getDevice(AUDIO_DEVICE_IN_TELEPHONY_RX,
+ String8(""), AUDIO_FORMAT_DEFAULT) == nullptr) ||
+ ((availPrimaryInputDevices.getDevice(
+ txDevice, String8(""), AUDIO_FORMAT_DEFAULT) != nullptr) &&
+ (primaryOutput->getPolicyAudioPort()->getModuleVersionMajor() < 3))) {
+ availableOutputDevices = availPrimaryOutputDevices;
}
}
// for phone strategy, we first consider the forced use and then the available devices by
@@ -222,49 +228,40 @@
switch (getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION)) {
case AUDIO_POLICY_FORCE_BT_SCO:
if (!isInCall() || strategy != STRATEGY_DTMF) {
- device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
- if (device) break;
+ devices = availableOutputDevices.getDevicesFromType(
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT);
+ if (!devices.isEmpty()) break;
}
- device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
- if (device) break;
- device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
- if (device) break;
+ devices = availableOutputDevices.getFirstDevicesFromTypes({
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET, AUDIO_DEVICE_OUT_BLUETOOTH_SCO});
+ if (!devices.isEmpty()) break;
// if SCO device is requested but no SCO device is available, fall back to default case
FALLTHROUGH_INTENDED;
default: // FORCE_NONE
- device = availableOutputDevicesType & AUDIO_DEVICE_OUT_HEARING_AID;
- if (device) break;
+ devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_HEARING_AID);
+ if (!devices.isEmpty()) break;
// when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP
if (!isInCall() &&
(getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
outputs.isA2dpSupported()) {
- device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
- if (device) break;
- device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
- if (device) break;
+ devices = availableOutputDevices.getFirstDevicesFromTypes({
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES});
+ if (!devices.isEmpty()) break;
}
- device = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
- if (device) break;
- device = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADSET;
- if (device) break;
- device = availableOutputDevicesType & AUDIO_DEVICE_OUT_LINE;
- if (device) break;
- device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_HEADSET;
- if (device) break;
- device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_DEVICE;
- if (device) break;
+ devices = availableOutputDevices.getFirstDevicesFromTypes({
+ AUDIO_DEVICE_OUT_WIRED_HEADPHONE, AUDIO_DEVICE_OUT_WIRED_HEADSET,
+ AUDIO_DEVICE_OUT_LINE, AUDIO_DEVICE_OUT_USB_HEADSET,
+ AUDIO_DEVICE_OUT_USB_DEVICE});
+ if (!devices.isEmpty()) break;
if (!isInCall()) {
- device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_ACCESSORY;
- if (device) break;
- device = availableOutputDevicesType & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
- if (device) break;
- device = availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_DIGITAL;
- if (device) break;
- device = availableOutputDevicesType & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
- if (device) break;
+ devices = availableOutputDevices.getFirstDevicesFromTypes({
+ AUDIO_DEVICE_OUT_USB_ACCESSORY, AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET,
+ AUDIO_DEVICE_OUT_AUX_DIGITAL, AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET});
+ if (!devices.isEmpty()) break;
}
- device = availableOutputDevicesType & AUDIO_DEVICE_OUT_EARPIECE;
+ devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_EARPIECE);
break;
case AUDIO_POLICY_FORCE_SPEAKER:
@@ -273,22 +270,18 @@
if (!isInCall() &&
(getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
outputs.isA2dpSupported()) {
- device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
- if (device) break;
+ devices = availableOutputDevices.getDevicesFromType(
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER);
+ if (!devices.isEmpty()) break;
}
if (!isInCall()) {
- device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_ACCESSORY;
- if (device) break;
- device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_DEVICE;
- if (device) break;
- device = availableOutputDevicesType & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
- if (device) break;
- device = availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_DIGITAL;
- if (device) break;
- device = availableOutputDevicesType & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
- if (device) break;
+ devices = availableOutputDevices.getFirstDevicesFromTypes({
+ AUDIO_DEVICE_OUT_USB_ACCESSORY, AUDIO_DEVICE_OUT_USB_DEVICE,
+ AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, AUDIO_DEVICE_OUT_AUX_DIGITAL,
+ AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET});
+ if (!devices.isEmpty()) break;
}
- device = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
+ devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
break;
}
break;
@@ -298,9 +291,8 @@
// If incall, just select the STRATEGY_PHONE device
if (isInCall() ||
outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_VOICE_CALL))) {
- device = getDeviceForStrategyInt(
- STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs,
- outputDeviceTypesToIgnore);
+ devices = getDevicesForStrategyInt(
+ STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs);
break;
}
FALLTHROUGH_INTENDED;
@@ -313,41 +305,37 @@
if ((strategy == STRATEGY_SONIFICATION) ||
(getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)) {
- device = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
+ devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
}
// if SCO headset is connected and we are told to use it, play ringtone over
// speaker and BT SCO
- if ((availableOutputDevicesType & AUDIO_DEVICE_OUT_ALL_SCO) != 0) {
- uint32_t device2 = AUDIO_DEVICE_NONE;
- device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
- if (device2 == AUDIO_DEVICE_NONE) {
- device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
- }
- if (device2 == AUDIO_DEVICE_NONE) {
- device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
- }
+ if (!availableOutputDevices.getDevicesFromTypes(getAudioDeviceOutAllScoSet()).isEmpty()) {
+ DeviceVector devices2;
+ devices2 = availableOutputDevices.getFirstDevicesFromTypes({
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT, AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET,
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO});
// Use ONLY Bluetooth SCO output when ringing in vibration mode
if (!((getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)
&& (strategy == STRATEGY_ENFORCED_AUDIBLE))) {
if (getForceUse(AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING)
== AUDIO_POLICY_FORCE_BT_SCO) {
- if (device2 != AUDIO_DEVICE_NONE) {
- device = device2;
+ if (!devices2.isEmpty()) {
+ devices = devices2;
break;
}
}
}
// Use both Bluetooth SCO and phone default output when ringing in normal mode
if (getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION) == AUDIO_POLICY_FORCE_BT_SCO) {
- if ((strategy == STRATEGY_SONIFICATION) &&
- (device & AUDIO_DEVICE_OUT_SPEAKER) &&
- (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
- device |= AUDIO_DEVICE_OUT_SPEAKER_SAFE;
- device &= ~AUDIO_DEVICE_OUT_SPEAKER;
+ if (strategy == STRATEGY_SONIFICATION) {
+ devices.replaceDevicesByType(
+ AUDIO_DEVICE_OUT_SPEAKER,
+ availableOutputDevices.getDevicesFromType(
+ AUDIO_DEVICE_OUT_SPEAKER_SAFE));
}
- if (device2 != AUDIO_DEVICE_NONE) {
- device |= device2;
+ if (!devices2.isEmpty()) {
+ devices.add(devices2);
break;
}
}
@@ -361,25 +349,20 @@
// compressed format as they would likely not be mixed and dropped.
for (size_t i = 0; i < outputs.size(); i++) {
sp<AudioOutputDescriptor> desc = outputs.valueAt(i);
- audio_devices_t devices = desc->devices().types() &
- (AUDIO_DEVICE_OUT_HDMI | AUDIO_DEVICE_OUT_SPDIF | AUDIO_DEVICE_OUT_HDMI_ARC);
- if (desc->isActive() && !audio_is_linear_pcm(desc->mFormat) &&
- devices != AUDIO_DEVICE_NONE) {
- availableOutputDevicesType = availableOutputDevices.types() & ~devices;
+ if (desc->isActive() && !audio_is_linear_pcm(desc->getFormat())) {
+ availableOutputDevices.remove(desc->devices().getDevicesFromTypes({
+ AUDIO_DEVICE_OUT_HDMI, AUDIO_DEVICE_OUT_SPDIF,
+ AUDIO_DEVICE_OUT_HDMI_ARC}));
}
}
- availableOutputDevices =
- availableOutputDevices.getDevicesFromTypeMask(availableOutputDevicesType);
if (outputs.isActive(toVolumeSource(AUDIO_STREAM_RING)) ||
outputs.isActive(toVolumeSource(AUDIO_STREAM_ALARM))) {
- return getDeviceForStrategyInt(
- STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs,
- outputDeviceTypesToIgnore);
+ return getDevicesForStrategyInt(
+ STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs);
}
if (isInCall()) {
- return getDeviceForStrategyInt(
- STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs,
- outputDeviceTypesToIgnore);
+ return getDevicesForStrategyInt(
+ STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs);
}
}
// For other cases, STRATEGY_ACCESSIBILITY behaves like STRATEGY_MEDIA
@@ -388,128 +371,118 @@
// FIXME: STRATEGY_REROUTING follow STRATEGY_MEDIA for now
case STRATEGY_REROUTING:
case STRATEGY_MEDIA: {
- uint32_t device2 = AUDIO_DEVICE_NONE;
+ DeviceVector devices2;
if (strategy != STRATEGY_SONIFICATION) {
// no sonification on remote submix (e.g. WFD)
- if (availableOutputDevices.getDevice(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
- String8("0"), AUDIO_FORMAT_DEFAULT) != 0) {
- device2 = availableOutputDevices.types() & AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+ sp<DeviceDescriptor> remoteSubmix;
+ if ((remoteSubmix = availableOutputDevices.getDevice(
+ AUDIO_DEVICE_OUT_REMOTE_SUBMIX, String8("0"),
+ AUDIO_FORMAT_DEFAULT)) != nullptr) {
+ devices2.add(remoteSubmix);
}
}
if (isInCall() && (strategy == STRATEGY_MEDIA)) {
- device = getDeviceForStrategyInt(
- STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs,
- outputDeviceTypesToIgnore);
+ devices = getDevicesForStrategyInt(
+ STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs);
break;
}
// FIXME: Find a better solution to prevent routing to BT hearing aid(b/122931261).
- if ((device2 == AUDIO_DEVICE_NONE) &&
+ if ((devices2.isEmpty()) &&
(getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP)) {
- device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_HEARING_AID;
+ devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_HEARING_AID);
}
- if ((device2 == AUDIO_DEVICE_NONE) &&
- (getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
- outputs.isA2dpSupported()) {
- device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
- if (device2 == AUDIO_DEVICE_NONE) {
- device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
- }
- if (device2 == AUDIO_DEVICE_NONE) {
- device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
- }
- }
- if ((device2 == AUDIO_DEVICE_NONE) &&
+ if ((devices2.isEmpty()) &&
(getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) == AUDIO_POLICY_FORCE_SPEAKER)) {
- device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
+ devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
}
- if (device2 == AUDIO_DEVICE_NONE) {
- device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+ if (devices2.isEmpty() && (getLastRemovableMediaDevices().size() > 0)) {
+ if ((getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
+ outputs.isA2dpSupported()) {
+ // Get the last connected device of wired and bluetooth a2dp
+ devices2 = availableOutputDevices.getFirstDevicesFromTypes(
+ getLastRemovableMediaDevices());
+ } else {
+ // Get the last connected device of wired except bluetooth a2dp
+ devices2 = availableOutputDevices.getFirstDevicesFromTypes(
+ getLastRemovableMediaDevices(GROUP_WIRED));
+ }
}
- if (device2 == AUDIO_DEVICE_NONE) {
- device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_LINE;
- }
- if (device2 == AUDIO_DEVICE_NONE) {
- device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADSET;
- }
- if (device2 == AUDIO_DEVICE_NONE) {
- device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_HEADSET;
- }
- if (device2 == AUDIO_DEVICE_NONE) {
- device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_ACCESSORY;
- }
- if (device2 == AUDIO_DEVICE_NONE) {
- device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_DEVICE;
- }
- if (device2 == AUDIO_DEVICE_NONE) {
- device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
- }
- if ((device2 == AUDIO_DEVICE_NONE) && (strategy != STRATEGY_SONIFICATION)) {
+ if ((devices2.isEmpty()) && (strategy != STRATEGY_SONIFICATION)) {
// no sonification on aux digital (e.g. HDMI)
- device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_DIGITAL;
+ devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_AUX_DIGITAL);
}
- if ((device2 == AUDIO_DEVICE_NONE) &&
+ if ((devices2.isEmpty()) &&
(getForceUse(AUDIO_POLICY_FORCE_FOR_DOCK) == AUDIO_POLICY_FORCE_ANALOG_DOCK)) {
- device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+ devices2 = availableOutputDevices.getDevicesFromType(
+ AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET);
}
- if (device2 == AUDIO_DEVICE_NONE) {
- device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
+ if (devices2.isEmpty()) {
+ devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
}
- int device3 = AUDIO_DEVICE_NONE;
+ DeviceVector devices3;
if (strategy == STRATEGY_MEDIA) {
// ARC, SPDIF and AUX_LINE can co-exist with others.
- device3 = availableOutputDevicesType & AUDIO_DEVICE_OUT_HDMI_ARC;
- device3 |= (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPDIF);
- device3 |= (availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_LINE);
+ devices3 = availableOutputDevices.getDevicesFromTypes({
+ AUDIO_DEVICE_OUT_HDMI_ARC, AUDIO_DEVICE_OUT_SPDIF, AUDIO_DEVICE_OUT_AUX_LINE});
}
- device2 |= device3;
+ devices2.add(devices3);
// device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION or
// STRATEGY_ENFORCED_AUDIBLE, AUDIO_DEVICE_NONE otherwise
- device |= device2;
+ devices.add(devices2);
// If hdmi system audio mode is on, remove speaker out of output list.
if ((strategy == STRATEGY_MEDIA) &&
(getForceUse(AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO) ==
AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED)) {
- device &= ~AUDIO_DEVICE_OUT_SPEAKER;
+ devices.remove(devices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER));
}
// for STRATEGY_SONIFICATION:
// if SPEAKER was selected, and SPEAKER_SAFE is available, use SPEAKER_SAFE instead
- if ((strategy == STRATEGY_SONIFICATION) &&
- (device & AUDIO_DEVICE_OUT_SPEAKER) &&
- (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
- device |= AUDIO_DEVICE_OUT_SPEAKER_SAFE;
- device &= ~AUDIO_DEVICE_OUT_SPEAKER;
+ if (strategy == STRATEGY_SONIFICATION) {
+ devices.replaceDevicesByType(
+ AUDIO_DEVICE_OUT_SPEAKER,
+ availableOutputDevices.getDevicesFromType(
+ AUDIO_DEVICE_OUT_SPEAKER_SAFE));
}
} break;
+ case STRATEGY_CALL_ASSISTANT:
+ devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_TELEPHONY_TX);
+ break;
+
default:
- ALOGW("getDeviceForStrategy() unknown strategy: %d", strategy);
+ ALOGW("getDevicesForStrategy() unknown strategy: %d", strategy);
break;
}
- if (device == AUDIO_DEVICE_NONE) {
- ALOGV("getDeviceForStrategy() no device found for strategy %d", strategy);
- device = getApmObserver()->getDefaultOutputDevice()->type();
- ALOGE_IF(device == AUDIO_DEVICE_NONE,
- "getDeviceForStrategy() no default device defined");
+ if (devices.isEmpty()) {
+ ALOGV("getDevicesForStrategy() no device found for strategy %d", strategy);
+ sp<DeviceDescriptor> defaultOutputDevice = getApmObserver()->getDefaultOutputDevice();
+ if (defaultOutputDevice != nullptr) {
+ devices.add(defaultOutputDevice);
+ }
+ ALOGE_IF(devices.isEmpty(),
+ "getDevicesForStrategy() no default device defined");
}
- ALOGVV("getDeviceForStrategy() strategy %d, device %x", strategy, device);
- return device;
+
+ ALOGVV("getDevices ForStrategy() strategy %d, device %s",
+ strategy, dumpDeviceTypes(devices.types()).c_str());
+ return devices;
}
-audio_devices_t Engine::getDeviceForInputSource(audio_source_t inputSource) const
+sp<DeviceDescriptor> Engine::getDeviceForInputSource(audio_source_t inputSource) const
{
const DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
const DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices();
const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
- audio_devices_t availableDeviceTypes = availableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN;
+ DeviceVector availableDevices = availableInputDevices;
sp<AudioOutputDescriptor> primaryOutput = outputs.getPrimaryOutput();
- audio_devices_t availablePrimaryDeviceTypes = availableInputDevices.getDeviceTypesFromHwModule(
- primaryOutput->getModuleHandle()) & ~AUDIO_DEVICE_BIT_IN;
- uint32_t device = AUDIO_DEVICE_NONE;
+ DeviceVector availablePrimaryDevices = primaryOutput == nullptr ? DeviceVector()
+ : availableInputDevices.getDevicesFromHwModule(primaryOutput->getModuleHandle());
+ sp<DeviceDescriptor> device;
// when a call is active, force device selection to match source VOICE_COMMUNICATION
// for most other input sources to avoid rerouting call TX audio
@@ -532,57 +505,48 @@
switch (inputSource) {
case AUDIO_SOURCE_DEFAULT:
case AUDIO_SOURCE_MIC:
- if (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {
- device = AUDIO_DEVICE_IN_BLUETOOTH_A2DP;
- } else if ((getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) == AUDIO_POLICY_FORCE_BT_SCO) &&
- (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET)) {
- device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
- } else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
- device = AUDIO_DEVICE_IN_WIRED_HEADSET;
- } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_HEADSET) {
- device = AUDIO_DEVICE_IN_USB_HEADSET;
- } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
- device = AUDIO_DEVICE_IN_USB_DEVICE;
- } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
- device = AUDIO_DEVICE_IN_BUILTIN_MIC;
- }
- break;
+ device = availableDevices.getDevice(
+ AUDIO_DEVICE_IN_BLUETOOTH_A2DP, String8(""), AUDIO_FORMAT_DEFAULT);
+ if (device != nullptr) break;
+ if (getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) == AUDIO_POLICY_FORCE_BT_SCO) {
+ device = availableDevices.getDevice(
+ AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, String8(""), AUDIO_FORMAT_DEFAULT);
+ if (device != nullptr) break;
+ }
+ device = availableDevices.getFirstExistingDevice({
+ AUDIO_DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_IN_USB_HEADSET,
+ AUDIO_DEVICE_IN_USB_DEVICE, AUDIO_DEVICE_IN_BUILTIN_MIC});
+ break;
case AUDIO_SOURCE_VOICE_COMMUNICATION:
// Allow only use of devices on primary input if in call and HAL does not support routing
// to voice call path.
if ((getPhoneState() == AUDIO_MODE_IN_CALL) &&
- (availableOutputDevices.types() & AUDIO_DEVICE_OUT_TELEPHONY_TX) == 0) {
- availableDeviceTypes = availablePrimaryDeviceTypes;
+ (availableOutputDevices.getDevice(AUDIO_DEVICE_OUT_TELEPHONY_TX,
+ String8(""), AUDIO_FORMAT_DEFAULT)) == nullptr) {
+ LOG_ALWAYS_FATAL_IF(availablePrimaryDevices.isEmpty(), "Primary devices not found");
+ availableDevices = availablePrimaryDevices;
}
switch (getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION)) {
case AUDIO_POLICY_FORCE_BT_SCO:
// if SCO device is requested but no SCO device is available, fall back to default case
- if (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
- device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+ device = availableDevices.getDevice(
+ AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, String8(""), AUDIO_FORMAT_DEFAULT);
+ if (device != nullptr) {
break;
}
FALLTHROUGH_INTENDED;
default: // FORCE_NONE
- if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
- device = AUDIO_DEVICE_IN_WIRED_HEADSET;
- } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_HEADSET) {
- device = AUDIO_DEVICE_IN_USB_HEADSET;
- } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
- device = AUDIO_DEVICE_IN_USB_DEVICE;
- } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
- device = AUDIO_DEVICE_IN_BUILTIN_MIC;
- }
+ device = availableDevices.getFirstExistingDevice({
+ AUDIO_DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_IN_USB_HEADSET,
+ AUDIO_DEVICE_IN_USB_DEVICE, AUDIO_DEVICE_IN_BUILTIN_MIC});
break;
case AUDIO_POLICY_FORCE_SPEAKER:
- if (availableDeviceTypes & AUDIO_DEVICE_IN_BACK_MIC) {
- device = AUDIO_DEVICE_IN_BACK_MIC;
- } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
- device = AUDIO_DEVICE_IN_BUILTIN_MIC;
- }
+ device = availableDevices.getFirstExistingDevice({
+ AUDIO_DEVICE_IN_BACK_MIC, AUDIO_DEVICE_IN_BUILTIN_MIC});
break;
}
break;
@@ -591,84 +555,70 @@
case AUDIO_SOURCE_UNPROCESSED:
case AUDIO_SOURCE_HOTWORD:
if (inputSource == AUDIO_SOURCE_HOTWORD) {
- availableDeviceTypes = availablePrimaryDeviceTypes;
+ // We should not use primary output criteria for Hotword but rather limit
+ // to devices attached to the same HW module as the build in mic
+ LOG_ALWAYS_FATAL_IF(availablePrimaryDevices.isEmpty(), "Primary devices not found");
+ availableDevices = availablePrimaryDevices;
}
- if (getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) == AUDIO_POLICY_FORCE_BT_SCO &&
- availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
- device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
- } else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
- device = AUDIO_DEVICE_IN_WIRED_HEADSET;
- } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_HEADSET) {
- device = AUDIO_DEVICE_IN_USB_HEADSET;
- } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
- device = AUDIO_DEVICE_IN_USB_DEVICE;
- } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
- device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ if (getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) == AUDIO_POLICY_FORCE_BT_SCO) {
+ device = availableDevices.getDevice(
+ AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, String8(""), AUDIO_FORMAT_DEFAULT);
+ if (device != nullptr) break;
}
+ device = availableDevices.getFirstExistingDevice({
+ AUDIO_DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_IN_USB_HEADSET,
+ AUDIO_DEVICE_IN_USB_DEVICE, AUDIO_DEVICE_IN_BUILTIN_MIC});
break;
case AUDIO_SOURCE_CAMCORDER:
- if (availableDeviceTypes & AUDIO_DEVICE_IN_BACK_MIC) {
- device = AUDIO_DEVICE_IN_BACK_MIC;
- } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
- device = AUDIO_DEVICE_IN_BUILTIN_MIC;
- } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
- // This is specifically for a device without built-in mic
- device = AUDIO_DEVICE_IN_USB_DEVICE;
- }
+ // For a device without built-in mic, adding usb device
+ device = availableDevices.getFirstExistingDevice({
+ AUDIO_DEVICE_IN_BACK_MIC, AUDIO_DEVICE_IN_BUILTIN_MIC,
+ AUDIO_DEVICE_IN_USB_DEVICE});
break;
case AUDIO_SOURCE_VOICE_DOWNLINK:
case AUDIO_SOURCE_VOICE_CALL:
case AUDIO_SOURCE_VOICE_UPLINK:
- if (availableDeviceTypes & AUDIO_DEVICE_IN_VOICE_CALL) {
- device = AUDIO_DEVICE_IN_VOICE_CALL;
- }
+ device = availableDevices.getDevice(
+ AUDIO_DEVICE_IN_VOICE_CALL, String8(""), AUDIO_FORMAT_DEFAULT);
break;
case AUDIO_SOURCE_VOICE_PERFORMANCE:
- if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
- device = AUDIO_DEVICE_IN_WIRED_HEADSET;
- } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_HEADSET) {
- device = AUDIO_DEVICE_IN_USB_HEADSET;
- } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
- device = AUDIO_DEVICE_IN_USB_DEVICE;
- } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
- device = AUDIO_DEVICE_IN_BUILTIN_MIC;
- }
+ device = availableDevices.getFirstExistingDevice({
+ AUDIO_DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_IN_USB_HEADSET,
+ AUDIO_DEVICE_IN_USB_DEVICE, AUDIO_DEVICE_IN_BUILTIN_MIC});
break;
case AUDIO_SOURCE_REMOTE_SUBMIX:
- if (availableDeviceTypes & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
- device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
- }
+ device = availableDevices.getDevice(
+ AUDIO_DEVICE_IN_REMOTE_SUBMIX, String8(""), AUDIO_FORMAT_DEFAULT);
break;
case AUDIO_SOURCE_FM_TUNER:
- if (availableDeviceTypes & AUDIO_DEVICE_IN_FM_TUNER) {
- device = AUDIO_DEVICE_IN_FM_TUNER;
- }
+ device = availableDevices.getDevice(
+ AUDIO_DEVICE_IN_FM_TUNER, String8(""), AUDIO_FORMAT_DEFAULT);
break;
case AUDIO_SOURCE_ECHO_REFERENCE:
- if (availableDeviceTypes & AUDIO_DEVICE_IN_ECHO_REFERENCE) {
- device = AUDIO_DEVICE_IN_ECHO_REFERENCE;
- }
+ device = availableDevices.getDevice(
+ AUDIO_DEVICE_IN_ECHO_REFERENCE, String8(""), AUDIO_FORMAT_DEFAULT);
break;
default:
ALOGW("getDeviceForInputSource() invalid input source %d", inputSource);
break;
}
- if (device == AUDIO_DEVICE_NONE) {
+ if (device == nullptr) {
ALOGV("getDeviceForInputSource() no device found for source %d", inputSource);
- if (availableDeviceTypes & AUDIO_DEVICE_IN_STUB) {
- device = AUDIO_DEVICE_IN_STUB;
- }
- ALOGE_IF(device == AUDIO_DEVICE_NONE,
+ device = availableDevices.getDevice(
+ AUDIO_DEVICE_IN_STUB, String8(""), AUDIO_FORMAT_DEFAULT);
+ ALOGE_IF(device == nullptr,
"getDeviceForInputSource() no default device defined");
}
- ALOGV("getDeviceForInputSource()input source %d, device %08x", inputSource, device);
+ ALOGV_IF(device != nullptr,
+ "getDeviceForInputSource()input source %d, device %08x",
+ inputSource, device->type());
return device;
}
void Engine::updateDeviceSelectionCache()
{
for (const auto &iter : getProductStrategies()) {
- const auto &strategy = iter.second;
+ const auto& strategy = iter.second;
auto devices = getDevicesForProductStrategy(strategy->getId());
mDevicesForStrategies[strategy->getId()] = devices;
strategy->setDeviceTypes(devices.types());
@@ -676,19 +626,34 @@
}
}
-DeviceVector Engine::getDevicesForProductStrategy(product_strategy_t strategy) const
-{
+DeviceVector Engine::getDevicesForProductStrategy(product_strategy_t strategy) const {
DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
- DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices();
- const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
+ // check if this strategy has a preferred device that is available,
+ // if yes, give priority to it
+ AudioDeviceTypeAddr preferredStrategyDevice;
+ const status_t status = getPreferredDeviceForStrategy(strategy, preferredStrategyDevice);
+ if (status == NO_ERROR) {
+ // there is a preferred device, is it available?
+ sp<DeviceDescriptor> preferredAvailableDevDescr = availableOutputDevices.getDevice(
+ preferredStrategyDevice.mType,
+ String8(preferredStrategyDevice.mAddress.c_str()),
+ AUDIO_FORMAT_DEFAULT);
+ if (preferredAvailableDevDescr != nullptr) {
+ ALOGVV("%s using pref device 0x%08x/%s for strategy %u",
+ __func__, preferredStrategyDevice.mType,
+ preferredStrategyDevice.mAddress.c_str(), strategy);
+ return DeviceVector(preferredAvailableDevDescr);
+ }
+ }
+
+ DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices();
+ const SwAudioOutputCollection& outputs = getApmObserver()->getOutputs();
auto legacyStrategy = mLegacyStrategyMap.find(strategy) != end(mLegacyStrategyMap) ?
- mLegacyStrategyMap.at(strategy) : STRATEGY_NONE;
- audio_devices_t devices = getDeviceForStrategyInt(legacyStrategy,
- availableOutputDevices,
- availableInputDevices, outputs,
- (uint32_t)AUDIO_DEVICE_NONE);
- return availableOutputDevices.getDevicesFromTypeMask(devices);
+ mLegacyStrategyMap.at(strategy) : STRATEGY_NONE;
+ return getDevicesForStrategyInt(legacyStrategy,
+ availableOutputDevices,
+ availableInputDevices, outputs);
}
DeviceVector Engine::getOutputDevicesForAttributes(const audio_attributes_t &attributes,
@@ -747,27 +712,25 @@
if (device != nullptr) {
return device;
}
- audio_devices_t deviceType = getDeviceForInputSource(attr.source);
- if (audio_is_remote_submix_device(deviceType)) {
- address = "0";
- std::size_t pos;
- std::string tags { attr.tags };
- if ((pos = tags.find("addr=")) != std::string::npos) {
- address = tags.substr(pos + std::strlen("addr="));
- }
+ device = getDeviceForInputSource(attr.source);
+ if (device == nullptr || !audio_is_remote_submix_device(device->type())) {
+ // Return immediately if the device is null or it is not a remote submix device.
+ return device;
}
- return availableInputDevices.getDevice(deviceType,
+
+ // For remote submix device, try to find the device by address.
+ address = "0";
+ std::size_t pos;
+ std::string tags { attr.tags };
+ if ((pos = tags.find("addr=")) != std::string::npos) {
+ address = tags.substr(pos + std::strlen("addr="));
+ }
+ return availableInputDevices.getDevice(device->type(),
String8(address.c_str()),
AUDIO_FORMAT_DEFAULT);
}
-template <>
-AudioPolicyManagerInterface *Engine::queryInterface()
-{
- return this;
-}
-
} // namespace audio_policy
} // namespace android
diff --git a/services/audiopolicy/enginedefault/src/Engine.h b/services/audiopolicy/enginedefault/src/Engine.h
index d5dfacc..bb9e2df 100644
--- a/services/audiopolicy/enginedefault/src/Engine.h
+++ b/services/audiopolicy/enginedefault/src/Engine.h
@@ -17,8 +17,7 @@
#pragma once
#include "EngineBase.h"
-#include "AudioPolicyManagerInterface.h"
-#include <AudioGain.h>
+#include "EngineInterface.h"
#include <policy.h>
namespace android
@@ -40,6 +39,7 @@
STRATEGY_TRANSMITTED_THROUGH_SPEAKER,
STRATEGY_ACCESSIBILITY,
STRATEGY_REROUTING,
+ STRATEGY_CALL_ASSISTANT,
};
class Engine : public EngineBase
@@ -48,12 +48,9 @@
Engine();
virtual ~Engine() = default;
- template <class RequestedInterface>
- RequestedInterface *queryInterface();
-
private:
///
- /// from EngineBase, so from AudioPolicyManagerInterface
+ /// from EngineBase, so from EngineInterface
///
status_t setForceUse(audio_policy_force_use_t usage,
audio_policy_forced_cfg_t config) override;
@@ -77,15 +74,14 @@
status_t setDefaultDevice(audio_devices_t device);
- audio_devices_t getDeviceForStrategyInt(legacy_strategy strategy,
- DeviceVector availableOutputDevices,
- DeviceVector availableInputDevices,
- const SwAudioOutputCollection &outputs,
- uint32_t outputDeviceTypesToIgnore) const;
+ DeviceVector getDevicesForStrategyInt(legacy_strategy strategy,
+ DeviceVector availableOutputDevices,
+ DeviceVector availableInputDevices,
+ const SwAudioOutputCollection &outputs) const;
DeviceVector getDevicesForProductStrategy(product_strategy_t strategy) const;
- audio_devices_t getDeviceForInputSource(audio_source_t inputSource) const;
+ sp<DeviceDescriptor> getDeviceForInputSource(audio_source_t inputSource) const;
DeviceStrategyMap mDevicesForStrategies;
diff --git a/services/audiopolicy/enginedefault/src/EngineInstance.cpp b/services/audiopolicy/enginedefault/src/EngineInstance.cpp
index 17e9832..eeb3758 100644
--- a/services/audiopolicy/enginedefault/src/EngineInstance.cpp
+++ b/services/audiopolicy/enginedefault/src/EngineInstance.cpp
@@ -14,41 +14,21 @@
* limitations under the License.
*/
-#include <AudioPolicyManagerInterface.h>
-#include "AudioPolicyEngineInstance.h"
+#include <EngineInterface.h>
#include "Engine.h"
-namespace android
-{
-namespace audio_policy
-{
+namespace android {
+namespace audio_policy {
-EngineInstance::EngineInstance()
+extern "C" EngineInterface* createEngineInstance()
{
+ return new (std::nothrow) Engine();
}
-EngineInstance *EngineInstance::getInstance()
+extern "C" void destroyEngineInstance(EngineInterface *engine)
{
- static EngineInstance instance;
- return &instance;
-}
-
-EngineInstance::~EngineInstance()
-{
-}
-
-Engine *EngineInstance::getEngine() const
-{
- static Engine engine;
- return &engine;
-}
-
-template <>
-AudioPolicyManagerInterface *EngineInstance::queryInterface() const
-{
- return getEngine()->queryInterface<AudioPolicyManagerInterface>();
+ delete static_cast<Engine*>(engine);
}
} // namespace audio_policy
} // namespace android
-
diff --git a/services/audiopolicy/manager/Android.mk b/services/audiopolicy/manager/Android.mk
index d6ca2f2..cae6cfa 100644
--- a/services/audiopolicy/manager/Android.mk
+++ b/services/audiopolicy/manager/Android.mk
@@ -23,8 +23,6 @@
LOCAL_CFLAGS := -Wall -Werror
-LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-
LOCAL_MODULE:= libaudiopolicymanager
include $(BUILD_SHARED_LIBRARY)
diff --git a/services/audiopolicy/manager/AudioPolicyFactory.cpp b/services/audiopolicy/manager/AudioPolicyFactory.cpp
index 7aff6a9..476a1ec 100644
--- a/services/audiopolicy/manager/AudioPolicyFactory.cpp
+++ b/services/audiopolicy/manager/AudioPolicyFactory.cpp
@@ -21,7 +21,13 @@
extern "C" AudioPolicyInterface* createAudioPolicyManager(
AudioPolicyClientInterface *clientInterface)
{
- return new AudioPolicyManager(clientInterface);
+ AudioPolicyManager *apm = new AudioPolicyManager(clientInterface);
+ status_t status = apm->initialize();
+ if (status != NO_ERROR) {
+ delete apm;
+ apm = nullptr;
+ }
+ return apm;
}
extern "C" void destroyAudioPolicyManager(AudioPolicyInterface *interface)
diff --git a/services/audiopolicy/managerdefault/Android.bp b/services/audiopolicy/managerdefault/Android.bp
new file mode 100644
index 0000000..577b42f
--- /dev/null
+++ b/services/audiopolicy/managerdefault/Android.bp
@@ -0,0 +1,43 @@
+cc_library_shared {
+ name: "libaudiopolicymanagerdefault",
+
+ srcs: [
+ "AudioPolicyManager.cpp",
+ "EngineLibrary.cpp",
+ ],
+
+ export_include_dirs: ["."],
+
+ shared_libs: [
+ "libaudiofoundation",
+ "libcutils",
+ "libdl",
+ "libutils",
+ "liblog",
+ "libaudiopolicy",
+ "libmedia_helper",
+ "libmediametrics",
+ "libbinder",
+ "libhidlbase",
+ "libxml2",
+ // The default audio policy engine is always present in the system image.
+ // libaudiopolicyengineconfigurable can be built in addition by specifying
+ // a dependency on it in the device makefile. There will be no build time
+ // conflict with libaudiopolicyenginedefault.
+ "libaudiopolicyenginedefault",
+ ],
+
+ header_libs: [
+ "libaudiopolicycommon",
+ "libaudiopolicyengine_interface_headers",
+ "libaudiopolicymanager_interface_headers",
+ ],
+
+ static_libs: ["libaudiopolicycomponents"],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+
+}
diff --git a/services/audiopolicy/managerdefault/Android.mk b/services/audiopolicy/managerdefault/Android.mk
deleted file mode 100644
index 684fc9f..0000000
--- a/services/audiopolicy/managerdefault/Android.mk
+++ /dev/null
@@ -1,56 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= AudioPolicyManager.cpp
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libutils \
- liblog \
- libaudiopolicy \
- libsoundtrigger
-
-ifeq ($(USE_CONFIGURABLE_AUDIO_POLICY), 1)
-
-ifneq ($(USE_XML_AUDIO_POLICY_CONF), 1)
-$(error Configurable policy does not support legacy conf file)
-endif #ifneq ($(USE_XML_AUDIO_POLICY_CONF), 1)
-
-LOCAL_SHARED_LIBRARIES += libaudiopolicyengineconfigurable
-
-else
-
-LOCAL_SHARED_LIBRARIES += libaudiopolicyenginedefault
-
-endif # ifeq ($(USE_CONFIGURABLE_AUDIO_POLICY), 1)
-
-LOCAL_C_INCLUDES += \
- $(call include-path-for, audio-utils)
-
-LOCAL_HEADER_LIBRARIES := \
- libaudiopolicycommon \
- libaudiopolicyengine_interface_headers \
- libaudiopolicymanager_interface_headers
-
-LOCAL_STATIC_LIBRARIES := \
- libaudiopolicycomponents
-
-LOCAL_SHARED_LIBRARIES += libmedia_helper
-LOCAL_SHARED_LIBRARIES += libmediametrics
-
-LOCAL_SHARED_LIBRARIES += libbinder libhidlbase libxml2
-
-ifeq ($(USE_XML_AUDIO_POLICY_CONF), 1)
-LOCAL_CFLAGS += -DUSE_XML_AUDIO_POLICY_CONF
-endif #ifeq ($(USE_XML_AUDIO_POLICY_CONF), 1)
-
-LOCAL_CFLAGS += -Wall -Werror
-
-LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-
-LOCAL_MODULE:= libaudiopolicymanagerdefault
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index a984b10..ffc3a0f 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -42,15 +42,11 @@
#include <set>
#include <unordered_set>
#include <vector>
-#include <AudioPolicyManagerInterface.h>
-#include <AudioPolicyEngineInstance.h>
#include <cutils/properties.h>
#include <utils/Log.h>
#include <media/AudioParameter.h>
#include <private/android_filesystem_config.h>
-#include <soundtrigger/SoundTrigger.h>
#include <system/audio.h>
-#include <audio_policy_conf.h>
#include "AudioPolicyManager.h"
#include <Serializer.h>
#include "TypeConverter.h"
@@ -76,6 +72,26 @@
AUDIO_CHANNEL_OUT_2POINT1POINT2, AUDIO_CHANNEL_OUT_2POINT0POINT2,
AUDIO_CHANNEL_OUT_5POINT1, AUDIO_CHANNEL_OUT_STEREO }};
+template <typename T>
+bool operator== (const SortedVector<T> &left, const SortedVector<T> &right)
+{
+ if (left.size() != right.size()) {
+ return false;
+ }
+ for (size_t index = 0; index < right.size(); index++) {
+ if (left[index] != right[index]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+template <typename T>
+bool operator!= (const SortedVector<T> &left, const SortedVector<T> &right)
+{
+ return !(left == right);
+}
+
// ----------------------------------------------------------------------------
// AudioPolicyInterface implementation
// ----------------------------------------------------------------------------
@@ -95,9 +111,9 @@
void AudioPolicyManager::broadcastDeviceConnectionState(const sp<DeviceDescriptor> &device,
audio_policy_dev_state_t state)
{
- AudioParameter param(device->address());
+ AudioParameter param(String8(device->address().c_str()));
const String8 key(state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE ?
- AudioParameter::keyStreamConnect : AudioParameter::keyStreamDisconnect);
+ AudioParameter::keyDeviceConnect : AudioParameter::keyDeviceDisconnect);
param.addInt(key, device->type());
mpClientInterface->setParameters(AUDIO_IO_HANDLE_NONE, param.toString());
}
@@ -408,7 +424,7 @@
if (!audio_is_output_device(device) && !audio_is_input_device(device)) return BAD_VALUE;
// Check if the device is currently connected
- DeviceVector deviceList = mAvailableOutputDevices.getDevicesFromTypeMask(device);
+ DeviceVector deviceList = mAvailableOutputDevices.getDevicesFromType(device);
if (deviceList.empty()) {
// Nothing to do: device is not connected
return NO_ERROR;
@@ -422,8 +438,8 @@
// Case 1: A2DP active device switches from primary to primary
// module
// Case 2: A2DP device config changes on primary module.
- if (device & AUDIO_DEVICE_OUT_ALL_A2DP) {
- sp<HwModule> module = mHwModules.getModuleForDeviceTypes(device, encodedFormat);
+ if (audio_is_a2dp_out_device(device)) {
+ sp<HwModule> module = mHwModules.getModuleForDeviceType(device, encodedFormat);
audio_module_handle_t primaryHandle = mPrimaryOutput->getModuleHandle();
if (availablePrimaryOutputDevices().contains(devDesc) &&
(module != 0 && module->getHandle() == primaryHandle)) {
@@ -475,8 +491,12 @@
std::unordered_set<audio_format_t> formatSet;
sp<HwModule> primaryModule =
mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY);
- DeviceVector declaredDevices = primaryModule->getDeclaredDevices().getDevicesFromTypeMask(
- AUDIO_DEVICE_OUT_ALL_A2DP);
+ if (primaryModule == nullptr) {
+ ALOGE("%s() unable to get primary module", __func__);
+ return NO_INIT;
+ }
+ DeviceVector declaredDevices = primaryModule->getDeclaredDevices().getDevicesFromTypes(
+ getAudioDeviceOutAllA2dpSet());
for (const auto& device : declaredDevices) {
formatSet.insert(device->encodedFormats().begin(), device->encodedFormats().end());
}
@@ -490,7 +510,8 @@
bool createRxPatch = false;
uint32_t muteWaitMs = 0;
- if(!hasPrimaryOutput() || mPrimaryOutput->devices().types() == AUDIO_DEVICE_OUT_STUB) {
+ if(!hasPrimaryOutput() ||
+ mPrimaryOutput->devices().onlyContainsDevicesWithType(AUDIO_DEVICE_OUT_STUB)) {
return muteWaitMs;
}
ALOG_ASSERT(!rxDevices.isEmpty(), "updateCallRouting() no selected output device");
@@ -504,19 +525,19 @@
// release existing RX patch if any
if (mCallRxPatch != 0) {
- mpClientInterface->releaseAudioPatch(mCallRxPatch->mAfPatchHandle, 0);
+ releaseAudioPatchInternal(mCallRxPatch->getHandle());
mCallRxPatch.clear();
}
// release TX patch if any
if (mCallTxPatch != 0) {
- mpClientInterface->releaseAudioPatch(mCallTxPatch->mAfPatchHandle, 0);
+ releaseAudioPatchInternal(mCallTxPatch->getHandle());
mCallTxPatch.clear();
}
auto telephonyRxModule =
- mHwModules.getModuleForDeviceTypes(AUDIO_DEVICE_IN_TELEPHONY_RX, AUDIO_FORMAT_DEFAULT);
+ mHwModules.getModuleForDeviceType(AUDIO_DEVICE_IN_TELEPHONY_RX, AUDIO_FORMAT_DEFAULT);
auto telephonyTxModule =
- mHwModules.getModuleForDeviceTypes(AUDIO_DEVICE_OUT_TELEPHONY_TX, AUDIO_FORMAT_DEFAULT);
+ mHwModules.getModuleForDeviceType(AUDIO_DEVICE_OUT_TELEPHONY_TX, AUDIO_FORMAT_DEFAULT);
// retrieve Rx Source and Tx Sink device descriptors
sp<DeviceDescriptor> rxSourceDevice =
mAvailableInputDevices.getDevice(AUDIO_DEVICE_IN_TELEPHONY_RX,
@@ -535,11 +556,9 @@
ALOGE("updateCallRouting() no telephony Tx and/or RX device");
return muteWaitMs;
}
- // do not create a patch (aka Sw Bridging) if Primary HW module has declared supporting a
- // route between telephony RX to Sink device and Source device to telephony TX
- const auto &primaryModule = telephonyRxModule;
- createRxPatch = !primaryModule->supportsPatch(rxSourceDevice, rxDevices.itemAt(0));
- createTxPatch = !primaryModule->supportsPatch(txSourceDevice, txSinkDevice);
+ // createAudioPatchInternal now supports both HW / SW bridging
+ createRxPatch = true;
+ createTxPatch = true;
} else {
// If the RX device is on the primary HW module, then use legacy routing method for
// voice calls via setOutputDevice() on primary output.
@@ -563,6 +582,15 @@
// assuming the device uses audio HAL V5.0 and above
}
if (createTxPatch) { // create TX path audio patch
+ // terminate active capture if on the same HW module as the call TX source device
+ // FIXME: would be better to refine to only inputs whose profile connects to the
+ // call TX device but this information is not in the audio patch and logic here must be
+ // symmetric to the one in startInput()
+ for (const auto& activeDesc : mInputs.getActiveInputs()) {
+ if (activeDesc->hasSameHwModuleAs(txSourceDevice)) {
+ closeActiveClients(activeDesc);
+ }
+ }
mCallTxPatch = createTelephonyPatch(false /*isRx*/, txSourceDevice, delayMs);
}
@@ -576,6 +604,8 @@
if (device == nullptr) {
return nullptr;
}
+
+ // @TODO: still ignoring the address, or not dealing platform with multiple telephony devices
if (isRx) {
patchBuilder.addSink(device).
addSource(mAvailableInputDevices.getDevice(
@@ -586,59 +616,15 @@
AUDIO_DEVICE_OUT_TELEPHONY_TX, String8(), AUDIO_FORMAT_DEFAULT));
}
- // @TODO: still ignoring the address, or not dealing platform with mutliple telephonydevices
- const sp<DeviceDescriptor> outputDevice = isRx ?
- device : mAvailableOutputDevices.getDevice(
- AUDIO_DEVICE_OUT_TELEPHONY_TX, String8(), AUDIO_FORMAT_DEFAULT);
- SortedVector<audio_io_handle_t> outputs =
- getOutputsForDevices(DeviceVector(outputDevice), mOutputs);
- const audio_io_handle_t output = selectOutput(outputs);
- // request to reuse existing output stream if one is already opened to reach the target device
- if (output != AUDIO_IO_HANDLE_NONE) {
- sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
- ALOG_ASSERT(!outputDesc->isDuplicated(), "%s() %s device output %d is duplicated", __func__,
- outputDevice->toString().c_str(), output);
- patchBuilder.addSource(outputDesc, { .stream = AUDIO_STREAM_PATCH });
+ audio_patch_handle_t patchHandle = AUDIO_PATCH_HANDLE_NONE;
+ status_t status =
+ createAudioPatchInternal(patchBuilder.patch(), &patchHandle, mUidCached, delayMs);
+ ssize_t index = mAudioPatches.indexOfKey(patchHandle);
+ if (status != NO_ERROR || index < 0) {
+ ALOGW("%s() error %d creating %s audio patch", __func__, status, isRx ? "RX" : "TX");
+ return nullptr;
}
-
- if (!isRx) {
- // terminate active capture if on the same HW module as the call TX source device
- // FIXME: would be better to refine to only inputs whose profile connects to the
- // call TX device but this information is not in the audio patch and logic here must be
- // symmetric to the one in startInput()
- for (const auto& activeDesc : mInputs.getActiveInputs()) {
- if (activeDesc->hasSameHwModuleAs(device)) {
- closeActiveClients(activeDesc);
- }
- }
- }
-
- audio_patch_handle_t afPatchHandle = AUDIO_PATCH_HANDLE_NONE;
- status_t status = mpClientInterface->createAudioPatch(
- patchBuilder.patch(), &afPatchHandle, delayMs);
- ALOGW_IF(status != NO_ERROR,
- "%s() error %d creating %s audio patch", __func__, status, isRx ? "RX" : "TX");
- sp<AudioPatch> audioPatch;
- if (status == NO_ERROR) {
- audioPatch = new AudioPatch(patchBuilder.patch(), mUidCached);
- audioPatch->mAfPatchHandle = afPatchHandle;
- audioPatch->mUid = mUidCached;
- }
- return audioPatch;
-}
-
-sp<DeviceDescriptor> AudioPolicyManager::findDevice(
- const DeviceVector& devices, audio_devices_t device) const {
- DeviceVector deviceList = devices.getDevicesFromTypeMask(device);
- ALOG_ASSERT(!deviceList.isEmpty(),
- "%s() selected device type %#x is not in devices list", __func__, device);
- return deviceList.itemAt(0);
-}
-
-audio_devices_t AudioPolicyManager::getModuleDeviceTypes(
- const DeviceVector& devices, const char *moduleId) const {
- sp<HwModule> mod = mHwModules.getModuleFromName(moduleId);
- return mod != 0 ? devices.getDeviceTypesFromHwModule(mod->getHandle()) : AUDIO_DEVICE_NONE;
+ return mAudioPatches.valueAt(index);
}
bool AudioPolicyManager::isDeviceOfModule(
@@ -674,8 +660,8 @@
* Switching to or from incall state or switching between telephony and VoIP lead to force
* routing command.
*/
- bool force = ((is_state_in_call(oldState) != is_state_in_call(state))
- || (is_state_in_call(state) && (state != oldState)));
+ bool force = ((isStateInCall(oldState) != isStateInCall(state))
+ || (isStateInCall(state) && (state != oldState)));
// check for device and output changes triggered by new phone state
checkForDeviceAndOutputChanges();
@@ -721,11 +707,11 @@
updateCallRouting(rxDevices, delayMs);
} else if (oldState == AUDIO_MODE_IN_CALL) {
if (mCallRxPatch != 0) {
- mpClientInterface->releaseAudioPatch(mCallRxPatch->mAfPatchHandle, 0);
+ releaseAudioPatchInternal(mCallRxPatch->getHandle());
mCallRxPatch.clear();
}
if (mCallTxPatch != 0) {
- mpClientInterface->releaseAudioPatch(mCallTxPatch->mAfPatchHandle, 0);
+ releaseAudioPatchInternal(mCallTxPatch->getHandle());
mCallTxPatch.clear();
}
setOutputDevices(mPrimaryOutput, rxDevices, force, 0);
@@ -786,27 +772,11 @@
//FIXME: workaround for truncated touch sounds
// to be removed when the problem is handled by system UI
uint32_t delayMs = 0;
- uint32_t waitMs = 0;
if (usage == AUDIO_POLICY_FORCE_FOR_COMMUNICATION) {
delayMs = TOUCH_SOUND_FIXED_DELAY_MS;
}
- if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) {
- DeviceVector newDevices = getNewOutputDevices(mPrimaryOutput, true /*fromCache*/);
- waitMs = updateCallRouting(newDevices, delayMs);
- }
- for (size_t i = 0; i < mOutputs.size(); i++) {
- sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(i);
- DeviceVector newDevices = getNewOutputDevices(outputDesc, true /*fromCache*/);
- if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || (outputDesc != mPrimaryOutput)) {
- // As done in setDeviceConnectionState, we could also fix default device issue by
- // preventing the force re-routing in case of default dev that distinguishes on address.
- // Let's give back to engine full device choice decision however.
- waitMs = setOutputDevices(outputDesc, newDevices, !newDevices.isEmpty(), delayMs);
- }
- if (forceVolumeReeval && !newDevices.isEmpty()) {
- applyStreamVolumes(outputDesc, newDevices.types(), waitMs, true);
- }
- }
+
+ updateCallAndOutputRouting(forceVolumeReeval, delayMs);
for (const auto& activeDesc : mInputs.getActiveInputs()) {
auto newDevice = getNewInputDevice(activeDesc);
@@ -839,7 +809,7 @@
// if explicitly requested
static const uint32_t kRelevantFlags =
(AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD |
- AUDIO_OUTPUT_FLAG_VOIP_RX);
+ AUDIO_OUTPUT_FLAG_VOIP_RX | AUDIO_OUTPUT_FLAG_MMAP_NOIRQ);
flags =
(audio_output_flags_t)((flags & kRelevantFlags) | AUDIO_OUTPUT_FLAG_DIRECT);
}
@@ -860,7 +830,7 @@
continue;
}
// reject profiles if connected device does not support codec
- if (!curProfile->deviceSupportsEncodedFormats(devices.types())) {
+ if (!curProfile->devicesSupportEncodedFormats(devices.types())) {
continue;
}
if (!directOnly) return curProfile;
@@ -937,7 +907,8 @@
audio_output_flags_t *flags,
audio_port_handle_t *selectedDeviceId,
bool *isRequestedDeviceForExclusiveUse,
- std::vector<sp<SwAudioOutputDescriptor>> *secondaryDescs)
+ std::vector<sp<SwAudioOutputDescriptor>> *secondaryDescs,
+ output_type_t *outputType)
{
DeviceVector outputDevices;
const audio_port_handle_t requestedPortId = *selectedDeviceId;
@@ -945,6 +916,7 @@
const sp<DeviceDescriptor> requestedDevice =
mAvailableOutputDevices.getDeviceFromId(requestedPortId);
+ *outputType = API_OUTPUT_INVALID;
status_t status = getAudioAttributes(resultAttr, attr, *stream);
if (status != NO_ERROR) {
return status;
@@ -978,13 +950,21 @@
if (usePrimaryOutputFromPolicyMixes) {
*output = policyDesc->mIoHandle;
sp<AudioPolicyMix> mix = policyDesc->mPolicyMix.promote();
- sp<DeviceDescriptor> deviceDesc =
- mAvailableOutputDevices.getDevice(mix->mDeviceType,
- mix->mDeviceAddress,
- AUDIO_FORMAT_DEFAULT);
- *selectedDeviceId = deviceDesc != 0 ? deviceDesc->getId() : AUDIO_PORT_HANDLE_NONE;
- ALOGV("getOutputForAttr() returns output %d", *output);
- return NO_ERROR;
+ if (mix != nullptr) {
+ sp<DeviceDescriptor> deviceDesc =
+ mAvailableOutputDevices.getDevice(mix->mDeviceType,
+ mix->mDeviceAddress,
+ AUDIO_FORMAT_DEFAULT);
+ *selectedDeviceId = deviceDesc != 0 ? deviceDesc->getId() : AUDIO_PORT_HANDLE_NONE;
+
+ ALOGV("getOutputForAttr() returns output %d", *output);
+ if (resultAttr->usage == AUDIO_USAGE_VIRTUAL_SOURCE) {
+ *outputType = API_OUT_MIX_PLAYBACK;
+ } else {
+ *outputType = API_OUTPUT_LEGACY;
+ }
+ return NO_ERROR;
+ }
}
// Virtual sources must always be dynamicaly or explicitly routed
if (resultAttr->usage == AUDIO_USAGE_VIRTUAL_SOURCE) {
@@ -1004,10 +984,10 @@
// FIXME: provide a more generic approach which is not device specific and move this back
// to getOutputForDevice.
// TODO: Remove check of AUDIO_STREAM_MUSIC once migration is completed on the app side.
- if (outputDevices.types() == AUDIO_DEVICE_OUT_TELEPHONY_TX &&
+ if (outputDevices.onlyContainsDevicesWithType(AUDIO_DEVICE_OUT_TELEPHONY_TX) &&
(*stream == AUDIO_STREAM_MUSIC || resultAttr->usage == AUDIO_USAGE_VOICE_COMMUNICATION) &&
audio_is_linear_pcm(config->format) &&
- isInCall()) {
+ isCallAudioAccessible()) {
if (requestedPortId != AUDIO_PORT_HANDLE_NONE) {
*flags = (audio_output_flags_t)AUDIO_OUTPUT_FLAG_INCALL_MUSIC;
*isRequestedDeviceForExclusiveUse = true;
@@ -1040,6 +1020,12 @@
*selectedDeviceId = getFirstDeviceId(outputDevices);
+ if (outputDevices.onlyContainsDevicesWithType(AUDIO_DEVICE_OUT_TELEPHONY_TX)) {
+ *outputType = API_OUTPUT_TELEPHONY_TX;
+ } else {
+ *outputType = API_OUTPUT_LEGACY;
+ }
+
ALOGV("%s returns output %d selectedDeviceId %d", __func__, *output, *selectedDeviceId);
return NO_ERROR;
@@ -1054,7 +1040,8 @@
audio_output_flags_t *flags,
audio_port_handle_t *selectedDeviceId,
audio_port_handle_t *portId,
- std::vector<audio_io_handle_t> *secondaryOutputs)
+ std::vector<audio_io_handle_t> *secondaryOutputs,
+ output_type_t *outputType)
{
// The supplied portId must be AUDIO_PORT_HANDLE_NONE
if (*portId != AUDIO_PORT_HANDLE_NONE) {
@@ -1074,7 +1061,7 @@
status_t status = getOutputForAttrInt(&resultAttr, output, session, attr, stream, uid,
config, flags, selectedDeviceId, &isRequestedDeviceForExclusiveUse,
- &secondaryOutputDescs);
+ &secondaryOutputDescs, outputType);
if (status != NO_ERROR) {
return status;
}
@@ -1085,9 +1072,10 @@
}
audio_config_base_t clientConfig = {.sample_rate = config->sample_rate,
+ .channel_mask = config->channel_mask,
.format = config->format,
- .channel_mask = config->channel_mask };
- *portId = AudioPort::getNextUniqueId();
+ };
+ *portId = PolicyAudioPort::getNextUniqueId();
sp<TrackClientDescriptor> clientDesc =
new TrackClientDescriptor(*portId, uid, session, resultAttr, clientConfig,
@@ -1184,9 +1172,9 @@
if (!desc->isDuplicated() && (profile == desc->mProfile)) {
// reuse direct output if currently open by the same client
// and configured with same parameters
- if ((config->sample_rate == desc->mSamplingRate) &&
- (config->format == desc->mFormat) &&
- (channelMask == desc->mChannelMask) &&
+ if ((config->sample_rate == desc->getSamplingRate()) &&
+ (config->format == desc->getFormat()) &&
+ (channelMask == desc->getChannelMask()) &&
(session == desc->mDirectClientSession)) {
desc->mDirectOpenCount++;
ALOGI("%s reusing direct output %d for session %d", __func__,
@@ -1213,10 +1201,10 @@
for (size_t j = 0; j < patch->mPatch.num_sinks; ++j) {
const struct audio_port_config *sink = &patch->mPatch.sinks[j];
if (sink->type == AUDIO_PORT_TYPE_DEVICE &&
- (sink->ext.device.type & devices.types()) != AUDIO_DEVICE_NONE &&
+ devices.containsDeviceWithType(sink->ext.device.type) &&
(address.isEmpty() || strncmp(sink->ext.device.address, address.string(),
AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0)) {
- releaseAudioPatch(patch->mHandle, mUidCached);
+ releaseAudioPatch(patch->getHandle(), mUidCached);
break;
}
}
@@ -1226,13 +1214,13 @@
// only accept an output with the requested parameters
if (status != NO_ERROR ||
- (config->sample_rate != 0 && config->sample_rate != outputDesc->mSamplingRate) ||
- (config->format != AUDIO_FORMAT_DEFAULT && config->format != outputDesc->mFormat) ||
- (channelMask != 0 && channelMask != outputDesc->mChannelMask)) {
+ (config->sample_rate != 0 && config->sample_rate != outputDesc->getSamplingRate()) ||
+ (config->format != AUDIO_FORMAT_DEFAULT && config->format != outputDesc->getFormat()) ||
+ (channelMask != 0 && channelMask != outputDesc->getChannelMask())) {
ALOGV("%s failed opening direct output: output %d sample rate %d %d,"
"format %d %d, channel mask %04x %04x", __func__, output, config->sample_rate,
- outputDesc->mSamplingRate, config->format, outputDesc->mFormat,
- channelMask, outputDesc->mChannelMask);
+ outputDesc->getSamplingRate(), config->format, outputDesc->getFormat(),
+ channelMask, outputDesc->getChannelMask());
if (output != AUDIO_IO_HANDLE_NONE) {
outputDesc->close();
}
@@ -1303,7 +1291,7 @@
const struct audio_port_config *source = &patch->mPatch.sources[j];
if (source->type == AUDIO_PORT_TYPE_DEVICE &&
source->ext.device.hw_module == msdModule->getHandle()) {
- msdPatches.addAudioPatch(patch->mHandle, patch);
+ msdPatches.addAudioPatch(patch->getHandle(), patch);
}
}
}
@@ -1338,19 +1326,19 @@
// Each IOProfile represents a MixPort from audio_policy_configuration.xml
for (const auto &inProfile : inputProfiles) {
if (hwAvSync == ((inProfile->getFlags() & AUDIO_INPUT_FLAG_HW_AV_SYNC) != 0)) {
- msdProfiles.appendVector(inProfile->getAudioProfiles());
+ appendAudioProfiles(msdProfiles, inProfile->getAudioProfiles());
}
}
AudioProfileVector deviceProfiles;
for (const auto &outProfile : outputProfiles) {
if (hwAvSync == ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) != 0)) {
- deviceProfiles.appendVector(outProfile->getAudioProfiles());
+ appendAudioProfiles(deviceProfiles, outProfile->getAudioProfiles());
}
}
struct audio_config_base bestSinkConfig;
- status_t result = msdProfiles.findBestMatchingOutputConfig(deviceProfiles,
+ status_t result = findBestMatchingOutputConfig(msdProfiles, deviceProfiles,
compressedFormatsOrder, surroundChannelMasksOrder, true /*preferHigherSamplingRates*/,
- &bestSinkConfig);
+ bestSinkConfig);
if (result != NO_ERROR) {
ALOGD("%s() no matching profiles found for device: %s, hwAvSync: %d",
__func__, outputDevice->toString().c_str(), hwAvSync);
@@ -1362,6 +1350,14 @@
// For encoded streams force direct flag to prevent downstream mixing.
sinkConfig->flags.output = static_cast<audio_output_flags_t>(
sinkConfig->flags.output | AUDIO_OUTPUT_FLAG_DIRECT);
+ if (audio_is_iec61937_compatible(sinkConfig->format)) {
+ // For formats compatible with IEC61937 encapsulation, assume that
+ // the record thread input from MSD is IEC61937 framed (for proportional buffer sizing).
+ // Add the AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO flag so downstream HAL can distinguish between
+ // raw and IEC61937 framed streams.
+ sinkConfig->flags.output = static_cast<audio_output_flags_t>(
+ sinkConfig->flags.output | AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO);
+ }
sourceConfig->sample_rate = bestSinkConfig.sample_rate;
// Specify exact channel mask to prevent guessing by bit count in PatchPanel.
sourceConfig->channel_mask = audio_channel_mask_out_to_in(bestSinkConfig.channel_mask);
@@ -1425,7 +1421,7 @@
if (audio_patches_are_equal(¤tPatch->mPatch, patch)) {
return NO_ERROR;
}
- releaseAudioPatch(currentPatch->mHandle, mUidCached);
+ releaseAudioPatch(currentPatch->getHandle(), mUidCached);
}
status_t status = installPatch(__func__, -1 /*index*/, nullptr /*patchHandle*/,
patch, 0 /*delayMs*/, mUidCached, nullptr /*patchDescPtr*/);
@@ -1503,13 +1499,13 @@
// If haptic channel is specified, use the haptic output if present.
// When using haptic output, same audio format and sample rate are required.
const uint32_t outputHapticChannelCount = audio_channel_count_from_out_mask(
- outputDesc->mChannelMask & AUDIO_CHANNEL_HAPTIC_ALL);
+ outputDesc->getChannelMask() & AUDIO_CHANNEL_HAPTIC_ALL);
if ((hapticChannelCount == 0) != (outputHapticChannelCount == 0)) {
continue;
}
if (outputHapticChannelCount >= hapticChannelCount
- && format == outputDesc->mFormat
- && samplingRate == outputDesc->mSamplingRate) {
+ && format == outputDesc->getFormat()
+ && samplingRate == outputDesc->getSamplingRate()) {
currentMatchCriteria[0] = outputHapticChannelCount;
}
@@ -1517,12 +1513,13 @@
currentMatchCriteria[1] = popcount(outputDesc->mFlags & functionalFlags);
// channel mask and channel count match
- uint32_t outputChannelCount = audio_channel_count_from_out_mask(outputDesc->mChannelMask);
+ uint32_t outputChannelCount = audio_channel_count_from_out_mask(
+ outputDesc->getChannelMask());
if (channelMask != AUDIO_CHANNEL_NONE && channelCount > 2 &&
channelCount <= outputChannelCount) {
if ((audio_channel_mask_get_representation(channelMask) ==
- audio_channel_mask_get_representation(outputDesc->mChannelMask)) &&
- ((channelMask & outputDesc->mChannelMask) == channelMask)) {
+ audio_channel_mask_get_representation(outputDesc->getChannelMask())) &&
+ ((channelMask & outputDesc->getChannelMask()) == channelMask)) {
currentMatchCriteria[2] = outputChannelCount;
}
currentMatchCriteria[3] = outputChannelCount;
@@ -1530,8 +1527,8 @@
// sampling rate match
if (samplingRate > SAMPLE_RATE_HZ_DEFAULT &&
- samplingRate <= outputDesc->mSamplingRate) {
- currentMatchCriteria[4] = outputDesc->mSamplingRate;
+ samplingRate <= outputDesc->getSamplingRate()) {
+ currentMatchCriteria[4] = outputDesc->getSamplingRate();
}
// performance flags match
@@ -1540,8 +1537,8 @@
// format match
if (format != AUDIO_FORMAT_INVALID) {
currentMatchCriteria[6] =
- AudioPort::kFormatDistanceMax -
- AudioPort::formatDistance(format, outputDesc->mFormat);
+ PolicyAudioPort::kFormatDistanceMax -
+ PolicyAudioPort::formatDistance(format, outputDesc->getFormat());
}
// primary output match
@@ -1630,7 +1627,7 @@
DeviceVector devices;
sp<AudioPolicyMix> policyMix = outputDesc->mPolicyMix.promote();
const char *address = NULL;
- if (policyMix != NULL) {
+ if (policyMix != nullptr) {
audio_devices_t newDeviceType;
address = policyMix->mDeviceAddress.string();
if ((policyMix->mRouteFlags & MIX_ROUTE_FLAG_LOOP_BACK) == MIX_ROUTE_FLAG_LOOP_BACK) {
@@ -1755,14 +1752,15 @@
}
if (stream == AUDIO_STREAM_ENFORCED_AUDIBLE &&
- mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) {
+ mEngine->getForceUse(
+ AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) {
setStrategyMute(streamToStrategy(AUDIO_STREAM_ALARM), true, outputDesc);
}
// Automatically enable the remote submix input when output is started on a re routing mix
// of type MIX_TYPE_RECORDERS
- if (audio_is_remote_submix_device(devices.types()) && policyMix != NULL &&
- policyMix->mMixType == MIX_TYPE_RECORDERS) {
+ if (isSingleDeviceType(devices.types(), &audio_is_remote_submix_device) &&
+ policyMix != NULL && policyMix->mMixType == MIX_TYPE_RECORDERS) {
setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
address,
@@ -1809,8 +1807,9 @@
// Automatically disable the remote submix input when output is stopped on a
// re routing mix of type MIX_TYPE_RECORDERS
sp<AudioPolicyMix> policyMix = outputDesc->mPolicyMix.promote();
- if (audio_is_remote_submix_device(outputDesc->devices().types()) &&
- policyMix != NULL &&
+ if (isSingleDeviceType(
+ outputDesc->devices().types(), &audio_is_remote_submix_device) &&
+ policyMix != nullptr &&
policyMix->mMixType == MIX_TYPE_RECORDERS) {
setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
@@ -2065,7 +2064,7 @@
isSoundTrigger = attributes.source == AUDIO_SOURCE_HOTWORD &&
mSoundTriggerSessions.indexOfKey(session) >= 0;
- *portId = AudioPort::getNextUniqueId();
+ *portId = PolicyAudioPort::getNextUniqueId();
clientDesc = new RecordClientDescriptor(*portId, riid, uid, session, attributes, *config,
requestedDeviceId, attributes.source, flags,
@@ -2239,19 +2238,25 @@
return status;
}
- // increment activity count before calling getNewInputDevice() below as only active sessions
+ // increment activity count before calling getNewInputDevice() below as only active sessions
// are considered for device selection
inputDesc->setClientActive(client, true);
// indicate active capture to sound trigger service if starting capture from a mic on
// primary HW module
sp<DeviceDescriptor> device = getNewInputDevice(inputDesc);
- setInputDevice(input, device, true /* force */);
+ if (device != nullptr) {
+ status = setInputDevice(input, device, true /* force */);
+ } else {
+ ALOGW("%s no new input device can be found for descriptor %d",
+ __FUNCTION__, inputDesc->getId());
+ status = BAD_VALUE;
+ }
- if (inputDesc->activeCount() == 1) {
+ if (status == NO_ERROR && inputDesc->activeCount() == 1) {
sp<AudioPolicyMix> policyMix = inputDesc->mPolicyMix.promote();
// if input maps to a dynamic policy with an activity listener, notify of state change
- if ((policyMix != NULL)
+ if ((policyMix != nullptr)
&& ((policyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
mpClientInterface->onDynamicPolicyMixStateUpdate(policyMix->mDeviceAddress,
MIX_STATE_MIXING);
@@ -2260,7 +2265,7 @@
DeviceVector primaryInputDevices = availablePrimaryModuleInputDevices();
if (primaryInputDevices.contains(device) &&
mInputs.activeInputsCountOnDevices(primaryInputDevices) == 1) {
- SoundTrigger::setCaptureState(true);
+ mpClientInterface->setSoundTriggerCaptureState(true);
}
// automatically enable the remote submix output when input is started if not
@@ -2268,7 +2273,7 @@
// For remote submix (a virtual device), we open only one input per capture request.
if (audio_is_remote_submix_device(inputDesc->getDeviceType())) {
String8 address = String8("");
- if (policyMix == NULL) {
+ if (policyMix == nullptr) {
address = String8("0");
} else if (policyMix->mMixType == MIX_TYPE_PLAYERS) {
address = policyMix->mDeviceAddress;
@@ -2279,11 +2284,16 @@
address, "remote-submix", AUDIO_FORMAT_DEFAULT);
}
}
+ } else if (status != NO_ERROR) {
+ // Restore client activity state.
+ inputDesc->setClientActive(client, false);
+ inputDesc->stop();
}
- ALOGV("%s input %d source = %d exit", __FUNCTION__, input, client->source());
+ ALOGV("%s input %d source = %d status = %d exit",
+ __FUNCTION__, input, client->source(), status);
- return NO_ERROR;
+ return status;
}
status_t AudioPolicyManager::stopInput(audio_port_handle_t portId)
@@ -2310,7 +2320,7 @@
} else {
sp<AudioPolicyMix> policyMix = inputDesc->mPolicyMix.promote();
// if input maps to a dynamic policy with an activity listener, notify of state change
- if ((policyMix != NULL)
+ if ((policyMix != nullptr)
&& ((policyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
mpClientInterface->onDynamicPolicyMixStateUpdate(policyMix->mDeviceAddress,
MIX_STATE_IDLE);
@@ -2320,7 +2330,7 @@
// used by a policy mix of type MIX_TYPE_RECORDERS
if (audio_is_remote_submix_device(inputDesc->getDeviceType())) {
String8 address = String8("");
- if (policyMix == NULL) {
+ if (policyMix == nullptr) {
address = String8("0");
} else if (policyMix->mMixType == MIX_TYPE_PLAYERS) {
address = policyMix->mDeviceAddress;
@@ -2338,7 +2348,7 @@
DeviceVector primaryInputDevices = availablePrimaryModuleInputDevices();
if (primaryInputDevices.contains(inputDesc->getDevice()) &&
mInputs.activeInputsCountOnDevices(primaryInputDevices) == 0) {
- SoundTrigger::setCaptureState(false);
+ mpClientInterface->setSoundTriggerCaptureState(false);
}
inputDesc->clearPreemptedSessions();
}
@@ -2397,7 +2407,8 @@
const sp<AudioInputDescriptor> input = mInputs.valueAt(i);
if (input->clientsList().size() == 0
|| !mAvailableInputDevices.containsAtLeastOne(input->supportedDevices())
- || (input->getAudioPort()->getFlags() & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0) {
+ || (input->getPolicyAudioPort()->getFlags()
+ & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0) {
inputsToClose.push_back(mInputs.keyAt(i));
} else {
bool close = false;
@@ -2457,10 +2468,12 @@
{
// if device is AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME, return volume for device selected for this
// stream by the engine.
+ DeviceTypeSet deviceTypes = {device};
if (device == AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
- device = mEngine->getOutputDevicesForStream(stream, true /*fromCache*/).types();
+ deviceTypes = mEngine->getOutputDevicesForStream(
+ stream, true /*fromCache*/).types();
}
- return getVolumeIndex(getVolumeCurves(stream), *index, device);
+ return getVolumeIndex(getVolumeCurves(stream), *index, deviceTypes);
}
status_t AudioPolicyManager::setVolumeIndexForAttributes(const audio_attributes_t &attributes,
@@ -2485,19 +2498,20 @@
return status;
}
- audio_devices_t curSrcDevice;
+ DeviceTypeSet curSrcDevices;
auto curCurvAttrs = curves.getAttributes();
if (!curCurvAttrs.empty() && curCurvAttrs.front() != defaultAttr) {
auto attr = curCurvAttrs.front();
- curSrcDevice = mEngine->getOutputDevicesForAttributes(attr, nullptr, false).types();
+ curSrcDevices = mEngine->getOutputDevicesForAttributes(attr, nullptr, false).types();
} else if (!curves.getStreamTypes().empty()) {
auto stream = curves.getStreamTypes().front();
- curSrcDevice = mEngine->getOutputDevicesForStream(stream, false).types();
+ curSrcDevices = mEngine->getOutputDevicesForStream(stream, false).types();
} else {
ALOGE("%s: Invalid src %d: no valid attributes nor stream",__func__, vs);
return BAD_VALUE;
}
- curSrcDevice = Volume::getDeviceForVolume(curSrcDevice);
+ audio_devices_t curSrcDevice = Volume::getDeviceForVolume(curSrcDevices);
+ resetDeviceTypes(curSrcDevices, curSrcDevice);
// update volume on all outputs and streams matching the following:
// - The requested stream (or a stream matching for volume control) is active on the output
@@ -2509,21 +2523,34 @@
// no specific device volume value exists for currently selected device.
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
- audio_devices_t curDevice = desc->devices().types();
+ DeviceTypeSet curDevices = desc->devices().types();
- if (curDevice & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
- curDevice |= AUDIO_DEVICE_OUT_SPEAKER;
- curDevice &= ~AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+ if (curDevices.erase(AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
+ curDevices.insert(AUDIO_DEVICE_OUT_SPEAKER);
}
-
+ if (!(desc->isActive(vs) || isInCall())) {
+ continue;
+ }
+ if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME &&
+ curDevices.find(device) == curDevices.end()) {
+ continue;
+ }
+ bool applyVolume = false;
+ if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
+ curSrcDevices.insert(device);
+ applyVolume = (curSrcDevices.find(
+ Volume::getDeviceForVolume(curDevices)) != curSrcDevices.end());
+ } else {
+ applyVolume = !curves.hasVolumeIndexForDevice(curSrcDevice);
+ }
+ if (!applyVolume) {
+ continue; // next output
+ }
// Inter / intra volume group priority management: Loop on strategies arranged by priority
// If a higher priority strategy is active, and the output is routed to a device with a
// HW Gain management, do not change the volume
- bool applyVolume = false;
if (desc->useHwGain()) {
- if (!(desc->isActive(toVolumeSource(group)) || isInCall())) {
- continue;
- }
+ applyVolume = false;
for (const auto &productStrategy : mEngine->getOrderedProductStrategies()) {
auto activeClients = desc->clientsList(true /*activeOnly*/, productStrategy,
false /*preferredDevice*/);
@@ -2557,37 +2584,16 @@
if (!applyVolume) {
continue; // next output
}
- status_t volStatus = checkAndSetVolume(curves, vs, index, desc, curDevice,
- (vs == toVolumeSource(AUDIO_STREAM_SYSTEM)?
- TOUCH_SOUND_FIXED_DELAY_MS : 0));
- if (volStatus != NO_ERROR) {
- status = volStatus;
- }
- continue;
}
- if (!(desc->isActive(vs) || isInCall())) {
- continue;
- }
- if ((device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) && ((curDevice & device) == 0)) {
- continue;
- }
- if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
- curSrcDevice |= device;
- applyVolume = (Volume::getDeviceForVolume(curDevice) & curSrcDevice) != 0;
- } else {
- applyVolume = !curves.hasVolumeIndexForDevice(curSrcDevice);
- }
- if (applyVolume) {
- //FIXME: workaround for truncated touch sounds
- // delayed volume change for system stream to be removed when the problem is
- // handled by system UI
- status_t volStatus = checkAndSetVolume(
- curves, vs, index, desc, curDevice,
- ((vs == toVolumeSource(AUDIO_STREAM_SYSTEM))?
- TOUCH_SOUND_FIXED_DELAY_MS : 0));
- if (volStatus != NO_ERROR) {
- status = volStatus;
- }
+ //FIXME: workaround for truncated touch sounds
+ // delayed volume change for system stream to be removed when the problem is
+ // handled by system UI
+ status_t volStatus = checkAndSetVolume(
+ curves, vs, index, desc, curDevices,
+ ((vs == toVolumeSource(AUDIO_STREAM_SYSTEM))?
+ TOUCH_SOUND_FIXED_DELAY_MS : 0));
+ if (volStatus != NO_ERROR) {
+ status = volStatus;
}
}
mpClientInterface->onAudioVolumeGroupChanged(group, 0 /*flags*/);
@@ -2625,22 +2631,23 @@
{
// if device is AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME, return volume for device selected for this
// stream by the engine.
+ DeviceTypeSet deviceTypes = {device};
if (device == AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
- device = mEngine->getOutputDevicesForAttributes(attr, nullptr, true /*fromCache*/).types();
+ DeviceTypeSet deviceTypes = mEngine->getOutputDevicesForAttributes(
+ attr, nullptr, true /*fromCache*/).types();
}
- return getVolumeIndex(getVolumeCurves(attr), index, device);
+ return getVolumeIndex(getVolumeCurves(attr), index, deviceTypes);
}
status_t AudioPolicyManager::getVolumeIndex(const IVolumeCurves &curves,
int &index,
- audio_devices_t device) const
+ const DeviceTypeSet& deviceTypes) const
{
- if (!audio_is_output_device(device)) {
+ if (isSingleDeviceType(deviceTypes, audio_is_output_device)) {
return BAD_VALUE;
}
- device = Volume::getDeviceForVolume(device);
- index = curves.getVolumeIndex(device);
- ALOGV("%s: device %08x index %d", __FUNCTION__, device, index);
+ index = curves.getVolumeIndex(deviceTypes);
+ ALOGV("%s: device %s index %d", __FUNCTION__, dumpDeviceTypes(deviceTypes).c_str(), index);
return NO_ERROR;
}
@@ -2735,12 +2742,14 @@
int session,
int id)
{
- ssize_t index = mOutputs.indexOfKey(io);
- if (index < 0) {
- index = mInputs.indexOfKey(io);
+ if (session != AUDIO_SESSION_DEVICE) {
+ ssize_t index = mOutputs.indexOfKey(io);
if (index < 0) {
- ALOGW("registerEffect() unknown io %d", io);
- return INVALID_OPERATION;
+ index = mInputs.indexOfKey(io);
+ if (index < 0) {
+ ALOGW("registerEffect() unknown io %d", io);
+ return INVALID_OPERATION;
+ }
}
}
return mEffects.registerEffect(desc, io, session, id,
@@ -2760,16 +2769,6 @@
return mEffects.unregisterEffect(id);
}
-void AudioPolicyManager::cleanUpEffectsForIo(audio_io_handle_t io)
-{
- EffectDescriptorCollection effects = mEffects.getEffectsForIo(io);
- for (size_t i = 0; i < effects.size(); i++) {
- ALOGW("%s removing stale effect %s, id %d on closed IO %d",
- __func__, effects.valueAt(i)->mDesc.name, effects.keyAt(i), io);
- unregisterEffect(effects.keyAt(i));
- }
-}
-
status_t AudioPolicyManager::setEffectEnabled(int id, bool enabled)
{
sp<EffectDescriptor> effect = mEffects.getEffect(id);
@@ -2889,9 +2888,9 @@
// stereo and let audio flinger do the channel conversion if needed.
outputConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
inputConfig.channel_mask = AUDIO_CHANNEL_IN_STEREO;
- rSubmixModule->addOutputProfile(address, &outputConfig,
+ rSubmixModule->addOutputProfile(address.c_str(), &outputConfig,
AUDIO_DEVICE_OUT_REMOTE_SUBMIX, address);
- rSubmixModule->addInputProfile(address, &inputConfig,
+ rSubmixModule->addInputProfile(address.c_str(), &inputConfig,
AUDIO_DEVICE_IN_REMOTE_SUBMIX, address);
if ((res = setDeviceConnectionStateInt(deviceTypeToMakeAvailable,
@@ -2987,8 +2986,8 @@
}
}
}
- rSubmixModule->removeOutputProfile(address);
- rSubmixModule->removeInputProfile(address);
+ rSubmixModule->removeOutputProfile(address.c_str());
+ rSubmixModule->removeInputProfile(address.c_str());
} else if ((mix.mRouteFlags & MIX_ROUTE_FLAG_RENDER) == MIX_ROUTE_FLAG_RENDER) {
if (mPolicyMixes.unregisterMix(mix) != NO_ERROR) {
@@ -3029,13 +3028,13 @@
// reevaluate outputs for all given devices
for (size_t i = 0; i < devices.size(); i++) {
sp<DeviceDescriptor> devDesc = mHwModules.getDeviceDescriptor(
- devices[i].mType, devices[i].mAddress, String8(),
+ devices[i].mType, devices[i].mAddress.c_str(), String8(),
AUDIO_FORMAT_DEFAULT);
SortedVector<audio_io_handle_t> outputs;
if (checkOutputsForDevice(devDesc, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
outputs) != NO_ERROR) {
ALOGE("setUidDeviceAffinities() error in checkOutputsForDevice for device=%08x"
- " addr=%s", devices[i].mType, devices[i].mAddress.string());
+ " addr=%s", devices[i].mType, devices[i].mAddress.c_str());
return INVALID_OPERATION;
}
}
@@ -3055,6 +3054,115 @@
return res;
}
+status_t AudioPolicyManager::setPreferredDeviceForStrategy(product_strategy_t strategy,
+ const AudioDeviceTypeAddr &device) {
+ ALOGI("%s() strategy=%d device=%08x addr=%s", __FUNCTION__,
+ strategy, device.mType, device.mAddress.c_str());
+ // strategy preferred device is only for output devices
+ if (!audio_is_output_device(device.mType)) {
+ ALOGE("%s() device=%08x is NOT an output device", __FUNCTION__, device.mType);
+ return BAD_VALUE;
+ }
+
+ status_t status = mEngine->setPreferredDeviceForStrategy(strategy, device);
+ if (status != NO_ERROR) {
+ ALOGW("Engine could not set preferred device %08x %s for strategy %d",
+ device.mType, device.mAddress.c_str(), strategy);
+ return status;
+ }
+
+ checkForDeviceAndOutputChanges();
+ updateCallAndOutputRouting();
+
+ return NO_ERROR;
+}
+
+void AudioPolicyManager::updateCallAndOutputRouting(bool forceVolumeReeval, uint32_t delayMs)
+{
+ uint32_t waitMs = 0;
+ if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) {
+ DeviceVector newDevices = getNewOutputDevices(mPrimaryOutput, true /*fromCache*/);
+ waitMs = updateCallRouting(newDevices, delayMs);
+ }
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(i);
+ DeviceVector newDevices = getNewOutputDevices(outputDesc, true /*fromCache*/);
+ if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || (outputDesc != mPrimaryOutput)) {
+ // As done in setDeviceConnectionState, we could also fix default device issue by
+ // preventing the force re-routing in case of default dev that distinguishes on address.
+ // Let's give back to engine full device choice decision however.
+ waitMs = setOutputDevices(outputDesc, newDevices, !newDevices.isEmpty(), delayMs);
+ }
+ if (forceVolumeReeval && !newDevices.isEmpty()) {
+ applyStreamVolumes(outputDesc, newDevices.types(), waitMs, true);
+ }
+ }
+}
+
+status_t AudioPolicyManager::removePreferredDeviceForStrategy(product_strategy_t strategy)
+{
+ ALOGI("%s() strategy=%d", __FUNCTION__, strategy);
+
+ status_t status = mEngine->removePreferredDeviceForStrategy(strategy);
+ if (status != NO_ERROR) {
+ ALOGW("Engine could not remove preferred device for strategy %d", strategy);
+ return status;
+ }
+
+ checkForDeviceAndOutputChanges();
+ updateCallAndOutputRouting();
+
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManager::getPreferredDeviceForStrategy(product_strategy_t strategy,
+ AudioDeviceTypeAddr &device) {
+ return mEngine->getPreferredDeviceForStrategy(strategy, device);
+}
+
+status_t AudioPolicyManager::setUserIdDeviceAffinities(int userId,
+ const Vector<AudioDeviceTypeAddr>& devices) {
+ ALOGI("%s() userId=%d num devices %zu", __FUNCTION__, userId, devices.size());
+ // userId/device affinity is only for output devices
+ for (size_t i = 0; i < devices.size(); i++) {
+ if (!audio_is_output_device(devices[i].mType)) {
+ ALOGE("%s() device=%08x is NOT an output device",
+ __FUNCTION__,
+ devices[i].mType);
+ return BAD_VALUE;
+ }
+ }
+
+ status_t status = mPolicyMixes.setUserIdDeviceAffinities(userId, devices);
+ if (status != NO_ERROR) {
+ ALOGE("%s() could not set device affinity for userId %d",
+ __FUNCTION__, userId);
+ return status;
+ }
+
+ // reevaluate outputs for all devices
+ checkForDeviceAndOutputChanges();
+ updateCallAndOutputRouting();
+
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManager::removeUserIdDeviceAffinities(int userId) {
+ ALOGI("%s() userId=%d", __FUNCTION__, userId);
+ status_t status = mPolicyMixes.removeUserIdDeviceAffinities(userId);
+ if (status != NO_ERROR) {
+ ALOGE("%s() Could not remove all device affinities fo userId = %d",
+ __FUNCTION__, userId);
+ return status;
+ }
+
+ // reevaluate outputs for all devices
+ checkForDeviceAndOutputChanges();
+ updateCallAndOutputRouting();
+
+ return NO_ERROR;
+}
+
void AudioPolicyManager::dump(String8 *dst) const
{
dst->appendFormat("\nAudioPolicyManager Dump: %p\n", this);
@@ -3200,7 +3308,7 @@
ALOGV("%s() profile %sfound with name: %s, "
"sample rate: %u, format: 0x%x, channel_mask: 0x%x, output flags: 0x%x",
__FUNCTION__, profile != 0 ? "" : "NOT ",
- (profile != 0 ? profile->getTagName().string() : "null"),
+ (profile != 0 ? profile->getTagName().c_str() : "null"),
config.sample_rate, config.format, config.channel_mask, output_flags);
return (profile != 0);
}
@@ -3302,16 +3410,16 @@
return BAD_VALUE;
}
-status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch,
- audio_patch_handle_t *handle,
- uid_t uid)
+status_t AudioPolicyManager::createAudioPatchInternal(const struct audio_patch *patch,
+ audio_patch_handle_t *handle,
+ uid_t uid, uint32_t delayMs,
+ const sp<SourceClientDescriptor>& sourceDesc)
{
- ALOGV("createAudioPatch()");
-
+ ALOGV("%s", __func__);
if (handle == NULL || patch == NULL) {
return BAD_VALUE;
}
- ALOGV("createAudioPatch() num sources %d num sinks %d", patch->num_sources, patch->num_sinks);
+ ALOGV("%s num sources %d num sinks %d", __func__, patch->num_sources, patch->num_sinks);
if (!audio_patch_is_valid(patch)) {
return BAD_VALUE;
@@ -3333,22 +3441,22 @@
sp<AudioPatch> patchDesc;
ssize_t index = mAudioPatches.indexOfKey(*handle);
- ALOGV("createAudioPatch source id %d role %d type %d", patch->sources[0].id,
- patch->sources[0].role,
- patch->sources[0].type);
+ ALOGV("%s source id %d role %d type %d", __func__, patch->sources[0].id,
+ patch->sources[0].role,
+ patch->sources[0].type);
#if LOG_NDEBUG == 0
for (size_t i = 0; i < patch->num_sinks; i++) {
- ALOGV("createAudioPatch sink %zu: id %d role %d type %d", i, patch->sinks[i].id,
- patch->sinks[i].role,
- patch->sinks[i].type);
+ ALOGV("%s sink %zu: id %d role %d type %d", __func__ ,i, patch->sinks[i].id,
+ patch->sinks[i].role,
+ patch->sinks[i].type);
}
#endif
if (index >= 0) {
patchDesc = mAudioPatches.valueAt(index);
- ALOGV("createAudioPatch() mUidCached %d patchDesc->mUid %d uid %d",
- mUidCached, patchDesc->mUid, uid);
- if (patchDesc->mUid != mUidCached && uid != patchDesc->mUid) {
+ ALOGV("%s mUidCached %d patchDesc->mUid %d uid %d",
+ __func__, mUidCached, patchDesc->getUid(), uid);
+ if (patchDesc->getUid() != mUidCached && uid != patchDesc->getUid()) {
return INVALID_OPERATION;
}
} else {
@@ -3358,15 +3466,15 @@
if (patch->sources[0].type == AUDIO_PORT_TYPE_MIX) {
sp<SwAudioOutputDescriptor> outputDesc = mOutputs.getOutputFromId(patch->sources[0].id);
if (outputDesc == NULL) {
- ALOGV("createAudioPatch() output not found for id %d", patch->sources[0].id);
+ ALOGV("%s output not found for id %d", __func__, patch->sources[0].id);
return BAD_VALUE;
}
ALOG_ASSERT(!outputDesc->isDuplicated(),"duplicated output %d in source in ports",
outputDesc->mIoHandle);
if (patchDesc != 0) {
if (patchDesc->mPatch.sources[0].id != patch->sources[0].id) {
- ALOGV("createAudioPatch() source id differs for patch current id %d new id %d",
- patchDesc->mPatch.sources[0].id, patch->sources[0].id);
+ ALOGV("%s source id differs for patch current id %d new id %d",
+ __func__, patchDesc->mPatch.sources[0].id, patch->sources[0].id);
return BAD_VALUE;
}
}
@@ -3375,13 +3483,13 @@
// Only support mix to devices connection
// TODO add support for mix to mix connection
if (patch->sinks[i].type != AUDIO_PORT_TYPE_DEVICE) {
- ALOGV("createAudioPatch() source mix but sink is not a device");
+ ALOGV("%s source mix but sink is not a device", __func__);
return INVALID_OPERATION;
}
sp<DeviceDescriptor> devDesc =
mAvailableOutputDevices.getDeviceFromId(patch->sinks[i].id);
if (devDesc == 0) {
- ALOGV("createAudioPatch() out device not found for id %d", patch->sinks[i].id);
+ ALOGV("%s out device not found for id %d", __func__, patch->sinks[i].id);
return BAD_VALUE;
}
@@ -3393,8 +3501,7 @@
patch->sources[0].channel_mask,
NULL, // updatedChannelMask
AUDIO_OUTPUT_FLAG_NONE /*FIXME*/)) {
- ALOGV("createAudioPatch() profile not supported for device %08x",
- devDesc->type());
+ ALOGV("%s profile not supported for device %08x", __func__, devDesc->type());
return INVALID_OPERATION;
}
devices.add(devDesc);
@@ -3404,19 +3511,19 @@
}
// TODO: reconfigure output format and channels here
- ALOGV("createAudioPatch() setting device %08x on output %d",
- devices.types(), outputDesc->mIoHandle);
+ ALOGV("%s setting device %s on output %d",
+ __func__, dumpDeviceTypes(devices.types()).c_str(), outputDesc->mIoHandle);
setOutputDevices(outputDesc, devices, true, 0, handle);
index = mAudioPatches.indexOfKey(*handle);
if (index >= 0) {
if (patchDesc != 0 && patchDesc != mAudioPatches.valueAt(index)) {
- ALOGW("createAudioPatch() setOutputDevice() did not reuse the patch provided");
+ ALOGW("%s setOutputDevice() did not reuse the patch provided", __func__);
}
patchDesc = mAudioPatches.valueAt(index);
- patchDesc->mUid = uid;
- ALOGV("createAudioPatch() success");
+ patchDesc->setUid(uid);
+ ALOGV("%s success", __func__);
} else {
- ALOGW("createAudioPatch() setOutputDevice() failed to create a patch");
+ ALOGW("%s setOutputDevice() failed to create a patch", __func__);
return INVALID_OPERATION;
}
} else if (patch->sources[0].type == AUDIO_PORT_TYPE_DEVICE) {
@@ -3455,19 +3562,19 @@
return INVALID_OPERATION;
}
// TODO: reconfigure output format and channels here
- ALOGV("%s() setting device %s on output %d", __func__,
+ ALOGV("%s setting device %s on output %d", __func__,
device->toString().c_str(), inputDesc->mIoHandle);
setInputDevice(inputDesc->mIoHandle, device, true, handle);
index = mAudioPatches.indexOfKey(*handle);
if (index >= 0) {
if (patchDesc != 0 && patchDesc != mAudioPatches.valueAt(index)) {
- ALOGW("createAudioPatch() setInputDevice() did not reuse the patch provided");
+ ALOGW("%s setInputDevice() did not reuse the patch provided", __func__);
}
patchDesc = mAudioPatches.valueAt(index);
- patchDesc->mUid = uid;
- ALOGV("createAudioPatch() success");
+ patchDesc->setUid(uid);
+ ALOGV("%s success", __func__);
} else {
- ALOGW("createAudioPatch() setInputDevice() failed to create a patch");
+ ALOGW("%s setInputDevice() failed to create a patch", __func__);
return INVALID_OPERATION;
}
} else if (patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE) {
@@ -3485,55 +3592,97 @@
//update source and sink with our own data as the data passed in the patch may
// be incomplete.
- struct audio_patch newPatch = *patch;
- srcDevice->toAudioPortConfig(&newPatch.sources[0], &patch->sources[0]);
+ PatchBuilder patchBuilder;
+ audio_port_config sourcePortConfig = {};
+ srcDevice->toAudioPortConfig(&sourcePortConfig, &patch->sources[0]);
+ patchBuilder.addSource(sourcePortConfig);
for (size_t i = 0; i < patch->num_sinks; i++) {
if (patch->sinks[i].type != AUDIO_PORT_TYPE_DEVICE) {
- ALOGV("createAudioPatch() source device but one sink is not a device");
+ ALOGV("%s source device but one sink is not a device", __func__);
return INVALID_OPERATION;
}
-
sp<DeviceDescriptor> sinkDevice =
mAvailableOutputDevices.getDeviceFromId(patch->sinks[i].id);
if (sinkDevice == 0) {
return BAD_VALUE;
}
- sinkDevice->toAudioPortConfig(&newPatch.sinks[i], &patch->sinks[i]);
+ audio_port_config sinkPortConfig = {};
+ sinkDevice->toAudioPortConfig(&sinkPortConfig, &patch->sinks[i]);
+ patchBuilder.addSink(sinkPortConfig);
// create a software bridge in PatchPanel if:
// - source and sink devices are on different HW modules OR
// - audio HAL version is < 3.0
// - audio HAL version is >= 3.0 but no route has been declared between devices
+ // - called from startAudioSource (aka sourceDesc != nullptr) and source device does
+ // not have a gain controller
if (!srcDevice->hasSameHwModuleAs(sinkDevice) ||
(srcDevice->getModuleVersionMajor() < 3) ||
- !srcDevice->getModule()->supportsPatch(srcDevice, sinkDevice)) {
+ !srcDevice->getModule()->supportsPatch(srcDevice, sinkDevice) ||
+ (sourceDesc != nullptr &&
+ srcDevice->getAudioPort()->getGains().size() == 0)) {
// support only one sink device for now to simplify output selection logic
if (patch->num_sinks > 1) {
return INVALID_OPERATION;
}
- SortedVector<audio_io_handle_t> outputs =
- getOutputsForDevices(DeviceVector(sinkDevice), mOutputs);
- // if the sink device is reachable via an opened output stream, request to go via
- // this output stream by adding a second source to the patch description
- const audio_io_handle_t output = selectOutput(outputs);
- if (output != AUDIO_IO_HANDLE_NONE) {
- sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
- if (outputDesc->isDuplicated()) {
+ audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
+ if (sourceDesc != nullptr) {
+ // take care of dynamic routing for SwOutput selection,
+ audio_attributes_t attributes = sourceDesc->attributes();
+ audio_stream_type_t stream = sourceDesc->stream();
+ audio_attributes_t resultAttr;
+ audio_config_t config = AUDIO_CONFIG_INITIALIZER;
+ config.sample_rate = sourceDesc->config().sample_rate;
+ config.channel_mask = sourceDesc->config().channel_mask;
+ config.format = sourceDesc->config().format;
+ audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ bool isRequestedDeviceForExclusiveUse = false;
+ std::vector<sp<SwAudioOutputDescriptor>> secondaryOutputs;
+ output_type_t outputType;
+ getOutputForAttrInt(&resultAttr, &output, AUDIO_SESSION_NONE, &attributes,
+ &stream, sourceDesc->uid(), &config, &flags,
+ &selectedDeviceId, &isRequestedDeviceForExclusiveUse,
+ &secondaryOutputs, &outputType);
+ if (output == AUDIO_IO_HANDLE_NONE) {
+ ALOGV("%s no output for device %s",
+ __FUNCTION__, sinkDevice->toString().c_str());
return INVALID_OPERATION;
}
- outputDesc->toAudioPortConfig(&newPatch.sources[1], &patch->sources[0]);
- newPatch.sources[1].ext.mix.usecase.stream = AUDIO_STREAM_PATCH;
- newPatch.num_sources = 2;
+ } else {
+ SortedVector<audio_io_handle_t> outputs =
+ getOutputsForDevices(DeviceVector(sinkDevice), mOutputs);
+ // if the sink device is reachable via an opened output stream, request to
+ // go via this output stream by adding a second source to the patch
+ // description
+ output = selectOutput(outputs);
+ }
+ if (output != AUDIO_IO_HANDLE_NONE) {
+ sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
+ if (outputDesc->isDuplicated()) {
+ ALOGV("%s output for device %s is duplicated",
+ __FUNCTION__, sinkDevice->toString().c_str());
+ return INVALID_OPERATION;
+ }
+ audio_port_config srcMixPortConfig = {};
+ outputDesc->toAudioPortConfig(&srcMixPortConfig, &patch->sources[0]);
+ if (sourceDesc != nullptr) {
+ sourceDesc->setSwOutput(outputDesc);
+ }
+ // for volume control, we may need a valid stream
+ srcMixPortConfig.ext.mix.usecase.stream = sourceDesc != nullptr ?
+ sourceDesc->stream() : AUDIO_STREAM_PATCH;
+ patchBuilder.addSource(srcMixPortConfig);
}
}
}
// TODO: check from routing capabilities in config file and other conflicting patches
- status_t status = installPatch(__func__, index, handle, &newPatch, 0, uid, &patchDesc);
+ status_t status = installPatch(
+ __func__, index, handle, patchBuilder.patch(), delayMs, uid, &patchDesc);
if (status != NO_ERROR) {
- ALOGW("createAudioPatch() patch panel could not connect device patch, error %d",
- status);
+ ALOGW("%s patch panel could not connect device patch, error %d", __func__, status);
return INVALID_OPERATION;
}
} else {
@@ -3556,18 +3705,29 @@
return BAD_VALUE;
}
sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
- ALOGV("releaseAudioPatch() mUidCached %d patchDesc->mUid %d uid %d",
- mUidCached, patchDesc->mUid, uid);
- if (patchDesc->mUid != mUidCached && uid != patchDesc->mUid) {
+ ALOGV("%s() mUidCached %d patchDesc->mUid %d uid %d",
+ __func__, mUidCached, patchDesc->getUid(), uid);
+ if (patchDesc->getUid() != mUidCached && uid != patchDesc->getUid()) {
return INVALID_OPERATION;
}
+ return releaseAudioPatchInternal(handle);
+}
+status_t AudioPolicyManager::releaseAudioPatchInternal(audio_patch_handle_t handle,
+ uint32_t delayMs)
+{
+ ALOGV("%s patch %d", __func__, handle);
+ if (mAudioPatches.indexOfKey(handle) < 0) {
+ ALOGE("%s: no patch found with handle=%d", __func__, handle);
+ return BAD_VALUE;
+ }
+ sp<AudioPatch> patchDesc = mAudioPatches.valueFor(handle);
struct audio_patch *patch = &patchDesc->mPatch;
- patchDesc->mUid = mUidCached;
+ patchDesc->setUid(mUidCached);
if (patch->sources[0].type == AUDIO_PORT_TYPE_MIX) {
sp<SwAudioOutputDescriptor> outputDesc = mOutputs.getOutputFromId(patch->sources[0].id);
if (outputDesc == NULL) {
- ALOGV("releaseAudioPatch() output not found for id %d", patch->sources[0].id);
+ ALOGV("%s output not found for id %d", __func__, patch->sources[0].id);
return BAD_VALUE;
}
@@ -3580,7 +3740,7 @@
if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) {
sp<AudioInputDescriptor> inputDesc = mInputs.getInputFromId(patch->sinks[0].id);
if (inputDesc == NULL) {
- ALOGV("releaseAudioPatch() input not found for id %d", patch->sinks[0].id);
+ ALOGV("%s input not found for id %d", __func__, patch->sinks[0].id);
return BAD_VALUE;
}
setInputDevice(inputDesc->mIoHandle,
@@ -3588,10 +3748,11 @@
true,
NULL);
} else if (patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE) {
- status_t status = mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
- ALOGV("releaseAudioPatch() patch panel returned %d patchHandle %d",
- status, patchDesc->mAfPatchHandle);
- removeAudioPatch(patchDesc->mHandle);
+ status_t status =
+ mpClientInterface->releaseAudioPatch(patchDesc->getAfHandle(), delayMs);
+ ALOGV("%s patch panel returned %d patchHandle %d",
+ __func__, status, patchDesc->getAfHandle());
+ removeAudioPatch(patchDesc->getHandle());
nextAudioPortGeneration();
mpClientInterface->onAudioPatchListUpdate();
} else {
@@ -3689,7 +3850,7 @@
{
for (ssize_t i = (ssize_t)mAudioPatches.size() - 1; i >= 0; i--) {
sp<AudioPatch> patchDesc = mAudioPatches.valueAt(i);
- if (patchDesc->mUid == uid) {
+ if (patchDesc->getUid() == uid) {
releaseAudioPatch(mAudioPatches.keyAt(i), uid);
}
}
@@ -3823,13 +3984,10 @@
return BAD_VALUE;
}
- *portId = AudioPort::getNextUniqueId();
-
- struct audio_patch dummyPatch = {};
- sp<AudioPatch> patchDesc = new AudioPatch(&dummyPatch, uid);
+ *portId = PolicyAudioPort::getNextUniqueId();
sp<SourceClientDescriptor> sourceDesc =
- new SourceClientDescriptor(*portId, uid, *attributes, patchDesc, srcDevice,
+ new SourceClientDescriptor(*portId, uid, *attributes, *source, srcDevice,
mEngine->getStreamTypeForAttributes(*attributes),
mEngine->getProductStrategyForAttributes(*attributes),
toVolumeSource(*attributes));
@@ -3849,7 +4007,6 @@
disconnectAudioSource(sourceDesc);
audio_attributes_t attributes = sourceDesc->attributes();
- audio_stream_type_t stream = sourceDesc->stream();
sp<DeviceDescriptor> srcDevice = sourceDesc->srcDevice();
DeviceVector sinkDevices =
@@ -3859,89 +4016,55 @@
ALOG_ASSERT(mAvailableOutputDevices.contains(sinkDevice), "%s: Device %s not available",
__FUNCTION__, sinkDevice->toString().c_str());
- audio_patch_handle_t afPatchHandle = AUDIO_PATCH_HANDLE_NONE;
-
- if (srcDevice->hasSameHwModuleAs(sinkDevice) &&
- srcDevice->getModuleVersionMajor() >= 3 &&
- sinkDevice->getModule()->supportsPatch(srcDevice, sinkDevice) &&
- srcDevice->getAudioPort()->mGains.size() > 0) {
- ALOGV("%s Device to Device route supported by >=3.0 HAL", __FUNCTION__);
- // TODO: may explicitly specify whether we should use HW or SW patch
- // create patch between src device and output device
- // create Hwoutput and add to mHwOutputs
- } else {
- audio_attributes_t resultAttr;
- audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
- audio_config_t config = AUDIO_CONFIG_INITIALIZER;
- config.sample_rate = sourceDesc->config().sample_rate;
- config.channel_mask = sourceDesc->config().channel_mask;
- config.format = sourceDesc->config().format;
- audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
- audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
- bool isRequestedDeviceForExclusiveUse = false;
- std::vector<sp<SwAudioOutputDescriptor>> secondaryOutputs;
- getOutputForAttrInt(&resultAttr, &output, AUDIO_SESSION_NONE,
- &attributes, &stream, sourceDesc->uid(), &config, &flags,
- &selectedDeviceId, &isRequestedDeviceForExclusiveUse,
- &secondaryOutputs);
- if (output == AUDIO_IO_HANDLE_NONE) {
- ALOGV("%s no output for device %08x", __FUNCTION__, sinkDevices.types());
- return INVALID_OPERATION;
- }
- sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
- if (outputDesc->isDuplicated()) {
- ALOGV("%s output for device %08x is duplicated", __FUNCTION__, sinkDevices.types());
- return INVALID_OPERATION;
- }
- status_t status = outputDesc->start();
+ PatchBuilder patchBuilder;
+ patchBuilder.addSink(sinkDevice).addSource(srcDevice);
+ audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE;
+ status_t status =
+ createAudioPatchInternal(patchBuilder.patch(), &handle, mUidCached, 0, sourceDesc);
+ if (status != NO_ERROR || mAudioPatches.indexOfKey(handle) < 0) {
+ ALOGW("%s patch panel could not connect device patch, error %d", __func__, status);
+ return INVALID_OPERATION;
+ }
+ sourceDesc->setPatchHandle(handle);
+ // SW Bridge? (@todo: HW bridge, keep track of HwOutput for device selection "reconsideration")
+ sp<SwAudioOutputDescriptor> swOutput = sourceDesc->swOutput().promote();
+ if (swOutput != 0) {
+ status = swOutput->start();
if (status != NO_ERROR) {
- return status;
+ goto FailureSourceAdded;
}
-
- // create a special patch with no sink and two sources:
- // - the second source indicates to PatchPanel through which output mix this patch should
- // be connected as well as the stream type for volume control
- // - the sink is defined by whatever output device is currently selected for the output
- // though which this patch is routed.
- PatchBuilder patchBuilder;
- patchBuilder.addSource(srcDevice).addSource(outputDesc, { .stream = stream });
- status = mpClientInterface->createAudioPatch(patchBuilder.patch(),
- &afPatchHandle,
- 0);
- ALOGV("%s patch panel returned %d patchHandle %d", __FUNCTION__,
- status, afPatchHandle);
- sourceDesc->patchDesc()->mPatch = *patchBuilder.patch();
- if (status != NO_ERROR) {
- ALOGW("%s patch panel could not connect device patch, error %d",
- __FUNCTION__, status);
- return INVALID_OPERATION;
- }
-
- if (outputDesc->getClient(sourceDesc->portId()) != nullptr) {
+ if (swOutput->getClient(sourceDesc->portId()) != nullptr) {
ALOGW("%s source portId has already been attached to outputDesc", __func__);
- return INVALID_OPERATION;
+ goto FailureReleasePatch;
}
- outputDesc->addClient(sourceDesc);
-
+ swOutput->addClient(sourceDesc);
uint32_t delayMs = 0;
- status = startSource(outputDesc, sourceDesc, &delayMs);
-
+ status = startSource(swOutput, sourceDesc, &delayMs);
if (status != NO_ERROR) {
- mpClientInterface->releaseAudioPatch(sourceDesc->patchDesc()->mAfPatchHandle, 0);
- outputDesc->removeClient(sourceDesc->portId());
- outputDesc->stop();
- return status;
+ ALOGW("%s failed to start source, error %d", __FUNCTION__, status);
+ goto FailureSourceActive;
}
- sourceDesc->setSwOutput(outputDesc);
if (delayMs != 0) {
usleep(delayMs * 1000);
}
+ } else {
+ sp<HwAudioOutputDescriptor> hwOutputDesc = sourceDesc->hwOutput().promote();
+ if (hwOutputDesc != 0) {
+ // create Hwoutput and add to mHwOutputs
+ } else {
+ ALOGW("%s source has neither SW nor HW output", __FUNCTION__);
+ }
}
-
- sourceDesc->patchDesc()->mAfPatchHandle = afPatchHandle;
- addAudioPatch(sourceDesc->patchDesc()->mHandle, sourceDesc->patchDesc());
-
return NO_ERROR;
+
+FailureSourceActive:
+ swOutput->stop();
+ releaseOutput(sourceDesc->portId());
+FailureSourceAdded:
+ sourceDesc->setSwOutput(nullptr);
+FailureReleasePatch:
+ releaseAudioPatchInternal(handle);
+ return INVALID_OPERATION;
}
status_t AudioPolicyManager::stopAudioSource(audio_port_handle_t portId)
@@ -3999,7 +4122,7 @@
float AudioPolicyManager::getStreamVolumeDB(
audio_stream_type_t stream, int index, audio_devices_t device)
{
- return computeVolume(getVolumeCurves(stream), toVolumeSource(stream), index, device);
+ return computeVolume(getVolumeCurves(stream), toVolumeSource(stream), index, {device});
}
status_t AudioPolicyManager::getSurroundFormats(unsigned int *numSurroundFormats,
@@ -4099,12 +4222,12 @@
sp<SwAudioOutputDescriptor> outputDesc;
bool profileUpdated = false;
- DeviceVector hdmiOutputDevices = mAvailableOutputDevices.getDevicesFromTypeMask(
- AUDIO_DEVICE_OUT_HDMI);
+ DeviceVector hdmiOutputDevices = mAvailableOutputDevices.getDevicesFromType(
+ AUDIO_DEVICE_OUT_HDMI);
for (size_t i = 0; i < hdmiOutputDevices.size(); i++) {
// Simulate reconnection to update enabled surround sound formats.
- String8 address = hdmiOutputDevices[i]->address();
- String8 name = hdmiOutputDevices[i]->getName();
+ String8 address = String8(hdmiOutputDevices[i]->address().c_str());
+ std::string name = hdmiOutputDevices[i]->getName();
status_t status = setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_HDMI,
AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
address.c_str(),
@@ -4121,12 +4244,12 @@
profileUpdated |= (status == NO_ERROR);
}
// FIXME: Why doing this for input HDMI devices if we don't augment their reported formats?
- DeviceVector hdmiInputDevices = mAvailableInputDevices.getDevicesFromTypeMask(
+ DeviceVector hdmiInputDevices = mAvailableInputDevices.getDevicesFromType(
AUDIO_DEVICE_IN_HDMI);
for (size_t i = 0; i < hdmiInputDevices.size(); i++) {
// Simulate reconnection to update enabled surround sound formats.
- String8 address = hdmiInputDevices[i]->address();
- String8 name = hdmiInputDevices[i]->getName();
+ String8 address = String8(hdmiInputDevices[i]->address().c_str());
+ std::string name = hdmiInputDevices[i]->getName();
status_t status = setDeviceConnectionStateInt(AUDIO_DEVICE_IN_HDMI,
AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
address.c_str(),
@@ -4151,11 +4274,11 @@
return profileUpdated ? NO_ERROR : INVALID_OPERATION;
}
-void AudioPolicyManager::setAppState(uid_t uid, app_state_t state)
+void AudioPolicyManager::setAppState(audio_port_handle_t portId, app_state_t state)
{
- ALOGV("%s(uid:%d, state:%d)", __func__, uid, state);
+ ALOGV("%s(portId:%d, state:%d)", __func__, portId, state);
for (size_t i = 0; i < mInputs.size(); i++) {
- mInputs.valueAt(i)->setAppState(uid, state);
+ mInputs.valueAt(i)->setAppState(portId, state);
}
}
@@ -4176,36 +4299,31 @@
return false;
}
+bool AudioPolicyManager::isCallScreenModeSupported()
+{
+ return getConfig().isCallScreenModeSupported();
+}
+
+
status_t AudioPolicyManager::disconnectAudioSource(const sp<SourceClientDescriptor>& sourceDesc)
{
ALOGV("%s port Id %d", __FUNCTION__, sourceDesc->portId());
-
- sp<AudioPatch> patchDesc = mAudioPatches.valueFor(sourceDesc->patchDesc()->mHandle);
- if (patchDesc == 0) {
- ALOGW("%s source has no patch with handle %d", __FUNCTION__,
- sourceDesc->patchDesc()->mHandle);
- return BAD_VALUE;
- }
- removeAudioPatch(sourceDesc->patchDesc()->mHandle);
-
- sp<SwAudioOutputDescriptor> swOutputDesc = sourceDesc->swOutput().promote();
- if (swOutputDesc != 0) {
- status_t status = stopSource(swOutputDesc, sourceDesc);
+ sp<SwAudioOutputDescriptor> swOutput = sourceDesc->swOutput().promote();
+ if (swOutput != 0) {
+ status_t status = stopSource(swOutput, sourceDesc);
if (status == NO_ERROR) {
- swOutputDesc->stop();
+ swOutput->stop();
}
- swOutputDesc->removeClient(sourceDesc->portId());
- mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
+ releaseOutput(sourceDesc->portId());
} else {
sp<HwAudioOutputDescriptor> hwOutputDesc = sourceDesc->hwOutput().promote();
if (hwOutputDesc != 0) {
- // release patch between src device and output device
// close Hwoutput and remove from mHwOutputs
} else {
ALOGW("%s source has neither SW nor HW output", __FUNCTION__);
}
}
- return NO_ERROR;
+ return releaseAudioPatchInternal(sourceDesc->getPatchHandle());
}
sp<SourceClientDescriptor> AudioPolicyManager::getSourceForAttributesOnOutput(
@@ -4279,7 +4397,7 @@
mpClientInterface(clientInterface),
mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
mA2dpSuspended(false),
- mConfig(mHwModulesAll, mAvailableOutputDevices, mAvailableInputDevices, mDefaultOutputDevice),
+ mConfig(mHwModulesAll, mOutputDevicesAll, mInputDevicesAll, mDefaultOutputDevice),
mAudioPortGeneration(1),
mBeaconMuteRefCount(0),
mBeaconPlayingRefCount(0),
@@ -4294,17 +4412,8 @@
: AudioPolicyManager(clientInterface, false /*forTesting*/)
{
loadConfig();
- initialize();
}
-// This check is to catch any legacy platform updating to Q without having
-// switched to XML since its deprecation on O.
-// TODO: after Q release, remove this check and flag as XML is now the only
-// option and all legacy platform should have transitioned to XML.
-#ifndef USE_XML_AUDIO_POLICY_CONF
-#error Audio policy no longer supports legacy .conf configuration format
-#endif
-
void AudioPolicyManager::loadConfig() {
if (deserializeAudioPolicyXmlConfig(getConfig()) != NO_ERROR) {
ALOGE("could not load audio policy configuration file, setting defaults");
@@ -4313,17 +4422,18 @@
}
status_t AudioPolicyManager::initialize() {
- // Once policy config has been parsed, retrieve an instance of the engine and initialize it.
- audio_policy::EngineInstance *engineInstance = audio_policy::EngineInstance::getInstance();
- if (!engineInstance) {
- ALOGE("%s: Could not get an instance of policy engine", __FUNCTION__);
- return NO_INIT;
- }
- // Retrieve the Policy Manager Interface
- mEngine = engineInstance->queryInterface<AudioPolicyManagerInterface>();
- if (mEngine == NULL) {
- ALOGE("%s: Failed to get Policy Engine Interface", __FUNCTION__);
- return NO_INIT;
+ {
+ auto engLib = EngineLibrary::load(
+ "libaudiopolicyengine" + getConfig().getEngineLibraryNameSuffix() + ".so");
+ if (!engLib) {
+ ALOGE("%s: Failed to load the engine library", __FUNCTION__);
+ return NO_INIT;
+ }
+ mEngine = engLib->createEngine();
+ if (mEngine == nullptr) {
+ ALOGE("%s: Failed to instantiate the APM engine", __FUNCTION__);
+ return NO_INIT;
+ }
}
mEngine->setObserver(this);
status_t status = mEngine->initCheck();
@@ -4332,141 +4442,9 @@
return status;
}
- // mAvailableOutputDevices and mAvailableInputDevices now contain all attached devices
+ // after parsing the config, mOutputDevicesAll and mInputDevicesAll contain all known devices;
// open all output streams needed to access attached devices
- for (const auto& hwModule : mHwModulesAll) {
- hwModule->setHandle(mpClientInterface->loadHwModule(hwModule->getName()));
- if (hwModule->getHandle() == AUDIO_MODULE_HANDLE_NONE) {
- ALOGW("could not open HW module %s", hwModule->getName());
- continue;
- }
- mHwModules.push_back(hwModule);
- // open all output streams needed to access attached devices
- // except for direct output streams that are only opened when they are actually
- // required by an app.
- // This also validates mAvailableOutputDevices list
- for (const auto& outProfile : hwModule->getOutputProfiles()) {
- if (!outProfile->canOpenNewIo()) {
- ALOGE("Invalid Output profile max open count %u for profile %s",
- outProfile->maxOpenCount, outProfile->getTagName().c_str());
- continue;
- }
- if (!outProfile->hasSupportedDevices()) {
- ALOGW("Output profile contains no device on module %s", hwModule->getName());
- continue;
- }
- if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_TTS) != 0) {
- mTtsOutputAvailable = true;
- }
-
- if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
- continue;
- }
- const DeviceVector &supportedDevices = outProfile->getSupportedDevices();
- DeviceVector availProfileDevices = supportedDevices.filter(mAvailableOutputDevices);
- sp<DeviceDescriptor> supportedDevice = 0;
- if (supportedDevices.contains(mDefaultOutputDevice)) {
- supportedDevice = mDefaultOutputDevice;
- } else {
- // choose first device present in profile's SupportedDevices also part of
- // mAvailableOutputDevices.
- if (availProfileDevices.isEmpty()) {
- continue;
- }
- supportedDevice = availProfileDevices.itemAt(0);
- }
- if (!mAvailableOutputDevices.contains(supportedDevice)) {
- continue;
- }
- sp<SwAudioOutputDescriptor> outputDesc = new SwAudioOutputDescriptor(outProfile,
- mpClientInterface);
- audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
- status_t status = outputDesc->open(nullptr, DeviceVector(supportedDevice),
- AUDIO_STREAM_DEFAULT,
- AUDIO_OUTPUT_FLAG_NONE, &output);
- if (status != NO_ERROR) {
- ALOGW("Cannot open output stream for devices %s on hw module %s",
- supportedDevice->toString().c_str(), hwModule->getName());
- continue;
- }
- for (const auto &device : availProfileDevices) {
- // give a valid ID to an attached device once confirmed it is reachable
- if (!device->isAttached()) {
- device->attach(hwModule);
- }
- }
- if (mPrimaryOutput == 0 &&
- outProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
- mPrimaryOutput = outputDesc;
- }
- addOutput(output, outputDesc);
- setOutputDevices(outputDesc,
- DeviceVector(supportedDevice),
- true,
- 0,
- NULL);
- }
- // open input streams needed to access attached devices to validate
- // mAvailableInputDevices list
- for (const auto& inProfile : hwModule->getInputProfiles()) {
- if (!inProfile->canOpenNewIo()) {
- ALOGE("Invalid Input profile max open count %u for profile %s",
- inProfile->maxOpenCount, inProfile->getTagName().c_str());
- continue;
- }
- if (!inProfile->hasSupportedDevices()) {
- ALOGW("Input profile contains no device on module %s", hwModule->getName());
- continue;
- }
- // chose first device present in profile's SupportedDevices also part of
- // available input devices
- const DeviceVector &supportedDevices = inProfile->getSupportedDevices();
- DeviceVector availProfileDevices = supportedDevices.filter(mAvailableInputDevices);
- if (availProfileDevices.isEmpty()) {
- ALOGE("%s: Input device list is empty!", __FUNCTION__);
- continue;
- }
- sp<AudioInputDescriptor> inputDesc =
- new AudioInputDescriptor(inProfile, mpClientInterface);
-
- audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
- status_t status = inputDesc->open(nullptr,
- availProfileDevices.itemAt(0),
- AUDIO_SOURCE_MIC,
- AUDIO_INPUT_FLAG_NONE,
- &input);
- if (status != NO_ERROR) {
- ALOGW("Cannot open input stream for device %s on hw module %s",
- availProfileDevices.toString().c_str(),
- hwModule->getName());
- continue;
- }
- for (const auto &device : availProfileDevices) {
- // give a valid ID to an attached device once confirmed it is reachable
- if (!device->isAttached()) {
- device->attach(hwModule);
- device->importAudioPort(inProfile, true);
- }
- }
- inputDesc->close();
- }
- }
- // make sure all attached devices have been allocated a unique ID
- auto checkAndSetAvailable = [this](auto& devices) {
- for (size_t i = 0; i < devices.size();) {
- const auto &device = devices[i];
- if (!device->isAttached()) {
- ALOGW("device %s is unreachable", device->toString().c_str());
- devices.remove(device);
- continue;
- }
- // Device is now validated and can be appended to the available devices of the engine
- setEngineDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
- i++;
- }
- };
- checkAndSetAvailable(mAvailableOutputDevices);
- checkAndSetAvailable(mAvailableInputDevices);
+ onNewAudioModulesAvailable();
// make sure default device is reachable
if (mDefaultOutputDevice == 0 || !mAvailableOutputDevices.contains(mDefaultOutputDevice)) {
@@ -4476,11 +4454,11 @@
}
// If microphones address is empty, set it according to device type
for (size_t i = 0; i < mAvailableInputDevices.size(); i++) {
- if (mAvailableInputDevices[i]->address().isEmpty()) {
+ if (mAvailableInputDevices[i]->address().empty()) {
if (mAvailableInputDevices[i]->type() == AUDIO_DEVICE_IN_BUILTIN_MIC) {
- mAvailableInputDevices[i]->setAddress(String8(AUDIO_BOTTOM_MICROPHONE_ADDRESS));
+ mAvailableInputDevices[i]->setAddress(AUDIO_BOTTOM_MICROPHONE_ADDRESS);
} else if (mAvailableInputDevices[i]->type() == AUDIO_DEVICE_IN_BACK_MIC) {
- mAvailableInputDevices[i]->setAddress(String8(AUDIO_BACK_MICROPHONE_ADDRESS));
+ mAvailableInputDevices[i]->setAddress(AUDIO_BACK_MICROPHONE_ADDRESS);
}
}
}
@@ -4521,11 +4499,139 @@
// ---
+void AudioPolicyManager::onNewAudioModulesAvailable()
+{
+ for (const auto& hwModule : mHwModulesAll) {
+ if (std::find(mHwModules.begin(), mHwModules.end(), hwModule) != mHwModules.end()) {
+ continue;
+ }
+ hwModule->setHandle(mpClientInterface->loadHwModule(hwModule->getName()));
+ if (hwModule->getHandle() == AUDIO_MODULE_HANDLE_NONE) {
+ ALOGW("could not open HW module %s", hwModule->getName());
+ continue;
+ }
+ mHwModules.push_back(hwModule);
+ // open all output streams needed to access attached devices
+ // except for direct output streams that are only opened when they are actually
+ // required by an app.
+ // This also validates mAvailableOutputDevices list
+ for (const auto& outProfile : hwModule->getOutputProfiles()) {
+ if (!outProfile->canOpenNewIo()) {
+ ALOGE("Invalid Output profile max open count %u for profile %s",
+ outProfile->maxOpenCount, outProfile->getTagName().c_str());
+ continue;
+ }
+ if (!outProfile->hasSupportedDevices()) {
+ ALOGW("Output profile contains no device on module %s", hwModule->getName());
+ continue;
+ }
+ if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_TTS) != 0) {
+ mTtsOutputAvailable = true;
+ }
+
+ if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
+ continue;
+ }
+ const DeviceVector &supportedDevices = outProfile->getSupportedDevices();
+ DeviceVector availProfileDevices = supportedDevices.filter(mOutputDevicesAll);
+ sp<DeviceDescriptor> supportedDevice = 0;
+ if (supportedDevices.contains(mDefaultOutputDevice)) {
+ supportedDevice = mDefaultOutputDevice;
+ } else {
+ // choose first device present in profile's SupportedDevices also part of
+ // mAvailableOutputDevices.
+ if (availProfileDevices.isEmpty()) {
+ continue;
+ }
+ supportedDevice = availProfileDevices.itemAt(0);
+ }
+ if (!mOutputDevicesAll.contains(supportedDevice)) {
+ continue;
+ }
+ sp<SwAudioOutputDescriptor> outputDesc = new SwAudioOutputDescriptor(outProfile,
+ mpClientInterface);
+ audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
+ status_t status = outputDesc->open(nullptr, DeviceVector(supportedDevice),
+ AUDIO_STREAM_DEFAULT,
+ AUDIO_OUTPUT_FLAG_NONE, &output);
+ if (status != NO_ERROR) {
+ ALOGW("Cannot open output stream for devices %s on hw module %s",
+ supportedDevice->toString().c_str(), hwModule->getName());
+ continue;
+ }
+ for (const auto &device : availProfileDevices) {
+ // give a valid ID to an attached device once confirmed it is reachable
+ if (!device->isAttached()) {
+ device->attach(hwModule);
+ mAvailableOutputDevices.add(device);
+ setEngineDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
+ }
+ }
+ if (mPrimaryOutput == 0 &&
+ outProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
+ mPrimaryOutput = outputDesc;
+ }
+ addOutput(output, outputDesc);
+ setOutputDevices(outputDesc,
+ DeviceVector(supportedDevice),
+ true,
+ 0,
+ NULL);
+ }
+ // open input streams needed to access attached devices to validate
+ // mAvailableInputDevices list
+ for (const auto& inProfile : hwModule->getInputProfiles()) {
+ if (!inProfile->canOpenNewIo()) {
+ ALOGE("Invalid Input profile max open count %u for profile %s",
+ inProfile->maxOpenCount, inProfile->getTagName().c_str());
+ continue;
+ }
+ if (!inProfile->hasSupportedDevices()) {
+ ALOGW("Input profile contains no device on module %s", hwModule->getName());
+ continue;
+ }
+ // chose first device present in profile's SupportedDevices also part of
+ // available input devices
+ const DeviceVector &supportedDevices = inProfile->getSupportedDevices();
+ DeviceVector availProfileDevices = supportedDevices.filter(mInputDevicesAll);
+ if (availProfileDevices.isEmpty()) {
+ ALOGE("%s: Input device list is empty!", __FUNCTION__);
+ continue;
+ }
+ sp<AudioInputDescriptor> inputDesc =
+ new AudioInputDescriptor(inProfile, mpClientInterface);
+
+ audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
+ status_t status = inputDesc->open(nullptr,
+ availProfileDevices.itemAt(0),
+ AUDIO_SOURCE_MIC,
+ AUDIO_INPUT_FLAG_NONE,
+ &input);
+ if (status != NO_ERROR) {
+ ALOGW("Cannot open input stream for device %s on hw module %s",
+ availProfileDevices.toString().c_str(),
+ hwModule->getName());
+ continue;
+ }
+ for (const auto &device : availProfileDevices) {
+ // give a valid ID to an attached device once confirmed it is reachable
+ if (!device->isAttached()) {
+ device->attach(hwModule);
+ device->importAudioPortAndPickAudioProfile(inProfile, true);
+ mAvailableInputDevices.add(device);
+ setEngineDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
+ }
+ }
+ inputDesc->close();
+ }
+ }
+}
+
void AudioPolicyManager::addOutput(audio_io_handle_t output,
const sp<SwAudioOutputDescriptor>& outputDesc)
{
mOutputs.add(output, outputDesc);
- applyStreamVolumes(outputDesc, AUDIO_DEVICE_NONE, 0 /* delayMs */, true /* force */);
+ applyStreamVolumes(outputDesc, DeviceTypeSet(), 0 /* delayMs */, true /* force */);
updateMono(output); // update mono status when adding to output list
selectOutputForMusicEffects();
nextAudioPortGeneration();
@@ -4549,7 +4655,7 @@
SortedVector<audio_io_handle_t>& outputs)
{
audio_devices_t deviceType = device->type();
- const String8 &address = device->address();
+ const String8 &address = String8(device->address().c_str());
sp<SwAudioOutputDescriptor> desc;
if (audio_device_is_digital(deviceType)) {
@@ -4562,7 +4668,7 @@
for (size_t i = 0; i < mOutputs.size(); i++) {
desc = mOutputs.valueAt(i);
if (!desc->isDuplicated() && desc->supportsDevice(device)
- && desc->deviceSupportsEncodedFormats(deviceType)) {
+ && desc->devicesSupportEncodedFormats({deviceType})) {
ALOGV("checkOutputsForDevice(): adding opened output %d on device %s",
mOutputs.keyAt(i), device->toString().c_str());
outputs.add(mOutputs.keyAt(i));
@@ -4601,7 +4707,7 @@
// matching profile: save the sample rates, format and channel masks supported
// by the profile in our device descriptor
if (audio_device_is_digital(deviceType)) {
- device->importAudioPort(profile);
+ device->importAudioPortAndPickAudioProfile(profile);
}
break;
}
@@ -4617,7 +4723,7 @@
}
ALOGV("opening output for device %08x with params %s profile %p name %s",
- deviceType, address.string(), profile.get(), profile->getName().string());
+ deviceType, address.string(), profile.get(), profile->getName().c_str());
desc = new SwAudioOutputDescriptor(profile, mpClientInterface);
audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
status_t status = desc->open(nullptr, DeviceVector(device),
@@ -4703,7 +4809,7 @@
outputs.add(output);
// Load digital format info only for digital devices
if (audio_device_is_digital(deviceType)) {
- device->importAudioPort(profile);
+ device->importAudioPortAndPickAudioProfile(profile);
}
if (device_distinguishes_on_address(deviceType)) {
@@ -4727,7 +4833,7 @@
if (!desc->isDuplicated()) {
// exact match on device
if (device_distinguishes_on_address(deviceType) && desc->supportsDevice(device)
- && desc->deviceSupportsEncodedFormats(deviceType)) {
+ && desc->devicesSupportEncodedFormats({deviceType})) {
outputs.add(mOutputs.keyAt(i));
} else if (!mAvailableOutputDevices.containsAtLeastOne(desc->supportedDevices())) {
ALOGV("checkOutputsForDevice(): disconnecting adding output %d",
@@ -4797,7 +4903,7 @@
desc = mInputs.valueAt(input_index);
if (desc->mProfile == profile) {
if (audio_device_is_digital(device->type())) {
- device->importAudioPort(profile);
+ device->importAudioPortAndPickAudioProfile(profile);
}
break;
}
@@ -4821,7 +4927,7 @@
&input);
if (status == NO_ERROR) {
- const String8& address = device->address();
+ const String8& address = String8(device->address().c_str());
if (!address.isEmpty()) {
char *param = audio_device_address_to_parameter(device->type(), address);
mpClientInterface->setParameters(input, String8(param));
@@ -4846,7 +4952,7 @@
profile_index--;
} else {
if (audio_device_is_digital(device->type())) {
- device->importAudioPort(profile);
+ device->importAudioPortAndPickAudioProfile(profile);
}
ALOGV("checkInputsForDevice(): adding input %d", input);
}
@@ -4921,7 +5027,8 @@
ssize_t index = mAudioPatches.indexOfKey(closingOutput->getPatchHandle());
if (index >= 0) {
sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
- (void) /*status_t status*/ mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
+ (void) /*status_t status*/ mpClientInterface->releaseAudioPatch(
+ patchDesc->getAfHandle(), 0);
mAudioPatches.removeItemsAt(index);
mpClientInterface->onAudioPatchListUpdate();
}
@@ -4949,8 +5056,6 @@
setMsdPatch();
}
}
-
- cleanUpEffectsForIo(output);
}
void AudioPolicyManager::closeInput(audio_io_handle_t input)
@@ -4969,7 +5074,8 @@
ssize_t index = mAudioPatches.indexOfKey(inputDesc->getPatchHandle());
if (index >= 0) {
sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
- (void) /*status_t status*/ mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
+ (void) /*status_t status*/ mpClientInterface->releaseAudioPatch(
+ patchDesc->getAfHandle(), 0);
mAudioPatches.removeItemsAt(index);
mpClientInterface->onAudioPatchListUpdate();
}
@@ -4980,10 +5086,8 @@
DeviceVector primaryInputDevices = availablePrimaryModuleInputDevices();
if (primaryInputDevices.contains(device) &&
mInputs.activeInputsCountOnDevices(primaryInputDevices) == 0) {
- SoundTrigger::setCaptureState(false);
+ mpClientInterface->setSoundTriggerCaptureState(false);
}
-
- cleanUpEffectsForIo(input);
}
SortedVector<audio_io_handle_t> AudioPolicyManager::getOutputsForDevices(
@@ -4998,7 +5102,7 @@
i, openOutputs.valueAt(i)->isDuplicated(),
openOutputs.valueAt(i)->supportedDevices().toString().c_str());
if (openOutputs.valueAt(i)->supportsAllDevices(devices)
- && openOutputs.valueAt(i)->deviceSupportsEncodedFormats(devices.types())) {
+ && openOutputs.valueAt(i)->devicesSupportEncodedFormats(devices.types())) {
ALOGVV("%s() found output %d", __func__, openOutputs.keyAt(i));
outputs.add(openOutputs.keyAt(i));
}
@@ -5033,16 +5137,19 @@
DeviceVector oldDevices = mEngine->getOutputDevicesForAttributes(attr, 0, true /*fromCache*/);
DeviceVector newDevices = mEngine->getOutputDevicesForAttributes(attr, 0, false /*fromCache*/);
+
SortedVector<audio_io_handle_t> srcOutputs = getOutputsForDevices(oldDevices, mPreviousOutputs);
SortedVector<audio_io_handle_t> dstOutputs = getOutputsForDevices(newDevices, mOutputs);
// also take into account external policy-related changes: add all outputs which are
// associated with policies in the "before" and "after" output vectors
ALOGVV("%s(): policy related outputs", __func__);
+ bool hasDynamicPolicy = false;
for (size_t i = 0 ; i < mPreviousOutputs.size() ; i++) {
const sp<SwAudioOutputDescriptor> desc = mPreviousOutputs.valueAt(i);
if (desc != 0 && desc->mPolicyMix != NULL) {
srcOutputs.add(desc->mIoHandle);
+ hasDynamicPolicy = true;
ALOGVV(" previous outputs: adding %d", desc->mIoHandle);
}
}
@@ -5050,6 +5157,7 @@
const sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
if (desc != 0 && desc->mPolicyMix != NULL) {
dstOutputs.add(desc->mIoHandle);
+ hasDynamicPolicy = true;
ALOGVV(" new outputs: adding %d", desc->mIoHandle);
}
}
@@ -5058,12 +5166,45 @@
// get maximum latency of all source outputs to determine the minimum mute time guaranteeing
// audio from invalidated tracks will be rendered when unmuting
uint32_t maxLatency = 0;
+ bool invalidate = hasDynamicPolicy;
for (audio_io_handle_t srcOut : srcOutputs) {
sp<SwAudioOutputDescriptor> desc = mPreviousOutputs.valueFor(srcOut);
- if (desc != 0 && maxLatency < desc->latency()) {
+ if (desc == nullptr) continue;
+
+ if (desc->isStrategyActive(psId) && maxLatency < desc->latency()) {
maxLatency = desc->latency();
}
+
+ if (invalidate) continue;
+
+ for (auto client : desc->clientsList(false /*activeOnly*/)) {
+ if (desc->isDuplicated() || !desc->mProfile->isDirectOutput()) {
+ // a client on a non direct outputs has necessarily a linear PCM format
+ // so we can call selectOutput() safely
+ const audio_io_handle_t newOutput = selectOutput(dstOutputs,
+ client->flags(),
+ client->config().format,
+ client->config().channel_mask,
+ client->config().sample_rate);
+ if (newOutput != srcOut) {
+ invalidate = true;
+ break;
+ }
+ } else {
+ sp<IOProfile> profile = getProfileForOutput(newDevices,
+ client->config().sample_rate,
+ client->config().format,
+ client->config().channel_mask,
+ client->flags(),
+ true /* directOnly */);
+ if (profile != desc->mProfile) {
+ invalidate = true;
+ break;
+ }
+ }
+ }
}
+
ALOGV_IF(!(srcOutputs.isEmpty() || dstOutputs.isEmpty()),
"%s: strategy %d, moving from output %s to output %s", __func__, psId,
std::to_string(srcOutputs[0]).c_str(),
@@ -5071,7 +5212,9 @@
// mute strategy while moving tracks from one output to another
for (audio_io_handle_t srcOut : srcOutputs) {
sp<SwAudioOutputDescriptor> desc = mPreviousOutputs.valueFor(srcOut);
- if (desc != 0 && desc->isStrategyActive(psId)) {
+ if (desc == nullptr) continue;
+
+ if (desc->isStrategyActive(psId)) {
setStrategyMute(psId, true, desc);
setStrategyMute(psId, false, desc, maxLatency * LATENCY_MUTE_FACTOR,
newDevices.types());
@@ -5087,8 +5230,10 @@
selectOutputForMusicEffects();
}
// Move tracks associated to this stream (and linked) from previous output to new output
- for (auto stream : mEngine->getStreamTypesForProductStrategy(psId)) {
- mpClientInterface->invalidateStream(stream);
+ if (invalidate) {
+ for (auto stream : mEngine->getStreamTypesForProductStrategy(psId)) {
+ mpClientInterface->invalidateStream(stream);
+ }
}
}
}
@@ -5133,9 +5278,8 @@
}
bool isScoConnected =
- ((mAvailableInputDevices.types() & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET &
- ~AUDIO_DEVICE_BIT_IN) != 0) ||
- ((mAvailableOutputDevices.types() & AUDIO_DEVICE_OUT_ALL_SCO) != 0);
+ (mAvailableInputDevices.types().count(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) != 0 ||
+ !Intersection(mAvailableOutputDevices.types(), getAudioDeviceOutAllScoSet()).empty());
// if suspended, restore A2DP output if:
// ((SCO device is NOT connected) ||
@@ -5182,7 +5326,7 @@
ssize_t index = mAudioPatches.indexOfKey(outputDesc->getPatchHandle());
if (index >= 0) {
sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
- if (patchDesc->mUid != mUidCached) {
+ if (patchDesc->getUid() != mUidCached) {
ALOGV("%s device %s forced by patch %d", __func__,
outputDesc->devices().toString().c_str(), outputDesc->getPatchHandle());
return outputDesc->devices();
@@ -5210,7 +5354,8 @@
auto attr = mEngine->getAllAttributesForProductStrategy(productStrategy).front();
if ((hasVoiceStream(streams) &&
- (isInCall() || mOutputs.isStrategyActiveOnSameModule(productStrategy, outputDesc))) ||
+ (isInCall() || mOutputs.isStrategyActiveOnSameModule(productStrategy, outputDesc)) &&
+ !isStreamActive(AUDIO_STREAM_ENFORCED_AUDIBLE, 0)) ||
((hasStream(streams, AUDIO_STREAM_ALARM) || hasStream(streams, AUDIO_STREAM_ENFORCED_AUDIBLE)) &&
mOutputs.isStrategyActiveOnSameModule(productStrategy, outputDesc)) ||
outputDesc->isStrategyActive(productStrategy)) {
@@ -5232,7 +5377,7 @@
ssize_t index = mAudioPatches.indexOfKey(inputDesc->getPatchHandle());
if (index >= 0) {
sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
- if (patchDesc->mUid != mUidCached) {
+ if (patchDesc->getUid() != mUidCached) {
ALOGV("getNewInputDevice() device %s forced by patch %d",
inputDesc->getDevice()->toString().c_str(), inputDesc->getPatchHandle());
return inputDesc->getDevice();
@@ -5297,12 +5442,42 @@
}
/*Filter SPEAKER_SAFE out of results, as AudioService doesn't know about it
and doesn't really need to.*/
- DeviceVector speakerSafeDevices = devices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_SPEAKER_SAFE);
+ DeviceVector speakerSafeDevices = devices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER_SAFE);
if (!speakerSafeDevices.isEmpty()) {
- devices.merge(mAvailableOutputDevices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_SPEAKER));
+ devices.merge(mAvailableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER));
devices.remove(speakerSafeDevices);
}
- return devices.types();
+ // FIXME: use DeviceTypeSet when Java layer is ready for it.
+ return deviceTypesToBitMask(devices.types());
+}
+
+status_t AudioPolicyManager::getDevicesForAttributes(
+ const audio_attributes_t &attr, AudioDeviceTypeAddrVector *devices) {
+ if (devices == nullptr) {
+ return BAD_VALUE;
+ }
+ // check dynamic policies but only for primary descriptors (secondary not used for audible
+ // audio routing, only used for duplication for playback capture)
+ sp<SwAudioOutputDescriptor> policyDesc;
+ status_t status = mPolicyMixes.getOutputForAttr(attr, 0 /*uid unknown here*/,
+ AUDIO_OUTPUT_FLAG_NONE, policyDesc, nullptr);
+ if (status != OK) {
+ return status;
+ }
+ if (policyDesc != nullptr) {
+ sp<AudioPolicyMix> mix = policyDesc->mPolicyMix.promote();
+ if (mix != nullptr) {
+ AudioDeviceTypeAddr device(mix->mDeviceType, mix->mDeviceAddress.c_str());
+ devices->push_back(device);
+ return NO_ERROR;
+ }
+ }
+
+ DeviceVector curDevices = mEngine->getOutputDevicesForAttributes(attr, nullptr, false);
+ for (const auto& device : curDevices) {
+ devices->push_back(device->getDeviceTypeAddr());
+ }
+ return NO_ERROR;
}
void AudioPolicyManager::handleNotificationRoutingForStream(audio_stream_type_t stream) {
@@ -5362,7 +5537,7 @@
auto ttsVolumeSource = toVolumeSource(AUDIO_STREAM_TTS);
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
- setVolumeSourceMute(ttsVolumeSource, mute/*on*/, desc, 0 /*delay*/, AUDIO_DEVICE_NONE);
+ setVolumeSourceMute(ttsVolumeSource, mute/*on*/, desc, 0 /*delay*/, DeviceTypeSet());
const uint32_t latency = desc->latency() * 2;
if (latency > maxLatency) {
maxLatency = latency;
@@ -5561,10 +5736,10 @@
return INVALID_OPERATION;
}
sp< AudioPatch> patchDesc = mAudioPatches.valueAt(index);
- status_t status = mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, delayMs);
+ status_t status = mpClientInterface->releaseAudioPatch(patchDesc->getAfHandle(), delayMs);
ALOGV("resetOutputDevice() releaseAudioPatch returned %d", status);
outputDesc->setPatchHandle(AUDIO_PATCH_HANDLE_NONE);
- removeAudioPatch(patchDesc->mHandle);
+ removeAudioPatch(patchDesc->getHandle());
nextAudioPortGeneration();
mpClientInterface->onAudioPatchListUpdate();
return status;
@@ -5614,10 +5789,10 @@
return INVALID_OPERATION;
}
sp< AudioPatch> patchDesc = mAudioPatches.valueAt(index);
- status_t status = mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
+ status_t status = mpClientInterface->releaseAudioPatch(patchDesc->getAfHandle(), 0);
ALOGV("resetInputDevice() releaseAudioPatch returned %d", status);
inputDesc->setPatchHandle(AUDIO_PATCH_HANDLE_NONE);
- removeAudioPatch(patchDesc->mHandle);
+ removeAudioPatch(patchDesc->getHandle());
nextAudioPortGeneration();
mpClientInterface->onAudioPatchListUpdate();
return status;
@@ -5681,9 +5856,9 @@
float AudioPolicyManager::computeVolume(IVolumeCurves &curves,
VolumeSource volumeSource,
int index,
- audio_devices_t device)
+ const DeviceTypeSet& deviceTypes)
{
- float volumeDb = curves.volIndexToDb(Volume::getDeviceCategory(device), index);
+ float volumeDb = curves.volIndexToDb(Volume::getDeviceCategory(deviceTypes), index);
// handle the case of accessibility active while a ringtone is playing: if the ringtone is much
// louder than the accessibility prompt, the prompt cannot be heard, thus masking the touch
@@ -5699,7 +5874,7 @@
&& (AUDIO_MODE_RINGTONE == mEngine->getPhoneState()) &&
mOutputs.isActive(ringVolumeSrc, 0)) {
auto &ringCurves = getVolumeCurves(AUDIO_STREAM_RING);
- const float ringVolumeDb = computeVolume(ringCurves, ringVolumeSrc, index, device);
+ const float ringVolumeDb = computeVolume(ringCurves, ringVolumeSrc, index, deviceTypes);
return ringVolumeDb - 4 > volumeDb ? ringVolumeDb - 4 : volumeDb;
}
@@ -5714,9 +5889,9 @@
volumeSource == toVolumeSource(AUDIO_STREAM_DTMF) ||
volumeSource == a11yVolumeSrc)) {
auto &voiceCurves = getVolumeCurves(callVolumeSrc);
- int voiceVolumeIndex = voiceCurves.getVolumeIndex(device);
+ int voiceVolumeIndex = voiceCurves.getVolumeIndex(deviceTypes);
const float maxVoiceVolDb =
- computeVolume(voiceCurves, callVolumeSrc, voiceVolumeIndex, device)
+ computeVolume(voiceCurves, callVolumeSrc, voiceVolumeIndex, deviceTypes)
+ IN_CALL_EARPIECE_HEADROOM_DB;
// FIXME: Workaround for call screening applications until a proper audio mode is defined
// to support this scenario : Exempt the RING stream from the audio cap if the audio was
@@ -5742,9 +5917,10 @@
// speaker is part of the select devices
// - if music is playing, always limit the volume to current music volume,
// with a minimum threshold at -36dB so that notification is always perceived.
- if ((device & (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP | AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
- AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
- AUDIO_DEVICE_OUT_USB_HEADSET | AUDIO_DEVICE_OUT_HEARING_AID)) &&
+ if (!Intersection(deviceTypes,
+ {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,
+ AUDIO_DEVICE_OUT_WIRED_HEADSET, AUDIO_DEVICE_OUT_WIRED_HEADPHONE,
+ AUDIO_DEVICE_OUT_USB_HEADSET, AUDIO_DEVICE_OUT_HEARING_AID}).empty() &&
((volumeSource == alarmVolumeSrc ||
volumeSource == ringVolumeSrc) ||
(volumeSource == toVolumeSource(AUDIO_STREAM_NOTIFICATION)) ||
@@ -5759,31 +5935,33 @@
if (isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY) ||
mLimitRingtoneVolume) {
volumeDb += SONIFICATION_HEADSET_VOLUME_FACTOR_DB;
- audio_devices_t musicDevice =
+ DeviceTypeSet musicDevice =
mEngine->getOutputDevicesForAttributes(attributes_initializer(AUDIO_USAGE_MEDIA),
nullptr, true /*fromCache*/).types();
auto &musicCurves = getVolumeCurves(AUDIO_STREAM_MUSIC);
- float musicVolDb = computeVolume(musicCurves, musicVolumeSrc,
- musicCurves.getVolumeIndex(musicDevice), musicDevice);
+ float musicVolDb = computeVolume(musicCurves,
+ musicVolumeSrc,
+ musicCurves.getVolumeIndex(musicDevice),
+ musicDevice);
float minVolDb = (musicVolDb > SONIFICATION_HEADSET_VOLUME_MIN_DB) ?
musicVolDb : SONIFICATION_HEADSET_VOLUME_MIN_DB;
if (volumeDb > minVolDb) {
volumeDb = minVolDb;
ALOGV("computeVolume limiting volume to %f musicVol %f", minVolDb, musicVolDb);
}
- if (device & (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
- AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES)) {
+ if (!Intersection(deviceTypes, {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES}).empty()) {
// on A2DP, also ensure notification volume is not too low compared to media when
// intended to be played
if ((volumeDb > -96.0f) &&
(musicVolDb - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB > volumeDb)) {
- ALOGV("%s increasing volume for volume source=%d device=0x%X from %f to %f",
- __func__, volumeSource, device, volumeDb,
+ ALOGV("%s increasing volume for volume source=%d device=%s from %f to %f",
+ __func__, volumeSource, dumpDeviceTypes(deviceTypes).c_str(), volumeDb,
musicVolDb - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB);
volumeDb = musicVolDb - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB;
}
}
- } else if ((Volume::getDeviceForVolume(device) != AUDIO_DEVICE_OUT_SPEAKER) ||
+ } else if ((Volume::getDeviceForVolume(deviceTypes) != AUDIO_DEVICE_OUT_SPEAKER) ||
(!(volumeSource == alarmVolumeSrc || volumeSource == ringVolumeSrc))) {
volumeDb += SONIFICATION_HEADSET_VOLUME_FACTOR_DB;
}
@@ -5822,7 +6000,7 @@
VolumeSource volumeSource,
int index,
const sp<AudioOutputDescriptor>& outputDesc,
- audio_devices_t device,
+ DeviceTypeSet deviceTypes,
int delayMs,
bool force)
{
@@ -5848,17 +6026,20 @@
volumeSource, forceUseForComm);
return INVALID_OPERATION;
}
- if (device == AUDIO_DEVICE_NONE) {
- device = outputDesc->devices().types();
+ if (deviceTypes.empty()) {
+ deviceTypes = outputDesc->devices().types();
}
- float volumeDb = computeVolume(curves, volumeSource, index, device);
- if (outputDesc->isFixedVolume(device) ||
+ float volumeDb = computeVolume(curves, volumeSource, index, deviceTypes);
+ if (outputDesc->isFixedVolume(deviceTypes) ||
// Force VoIP volume to max for bluetooth SCO
- ((isVoiceVolSrc || isBtScoVolSrc) && (device & AUDIO_DEVICE_OUT_ALL_SCO) != 0)) {
+
+ ((isVoiceVolSrc || isBtScoVolSrc) &&
+ isSingleDeviceType(deviceTypes, audio_is_bluetooth_out_sco_device))) {
volumeDb = 0.0f;
}
- outputDesc->setVolume(volumeDb, volumeSource, curves.getStreamTypes(), device, delayMs, force);
+ outputDesc->setVolume(
+ volumeDb, volumeSource, curves.getStreamTypes(), deviceTypes, delayMs, force);
if (isVoiceVolSrc || isBtScoVolSrc) {
float voiceVolume;
@@ -5877,15 +6058,16 @@
}
void AudioPolicyManager::applyStreamVolumes(const sp<AudioOutputDescriptor>& outputDesc,
- audio_devices_t device,
- int delayMs,
- bool force)
+ const DeviceTypeSet& deviceTypes,
+ int delayMs,
+ bool force)
{
- ALOGVV("applyStreamVolumes() for device %08x", device);
+ ALOGVV("applyStreamVolumes() for device %s", dumpDeviceTypes(deviceTypes).c_str());
for (const auto &volumeGroup : mEngine->getVolumeGroups()) {
auto &curves = getVolumeCurves(toVolumeSource(volumeGroup));
checkAndSetVolume(curves, toVolumeSource(volumeGroup),
- curves.getVolumeIndex(device), outputDesc, device, delayMs, force);
+ curves.getVolumeIndex(deviceTypes),
+ outputDesc, deviceTypes, delayMs, force);
}
}
@@ -5893,7 +6075,7 @@
bool on,
const sp<AudioOutputDescriptor>& outputDesc,
int delayMs,
- audio_devices_t device)
+ DeviceTypeSet deviceTypes)
{
std::vector<VolumeSource> sourcesToMute;
for (auto attributes: mEngine->getAllAttributesForProductStrategy(strategy)) {
@@ -5905,7 +6087,7 @@
}
}
for (auto source : sourcesToMute) {
- setVolumeSourceMute(source, on, outputDesc, delayMs, device);
+ setVolumeSourceMute(source, on, outputDesc, delayMs, deviceTypes);
}
}
@@ -5914,10 +6096,10 @@
bool on,
const sp<AudioOutputDescriptor>& outputDesc,
int delayMs,
- audio_devices_t device)
+ DeviceTypeSet deviceTypes)
{
- if (device == AUDIO_DEVICE_NONE) {
- device = outputDesc->devices().types();
+ if (deviceTypes.empty()) {
+ deviceTypes = outputDesc->devices().types();
}
auto &curves = getVolumeCurves(volumeSource);
if (on) {
@@ -5926,7 +6108,7 @@
(volumeSource != toVolumeSource(AUDIO_STREAM_ENFORCED_AUDIBLE) ||
(mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) ==
AUDIO_POLICY_FORCE_NONE))) {
- checkAndSetVolume(curves, volumeSource, 0, outputDesc, device, delayMs);
+ checkAndSetVolume(curves, volumeSource, 0, outputDesc, deviceTypes, delayMs);
}
}
// increment mMuteCount after calling checkAndSetVolume() so that volume change is not
@@ -5939,9 +6121,9 @@
}
if (outputDesc->decMuteCount(volumeSource) == 0) {
checkAndSetVolume(curves, volumeSource,
- curves.getVolumeIndex(device),
+ curves.getVolumeIndex(deviceTypes),
outputDesc,
- device,
+ deviceTypes,
delayMs);
}
}
@@ -5973,6 +6155,11 @@
case AUDIO_USAGE_GAME:
case AUDIO_USAGE_VIRTUAL_SOURCE:
case AUDIO_USAGE_ASSISTANT:
+ case AUDIO_USAGE_CALL_ASSISTANT:
+ case AUDIO_USAGE_EMERGENCY:
+ case AUDIO_USAGE_SAFETY:
+ case AUDIO_USAGE_VEHICLE_STATUS:
+ case AUDIO_USAGE_ANNOUNCEMENT:
break;
default:
return false;
@@ -5995,6 +6182,14 @@
return is_state_in_call(state);
}
+bool AudioPolicyManager::isCallAudioAccessible()
+{
+ audio_mode_t mode = mEngine->getPhoneState();
+ return (mode == AUDIO_MODE_IN_CALL)
+ || (mode == AUDIO_MODE_IN_COMMUNICATION)
+ || (mode == AUDIO_MODE_CALL_SCREEN);
+}
+
void AudioPolicyManager::cleanUpForDevice(const sp<DeviceDescriptor>& deviceDesc)
{
for (ssize_t i = (ssize_t)mAudioSources.size() - 1; i >= 0; i--) {
@@ -6023,8 +6218,8 @@
}
}
if (release) {
- ALOGV("%s releasing patch %u", __FUNCTION__, patchDesc->mHandle);
- releaseAudioPatch(patchDesc->mHandle, patchDesc->mUid);
+ ALOGV("%s releasing patch %u", __FUNCTION__, patchDesc->getHandle());
+ releaseAudioPatch(patchDesc->getHandle(), patchDesc->getUid());
}
}
@@ -6083,24 +6278,24 @@
formatSet.insert(enforcedSurround.begin(), enforcedSurround.end());
}
for (const auto& format : formatSet) {
- formatsPtr->push(format);
+ formatsPtr->push_back(format);
}
}
-void AudioPolicyManager::modifySurroundChannelMasks(ChannelsVector *channelMasksPtr) {
- ChannelsVector &channelMasks = *channelMasksPtr;
+void AudioPolicyManager::modifySurroundChannelMasks(ChannelMaskSet *channelMasksPtr) {
+ ChannelMaskSet &channelMasks = *channelMasksPtr;
audio_policy_forced_cfg_t forceUse = mEngine->getForceUse(
AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND);
// If NEVER, then remove support for channelMasks > stereo.
if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER) {
- for (size_t maskIndex = 0; maskIndex < channelMasks.size(); ) {
- audio_channel_mask_t channelMask = channelMasks[maskIndex];
+ for (auto it = channelMasks.begin(); it != channelMasks.end();) {
+ audio_channel_mask_t channelMask = *it;
if (channelMask & ~AUDIO_CHANNEL_OUT_STEREO) {
ALOGI("%s: force NEVER, so remove channelMask 0x%08x", __FUNCTION__, channelMask);
- channelMasks.removeAt(maskIndex);
+ it = channelMasks.erase(it);
} else {
- maskIndex++;
+ ++it;
}
}
// If ALWAYS or MANUAL, then make sure we at least support 5.1
@@ -6116,7 +6311,7 @@
}
// If not then add 5.1 support.
if (!supports5dot1) {
- channelMasks.add(AUDIO_CHANNEL_OUT_5POINT1);
+ channelMasks.insert(AUDIO_CHANNEL_OUT_5POINT1);
ALOGI("%s: force MANUAL or ALWAYS, so adding channelMask for 5.1 surround", __func__);
}
}
@@ -6145,12 +6340,12 @@
|| isDeviceOfModule(devDesc, AUDIO_HARDWARE_MODULE_ID_MSD)) {
modifySurroundFormats(devDesc, &formats);
}
- profiles.setFormats(formats);
+ addProfilesForFormats(profiles, formats);
}
for (audio_format_t format : profiles.getSupportedFormats()) {
- ChannelsVector channelMasks;
- SampleRateVector samplingRates;
+ ChannelMaskSet channelMasks;
+ SampleRateSet samplingRates;
AudioParameter requestedParameters;
requestedParameters.addInt(String8(AudioParameter::keyFormat), format);
@@ -6181,7 +6376,8 @@
}
}
}
- profiles.addProfileFromHal(new AudioProfile(format, channelMasks, samplingRates));
+ addDynamicAudioProfileAndSort(
+ profiles, new AudioProfile(format, channelMasks, samplingRates));
}
}
@@ -6198,7 +6394,7 @@
status_t status = installPatch(
caller, index, patchHandle, patch, delayMs, mUidCached, &patchDesc);
if (status == NO_ERROR) {
- ioDescriptor->setPatchHandle(patchDesc->mHandle);
+ ioDescriptor->setPatchHandle(patchDesc->getHandle());
}
return status;
}
@@ -6215,7 +6411,7 @@
audio_patch_handle_t afPatchHandle = AUDIO_PATCH_HANDLE_NONE;
if (index >= 0) {
patchDesc = mAudioPatches.valueAt(index);
- afPatchHandle = patchDesc->mAfPatchHandle;
+ afPatchHandle = patchDesc->getAfHandle();
}
status_t status = mpClientInterface->createAudioPatch(patch, &afPatchHandle, delayMs);
@@ -6224,13 +6420,13 @@
if (status == NO_ERROR) {
if (index < 0) {
patchDesc = new AudioPatch(patch, uid);
- addAudioPatch(patchDesc->mHandle, patchDesc);
+ addAudioPatch(patchDesc->getHandle(), patchDesc);
} else {
patchDesc->mPatch = *patch;
}
- patchDesc->mAfPatchHandle = afPatchHandle;
+ patchDesc->setAfHandle(afPatchHandle);
if (patchHandle) {
- *patchHandle = patchDesc->mHandle;
+ *patchHandle = patchDesc->getHandle();
}
nextAudioPortGeneration();
mpClientInterface->onAudioPatchListUpdate();
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index dc548d6..8121f86 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -31,16 +31,14 @@
#include <utils/SortedVector.h>
#include <media/AudioParameter.h>
#include <media/AudioPolicy.h>
+#include <media/AudioProfile.h>
#include <media/PatchBuilder.h>
#include "AudioPolicyInterface.h"
-#include <AudioPolicyManagerInterface.h>
#include <AudioPolicyManagerObserver.h>
-#include <AudioGain.h>
#include <AudioPolicyConfig.h>
-#include <AudioPort.h>
+#include <PolicyAudioPort.h>
#include <AudioPatch.h>
-#include <AudioProfile.h>
#include <DeviceDescriptor.h>
#include <IOProfile.h>
#include <HwModule.h>
@@ -49,6 +47,7 @@
#include <AudioPolicyMix.h>
#include <EffectDescriptor.h>
#include <SoundTriggerSession.h>
+#include "EngineLibrary.h"
#include "TypeConverter.h"
namespace android {
@@ -122,7 +121,8 @@
audio_output_flags_t *flags,
audio_port_handle_t *selectedDeviceId,
audio_port_handle_t *portId,
- std::vector<audio_io_handle_t> *secondaryOutputs) override;
+ std::vector<audio_io_handle_t> *secondaryOutputs,
+ output_type_t *outputType) override;
virtual status_t startOutput(audio_port_handle_t portId);
virtual status_t stopOutput(audio_port_handle_t portId);
virtual void releaseOutput(audio_port_handle_t portId);
@@ -177,7 +177,7 @@
IVolumeCurves &volumeCurves);
status_t getVolumeIndex(const IVolumeCurves &curves, int &index,
- audio_devices_t device) const;
+ const DeviceTypeSet& deviceTypes) const;
// return the strategy corresponding to a given stream type
virtual uint32_t getStrategyForStream(audio_stream_type_t stream)
@@ -193,6 +193,10 @@
// return the enabled output devices for the given stream type
virtual audio_devices_t getDevicesForStream(audio_stream_type_t stream);
+ virtual status_t getDevicesForAttributes(
+ const audio_attributes_t &attributes,
+ AudioDeviceTypeAddrVector *devices);
+
virtual audio_io_handle_t getOutputForEffect(const effect_descriptor_t *desc = NULL);
virtual status_t registerEffect(const effect_descriptor_t *desc,
audio_io_handle_t io,
@@ -234,7 +238,10 @@
virtual status_t getAudioPort(struct audio_port *port);
virtual status_t createAudioPatch(const struct audio_patch *patch,
audio_patch_handle_t *handle,
- uid_t uid);
+ uid_t uid) {
+ return createAudioPatchInternal(patch, handle, uid);
+ }
+
virtual status_t releaseAudioPatch(audio_patch_handle_t handle,
uid_t uid);
virtual status_t listAudioPatches(unsigned int *num_patches,
@@ -258,6 +265,15 @@
virtual status_t setUidDeviceAffinities(uid_t uid,
const Vector<AudioDeviceTypeAddr>& devices);
virtual status_t removeUidDeviceAffinities(uid_t uid);
+ virtual status_t setUserIdDeviceAffinities(int userId,
+ const Vector<AudioDeviceTypeAddr>& devices);
+ virtual status_t removeUserIdDeviceAffinities(int userId);
+
+ virtual status_t setPreferredDeviceForStrategy(product_strategy_t strategy,
+ const AudioDeviceTypeAddr &device);
+ virtual status_t removePreferredDeviceForStrategy(product_strategy_t strategy);
+ virtual status_t getPreferredDeviceForStrategy(product_strategy_t strategy,
+ AudioDeviceTypeAddr &device);
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
@@ -279,7 +295,7 @@
virtual status_t getHwOffloadEncodingFormatsSupportedForA2DP(
std::vector<audio_format_t> *formats);
- virtual void setAppState(uid_t uid, app_state_t state);
+ virtual void setAppState(audio_port_handle_t portId, app_state_t state);
virtual bool isHapticPlaybackSupported();
@@ -307,6 +323,12 @@
return volumeGroup != VOLUME_GROUP_NONE ? NO_ERROR : BAD_VALUE;
}
+ bool isCallScreenModeSupported() override;
+
+ void onNewAudioModulesAvailable() override;
+
+ status_t initialize();
+
protected:
// A constructor that allows more fine-grained control over initialization process,
// used in automatic tests.
@@ -321,7 +343,6 @@
// - initialize.
AudioPolicyConfig& getConfig() { return mConfig; }
void loadConfig();
- status_t initialize();
// From AudioPolicyManagerObserver
virtual const AudioPatchCollection &getAudioPatches() const
@@ -422,7 +443,7 @@
virtual float computeVolume(IVolumeCurves &curves,
VolumeSource volumeSource,
int index,
- audio_devices_t device);
+ const DeviceTypeSet& deviceTypes);
// rescale volume index from srcStream within range of dstStream
int rescaleVolumeIndex(int srcIndex,
@@ -432,12 +453,13 @@
virtual status_t checkAndSetVolume(IVolumeCurves &curves,
VolumeSource volumeSource, int index,
const sp<AudioOutputDescriptor>& outputDesc,
- audio_devices_t device,
+ DeviceTypeSet deviceTypes,
int delayMs = 0, bool force = false);
// apply all stream volumes to the specified output and device
void applyStreamVolumes(const sp<AudioOutputDescriptor>& outputDesc,
- audio_devices_t device, int delayMs = 0, bool force = false);
+ const DeviceTypeSet& deviceTypes,
+ int delayMs = 0, bool force = false);
/**
* @brief setStrategyMute Mute or unmute all active clients on the considered output
@@ -452,7 +474,7 @@
bool on,
const sp<AudioOutputDescriptor>& outputDesc,
int delayMs = 0,
- audio_devices_t device = AUDIO_DEVICE_NONE);
+ DeviceTypeSet deviceTypes = DeviceTypeSet());
/**
* @brief setVolumeSourceMute Mute or unmute the volume source on the specified output
@@ -467,7 +489,7 @@
bool on,
const sp<AudioOutputDescriptor>& outputDesc,
int delayMs = 0,
- audio_devices_t device = AUDIO_DEVICE_NONE);
+ DeviceTypeSet deviceTypes = DeviceTypeSet());
audio_mode_t getPhoneState();
@@ -475,6 +497,8 @@
virtual bool isInCall();
// true if given state represents a device in a telephony or VoIP call
virtual bool isStateInCall(int state);
+ // true if playback to call TX or capture from call RX is possible
+ bool isCallAudioAccessible();
// when a device is connected, checks if an open output can be routed
// to this device. If none is open, tries to open one of the available outputs.
@@ -495,13 +519,19 @@
// close an input.
void closeInput(audio_io_handle_t input);
- // runs all the checks required for accomodating changes in devices and outputs
+ // runs all the checks required for accommodating changes in devices and outputs
// if 'onOutputsChecked' callback is provided, it is executed after the outputs
// check via 'checkOutputForAllStrategies'. If the callback returns 'true',
// A2DP suspend status is rechecked.
void checkForDeviceAndOutputChanges(std::function<bool()> onOutputsChecked = nullptr);
/**
+ * @brief updates routing for all outputs (including call if call in progress).
+ * @param delayMs delay for unmuting if required
+ */
+ void updateCallAndOutputRouting(bool forceVolumeReeval = true, uint32_t delayMs = 0);
+
+ /**
* @brief checkOutputForAttributes checks and if necessary changes outputs used for the
* given audio attributes.
* must be called every time a condition that affects the output choice for a given
@@ -646,16 +676,13 @@
}
String8 getFirstDeviceAddress(const DeviceVector &devices) const
{
- return (devices.size() > 0) ? devices.itemAt(0)->address() : String8("");
+ return (devices.size() > 0) ?
+ String8(devices.itemAt(0)->address().c_str()) : String8("");
}
uint32_t updateCallRouting(const DeviceVector &rxDevices, uint32_t delayMs = 0);
sp<AudioPatch> createTelephonyPatch(bool isRx, const sp<DeviceDescriptor> &device,
uint32_t delayMs);
- sp<DeviceDescriptor> findDevice(
- const DeviceVector& devices, audio_devices_t device) const;
- audio_devices_t getModuleDeviceTypes(
- const DeviceVector& devices, const char *moduleId) const;
bool isDeviceOfModule(const sp<DeviceDescriptor>& devDesc, const char *moduleId) const;
status_t startSource(const sp<SwAudioOutputDescriptor>& outputDesc,
@@ -704,6 +731,8 @@
SwAudioOutputCollection mPreviousOutputs;
AudioInputCollection mInputs; // list of input descriptors
+ DeviceVector mOutputDevicesAll; // all output devices from the config
+ DeviceVector mInputDevicesAll; // all input devices from the config
DeviceVector mAvailableOutputDevices; // all available output devices
DeviceVector mAvailableInputDevices; // all available input devices
@@ -714,9 +743,8 @@
EffectDescriptorCollection mEffects; // list of registered audio effects
sp<DeviceDescriptor> mDefaultOutputDevice; // output device selected by default at boot time
- HwModuleCollection mHwModules; // contains only modules that have been loaded successfully
- HwModuleCollection mHwModulesAll; // normally not needed, used during construction and for
- // dumps
+ HwModuleCollection mHwModules; // contains modules that have been loaded successfully
+ HwModuleCollection mHwModulesAll; // contains all modules declared in the config
AudioPolicyConfig mConfig;
@@ -752,7 +780,7 @@
uint32_t nextAudioPortGeneration();
// Audio Policy Engine Interface.
- AudioPolicyManagerInterface *mEngine;
+ EngineInstance mEngine;
// Surround formats that are enabled manually. Taken into account when
// "encoded surround" is forced into "manual" mode.
@@ -762,7 +790,7 @@
private:
// Add or remove AC3 DTS encodings based on user preferences.
void modifySurroundFormats(const sp<DeviceDescriptor>& devDesc, FormatVector *formatsPtr);
- void modifySurroundChannelMasks(ChannelsVector *channelMasksPtr);
+ void modifySurroundChannelMasks(ChannelMaskSet *channelMasksPtr);
// Support for Multi-Stream Decoder (MSD) module
sp<DeviceDescriptor> getMsdAudioInDevice() const;
@@ -807,7 +835,8 @@
audio_output_flags_t *flags,
audio_port_handle_t *selectedDeviceId,
bool *isRequestedDeviceForExclusiveUse,
- std::vector<sp<SwAudioOutputDescriptor>> *secondaryDescs);
+ std::vector<sp<SwAudioOutputDescriptor>> *secondaryDescs,
+ output_type_t *outputType);
// internal method to return the output handle for the given device and format
audio_io_handle_t getOutputForDevices(
const DeviceVector &devices,
@@ -858,6 +887,29 @@
param.addInt(String8(AudioParameter::keyMonoOutput), (int)mMasterMono);
mpClientInterface->setParameters(output, param.toString());
}
+
+ /**
+ * @brief createAudioPatchInternal internal function to manage audio patch creation
+ * @param[in] patch structure containing sink and source ports configuration
+ * @param[out] handle patch handle to be provided if patch installed correctly
+ * @param[in] uid of the client
+ * @param[in] delayMs if required
+ * @param[in] sourceDesc [optional] in case of external source, source client to be
+ * configured by the patch, i.e. assigning an Output (HW or SW)
+ * @return NO_ERROR if patch installed correctly, error code otherwise.
+ */
+ status_t createAudioPatchInternal(const struct audio_patch *patch,
+ audio_patch_handle_t *handle,
+ uid_t uid, uint32_t delayMs = 0,
+ const sp<SourceClientDescriptor>& sourceDesc = nullptr);
+ /**
+ * @brief releaseAudioPatchInternal internal function to remove an audio patch
+ * @param[in] handle of the patch to be removed
+ * @param[in] delayMs if required
+ * @return NO_ERROR if patch removed correctly, error code otherwise.
+ */
+ status_t releaseAudioPatchInternal(audio_patch_handle_t handle, uint32_t delayMs = 0);
+
status_t installPatch(const char *caller,
audio_patch_handle_t *patchHandle,
AudioIODescriptorInterface *ioDescriptor,
@@ -870,8 +922,6 @@
int delayMs,
uid_t uid,
sp<AudioPatch> *patchDescPtr);
-
- void cleanUpEffectsForIo(audio_io_handle_t io);
};
};
diff --git a/services/audiopolicy/managerdefault/EngineLibrary.cpp b/services/audiopolicy/managerdefault/EngineLibrary.cpp
new file mode 100644
index 0000000..ef699aa
--- /dev/null
+++ b/services/audiopolicy/managerdefault/EngineLibrary.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright 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.
+ */
+
+#define LOG_TAG "APM_EngineLoader"
+
+#include <dlfcn.h>
+#include <utils/Log.h>
+
+#include "EngineLibrary.h"
+
+namespace android {
+
+// static
+std::shared_ptr<EngineLibrary> EngineLibrary::load(std::string libraryPath)
+{
+ std::shared_ptr<EngineLibrary> engLib(new EngineLibrary());
+ return engLib->init(std::move(libraryPath)) ? engLib : nullptr;
+}
+
+EngineLibrary::~EngineLibrary()
+{
+ close();
+}
+
+bool EngineLibrary::init(std::string libraryPath)
+{
+ mLibraryHandle = dlopen(libraryPath.c_str(), 0);
+ if (mLibraryHandle == nullptr) {
+ ALOGE("Could not dlopen %s: %s", libraryPath.c_str(), dlerror());
+ return false;
+ }
+ mCreateEngineInstance = (EngineInterface* (*)())dlsym(mLibraryHandle, "createEngineInstance");
+ mDestroyEngineInstance = (void (*)(EngineInterface*))dlsym(
+ mLibraryHandle, "destroyEngineInstance");
+ if (mCreateEngineInstance == nullptr || mDestroyEngineInstance == nullptr) {
+ ALOGE("Could not find engine interface functions in %s", libraryPath.c_str());
+ close();
+ return false;
+ }
+ ALOGD("Loaded engine from %s", libraryPath.c_str());
+ return true;
+}
+
+EngineInstance EngineLibrary::createEngine()
+{
+ if (mCreateEngineInstance == nullptr || mDestroyEngineInstance == nullptr) {
+ return EngineInstance();
+ }
+ return EngineInstance(mCreateEngineInstance(),
+ [lib = shared_from_this(), destroy = mDestroyEngineInstance] (EngineInterface* e) {
+ destroy(e);
+ });
+}
+
+void EngineLibrary::close()
+{
+ if (mLibraryHandle != nullptr) {
+ dlclose(mLibraryHandle);
+ }
+ mLibraryHandle = nullptr;
+ mCreateEngineInstance = nullptr;
+ mDestroyEngineInstance = nullptr;
+}
+
+} // namespace android
diff --git a/services/audiopolicy/managerdefault/EngineLibrary.h b/services/audiopolicy/managerdefault/EngineLibrary.h
new file mode 100644
index 0000000..f143916
--- /dev/null
+++ b/services/audiopolicy/managerdefault/EngineLibrary.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#include <functional>
+#include <memory>
+#include <string>
+
+#include <EngineInterface.h>
+
+namespace android {
+
+using EngineInstance = std::unique_ptr<EngineInterface, std::function<void (EngineInterface*)>>;
+
+class EngineLibrary : public std::enable_shared_from_this<EngineLibrary> {
+public:
+ static std::shared_ptr<EngineLibrary> load(std::string libraryPath);
+ ~EngineLibrary();
+
+ EngineLibrary(const EngineLibrary&) = delete;
+ EngineLibrary(EngineLibrary&&) = delete;
+ EngineLibrary& operator=(const EngineLibrary&) = delete;
+ EngineLibrary& operator=(EngineLibrary&&) = delete;
+
+ EngineInstance createEngine();
+
+private:
+ EngineLibrary() = default;
+ bool init(std::string libraryPath);
+ void close();
+
+ void *mLibraryHandle = nullptr;
+ EngineInterface* (*mCreateEngineInstance)() = nullptr;
+ void (*mDestroyEngineInstance)(EngineInterface*) = nullptr;
+};
+
+} // namespace android
diff --git a/services/audiopolicy/service/Android.mk b/services/audiopolicy/service/Android.mk
index c4f4c56..80f4eab 100644
--- a/services/audiopolicy/service/Android.mk
+++ b/services/audiopolicy/service/Android.mk
@@ -24,13 +24,15 @@
libbinder \
libaudioclient \
libaudioutils \
+ libaudiofoundation \
libhardware_legacy \
libaudiopolicymanager \
libmedia_helper \
libmediametrics \
libmediautils \
libeffectsconfig \
- libsensorprivacy
+ libsensorprivacy \
+ soundtrigger_middleware-aidl-cpp
LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := \
libsensorprivacy
@@ -38,8 +40,6 @@
LOCAL_STATIC_LIBRARIES := \
libaudiopolicycomponents
-LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-
LOCAL_MODULE:= libaudiopolicyservice
LOCAL_CFLAGS += -fvisibility=hidden
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index d51cc6e..5b81b9d 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -17,10 +17,13 @@
#define LOG_TAG "AudioPolicyClientImpl"
//#define LOG_NDEBUG 0
-#include <soundtrigger/SoundTrigger.h>
-#include <utils/Log.h>
#include "AudioPolicyService.h"
+#include <android/media/soundtrigger_middleware/ISoundTriggerMiddlewareService.h>
+#include <utils/Log.h>
+
+#include "BinderProxy.h"
+
namespace android {
/* implementation of the client interface from the policy manager */
@@ -39,8 +42,7 @@
status_t AudioPolicyService::AudioPolicyClient::openOutput(audio_module_handle_t module,
audio_io_handle_t *output,
audio_config_t *config,
- audio_devices_t *devices,
- const String8& address,
+ const sp<DeviceDescriptorBase>& device,
uint32_t *latencyMs,
audio_output_flags_t flags)
{
@@ -49,7 +51,7 @@
ALOGW("%s: could not get AudioFlinger", __func__);
return PERMISSION_DENIED;
}
- return af->openOutput(module, output, config, devices, address, latencyMs, flags);
+ return af->openOutput(module, output, config, device, latencyMs, flags);
}
audio_io_handle_t AudioPolicyService::AudioPolicyClient::openDuplicateOutput(
@@ -240,4 +242,12 @@
return AudioSystem::newAudioUniqueId(use);
}
+void AudioPolicyService::AudioPolicyClient::setSoundTriggerCaptureState(bool active) {
+ using media::soundtrigger_middleware::ISoundTriggerMiddlewareService;
+
+ static BinderProxy<ISoundTriggerMiddlewareService>
+ proxy("soundtrigger_middleware");
+ proxy.waitServiceOrDie()->setExternalCaptureState(active);
+}
+
} // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp
index 4947714..738a279 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.cpp
+++ b/services/audiopolicy/service/AudioPolicyEffects.cpp
@@ -42,7 +42,10 @@
AudioPolicyEffects::AudioPolicyEffects()
{
status_t loadResult = loadAudioEffectXmlConfig();
- if (loadResult < 0) {
+ if (loadResult == NO_ERROR) {
+ mDefaultDeviceEffectFuture = std::async(
+ std::launch::async, &AudioPolicyEffects::initDefaultDeviceEffects, this);
+ } else if (loadResult < 0) {
ALOGW("Failed to load XML effect configuration, fallback to .conf");
// load automatic audio effect modules
if (access(AUDIO_EFFECT_VENDOR_CONFIG_FILE, R_OK) == 0) {
@@ -562,7 +565,8 @@
AUDIO_STREAM_BLUETOOTH_SCO_TAG,
AUDIO_STREAM_ENFORCED_AUDIBLE_TAG,
AUDIO_STREAM_DTMF_TAG,
- AUDIO_STREAM_TTS_TAG
+ AUDIO_STREAM_TTS_TAG,
+ AUDIO_STREAM_ASSISTANT_TAG
};
// returns the audio_stream_t enum corresponding to the output stream name or
@@ -907,8 +911,24 @@
streams.add(stream.type, effectDescs.release());
}
};
+
+ auto loadDeviceProcessingChain = [](auto &processingChain, auto& devicesEffects) {
+ for (auto& deviceProcess : processingChain) {
+
+ auto effectDescs = std::make_unique<EffectDescVector>();
+ for (auto& effect : deviceProcess.effects) {
+ effectDescs->mEffects.add(
+ new EffectDesc{effect.get().name.c_str(), effect.get().uuid});
+ }
+ auto deviceEffects = std::make_unique<DeviceEffects>(
+ std::move(effectDescs), deviceProcess.type, deviceProcess.address);
+ devicesEffects.emplace(deviceProcess.address, std::move(deviceEffects));
+ }
+ };
+
loadProcessingChain(result.parsedConfig->preprocess, mInputSources);
loadProcessingChain(result.parsedConfig->postprocess, mOutputStreams);
+ loadDeviceProcessingChain(result.parsedConfig->deviceprocess, mDeviceEffects);
// Casting from ssize_t to status_t is probably safe, there should not be more than 2^31 errors
return result.nbSkippedElement;
}
@@ -941,5 +961,32 @@
return NO_ERROR;
}
+void AudioPolicyEffects::initDefaultDeviceEffects()
+{
+ Mutex::Autolock _l(mLock);
+ for (const auto& deviceEffectsIter : mDeviceEffects) {
+ const auto& deviceEffects = deviceEffectsIter.second;
+ for (const auto& effectDesc : deviceEffects->mEffectDescriptors->mEffects) {
+ auto fx = std::make_unique<AudioEffect>(
+ EFFECT_UUID_NULL, String16("android"), &effectDesc->mUuid, 0, nullptr,
+ nullptr, AUDIO_SESSION_DEVICE, AUDIO_IO_HANDLE_NONE,
+ AudioDeviceTypeAddr{deviceEffects->getDeviceType(),
+ deviceEffects->getDeviceAddress()});
+ status_t status = fx->initCheck();
+ if (status != NO_ERROR && status != ALREADY_EXISTS) {
+ ALOGE("%s(): failed to create Fx %s on port type=%d address=%s", __func__,
+ effectDesc->mName, deviceEffects->getDeviceType(),
+ deviceEffects->getDeviceAddress().c_str());
+ // fx goes out of scope and strong ref on AudioEffect is released
+ continue;
+ }
+ fx->setEnabled(true);
+ ALOGV("%s(): create Fx %s added on port type=%d address=%s", __func__,
+ effectDesc->mName, deviceEffects->getDeviceType(),
+ deviceEffects->getDeviceAddress().c_str());
+ deviceEffects->mEffects.push_back(std::move(fx));
+ }
+ }
+}
} // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyEffects.h b/services/audiopolicy/service/AudioPolicyEffects.h
index dcf093b..81c728d 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.h
+++ b/services/audiopolicy/service/AudioPolicyEffects.h
@@ -25,6 +25,9 @@
#include <system/audio.h>
#include <utils/Vector.h>
#include <utils/SortedVector.h>
+#include <android-base/thread_annotations.h>
+
+#include <future>
namespace android {
@@ -104,6 +107,7 @@
status_t removeStreamDefaultEffect(audio_unique_id_t id);
private:
+ void initDefaultDeviceEffects();
// class to store the description of an effects and its parameters
// as defined in audio_effects.conf
@@ -192,6 +196,28 @@
Vector< sp<AudioEffect> >mEffects;
};
+ /**
+ * @brief The DeviceEffects class stores the effects associated to a given Device Port.
+ */
+ class DeviceEffects {
+ public:
+ DeviceEffects(std::unique_ptr<EffectDescVector> effectDescriptors,
+ audio_devices_t device, const std::string& address) :
+ mEffectDescriptors(std::move(effectDescriptors)),
+ mDeviceType(device), mDeviceAddress(address) {}
+ /*virtual*/ ~DeviceEffects() = default;
+
+ std::vector<std::unique_ptr<AudioEffect>> mEffects;
+ audio_devices_t getDeviceType() const { return mDeviceType; }
+ std::string getDeviceAddress() const { return mDeviceAddress; }
+ const std::unique_ptr<EffectDescVector> mEffectDescriptors;
+
+ private:
+ const audio_devices_t mDeviceType;
+ const std::string mDeviceAddress;
+
+ };
+
static const char * const kInputSourceNames[AUDIO_SOURCE_CNT -1];
static audio_source_t inputSourceNameToEnum(const char *name);
@@ -237,6 +263,19 @@
KeyedVector< audio_stream_type_t, EffectDescVector* > mOutputStreams;
// Automatic output effects are unique for audiosession ID
KeyedVector< audio_session_t, EffectVector* > mOutputSessions;
+
+ /**
+ * @brief mDeviceEffects map of device effects indexed by the device address
+ */
+ std::map<std::string, std::unique_ptr<DeviceEffects>> mDeviceEffects GUARDED_BY(mLock);
+
+ /**
+ * Device Effect initialization must be asynchronous: the audio_policy service parses and init
+ * effect on first reference. AudioFlinger will handle effect creation and register these
+ * effect on audio_policy service.
+ * We must store the reference of the furture garantee real asynchronous operation.
+ */
+ std::future<void> mDefaultDeviceEffectFuture;
};
} // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 20e1c9e..0da3b9c 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -19,15 +19,61 @@
#include "AudioPolicyService.h"
#include "TypeConverter.h"
-#include <media/MediaAnalyticsItem.h>
+#include <media/MediaMetricsItem.h>
#include <media/AudioPolicy.h>
#include <utils/Log.h>
namespace android {
+const std::vector<audio_usage_t>& SYSTEM_USAGES = {
+ AUDIO_USAGE_CALL_ASSISTANT,
+ AUDIO_USAGE_EMERGENCY,
+ AUDIO_USAGE_SAFETY,
+ AUDIO_USAGE_VEHICLE_STATUS,
+ AUDIO_USAGE_ANNOUNCEMENT
+};
+
+bool isSystemUsage(audio_usage_t usage) {
+ return std::find(std::begin(SYSTEM_USAGES), std::end(SYSTEM_USAGES), usage)
+ != std::end(SYSTEM_USAGES);
+}
+
+bool AudioPolicyService::isSupportedSystemUsage(audio_usage_t usage) {
+ return std::find(std::begin(mSupportedSystemUsages), std::end(mSupportedSystemUsages), usage)
+ != std::end(mSupportedSystemUsages);
+}
+
+status_t AudioPolicyService::validateUsage(audio_usage_t usage) {
+ return validateUsage(usage, IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid());
+}
+
+status_t AudioPolicyService::validateUsage(audio_usage_t usage, pid_t pid, uid_t uid) {
+ if (isSystemUsage(usage)) {
+ if (isSupportedSystemUsage(usage)) {
+ if (!modifyAudioRoutingAllowed(pid, uid)) {
+ ALOGE("permission denied: modify audio routing not allowed for uid %d", uid);
+ return PERMISSION_DENIED;
+ }
+ } else {
+ return BAD_VALUE;
+ }
+ }
+ return NO_ERROR;
+}
+
+
// ----------------------------------------------------------------------------
+void AudioPolicyService::doOnNewAudioModulesAvailable()
+{
+ if (mAudioPolicyManager == NULL) return;
+ Mutex::Autolock _l(mLock);
+ AutoCallerClear acc;
+ mAudioPolicyManager->onNewAudioModulesAvailable();
+}
+
status_t AudioPolicyService::setDeviceConnectionState(audio_devices_t device,
audio_policy_dev_state_t state,
const char *device_address,
@@ -83,7 +129,7 @@
device_name, encodedFormat);
}
-status_t AudioPolicyService::setPhoneState(audio_mode_t state)
+status_t AudioPolicyService::setPhoneState(audio_mode_t state, uid_t uid)
{
if (mAudioPolicyManager == NULL) {
return NO_INIT;
@@ -107,6 +153,7 @@
AutoCallerClear acc;
mAudioPolicyManager->setPhoneState(state);
mPhoneState = state;
+ mPhoneStateOwnerUid = uid;
return NO_ERROR;
}
@@ -172,6 +219,7 @@
audio_stream_type_t *stream,
pid_t pid,
uid_t uid,
+ const String16& opPackageName,
const audio_config_t *config,
audio_output_flags_t flags,
audio_port_handle_t *selectedDeviceId,
@@ -181,13 +229,19 @@
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
- ALOGV("getOutputForAttr()");
+
+ status_t result = validateUsage(attr->usage, pid, uid);
+ if (result != NO_ERROR) {
+ return result;
+ }
+
+ ALOGV("%s()", __func__);
Mutex::Autolock _l(mLock);
const uid_t callingUid = IPCThreadState::self()->getCallingUid();
if (!isAudioServerOrMediaServerUid(callingUid) || uid == (uid_t)-1) {
ALOGW_IF(uid != (uid_t)-1 && uid != callingUid,
- "%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, uid);
+ "%s uid %d tried to pass itself off as %d", __func__, callingUid, uid);
uid = callingUid;
}
if (!mPackageManager.allowPlaybackCapture(uid)) {
@@ -197,32 +251,45 @@
&& !bypassInterruptionPolicyAllowed(pid, uid)) {
attr->flags &= ~(AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY|AUDIO_FLAG_BYPASS_MUTE);
}
- audio_output_flags_t originalFlags = flags;
AutoCallerClear acc;
- status_t result = mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, uid,
+ AudioPolicyInterface::output_type_t outputType;
+ result = mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, uid,
config,
&flags, selectedDeviceId, portId,
- secondaryOutputs);
+ secondaryOutputs,
+ &outputType);
// FIXME: Introduce a way to check for the the telephony device before opening the output
- if ((result == NO_ERROR) &&
- (flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) &&
- !modifyPhoneStateAllowed(pid, uid)) {
- // If the app tries to play music through the telephony device and doesn't have permission
- // the fallback to the default output device.
- mAudioPolicyManager->releaseOutput(*portId);
- flags = originalFlags;
- *selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
- *portId = AUDIO_PORT_HANDLE_NONE;
- secondaryOutputs->clear();
- result = mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, uid, config,
- &flags, selectedDeviceId, portId,
- secondaryOutputs);
+ if (result == NO_ERROR) {
+ // enforce permission (if any) required for each type of input
+ switch (outputType) {
+ case AudioPolicyInterface::API_OUTPUT_LEGACY:
+ break;
+ case AudioPolicyInterface::API_OUTPUT_TELEPHONY_TX:
+ if (!modifyPhoneStateAllowed(pid, uid) &&
+ !accessCallAudioAllowed(opPackageName, pid, uid)) {
+ ALOGE("%s() permission denied: modify phone state not allowed for uid %d",
+ __func__, uid);
+ result = PERMISSION_DENIED;
+ }
+ break;
+ case AudioPolicyInterface::API_OUT_MIX_PLAYBACK:
+ if (!modifyAudioRoutingAllowed(pid, uid)) {
+ ALOGE("%s() permission denied: modify audio routing not allowed for uid %d",
+ __func__, uid);
+ result = PERMISSION_DENIED;
+ }
+ break;
+ case AudioPolicyInterface::API_OUTPUT_INVALID:
+ default:
+ LOG_ALWAYS_FATAL("%s() encountered an invalid output type %d",
+ __func__, (int)outputType);
+ }
}
if (result == NO_ERROR) {
sp <AudioPlaybackClient> client =
- new AudioPlaybackClient(*attr, *output, uid, pid, session, *selectedDeviceId, *stream);
+ new AudioPlaybackClient(*attr, *output, uid, pid, session, *portId, *selectedDeviceId, *stream);
mAudioPlaybackClients.add(*portId, client);
}
return result;
@@ -351,12 +418,22 @@
return NO_INIT;
}
+ status_t result = validateUsage(attr->usage, pid, uid);
+ if (result != NO_ERROR) {
+ return result;
+ }
+
+ audio_source_t inputSource = attr->source;
+ if (inputSource == AUDIO_SOURCE_DEFAULT) {
+ inputSource = AUDIO_SOURCE_MIC;
+ }
+
// already checked by client, but double-check in case the client wrapper is bypassed
- if ((attr->source < AUDIO_SOURCE_DEFAULT)
- || (attr->source >= AUDIO_SOURCE_CNT
- && attr->source != AUDIO_SOURCE_HOTWORD
- && attr->source != AUDIO_SOURCE_FM_TUNER
- && attr->source != AUDIO_SOURCE_ECHO_REFERENCE)) {
+ if ((inputSource < AUDIO_SOURCE_DEFAULT)
+ || (inputSource >= AUDIO_SOURCE_CNT
+ && inputSource != AUDIO_SOURCE_HOTWORD
+ && inputSource != AUDIO_SOURCE_FM_TUNER
+ && inputSource != AUDIO_SOURCE_ECHO_REFERENCE)) {
return BAD_VALUE;
}
@@ -377,24 +454,34 @@
pid = callingPid;
}
- // check calling permissions
- if (!recordingAllowed(opPackageName, pid, uid)) {
+ // check calling permissions.
+ // Capturing from FM_TUNER source is controlled by captureAudioOutputAllowed() only as this
+ // does not affect users privacy as does capturing from an actual microphone.
+ if (!(recordingAllowed(opPackageName, pid, uid) || attr->source == AUDIO_SOURCE_FM_TUNER)) {
ALOGE("%s permission denied: recording not allowed for uid %d pid %d",
__func__, uid, pid);
return PERMISSION_DENIED;
}
bool canCaptureOutput = captureAudioOutputAllowed(pid, uid);
- if ((attr->source == AUDIO_SOURCE_VOICE_UPLINK ||
- attr->source == AUDIO_SOURCE_VOICE_DOWNLINK ||
- attr->source == AUDIO_SOURCE_VOICE_CALL ||
- attr->source == AUDIO_SOURCE_ECHO_REFERENCE) &&
+ bool canCaptureTelephonyOutput = canCaptureOutput
+ || accessCallAudioAllowed(opPackageName, pid, uid);
+
+ if ((attr->source == AUDIO_SOURCE_ECHO_REFERENCE ||
+ attr->source == AUDIO_SOURCE_FM_TUNER) &&
!canCaptureOutput) {
return PERMISSION_DENIED;
}
+ if ((attr->source == AUDIO_SOURCE_VOICE_UPLINK ||
+ attr->source == AUDIO_SOURCE_VOICE_DOWNLINK ||
+ attr->source == AUDIO_SOURCE_VOICE_CALL) &&
+ !canCaptureTelephonyOutput) {
+ return PERMISSION_DENIED;
+ }
+
bool canCaptureHotword = captureHotwordAllowed(opPackageName, pid, uid);
- if ((attr->source == AUDIO_SOURCE_HOTWORD) && !canCaptureHotword) {
+ if ((inputSource == AUDIO_SOURCE_HOTWORD) && !canCaptureHotword) {
return BAD_VALUE;
}
@@ -424,6 +511,11 @@
break;
case AudioPolicyInterface::API_INPUT_TELEPHONY_RX:
// FIXME: use the same permission as for remote submix for now.
+ if (!canCaptureTelephonyOutput) {
+ ALOGE("getInputForAttr() permission denied: call capture not allowed");
+ status = PERMISSION_DENIED;
+ }
+ break;
case AudioPolicyInterface::API_INPUT_MIX_CAPTURE:
if (!canCaptureOutput) {
ALOGE("getInputForAttr() permission denied: capture not allowed");
@@ -431,7 +523,7 @@
}
break;
case AudioPolicyInterface::API_INPUT_MIX_EXT_POLICY_REROUTE:
- if (!modifyAudioRoutingAllowed()) {
+ if (!modifyAudioRoutingAllowed(pid, uid)) {
ALOGE("getInputForAttr() permission denied: modify audio routing not allowed");
status = PERMISSION_DENIED;
}
@@ -451,15 +543,19 @@
return status;
}
- sp<AudioRecordClient> client = new AudioRecordClient(*attr, *input, uid, pid, session,
+ bool allowAudioCapture = canCaptureOutput ||
+ (inputType == AudioPolicyInterface::API_INPUT_TELEPHONY_RX &&
+ canCaptureTelephonyOutput);
+
+ sp<AudioRecordClient> client = new AudioRecordClient(*attr, *input, uid, pid, session, *portId,
*selectedDeviceId, opPackageName,
- canCaptureOutput, canCaptureHotword);
+ allowAudioCapture, canCaptureHotword);
mAudioRecordClients.add(*portId, client);
}
if (audioPolicyEffects != 0) {
// create audio pre processors according to input source
- status_t status = audioPolicyEffects->addInputEffects(*input, attr->source, session);
+ status_t status = audioPolicyEffects->addInputEffects(*input, inputSource, session);
if (status != NO_ERROR && status != ALREADY_EXISTS) {
ALOGW("Failed to add effects on input %d", *input);
}
@@ -494,7 +590,8 @@
}
// check calling permissions
- if (!startRecording(client->opPackageName, client->pid, client->uid)) {
+ if (!(startRecording(client->opPackageName, client->pid, client->uid)
+ || client->attributes.source == AUDIO_SOURCE_FM_TUNER)) {
ALOGE("%s permission denied: recording not allowed for uid %d pid %d",
__func__, client->uid, client->pid);
return PERMISSION_DENIED;
@@ -532,7 +629,7 @@
static constexpr char kAudioPolicyActiveDevice[] =
"android.media.audiopolicy.active.device";
- MediaAnalyticsItem *item = MediaAnalyticsItem::create(kAudioPolicy);
+ mediametrics::Item *item = mediametrics::Item::create(kAudioPolicy);
if (item != NULL) {
item->setInt32(kAudioPolicyStatus, status);
@@ -785,6 +882,17 @@
return mAudioPolicyManager->getDevicesForStream(stream);
}
+status_t AudioPolicyService::getDevicesForAttributes(const AudioAttributes &aa,
+ AudioDeviceTypeAddrVector *devices) const
+{
+ if (mAudioPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ Mutex::Autolock _l(mLock);
+ AutoCallerClear acc;
+ return mAudioPolicyManager->getDevicesForAttributes(aa.getAttributes(), devices);
+}
+
audio_io_handle_t AudioPolicyService::getOutputForEffect(const effect_descriptor_t *desc)
{
// FIXME change return type to status_t, and return NO_INIT here
@@ -970,6 +1078,22 @@
return audioPolicyEffects->removeStreamDefaultEffect(id);
}
+status_t AudioPolicyService::setSupportedSystemUsages(const std::vector<audio_usage_t>& systemUsages) {
+ Mutex::Autolock _l(mLock);
+ if(!modifyAudioRoutingAllowed()) {
+ return PERMISSION_DENIED;
+ }
+
+ bool areAllSystemUsages = std::all_of(begin(systemUsages), end(systemUsages),
+ [](audio_usage_t usage) { return isSystemUsage(usage); });
+ if (!areAllSystemUsages) {
+ return BAD_VALUE;
+ }
+
+ mSupportedSystemUsages = systemUsages;
+ return NO_ERROR;
+}
+
status_t AudioPolicyService::setAllowedCapturePolicy(uid_t uid, audio_flags_mask_t capturePolicy) {
Mutex::Autolock _l(mLock);
if (mAudioPolicyManager == NULL) {
@@ -996,6 +1120,12 @@
ALOGV("mAudioPolicyManager == NULL");
return false;
}
+
+ status_t result = validateUsage(attributes.usage);
+ if (result != NO_ERROR) {
+ return result;
+ }
+
Mutex::Autolock _l(mLock);
return mAudioPolicyManager->isDirectOutputSupported(config, attributes);
}
@@ -1112,14 +1242,27 @@
return PERMISSION_DENIED;
}
+ // If one of the mixes has needCaptureVoiceCommunicationOutput set to true, then we
+ // need to verify that the caller still has CAPTURE_VOICE_COMMUNICATION_OUTPUT
+ bool needCaptureVoiceCommunicationOutput =
+ std::any_of(mixes.begin(), mixes.end(), [](auto& mix) {
+ return mix.mVoiceCommunicationCaptureAllowed; });
+
bool needCaptureMediaOutput = std::any_of(mixes.begin(), mixes.end(), [](auto& mix) {
return mix.mAllowPrivilegedPlaybackCapture; });
+
const uid_t callingUid = IPCThreadState::self()->getCallingUid();
const pid_t callingPid = IPCThreadState::self()->getCallingPid();
+
if (needCaptureMediaOutput && !captureMediaOutputAllowed(callingPid, callingUid)) {
return PERMISSION_DENIED;
}
+ if (needCaptureVoiceCommunicationOutput &&
+ !captureVoiceCommunicationOutputAllowed(callingPid, callingUid)) {
+ return PERMISSION_DENIED;
+ }
+
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
@@ -1156,6 +1299,31 @@
return mAudioPolicyManager->removeUidDeviceAffinities(uid);
}
+status_t AudioPolicyService::setUserIdDeviceAffinities(int userId,
+ const Vector<AudioDeviceTypeAddr>& devices) {
+ Mutex::Autolock _l(mLock);
+ if(!modifyAudioRoutingAllowed()) {
+ return PERMISSION_DENIED;
+ }
+ if (mAudioPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ AutoCallerClear acc;
+ return mAudioPolicyManager->setUserIdDeviceAffinities(userId, devices);
+}
+
+status_t AudioPolicyService::removeUserIdDeviceAffinities(int userId) {
+ Mutex::Autolock _l(mLock);
+ if(!modifyAudioRoutingAllowed()) {
+ return PERMISSION_DENIED;
+ }
+ if (mAudioPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ AutoCallerClear acc;
+ return mAudioPolicyManager->removeUserIdDeviceAffinities(userId);
+}
+
status_t AudioPolicyService::startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
audio_port_handle_t *portId)
@@ -1164,6 +1332,12 @@
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
+
+ status_t result = validateUsage(attributes->usage);
+ if (result != NO_ERROR) {
+ return result;
+ }
+
// startAudioSource should be created as the calling uid
const uid_t callingUid = IPCThreadState::self()->getCallingUid();
AutoCallerClear acc;
@@ -1320,4 +1494,44 @@
return NO_ERROR;
}
+bool AudioPolicyService::isCallScreenModeSupported()
+{
+ if (mAudioPolicyManager == NULL) {
+ ALOGW("%s, mAudioPolicyManager == NULL", __func__);
+ return false;
+ }
+ Mutex::Autolock _l(mLock);
+ AutoCallerClear acc;
+ return mAudioPolicyManager->isCallScreenModeSupported();
+}
+
+status_t AudioPolicyService::setPreferredDeviceForStrategy(product_strategy_t strategy,
+ const AudioDeviceTypeAddr &device)
+{
+ if (mAudioPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ Mutex::Autolock _l(mLock);
+ return mAudioPolicyManager->setPreferredDeviceForStrategy(strategy, device);
+}
+
+status_t AudioPolicyService::removePreferredDeviceForStrategy(product_strategy_t strategy)
+{
+ if (mAudioPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ Mutex::Autolock _l(mLock);
+ return mAudioPolicyManager->removePreferredDeviceForStrategy(strategy);
+}
+
+status_t AudioPolicyService::getPreferredDeviceForStrategy(product_strategy_t strategy,
+ AudioDeviceTypeAddr &device)
+{
+ if (mAudioPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ Mutex::Autolock _l(mLock);
+ return mAudioPolicyManager->getPreferredDeviceForStrategy(strategy, device);
+}
+
} // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index a6cda20..bf38477 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -29,7 +29,6 @@
#include <utils/Log.h>
#include <cutils/properties.h>
#include <binder/IPCThreadState.h>
-#include <binder/ActivityManager.h>
#include <binder/PermissionController.h>
#include <binder/IResultReceiver.h>
#include <utils/String16.h>
@@ -75,6 +74,8 @@
mAudioPolicyClient = new AudioPolicyClient(this);
mAudioPolicyManager = createAudioPolicyManager(mAudioPolicyClient);
+
+ mSupportedSystemUsages = std::vector<audio_usage_t> {};
}
// load audio processing modules
sp<AudioPolicyEffects>audioPolicyEffects = new AudioPolicyEffects();
@@ -393,6 +394,14 @@
snprintf(buffer, SIZE, "Command Thread: %p\n", mAudioCommandThread.get());
result.append(buffer);
+ snprintf(buffer, SIZE, "Supported System Usages:\n");
+ result.append(buffer);
+ for (std::vector<audio_usage_t>::iterator it = mSupportedSystemUsages.begin();
+ it != mSupportedSystemUsages.end(); ++it) {
+ snprintf(buffer, SIZE, "\t%d\n", *it);
+ result.append(buffer);
+ }
+
write(fd, result.string(), result.size());
return NO_ERROR;
}
@@ -407,8 +416,7 @@
{
// Go over all active clients and allow capture (does not force silence) in the
// following cases:
-// Another client in the same UID has already been allowed to capture
-// OR The client is the assistant
+// The client is the assistant
// AND an accessibility service is on TOP or a RTT call is active
// AND the source is VOICE_RECOGNITION or HOTWORD
// OR uses VOICE_RECOGNITION AND is on TOP
@@ -424,26 +432,35 @@
// AND is on TOP
// AND the source is VOICE_RECOGNITION or HOTWORD
// OR the client source is virtual (remote submix, call audio TX or RX...)
+// OR the client source is HOTWORD
+// AND is on TOP
+// OR all active clients are using HOTWORD source
+// AND no call is active
+// OR client has CAPTURE_AUDIO_OUTPUT privileged permission
// OR Any client
// AND The assistant is not on TOP
// AND is on TOP or latest started
// AND there is no active privacy sensitive capture or call
// OR client has CAPTURE_AUDIO_OUTPUT privileged permission
+
sp<AudioRecordClient> topActive;
sp<AudioRecordClient> latestActive;
+ sp<AudioRecordClient> topSensitiveActive;
sp<AudioRecordClient> latestSensitiveActive;
nsecs_t topStartNs = 0;
nsecs_t latestStartNs = 0;
+ nsecs_t topSensitiveStartNs = 0;
nsecs_t latestSensitiveStartNs = 0;
bool isA11yOnTop = mUidPolicy->isA11yOnTop();
bool isAssistantOnTop = false;
bool isSensitiveActive = false;
bool isInCall = mPhoneState == AUDIO_MODE_IN_CALL;
- bool rttCallActive =
- (mPhoneState == AUDIO_MODE_IN_CALL || mPhoneState == AUDIO_MODE_IN_COMMUNICATION)
+ bool isInCommunication = mPhoneState == AUDIO_MODE_IN_COMMUNICATION;
+ bool rttCallActive = (isInCall || isInCommunication)
&& mUidPolicy->isRttEnabled();
+ bool onlyHotwordActive = true;
// if Sensor Privacy is enabled then all recordings should be silenced.
if (mSensorPrivacyPolicy->isSensorPrivacyEnabled()) {
@@ -464,42 +481,71 @@
continue;
}
- bool isAssistant = mUidPolicy->isAssistantUid(current->uid);
bool isAccessibility = mUidPolicy->isA11yUid(current->uid);
- if (appState == APP_STATE_TOP && !isAccessibility) {
- if (current->startTimeNs > topStartNs) {
- topActive = current;
- topStartNs = current->startTimeNs;
+ // Clients capturing for Accessibility services are not considered
+ // for top or latest active to avoid masking regular clients started before
+ if (!isAccessibility) {
+ bool isAssistant = mUidPolicy->isAssistantUid(current->uid);
+ bool isPrivacySensitive =
+ (current->attributes.flags & AUDIO_FLAG_CAPTURE_PRIVATE) != 0;
+ if (appState == APP_STATE_TOP) {
+ if (isPrivacySensitive) {
+ if (current->startTimeNs > topSensitiveStartNs) {
+ topSensitiveActive = current;
+ topSensitiveStartNs = current->startTimeNs;
+ }
+ } else {
+ if (current->startTimeNs > topStartNs) {
+ topActive = current;
+ topStartNs = current->startTimeNs;
+ }
+ }
+ if (isAssistant) {
+ isAssistantOnTop = true;
+ }
}
- if (isAssistant) {
- isAssistantOnTop = true;
+ // Clients capturing for HOTWORD are not considered
+ // for latest active to avoid masking regular clients started before
+ if (!(current->attributes.source == AUDIO_SOURCE_HOTWORD
+ || ((isA11yOnTop || rttCallActive) && isAssistant))) {
+ if (isPrivacySensitive) {
+ if (current->startTimeNs > latestSensitiveStartNs) {
+ latestSensitiveActive = current;
+ latestSensitiveStartNs = current->startTimeNs;
+ }
+ isSensitiveActive = true;
+ } else {
+ if (current->startTimeNs > latestStartNs) {
+ latestActive = current;
+ latestStartNs = current->startTimeNs;
+ }
+ }
}
}
- // Assistant capturing for HOTWORD or Accessibility services not considered
- // for latest active to avoid masking regular clients started before
- if (current->startTimeNs > latestStartNs
- && !((current->attributes.source == AUDIO_SOURCE_HOTWORD
- || isA11yOnTop || rttCallActive)
- && isAssistant)
- && !isAccessibility) {
- latestActive = current;
- latestStartNs = current->startTimeNs;
- }
- if (isPrivacySensitiveSource(current->attributes.source)) {
- if (current->startTimeNs > latestSensitiveStartNs) {
- latestSensitiveActive = current;
- latestSensitiveStartNs = current->startTimeNs;
- }
- isSensitiveActive = true;
+ if (current->attributes.source != AUDIO_SOURCE_HOTWORD) {
+ onlyHotwordActive = false;
}
}
// if no active client with UI on Top, consider latest active as top
if (topActive == nullptr) {
topActive = latestActive;
+ topStartNs = latestStartNs;
+ }
+ if (topSensitiveActive == nullptr) {
+ topSensitiveActive = latestSensitiveActive;
+ topSensitiveStartNs = latestSensitiveStartNs;
}
- std::vector<uid_t> enabledUids;
+ // If both privacy sensitive and regular capture are active:
+ // if the regular capture is privileged
+ // allow concurrency
+ // else
+ // favor the privacy sensitive case
+ if (topActive != nullptr && topSensitiveActive != nullptr
+ && !topActive->canCaptureCallOrOutput) {
+ topActive = nullptr;
+ }
for (size_t i =0; i < mAudioRecordClients.size(); i++) {
sp<AudioRecordClient> current = mAudioRecordClients[i];
@@ -507,17 +553,19 @@
continue;
}
- // keep capture allowed if another client with the same UID has already
- // been allowed to capture
- if (std::find(enabledUids.begin(), enabledUids.end(), current->uid)
- != enabledUids.end()) {
- continue;
- }
-
audio_source_t source = current->attributes.source;
bool isTopOrLatestActive = topActive == nullptr ? false : current->uid == topActive->uid;
- bool isLatestSensitive = latestSensitiveActive == nullptr ?
- false : current->uid == latestSensitiveActive->uid;
+ bool isTopOrLatestSensitive = topSensitiveActive == nullptr ?
+ false : current->uid == topSensitiveActive->uid;
+
+ auto canCaptureIfInCallOrCommunication = [&](const auto &recordClient) {
+ bool canCaptureCall = recordClient->canCaptureCallOrOutput;
+ bool canCaptureCommunication = recordClient->canCaptureCallOrOutput
+ || recordClient->uid == mPhoneStateOwnerUid
+ || isServiceUid(mPhoneStateOwnerUid);
+ return !(isInCall && !canCaptureCall)
+ && !(isInCommunication && !canCaptureCommunication);
+ };
// By default allow capture if:
// The assistant is not on TOP
@@ -525,9 +573,10 @@
// AND there is no active privacy sensitive capture or call
// OR client has CAPTURE_AUDIO_OUTPUT privileged permission
bool allowCapture = !isAssistantOnTop
- && ((isTopOrLatestActive && !isLatestSensitive) || isLatestSensitive)
- && !(isSensitiveActive && !(isLatestSensitive || current->canCaptureOutput))
- && !(isInCall && !current->canCaptureOutput);
+ && (isTopOrLatestActive || isTopOrLatestSensitive)
+ && !(isSensitiveActive
+ && !(isTopOrLatestSensitive || current->canCaptureCallOrOutput))
+ && canCaptureIfInCallOrCommunication(current);
if (isVirtualSource(source)) {
// Allow capture for virtual (remote submix, call audio TX or RX...) sources
@@ -546,36 +595,42 @@
}
} else {
if (((isAssistantOnTop && source == AUDIO_SOURCE_VOICE_RECOGNITION) ||
- source == AUDIO_SOURCE_HOTWORD) &&
- (!(isSensitiveActive || isInCall) || current->canCaptureOutput)) {
+ source == AUDIO_SOURCE_HOTWORD)
+ && !(isSensitiveActive && !current->canCaptureCallOrOutput)
+ && canCaptureIfInCallOrCommunication(current)) {
allowCapture = true;
}
}
} else if (mUidPolicy->isA11yUid(current->uid)) {
// For accessibility service allow capture if:
- // Is on TOP
- // AND the source is VOICE_RECOGNITION or HOTWORD
- // Or
- // The assistant is not on TOP
- // AND there is no active privacy sensitive capture or call
+ // The assistant is not on TOP
+ // AND there is no active privacy sensitive capture or call
// OR client has CAPTURE_AUDIO_OUTPUT privileged permission
+ // OR
+ // Is on TOP AND the source is VOICE_RECOGNITION or HOTWORD
+ if (!isAssistantOnTop
+ && !(isSensitiveActive && !current->canCaptureCallOrOutput)
+ && canCaptureIfInCallOrCommunication(current)) {
+ allowCapture = true;
+ }
if (isA11yOnTop) {
if (source == AUDIO_SOURCE_VOICE_RECOGNITION || source == AUDIO_SOURCE_HOTWORD) {
allowCapture = true;
}
- } else {
- if (!isAssistantOnTop
- && (!(isSensitiveActive || isInCall) || current->canCaptureOutput)) {
- allowCapture = true;
- }
+ }
+ } else if (source == AUDIO_SOURCE_HOTWORD) {
+ // For HOTWORD source allow capture when not on TOP if:
+ // All active clients are using HOTWORD source
+ // AND no call is active
+ // OR client has CAPTURE_AUDIO_OUTPUT privileged permission
+ if (onlyHotwordActive
+ && canCaptureIfInCallOrCommunication(current)) {
+ allowCapture = true;
}
}
- setAppState_l(current->uid,
+ setAppState_l(current->portId,
allowCapture ? apmStatFromAmState(mUidPolicy->getUidState(current->uid)) :
APP_STATE_IDLE);
- if (allowCapture) {
- enabledUids.push_back(current->uid);
- }
}
}
@@ -583,7 +638,7 @@
for (size_t i = 0; i < mAudioRecordClients.size(); i++) {
sp<AudioRecordClient> current = mAudioRecordClients[i];
if (!isVirtualSource(current->attributes.source)) {
- setAppState_l(current->uid, APP_STATE_IDLE);
+ setAppState_l(current->portId, APP_STATE_IDLE);
}
}
}
@@ -601,19 +656,6 @@
}
/* static */
-bool AudioPolicyService::isPrivacySensitiveSource(audio_source_t source)
-{
- switch (source) {
- case AUDIO_SOURCE_CAMCORDER:
- case AUDIO_SOURCE_VOICE_COMMUNICATION:
- return true;
- default:
- break;
- }
- return false;
-}
-
-/* static */
bool AudioPolicyService::isVirtualSource(audio_source_t source)
{
switch (source) {
@@ -629,17 +671,17 @@
return false;
}
-void AudioPolicyService::setAppState_l(uid_t uid, app_state_t state)
+void AudioPolicyService::setAppState_l(audio_port_handle_t portId, app_state_t state)
{
AutoCallerClear acc;
if (mAudioPolicyManager) {
- mAudioPolicyManager->setAppState(uid, state);
+ mAudioPolicyManager->setAppState(portId, state);
}
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
if (af) {
bool silenced = state == APP_STATE_IDLE;
- af->setRecordSilenced(uid, silenced);
+ af->setRecordSilenced(portId, silenced);
}
}
@@ -844,28 +886,26 @@
// ----------- AudioPolicyService::UidPolicy implementation ----------
void AudioPolicyService::UidPolicy::registerSelf() {
- ActivityManager am;
- am.registerUidObserver(this, ActivityManager::UID_OBSERVER_GONE
+ status_t res = mAm.linkToDeath(this);
+ mAm.registerUidObserver(this, ActivityManager::UID_OBSERVER_GONE
| ActivityManager::UID_OBSERVER_IDLE
| ActivityManager::UID_OBSERVER_ACTIVE
| ActivityManager::UID_OBSERVER_PROCSTATE,
ActivityManager::PROCESS_STATE_UNKNOWN,
String16("audioserver"));
- status_t res = am.linkToDeath(this);
if (!res) {
Mutex::Autolock _l(mLock);
mObserverRegistered = true;
} else {
ALOGE("UidPolicy::registerSelf linkToDeath failed: %d", res);
- am.unregisterUidObserver(this);
+ mAm.unregisterUidObserver(this);
}
}
void AudioPolicyService::UidPolicy::unregisterSelf() {
- ActivityManager am;
- am.unlinkToDeath(this);
- am.unregisterUidObserver(this);
+ mAm.unlinkToDeath(this);
+ mAm.unregisterUidObserver(this);
Mutex::Autolock _l(mLock);
mObserverRegistered = false;
}
@@ -978,7 +1018,8 @@
void AudioPolicyService::UidPolicy::onUidStateChanged(uid_t uid,
int32_t procState,
- int64_t procStateSeq __unused) {
+ int64_t procStateSeq __unused,
+ int32_t capability __unused) {
if (procState != ActivityManager::PROCESS_STATE_UNKNOWN) {
updateUid(&mCachedUids, uid, true, procState, true);
}
@@ -1043,8 +1084,7 @@
bool AudioPolicyService::UidPolicy::isA11yOnTop() {
for (const auto &uid : mCachedUids) {
- std::vector<uid_t>::iterator it = find(mA11yUids.begin(), mA11yUids.end(), uid.first);
- if (it == mA11yUids.end()) {
+ if (!isA11yUid(uid.first)) {
continue;
}
if (uid.second.second >= ActivityManager::PROCESS_STATE_TOP
@@ -1281,6 +1321,16 @@
mLock.lock();
}
} break;
+ case AUDIO_MODULES_UPDATE: {
+ ALOGV("AudioCommandThread() processing audio modules update");
+ svc = mService.promote();
+ if (svc == 0) {
+ break;
+ }
+ mLock.unlock();
+ svc->doOnNewAudioModulesAvailable();
+ mLock.lock();
+ } break;
default:
ALOGW("AudioCommandThread() unknown command %d", command->mCommand);
@@ -1570,6 +1620,13 @@
sendCommand(command);
}
+void AudioPolicyService::AudioCommandThread::audioModulesUpdateCommand()
+{
+ sp<AudioCommand> command = new AudioCommand();
+ command->mCommand = AUDIO_MODULES_UPDATE;
+ sendCommand(command);
+}
+
status_t AudioPolicyService::AudioCommandThread::sendCommand(sp<AudioCommand>& command, int delayMs)
{
{
@@ -1817,6 +1874,11 @@
mAudioCommandThread->setEffectSuspendedCommand(effectId, sessionId, suspended);
}
+void AudioPolicyService::onNewAudioModulesAvailable()
+{
+ mAudioCommandThread->audioModulesUpdateCommand();
+}
+
extern "C" {
audio_module_handle_t aps_load_hw_module(void *service __unused,
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index e467f70..ff99124 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -23,6 +23,7 @@
#include <utils/String8.h>
#include <utils/Vector.h>
#include <utils/SortedVector.h>
+#include <binder/ActivityManager.h>
#include <binder/BinderService.h>
#include <binder/IUidObserver.h>
#include <system/audio.h>
@@ -59,6 +60,7 @@
// BnAudioPolicyService (see AudioPolicyInterface for method descriptions)
//
+ void onNewAudioModulesAvailable() override;
virtual status_t setDeviceConnectionState(audio_devices_t device,
audio_policy_dev_state_t state,
const char *device_address,
@@ -71,7 +73,7 @@
const char *device_address,
const char *device_name,
audio_format_t encodedFormat);
- virtual status_t setPhoneState(audio_mode_t state);
+ virtual status_t setPhoneState(audio_mode_t state, uid_t uid);
virtual status_t setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config);
virtual audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage);
virtual audio_io_handle_t getOutput(audio_stream_type_t stream);
@@ -81,6 +83,7 @@
audio_stream_type_t *stream,
pid_t pid,
uid_t uid,
+ const String16& opPackageName,
const audio_config_t *config,
audio_output_flags_t flags,
audio_port_handle_t *selectedDeviceId,
@@ -126,6 +129,8 @@
virtual uint32_t getStrategyForStream(audio_stream_type_t stream);
virtual audio_devices_t getDevicesForStream(audio_stream_type_t stream);
+ virtual status_t getDevicesForAttributes(const AudioAttributes &aa,
+ AudioDeviceTypeAddrVector *devices) const;
virtual audio_io_handle_t getOutputForEffect(const effect_descriptor_t *desc);
virtual status_t registerEffect(const effect_descriptor_t *desc,
@@ -184,6 +189,7 @@
audio_io_handle_t output,
int delayMs = 0);
virtual status_t setVoiceVolume(float volume, int delayMs = 0);
+ status_t setSupportedSystemUsages(const std::vector<audio_usage_t>& systemUsages);
status_t setAllowedCapturePolicy(uint_t uid, audio_flags_mask_t capturePolicy) override;
virtual bool isOffloadSupported(const audio_offload_info_t &config);
virtual bool isDirectOutputSupported(const audio_config_base_t& config,
@@ -223,6 +229,18 @@
virtual status_t removeUidDeviceAffinities(uid_t uid);
+ virtual status_t setPreferredDeviceForStrategy(product_strategy_t strategy,
+ const AudioDeviceTypeAddr &device);
+
+ virtual status_t removePreferredDeviceForStrategy(product_strategy_t strategy);
+
+
+ virtual status_t getPreferredDeviceForStrategy(product_strategy_t strategy,
+ AudioDeviceTypeAddr &device);
+ virtual status_t setUserIdDeviceAffinities(int userId, const Vector<AudioDeviceTypeAddr>& devices);
+
+ virtual status_t removeUserIdDeviceAffinities(int userId);
+
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
audio_port_handle_t *portId);
@@ -258,6 +276,9 @@
virtual status_t setRttEnabled(bool enabled);
+ bool isCallScreenModeSupported() override;
+
+ void doOnNewAudioModulesAvailable();
status_t doStopOutput(audio_port_handle_t portId);
void doReleaseOutput(audio_port_handle_t portId);
@@ -310,7 +331,7 @@
virtual status_t shellCommand(int in, int out, int err, Vector<String16>& args);
// Sets whether the given UID records only silence
- virtual void setAppState_l(uid_t uid, app_state_t state);
+ virtual void setAppState_l(audio_port_handle_t portId, app_state_t state);
// Overrides the UID state as if it is idle
status_t handleSetUidState(Vector<String16>& args, int err);
@@ -330,12 +351,15 @@
app_state_t apmStatFromAmState(int amState);
+ bool isSupportedSystemUsage(audio_usage_t usage);
+ status_t validateUsage(audio_usage_t usage);
+ status_t validateUsage(audio_usage_t usage, pid_t pid, uid_t uid);
+
void updateUidStates();
void updateUidStates_l();
void silenceAllRecordings_l();
- static bool isPrivacySensitiveSource(audio_source_t source);
static bool isVirtualSource(audio_source_t source);
// If recording we need to make sure the UID is allowed to do that. If the UID is idle
@@ -370,7 +394,8 @@
void onUidActive(uid_t uid) override;
void onUidGone(uid_t uid, bool disabled) override;
void onUidIdle(uid_t uid, bool disabled) override;
- void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq);
+ void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq,
+ int32_t capability);
void addOverrideUid(uid_t uid, bool active) { updateOverrideUid(uid, active, true); }
void removeOverrideUid(uid_t uid) { updateOverrideUid(uid, false, false); }
@@ -387,6 +412,7 @@
wp<AudioPolicyService> mService;
Mutex mLock;
+ ActivityManager mAm;
bool mObserverRegistered;
std::unordered_map<uid_t, std::pair<bool, int>> mOverrideUids;
std::unordered_map<uid_t, std::pair<bool, int>> mCachedUids;
@@ -439,6 +465,7 @@
DYN_POLICY_MIX_STATE_UPDATE,
RECORDING_CONFIGURATION_UPDATE,
SET_EFFECT_SUSPENDED,
+ AUDIO_MODULES_UPDATE,
};
AudioCommandThread (String8 name, const wp<AudioPolicyService>& service);
@@ -484,6 +511,7 @@
void setEffectSuspendedCommand(int effectId,
audio_session_t sessionId,
bool suspended);
+ void audioModulesUpdateCommand();
void insertCommand_l(AudioCommand *command, int delayMs = 0);
private:
class AudioCommandData;
@@ -620,8 +648,7 @@
virtual status_t openOutput(audio_module_handle_t module,
audio_io_handle_t *output,
audio_config_t *config,
- audio_devices_t *devices,
- const String8& address,
+ const sp<DeviceDescriptorBase>& device,
uint32_t *latencyMs,
audio_output_flags_t flags);
// creates a special output that is duplicated to the two outputs passed as arguments. The duplication is performed by
@@ -705,6 +732,8 @@
virtual audio_unique_id_t newAudioUniqueId(audio_unique_id_use_t use);
+ void setSoundTriggerCaptureState(bool active) override;
+
private:
AudioPolicyService *mAudioPolicyService;
};
@@ -757,9 +786,10 @@
public:
AudioClient(const audio_attributes_t attributes,
const audio_io_handle_t io, uid_t uid, pid_t pid,
- const audio_session_t session, const audio_port_handle_t deviceId) :
+ const audio_session_t session, audio_port_handle_t portId,
+ const audio_port_handle_t deviceId) :
attributes(attributes), io(io), uid(uid), pid(pid),
- session(session), deviceId(deviceId), active(false) {}
+ session(session), portId(portId), deviceId(deviceId), active(false) {}
~AudioClient() override = default;
@@ -768,6 +798,7 @@
const uid_t uid; // client UID
const pid_t pid; // client PID
const audio_session_t session; // audio session ID
+ const audio_port_handle_t portId;
const audio_port_handle_t deviceId; // selected input device port ID
bool active; // Playback/Capture is active or inactive
};
@@ -779,17 +810,18 @@
public:
AudioRecordClient(const audio_attributes_t attributes,
const audio_io_handle_t io, uid_t uid, pid_t pid,
- const audio_session_t session, const audio_port_handle_t deviceId,
- const String16& opPackageName,
- bool canCaptureOutput, bool canCaptureHotword) :
- AudioClient(attributes, io, uid, pid, session, deviceId),
+ const audio_session_t session, audio_port_handle_t portId,
+ const audio_port_handle_t deviceId, const String16& opPackageName,
+ bool canCaptureCallOrOutput, bool canCaptureHotword) :
+ AudioClient(attributes, io, uid, pid, session, portId, deviceId),
opPackageName(opPackageName), startTimeNs(0),
- canCaptureOutput(canCaptureOutput), canCaptureHotword(canCaptureHotword) {}
+ canCaptureCallOrOutput(canCaptureCallOrOutput),
+ canCaptureHotword(canCaptureHotword) {}
~AudioRecordClient() override = default;
const String16 opPackageName; // client package name
nsecs_t startTimeNs;
- const bool canCaptureOutput;
+ const bool canCaptureCallOrOutput;
const bool canCaptureHotword;
};
@@ -800,9 +832,9 @@
public:
AudioPlaybackClient(const audio_attributes_t attributes,
const audio_io_handle_t io, uid_t uid, pid_t pid,
- const audio_session_t session, audio_port_handle_t deviceId,
- audio_stream_type_t stream) :
- AudioClient(attributes, io, uid, pid, session, deviceId), stream(stream) {}
+ const audio_session_t session, audio_port_handle_t portId,
+ audio_port_handle_t deviceId, audio_stream_type_t stream) :
+ AudioClient(attributes, io, uid, pid, session, portId, deviceId), stream(stream) {}
~AudioPlaybackClient() override = default;
const audio_stream_type_t stream;
@@ -845,6 +877,7 @@
struct audio_policy *mpAudioPolicy;
AudioPolicyInterface *mAudioPolicyManager;
AudioPolicyClient *mAudioPolicyClient;
+ std::vector<audio_usage_t> mSupportedSystemUsages;
DefaultKeyedVector< int64_t, sp<NotificationClient> > mNotificationClients;
Mutex mNotificationClientsLock; // protects mNotificationClients
@@ -853,6 +886,7 @@
// those can call back into AudioPolicyService methods and try to acquire the mutex
sp<AudioPolicyEffects> mAudioPolicyEffects;
audio_mode_t mPhoneState;
+ uid_t mPhoneStateOwnerUid;
sp<UidPolicy> mUidPolicy;
sp<SensorPrivacyPolicy> mSensorPrivacyPolicy;
diff --git a/services/audiopolicy/service/BinderProxy.h b/services/audiopolicy/service/BinderProxy.h
new file mode 100644
index 0000000..516e84d
--- /dev/null
+++ b/services/audiopolicy/service/BinderProxy.h
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <mutex>
+#include <type_traits>
+#include <binder/IInterface.h>
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+
+namespace android {
+
+// A simple utility that caches a proxy for a service and handles death notification.
+// Typically, intended to be used as a static-lifetime object.
+//
+// Example usage:
+// static BinderProxy<IMyInterface> myInterface("my_interface_svc");
+// ...
+// myInterface.waitServiceOrDie()->doSomething();
+//
+// If the service is unavailable, will wait until it becomes available.
+// Will die if the service doesn't implement the requested interface, or cannot be used for
+// permission reasons.
+template<typename ServiceType>
+class BinderProxy {
+public:
+ static_assert(std::is_base_of_v<IInterface, ServiceType>,
+ "Service type must be a sub-type of IInterface.");
+
+ explicit BinderProxy(std::string_view serviceName)
+ : mServiceName(serviceName), mDeathRecipient(new DeathRecipient(this)) {}
+
+ ~BinderProxy() {
+ if (mDelegate != nullptr) {
+ sp<IBinder> binder = IInterface::asBinder(mDelegate);
+ if (binder != nullptr) {
+ binder->unlinkToDeath(mDeathRecipient);
+ }
+ }
+ }
+
+ sp<ServiceType> waitServiceOrDie() {
+ std::lock_guard<std::mutex> _l(mDelegateMutex);
+ if (mDelegate == nullptr) {
+ mDelegate = waitForService<ServiceType>(String16(mServiceName.c_str()));
+ LOG_ALWAYS_FATAL_IF(mDelegate == nullptr,
+ "Service %s doesn't implement the required interface.",
+ mServiceName.c_str());
+ sp<IBinder> binder = IInterface::asBinder(mDelegate);
+ if (binder != nullptr) {
+ binder->linkToDeath(mDeathRecipient);
+ }
+ }
+ return mDelegate;
+ }
+
+private:
+ sp<ServiceType> mDelegate;
+ std::mutex mDelegateMutex;
+ const std::string mServiceName;
+ sp<IBinder::DeathRecipient> mDeathRecipient;
+
+ class DeathRecipient : public IBinder::DeathRecipient {
+ public:
+ DeathRecipient(BinderProxy* proxy) : mProxy(proxy) {}
+
+ void binderDied(const wp<IBinder>&) override {
+ mProxy->binderDied();
+ }
+
+ private:
+ BinderProxy* const mProxy;
+ };
+
+ void binderDied() {
+ std::lock_guard<std::mutex> _l(mDelegateMutex);
+ mDelegate.clear();
+ ALOGW("Binder died: %s", mServiceName.c_str());
+ }
+};
+
+} // namespace android
diff --git a/services/audiopolicy/tests/Android.bp b/services/audiopolicy/tests/Android.bp
new file mode 100644
index 0000000..efdb241
--- /dev/null
+++ b/services/audiopolicy/tests/Android.bp
@@ -0,0 +1,71 @@
+cc_test {
+ name: "audiopolicy_tests",
+
+ include_dirs: [
+ "frameworks/av/services/audiopolicy",
+ ],
+
+ shared_libs: [
+ "libaudioclient",
+ "libaudiofoundation",
+ "libaudiopolicy",
+ "libaudiopolicymanagerdefault",
+ "libbase",
+ "libhidlbase",
+ "liblog",
+ "libmedia_helper",
+ "libutils",
+ "libxml2",
+ ],
+
+ static_libs: ["libaudiopolicycomponents"],
+
+ header_libs: [
+ "libaudiopolicycommon",
+ "libaudiopolicyengine_interface_headers",
+ "libaudiopolicymanager_interface_headers",
+ ],
+
+ srcs: ["audiopolicymanager_tests.cpp"],
+
+ data: [":audiopolicytest_configuration_files",],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ test_suites: ["device-tests"],
+
+}
+
+
+cc_test {
+ name: "audio_health_tests",
+
+ shared_libs: [
+ "libaudiofoundation",
+ "libaudioclient",
+ "libaudiopolicymanagerdefault",
+ "liblog",
+ "libmedia_helper",
+ "libutils",
+ ],
+
+ static_libs: ["libaudiopolicycomponents"],
+
+ header_libs: [
+ "libaudiopolicyengine_interface_headers",
+ "libaudiopolicymanager_interface_headers",
+ ],
+
+ srcs: ["audio_health_tests.cpp"],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ test_suites: ["device-tests"],
+
+}
diff --git a/services/audiopolicy/tests/Android.mk b/services/audiopolicy/tests/Android.mk
deleted file mode 100644
index ab9f78b..0000000
--- a/services/audiopolicy/tests/Android.mk
+++ /dev/null
@@ -1,65 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_C_INCLUDES := \
- frameworks/av/services/audiopolicy \
- $(call include-path-for, audio-utils) \
-
-LOCAL_SHARED_LIBRARIES := \
- libaudiopolicymanagerdefault \
- libbase \
- liblog \
- libmedia_helper \
- libutils \
-
-LOCAL_STATIC_LIBRARIES := \
- libaudiopolicycomponents \
-
-LOCAL_HEADER_LIBRARIES := \
- libaudiopolicycommon \
- libaudiopolicyengine_interface_headers \
- libaudiopolicymanager_interface_headers
-
-LOCAL_SRC_FILES := \
- audiopolicymanager_tests.cpp \
-
-LOCAL_MODULE := audiopolicy_tests
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_CFLAGS := -Werror -Wall
-
-LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-include $(BUILD_NATIVE_TEST)
-
-# system/audio.h utilities test
-
-include $(CLEAR_VARS)
-
-LOCAL_SHARED_LIBRARIES := \
- libbase \
- liblog \
- libmedia_helper \
- libutils
-
-LOCAL_HEADER_LIBRARIES := \
- libmedia_headers
-
-LOCAL_SRC_FILES := \
- systemaudio_tests.cpp \
-
-LOCAL_MODULE := systemaudio_tests
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_CFLAGS := -Werror -Wall
-
-LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-include $(BUILD_NATIVE_TEST)
diff --git a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
new file mode 100644
index 0000000..af69466
--- /dev/null
+++ b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+#include <map>
+#include <set>
+
+#include <system/audio.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include "AudioPolicyTestClient.h"
+
+namespace android {
+
+class AudioPolicyManagerTestClient : public AudioPolicyTestClient {
+public:
+ // AudioPolicyClientInterface implementation
+ audio_module_handle_t loadHwModule(const char* name) override {
+ if (!mAllowedModuleNames.empty() && !mAllowedModuleNames.count(name)) {
+ return AUDIO_MODULE_HANDLE_NONE;
+ }
+ return mNextModuleHandle++;
+ }
+
+ status_t openOutput(audio_module_handle_t module,
+ audio_io_handle_t *output,
+ audio_config_t * /*config*/,
+ const sp<DeviceDescriptorBase>& /*device*/,
+ uint32_t * /*latencyMs*/,
+ audio_output_flags_t /*flags*/) override {
+ if (module >= mNextModuleHandle) {
+ ALOGE("%s: Module handle %d has not been allocated yet (next is %d)",
+ __func__, module, mNextModuleHandle);
+ return BAD_VALUE;
+ }
+ *output = mNextIoHandle++;
+ return NO_ERROR;
+ }
+
+ audio_io_handle_t openDuplicateOutput(audio_io_handle_t /*output1*/,
+ audio_io_handle_t /*output2*/) override {
+ audio_io_handle_t id = mNextIoHandle++;
+ return id;
+ }
+
+ status_t openInput(audio_module_handle_t module,
+ audio_io_handle_t *input,
+ audio_config_t * /*config*/,
+ audio_devices_t * /*device*/,
+ const String8 & /*address*/,
+ audio_source_t /*source*/,
+ audio_input_flags_t /*flags*/) override {
+ if (module >= mNextModuleHandle) {
+ ALOGE("%s: Module handle %d has not been allocated yet (next is %d)",
+ __func__, module, mNextModuleHandle);
+ return BAD_VALUE;
+ }
+ *input = mNextIoHandle++;
+ return NO_ERROR;
+ }
+
+ status_t createAudioPatch(const struct audio_patch *patch,
+ audio_patch_handle_t *handle,
+ int /*delayMs*/) override {
+ *handle = mNextPatchHandle++;
+ mActivePatches.insert(std::make_pair(*handle, *patch));
+ return NO_ERROR;
+ }
+
+ status_t releaseAudioPatch(audio_patch_handle_t handle,
+ int /*delayMs*/) override {
+ if (mActivePatches.erase(handle) != 1) {
+ if (handle >= mNextPatchHandle) {
+ ALOGE("%s: Patch handle %d has not been allocated yet (next is %d)",
+ __func__, handle, mNextPatchHandle);
+ } else {
+ ALOGE("%s: Attempt to release patch %d twice", __func__, handle);
+ }
+ return BAD_VALUE;
+ }
+ return NO_ERROR;
+ }
+
+ // Helper methods for tests
+ size_t getActivePatchesCount() const { return mActivePatches.size(); }
+
+ const struct audio_patch *getLastAddedPatch() const {
+ if (mActivePatches.empty()) {
+ return nullptr;
+ }
+ auto it = --mActivePatches.end();
+ return &it->second;
+ };
+
+ audio_module_handle_t peekNextModuleHandle() const { return mNextModuleHandle; }
+
+ void swapAllowedModuleNames(std::set<std::string>&& names = {}) {
+ mAllowedModuleNames.swap(names);
+ }
+
+private:
+ audio_module_handle_t mNextModuleHandle = AUDIO_MODULE_HANDLE_NONE + 1;
+ audio_io_handle_t mNextIoHandle = AUDIO_IO_HANDLE_NONE + 1;
+ audio_patch_handle_t mNextPatchHandle = AUDIO_PATCH_HANDLE_NONE + 1;
+ std::map<audio_patch_handle_t, struct audio_patch> mActivePatches;
+ std::set<std::string> mAllowedModuleNames;
+};
+
+} // namespace android
diff --git a/services/audiopolicy/tests/AudioPolicyTestClient.h b/services/audiopolicy/tests/AudioPolicyTestClient.h
index e4c64e5..c628e70 100644
--- a/services/audiopolicy/tests/AudioPolicyTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyTestClient.h
@@ -31,8 +31,7 @@
status_t openOutput(audio_module_handle_t /*module*/,
audio_io_handle_t* /*output*/,
audio_config_t* /*config*/,
- audio_devices_t* /*devices*/,
- const String8& /*address*/,
+ const sp<DeviceDescriptorBase>& /*device*/,
uint32_t* /*latencyMs*/,
audio_output_flags_t /*flags*/) override { return NO_INIT; }
audio_io_handle_t openDuplicateOutput(audio_io_handle_t /*output1*/,
@@ -87,6 +86,7 @@
void setEffectSuspended(int effectId __unused,
audio_session_t sessionId __unused,
bool suspended __unused) {}
+ void setSoundTriggerCaptureState(bool active __unused) override {};
};
} // namespace android
diff --git a/services/audiopolicy/tests/AudioPolicyTestManager.h b/services/audiopolicy/tests/AudioPolicyTestManager.h
index fe543a6..922a538 100644
--- a/services/audiopolicy/tests/AudioPolicyTestManager.h
+++ b/services/audiopolicy/tests/AudioPolicyTestManager.h
@@ -24,7 +24,11 @@
explicit AudioPolicyTestManager(AudioPolicyClientInterface *clientInterface)
: AudioPolicyManager(clientInterface, true /*forTesting*/) { }
using AudioPolicyManager::getConfig;
+ using AudioPolicyManager::loadConfig;
using AudioPolicyManager::initialize;
+ using AudioPolicyManager::getOutputs;
+ using AudioPolicyManager::getAvailableOutputDevices;
+ using AudioPolicyManager::getAvailableInputDevices;
};
} // namespace android
diff --git a/services/audiopolicy/tests/audio_health_tests.cpp b/services/audiopolicy/tests/audio_health_tests.cpp
new file mode 100644
index 0000000..b5c67a1
--- /dev/null
+++ b/services/audiopolicy/tests/audio_health_tests.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "AudioPolicy_Boot_Test"
+
+#include <unordered_set>
+
+#include <gtest/gtest.h>
+
+#include <media/AudioSystem.h>
+#include <system/audio.h>
+#include <utils/Log.h>
+
+#include "AudioPolicyManagerTestClient.h"
+#include "AudioPolicyTestManager.h"
+
+using namespace android;
+
+TEST(AudioHealthTest, AttachedDeviceFound) {
+ unsigned int numPorts;
+ unsigned int generation1;
+ unsigned int generation;
+ struct audio_port *audioPorts = NULL;
+ int attempts = 10;
+ do {
+ if (attempts-- < 0) {
+ free(audioPorts);
+ GTEST_FAIL() << "Query audio ports time out";
+ }
+ numPorts = 0;
+ ASSERT_EQ(NO_ERROR, AudioSystem::listAudioPorts(
+ AUDIO_PORT_ROLE_NONE, AUDIO_PORT_TYPE_DEVICE, &numPorts, NULL, &generation1));
+ if (numPorts == 0) {
+ free(audioPorts);
+ GTEST_FAIL() << "Number of audio ports should not be zero";
+ }
+
+ audioPorts = (struct audio_port *)realloc(audioPorts, numPorts * sizeof(struct audio_port));
+ status_t status = AudioSystem::listAudioPorts(
+ AUDIO_PORT_ROLE_NONE, AUDIO_PORT_TYPE_DEVICE, &numPorts, audioPorts, &generation);
+ if (status != NO_ERROR) {
+ free(audioPorts);
+ GTEST_FAIL() << "Query audio ports failed";
+ }
+ } while (generation1 != generation);
+ std::unordered_set<audio_devices_t> attachedDevices;
+ for (int i = 0 ; i < numPorts; i++) {
+ attachedDevices.insert(audioPorts[i].ext.device.type);
+ }
+ free(audioPorts);
+
+ AudioPolicyManagerTestClient client;
+ AudioPolicyTestManager manager(&client);
+ manager.loadConfig();
+ ASSERT_NE("AudioPolicyConfig::setDefault", manager.getConfig().getSource());
+
+ for (auto desc : manager.getConfig().getInputDevices()) {
+ ASSERT_NE(attachedDevices.end(), attachedDevices.find(desc->type()));
+ }
+ for (auto desc : manager.getConfig().getOutputDevices()) {
+ ASSERT_NE(attachedDevices.end(), attachedDevices.find(desc->type()));
+ }
+}
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index de5670c..7d92f34 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -15,22 +15,38 @@
*/
#include <memory>
-#include <set>
+#include <string>
#include <sys/wait.h>
#include <unistd.h>
#include <gtest/gtest.h>
#define LOG_TAG "APM_Test"
-#include <log/log.h>
+#include <Serializer.h>
+#include <android-base/file.h>
+#include <media/AudioPolicy.h>
#include <media/PatchBuilder.h>
+#include <media/RecordingActivityTracker.h>
+#include <utils/Log.h>
+#include <utils/Vector.h>
+#include "AudioPolicyInterface.h"
+#include "AudioPolicyManagerTestClient.h"
#include "AudioPolicyTestClient.h"
#include "AudioPolicyTestManager.h"
using namespace android;
-TEST(AudioPolicyManagerTestInit, Failure) {
+TEST(AudioPolicyManagerTestInit, EngineFailure) {
+ AudioPolicyTestClient client;
+ AudioPolicyTestManager manager(&client);
+ manager.getConfig().setDefault();
+ manager.getConfig().setEngineLibraryNameSuffix("non-existent");
+ ASSERT_EQ(NO_INIT, manager.initialize());
+ ASSERT_EQ(NO_INIT, manager.initCheck());
+}
+
+TEST(AudioPolicyManagerTestInit, ClientFailure) {
AudioPolicyTestClient client;
AudioPolicyTestManager manager(&client);
manager.getConfig().setDefault();
@@ -41,77 +57,6 @@
}
-class AudioPolicyManagerTestClient : public AudioPolicyTestClient {
- public:
- // AudioPolicyClientInterface implementation
- audio_module_handle_t loadHwModule(const char* /*name*/) override {
- return mNextModuleHandle++;
- }
-
- status_t openOutput(audio_module_handle_t module,
- audio_io_handle_t* output,
- audio_config_t* /*config*/,
- audio_devices_t* /*devices*/,
- const String8& /*address*/,
- uint32_t* /*latencyMs*/,
- audio_output_flags_t /*flags*/) override {
- if (module >= mNextModuleHandle) {
- ALOGE("%s: Module handle %d has not been allocated yet (next is %d)",
- __func__, module, mNextModuleHandle);
- return BAD_VALUE;
- }
- *output = mNextIoHandle++;
- return NO_ERROR;
- }
-
- status_t openInput(audio_module_handle_t module,
- audio_io_handle_t* input,
- audio_config_t* /*config*/,
- audio_devices_t* /*device*/,
- const String8& /*address*/,
- audio_source_t /*source*/,
- audio_input_flags_t /*flags*/) override {
- if (module >= mNextModuleHandle) {
- ALOGE("%s: Module handle %d has not been allocated yet (next is %d)",
- __func__, module, mNextModuleHandle);
- return BAD_VALUE;
- }
- *input = mNextIoHandle++;
- return NO_ERROR;
- }
-
- status_t createAudioPatch(const struct audio_patch* /*patch*/,
- audio_patch_handle_t* handle,
- int /*delayMs*/) override {
- *handle = mNextPatchHandle++;
- mActivePatches.insert(*handle);
- return NO_ERROR;
- }
-
- status_t releaseAudioPatch(audio_patch_handle_t handle,
- int /*delayMs*/) override {
- if (mActivePatches.erase(handle) != 1) {
- if (handle >= mNextPatchHandle) {
- ALOGE("%s: Patch handle %d has not been allocated yet (next is %d)",
- __func__, handle, mNextPatchHandle);
- } else {
- ALOGE("%s: Attempt to release patch %d twice", __func__, handle);
- }
- return BAD_VALUE;
- }
- return NO_ERROR;
- }
-
- // Helper methods for tests
- size_t getActivePatchesCount() const { return mActivePatches.size(); }
-
- private:
- audio_module_handle_t mNextModuleHandle = AUDIO_MODULE_HANDLE_NONE + 1;
- audio_io_handle_t mNextIoHandle = AUDIO_IO_HANDLE_NONE + 1;
- audio_patch_handle_t mNextPatchHandle = AUDIO_PATCH_HANDLE_NONE + 1;
- std::set<audio_patch_handle_t> mActivePatches;
-};
-
class PatchCountCheck {
public:
explicit PatchCountCheck(AudioPolicyManagerTestClient *client)
@@ -134,18 +79,35 @@
protected:
void SetUp() override;
void TearDown() override;
- virtual void SetUpConfig(AudioPolicyConfig *config) { (void)config; }
+ virtual void SetUpManagerConfig();
void dumpToLog();
+ // When explicit routing is needed, selectedDeviceId needs to be set as the wanted port
+ // id. Otherwise, selectedDeviceId needs to be initialized as AUDIO_PORT_HANDLE_NONE.
void getOutputForAttr(
audio_port_handle_t *selectedDeviceId,
audio_format_t format,
int channelMask,
int sampleRate,
audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
+ audio_io_handle_t *output = nullptr,
+ audio_port_handle_t *portId = nullptr,
+ audio_attributes_t attr = {});
+ void getInputForAttr(
+ const audio_attributes_t &attr,
+ audio_unique_id_t riid,
+ audio_port_handle_t *selectedDeviceId,
+ audio_format_t format,
+ int channelMask,
+ int sampleRate,
+ audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE,
audio_port_handle_t *portId = nullptr);
PatchCountCheck snapshotPatchCount() { return PatchCountCheck(mClient.get()); }
+ void findDevicePort(audio_port_role_t role, audio_devices_t deviceType,
+ const std::string &address, audio_port &foundPort);
+ static audio_port_handle_t getDeviceIdFromPatch(const struct audio_patch* patch);
+
std::unique_ptr<AudioPolicyManagerTestClient> mClient;
std::unique_ptr<AudioPolicyTestManager> mManager;
};
@@ -153,8 +115,7 @@
void AudioPolicyManagerTest::SetUp() {
mClient.reset(new AudioPolicyManagerTestClient);
mManager.reset(new AudioPolicyTestManager(mClient.get()));
- mManager->getConfig().setDefault();
- SetUpConfig(&mManager->getConfig()); // Subclasses may want to customize the config.
+ SetUpManagerConfig(); // Subclasses may want to customize the config.
ASSERT_EQ(NO_ERROR, mManager->initialize());
ASSERT_EQ(NO_ERROR, mManager->initCheck());
}
@@ -164,6 +125,10 @@
mClient.reset();
}
+void AudioPolicyManagerTest::SetUpManagerConfig() {
+ mManager->getConfig().setDefault();
+}
+
void AudioPolicyManagerTest::dumpToLog() {
int pipefd[2];
ASSERT_NE(-1, pipe(pipefd));
@@ -200,22 +165,91 @@
int channelMask,
int sampleRate,
audio_output_flags_t flags,
- audio_port_handle_t *portId) {
- audio_attributes_t attr = {};
- audio_io_handle_t output = AUDIO_PORT_HANDLE_NONE;
+ audio_io_handle_t *output,
+ audio_port_handle_t *portId,
+ audio_attributes_t attr) {
+ audio_io_handle_t localOutput;
+ if (!output) output = &localOutput;
+ *output = AUDIO_IO_HANDLE_NONE;
audio_stream_type_t stream = AUDIO_STREAM_DEFAULT;
audio_config_t config = AUDIO_CONFIG_INITIALIZER;
config.sample_rate = sampleRate;
config.channel_mask = channelMask;
config.format = format;
- *selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
audio_port_handle_t localPortId;
if (!portId) portId = &localPortId;
*portId = AUDIO_PORT_HANDLE_NONE;
+ AudioPolicyInterface::output_type_t outputType;
ASSERT_EQ(OK, mManager->getOutputForAttr(
- &attr, &output, AUDIO_SESSION_NONE, &stream, 0 /*uid*/, &config, &flags,
- selectedDeviceId, portId, {}));
+ &attr, output, AUDIO_SESSION_NONE, &stream, 0 /*uid*/, &config, &flags,
+ selectedDeviceId, portId, {}, &outputType));
ASSERT_NE(AUDIO_PORT_HANDLE_NONE, *portId);
+ ASSERT_NE(AUDIO_IO_HANDLE_NONE, *output);
+}
+
+void AudioPolicyManagerTest::getInputForAttr(
+ const audio_attributes_t &attr,
+ audio_unique_id_t riid,
+ audio_port_handle_t *selectedDeviceId,
+ audio_format_t format,
+ int channelMask,
+ int sampleRate,
+ audio_input_flags_t flags,
+ audio_port_handle_t *portId) {
+ audio_io_handle_t input = AUDIO_PORT_HANDLE_NONE;
+ audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
+ config.sample_rate = sampleRate;
+ config.channel_mask = channelMask;
+ config.format = format;
+ audio_port_handle_t localPortId;
+ if (!portId) portId = &localPortId;
+ *portId = AUDIO_PORT_HANDLE_NONE;
+ AudioPolicyInterface::input_type_t inputType;
+ ASSERT_EQ(OK, mManager->getInputForAttr(
+ &attr, &input, riid, AUDIO_SESSION_NONE, 0 /*uid*/, &config, flags,
+ selectedDeviceId, &inputType, portId));
+ ASSERT_NE(AUDIO_PORT_HANDLE_NONE, *portId);
+}
+
+void AudioPolicyManagerTest::findDevicePort(audio_port_role_t role,
+ audio_devices_t deviceType, const std::string &address, audio_port &foundPort) {
+ uint32_t numPorts = 0;
+ uint32_t generation1;
+ status_t ret;
+
+ ret = mManager->listAudioPorts(role, AUDIO_PORT_TYPE_DEVICE, &numPorts, nullptr, &generation1);
+ ASSERT_EQ(NO_ERROR, ret);
+
+ uint32_t generation2;
+ struct audio_port ports[numPorts];
+ ret = mManager->listAudioPorts(role, AUDIO_PORT_TYPE_DEVICE, &numPorts, ports, &generation2);
+ ASSERT_EQ(NO_ERROR, ret);
+ ASSERT_EQ(generation1, generation2);
+
+ for (const auto &port : ports) {
+ if (port.role == role && port.ext.device.type == deviceType &&
+ (strncmp(port.ext.device.address, address.c_str(),
+ AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0)) {
+ foundPort = port;
+ return;
+ }
+ }
+ GTEST_FAIL() << "Device port with role " << role << " and address " << address << "not found";
+}
+
+audio_port_handle_t AudioPolicyManagerTest::getDeviceIdFromPatch(
+ const struct audio_patch* patch) {
+ // The logic here is the same as the one in AudioIoDescriptor.
+ // Note this function is aim to get routed device id for test.
+ // In that case, device to device patch is not expected here.
+ if (patch->num_sources != 0 && patch->num_sinks != 0) {
+ if (patch->sources[0].type == AUDIO_PORT_TYPE_MIX) {
+ return patch->sinks[0].id;
+ } else {
+ return patch->sources[0].id;
+ }
+ }
+ return AUDIO_PORT_HANDLE_NONE;
}
@@ -264,9 +298,9 @@
audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE;
uid_t uid = 42;
const PatchCountCheck patchCount = snapshotPatchCount();
- ASSERT_FALSE(mManager->getConfig().getAvailableInputDevices().isEmpty());
+ ASSERT_FALSE(mManager->getAvailableInputDevices().isEmpty());
PatchBuilder patchBuilder;
- patchBuilder.addSource(mManager->getConfig().getAvailableInputDevices()[0]).
+ patchBuilder.addSource(mManager->getAvailableInputDevices()[0]).
addSink(mManager->getConfig().getDefaultOutputDevice());
ASSERT_EQ(NO_ERROR, mManager->createAudioPatch(patchBuilder.patch(), &handle, uid));
ASSERT_NE(AUDIO_PATCH_HANDLE_NONE, handle);
@@ -277,15 +311,17 @@
class AudioPolicyManagerTestMsd : public AudioPolicyManagerTest {
protected:
- void SetUpConfig(AudioPolicyConfig *config) override;
+ void SetUpManagerConfig() override;
void TearDown() override;
sp<DeviceDescriptor> mMsdOutputDevice;
sp<DeviceDescriptor> mMsdInputDevice;
};
-void AudioPolicyManagerTestMsd::SetUpConfig(AudioPolicyConfig *config) {
+void AudioPolicyManagerTestMsd::SetUpManagerConfig() {
// TODO: Consider using Serializer to load part of the config from a string.
+ AudioPolicyManagerTest::SetUpManagerConfig();
+ AudioPolicyConfig& config = mManager->getConfig();
mMsdOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_BUS);
sp<AudioProfile> pcmOutputProfile = new AudioProfile(
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 48000);
@@ -298,22 +334,19 @@
sp<AudioProfile> pcmInputProfile = new AudioProfile(
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO, 44100);
mMsdInputDevice->addAudioProfile(pcmInputProfile);
- config->addAvailableDevice(mMsdOutputDevice);
- config->addAvailableDevice(mMsdInputDevice);
+ config.addDevice(mMsdOutputDevice);
+ config.addDevice(mMsdInputDevice);
sp<HwModule> msdModule = new HwModule(AUDIO_HARDWARE_MODULE_ID_MSD, 2 /*halVersionMajor*/);
- HwModuleCollection modules = config->getHwModules();
+ HwModuleCollection modules = config.getHwModules();
modules.add(msdModule);
- config->setHwModules(modules);
- mMsdOutputDevice->attach(msdModule);
- mMsdInputDevice->attach(msdModule);
+ config.setHwModules(modules);
- sp<OutputProfile> msdOutputProfile = new OutputProfile(String8("msd input"));
+ sp<OutputProfile> msdOutputProfile = new OutputProfile("msd input");
msdOutputProfile->addAudioProfile(pcmOutputProfile);
msdOutputProfile->addSupportedDevice(mMsdOutputDevice);
msdModule->addOutputProfile(msdOutputProfile);
- sp<OutputProfile> msdCompressedOutputProfile =
- new OutputProfile(String8("msd compressed input"));
+ sp<OutputProfile> msdCompressedOutputProfile = new OutputProfile("msd compressed input");
msdCompressedOutputProfile->addAudioProfile(ac3OutputProfile);
msdCompressedOutputProfile->setFlags(
AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD |
@@ -321,7 +354,7 @@
msdCompressedOutputProfile->addSupportedDevice(mMsdOutputDevice);
msdModule->addOutputProfile(msdCompressedOutputProfile);
- sp<InputProfile> msdInputProfile = new InputProfile(String8("msd output"));
+ sp<InputProfile> msdInputProfile = new InputProfile("msd output");
msdInputProfile->addAudioProfile(pcmInputProfile);
msdInputProfile->addSupportedDevice(mMsdInputDevice);
msdModule->addInputProfile(msdInputProfile);
@@ -330,12 +363,12 @@
// of streams that are not supported by MSD.
sp<AudioProfile> dtsOutputProfile = new AudioProfile(
AUDIO_FORMAT_DTS, AUDIO_CHANNEL_OUT_5POINT1, 48000);
- config->getDefaultOutputDevice()->addAudioProfile(dtsOutputProfile);
- sp<OutputProfile> primaryEncodedOutputProfile = new OutputProfile(String8("encoded"));
+ config.getDefaultOutputDevice()->addAudioProfile(dtsOutputProfile);
+ sp<OutputProfile> primaryEncodedOutputProfile = new OutputProfile("encoded");
primaryEncodedOutputProfile->addAudioProfile(dtsOutputProfile);
primaryEncodedOutputProfile->setFlags(AUDIO_OUTPUT_FLAG_DIRECT);
- primaryEncodedOutputProfile->addSupportedDevice(config->getDefaultOutputDevice());
- config->getHwModules().getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY)->
+ primaryEncodedOutputProfile->addSupportedDevice(config.getDefaultOutputDevice());
+ config.getHwModules().getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY)->
addOutputProfile(primaryEncodedOutputProfile);
}
@@ -363,7 +396,7 @@
TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrEncodedRoutesToMsd) {
const PatchCountCheck patchCount = snapshotPatchCount();
- audio_port_handle_t selectedDeviceId;
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
getOutputForAttr(&selectedDeviceId,
AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT);
ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
@@ -372,7 +405,7 @@
TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrPcmRoutesToMsd) {
const PatchCountCheck patchCount = snapshotPatchCount();
- audio_port_handle_t selectedDeviceId;
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
getOutputForAttr(&selectedDeviceId,
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 48000);
ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
@@ -381,7 +414,7 @@
TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrEncodedPlusPcmRoutesToMsd) {
const PatchCountCheck patchCount = snapshotPatchCount();
- audio_port_handle_t selectedDeviceId;
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
getOutputForAttr(&selectedDeviceId,
AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT);
ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
@@ -394,7 +427,7 @@
TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrUnsupportedFormatBypassesMsd) {
const PatchCountCheck patchCount = snapshotPatchCount();
- audio_port_handle_t selectedDeviceId;
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
getOutputForAttr(&selectedDeviceId,
AUDIO_FORMAT_DTS, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT);
ASSERT_NE(selectedDeviceId, mMsdOutputDevice->getId());
@@ -405,10 +438,11 @@
// Switch between formats that are supported and not supported by MSD.
{
const PatchCountCheck patchCount = snapshotPatchCount();
- audio_port_handle_t selectedDeviceId, portId;
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ audio_port_handle_t portId;
getOutputForAttr(&selectedDeviceId,
AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT,
- &portId);
+ nullptr /*output*/, &portId);
ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
ASSERT_EQ(1, patchCount.deltaFromSnapshot());
mManager->releaseOutput(portId);
@@ -416,10 +450,11 @@
}
{
const PatchCountCheck patchCount = snapshotPatchCount();
- audio_port_handle_t selectedDeviceId, portId;
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ audio_port_handle_t portId;
getOutputForAttr(&selectedDeviceId,
AUDIO_FORMAT_DTS, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT,
- &portId);
+ nullptr /*output*/, &portId);
ASSERT_NE(selectedDeviceId, mMsdOutputDevice->getId());
ASSERT_EQ(-1, patchCount.deltaFromSnapshot());
mManager->releaseOutput(portId);
@@ -427,10 +462,703 @@
}
{
const PatchCountCheck patchCount = snapshotPatchCount();
- audio_port_handle_t selectedDeviceId;
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
getOutputForAttr(&selectedDeviceId,
AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT);
ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
ASSERT_EQ(0, patchCount.deltaFromSnapshot());
}
}
+
+class AudioPolicyManagerTestWithConfigurationFile : public AudioPolicyManagerTest {
+protected:
+ void SetUpManagerConfig() override;
+ virtual std::string getConfigFile() { return sDefaultConfig; }
+
+ static const std::string sExecutableDir;
+ static const std::string sDefaultConfig;
+};
+
+const std::string AudioPolicyManagerTestWithConfigurationFile::sExecutableDir =
+ base::GetExecutableDirectory() + "/";
+
+const std::string AudioPolicyManagerTestWithConfigurationFile::sDefaultConfig =
+ sExecutableDir + "test_audio_policy_configuration.xml";
+
+void AudioPolicyManagerTestWithConfigurationFile::SetUpManagerConfig() {
+ status_t status = deserializeAudioPolicyFile(getConfigFile().c_str(), &mManager->getConfig());
+ ASSERT_EQ(NO_ERROR, status);
+}
+
+TEST_F(AudioPolicyManagerTestWithConfigurationFile, InitSuccess) {
+ // SetUp must finish with no assertions.
+}
+
+TEST_F(AudioPolicyManagerTestWithConfigurationFile, Dump) {
+ dumpToLog();
+}
+
+using PolicyMixTuple = std::tuple<audio_usage_t, audio_source_t, uint32_t>;
+
+class AudioPolicyManagerTestDynamicPolicy : public AudioPolicyManagerTestWithConfigurationFile {
+protected:
+ void TearDown() override;
+
+ status_t addPolicyMix(int mixType, int mixFlag, audio_devices_t deviceType,
+ std::string mixAddress, const audio_config_t& audioConfig,
+ const std::vector<PolicyMixTuple>& rules);
+ void clearPolicyMix();
+
+ Vector<AudioMix> mAudioMixes;
+ const std::string mMixAddress = "remote_submix_media";
+};
+
+void AudioPolicyManagerTestDynamicPolicy::TearDown() {
+ mManager->unregisterPolicyMixes(mAudioMixes);
+ AudioPolicyManagerTestWithConfigurationFile::TearDown();
+}
+
+status_t AudioPolicyManagerTestDynamicPolicy::addPolicyMix(int mixType, int mixFlag,
+ audio_devices_t deviceType, std::string mixAddress, const audio_config_t& audioConfig,
+ const std::vector<PolicyMixTuple>& rules) {
+ Vector<AudioMixMatchCriterion> myMixMatchCriteria;
+
+ for(const auto &rule: rules) {
+ myMixMatchCriteria.add(AudioMixMatchCriterion(
+ std::get<0>(rule), std::get<1>(rule), std::get<2>(rule)));
+ }
+
+ AudioMix myAudioMix(myMixMatchCriteria, mixType, audioConfig, mixFlag,
+ String8(mixAddress.c_str()), 0);
+ myAudioMix.mDeviceType = deviceType;
+ // Clear mAudioMix before add new one to make sure we don't add already exist mixes.
+ mAudioMixes.clear();
+ mAudioMixes.add(myAudioMix);
+
+ // As the policy mixes registration may fail at some case,
+ // caller need to check the returned status.
+ status_t ret = mManager->registerPolicyMixes(mAudioMixes);
+ return ret;
+}
+
+void AudioPolicyManagerTestDynamicPolicy::clearPolicyMix() {
+ if (mManager != nullptr) {
+ mManager->unregisterPolicyMixes(mAudioMixes);
+ }
+ mAudioMixes.clear();
+}
+
+TEST_F(AudioPolicyManagerTestDynamicPolicy, InitSuccess) {
+ // SetUp must finish with no assertions
+}
+
+TEST_F(AudioPolicyManagerTestDynamicPolicy, Dump) {
+ dumpToLog();
+}
+
+TEST_F(AudioPolicyManagerTestDynamicPolicy, RegisterPolicyMixes) {
+ status_t ret;
+ audio_config_t audioConfig = AUDIO_CONFIG_INITIALIZER;
+
+ // Only capture of playback is allowed in LOOP_BACK &RENDER mode
+ ret = addPolicyMix(MIX_TYPE_RECORDERS, MIX_ROUTE_FLAG_LOOP_BACK_AND_RENDER,
+ AUDIO_DEVICE_OUT_REMOTE_SUBMIX, "", audioConfig, std::vector<PolicyMixTuple>());
+ ASSERT_EQ(INVALID_OPERATION, ret);
+
+ // Fail due to the device is already connected.
+ clearPolicyMix();
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_LOOP_BACK,
+ AUDIO_DEVICE_OUT_REMOTE_SUBMIX, "", audioConfig, std::vector<PolicyMixTuple>());
+ ASSERT_EQ(INVALID_OPERATION, ret);
+
+ // The first time to register policy mixes with valid parameter should succeed.
+ clearPolicyMix();
+ audioConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+ audioConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+ audioConfig.sample_rate = 48000;
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_LOOP_BACK,
+ AUDIO_DEVICE_OUT_REMOTE_SUBMIX, mMixAddress, audioConfig,
+ std::vector<PolicyMixTuple>());
+ ASSERT_EQ(NO_ERROR, ret);
+ // Registering the same policy mixes should fail.
+ ret = mManager->registerPolicyMixes(mAudioMixes);
+ ASSERT_EQ(INVALID_OPERATION, ret);
+
+ // Registration should fail due to device not found.
+ // Note that earpiece is not present in the test configuration file.
+ // This will need to be updated if earpiece is added in the test configuration file.
+ clearPolicyMix();
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_EARPIECE, "", audioConfig, std::vector<PolicyMixTuple>());
+ ASSERT_EQ(INVALID_OPERATION, ret);
+
+ // Registration should fail due to output not found.
+ clearPolicyMix();
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_REMOTE_SUBMIX, "", audioConfig, std::vector<PolicyMixTuple>());
+ ASSERT_EQ(INVALID_OPERATION, ret);
+
+ // The first time to register valid policy mixes should succeed.
+ clearPolicyMix();
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_SPEAKER, "", audioConfig, std::vector<PolicyMixTuple>());
+ ASSERT_EQ(NO_ERROR, ret);
+ // Registering the same policy mixes should fail.
+ ret = mManager->registerPolicyMixes(mAudioMixes);
+ ASSERT_EQ(INVALID_OPERATION, ret);
+}
+
+TEST_F(AudioPolicyManagerTestDynamicPolicy, UnregisterPolicyMixes) {
+ status_t ret;
+ audio_config_t audioConfig = AUDIO_CONFIG_INITIALIZER;
+
+ audioConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+ audioConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+ audioConfig.sample_rate = 48000;
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_LOOP_BACK,
+ AUDIO_DEVICE_OUT_REMOTE_SUBMIX, mMixAddress, audioConfig,
+ std::vector<PolicyMixTuple>());
+ ASSERT_EQ(NO_ERROR, ret);
+
+ // After successfully registering policy mixes, it should be able to unregister.
+ ret = mManager->unregisterPolicyMixes(mAudioMixes);
+ ASSERT_EQ(NO_ERROR, ret);
+
+ // After unregistering policy mixes successfully, it should fail unregistering
+ // the same policy mixes as they are not registered.
+ ret = mManager->unregisterPolicyMixes(mAudioMixes);
+ ASSERT_EQ(INVALID_OPERATION, ret);
+}
+
+class AudioPolicyManagerTestDPNoRemoteSubmixModule : public AudioPolicyManagerTestDynamicPolicy {
+protected:
+ std::string getConfigFile() override { return sPrimaryOnlyConfig; }
+
+ static const std::string sPrimaryOnlyConfig;
+};
+
+const std::string AudioPolicyManagerTestDPNoRemoteSubmixModule::sPrimaryOnlyConfig =
+ sExecutableDir + "test_audio_policy_primary_only_configuration.xml";
+
+TEST_F(AudioPolicyManagerTestDPNoRemoteSubmixModule, InitSuccess) {
+ // SetUp must finish with no assertions.
+}
+
+TEST_F(AudioPolicyManagerTestDPNoRemoteSubmixModule, Dump) {
+ dumpToLog();
+}
+
+TEST_F(AudioPolicyManagerTestDPNoRemoteSubmixModule, RegistrationFailure) {
+ // Registration/Unregistration should fail due to module for remote submix not found.
+ status_t ret;
+ audio_config_t audioConfig = AUDIO_CONFIG_INITIALIZER;
+ audioConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+ audioConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+ audioConfig.sample_rate = 48000;
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_LOOP_BACK,
+ AUDIO_DEVICE_OUT_REMOTE_SUBMIX, "", audioConfig, std::vector<PolicyMixTuple>());
+ ASSERT_EQ(INVALID_OPERATION, ret);
+
+ ret = mManager->unregisterPolicyMixes(mAudioMixes);
+ ASSERT_EQ(INVALID_OPERATION, ret);
+}
+
+class AudioPolicyManagerTestDPPlaybackReRouting : public AudioPolicyManagerTestDynamicPolicy,
+ public testing::WithParamInterface<audio_attributes_t> {
+protected:
+ void SetUp() override;
+ void TearDown() override;
+
+ std::unique_ptr<RecordingActivityTracker> mTracker;
+
+ std::vector<PolicyMixTuple> mUsageRules = {
+ {AUDIO_USAGE_MEDIA, AUDIO_SOURCE_DEFAULT, RULE_MATCH_ATTRIBUTE_USAGE},
+ {AUDIO_USAGE_ALARM, AUDIO_SOURCE_DEFAULT, RULE_MATCH_ATTRIBUTE_USAGE}
+ };
+
+ struct audio_port mInjectionPort;
+ audio_port_handle_t mPortId = AUDIO_PORT_HANDLE_NONE;
+};
+
+void AudioPolicyManagerTestDPPlaybackReRouting::SetUp() {
+ AudioPolicyManagerTestDynamicPolicy::SetUp();
+
+ mTracker.reset(new RecordingActivityTracker());
+
+ audio_config_t audioConfig = AUDIO_CONFIG_INITIALIZER;
+ audioConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+ audioConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+ audioConfig.sample_rate = 48000;
+ status_t ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_LOOP_BACK,
+ AUDIO_DEVICE_OUT_REMOTE_SUBMIX, mMixAddress, audioConfig, mUsageRules);
+ ASSERT_EQ(NO_ERROR, ret);
+
+ struct audio_port extractionPort;
+ findDevicePort(AUDIO_PORT_ROLE_SOURCE, AUDIO_DEVICE_IN_REMOTE_SUBMIX,
+ mMixAddress, extractionPort);
+
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ audio_source_t source = AUDIO_SOURCE_REMOTE_SUBMIX;
+ audio_attributes_t attr = {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, source, 0, ""};
+ std::string tags = "addr=" + mMixAddress;
+ strncpy(attr.tags, tags.c_str(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
+ getInputForAttr(attr, mTracker->getRiid(), &selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT,
+ AUDIO_CHANNEL_IN_STEREO, 48000 /*sampleRate*/, AUDIO_INPUT_FLAG_NONE, &mPortId);
+ ASSERT_EQ(NO_ERROR, mManager->startInput(mPortId));
+ ASSERT_EQ(extractionPort.id, selectedDeviceId);
+
+ findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+ mMixAddress, mInjectionPort);
+}
+
+void AudioPolicyManagerTestDPPlaybackReRouting::TearDown() {
+ mManager->stopInput(mPortId);
+ AudioPolicyManagerTestDynamicPolicy::TearDown();
+}
+
+TEST_F(AudioPolicyManagerTestDPPlaybackReRouting, InitSuccess) {
+ // SetUp must finish with no assertions
+}
+
+TEST_F(AudioPolicyManagerTestDPPlaybackReRouting, Dump) {
+ dumpToLog();
+}
+
+TEST_P(AudioPolicyManagerTestDPPlaybackReRouting, PlaybackReRouting) {
+ const audio_attributes_t attr = GetParam();
+ const audio_usage_t usage = attr.usage;
+
+ audio_port_handle_t playbackRoutedPortId = AUDIO_PORT_HANDLE_NONE;
+ getOutputForAttr(&playbackRoutedPortId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+ 48000 /*sampleRate*/, AUDIO_OUTPUT_FLAG_NONE,
+ nullptr /*output*/, nullptr /*portId*/, attr);
+ if (std::find_if(begin(mUsageRules), end(mUsageRules), [&usage](const auto &usageRule) {
+ return (std::get<0>(usageRule) == usage) &&
+ (std::get<2>(usageRule) == RULE_MATCH_ATTRIBUTE_USAGE);}) != end(mUsageRules) ||
+ (strncmp(attr.tags, "addr=", strlen("addr=")) == 0 &&
+ strncmp(attr.tags + strlen("addr="), mMixAddress.c_str(),
+ AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0)) {
+ EXPECT_EQ(mInjectionPort.id, playbackRoutedPortId);
+ } else {
+ EXPECT_NE(mInjectionPort.id, playbackRoutedPortId);
+ }
+}
+
+INSTANTIATE_TEST_CASE_P(
+ PlaybackReroutingUsageMatch,
+ AudioPolicyManagerTestDPPlaybackReRouting,
+ testing::Values(
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_MEDIA,
+ AUDIO_SOURCE_DEFAULT, 0, ""},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_ALARM,
+ AUDIO_SOURCE_DEFAULT, 0, ""}
+ )
+ );
+
+INSTANTIATE_TEST_CASE_P(
+ PlaybackReroutingAddressPriorityMatch,
+ AudioPolicyManagerTestDPPlaybackReRouting,
+ testing::Values(
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_MEDIA,
+ AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_VOICE_COMMUNICATION,
+ AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+ AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING,
+ AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_ALARM,
+ AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_NOTIFICATION,
+ AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+ AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE,
+ AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+ AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
+ AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+ AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT,
+ AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+ AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED,
+ AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_NOTIFICATION_EVENT,
+ AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+ AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY,
+ AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+ AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+ AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+ AUDIO_USAGE_ASSISTANCE_SONIFICATION,
+ AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_GAME,
+ AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_VIRTUAL_SOURCE,
+ AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_ASSISTANT,
+ AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_SPEECH, AUDIO_USAGE_ASSISTANT,
+ AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"}
+ )
+ );
+
+INSTANTIATE_TEST_CASE_P(
+ PlaybackReroutingUnHandledUsages,
+ AudioPolicyManagerTestDPPlaybackReRouting,
+ testing::Values(
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_VOICE_COMMUNICATION,
+ AUDIO_SOURCE_DEFAULT, 0, ""},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+ AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING,
+ AUDIO_SOURCE_DEFAULT, 0, ""},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_NOTIFICATION,
+ AUDIO_SOURCE_DEFAULT, 0, ""},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+ AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE,
+ AUDIO_SOURCE_DEFAULT, 0, ""},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+ AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
+ AUDIO_SOURCE_DEFAULT, 0, ""},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+ AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT,
+ AUDIO_SOURCE_DEFAULT, 0, ""},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+ AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED,
+ AUDIO_SOURCE_DEFAULT, 0, ""},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_NOTIFICATION_EVENT,
+ AUDIO_SOURCE_DEFAULT, 0, ""},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+ AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY,
+ AUDIO_SOURCE_DEFAULT, 0, ""},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+ AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+ AUDIO_SOURCE_DEFAULT, 0, ""},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+ AUDIO_USAGE_ASSISTANCE_SONIFICATION,
+ AUDIO_SOURCE_DEFAULT, 0, ""},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_GAME,
+ AUDIO_SOURCE_DEFAULT, 0, ""},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_ASSISTANT,
+ AUDIO_SOURCE_DEFAULT, 0, ""},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_SPEECH, AUDIO_USAGE_ASSISTANT,
+ AUDIO_SOURCE_DEFAULT, 0, ""}
+ )
+ );
+
+class AudioPolicyManagerTestDPMixRecordInjection : public AudioPolicyManagerTestDynamicPolicy,
+ public testing::WithParamInterface<audio_attributes_t> {
+protected:
+ void SetUp() override;
+ void TearDown() override;
+
+ std::unique_ptr<RecordingActivityTracker> mTracker;
+
+ std::vector<PolicyMixTuple> mSourceRules = {
+ {AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_CAMCORDER, RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET},
+ {AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_MIC, RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET},
+ {AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_VOICE_COMMUNICATION, RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET}
+ };
+
+ struct audio_port mExtractionPort;
+ audio_port_handle_t mPortId = AUDIO_PORT_HANDLE_NONE;
+};
+
+void AudioPolicyManagerTestDPMixRecordInjection::SetUp() {
+ AudioPolicyManagerTestDynamicPolicy::SetUp();
+
+ mTracker.reset(new RecordingActivityTracker());
+
+ audio_config_t audioConfig = AUDIO_CONFIG_INITIALIZER;
+ audioConfig.channel_mask = AUDIO_CHANNEL_IN_STEREO;
+ audioConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+ audioConfig.sample_rate = 48000;
+ status_t ret = addPolicyMix(MIX_TYPE_RECORDERS, MIX_ROUTE_FLAG_LOOP_BACK,
+ AUDIO_DEVICE_IN_REMOTE_SUBMIX, mMixAddress, audioConfig, mSourceRules);
+ ASSERT_EQ(NO_ERROR, ret);
+
+ struct audio_port injectionPort;
+ findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+ mMixAddress, injectionPort);
+
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ audio_usage_t usage = AUDIO_USAGE_VIRTUAL_SOURCE;
+ audio_attributes_t attr = {AUDIO_CONTENT_TYPE_UNKNOWN, usage, AUDIO_SOURCE_DEFAULT, 0, ""};
+ std::string tags = std::string("addr=") + mMixAddress;
+ strncpy(attr.tags, tags.c_str(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
+ getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+ 48000 /*sampleRate*/, AUDIO_OUTPUT_FLAG_NONE, nullptr /*output*/, &mPortId, attr);
+ ASSERT_EQ(NO_ERROR, mManager->startOutput(mPortId));
+ ASSERT_EQ(injectionPort.id, getDeviceIdFromPatch(mClient->getLastAddedPatch()));
+
+ findDevicePort(AUDIO_PORT_ROLE_SOURCE, AUDIO_DEVICE_IN_REMOTE_SUBMIX,
+ mMixAddress, mExtractionPort);
+}
+
+void AudioPolicyManagerTestDPMixRecordInjection::TearDown() {
+ mManager->stopOutput(mPortId);
+ AudioPolicyManagerTestDynamicPolicy::TearDown();
+}
+
+TEST_F(AudioPolicyManagerTestDPMixRecordInjection, InitSuccess) {
+ // SetUp mush finish with no assertions.
+}
+
+TEST_F(AudioPolicyManagerTestDPMixRecordInjection, Dump) {
+ dumpToLog();
+}
+
+TEST_P(AudioPolicyManagerTestDPMixRecordInjection, RecordingInjection) {
+ const audio_attributes_t attr = GetParam();
+ const audio_source_t source = attr.source;
+
+ audio_port_handle_t captureRoutedPortId = AUDIO_PORT_HANDLE_NONE;
+ audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
+ getInputForAttr(attr, mTracker->getRiid(), &captureRoutedPortId, AUDIO_FORMAT_PCM_16_BIT,
+ AUDIO_CHANNEL_IN_STEREO, 48000 /*sampleRate*/, AUDIO_INPUT_FLAG_NONE, &portId);
+ if (std::find_if(begin(mSourceRules), end(mSourceRules), [&source](const auto &sourceRule) {
+ return (std::get<1>(sourceRule) == source) &&
+ (std::get<2>(sourceRule) == RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET);})
+ != end(mSourceRules)) {
+ EXPECT_EQ(mExtractionPort.id, captureRoutedPortId);
+ } else {
+ EXPECT_NE(mExtractionPort.id, captureRoutedPortId);
+ }
+}
+
+// No address priority rule for remote recording, address is a "don't care"
+INSTANTIATE_TEST_CASE_P(
+ RecordInjectionSourceMatch,
+ AudioPolicyManagerTestDPMixRecordInjection,
+ testing::Values(
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+ AUDIO_SOURCE_CAMCORDER, 0, ""},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+ AUDIO_SOURCE_CAMCORDER, 0, "addr=remote_submix_media"},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+ AUDIO_SOURCE_MIC, 0, "addr=remote_submix_media"},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+ AUDIO_SOURCE_MIC, 0, ""},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+ AUDIO_SOURCE_VOICE_COMMUNICATION, 0, ""},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+ AUDIO_SOURCE_VOICE_COMMUNICATION, 0,
+ "addr=remote_submix_media"}
+ )
+ );
+
+// No address priority rule for remote recording
+INSTANTIATE_TEST_CASE_P(
+ RecordInjectionSourceNotMatch,
+ AudioPolicyManagerTestDPMixRecordInjection,
+ testing::Values(
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+ AUDIO_SOURCE_VOICE_RECOGNITION, 0, ""},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+ AUDIO_SOURCE_HOTWORD, 0, ""},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+ AUDIO_SOURCE_VOICE_RECOGNITION, 0,
+ "addr=remote_submix_media"},
+ (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+ AUDIO_SOURCE_HOTWORD, 0, "addr=remote_submix_media"}
+ )
+ );
+
+using DeviceConnectionTestParams =
+ std::tuple<audio_devices_t /*type*/, std::string /*name*/, std::string /*address*/>;
+
+class AudioPolicyManagerTestDeviceConnection : public AudioPolicyManagerTestWithConfigurationFile,
+ public testing::WithParamInterface<DeviceConnectionTestParams> {
+};
+
+TEST_F(AudioPolicyManagerTestDeviceConnection, InitSuccess) {
+ // SetUp must finish with no assertions.
+}
+
+TEST_F(AudioPolicyManagerTestDeviceConnection, Dump) {
+ dumpToLog();
+}
+
+TEST_P(AudioPolicyManagerTestDeviceConnection, SetDeviceConnectionState) {
+ const audio_devices_t type = std::get<0>(GetParam());
+ const std::string name = std::get<1>(GetParam());
+ const std::string address = std::get<2>(GetParam());
+
+ if (type == AUDIO_DEVICE_OUT_HDMI) {
+ // Set device connection state failed due to no device descriptor found
+ // For HDMI case, it is easier to simulate device descriptor not found error
+ // by using a undeclared encoded format.
+ ASSERT_EQ(INVALID_OPERATION, mManager->setDeviceConnectionState(
+ type, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ address.c_str(), name.c_str(), AUDIO_FORMAT_MAT_2_1));
+ }
+ // Connect with valid parameters should succeed
+ ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(
+ type, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ address.c_str(), name.c_str(), AUDIO_FORMAT_DEFAULT));
+ // Try to connect with the same device again should fail
+ ASSERT_EQ(INVALID_OPERATION, mManager->setDeviceConnectionState(
+ type, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ address.c_str(), name.c_str(), AUDIO_FORMAT_DEFAULT));
+ // Disconnect the connected device should succeed
+ ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(
+ type, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ address.c_str(), name.c_str(), AUDIO_FORMAT_DEFAULT));
+ // Disconnect device that is not connected should fail
+ ASSERT_EQ(INVALID_OPERATION, mManager->setDeviceConnectionState(
+ type, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ address.c_str(), name.c_str(), AUDIO_FORMAT_DEFAULT));
+ // Try to set device connection state with a invalid connection state should fail
+ ASSERT_EQ(BAD_VALUE, mManager->setDeviceConnectionState(
+ type, AUDIO_POLICY_DEVICE_STATE_CNT,
+ "", "", AUDIO_FORMAT_DEFAULT));
+}
+
+TEST_P(AudioPolicyManagerTestDeviceConnection, ExplicitlyRoutingAfterConnection) {
+ const audio_devices_t type = std::get<0>(GetParam());
+ const std::string name = std::get<1>(GetParam());
+ const std::string address = std::get<2>(GetParam());
+
+ // Connect device to do explicitly routing test
+ ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(
+ type, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ address.c_str(), name.c_str(), AUDIO_FORMAT_DEFAULT));
+
+ audio_port devicePort;
+ const audio_port_role_t role = audio_is_output_device(type)
+ ? AUDIO_PORT_ROLE_SINK : AUDIO_PORT_ROLE_SOURCE;
+ findDevicePort(role, type, address, devicePort);
+
+ audio_port_handle_t routedPortId = devicePort.id;
+ // Try start input or output according to the device type
+ if (audio_is_output_devices(type)) {
+ getOutputForAttr(&routedPortId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+ 48000 /*sampleRate*/, AUDIO_OUTPUT_FLAG_NONE);
+ } else if (audio_is_input_device(type)) {
+ RecordingActivityTracker tracker;
+ getInputForAttr({}, tracker.getRiid(), &routedPortId, AUDIO_FORMAT_PCM_16_BIT,
+ AUDIO_CHANNEL_IN_STEREO, 48000 /*sampleRate*/, AUDIO_INPUT_FLAG_NONE);
+ }
+ ASSERT_EQ(devicePort.id, routedPortId);
+
+ ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(
+ type, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ address.c_str(), name.c_str(), AUDIO_FORMAT_DEFAULT));
+}
+
+INSTANTIATE_TEST_CASE_P(
+ DeviceConnectionState,
+ AudioPolicyManagerTestDeviceConnection,
+ testing::Values(
+ DeviceConnectionTestParams({AUDIO_DEVICE_IN_HDMI, "test_in_hdmi",
+ "audio_policy_test_in_hdmi"}),
+ DeviceConnectionTestParams({AUDIO_DEVICE_OUT_HDMI, "test_out_hdmi",
+ "audio_policy_test_out_hdmi"}),
+ DeviceConnectionTestParams({AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, "bt_hfp_in",
+ "hfp_client_in"}),
+ DeviceConnectionTestParams({AUDIO_DEVICE_OUT_BLUETOOTH_SCO, "bt_hfp_out",
+ "hfp_client_out"})
+ )
+ );
+
+class AudioPolicyManagerTVTest : public AudioPolicyManagerTestWithConfigurationFile {
+protected:
+ std::string getConfigFile() override { return sTvConfig; }
+ void testHDMIPortSelection(audio_output_flags_t flags, const char* expectedMixPortName);
+
+ static const std::string sTvConfig;
+};
+
+const std::string AudioPolicyManagerTVTest::sTvConfig =
+ AudioPolicyManagerTVTest::sExecutableDir + "test_tv_apm_configuration.xml";
+
+// SwAudioOutputDescriptor doesn't populate flags so check against the port name.
+void AudioPolicyManagerTVTest::testHDMIPortSelection(
+ audio_output_flags_t flags, const char* expectedMixPortName) {
+ ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(
+ AUDIO_DEVICE_OUT_AUX_DIGITAL, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ "" /*address*/, "" /*name*/, AUDIO_FORMAT_DEFAULT));
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ audio_io_handle_t output;
+ audio_port_handle_t portId;
+ getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 48000,
+ flags, &output, &portId);
+ sp<SwAudioOutputDescriptor> outDesc = mManager->getOutputs().valueFor(output);
+ ASSERT_NE(nullptr, outDesc.get());
+ audio_port port = {};
+ outDesc->toAudioPort(&port);
+ mManager->releaseOutput(portId);
+ ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(
+ AUDIO_DEVICE_OUT_AUX_DIGITAL, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ "" /*address*/, "" /*name*/, AUDIO_FORMAT_DEFAULT));
+ ASSERT_EQ(AUDIO_PORT_TYPE_MIX, port.type);
+ ASSERT_EQ(AUDIO_PORT_ROLE_SOURCE, port.role);
+ ASSERT_STREQ(expectedMixPortName, port.name);
+}
+
+TEST_F(AudioPolicyManagerTVTest, InitSuccess) {
+ // SetUp must finish with no assertions.
+}
+
+TEST_F(AudioPolicyManagerTVTest, Dump) {
+ dumpToLog();
+}
+
+TEST_F(AudioPolicyManagerTVTest, MatchNoFlags) {
+ testHDMIPortSelection(AUDIO_OUTPUT_FLAG_NONE, "primary output");
+}
+
+TEST_F(AudioPolicyManagerTVTest, MatchOutputDirectNoHwAvSync) {
+ // b/140447125: The selected port must not have HW AV Sync flag (see the config file).
+ testHDMIPortSelection(AUDIO_OUTPUT_FLAG_DIRECT, "direct");
+}
+
+TEST_F(AudioPolicyManagerTVTest, MatchOutputDirectHwAvSync) {
+ testHDMIPortSelection(static_cast<audio_output_flags_t>(
+ AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_HW_AV_SYNC),
+ "tunnel");
+}
+
+TEST_F(AudioPolicyManagerTVTest, MatchOutputDirectMMapNoIrq) {
+ testHDMIPortSelection(static_cast<audio_output_flags_t>(
+ AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_MMAP_NOIRQ),
+ "low latency");
+}
+
+class AudioPolicyManagerDynamicHwModulesTest : public AudioPolicyManagerTestWithConfigurationFile {
+protected:
+ void SetUpManagerConfig() override;
+};
+
+void AudioPolicyManagerDynamicHwModulesTest::SetUpManagerConfig() {
+ AudioPolicyManagerTestWithConfigurationFile::SetUpManagerConfig();
+ // Only allow successful opening of "primary" hw module during APM initialization.
+ mClient->swapAllowedModuleNames({"primary"});
+}
+
+TEST_F(AudioPolicyManagerDynamicHwModulesTest, InitSuccess) {
+ // SetUp must finish with no assertions.
+}
+
+TEST_F(AudioPolicyManagerDynamicHwModulesTest, DynamicAddition) {
+ const auto handleBefore = mClient->peekNextModuleHandle();
+ mManager->onNewAudioModulesAvailable();
+ ASSERT_EQ(handleBefore, mClient->peekNextModuleHandle());
+ // Reset module loading restrictions.
+ mClient->swapAllowedModuleNames();
+ mManager->onNewAudioModulesAvailable();
+ const auto handleAfter = mClient->peekNextModuleHandle();
+ ASSERT_GT(handleAfter, handleBefore);
+ mManager->onNewAudioModulesAvailable();
+ ASSERT_EQ(handleAfter, mClient->peekNextModuleHandle());
+}
+
+TEST_F(AudioPolicyManagerDynamicHwModulesTest, AddedDeviceAvailable) {
+ ASSERT_EQ(AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, mManager->getDeviceConnectionState(
+ AUDIO_DEVICE_IN_REMOTE_SUBMIX, "0"));
+ mClient->swapAllowedModuleNames({"primary", "r_submix"});
+ mManager->onNewAudioModulesAvailable();
+ ASSERT_EQ(AUDIO_POLICY_DEVICE_STATE_AVAILABLE, mManager->getDeviceConnectionState(
+ AUDIO_DEVICE_IN_REMOTE_SUBMIX, "0"));
+}
diff --git a/services/audiopolicy/tests/resources/Android.bp b/services/audiopolicy/tests/resources/Android.bp
new file mode 100644
index 0000000..d9476d9
--- /dev/null
+++ b/services/audiopolicy/tests/resources/Android.bp
@@ -0,0 +1,8 @@
+filegroup {
+ name: "audiopolicytest_configuration_files",
+ srcs: [
+ "test_audio_policy_configuration.xml",
+ "test_audio_policy_primary_only_configuration.xml",
+ "test_tv_apm_configuration.xml",
+ ],
+}
diff --git a/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml b/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
new file mode 100644
index 0000000..87f0ab9
--- /dev/null
+++ b/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- 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.
+-->
+
+<audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <globalConfiguration speaker_drc_enabled="true"/>
+
+ <modules>
+ <!-- Primary module -->
+ <module name="primary" halVersion="2.0">
+ <attachedDevices>
+ <item>Speaker</item>
+ <item>Built-In Mic</item>
+ </attachedDevices>
+ <defaultOutputDevice>Speaker</defaultOutputDevice>
+ <mixPorts>
+ <mixPort name="primary output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="primary input" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000"
+ channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+ </mixPort>
+ <mixPort name="mixport_bt_hfp_output" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="mixport_bt_hfp_input" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="8000,11025,16000,44100,48000"
+ channelMasks="AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_MONO"/>
+ </mixPort>
+ </mixPorts>
+ <devicePorts>
+ <devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="sink">
+ </devicePort>
+ <devicePort tagName="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source">
+ </devicePort>
+ <devicePort tagName="Hdmi" type="AUDIO_DEVICE_OUT_HDMI" role="sink">
+ </devicePort>
+ <devicePort tagName="Hdmi-In Mic" type="AUDIO_DEVICE_IN_HDMI" role="source">
+ </devicePort>
+ <devicePort tagName="BT SCO" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO"
+ role="sink" address="hfp_client_out">
+ </devicePort>
+ <devicePort tagName="BT SCO Headset Mic" type="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET"
+ role="source" address="hfp_client_in">
+ </devicePort>
+ </devicePorts>
+ <routes>
+ <route type="mix" sink="Speaker"
+ sources="primary output"/>
+ <route type="mix" sink="primary input"
+ sources="Built-In Mic,Hdmi-In Mic"/>
+ <route type="mix" sink="Hdmi"
+ sources="primary output"/>
+ <route type="mix" sink="BT SCO"
+ sources="mixport_bt_hfp_output"/>
+ <route type="mix" sink="mixport_bt_hfp_input"
+ sources="BT SCO Headset Mic"/>
+ </routes>
+ </module>
+
+ <!-- Remote Submix module -->
+ <module name="r_submix" halVersion="2.0">
+ <attachedDevices>
+ <item>Remote Submix In</item>
+ </attachedDevices>
+ <mixPorts>
+ <mixPort name="r_submix output" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="r_submix input" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+ </mixPort>
+ </mixPorts>
+ <devicePorts>
+ <devicePort tagName="Remote Submix Out" type="AUDIO_DEVICE_OUT_REMOTE_SUBMIX" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ <devicePort tagName="Remote Submix In" type="AUDIO_DEVICE_IN_REMOTE_SUBMIX" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+ </devicePort>
+ </devicePorts>
+ <routes>
+ <route type="mix" sink="Remote Submix Out"
+ sources="r_submix output"/>
+ <route type="mix" sink="r_submix input"
+ sources="Remote Submix In"/>
+ </routes>
+ </module>
+ </modules>
+</audioPolicyConfiguration>
diff --git a/services/audiopolicy/tests/resources/test_audio_policy_primary_only_configuration.xml b/services/audiopolicy/tests/resources/test_audio_policy_primary_only_configuration.xml
new file mode 100644
index 0000000..edc0adb
--- /dev/null
+++ b/services/audiopolicy/tests/resources/test_audio_policy_primary_only_configuration.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- 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.
+-->
+
+<audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <globalConfiguration speaker_drc_enabled="true"/>
+
+ <modules>
+ <!-- Primary module -->
+ <module name="primary" halVersion="2.0">
+ <attachedDevices>
+ <item>Speaker</item>
+ <item>Built-In Mic</item>
+ </attachedDevices>
+ <defaultOutputDevice>Speaker</defaultOutputDevice>
+ <mixPorts>
+ <mixPort name="primary output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="primary input" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000"
+ channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+ </mixPort>
+ </mixPorts>
+ <devicePorts>
+ <devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="sink">
+ </devicePort>
+ <devicePort tagName="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source">
+ </devicePort>
+ </devicePorts>
+ <routes>
+ <route type="mix" sink="Speaker"
+ sources="primary output"/>
+ <route type="mix" sink="primary input"
+ sources="Built-In Mic"/>
+ </routes>
+ </module>
+ </modules>
+</audioPolicyConfiguration>
diff --git a/services/audiopolicy/tests/resources/test_tv_apm_configuration.xml b/services/audiopolicy/tests/resources/test_tv_apm_configuration.xml
new file mode 100644
index 0000000..f1638f3
--- /dev/null
+++ b/services/audiopolicy/tests/resources/test_tv_apm_configuration.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- 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.
+-->
+
+<audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <globalConfiguration speaker_drc_enabled="false"/>
+ <modules>
+ <module name="primary" halVersion="2.0">
+ <attachedDevices>
+ <item>Speaker</item>
+ </attachedDevices>
+ <defaultOutputDevice>Speaker</defaultOutputDevice>
+ <mixPorts>
+ <!-- Profiles on the HDMI port are explicit for simplicity. In reality they are dynamic -->
+ <!-- Note: ports are intentionally arranged from more specific to less
+ specific in order to test b/140447125 for HW AV Sync, and similar "explicit matches" -->
+ <mixPort name="tunnel" role="source"
+ flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_HW_AV_SYNC">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="low latency" role="source"
+ flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_MMAP_NOIRQ">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="direct" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="primary output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ </mixPorts>
+ <devicePorts>
+ <devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="sink" />
+ <devicePort tagName="Out Aux Digital" type="AUDIO_DEVICE_OUT_AUX_DIGITAL" role="sink" />
+ </devicePorts>
+ <routes>
+ <route type="mix" sink="Speaker" sources="primary output"/>
+ <route type="mix" sink="Out Aux Digital" sources="primary output,tunnel,direct,low latency"/>
+ </routes>
+ </module>
+ </modules>
+</audioPolicyConfiguration>
diff --git a/services/audiopolicy/tests/systemaudio_tests.cpp b/services/audiopolicy/tests/systemaudio_tests.cpp
deleted file mode 100644
index abaae52..0000000
--- a/services/audiopolicy/tests/systemaudio_tests.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <gtest/gtest.h>
-
-#define LOG_TAG "SysAudio_Test"
-#include <log/log.h>
-#include <media/PatchBuilder.h>
-#include <system/audio.h>
-
-using namespace android;
-
-TEST(SystemAudioTest, PatchInvalid) {
- audio_patch patch{};
- ASSERT_FALSE(audio_patch_is_valid(&patch));
- patch.num_sources = AUDIO_PATCH_PORTS_MAX + 1;
- patch.num_sinks = 1;
- ASSERT_FALSE(audio_patch_is_valid(&patch));
- patch.num_sources = 1;
- patch.num_sinks = AUDIO_PATCH_PORTS_MAX + 1;
- ASSERT_FALSE(audio_patch_is_valid(&patch));
- patch.num_sources = 0;
- patch.num_sinks = 1;
- ASSERT_FALSE(audio_patch_is_valid(&patch));
-}
-
-TEST(SystemAudioTest, PatchValid) {
- const audio_port_config src = {
- .id = 1, .role = AUDIO_PORT_ROLE_SOURCE, .type = AUDIO_PORT_TYPE_DEVICE };
- // It's OK not to have sinks.
- ASSERT_TRUE(audio_patch_is_valid((PatchBuilder{}).addSource(src).patch()));
- const audio_port_config sink = {
- .id = 2, .role = AUDIO_PORT_ROLE_SINK, .type = AUDIO_PORT_TYPE_DEVICE };
- ASSERT_TRUE(audio_patch_is_valid((PatchBuilder{}).addSource(src).addSink(sink).patch()));
- ASSERT_TRUE(audio_patch_is_valid(
- (PatchBuilder{}).addSource(src).addSource(src).addSink(sink).patch()));
- ASSERT_TRUE(audio_patch_is_valid(
- (PatchBuilder{}).addSource(src).addSink(sink).addSink(sink).patch()));
- ASSERT_TRUE(audio_patch_is_valid(
- (PatchBuilder{}).addSource(src).addSource(src).
- addSink(sink).addSink(sink).patch()));
-}
-
-TEST(SystemAudioTest, PatchHwAvSync) {
- audio_port_config device_src_cfg = {
- .id = 1, .role = AUDIO_PORT_ROLE_SOURCE, .type = AUDIO_PORT_TYPE_DEVICE };
- ASSERT_FALSE(audio_port_config_has_hw_av_sync(&device_src_cfg));
- device_src_cfg.config_mask |= AUDIO_PORT_CONFIG_FLAGS;
- ASSERT_FALSE(audio_port_config_has_hw_av_sync(&device_src_cfg));
- device_src_cfg.flags.input = AUDIO_INPUT_FLAG_HW_AV_SYNC;
- ASSERT_TRUE(audio_port_config_has_hw_av_sync(&device_src_cfg));
-
- audio_port_config device_sink_cfg = {
- .id = 1, .role = AUDIO_PORT_ROLE_SINK, .type = AUDIO_PORT_TYPE_DEVICE };
- ASSERT_FALSE(audio_port_config_has_hw_av_sync(&device_sink_cfg));
- device_sink_cfg.config_mask |= AUDIO_PORT_CONFIG_FLAGS;
- ASSERT_FALSE(audio_port_config_has_hw_av_sync(&device_sink_cfg));
- device_sink_cfg.flags.output = AUDIO_OUTPUT_FLAG_HW_AV_SYNC;
- ASSERT_TRUE(audio_port_config_has_hw_av_sync(&device_sink_cfg));
-
- audio_port_config mix_sink_cfg = {
- .id = 1, .role = AUDIO_PORT_ROLE_SINK, .type = AUDIO_PORT_TYPE_MIX };
- ASSERT_FALSE(audio_port_config_has_hw_av_sync(&mix_sink_cfg));
- mix_sink_cfg.config_mask |= AUDIO_PORT_CONFIG_FLAGS;
- ASSERT_FALSE(audio_port_config_has_hw_av_sync(&mix_sink_cfg));
- mix_sink_cfg.flags.input = AUDIO_INPUT_FLAG_HW_AV_SYNC;
- ASSERT_TRUE(audio_port_config_has_hw_av_sync(&mix_sink_cfg));
-
- audio_port_config mix_src_cfg = {
- .id = 1, .role = AUDIO_PORT_ROLE_SOURCE, .type = AUDIO_PORT_TYPE_MIX };
- ASSERT_FALSE(audio_port_config_has_hw_av_sync(&mix_src_cfg));
- mix_src_cfg.config_mask |= AUDIO_PORT_CONFIG_FLAGS;
- ASSERT_FALSE(audio_port_config_has_hw_av_sync(&mix_src_cfg));
- mix_src_cfg.flags.output = AUDIO_OUTPUT_FLAG_HW_AV_SYNC;
- ASSERT_TRUE(audio_port_config_has_hw_av_sync(&mix_src_cfg));
-}
-
-TEST(SystemAudioTest, PatchEqual) {
- const audio_patch patch1{}, patch2{};
- // Invalid patches are not equal.
- ASSERT_FALSE(audio_patches_are_equal(&patch1, &patch2));
- const audio_port_config src = {
- .id = 1, .role = AUDIO_PORT_ROLE_SOURCE, .type = AUDIO_PORT_TYPE_DEVICE };
- const audio_port_config sink = {
- .id = 2, .role = AUDIO_PORT_ROLE_SINK, .type = AUDIO_PORT_TYPE_DEVICE };
- ASSERT_FALSE(audio_patches_are_equal(
- (PatchBuilder{}).addSource(src).patch(),
- (PatchBuilder{}).addSource(src).addSink(sink).patch()));
- ASSERT_TRUE(audio_patches_are_equal(
- (PatchBuilder{}).addSource(src).addSink(sink).patch(),
- (PatchBuilder{}).addSource(src).addSink(sink).patch()));
- ASSERT_FALSE(audio_patches_are_equal(
- (PatchBuilder{}).addSource(src).addSink(sink).patch(),
- (PatchBuilder{}).addSource(src).addSource(src).addSink(sink).patch()));
- audio_port_config sink_hw_av_sync = sink;
- sink_hw_av_sync.config_mask |= AUDIO_PORT_CONFIG_FLAGS;
- sink_hw_av_sync.flags.output = AUDIO_OUTPUT_FLAG_HW_AV_SYNC;
- ASSERT_FALSE(audio_patches_are_equal(
- (PatchBuilder{}).addSource(src).addSink(sink).patch(),
- (PatchBuilder{}).addSource(src).addSink(sink_hw_av_sync).patch()));
- ASSERT_TRUE(audio_patches_are_equal(
- (PatchBuilder{}).addSource(src).addSink(sink_hw_av_sync).patch(),
- (PatchBuilder{}).addSource(src).addSink(sink_hw_av_sync).patch()));
-}
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index 1c1f5e6..501d922 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -26,7 +26,9 @@
"CameraFlashlight.cpp",
"common/Camera2ClientBase.cpp",
"common/CameraDeviceBase.cpp",
+ "common/CameraOfflineSessionBase.cpp",
"common/CameraProviderManager.cpp",
+ "common/DepthPhotoProcessor.cpp",
"common/FrameProcessorBase.cpp",
"api1/CameraClient.cpp",
"api1/Camera2Client.cpp",
@@ -39,12 +41,15 @@
"api1/client2/CaptureSequencer.cpp",
"api1/client2/ZslProcessor.cpp",
"api2/CameraDeviceClient.cpp",
+ "api2/CameraOfflineSessionClient.cpp",
"api2/CompositeStream.cpp",
"api2/DepthCompositeStream.cpp",
"api2/HeicEncoderInfoManager.cpp",
"api2/HeicCompositeStream.cpp",
"device1/CameraHardwareInterface.cpp",
+ "device3/BufferUtils.cpp",
"device3/Camera3Device.cpp",
+ "device3/Camera3OfflineSession.cpp",
"device3/Camera3Stream.cpp",
"device3/Camera3IOStreamBase.cpp",
"device3/Camera3InputStream.cpp",
@@ -54,21 +59,32 @@
"device3/StatusTracker.cpp",
"device3/Camera3BufferManager.cpp",
"device3/Camera3StreamSplitter.cpp",
+ "device3/CoordinateMapper.cpp",
"device3/DistortionMapper.cpp",
+ "device3/ZoomRatioMapper.cpp",
+ "device3/RotateAndCropMapper.cpp",
+ "device3/Camera3OutputStreamInterface.cpp",
+ "device3/Camera3OutputUtils.cpp",
"gui/RingBufferConsumer.cpp",
- "utils/CameraThreadState.cpp",
"hidl/AidlCameraDeviceCallbacks.cpp",
"hidl/AidlCameraServiceListener.cpp",
"hidl/Convert.cpp",
"hidl/HidlCameraDeviceUser.cpp",
"hidl/HidlCameraService.cpp",
+ "utils/CameraThreadState.cpp",
"utils/CameraTraces.cpp",
"utils/AutoConditionLock.cpp",
"utils/ExifUtils.cpp",
+ "utils/SessionConfigurationUtils.cpp",
"utils/TagMonitor.cpp",
"utils/LatencyHistogram.cpp",
],
+ header_libs: [
+ "libmediadrm_headers",
+ "libmediametrics_headers",
+ ],
+
shared_libs: [
"libbase",
"libdl",
@@ -83,30 +99,39 @@
"libmediautils",
"libcamera_client",
"libcamera_metadata",
+ "libdynamic_depth",
"libfmq",
"libgui",
"libhardware",
- "libhwbinder",
"libhidlbase",
- "libhidltransport",
+ "libimage_io",
"libjpeg",
+ "libmedia_codeclist",
"libmedia_omx",
"libmemunreachable",
"libsensorprivacy",
"libstagefright",
"libstagefright_foundation",
+ "libxml2",
"libyuv",
"android.frameworks.cameraservice.common@2.0",
"android.frameworks.cameraservice.service@2.0",
+ "android.frameworks.cameraservice.service@2.1",
"android.frameworks.cameraservice.device@2.0",
"android.hardware.camera.common@1.0",
"android.hardware.camera.provider@2.4",
"android.hardware.camera.provider@2.5",
+ "android.hardware.camera.provider@2.6",
"android.hardware.camera.device@1.0",
"android.hardware.camera.device@3.2",
"android.hardware.camera.device@3.3",
"android.hardware.camera.device@3.4",
"android.hardware.camera.device@3.5",
+ "android.hardware.camera.device@3.6"
+ ],
+
+ static_libs: [
+ "libbinderthreadstateutils",
],
export_shared_lib_headers: [
@@ -135,40 +160,3 @@
}
-cc_library_shared {
- name: "libdepthphoto",
-
- srcs: [
- "utils/ExifUtils.cpp",
- "common/DepthPhotoProcessor.cpp",
- ],
-
- shared_libs: [
- "libimage_io",
- "libdynamic_depth",
- "libxml2",
- "liblog",
- "libutilscallstack",
- "libutils",
- "libcutils",
- "libjpeg",
- "libmemunreachable",
- "libexif",
- "libcamera_client",
- ],
-
- include_dirs: [
- "external/dynamic_depth/includes",
- "external/dynamic_depth/internal",
- ],
-
- export_include_dirs: ["."],
-
- cflags: [
- "-Wall",
- "-Wextra",
- "-Werror",
- "-Wno-ignored-qualifiers",
- ],
-
-}
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 670e026..9bc79e0 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -43,6 +43,7 @@
#include <binder/PermissionController.h>
#include <binder/ProcessInfoService.h>
#include <binder/IResultReceiver.h>
+#include <binderthreadstate/CallerUtils.h>
#include <cutils/atomic.h>
#include <cutils/properties.h>
#include <cutils/misc.h>
@@ -56,12 +57,12 @@
#include <media/IMediaHTTPService.h>
#include <media/mediaplayer.h>
#include <mediautils/BatteryNotifier.h>
-#include <sensorprivacy/SensorPrivacyManager.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <utils/String16.h>
#include <utils/SystemClock.h>
#include <utils/Trace.h>
+#include <utils/CallStack.h>
#include <private/android_filesystem_config.h>
#include <system/camera_vendor_tags.h>
#include <system/camera_metadata.h>
@@ -91,6 +92,8 @@
using hardware::ICameraServiceListener;
using hardware::camera::common::V1_0::CameraDeviceStatus;
using hardware::camera::common::V1_0::TorchModeStatus;
+using hardware::camera2::utils::CameraIdAndSessionConfiguration;
+using hardware::camera2::utils::ConcurrentCameraIdCombination;
// ----------------------------------------------------------------------------
// Logging support -- this is for debugging only
@@ -117,7 +120,12 @@
// ----------------------------------------------------------------------------
+static const String16 sDumpPermission("android.permission.DUMP");
static const String16 sManageCameraPermission("android.permission.MANAGE_CAMERA");
+static const String16 sCameraPermission("android.permission.CAMERA");
+static const String16 sSystemCameraPermission("android.permission.SYSTEM_CAMERA");
+static const String16
+ sCameraSendSystemEventsPermission("android.permission.CAMERA_SEND_SYSTEM_EVENTS");
static const String16 sCameraOpenCloseListenerPermission(
"android.permission.CAMERA_OPEN_CLOSE_LISTENER");
@@ -125,6 +133,7 @@
static constexpr int32_t kVendorClientScore = 200;
// Matches with PROCESS_STATE_PERSISTENT_UI in ActivityManager.java
static constexpr int32_t kVendorClientState = 1;
+const String8 CameraService::kOfflineDevice("offline-");
Mutex CameraService::sProxyMutex;
sp<hardware::ICameraServiceProxy> CameraService::sCameraServiceProxy;
@@ -132,7 +141,9 @@
CameraService::CameraService() :
mEventLog(DEFAULT_EVENT_LOG_LENGTH),
mNumberOfCameras(0),
- mSoundRef(0), mInitialized(false) {
+ mNumberOfCamerasWithoutSystemCamera(0),
+ mSoundRef(0), mInitialized(false),
+ mAudioRestriction(hardware::camera2::ICameraDeviceUser::AUDIO_RESTRICTION_NONE) {
ALOGI("CameraService started (pid=%d)", getpid());
mServiceLockWrapper = std::make_shared<WaitableMutexWrapper>(&mServiceLock);
}
@@ -159,6 +170,7 @@
mUidPolicy->registerSelf();
mSensorPrivacyPolicy = new SensorPrivacyPolicy(this);
mSensorPrivacyPolicy->registerSelf();
+ mAppOps.setCameraAudioRestriction(mAudioRestriction);
sp<HidlCameraService> hcs = HidlCameraService::getInstance(this);
if (hcs->registerAsService() != android::OK) {
ALOGE("%s: Failed to register default android.frameworks.cameraservice.service@1.0",
@@ -244,7 +256,7 @@
Mutex::Autolock lock(mStatusListenerLock);
for (auto& i : mListenerList) {
- i.second->getListener()->onTorchStatusChanged(mapToInterface(status), String16{cameraId});
+ i->getListener()->onTorchStatusChanged(mapToInterface(status), String16{cameraId});
}
}
@@ -258,32 +270,62 @@
enumerateProviders();
}
-bool CameraService::isPublicallyHiddenSecureCamera(const String8& cameraId) {
+void CameraService::filterAPI1SystemCameraLocked(
+ const std::vector<std::string> &normalDeviceIds) {
+ mNormalDeviceIdsWithoutSystemCamera.clear();
+ for (auto &deviceId : normalDeviceIds) {
+ SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
+ if (getSystemCameraKind(String8(deviceId.c_str()), &deviceKind) != OK) {
+ ALOGE("%s: Invalid camera id %s, skipping", __FUNCTION__, deviceId.c_str());
+ continue;
+ }
+ if (deviceKind == SystemCameraKind::SYSTEM_ONLY_CAMERA) {
+ // All system camera ids will necessarily come after public camera
+ // device ids as per the HAL interface contract.
+ break;
+ }
+ mNormalDeviceIdsWithoutSystemCamera.push_back(deviceId);
+ }
+ ALOGV("%s: number of API1 compatible public cameras is %zu", __FUNCTION__,
+ mNormalDeviceIdsWithoutSystemCamera.size());
+}
+
+status_t CameraService::getSystemCameraKind(const String8& cameraId, SystemCameraKind *kind) const {
auto state = getCameraState(cameraId);
if (state != nullptr) {
- return state->isPublicallyHiddenSecureCamera();
+ *kind = state->getSystemCameraKind();
+ return OK;
}
// Hidden physical camera ids won't have CameraState
- return mCameraProviderManager->isPublicallyHiddenSecureCamera(cameraId.c_str());
+ return mCameraProviderManager->getSystemCameraKind(cameraId.c_str(), kind);
}
void CameraService::updateCameraNumAndIds() {
Mutex::Autolock l(mServiceLock);
- mNumberOfCameras = mCameraProviderManager->getCameraCount();
+ std::pair<int, int> systemAndNonSystemCameras = mCameraProviderManager->getCameraCount();
+ // Excludes hidden secure cameras
+ mNumberOfCameras =
+ systemAndNonSystemCameras.first + systemAndNonSystemCameras.second;
+ mNumberOfCamerasWithoutSystemCamera = systemAndNonSystemCameras.second;
mNormalDeviceIds =
mCameraProviderManager->getAPI1CompatibleCameraDeviceIds();
+ filterAPI1SystemCameraLocked(mNormalDeviceIds);
}
void CameraService::addStates(const String8 id) {
std::string cameraId(id.c_str());
hardware::camera::common::V1_0::CameraResourceCost cost;
status_t res = mCameraProviderManager->getResourceCost(cameraId, &cost);
+ SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
if (res != OK) {
ALOGE("Failed to query device resource cost: %s (%d)", strerror(-res), res);
return;
}
- bool isPublicallyHiddenSecureCamera =
- mCameraProviderManager->isPublicallyHiddenSecureCamera(id.string());
+ res = mCameraProviderManager->getSystemCameraKind(cameraId, &deviceKind);
+ if (res != OK) {
+ ALOGE("Failed to query device kind: %s (%d)", strerror(-res), res);
+ return;
+ }
std::set<String8> conflicting;
for (size_t i = 0; i < cost.conflictingDevices.size(); i++) {
conflicting.emplace(String8(cost.conflictingDevices[i].c_str()));
@@ -292,8 +334,7 @@
{
Mutex::Autolock lock(mCameraStatesLock);
mCameraStates.emplace(id, std::make_shared<CameraState>(id, cost.resourceCost,
- conflicting,
- isPublicallyHiddenSecureCamera));
+ conflicting, deviceKind));
}
if (mFlashlight->hasFlashUnit(id)) {
@@ -359,7 +400,7 @@
// to this device until the status changes
updateStatus(StatusInternal::NOT_PRESENT, id);
- sp<BasicClient> clientToDisconnect;
+ sp<BasicClient> clientToDisconnectOnline, clientToDisconnectOffline;
{
// Don't do this in updateStatus to avoid deadlock over mServiceLock
Mutex::Autolock lock(mServiceLock);
@@ -367,23 +408,14 @@
// Remove cached shim parameters
state->setShimParams(CameraParameters());
- // Remove the client from the list of active clients, if there is one
- clientToDisconnect = removeClientLocked(id);
+ // Remove online as well as offline client from the list of active clients,
+ // if they are present
+ clientToDisconnectOnline = removeClientLocked(id);
+ clientToDisconnectOffline = removeClientLocked(kOfflineDevice + id);
}
- // Disconnect client
- if (clientToDisconnect.get() != nullptr) {
- ALOGI("%s: Client for camera ID %s evicted due to device status change from HAL",
- __FUNCTION__, id.string());
- // Notify the client of disconnection
- clientToDisconnect->notifyError(
- hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DISCONNECTED,
- CaptureResultExtras{});
- // Ensure not in binder RPC so client disconnect PID checks work correctly
- LOG_ALWAYS_FATAL_IF(CameraThreadState::getCallingPid() != getpid(),
- "onDeviceStatusChanged must be called from the camera service process!");
- clientToDisconnect->disconnect();
- }
+ disconnectClient(id, clientToDisconnectOnline);
+ disconnectClient(kOfflineDevice + id, clientToDisconnectOffline);
removeStates(id);
} else {
@@ -393,7 +425,71 @@
}
updateStatus(newStatus, id);
}
+}
+void CameraService::onDeviceStatusChanged(const String8& id,
+ const String8& physicalId,
+ CameraDeviceStatus newHalStatus) {
+ ALOGI("%s: Status changed for cameraId=%s, physicalCameraId=%s, newStatus=%d",
+ __FUNCTION__, id.string(), physicalId.string(), newHalStatus);
+
+ StatusInternal newStatus = mapToInternal(newHalStatus);
+
+ std::shared_ptr<CameraState> state = getCameraState(id);
+
+ if (state == nullptr) {
+ ALOGE("%s: Physical camera id %s status change on a non-present ID %s",
+ __FUNCTION__, id.string(), physicalId.string());
+ return;
+ }
+
+ StatusInternal logicalCameraStatus = state->getStatus();
+ if (logicalCameraStatus != StatusInternal::PRESENT &&
+ logicalCameraStatus != StatusInternal::NOT_AVAILABLE) {
+ ALOGE("%s: Physical camera id %s status %d change for an invalid logical camera state %d",
+ __FUNCTION__, physicalId.string(), newHalStatus, logicalCameraStatus);
+ return;
+ }
+
+ bool updated = false;
+ if (newStatus == StatusInternal::PRESENT) {
+ updated = state->removeUnavailablePhysicalId(physicalId);
+ } else {
+ updated = state->addUnavailablePhysicalId(physicalId);
+ }
+
+ if (updated) {
+ String8 idCombo = id + " : " + physicalId;
+ if (newStatus == StatusInternal::PRESENT) {
+ logDeviceAdded(idCombo,
+ String8::format("Device status changed to %d", newStatus));
+ } else {
+ logDeviceRemoved(idCombo,
+ String8::format("Device status changed to %d", newStatus));
+ }
+
+ String16 id16(id), physicalId16(physicalId);
+ Mutex::Autolock lock(mStatusListenerLock);
+ for (auto& listener : mListenerList) {
+ listener->getListener()->onPhysicalCameraStatusChanged(mapToInterface(newStatus),
+ id16, physicalId16);
+ }
+ }
+}
+
+void CameraService::disconnectClient(const String8& id, sp<BasicClient> clientToDisconnect) {
+ if (clientToDisconnect.get() != nullptr) {
+ ALOGI("%s: Client for camera ID %s evicted due to device status change from HAL",
+ __FUNCTION__, id.string());
+ // Notify the client of disconnection
+ clientToDisconnect->notifyError(
+ hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DISCONNECTED,
+ CaptureResultExtras{});
+ // Ensure not in binder RPC so client disconnect PID checks work correctly
+ LOG_ALWAYS_FATAL_IF(CameraThreadState::getCallingPid() != getpid(),
+ "onDeviceStatusChanged must be called from the camera service process!");
+ clientToDisconnect->disconnect();
+ }
}
void CameraService::onTorchStatusChanged(const String8& cameraId,
@@ -456,15 +552,31 @@
broadcastTorchModeStatus(cameraId, newStatus);
}
+static bool hasPermissionsForSystemCamera(int callingPid, int callingUid) {
+ return checkPermission(sSystemCameraPermission, callingPid, callingUid) &&
+ checkPermission(sCameraPermission, callingPid, callingUid);
+}
+
Status CameraService::getNumberOfCameras(int32_t type, int32_t* numCameras) {
ATRACE_CALL();
Mutex::Autolock l(mServiceLock);
+ bool hasSystemCameraPermissions =
+ hasPermissionsForSystemCamera(CameraThreadState::getCallingPid(),
+ CameraThreadState::getCallingUid());
switch (type) {
case CAMERA_TYPE_BACKWARD_COMPATIBLE:
- *numCameras = static_cast<int>(mNormalDeviceIds.size());
+ if (hasSystemCameraPermissions) {
+ *numCameras = static_cast<int>(mNormalDeviceIds.size());
+ } else {
+ *numCameras = static_cast<int>(mNormalDeviceIdsWithoutSystemCamera.size());
+ }
break;
case CAMERA_TYPE_ALL:
- *numCameras = mNumberOfCameras;
+ if (hasSystemCameraPermissions) {
+ *numCameras = mNumberOfCameras;
+ } else {
+ *numCameras = mNumberOfCamerasWithoutSystemCamera;
+ }
break;
default:
ALOGW("%s: Unknown camera type %d",
@@ -479,20 +591,31 @@
CameraInfo* cameraInfo) {
ATRACE_CALL();
Mutex::Autolock l(mServiceLock);
+ std::string cameraIdStr = cameraIdIntToStrLocked(cameraId);
+ if (shouldRejectSystemCameraConnection(String8(cameraIdStr.c_str()))) {
+ return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Unable to retrieve camera"
+ "characteristics for system only device %s: ", cameraIdStr.c_str());
+ }
if (!mInitialized) {
return STATUS_ERROR(ERROR_DISCONNECTED,
"Camera subsystem is not available");
}
-
- if (cameraId < 0 || cameraId >= mNumberOfCameras) {
+ bool hasSystemCameraPermissions =
+ hasPermissionsForSystemCamera(CameraThreadState::getCallingPid(),
+ CameraThreadState::getCallingUid());
+ int cameraIdBound = mNumberOfCamerasWithoutSystemCamera;
+ if (hasSystemCameraPermissions) {
+ cameraIdBound = mNumberOfCameras;
+ }
+ if (cameraId < 0 || cameraId >= cameraIdBound) {
return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT,
"CameraId is not valid");
}
Status ret = Status::ok();
status_t err = mCameraProviderManager->getCameraInfo(
- cameraIdIntToStrLocked(cameraId), cameraInfo);
+ cameraIdStr.c_str(), cameraInfo);
if (err != OK) {
ret = STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
"Error retrieving camera info from device %d: %s (%d)", cameraId,
@@ -503,13 +626,20 @@
}
std::string CameraService::cameraIdIntToStrLocked(int cameraIdInt) {
- if (cameraIdInt < 0 || cameraIdInt >= static_cast<int>(mNormalDeviceIds.size())) {
+ const std::vector<std::string> *deviceIds = &mNormalDeviceIdsWithoutSystemCamera;
+ auto callingPid = CameraThreadState::getCallingPid();
+ auto callingUid = CameraThreadState::getCallingUid();
+ if (checkPermission(sSystemCameraPermission, callingPid, callingUid) ||
+ getpid() == callingPid) {
+ deviceIds = &mNormalDeviceIds;
+ }
+ if (cameraIdInt < 0 || cameraIdInt >= static_cast<int>(deviceIds->size())) {
ALOGE("%s: input id %d invalid: valid range (0, %zu)",
- __FUNCTION__, cameraIdInt, mNormalDeviceIds.size());
+ __FUNCTION__, cameraIdInt, deviceIds->size());
return std::string{};
}
- return mNormalDeviceIds[cameraIdInt];
+ return (*deviceIds)[cameraIdInt];
}
String8 CameraService::cameraIdIntToStr(int cameraIdInt) {
@@ -531,16 +661,13 @@
"Camera subsystem is not available");;
}
- if (shouldRejectHiddenCameraConnection(String8(cameraId))) {
- ALOGW("Attempting to retrieve characteristics for system-only camera id %s, rejected",
- String8(cameraId).string());
- return STATUS_ERROR_FMT(ERROR_DISCONNECTED,
- "No camera device with ID \"%s\" currently available",
- String8(cameraId).string());
-
+ if (shouldRejectSystemCameraConnection(String8(cameraId))) {
+ return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Unable to retrieve camera"
+ "characteristics for system only device %s: ", String8(cameraId).string());
}
Status ret{};
+
status_t res = mCameraProviderManager->getCameraCharacteristics(
String8(cameraId).string(), cameraInfo);
if (res != OK) {
@@ -548,13 +675,21 @@
"characteristics for device %s: %s (%d)", String8(cameraId).string(),
strerror(-res), res);
}
-
+ SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
+ if (getSystemCameraKind(String8(cameraId), &deviceKind) != OK) {
+ ALOGE("%s: Invalid camera id %s, skipping", __FUNCTION__, String8(cameraId).string());
+ return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Unable to retrieve camera kind "
+ "for device %s", String8(cameraId).string());
+ }
int callingPid = CameraThreadState::getCallingPid();
int callingUid = CameraThreadState::getCallingUid();
std::vector<int32_t> tagsRemoved;
- // If it's not calling from cameraserver, check the permission.
+ // If it's not calling from cameraserver, check the permission only if
+ // android.permission.CAMERA is required. If android.permission.SYSTEM_CAMERA was needed,
+ // it would've already been checked in shouldRejectSystemCameraConnection.
if ((callingPid != getpid()) &&
- !checkPermission(String16("android.permission.CAMERA"), callingPid, callingUid)) {
+ (deviceKind != SystemCameraKind::SYSTEM_ONLY_CAMERA) &&
+ !checkPermission(sCameraPermission, callingPid, callingUid)) {
res = cameraInfo->removePermissionEntries(
mCameraProviderManager->getProviderTagIdLocked(String8(cameraId).string()),
&tagsRemoved);
@@ -658,9 +793,10 @@
}
Status CameraService::makeClient(const sp<CameraService>& cameraService,
- const sp<IInterface>& cameraCb, const String16& packageName, const String8& cameraId,
- int api1CameraId, int facing, int clientPid, uid_t clientUid, int servicePid,
- int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
+ const sp<IInterface>& cameraCb, const String16& packageName,
+ const std::unique_ptr<String16>& featureId, const String8& cameraId, int api1CameraId,
+ int facing, int clientPid, uid_t clientUid, int servicePid, int halVersion,
+ int deviceVersion, apiLevel effectiveApiLevel,
/*out*/sp<BasicClient>* client) {
if (halVersion < 0 || halVersion == deviceVersion) {
@@ -670,7 +806,7 @@
case CAMERA_DEVICE_API_VERSION_1_0:
if (effectiveApiLevel == API_1) { // Camera1 API route
sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
- *client = new CameraClient(cameraService, tmp, packageName,
+ *client = new CameraClient(cameraService, tmp, packageName, featureId,
api1CameraId, facing, clientPid, clientUid,
getpid());
} else { // Camera2 API route
@@ -686,17 +822,18 @@
case CAMERA_DEVICE_API_VERSION_3_3:
case CAMERA_DEVICE_API_VERSION_3_4:
case CAMERA_DEVICE_API_VERSION_3_5:
+ case CAMERA_DEVICE_API_VERSION_3_6:
if (effectiveApiLevel == API_1) { // Camera1 API route
sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
- *client = new Camera2Client(cameraService, tmp, packageName,
+ *client = new Camera2Client(cameraService, tmp, packageName, featureId,
cameraId, api1CameraId,
facing, clientPid, clientUid,
servicePid);
} else { // Camera2 API route
sp<hardware::camera2::ICameraDeviceCallbacks> tmp =
static_cast<hardware::camera2::ICameraDeviceCallbacks*>(cameraCb.get());
- *client = new CameraDeviceClient(cameraService, tmp, packageName, cameraId,
- facing, clientPid, clientUid, servicePid);
+ *client = new CameraDeviceClient(cameraService, tmp, packageName, featureId,
+ cameraId, facing, clientPid, clientUid, servicePid);
}
break;
default:
@@ -713,7 +850,7 @@
halVersion == CAMERA_DEVICE_API_VERSION_1_0) {
// Only support higher HAL version device opened as HAL1.0 device.
sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
- *client = new CameraClient(cameraService, tmp, packageName,
+ *client = new CameraClient(cameraService, tmp, packageName, featureId,
api1CameraId, facing, clientPid, clientUid,
servicePid);
} else {
@@ -813,7 +950,7 @@
if (!(ret = connectHelper<ICameraClient,Client>(
sp<ICameraClient>{nullptr}, id, cameraId,
static_cast<int>(CAMERA_HAL_API_VERSION_UNSPECIFIED),
- internalPackageName, uid, USE_CALLING_PID,
+ internalPackageName, std::unique_ptr<String16>(), uid, USE_CALLING_PID,
API_1, /*shimUpdateOnly*/ true, /*out*/ tmp)
).isOk()) {
ALOGE("%s: Error initializing shim metadata: %s", __FUNCTION__, ret.toString8().string());
@@ -994,9 +1131,26 @@
clientName8.string(), clientUid, clientPid);
}
- // If it's not calling from cameraserver, check the permission.
+ if (shouldRejectSystemCameraConnection(cameraId)) {
+ ALOGW("Attempting to connect to system-only camera id %s, connection rejected",
+ cameraId.c_str());
+ return STATUS_ERROR_FMT(ERROR_DISCONNECTED, "No camera device with ID \"%s\" is"
+ "available", cameraId.string());
+ }
+ SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
+ if (getSystemCameraKind(cameraId, &deviceKind) != OK) {
+ ALOGE("%s: Invalid camera id %s, skipping", __FUNCTION__, cameraId.string());
+ return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT, "No camera device with ID \"%s\""
+ "found while trying to query device kind", cameraId.string());
+
+ }
+
+ // If it's not calling from cameraserver, check the permission if the
+ // device isn't a system only camera (shouldRejectSystemCameraConnection already checks for
+ // android.permission.SYSTEM_CAMERA for system only camera devices).
if (callingPid != getpid() &&
- !checkPermission(String16("android.permission.CAMERA"), clientPid, clientUid)) {
+ (deviceKind != SystemCameraKind::SYSTEM_ONLY_CAMERA) &&
+ !checkPermission(sCameraPermission, clientPid, clientUid)) {
ALOGE("Permission Denial: can't use the camera pid=%d, uid=%d", clientPid, clientUid);
return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
"Caller \"%s\" (PID %d, UID %d) cannot open camera \"%s\" without camera permission",
@@ -1032,7 +1186,7 @@
// Only allow clients who are being used by the current foreground device user, unless calling
// from our own process OR the caller is using the cameraserver's HIDL interface.
- if (!hardware::IPCThreadState::self()->isServingCall() && callingPid != getpid() &&
+ if (getCurrentServingCall() != BinderCallType::HWBINDER && callingPid != getpid() &&
(mAllowedUsers.find(clientUserId) == mAllowedUsers.end())) {
ALOGE("CameraService::connect X (PID %d) rejected (cannot connect from "
"device user %d, currently allowed device users: %s)", callingPid, clientUserId,
@@ -1309,8 +1463,8 @@
String8 id = cameraIdIntToStr(api1CameraId);
sp<Client> client = nullptr;
ret = connectHelper<ICameraClient,Client>(cameraClient, id, api1CameraId,
- CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName, clientUid, clientPid, API_1,
- /*shimUpdateOnly*/ false, /*out*/client);
+ CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName, std::unique_ptr<String16>(),
+ clientUid, clientPid, API_1, /*shimUpdateOnly*/ false, /*out*/client);
if(!ret.isOk()) {
logRejected(id, CameraThreadState::getCallingPid(), String8(clientPackageName),
@@ -1336,8 +1490,8 @@
Status ret = Status::ok();
sp<Client> client = nullptr;
ret = connectHelper<ICameraClient,Client>(cameraClient, id, api1CameraId, halVersion,
- clientPackageName, clientUid, USE_CALLING_PID, API_1, /*shimUpdateOnly*/ false,
- /*out*/client);
+ clientPackageName, std::unique_ptr<String16>(), clientUid, USE_CALLING_PID, API_1,
+ /*shimUpdateOnly*/ false, /*out*/client);
if(!ret.isOk()) {
logRejected(id, CameraThreadState::getCallingPid(), String8(clientPackageName),
@@ -1349,22 +1503,69 @@
return ret;
}
-bool CameraService::shouldRejectHiddenCameraConnection(const String8 & cameraId) {
- // If the thread serving this call is not a hwbinder thread and the caller
- // isn't the cameraserver itself, and the camera id being requested is to be
- // publically hidden, we should reject the connection.
- if (!hardware::IPCThreadState::self()->isServingCall() &&
- CameraThreadState::getCallingPid() != getpid() &&
- isPublicallyHiddenSecureCamera(cameraId)) {
+bool CameraService::shouldSkipStatusUpdates(SystemCameraKind systemCameraKind,
+ bool isVendorListener, int clientPid, int clientUid) {
+ // If the client is not a vendor client, don't add listener if
+ // a) the camera is a publicly hidden secure camera OR
+ // b) the camera is a system only camera and the client doesn't
+ // have android.permission.SYSTEM_CAMERA permissions.
+ if (!isVendorListener && (systemCameraKind == SystemCameraKind::HIDDEN_SECURE_CAMERA ||
+ (systemCameraKind == SystemCameraKind::SYSTEM_ONLY_CAMERA &&
+ !hasPermissionsForSystemCamera(clientPid, clientUid)))) {
return true;
}
return false;
}
+bool CameraService::shouldRejectSystemCameraConnection(const String8& cameraId) const {
+ // Rules for rejection:
+ // 1) If cameraserver tries to access this camera device, accept the
+ // connection.
+ // 2) The camera device is a publicly hidden secure camera device AND some
+ // component is trying to access it on a non-hwbinder thread (generally a non HAL client),
+ // reject it.
+ // 3) if the camera device is advertised by the camera HAL as SYSTEM_ONLY
+ // and the serving thread is a non hwbinder thread, the client must have
+ // android.permission.SYSTEM_CAMERA permissions to connect.
+
+ int cPid = CameraThreadState::getCallingPid();
+ int cUid = CameraThreadState::getCallingUid();
+ SystemCameraKind systemCameraKind = SystemCameraKind::PUBLIC;
+ if (getSystemCameraKind(cameraId, &systemCameraKind) != OK) {
+ ALOGE("%s: Invalid camera id %s, ", __FUNCTION__, cameraId.c_str());
+ return true;
+ }
+
+ // (1) Cameraserver trying to connect, accept.
+ if (CameraThreadState::getCallingPid() == getpid()) {
+ return false;
+ }
+ // (2)
+ if (getCurrentServingCall() != BinderCallType::HWBINDER &&
+ systemCameraKind == SystemCameraKind::HIDDEN_SECURE_CAMERA) {
+ ALOGW("Rejecting access to secure hidden camera %s", cameraId.c_str());
+ return true;
+ }
+ // (3) Here we only check for permissions if it is a system only camera device. This is since
+ // getCameraCharacteristics() allows for calls to succeed (albeit after hiding some
+ // characteristics) even if clients don't have android.permission.CAMERA. We do not want the
+ // same behavior for system camera devices.
+ if (getCurrentServingCall() != BinderCallType::HWBINDER &&
+ systemCameraKind == SystemCameraKind::SYSTEM_ONLY_CAMERA &&
+ !hasPermissionsForSystemCamera(cPid, cUid)) {
+ ALOGW("Rejecting access to system only camera %s, inadequete permissions",
+ cameraId.c_str());
+ return true;
+ }
+
+ return false;
+}
+
Status CameraService::connectDevice(
const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
const String16& cameraId,
const String16& clientPackageName,
+ const std::unique_ptr<String16>& clientFeatureId,
int clientUid,
/*out*/
sp<hardware::camera2::ICameraDeviceUser>* device) {
@@ -1374,14 +1575,15 @@
String8 id = String8(cameraId);
sp<CameraDeviceClient> client = nullptr;
String16 clientPackageNameAdj = clientPackageName;
- if (hardware::IPCThreadState::self()->isServingCall()) {
+
+ if (getCurrentServingCall() == BinderCallType::HWBINDER) {
std::string vendorClient =
StringPrintf("vendor.client.pid<%d>", CameraThreadState::getCallingPid());
clientPackageNameAdj = String16(vendorClient.c_str());
}
ret = connectHelper<hardware::camera2::ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb, id,
/*api1CameraId*/-1,
- CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageNameAdj,
+ CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageNameAdj, clientFeatureId,
clientUid, USE_CALLING_PID, API_2, /*shimUpdateOnly*/ false, /*out*/client);
if(!ret.isOk()) {
@@ -1396,8 +1598,9 @@
template<class CALLBACK, class CLIENT>
Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
- int api1CameraId, int halVersion, const String16& clientPackageName, int clientUid,
- int clientPid, apiLevel effectiveApiLevel, bool shimUpdateOnly,
+ int api1CameraId, int halVersion, const String16& clientPackageName,
+ const std::unique_ptr<String16>& clientFeatureId, int clientUid, int clientPid,
+ apiLevel effectiveApiLevel, bool shimUpdateOnly,
/*out*/sp<CLIENT>& device) {
binder::Status ret = binder::Status::ok();
@@ -1410,14 +1613,6 @@
(halVersion == -1) ? "default" : std::to_string(halVersion).c_str(),
static_cast<int>(effectiveApiLevel));
- if (shouldRejectHiddenCameraConnection(cameraId)) {
- ALOGW("Attempting to connect to system-only camera id %s, connection rejected",
- cameraId.c_str());
- return STATUS_ERROR_FMT(ERROR_DISCONNECTED,
- "No camera device with ID \"%s\" currently available",
- cameraId.string());
-
- }
sp<CLIENT> client = nullptr;
{
// Acquire mServiceLock and prevent other clients from connecting
@@ -1488,7 +1683,7 @@
}
sp<BasicClient> tmp = nullptr;
- if(!(ret = makeClient(this, cameraCb, clientPackageName,
+ if(!(ret = makeClient(this, cameraCb, clientPackageName, clientFeatureId,
cameraId, api1CameraId, facing,
clientPid, clientUid, getpid(),
halVersion, deviceVersion, effectiveApiLevel,
@@ -1545,6 +1740,11 @@
}
}
+ // Set rotate-and-crop override behavior
+ if (mOverrideRotateAndCropMode != ANDROID_SCALER_ROTATE_AND_CROP_AUTO) {
+ client->setRotateAndCropOverride(mOverrideRotateAndCropMode);
+ }
+
if (shimUpdateOnly) {
// If only updating legacy shim parameters, immediately disconnect client
mServiceLock.unlock();
@@ -1562,6 +1762,77 @@
return ret;
}
+status_t CameraService::addOfflineClient(String8 cameraId, sp<BasicClient> offlineClient) {
+ if (offlineClient.get() == nullptr) {
+ return BAD_VALUE;
+ }
+
+ {
+ // Acquire mServiceLock and prevent other clients from connecting
+ std::unique_ptr<AutoConditionLock> lock =
+ AutoConditionLock::waitAndAcquire(mServiceLockWrapper, DEFAULT_CONNECT_TIMEOUT_NS);
+
+ if (lock == nullptr) {
+ ALOGE("%s: (PID %d) rejected (too many other clients connecting)."
+ , __FUNCTION__, offlineClient->getClientPid());
+ return TIMED_OUT;
+ }
+
+ auto onlineClientDesc = mActiveClientManager.get(cameraId);
+ if (onlineClientDesc.get() == nullptr) {
+ ALOGE("%s: No active online client using camera id: %s", __FUNCTION__,
+ cameraId.c_str());
+ return BAD_VALUE;
+ }
+
+ // Offline clients do not evict or conflict with other online devices. Resource sharing
+ // conflicts are handled by the camera provider which will either succeed or fail before
+ // reaching this method.
+ const auto& onlinePriority = onlineClientDesc->getPriority();
+ auto offlineClientDesc = CameraClientManager::makeClientDescriptor(
+ kOfflineDevice + onlineClientDesc->getKey(), offlineClient, /*cost*/ 0,
+ /*conflictingKeys*/ std::set<String8>(), onlinePriority.getScore(),
+ onlineClientDesc->getOwnerId(), onlinePriority.getState());
+
+ // Allow only one offline device per camera
+ auto incompatibleClients = mActiveClientManager.getIncompatibleClients(offlineClientDesc);
+ if (!incompatibleClients.empty()) {
+ ALOGE("%s: Incompatible offline clients present!", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ auto err = offlineClient->initialize(mCameraProviderManager, mMonitorTags);
+ if (err != OK) {
+ ALOGE("%s: Could not initialize offline client.", __FUNCTION__);
+ return err;
+ }
+
+ auto evicted = mActiveClientManager.addAndEvict(offlineClientDesc);
+ if (evicted.size() > 0) {
+ for (auto& i : evicted) {
+ ALOGE("%s: Invalid state: Offline client for camera %s was not removed ",
+ __FUNCTION__, i->getKey().string());
+ }
+
+ LOG_ALWAYS_FATAL("%s: Invalid state for CameraService, offline clients not evicted "
+ "properly", __FUNCTION__);
+
+ return BAD_VALUE;
+ }
+
+ logConnectedOffline(offlineClientDesc->getKey(),
+ static_cast<int>(offlineClientDesc->getOwnerId()),
+ String8(offlineClient->getPackageName()));
+
+ sp<IBinder> remoteCallback = offlineClient->getRemote();
+ if (remoteCallback != nullptr) {
+ remoteCallback->linkToDeath(this);
+ }
+ } // lock is destroyed, allow further connect calls
+
+ return OK;
+}
+
Status CameraService::setTorchMode(const String16& cameraId, bool enabled,
const sp<IBinder>& clientBinder) {
Mutex::Autolock lock(mServiceLock);
@@ -1693,8 +1964,7 @@
if (pid != selfPid) {
// Ensure we're being called by system_server, or similar process with
// permissions to notify the camera service about system events
- if (!checkCallingPermission(
- String16("android.permission.CAMERA_SEND_SYSTEM_EVENTS"))) {
+ if (!checkCallingPermission(sCameraSendSystemEventsPermission)) {
const int uid = CameraThreadState::getCallingUid();
ALOGE("Permission Denial: cannot send updates to camera service about system"
" events from pid=%d, uid=%d", pid, uid);
@@ -1729,7 +1999,7 @@
Mutex::Autolock lock(mStatusListenerLock);
for (const auto& it : mListenerList) {
- auto ret = it.second->getListener()->onCameraAccessPrioritiesChanged();
+ auto ret = it->getListener()->onCameraAccessPrioritiesChanged();
if (!ret.isOk()) {
ALOGE("%s: Failed to trigger permission callback: %d", __FUNCTION__,
ret.exceptionCode());
@@ -1745,8 +2015,7 @@
if (pid != selfPid) {
// Ensure we're being called by system_server, or similar process with
// permissions to notify the camera service about system events
- if (!checkCallingPermission(
- String16("android.permission.CAMERA_SEND_SYSTEM_EVENTS"))) {
+ if (!checkCallingPermission(sCameraSendSystemEventsPermission)) {
const int uid = CameraThreadState::getCallingUid();
ALOGE("Permission Denial: cannot send updates to camera service about device"
" state changes from pid=%d, uid=%d", pid, uid);
@@ -1780,6 +2049,83 @@
return Status::ok();
}
+ Status CameraService::getConcurrentCameraIds(
+ std::vector<ConcurrentCameraIdCombination>* concurrentCameraIds) {
+ ATRACE_CALL();
+ if (!concurrentCameraIds) {
+ ALOGE("%s: concurrentCameraIds is NULL", __FUNCTION__);
+ return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "concurrentCameraIds is NULL");
+ }
+
+ if (!mInitialized) {
+ ALOGE("%s: Camera HAL couldn't be initialized", __FUNCTION__);
+ return STATUS_ERROR(ERROR_DISCONNECTED,
+ "Camera subsystem is not available");
+ }
+ // First call into the provider and get the set of concurrent camera
+ // combinations
+ std::vector<std::unordered_set<std::string>> concurrentCameraCombinations =
+ mCameraProviderManager->getConcurrentCameraIds();
+ for (auto &combination : concurrentCameraCombinations) {
+ std::vector<std::string> validCombination;
+ for (auto &cameraId : combination) {
+ // if the camera state is not present, skip
+ String8 cameraIdStr(cameraId.c_str());
+ auto state = getCameraState(cameraIdStr);
+ if (state == nullptr) {
+ ALOGW("%s: camera id %s does not exist", __FUNCTION__, cameraId.c_str());
+ continue;
+ }
+ StatusInternal status = state->getStatus();
+ if (status == StatusInternal::NOT_PRESENT || status == StatusInternal::ENUMERATING) {
+ continue;
+ }
+ if (shouldRejectSystemCameraConnection(cameraIdStr)) {
+ continue;
+ }
+ validCombination.push_back(cameraId);
+ }
+ if (validCombination.size() != 0) {
+ concurrentCameraIds->push_back(std::move(validCombination));
+ }
+ }
+ return Status::ok();
+}
+
+Status CameraService::isConcurrentSessionConfigurationSupported(
+ const std::vector<CameraIdAndSessionConfiguration>& cameraIdsAndSessionConfigurations,
+ /*out*/bool* isSupported) {
+ if (!isSupported) {
+ ALOGE("%s: isSupported is NULL", __FUNCTION__);
+ return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "isSupported is NULL");
+ }
+
+ if (!mInitialized) {
+ ALOGE("%s: Camera HAL couldn't be initialized", __FUNCTION__);
+ return STATUS_ERROR(ERROR_DISCONNECTED,
+ "Camera subsystem is not available");
+ }
+
+ // Check for camera permissions
+ int callingPid = CameraThreadState::getCallingPid();
+ int callingUid = CameraThreadState::getCallingUid();
+ if ((callingPid != getpid()) && !checkPermission(sCameraPermission, callingPid, callingUid)) {
+ ALOGE("%s: pid %d doesn't have camera permissions", __FUNCTION__, callingPid);
+ return STATUS_ERROR(ERROR_PERMISSION_DENIED,
+ "android.permission.CAMERA needed to call"
+ "isConcurrentSessionConfigurationSupported");
+ }
+
+ status_t res =
+ mCameraProviderManager->isConcurrentSessionConfigurationSupported(
+ cameraIdsAndSessionConfigurations, isSupported);
+ if (res != OK) {
+ return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Unable to query session configuration "
+ "support %s (%d)", strerror(-res), res);
+ }
+ return Status::ok();
+}
+
Status CameraService::addListener(const sp<ICameraServiceListener>& listener,
/*out*/
std::vector<hardware::CameraStatus> *cameraStatuses) {
@@ -1800,24 +2146,26 @@
return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "Null listener given to addListener");
}
+ auto clientUid = CameraThreadState::getCallingUid();
+ auto clientPid = CameraThreadState::getCallingPid();
+ bool openCloseCallbackAllowed = checkPermission(sCameraOpenCloseListenerPermission,
+ clientPid, clientUid);
+
Mutex::Autolock lock(mServiceLock);
{
Mutex::Autolock lock(mStatusListenerLock);
for (const auto &it : mListenerList) {
- if (IInterface::asBinder(it.second->getListener()) == IInterface::asBinder(listener)) {
+ if (IInterface::asBinder(it->getListener()) == IInterface::asBinder(listener)) {
ALOGW("%s: Tried to add listener %p which was already subscribed",
__FUNCTION__, listener.get());
return STATUS_ERROR(ERROR_ALREADY_EXISTS, "Listener already registered");
}
}
- auto clientUid = CameraThreadState::getCallingUid();
- auto clientPid = CameraThreadState::getCallingPid();
- bool openCloseCallbackAllowed = checkPermission(sCameraOpenCloseListenerPermission,
- clientPid, clientUid);
- sp<ServiceListener> serviceListener = new ServiceListener(this, listener,
- clientUid, clientPid, openCloseCallbackAllowed);
+ sp<ServiceListener> serviceListener =
+ new ServiceListener(this, listener, clientUid, clientPid, isVendorListener,
+ openCloseCallbackAllowed);
auto ret = serviceListener->initialize();
if (ret != NO_ERROR) {
String8 msg = String8::format("Failed to initialize service listener: %s (%d)",
@@ -1825,7 +2173,10 @@
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, msg.string());
}
- mListenerList.emplace_back(isVendorListener, serviceListener);
+ // The listener still needs to be added to the list of listeners, regardless of what
+ // permissions the listener process has / whether it is a vendor listener. Since it might be
+ // eligible to listen to other camera ids.
+ mListenerList.emplace_back(serviceListener);
mUidPolicy->registerMonitorUid(clientUid);
}
@@ -1833,24 +2184,25 @@
{
Mutex::Autolock lock(mCameraStatesLock);
for (auto& i : mCameraStates) {
- cameraStatuses->emplace_back(i.first, mapToInterface(i.second->getStatus()));
+ cameraStatuses->emplace_back(i.first,
+ mapToInterface(i.second->getStatus()), i.second->getUnavailablePhysicalIds());
}
}
-
// Remove the camera statuses that should be hidden from the client, we do
// this after collecting the states in order to avoid holding
- // mCameraStatesLock and mInterfaceLock (held in
- // isPublicallyHiddenSecureCamera()) at the same time.
+ // mCameraStatesLock and mInterfaceLock (held in getSystemCameraKind()) at
+ // the same time.
cameraStatuses->erase(std::remove_if(cameraStatuses->begin(), cameraStatuses->end(),
- [this, &isVendorListener](const hardware::CameraStatus& s) {
- bool ret = !isVendorListener && isPublicallyHiddenSecureCamera(s.cameraId);
- if (ret) {
- ALOGV("Cannot add public listener for hidden system-only %s for pid %d",
- s.cameraId.c_str(), CameraThreadState::getCallingPid());
+ [this, &isVendorListener, &clientPid, &clientUid](const hardware::CameraStatus& s) {
+ SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
+ if (getSystemCameraKind(s.cameraId, &deviceKind) != OK) {
+ ALOGE("%s: Invalid camera id %s, skipping status update",
+ __FUNCTION__, s.cameraId.c_str());
+ return true;
}
- return ret;
- }),
- cameraStatuses->end());
+ return shouldSkipStatusUpdates(deviceKind, isVendorListener, clientPid,
+ clientUid);}), cameraStatuses->end());
+
/*
* Immediately signal current torch status to this listener only
@@ -1882,9 +2234,9 @@
{
Mutex::Autolock lock(mStatusListenerLock);
for (auto it = mListenerList.begin(); it != mListenerList.end(); it++) {
- if (IInterface::asBinder(it->second->getListener()) == IInterface::asBinder(listener)) {
- mUidPolicy->unregisterMonitorUid(it->second->getListenerUid());
- IInterface::asBinder(listener)->unlinkToDeath(it->second);
+ if (IInterface::asBinder((*it)->getListener()) == IInterface::asBinder(listener)) {
+ mUidPolicy->unregisterMonitorUid((*it)->getListenerUid());
+ IInterface::asBinder(listener)->unlinkToDeath(*it);
mListenerList.erase(it);
return Status::ok();
}
@@ -1960,6 +2312,7 @@
case CAMERA_DEVICE_API_VERSION_3_3:
case CAMERA_DEVICE_API_VERSION_3_4:
case CAMERA_DEVICE_API_VERSION_3_5:
+ case CAMERA_DEVICE_API_VERSION_3_6:
ALOGV("%s: Camera id %s uses HAL3.2 or newer, supports api1/api2 directly",
__FUNCTION__, id.string());
*isSupported = true;
@@ -2000,6 +2353,7 @@
mActiveClientManager.remove(i);
}
}
+ updateAudioRestrictionLocked();
}
bool CameraService::evictClientIdByRemote(const wp<IBinder>& remote) {
@@ -2164,6 +2518,13 @@
clientPackage, clientPid));
}
+void CameraService::logDisconnectedOffline(const char* cameraId, int clientPid,
+ const char* clientPackage) {
+ // Log the clients evicted
+ logEvent(String8::format("DISCONNECT offline device %s client for package %s (PID %d)",
+ cameraId, clientPackage, clientPid));
+}
+
void CameraService::logConnected(const char* cameraId, int clientPid,
const char* clientPackage) {
// Log the clients evicted
@@ -2171,6 +2532,13 @@
clientPackage, clientPid));
}
+void CameraService::logConnectedOffline(const char* cameraId, int clientPid,
+ const char* clientPackage) {
+ // Log the clients evicted
+ logEvent(String8::format("CONNECT offline device %s client for package %s (PID %d)", cameraId,
+ clientPackage, clientPid));
+}
+
void CameraService::logRejected(const char* cameraId, int clientPid,
const char* clientPackage, const char* reason) {
// Log the client rejected
@@ -2329,13 +2697,14 @@
CameraService::Client::Client(const sp<CameraService>& cameraService,
const sp<ICameraClient>& cameraClient,
const String16& clientPackageName,
+ const std::unique_ptr<String16>& clientFeatureId,
const String8& cameraIdStr,
int api1CameraId, int cameraFacing,
int clientPid, uid_t clientUid,
int servicePid) :
CameraService::BasicClient(cameraService,
IInterface::asBinder(cameraClient),
- clientPackageName,
+ clientPackageName, clientFeatureId,
cameraIdStr, cameraFacing,
clientPid, clientUid,
servicePid),
@@ -2365,16 +2734,24 @@
CameraService::BasicClient::BasicClient(const sp<CameraService>& cameraService,
const sp<IBinder>& remoteCallback,
- const String16& clientPackageName,
+ const String16& clientPackageName, const std::unique_ptr<String16>& clientFeatureId,
const String8& cameraIdStr, int cameraFacing,
int clientPid, uid_t clientUid,
int servicePid):
mCameraIdStr(cameraIdStr), mCameraFacing(cameraFacing),
- mClientPackageName(clientPackageName), mClientPid(clientPid), mClientUid(clientUid),
+ mClientPackageName(clientPackageName),
+ mClientPid(clientPid), mClientUid(clientUid),
mServicePid(servicePid),
mDisconnected(false),
+ mAudioRestriction(hardware::camera2::ICameraDeviceUser::AUDIO_RESTRICTION_NONE),
mRemoteBinder(remoteCallback)
{
+ if (clientFeatureId) {
+ mClientFeatureId = std::unique_ptr<String16>(new String16(*clientFeatureId));
+ } else {
+ mClientFeatureId = std::unique_ptr<String16>();
+ }
+
if (sCameraService == nullptr) {
sCameraService = cameraService;
}
@@ -2411,7 +2788,7 @@
}
mClientPackageName = packages[0];
}
- if (!hardware::IPCThreadState::self()->isServingCall()) {
+ if (getCurrentServingCall() != BinderCallType::HWBINDER) {
mAppOpsManager = std::make_unique<AppOpsManager>();
}
}
@@ -2476,6 +2853,35 @@
return level == API_2;
}
+status_t CameraService::BasicClient::setAudioRestriction(int32_t mode) {
+ {
+ Mutex::Autolock l(mAudioRestrictionLock);
+ mAudioRestriction = mode;
+ }
+ sCameraService->updateAudioRestriction();
+ return OK;
+}
+
+int32_t CameraService::BasicClient::getServiceAudioRestriction() const {
+ return sCameraService->updateAudioRestriction();
+}
+
+int32_t CameraService::BasicClient::getAudioRestriction() const {
+ Mutex::Autolock l(mAudioRestrictionLock);
+ return mAudioRestriction;
+}
+
+bool CameraService::BasicClient::isValidAudioRestriction(int32_t mode) {
+ switch (mode) {
+ case hardware::camera2::ICameraDeviceUser::AUDIO_RESTRICTION_NONE:
+ case hardware::camera2::ICameraDeviceUser::AUDIO_RESTRICTION_VIBRATION:
+ case hardware::camera2::ICameraDeviceUser::AUDIO_RESTRICTION_VIBRATION_SOUND:
+ return true;
+ default:
+ return false;
+ }
+}
+
status_t CameraService::BasicClient::startCameraOps() {
ATRACE_CALL();
@@ -2489,8 +2895,9 @@
int32_t res;
mAppOpsManager->startWatchingMode(AppOpsManager::OP_CAMERA,
mClientPackageName, mOpsCallback);
- res = mAppOpsManager->startOpNoThrow(AppOpsManager::OP_CAMERA,
- mClientUid, mClientPackageName, /*startIfModeDefault*/ false);
+ 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",
@@ -2535,7 +2942,7 @@
// Notify app ops that the camera is available again
if (mAppOpsManager != nullptr) {
mAppOpsManager->finishOp(AppOpsManager::OP_CAMERA, mClientUid,
- mClientPackageName);
+ mClientPackageName, mClientFeatureId);
mOpsActive = false;
}
// This function is called when a client disconnects. This should
@@ -2575,6 +2982,7 @@
if (mAppOpsManager == nullptr) {
return;
}
+ // TODO : add offline camera session case
if (op != AppOpsManager::OP_CAMERA) {
ALOGW("Unexpected app ops notification received: %d", op);
return;
@@ -2652,14 +3060,13 @@
void CameraService::UidPolicy::registerSelf() {
Mutex::Autolock _l(mUidLock);
- ActivityManager am;
if (mRegistered) return;
- am.registerUidObserver(this, ActivityManager::UID_OBSERVER_GONE
+ status_t res = mAm.linkToDeath(this);
+ mAm.registerUidObserver(this, ActivityManager::UID_OBSERVER_GONE
| ActivityManager::UID_OBSERVER_IDLE
| ActivityManager::UID_OBSERVER_ACTIVE | ActivityManager::UID_OBSERVER_PROCSTATE,
ActivityManager::PROCESS_STATE_UNKNOWN,
String16("cameraserver"));
- status_t res = am.linkToDeath(this);
if (res == OK) {
mRegistered = true;
ALOGV("UidPolicy: Registered with ActivityManager");
@@ -2669,9 +3076,8 @@
void CameraService::UidPolicy::unregisterSelf() {
Mutex::Autolock _l(mUidLock);
- ActivityManager am;
- am.unregisterUidObserver(this);
- am.unlinkToDeath(this);
+ mAm.unregisterUidObserver(this);
+ mAm.unlinkToDeath(this);
mRegistered = false;
mActiveUids.clear();
ALOGV("UidPolicy: Unregistered with ActivityManager");
@@ -2703,7 +3109,7 @@
}
void CameraService::UidPolicy::onUidStateChanged(uid_t uid, int32_t procState,
- int64_t /*procStateSeq*/) {
+ int64_t procStateSeq __unused, int32_t capability __unused) {
bool procStateChange = false;
{
Mutex::Autolock _l(mUidLock);
@@ -2867,10 +3273,9 @@
if (mRegistered) {
return;
}
- SensorPrivacyManager spm;
- spm.addSensorPrivacyListener(this);
- mSensorPrivacyEnabled = spm.isSensorPrivacyEnabled();
- status_t res = spm.linkToDeath(this);
+ mSpm.addSensorPrivacyListener(this);
+ mSensorPrivacyEnabled = mSpm.isSensorPrivacyEnabled();
+ status_t res = mSpm.linkToDeath(this);
if (res == OK) {
mRegistered = true;
ALOGV("SensorPrivacyPolicy: Registered with SensorPrivacyManager");
@@ -2879,9 +3284,8 @@
void CameraService::SensorPrivacyPolicy::unregisterSelf() {
Mutex::Autolock _l(mSensorPrivacyLock);
- SensorPrivacyManager spm;
- spm.removeSensorPrivacyListener(this);
- spm.unlinkToDeath(this);
+ mSpm.removeSensorPrivacyListener(this);
+ mSpm.unlinkToDeath(this);
mRegistered = false;
ALOGV("SensorPrivacyPolicy: Unregistered with SensorPrivacyManager");
}
@@ -2917,9 +3321,9 @@
// ----------------------------------------------------------------------------
CameraService::CameraState::CameraState(const String8& id, int cost,
- const std::set<String8>& conflicting, bool isHidden) : mId(id),
+ const std::set<String8>& conflicting, SystemCameraKind systemCameraKind) : mId(id),
mStatus(StatusInternal::NOT_PRESENT), mCost(cost), mConflicting(conflicting),
- mIsPublicallyHiddenSecureCamera(isHidden) {}
+ mSystemCameraKind(systemCameraKind) {}
CameraService::CameraState::~CameraState() {}
@@ -2928,6 +3332,12 @@
return mStatus;
}
+std::vector<String8> CameraService::CameraState::getUnavailablePhysicalIds() const {
+ Mutex::Autolock lock(mStatusLock);
+ std::vector<String8> res(mUnavailablePhysicalIds.begin(), mUnavailablePhysicalIds.end());
+ return res;
+}
+
CameraParameters CameraService::CameraState::getShimParams() const {
return mShimParams;
}
@@ -2948,8 +3358,20 @@
return mId;
}
-bool CameraService::CameraState::isPublicallyHiddenSecureCamera() const {
- return mIsPublicallyHiddenSecureCamera;
+SystemCameraKind CameraService::CameraState::getSystemCameraKind() const {
+ return mSystemCameraKind;
+}
+
+bool CameraService::CameraState::addUnavailablePhysicalId(const String8& physicalId) {
+ Mutex::Autolock lock(mStatusLock);
+ auto result = mUnavailablePhysicalIds.insert(physicalId);
+ return result.second;
+}
+
+bool CameraService::CameraState::removeUnavailablePhysicalId(const String8& physicalId) {
+ Mutex::Autolock lock(mStatusLock);
+ auto count = mUnavailablePhysicalIds.erase(physicalId);
+ return count > 0;
}
// ----------------------------------------------------------------------------
@@ -3044,7 +3466,7 @@
const std::set<String8>& conflictingKeys, int32_t score, int32_t ownerId,
int32_t state) {
- bool isVendorClient = hardware::IPCThreadState::self()->isServingCall();
+ bool isVendorClient = getCurrentServingCall() == BinderCallType::HWBINDER;
int32_t score_adj = isVendorClient ? kVendorClientScore : score;
int32_t state_adj = isVendorClient ? kVendorClientState: state;
@@ -3080,7 +3502,7 @@
status_t CameraService::dump(int fd, const Vector<String16>& args) {
ATRACE_CALL();
- if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
+ if (checkCallingPermission(sDumpPermission) == false) {
dprintf(fd, "Permission Denial: can't dump CameraService from pid=%d, uid=%d\n",
CameraThreadState::getCallingPid(),
CameraThreadState::getCallingUid());
@@ -3104,6 +3526,8 @@
dprintf(fd, "\n== Service global info: ==\n\n");
dprintf(fd, "Number of camera devices: %d\n", mNumberOfCameras);
dprintf(fd, "Number of normal camera devices: %zu\n", mNormalDeviceIds.size());
+ dprintf(fd, "Number of public camera devices visible to API1: %zu\n",
+ mNormalDeviceIdsWithoutSystemCamera.size());
for (size_t i = 0; i < mNormalDeviceIds.size(); i++) {
dprintf(fd, " Device %zu maps to \"%s\"\n", i, mNormalDeviceIds[i].c_str());
}
@@ -3287,10 +3711,28 @@
cameraId.string());
return;
}
- bool isHidden = isPublicallyHiddenSecureCamera(cameraId);
+
+ // Avoid calling getSystemCameraKind() with mStatusListenerLock held (b/141756275)
+ SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
+ if (getSystemCameraKind(cameraId, &deviceKind) != OK) {
+ ALOGE("%s: Invalid camera id %s, skipping", __FUNCTION__, cameraId.string());
+ return;
+ }
+ bool supportsHAL3 = false;
+ // supportsCameraApi also holds mInterfaceMutex, we can't call it in the
+ // HIDL onStatusChanged wrapper call (we'll hold mStatusListenerLock and
+ // mInterfaceMutex together, which can lead to deadlocks)
+ binder::Status sRet =
+ supportsCameraApi(String16(cameraId), hardware::ICameraService::API_VERSION_2,
+ &supportsHAL3);
+ if (!sRet.isOk()) {
+ ALOGW("%s: Failed to determine if device supports HAL3 %s, supportsCameraApi call failed",
+ __FUNCTION__, cameraId.string());
+ return;
+ }
// Update the status for this camera state, then send the onStatusChangedCallbacks to each
- // of the listeners with both the mStatusStatus and mStatusListenerLock held
- state->updateStatus(status, cameraId, rejectSourceStates, [this,&isHidden]
+ // of the listeners with both the mStatusLock and mStatusListenerLock held
+ state->updateStatus(status, cameraId, rejectSourceStates, [this, &deviceKind, &supportsHAL3]
(const String8& cameraId, StatusInternal status) {
if (status != StatusInternal::ENUMERATING) {
@@ -3311,13 +3753,18 @@
Mutex::Autolock lock(mStatusListenerLock);
+ notifyPhysicalCameraStatusLocked(mapToInterface(status), cameraId);
+
for (auto& listener : mListenerList) {
- if (!listener.first && isHidden) {
- ALOGV("Skipping camera discovery callback for system-only camera %s",
- cameraId.c_str());
+ bool isVendorListener = listener->isVendorListener();
+ if (shouldSkipStatusUpdates(deviceKind, isVendorListener,
+ listener->getListenerPid(), listener->getListenerUid()) ||
+ (isVendorListener && !supportsHAL3)) {
+ ALOGV("Skipping discovery callback for system-only camera/HAL1 device %s",
+ cameraId.c_str());
continue;
}
- listener.second->getListener()->onStatusChanged(mapToInterface(status),
+ listener->getListener()->onStatusChanged(mapToInterface(status),
String16(cameraId));
}
});
@@ -3328,16 +3775,16 @@
Mutex::Autolock lock(mStatusListenerLock);
for (const auto& it : mListenerList) {
- if (!it.second->isOpenCloseCallbackAllowed()) {
+ if (!it->isOpenCloseCallbackAllowed()) {
continue;
}
binder::Status ret;
String16 cameraId64(cameraId);
if (open) {
- ret = it.second->getListener()->onCameraOpened(cameraId64, clientPackageName);
+ ret = it->getListener()->onCameraOpened(cameraId64, clientPackageName);
} else {
- ret = it.second->getListener()->onCameraClosed(cameraId64);
+ ret = it->getListener()->onCameraClosed(cameraId64);
}
if (!ret.isOk()) {
ALOGE("%s: Failed to trigger onCameraOpened/onCameraClosed callback: %d", __FUNCTION__,
@@ -3424,6 +3871,28 @@
return OK;
}
+void CameraService::notifyPhysicalCameraStatusLocked(int32_t status, const String8& cameraId) {
+ Mutex::Autolock lock(mCameraStatesLock);
+ for (const auto& state : mCameraStates) {
+ std::vector<std::string> physicalCameraIds;
+ if (!mCameraProviderManager->isLogicalCamera(state.first.c_str(), &physicalCameraIds)) {
+ // This is not a logical multi-camera.
+ continue;
+ }
+ if (std::find(physicalCameraIds.begin(), physicalCameraIds.end(), cameraId.c_str())
+ == physicalCameraIds.end()) {
+ // cameraId is not a physical camera of this logical multi-camera.
+ continue;
+ }
+
+ String16 id16(state.first), physicalId16(cameraId);
+ for (auto& listener : mListenerList) {
+ listener->getListener()->onPhysicalCameraStatusChanged(status,
+ id16, physicalId16);
+ }
+ }
+}
+
void CameraService::blockClientsForUid(uid_t uid) {
const auto clients = mActiveClientManager.getAll();
for (auto& current : clients) {
@@ -3462,6 +3931,10 @@
return handleResetUidState(args, err);
} else if (args.size() >= 2 && args[0] == String16("get-uid-state")) {
return handleGetUidState(args, out, err);
+ } else if (args.size() >= 2 && args[0] == String16("set-rotate-and-crop")) {
+ return handleSetRotateAndCrop(args);
+ } else if (args.size() >= 1 && args[0] == String16("get-rotate-and-crop")) {
+ return handleGetRotateAndCrop(out);
} else if (args.size() == 1 && args[0] == String16("help")) {
printHelp(out);
return NO_ERROR;
@@ -3532,12 +4005,65 @@
}
}
+status_t CameraService::handleSetRotateAndCrop(const Vector<String16>& args) {
+ int rotateValue = atoi(String8(args[1]));
+ if (rotateValue < ANDROID_SCALER_ROTATE_AND_CROP_NONE ||
+ rotateValue > ANDROID_SCALER_ROTATE_AND_CROP_AUTO) return BAD_VALUE;
+ Mutex::Autolock lock(mServiceLock);
+
+ mOverrideRotateAndCropMode = rotateValue;
+
+ if (rotateValue == ANDROID_SCALER_ROTATE_AND_CROP_AUTO) return OK;
+
+ const auto clients = mActiveClientManager.getAll();
+ for (auto& current : clients) {
+ if (current != nullptr) {
+ const auto basicClient = current->getValue();
+ if (basicClient.get() != nullptr) {
+ basicClient->setRotateAndCropOverride(rotateValue);
+ }
+ }
+ }
+
+ return OK;
+}
+
+status_t CameraService::handleGetRotateAndCrop(int out) {
+ Mutex::Autolock lock(mServiceLock);
+
+ return dprintf(out, "rotateAndCrop override: %d\n", mOverrideRotateAndCropMode);
+}
+
status_t CameraService::printHelp(int out) {
return dprintf(out, "Camera service commands:\n"
" get-uid-state <PACKAGE> [--user USER_ID] gets the uid state\n"
" set-uid-state <PACKAGE> <active|idle> [--user USER_ID] overrides the uid state\n"
" reset-uid-state <PACKAGE> [--user USER_ID] clears the uid state override\n"
+ " set-rotate-and-crop <ROTATION> overrides the rotate-and-crop value for AUTO backcompat\n"
+ " Valid values 0=0 deg, 1=90 deg, 2=180 deg, 3=270 deg, 4=No override\n"
+ " get-rotate-and-crop returns the current override rotate-and-crop value\n"
" help print this message\n");
}
+int32_t CameraService::updateAudioRestriction() {
+ Mutex::Autolock lock(mServiceLock);
+ return updateAudioRestrictionLocked();
+}
+
+int32_t CameraService::updateAudioRestrictionLocked() {
+ int32_t mode = 0;
+ // iterate through all active client
+ for (const auto& i : mActiveClientManager.getAll()) {
+ const auto clientSp = i->getValue();
+ mode |= clientSp->getAudioRestriction();
+ }
+
+ bool modeChanged = (mAudioRestriction != mode);
+ mAudioRestriction = mode;
+ if (modeChanged) {
+ mAppOps.setCameraAudioRestriction(mode);
+ }
+ return mode;
+}
+
}; // namespace android
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index bcaca9f..1adf15a 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -25,17 +25,20 @@
#include <cutils/multiuser.h>
#include <utils/Vector.h>
#include <utils/KeyedVector.h>
+#include <binder/ActivityManager.h>
#include <binder/AppOpsManager.h>
#include <binder/BinderService.h>
#include <binder/IAppOpsCallback.h>
#include <binder/IUidObserver.h>
#include <hardware/camera.h>
+#include <sensorprivacy/SensorPrivacyManager.h>
#include <android/hardware/camera/common/1.0/types.h>
#include <camera/VendorTagDescriptor.h>
#include <camera/CaptureResult.h>
#include <camera/CameraParameters.h>
+#include <camera/camera2/ConcurrentCamera.h>
#include "CameraFlashlight.h"
@@ -67,9 +70,11 @@
{
friend class BinderService<CameraService>;
friend class CameraClient;
+ friend class CameraOfflineSessionClient;
public:
class Client;
class BasicClient;
+ class OfflineClient;
// The effective API level. The Camera2 API running in LEGACY mode counts as API_1.
enum apiLevel {
@@ -100,6 +105,9 @@
virtual void onDeviceStatusChanged(const String8 &cameraId,
hardware::camera::common::V1_0::CameraDeviceStatus newHalStatus) override;
+ virtual void onDeviceStatusChanged(const String8 &cameraId,
+ const String8 &physicalCameraId,
+ hardware::camera::common::V1_0::CameraDeviceStatus newHalStatus) override;
virtual void onTorchStatusChanged(const String8& cameraId,
hardware::camera::common::V1_0::TorchModeStatus newStatus) override;
virtual void onNewProviderRegistered() override;
@@ -133,7 +141,8 @@
virtual binder::Status connectDevice(
const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb, const String16& cameraId,
- const String16& clientPackageName, int32_t clientUid,
+ const String16& clientPackageName, const std::unique_ptr<String16>& clientFeatureId,
+ int32_t clientUid,
/*out*/
sp<hardware::camera2::ICameraDeviceUser>* device);
@@ -143,6 +152,14 @@
virtual binder::Status removeListener(
const sp<hardware::ICameraServiceListener>& listener);
+ virtual binder::Status getConcurrentCameraIds(
+ /*out*/
+ std::vector<hardware::camera2::utils::ConcurrentCameraIdCombination>* concurrentCameraIds);
+
+ virtual binder::Status isConcurrentSessionConfigurationSupported(
+ const std::vector<hardware::camera2::utils::CameraIdAndSessionConfiguration>& sessions,
+ /*out*/bool* supported);
+
virtual binder::Status getLegacyParameters(
int32_t cameraId,
/*out*/
@@ -182,6 +199,9 @@
// Monitored UIDs availability notification
void notifyMonitoredUids();
+ // Register an offline client for a given active camera id
+ status_t addOfflineClient(String8 cameraId, sp<BasicClient> offlineClient);
+
/////////////////////////////////////////////////////////////////////
// Client functionality
@@ -257,10 +277,28 @@
// Block the client form using the camera
virtual void block();
+
+ // set audio restriction from client
+ // Will call into camera service and hold mServiceLock
+ virtual status_t setAudioRestriction(int32_t mode);
+
+ // Get current global audio restriction setting
+ // Will call into camera service and hold mServiceLock
+ virtual int32_t getServiceAudioRestriction() const;
+
+ // Get current audio restriction setting for this client
+ virtual int32_t getAudioRestriction() const;
+
+ static bool isValidAudioRestriction(int32_t mode);
+
+ // Override rotate-and-crop AUTO behavior
+ virtual status_t setRotateAndCropOverride(uint8_t rotateAndCrop) = 0;
+
protected:
BasicClient(const sp<CameraService>& cameraService,
const sp<IBinder>& remoteCallback,
const String16& clientPackageName,
+ const std::unique_ptr<String16>& clientFeatureId,
const String8& cameraIdStr,
int cameraFacing,
int clientPid,
@@ -280,19 +318,22 @@
const String8 mCameraIdStr;
const int mCameraFacing;
String16 mClientPackageName;
+ std::unique_ptr<String16> mClientFeatureId;
pid_t mClientPid;
const uid_t mClientUid;
const pid_t mServicePid;
bool mDisconnected;
+ mutable Mutex mAudioRestrictionLock;
+ int32_t mAudioRestriction;
+
// - The app-side Binder interface to receive callbacks from us
sp<IBinder> mRemoteBinder; // immutable after constructor
// permissions management
- status_t startCameraOps();
- status_t finishCameraOps();
+ virtual status_t startCameraOps();
+ virtual status_t finishCameraOps();
- private:
std::unique_ptr<AppOpsManager> mAppOpsManager = nullptr;
class OpsCallback : public BnAppOpsCallback {
@@ -348,6 +389,7 @@
Client(const sp<CameraService>& cameraService,
const sp<hardware::ICameraClient>& cameraClient,
const String16& clientPackageName,
+ const std::unique_ptr<String16>& clientFeatureId,
const String8& cameraIdStr,
int api1CameraId,
int cameraFacing,
@@ -438,6 +480,9 @@
}; // class CameraClientManager
+ int32_t updateAudioRestriction();
+ int32_t updateAudioRestrictionLocked();
+
private:
typedef hardware::camera::common::V1_0::CameraDeviceStatus CameraDeviceStatus;
@@ -471,7 +516,7 @@
* returned in the HAL's camera_info struct for each device.
*/
CameraState(const String8& id, int cost, const std::set<String8>& conflicting,
- bool isHidden);
+ SystemCameraKind deviceKind);
virtual ~CameraState();
/**
@@ -524,18 +569,31 @@
String8 getId() const;
/**
- * Return if the camera device is a publically hidden secure camera
+ * Return the kind (SystemCameraKind) of this camera device.
*/
- bool isPublicallyHiddenSecureCamera() const;
+ SystemCameraKind getSystemCameraKind() const;
+ /**
+ * Add/Remove the unavailable physical camera ID.
+ */
+ bool addUnavailablePhysicalId(const String8& physicalId);
+ bool removeUnavailablePhysicalId(const String8& physicalId);
+
+ /**
+ * Return the unavailable physical ids for this device.
+ *
+ * This method acquires mStatusLock.
+ */
+ std::vector<String8> getUnavailablePhysicalIds() const;
private:
const String8 mId;
StatusInternal mStatus; // protected by mStatusLock
const int mCost;
std::set<String8> mConflicting;
+ std::set<String8> mUnavailablePhysicalIds;
mutable Mutex mStatusLock;
CameraParameters mShimParams;
- const bool mIsPublicallyHiddenSecureCamera;
+ const SystemCameraKind mSystemCameraKind;
}; // class CameraState
// Observer for UID lifecycle enforcing that UIDs in idle
@@ -554,7 +612,8 @@
void onUidGone(uid_t uid, bool disabled);
void onUidActive(uid_t uid);
void onUidIdle(uid_t uid, bool disabled);
- void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq);
+ void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq,
+ int32_t capability);
void addOverrideUid(uid_t uid, String16 callingPackage, bool active);
void removeOverrideUid(uid_t uid, String16 callingPackage);
@@ -571,6 +630,7 @@
Mutex mUidLock;
bool mRegistered;
+ ActivityManager mAm;
wp<CameraService> mService;
std::unordered_set<uid_t> mActiveUids;
// Monitored uid map to cached procState and refCount pair
@@ -597,6 +657,7 @@
virtual void binderDied(const wp<IBinder> &who);
private:
+ SensorPrivacyManager mSpm;
wp<CameraService> mService;
Mutex mSensorPrivacyLock;
bool mSensorPrivacyEnabled;
@@ -638,18 +699,36 @@
sp<BasicClient>* client,
std::shared_ptr<resource_policy::ClientDescriptor<String8, sp<BasicClient>>>* partial);
- // Should an operation attempt on a cameraId be rejected, if the camera id is
- // advertised as a publically hidden secure camera, by the camera HAL ?
- bool shouldRejectHiddenCameraConnection(const String8& cameraId);
+ // Should an operation attempt on a cameraId be rejected ? (this can happen
+ // under various conditions. For example if a camera device is advertised as
+ // system only or hidden secure camera, amongst possible others.
+ bool shouldRejectSystemCameraConnection(const String8 & cameraId) const;
- bool isPublicallyHiddenSecureCamera(const String8& cameraId);
+ // Should a device status update be skipped for a particular camera device ? (this can happen
+ // under various conditions. For example if a camera device is advertised as
+ // system only or hidden secure camera, amongst possible others.
+ static bool shouldSkipStatusUpdates(SystemCameraKind systemCameraKind, bool isVendorListener,
+ int clientPid, int clientUid);
+
+ // Gets the kind of camera device (i.e public, hidden secure or system only)
+ // getSystemCameraKind() needs mInterfaceMutex which might lead to deadlocks
+ // if held along with mStatusListenerLock (depending on lock ordering, b/141756275), it is
+ // recommended that we don't call this function with mStatusListenerLock held.
+ status_t getSystemCameraKind(const String8& cameraId, SystemCameraKind *kind) const;
+
+ // Update the set of API1Compatible camera devices without including system
+ // cameras and secure cameras. This is used for hiding system only cameras
+ // from clients using camera1 api and not having android.permission.SYSTEM_CAMERA.
+ // This function expects @param normalDeviceIds, to have normalDeviceIds
+ // sorted in alpha-numeric order.
+ void filterAPI1SystemCameraLocked(const std::vector<std::string> &normalDeviceIds);
// Single implementation shared between the various connect calls
template<class CALLBACK, class CLIENT>
binder::Status connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
int api1CameraId, int halVersion, const String16& clientPackageName,
- int clientUid, int clientPid, apiLevel effectiveApiLevel, bool shimUpdateOnly,
- /*out*/sp<CLIENT>& device);
+ const std::unique_ptr<String16>& clientFeatureId, int clientUid, int clientPid,
+ apiLevel effectiveApiLevel, bool shimUpdateOnly, /*out*/sp<CLIENT>& device);
// Lock guarding camera service state
Mutex mServiceLock;
@@ -746,6 +825,17 @@
void logDisconnected(const char* cameraId, int clientPid, const char* clientPackage);
/**
+ * Add an event log message that a client has been disconnected from offline device.
+ */
+ void logDisconnectedOffline(const char* cameraId, int clientPid, const char* clientPackage);
+
+ /**
+ * Add an event log message that an offline client has been connected.
+ */
+ void logConnectedOffline(const char* cameraId, int clientPid,
+ const char* clientPackage);
+
+ /**
* Add an event log message that a client has been connected.
*/
void logConnected(const char* cameraId, int clientPid, const char* clientPackage);
@@ -798,9 +888,14 @@
*/
void updateCameraNumAndIds();
+ // Number of camera devices (excluding hidden secure cameras)
int mNumberOfCameras;
+ // Number of camera devices (excluding hidden secure cameras and
+ // system cameras)
+ int mNumberOfCamerasWithoutSystemCamera;
std::vector<std::string> mNormalDeviceIds;
+ std::vector<std::string> mNormalDeviceIdsWithoutSystemCamera;
// sounds
sp<MediaPlayer> newMediaPlayer(const char *file);
@@ -817,9 +912,10 @@
class ServiceListener : public virtual IBinder::DeathRecipient {
public:
ServiceListener(sp<CameraService> parent, sp<hardware::ICameraServiceListener> listener,
- int uid, int pid, bool openCloseCallbackAllowed) : mParent(parent),
- mListener(listener), mListenerUid(uid), mListenerPid(pid),
- mOpenCloseCallbackAllowed(openCloseCallbackAllowed) {}
+ int uid, int pid, bool isVendorClient, bool openCloseCallbackAllowed)
+ : mParent(parent), mListener(listener), mListenerUid(uid), mListenerPid(pid),
+ mIsVendorListener(isVendorClient),
+ mOpenCloseCallbackAllowed(openCloseCallbackAllowed) { }
status_t initialize() {
return IInterface::asBinder(mListener)->linkToDeath(this);
@@ -835,18 +931,20 @@
int getListenerUid() { return mListenerUid; }
int getListenerPid() { return mListenerPid; }
sp<hardware::ICameraServiceListener> getListener() { return mListener; }
+ bool isVendorListener() { return mIsVendorListener; }
bool isOpenCloseCallbackAllowed() { return mOpenCloseCallbackAllowed; }
private:
wp<CameraService> mParent;
sp<hardware::ICameraServiceListener> mListener;
- int mListenerUid;
- int mListenerPid;
+ int mListenerUid = -1;
+ int mListenerPid = -1;
+ bool mIsVendorListener = false;
bool mOpenCloseCallbackAllowed = false;
};
// Guarded by mStatusListenerMutex
- std::vector<std::pair<bool, sp<ServiceListener>>> mListenerList;
+ std::vector<sp<ServiceListener>> mListenerList;
Mutex mStatusListenerLock;
@@ -905,6 +1003,9 @@
status_t setTorchStatusLocked(const String8 &cameraId,
hardware::camera::common::V1_0::TorchModeStatus status);
+ // notify physical camera status when the physical camera is public.
+ void notifyPhysicalCameraStatusLocked(int32_t status, const String8& cameraId);
+
// IBinder::DeathRecipient implementation
virtual void binderDied(const wp<IBinder> &who);
@@ -938,6 +1039,12 @@
// Gets the UID state
status_t handleGetUidState(const Vector<String16>& args, int out, int err);
+ // Set the rotate-and-crop AUTO override behavior
+ status_t handleSetRotateAndCrop(const Vector<String16>& args);
+
+ // Get the rotate-and-crop AUTO override behavior
+ status_t handleGetRotateAndCrop(int out);
+
// Prints the shell command help
status_t printHelp(int out);
@@ -947,9 +1054,10 @@
static String8 getFormattedCurrentTime();
static binder::Status makeClient(const sp<CameraService>& cameraService,
- const sp<IInterface>& cameraCb, const String16& packageName, const String8& cameraId,
- int api1CameraId, int facing, int clientPid, uid_t clientUid, int servicePid,
- int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
+ const sp<IInterface>& cameraCb, const String16& packageName,
+ const std::unique_ptr<String16>& featureId, const String8& cameraId, int api1CameraId,
+ int facing, int clientPid, uid_t clientUid, int servicePid, int halVersion,
+ int deviceVersion, apiLevel effectiveApiLevel,
/*out*/sp<BasicClient>* client);
status_t checkCameraAccess(const String16& opPackageName);
@@ -969,6 +1077,22 @@
void broadcastTorchModeStatus(const String8& cameraId,
hardware::camera::common::V1_0::TorchModeStatus status);
+
+ void disconnectClient(const String8& id, sp<BasicClient> clientToDisconnect);
+
+ // Regular online and offline devices must not be in conflict at camera service layer.
+ // Use separate keys for offline devices.
+ static const String8 kOfflineDevice;
+
+ // TODO: right now each BasicClient holds one AppOpsManager instance.
+ // We can refactor the code so all of clients share this instance
+ AppOpsManager mAppOps;
+
+ // Aggreated audio restriction mode for all camera clients
+ int32_t mAudioRestriction;
+
+ // Current override rotate-and-crop mode
+ uint8_t mOverrideRotateAndCropMode = ANDROID_SCALER_ROTATE_AND_CROP_AUTO;
};
} // namespace android
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 162b50f..1d62a74 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -50,13 +50,14 @@
Camera2Client::Camera2Client(const sp<CameraService>& cameraService,
const sp<hardware::ICameraClient>& cameraClient,
const String16& clientPackageName,
+ const std::unique_ptr<String16>& clientFeatureId,
const String8& cameraDeviceId,
int api1CameraId,
int cameraFacing,
int clientPid,
uid_t clientUid,
int servicePid):
- Camera2ClientBase(cameraService, cameraClient, clientPackageName,
+ Camera2ClientBase(cameraService, cameraClient, clientPackageName, clientFeatureId,
cameraDeviceId, api1CameraId, cameraFacing,
clientPid, clientUid, servicePid),
mParameters(api1CameraId, cameraFacing)
@@ -959,6 +960,11 @@
case Parameters::RECORD:
case Parameters::PREVIEW:
syncWithDevice();
+ // Due to flush a camera device sync is not a sufficient
+ // guarantee that the current client parameters are
+ // correctly applied. To resolve this wait for the current
+ // request id to return in the results.
+ waitUntilCurrentRequestIdLocked();
res = stopStream();
if (res != OK) {
ALOGE("%s: Camera %d: Can't stop streaming: %s (%d)",
@@ -2253,6 +2259,65 @@
return OK;
}
+status_t Camera2Client::setAudioRestriction(int /*mode*/) {
+ // Empty implementation. setAudioRestriction is hidden interface and not
+ // supported by android.hardware.Camera API
+ return INVALID_OPERATION;
+}
+
+int32_t Camera2Client::getGlobalAudioRestriction() {
+ // Empty implementation. getAudioRestriction is hidden interface and not
+ // supported by android.hardware.Camera API
+ return INVALID_OPERATION;
+}
+
+status_t Camera2Client::setRotateAndCropOverride(uint8_t rotateAndCrop) {
+ if (rotateAndCrop > ANDROID_SCALER_ROTATE_AND_CROP_AUTO) return BAD_VALUE;
+
+ return mDevice->setRotateAndCropAutoBehavior(
+ static_cast<camera_metadata_enum_android_scaler_rotate_and_crop_t>(rotateAndCrop));
+}
+
+status_t Camera2Client::waitUntilCurrentRequestIdLocked() {
+ int32_t activeRequestId = mStreamingProcessor->getActiveRequestId();
+ if (activeRequestId != 0) {
+ auto res = waitUntilRequestIdApplied(activeRequestId,
+ mDevice->getExpectedInFlightDuration());
+ if (res == TIMED_OUT) {
+ ALOGE("%s: Camera %d: Timed out waiting for current request id to return in results!",
+ __FUNCTION__, mCameraId);
+ return res;
+ } else if (res != OK) {
+ ALOGE("%s: Camera %d: Error while waiting for current request id to return in results!",
+ __FUNCTION__, mCameraId);
+ return res;
+ }
+ }
+
+ return OK;
+}
+
+status_t Camera2Client::waitUntilRequestIdApplied(int32_t requestId, nsecs_t timeout) {
+ Mutex::Autolock l(mLatestRequestMutex);
+ while (mLatestRequestId != requestId) {
+ nsecs_t startTime = systemTime();
+
+ auto res = mLatestRequestSignal.waitRelative(mLatestRequestMutex, timeout);
+ if (res != OK) return res;
+
+ timeout -= (systemTime() - startTime);
+ }
+
+ return OK;
+}
+
+void Camera2Client::notifyRequestId(int32_t requestId) {
+ Mutex::Autolock al(mLatestRequestMutex);
+
+ mLatestRequestId = requestId;
+ mLatestRequestSignal.signal();
+}
+
const char* Camera2Client::kAutofocusLabel = "autofocus";
const char* Camera2Client::kTakepictureLabel = "take_picture";
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index a9ea271..3144e0e 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -83,6 +83,9 @@
virtual void notifyError(int32_t errorCode,
const CaptureResultExtras& resultExtras);
virtual status_t setVideoTarget(const sp<IGraphicBufferProducer>& bufferProducer);
+ virtual status_t setAudioRestriction(int mode);
+ virtual int32_t getGlobalAudioRestriction();
+ virtual status_t setRotateAndCropOverride(uint8_t rotateAndCrop);
/**
* Interface used by CameraService
@@ -91,6 +94,7 @@
Camera2Client(const sp<CameraService>& cameraService,
const sp<hardware::ICameraClient>& cameraClient,
const String16& clientPackageName,
+ const std::unique_ptr<String16>& clientFeatureId,
const String8& cameraDeviceId,
int api1CameraId,
int cameraFacing,
@@ -122,6 +126,8 @@
camera2::SharedParameters& getParameters();
+ void notifyRequestId(int32_t requestId);
+
int getPreviewStreamId() const;
int getCaptureStreamId() const;
int getCallbackStreamId() const;
@@ -227,6 +233,12 @@
status_t initializeImpl(TProviderPtr providerPtr, const String8& monitorTags);
bool isZslEnabledInStillTemplate();
+
+ mutable Mutex mLatestRequestMutex;
+ Condition mLatestRequestSignal;
+ int32_t mLatestRequestId = -1;
+ status_t waitUntilRequestIdApplied(int32_t requestId, nsecs_t timeout);
+ status_t waitUntilCurrentRequestIdLocked();
};
}; // namespace android
diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
index d65ac7b..892996c 100644
--- a/services/camera/libcameraservice/api1/CameraClient.cpp
+++ b/services/camera/libcameraservice/api1/CameraClient.cpp
@@ -34,11 +34,11 @@
CameraClient::CameraClient(const sp<CameraService>& cameraService,
const sp<hardware::ICameraClient>& cameraClient,
- const String16& clientPackageName,
+ const String16& clientPackageName, const std::unique_ptr<String16>& clientFeatureId,
int cameraId, int cameraFacing,
int clientPid, int clientUid,
int servicePid):
- Client(cameraService, cameraClient, clientPackageName,
+ Client(cameraService, cameraClient, clientPackageName, clientFeatureId,
String8::format("%d", cameraId), cameraId, cameraFacing, clientPid,
clientUid, servicePid)
{
@@ -534,7 +534,7 @@
}
if (mHardware != nullptr) {
- VideoNativeHandleMetadata *metadata = (VideoNativeHandleMetadata*)(dataPtr->pointer());
+ VideoNativeHandleMetadata *metadata = (VideoNativeHandleMetadata*)(dataPtr->unsecurePointer());
metadata->eType = kMetadataBufferTypeNativeHandleSource;
metadata->pHandle = handle;
mHardware->releaseRecordingFrame(dataPtr);
@@ -573,7 +573,7 @@
}
if (!disconnected) {
- VideoNativeHandleMetadata *metadata = (VideoNativeHandleMetadata*)(dataPtr->pointer());
+ VideoNativeHandleMetadata *metadata = (VideoNativeHandleMetadata*)(dataPtr->unsecurePointer());
metadata->eType = kMetadataBufferTypeNativeHandleSource;
metadata->pHandle = handle;
frames.push_back(dataPtr);
@@ -916,8 +916,12 @@
ALOGE("%s: dataPtr does not contain VideoNativeHandleMetadata!", __FUNCTION__);
return;
}
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
VideoNativeHandleMetadata *metadata =
- (VideoNativeHandleMetadata*)(msg.dataPtr->pointer());
+ (VideoNativeHandleMetadata*)(msg.dataPtr->unsecurePointer());
if (metadata->eType == kMetadataBufferTypeNativeHandleSource) {
handle = metadata->pHandle;
}
@@ -1073,8 +1077,12 @@
// Check if dataPtr contains a VideoNativeHandleMetadata.
if (dataPtr->size() == sizeof(VideoNativeHandleMetadata)) {
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
VideoNativeHandleMetadata *metadata =
- (VideoNativeHandleMetadata*)(dataPtr->pointer());
+ (VideoNativeHandleMetadata*)(dataPtr->unsecurePointer());
if (metadata->eType == kMetadataBufferTypeNativeHandleSource) {
handle = metadata->pHandle;
}
@@ -1171,4 +1179,30 @@
return INVALID_OPERATION;
}
+status_t CameraClient::setAudioRestriction(int mode) {
+ if (!isValidAudioRestriction(mode)) {
+ ALOGE("%s: invalid audio restriction mode %d", __FUNCTION__, mode);
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock lock(mLock);
+ if (checkPidAndHardware() != NO_ERROR) {
+ return INVALID_OPERATION;
+ }
+ return BasicClient::setAudioRestriction(mode);
+}
+
+int32_t CameraClient::getGlobalAudioRestriction() {
+ Mutex::Autolock lock(mLock);
+ if (checkPidAndHardware() != NO_ERROR) {
+ return INVALID_OPERATION;
+ }
+ return BasicClient::getServiceAudioRestriction();
+}
+
+// API1->Device1 does not support this feature
+status_t CameraClient::setRotateAndCropOverride(uint8_t /*rotateAndCrop*/) {
+ return OK;
+}
+
}; // namespace android
diff --git a/services/camera/libcameraservice/api1/CameraClient.h b/services/camera/libcameraservice/api1/CameraClient.h
index 9530b6c..a7eb960 100644
--- a/services/camera/libcameraservice/api1/CameraClient.h
+++ b/services/camera/libcameraservice/api1/CameraClient.h
@@ -59,11 +59,16 @@
virtual String8 getParameters() const;
virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
virtual status_t setVideoTarget(const sp<IGraphicBufferProducer>& bufferProducer);
+ virtual status_t setAudioRestriction(int mode);
+ virtual int32_t getGlobalAudioRestriction();
+
+ virtual status_t setRotateAndCropOverride(uint8_t override);
// Interface used by CameraService
CameraClient(const sp<CameraService>& cameraService,
const sp<hardware::ICameraClient>& cameraClient,
const String16& clientPackageName,
+ const std::unique_ptr<String16>& clientFeatureId,
int cameraId,
int cameraFacing,
int clientPid,
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
index 88799f9..0c01a91 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
@@ -265,7 +265,7 @@
Mutex::Autolock l(mInputMutex);
while (!mStartCapture) {
res = mStartCaptureSignal.waitRelative(mInputMutex,
- kWaitDuration);
+ kIdleWaitDuration);
if (res == TIMED_OUT) break;
}
if (mStartCapture) {
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
index 727dd53..9475a39 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
@@ -111,6 +111,7 @@
* Internal to CaptureSequencer
*/
static const nsecs_t kWaitDuration = 100000000; // 100 ms
+ static const nsecs_t kIdleWaitDuration = 10000000; // 10 ms
static const int kMaxTimeoutsForPrecaptureStart = 10; // 1 sec
static const int kMaxTimeoutsForPrecaptureEnd = 20; // 2 sec
static const int kMaxTimeoutsForCaptureEnd = 40; // 4 sec
diff --git a/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp b/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp
index 683e84d..2daacd1 100644
--- a/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp
@@ -66,7 +66,7 @@
}
bool FrameProcessor::processSingleFrame(CaptureResult &frame,
- const sp<CameraDeviceBase> &device) {
+ const sp<FrameProducer> &device) {
sp<Camera2Client> client = mClient.promote();
if (!client.get()) {
@@ -86,6 +86,12 @@
process3aState(frame, client);
}
+ if (mCurrentRequestId != frame.mResultExtras.requestId) {
+ mCurrentRequestId = frame.mResultExtras.requestId;
+
+ client->notifyRequestId(mCurrentRequestId);
+ }
+
return FrameProcessorBase::processSingleFrame(frame, device);
}
diff --git a/services/camera/libcameraservice/api1/client2/FrameProcessor.h b/services/camera/libcameraservice/api1/client2/FrameProcessor.h
index 8183c12..bb985f6 100644
--- a/services/camera/libcameraservice/api1/client2/FrameProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/FrameProcessor.h
@@ -24,6 +24,7 @@
#include <utils/List.h>
#include <camera/CameraMetadata.h>
+#include "common/CameraDeviceBase.h"
#include "common/FrameProcessorBase.h"
struct camera_frame_metadata;
@@ -54,7 +55,7 @@
void processNewFrames(const sp<Camera2Client> &client);
virtual bool processSingleFrame(CaptureResult &frame,
- const sp<CameraDeviceBase> &device);
+ const sp<FrameProducer> &device);
status_t processFaceDetect(const CameraMetadata &frame,
const sp<Camera2Client> &client);
@@ -94,6 +95,7 @@
};
AlgState m3aState;
+ int32_t mCurrentRequestId = -1;
// frame number -> pending 3A states that not all data are received yet.
KeyedVector<int32_t, AlgState> mPending3AStates;
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 18addb5..20333d1 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -2454,12 +2454,9 @@
camera_metadata_ro_entry_t availableFocalLengths =
staticInfo(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS, 0, 0, /*required*/false);
- if (!availableFocalLengths.count && !fastInfo.isExternalCamera) return NO_INIT;
// Find focal length in PREVIEW template to use as default focal length.
- if (fastInfo.isExternalCamera) {
- fastInfo.defaultFocalLength = -1.0;
- } else {
+ if (availableFocalLengths.count) {
// Find smallest (widest-angle) focal length to use as basis of still
// picture FOV reporting.
fastInfo.defaultFocalLength = availableFocalLengths.data.f[0];
@@ -2481,6 +2478,10 @@
if (entry.count != 0) {
fastInfo.defaultFocalLength = entry.data.f[0];
}
+ } else if (fastInfo.isExternalCamera) {
+ fastInfo.defaultFocalLength = -1.0;
+ } else {
+ return NO_INIT;
}
return OK;
}
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 3587db3..e35b436 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -54,6 +54,7 @@
const sp<CameraService>& cameraService,
const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
const String16& clientPackageName,
+ const std::unique_ptr<String16>& clientFeatureId,
const String8& cameraId,
int api1CameraId,
int cameraFacing,
@@ -63,6 +64,7 @@
BasicClient(cameraService,
IInterface::asBinder(remoteCallback),
clientPackageName,
+ clientFeatureId,
cameraId,
cameraFacing,
clientPid,
@@ -78,12 +80,13 @@
CameraDeviceClient::CameraDeviceClient(const sp<CameraService>& cameraService,
const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
const String16& clientPackageName,
+ const std::unique_ptr<String16>& clientFeatureId,
const String8& cameraId,
int cameraFacing,
int clientPid,
uid_t clientUid,
int servicePid) :
- Camera2ClientBase(cameraService, remoteCallback, clientPackageName,
+ Camera2ClientBase(cameraService, remoteCallback, clientPackageName, clientFeatureId,
cameraId, /*API1 camera ID*/ -1,
cameraFacing, clientPid, clientUid, servicePid),
mInputStream(),
@@ -114,8 +117,8 @@
threadName = String8::format("CDU-%s-FrameProc", mCameraIdStr.string());
mFrameProcessor->run(threadName.string());
- mFrameProcessor->registerListener(FRAME_PROCESSOR_LISTENER_MIN_ID,
- FRAME_PROCESSOR_LISTENER_MAX_ID,
+ mFrameProcessor->registerListener(camera2::FrameProcessorBase::FRAME_PROCESSOR_LISTENER_MIN_ID,
+ camera2::FrameProcessorBase::FRAME_PROCESSOR_LISTENER_MAX_ID,
/*listener*/this,
/*sendPartials*/true);
@@ -467,7 +470,8 @@
}
binder::Status CameraDeviceClient::endConfigure(int operatingMode,
- const hardware::camera2::impl::CameraMetadataNative& sessionParams) {
+ const hardware::camera2::impl::CameraMetadataNative& sessionParams,
+ std::vector<int>* offlineStreamIds /*out*/) {
ATRACE_CALL();
ALOGV("%s: ending configure (%d input stream, %zu output surfaces)",
__FUNCTION__, mInputStream.configured ? 1 : 0,
@@ -476,13 +480,19 @@
binder::Status res;
if (!(res = checkPidStatus(__FUNCTION__)).isOk()) return res;
+ if (offlineStreamIds == nullptr) {
+ String8 msg = String8::format("Invalid offline stream ids");
+ ALOGE("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+ }
+
Mutex::Autolock icl(mBinderSerializationLock);
if (!mDevice.get()) {
return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
}
- res = checkOperatingModeLocked(operatingMode);
+ res = checkOperatingMode(operatingMode, mDevice->info(), mCameraIdStr);
if (!res.isOk()) {
return res;
}
@@ -499,23 +509,49 @@
ALOGE("%s: %s", __FUNCTION__, msg.string());
res = STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
} else {
+ offlineStreamIds->clear();
+ mDevice->getOfflineStreamIds(offlineStreamIds);
+
for (size_t i = 0; i < mCompositeStreamMap.size(); ++i) {
err = mCompositeStreamMap.valueAt(i)->configureStream();
- if (err != OK ) {
+ if (err != OK) {
String8 msg = String8::format("Camera %s: Error configuring composite "
"streams: %s (%d)", mCameraIdStr.string(), strerror(-err), err);
ALOGE("%s: %s", __FUNCTION__, msg.string());
res = STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
break;
}
+
+ // Composite streams can only support offline mode in case all individual internal
+ // streams are also supported.
+ std::vector<int> internalStreams;
+ mCompositeStreamMap.valueAt(i)->insertCompositeStreamIds(&internalStreams);
+ offlineStreamIds->erase(
+ std::remove_if(offlineStreamIds->begin(), offlineStreamIds->end(),
+ [&internalStreams] (int streamId) {
+ auto it = std::find(internalStreams.begin(), internalStreams.end(),
+ streamId);
+ if (it != internalStreams.end()) {
+ internalStreams.erase(it);
+ return true;
+ }
+
+ return false;}), offlineStreamIds->end());
+ if (internalStreams.empty()) {
+ offlineStreamIds->push_back(mCompositeStreamMap.valueAt(i)->getStreamId());
+ }
+ }
+
+ for (const auto& offlineStreamId : *offlineStreamIds) {
+ mStreamInfoMap[offlineStreamId].supportsOffline = true;
}
}
return res;
}
-binder::Status CameraDeviceClient::checkSurfaceTypeLocked(size_t numBufferProducers,
- bool deferredConsumer, int surfaceType) const {
+binder::Status CameraDeviceClient::checkSurfaceType(size_t numBufferProducers,
+ bool deferredConsumer, int surfaceType) {
if (numBufferProducers > MAX_SURFACES_PER_STREAM) {
ALOGE("%s: GraphicBufferProducer count %zu for stream exceeds limit of %d",
__FUNCTION__, numBufferProducers, MAX_SURFACES_PER_STREAM);
@@ -536,28 +572,27 @@
return binder::Status::ok();
}
-binder::Status CameraDeviceClient::checkPhysicalCameraIdLocked(String8 physicalCameraId) {
- if (physicalCameraId.size() > 0) {
- std::vector<std::string> physicalCameraIds;
- bool logicalCamera =
- mProviderManager->isLogicalCamera(mCameraIdStr.string(), &physicalCameraIds);
- if (!logicalCamera ||
- std::find(physicalCameraIds.begin(), physicalCameraIds.end(),
- physicalCameraId.string()) == physicalCameraIds.end()) {
- String8 msg = String8::format("Camera %s: Camera doesn't support physicalCameraId %s.",
- mCameraIdStr.string(), physicalCameraId.string());
- ALOGE("%s: %s", __FUNCTION__, msg.string());
- return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
- }
+binder::Status CameraDeviceClient::checkPhysicalCameraId(
+ const std::vector<std::string> &physicalCameraIds, const String8 &physicalCameraId,
+ const String8 &logicalCameraId) {
+ if (physicalCameraId.size() == 0) {
+ return binder::Status::ok();
}
-
+ if (std::find(physicalCameraIds.begin(), physicalCameraIds.end(),
+ physicalCameraId.string()) == physicalCameraIds.end()) {
+ String8 msg = String8::format("Camera %s: Camera doesn't support physicalCameraId %s.",
+ logicalCameraId.string(), physicalCameraId.string());
+ ALOGE("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+ }
return binder::Status::ok();
}
-binder::Status CameraDeviceClient::checkOperatingModeLocked(int operatingMode) const {
+binder::Status CameraDeviceClient::checkOperatingMode(int operatingMode,
+ const CameraMetadata &staticInfo, const String8 &cameraId) {
if (operatingMode < 0) {
String8 msg = String8::format(
- "Camera %s: Invalid operating mode %d requested", mCameraIdStr.string(), operatingMode);
+ "Camera %s: Invalid operating mode %d requested", cameraId.string(), operatingMode);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
msg.string());
@@ -565,8 +600,7 @@
bool isConstrainedHighSpeed = (operatingMode == ICameraDeviceUser::CONSTRAINED_HIGH_SPEED_MODE);
if (isConstrainedHighSpeed) {
- CameraMetadata staticInfo = mDevice->info();
- camera_metadata_entry_t entry = staticInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+ camera_metadata_ro_entry_t entry = staticInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
bool isConstrainedHighSpeedSupported = false;
for(size_t i = 0; i < entry.count; ++i) {
uint8_t capability = entry.data.u8[i];
@@ -578,7 +612,7 @@
if (!isConstrainedHighSpeedSupported) {
String8 msg = String8::format(
"Camera %s: Try to create a constrained high speed configuration on a device"
- " that doesn't support it.", mCameraIdStr.string());
+ " that doesn't support it.", cameraId.string());
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
msg.string());
@@ -609,39 +643,31 @@
stream->bufferSize = 0;
}
-binder::Status CameraDeviceClient::isSessionConfigurationSupported(
- const SessionConfiguration& sessionConfiguration, bool *status /*out*/) {
- ATRACE_CALL();
-
- binder::Status res;
- if (!(res = checkPidStatus(__FUNCTION__)).isOk()) return res;
-
- Mutex::Autolock icl(mBinderSerializationLock);
-
- if (!mDevice.get()) {
- return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
- }
-
+binder::Status
+CameraDeviceClient::convertToHALStreamCombination(const SessionConfiguration& sessionConfiguration,
+ const String8 &logicalCameraId, const CameraMetadata &deviceInfo,
+ metadataGetter getMetadata, const std::vector<std::string> &physicalCameraIds,
+ hardware::camera::device::V3_4::StreamConfiguration &streamConfiguration,
+ bool *unsupported) {
auto operatingMode = sessionConfiguration.getOperatingMode();
- res = checkOperatingModeLocked(operatingMode);
+ binder::Status res = checkOperatingMode(operatingMode, deviceInfo, logicalCameraId);
if (!res.isOk()) {
return res;
}
- if (status == nullptr) {
- String8 msg = String8::format( "Camera %s: Invalid status!", mCameraIdStr.string());
+ if (unsupported == nullptr) {
+ String8 msg("unsupported nullptr");
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
-
- hardware::camera::device::V3_4::StreamConfiguration streamConfiguration;
+ *unsupported = false;
auto ret = Camera3Device::mapToStreamConfigurationMode(
static_cast<camera3_stream_configuration_mode_t> (operatingMode),
/*out*/ &streamConfiguration.operationMode);
if (ret != OK) {
String8 msg = String8::format(
- "Camera %s: Failed mapping operating mode %d requested: %s (%d)", mCameraIdStr.string(),
- operatingMode, strerror(-ret), ret);
+ "Camera %s: Failed mapping operating mode %d requested: %s (%d)",
+ logicalCameraId.string(), operatingMode, strerror(-ret), ret);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
msg.string());
@@ -675,12 +701,12 @@
bool isStreamInfoValid = false;
OutputStreamInfo streamInfo;
- res = checkSurfaceTypeLocked(numBufferProducers, deferredConsumer, it.getSurfaceType());
+ res = checkSurfaceType(numBufferProducers, deferredConsumer, it.getSurfaceType());
if (!res.isOk()) {
return res;
}
-
- res = checkPhysicalCameraIdLocked(physicalCameraId);
+ res = checkPhysicalCameraId(physicalCameraIds, physicalCameraId,
+ logicalCameraId);
if (!res.isOk()) {
return res;
}
@@ -706,8 +732,10 @@
for (auto& bufferProducer : bufferProducers) {
sp<Surface> surface;
+ const CameraMetadata &physicalDeviceInfo = getMetadata(physicalCameraId);
res = createSurfaceFromGbp(streamInfo, isStreamInfoValid, surface, bufferProducer,
- physicalCameraId);
+ logicalCameraId,
+ physicalCameraId.size() > 0 ? physicalDeviceInfo : deviceInfo );
if (!res.isOk())
return res;
@@ -723,15 +751,15 @@
std::vector<OutputStreamInfo> compositeStreams;
if (isDepthCompositeStream) {
ret = camera3::DepthCompositeStream::getCompositeStreamInfo(streamInfo,
- mDevice->info(), &compositeStreams);
+ deviceInfo, &compositeStreams);
} else {
ret = camera3::HeicCompositeStream::getCompositeStreamInfo(streamInfo,
- mDevice->info(), &compositeStreams);
+ deviceInfo, &compositeStreams);
}
if (ret != OK) {
String8 msg = String8::format(
"Camera %s: Failed adding composite streams: %s (%d)",
- mCameraIdStr.string(), strerror(-ret), ret);
+ logicalCameraId.string(), strerror(-ret), ret);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
@@ -739,7 +767,7 @@
if (compositeStreams.size() == 0) {
// No internal streams means composite stream not
// supported.
- *status = false;
+ *unsupported = true;
return binder::Status::ok();
} else if (compositeStreams.size() > 1) {
streamCount += compositeStreams.size() - 1;
@@ -760,6 +788,49 @@
}
}
}
+ return binder::Status::ok();
+}
+
+binder::Status CameraDeviceClient::isSessionConfigurationSupported(
+ const SessionConfiguration& sessionConfiguration, bool *status /*out*/) {
+ ATRACE_CALL();
+
+ binder::Status res;
+ status_t ret = OK;
+ if (!(res = checkPidStatus(__FUNCTION__)).isOk()) return res;
+
+ Mutex::Autolock icl(mBinderSerializationLock);
+
+ if (!mDevice.get()) {
+ return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
+ }
+
+ auto operatingMode = sessionConfiguration.getOperatingMode();
+ res = checkOperatingMode(operatingMode, mDevice->info(), mCameraIdStr);
+ if (!res.isOk()) {
+ return res;
+ }
+
+ if (status == nullptr) {
+ String8 msg = String8::format( "Camera %s: Invalid status!", mCameraIdStr.string());
+ ALOGE("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+ }
+ hardware::camera::device::V3_4::StreamConfiguration streamConfiguration;
+ bool earlyExit = false;
+ metadataGetter getMetadata = [this](const String8 &id) {return mDevice->infoPhysical(id);};
+ std::vector<std::string> physicalCameraIds;
+ mProviderManager->isLogicalCamera(mCameraIdStr.string(), &physicalCameraIds);
+ res = convertToHALStreamCombination(sessionConfiguration, mCameraIdStr,
+ mDevice->info(), getMetadata, physicalCameraIds, streamConfiguration, &earlyExit);
+ if (!res.isOk()) {
+ return res;
+ }
+
+ if (earlyExit) {
+ *status = false;
+ return binder::Status::ok();
+ }
*status = false;
ret = mProviderManager->isSessionConfigurationSupported(mCameraIdStr.string(),
@@ -899,7 +970,7 @@
String8 physicalCameraId = String8(outputConfiguration.getPhysicalCameraId());
bool deferredConsumerOnly = deferredConsumer && numBufferProducers == 0;
- res = checkSurfaceTypeLocked(numBufferProducers, deferredConsumer,
+ res = checkSurfaceType(numBufferProducers, deferredConsumer,
outputConfiguration.getSurfaceType());
if (!res.isOk()) {
return res;
@@ -908,8 +979,9 @@
if (!mDevice.get()) {
return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
}
-
- res = checkPhysicalCameraIdLocked(physicalCameraId);
+ std::vector<std::string> physicalCameraIds;
+ mProviderManager->isLogicalCamera(mCameraIdStr.string(), &physicalCameraIds);
+ res = checkPhysicalCameraId(physicalCameraIds, physicalCameraId, mCameraIdStr);
if (!res.isOk()) {
return res;
}
@@ -938,7 +1010,7 @@
sp<Surface> surface;
res = createSurfaceFromGbp(streamInfo, isStreamInfoValid, surface, bufferProducer,
- physicalCameraId);
+ mCameraIdStr, mDevice->infoPhysical(physicalCameraId));
if (!res.isOk())
return res;
@@ -1242,7 +1314,7 @@
OutputStreamInfo outInfo;
sp<Surface> surface;
res = createSurfaceFromGbp(outInfo, /*isStreamInfoValid*/ false, surface,
- newOutputsMap.valueAt(i), physicalCameraId);
+ newOutputsMap.valueAt(i), mCameraIdStr, mDevice->infoPhysical(physicalCameraId));
if (!res.isOk())
return res;
@@ -1322,11 +1394,11 @@
binder::Status CameraDeviceClient::createSurfaceFromGbp(
OutputStreamInfo& streamInfo, bool isStreamInfoValid,
sp<Surface>& surface, const sp<IGraphicBufferProducer>& gbp,
- const String8& physicalId) {
+ const String8 &cameraId, const CameraMetadata &physicalCameraMetadata) {
// bufferProducer must be non-null
if (gbp == nullptr) {
- String8 msg = String8::format("Camera %s: Surface is NULL", mCameraIdStr.string());
+ String8 msg = String8::format("Camera %s: Surface is NULL", cameraId.string());
ALOGW("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
@@ -1338,13 +1410,13 @@
status_t err;
if ((err = gbp->getConsumerUsage(&consumerUsage)) != OK) {
String8 msg = String8::format("Camera %s: Failed to query Surface consumer usage: %s (%d)",
- mCameraIdStr.string(), strerror(-err), err);
+ cameraId.string(), strerror(-err), err);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
}
if (consumerUsage & GraphicBuffer::USAGE_HW_TEXTURE) {
ALOGW("%s: Camera %s with consumer usage flag: %" PRIu64 ": Forcing asynchronous mode for stream",
- __FUNCTION__, mCameraIdStr.string(), consumerUsage);
+ __FUNCTION__, cameraId.string(), consumerUsage);
useAsync = true;
}
@@ -1363,26 +1435,26 @@
android_dataspace dataSpace;
if ((err = anw->query(anw, NATIVE_WINDOW_WIDTH, &width)) != OK) {
String8 msg = String8::format("Camera %s: Failed to query Surface width: %s (%d)",
- mCameraIdStr.string(), strerror(-err), err);
+ cameraId.string(), strerror(-err), err);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
}
if ((err = anw->query(anw, NATIVE_WINDOW_HEIGHT, &height)) != OK) {
String8 msg = String8::format("Camera %s: Failed to query Surface height: %s (%d)",
- mCameraIdStr.string(), strerror(-err), err);
+ cameraId.string(), strerror(-err), err);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
}
if ((err = anw->query(anw, NATIVE_WINDOW_FORMAT, &format)) != OK) {
String8 msg = String8::format("Camera %s: Failed to query Surface format: %s (%d)",
- mCameraIdStr.string(), strerror(-err), err);
+ cameraId.string(), strerror(-err), err);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
}
if ((err = anw->query(anw, NATIVE_WINDOW_DEFAULT_DATASPACE,
reinterpret_cast<int*>(&dataSpace))) != OK) {
String8 msg = String8::format("Camera %s: Failed to query Surface dataspace: %s (%d)",
- mCameraIdStr.string(), strerror(-err), err);
+ cameraId.string(), strerror(-err), err);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
}
@@ -1393,16 +1465,16 @@
((consumerUsage & GRALLOC_USAGE_HW_MASK) &&
((consumerUsage & GRALLOC_USAGE_SW_READ_MASK) == 0))) {
ALOGW("%s: Camera %s: Overriding format %#x to IMPLEMENTATION_DEFINED",
- __FUNCTION__, mCameraIdStr.string(), format);
+ __FUNCTION__, cameraId.string(), format);
format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
}
// Round dimensions to the nearest dimensions available for this format
if (flexibleConsumer && isPublicFormat(format) &&
!CameraDeviceClient::roundBufferDimensionNearest(width, height,
- format, dataSpace, mDevice->info(physicalId), /*out*/&width, /*out*/&height)) {
+ format, dataSpace, physicalCameraMetadata, /*out*/&width, /*out*/&height)) {
String8 msg = String8::format("Camera %s: No supported stream configurations with "
"format %#x defined, failed to create output stream",
- mCameraIdStr.string(), format);
+ cameraId.string(), format);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
@@ -1417,26 +1489,26 @@
}
if (width != streamInfo.width) {
String8 msg = String8::format("Camera %s:Surface width doesn't match: %d vs %d",
- mCameraIdStr.string(), width, streamInfo.width);
+ cameraId.string(), width, streamInfo.width);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
if (height != streamInfo.height) {
String8 msg = String8::format("Camera %s:Surface height doesn't match: %d vs %d",
- mCameraIdStr.string(), height, streamInfo.height);
+ cameraId.string(), height, streamInfo.height);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
if (format != streamInfo.format) {
String8 msg = String8::format("Camera %s:Surface format doesn't match: %d vs %d",
- mCameraIdStr.string(), format, streamInfo.format);
+ cameraId.string(), format, streamInfo.format);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
if (format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
if (dataSpace != streamInfo.dataSpace) {
String8 msg = String8::format("Camera %s:Surface dataSpace doesn't match: %d vs %d",
- mCameraIdStr.string(), dataSpace, streamInfo.dataSpace);
+ cameraId.string(), dataSpace, streamInfo.dataSpace);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
@@ -1445,7 +1517,7 @@
if (consumerUsage != streamInfo.consumerUsage) {
String8 msg = String8::format(
"Camera %s:Surface usage flag doesn't match %" PRIu64 " vs %" PRIu64 "",
- mCameraIdStr.string(), consumerUsage, streamInfo.consumerUsage);
+ cameraId.string(), consumerUsage, streamInfo.consumerUsage);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
@@ -1825,7 +1897,7 @@
sp<Surface> surface;
res = createSurfaceFromGbp(mStreamInfoMap[streamId], true /*isStreamInfoValid*/,
- surface, bufferProducer, physicalId);
+ surface, bufferProducer, mCameraIdStr, mDevice->infoPhysical(physicalId));
if (!res.isOk())
return res;
@@ -1870,6 +1942,159 @@
return res;
}
+binder::Status CameraDeviceClient::setCameraAudioRestriction(int32_t mode) {
+ ATRACE_CALL();
+ binder::Status res;
+ if (!(res = checkPidStatus(__FUNCTION__)).isOk()) return res;
+
+ if (!isValidAudioRestriction(mode)) {
+ String8 msg = String8::format("Camera %s: invalid audio restriction mode %d",
+ mCameraIdStr.string(), mode);
+ ALOGW("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+ }
+
+ Mutex::Autolock icl(mBinderSerializationLock);
+ BasicClient::setAudioRestriction(mode);
+ return binder::Status::ok();
+}
+
+binder::Status CameraDeviceClient::getGlobalAudioRestriction(/*out*/ int32_t* outMode) {
+ ATRACE_CALL();
+ binder::Status res;
+ if (!(res = checkPidStatus(__FUNCTION__)).isOk()) return res;
+ Mutex::Autolock icl(mBinderSerializationLock);
+ if (outMode != nullptr) {
+ *outMode = BasicClient::getServiceAudioRestriction();
+ }
+ return binder::Status::ok();
+}
+
+status_t CameraDeviceClient::setRotateAndCropOverride(uint8_t rotateAndCrop) {
+ if (rotateAndCrop > ANDROID_SCALER_ROTATE_AND_CROP_AUTO) return BAD_VALUE;
+
+ return mDevice->setRotateAndCropAutoBehavior(
+ static_cast<camera_metadata_enum_android_scaler_rotate_and_crop_t>(rotateAndCrop));
+}
+
+binder::Status CameraDeviceClient::switchToOffline(
+ const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
+ const std::vector<int>& offlineOutputIds,
+ /*out*/
+ sp<hardware::camera2::ICameraOfflineSession>* session) {
+ ATRACE_CALL();
+
+ binder::Status res;
+ if (!(res = checkPidStatus(__FUNCTION__)).isOk()) return res;
+
+ Mutex::Autolock icl(mBinderSerializationLock);
+
+ if (!mDevice.get()) {
+ return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
+ }
+
+ if (offlineOutputIds.empty()) {
+ String8 msg = String8::format("Offline surfaces must not be empty");
+ ALOGE("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+ }
+
+ if (session == nullptr) {
+ String8 msg = String8::format("Invalid offline session");
+ ALOGE("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+ }
+
+ std::vector<int32_t> offlineStreamIds;
+ offlineStreamIds.reserve(offlineOutputIds.size());
+ KeyedVector<sp<IBinder>, sp<CompositeStream>> offlineCompositeStreamMap;
+ for (const auto& streamId : offlineOutputIds) {
+ ssize_t index = mConfiguredOutputs.indexOfKey(streamId);
+ if (index == NAME_NOT_FOUND) {
+ String8 msg = String8::format("Offline surface with id: %d is not registered",
+ streamId);
+ ALOGE("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+ }
+
+ if (!mStreamInfoMap[streamId].supportsOffline) {
+ String8 msg = String8::format("Offline surface with id: %d doesn't support "
+ "offline mode", streamId);
+ ALOGE("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+ }
+
+ bool isCompositeStream = false;
+ for (const auto& gbp : mConfiguredOutputs[streamId].getGraphicBufferProducers()) {
+ sp<Surface> s = new Surface(gbp, false /*controlledByApp*/);
+ isCompositeStream = camera3::DepthCompositeStream::isDepthCompositeStream(s) |
+ camera3::HeicCompositeStream::isHeicCompositeStream(s);
+ if (isCompositeStream) {
+ auto compositeIdx = mCompositeStreamMap.indexOfKey(IInterface::asBinder(gbp));
+ if (compositeIdx == NAME_NOT_FOUND) {
+ ALOGE("%s: Unknown composite stream", __FUNCTION__);
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+ "Unknown composite stream");
+ }
+
+ mCompositeStreamMap.valueAt(compositeIdx)->insertCompositeStreamIds(
+ &offlineStreamIds);
+ offlineCompositeStreamMap.add(mCompositeStreamMap.keyAt(compositeIdx),
+ mCompositeStreamMap.valueAt(compositeIdx));
+ break;
+ }
+ }
+
+ if (!isCompositeStream) {
+ offlineStreamIds.push_back(streamId);
+ }
+ }
+
+ sp<CameraOfflineSessionBase> offlineSession;
+ auto ret = mDevice->switchToOffline(offlineStreamIds, &offlineSession);
+ if (ret != OK) {
+ return STATUS_ERROR_FMT(CameraService::ERROR_ILLEGAL_ARGUMENT,
+ "Camera %s: Error switching to offline mode: %s (%d)",
+ mCameraIdStr.string(), strerror(ret), ret);
+ }
+
+ sp<CameraOfflineSessionClient> offlineClient;
+ if (offlineSession.get() != nullptr) {
+ offlineClient = new CameraOfflineSessionClient(sCameraService,
+ offlineSession, offlineCompositeStreamMap, cameraCb, mClientPackageName,
+ mClientFeatureId, mCameraIdStr, mCameraFacing, mClientPid, mClientUid, mServicePid);
+ ret = sCameraService->addOfflineClient(mCameraIdStr, offlineClient);
+ }
+
+ if (ret == OK) {
+ // A successful offline session switch must reset the current camera client
+ // and release any resources occupied by previously configured streams.
+ mStreamMap.clear();
+ mConfiguredOutputs.clear();
+ mDeferredStreams.clear();
+ mStreamInfoMap.clear();
+ mCompositeStreamMap.clear();
+ mInputStream = {false, 0, 0, 0, 0};
+ } else {
+ switch(ret) {
+ case BAD_VALUE:
+ return STATUS_ERROR_FMT(CameraService::ERROR_ILLEGAL_ARGUMENT,
+ "Illegal argument to HAL module for camera \"%s\"", mCameraIdStr.c_str());
+ case TIMED_OUT:
+ return STATUS_ERROR_FMT(CameraService::ERROR_CAMERA_IN_USE,
+ "Camera \"%s\" is already open", mCameraIdStr.c_str());
+ default:
+ return STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
+ "Failed to initialize camera \"%s\": %s (%d)", mCameraIdStr.c_str(),
+ strerror(-ret), ret);
+ }
+ }
+
+ *session = offlineClient;
+
+ return binder::Status::ok();
+}
+
status_t CameraDeviceClient::dump(int fd, const Vector<String16>& args) {
return BasicClient::dump(fd, args);
}
@@ -1982,8 +2207,8 @@
ALOGV("Camera %s: Stopping processors", mCameraIdStr.string());
- mFrameProcessor->removeListener(FRAME_PROCESSOR_LISTENER_MIN_ID,
- FRAME_PROCESSOR_LISTENER_MAX_ID,
+ mFrameProcessor->removeListener(camera2::FrameProcessorBase::FRAME_PROCESSOR_LISTENER_MIN_ID,
+ camera2::FrameProcessorBase::FRAME_PROCESSOR_LISTENER_MAX_ID,
/*listener*/this);
mFrameProcessor->requestExit();
ALOGV("Camera %s: Waiting for threads", mCameraIdStr.string());
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 1c5abb0..964c96a 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -23,6 +23,7 @@
#include <camera/camera2/SessionConfiguration.h>
#include <camera/camera2/SubmitInfo.h>
+#include "CameraOfflineSessionClient.h"
#include "CameraService.h"
#include "common/FrameProcessorBase.h"
#include "common/Camera2ClientBase.h"
@@ -33,6 +34,8 @@
namespace android {
+typedef std::function<CameraMetadata (const String8 &)> metadataGetter;
+
struct CameraDeviceClientBase :
public CameraService::BasicClient,
public hardware::camera2::BnCameraDeviceUser
@@ -47,6 +50,7 @@
CameraDeviceClientBase(const sp<CameraService>& cameraService,
const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
const String16& clientPackageName,
+ const std::unique_ptr<String16>& clientFeatureId,
const String8& cameraId,
int api1CameraId,
int cameraFacing,
@@ -90,7 +94,9 @@
virtual binder::Status beginConfigure() override;
virtual binder::Status endConfigure(int operatingMode,
- const hardware::camera2::impl::CameraMetadataNative& sessionParams) override;
+ const hardware::camera2::impl::CameraMetadataNative& sessionParams,
+ /*out*/
+ std::vector<int>* offlineStreamIds) override;
// Verify specific session configuration.
virtual binder::Status isSessionConfigurationSupported(
@@ -152,6 +158,16 @@
virtual binder::Status finalizeOutputConfigurations(int32_t streamId,
const hardware::camera2::params::OutputConfiguration &outputConfiguration) override;
+ virtual binder::Status setCameraAudioRestriction(int32_t mode) override;
+
+ virtual binder::Status getGlobalAudioRestriction(/*out*/int32_t* outMode) override;
+
+ virtual binder::Status switchToOffline(
+ const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
+ const std::vector<int>& offlineOutputIds,
+ /*out*/
+ sp<hardware::camera2::ICameraOfflineSession>* session) override;
+
/**
* Interface used by CameraService
*/
@@ -159,6 +175,7 @@
CameraDeviceClient(const sp<CameraService>& cameraService,
const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
const String16& clientPackageName,
+ const std::unique_ptr<String16>& clientFeatureId,
const String8& cameraId,
int cameraFacing,
int clientPid,
@@ -169,6 +186,8 @@
virtual status_t initialize(sp<CameraProviderManager> manager,
const String8& monitorTags) override;
+ virtual status_t setRotateAndCropOverride(uint8_t rotateAndCrop) override;
+
virtual status_t dump(int fd, const Vector<String16>& args);
virtual status_t dumpClient(int fd, const Vector<String16>& args);
@@ -185,6 +204,16 @@
virtual void notifyRequestQueueEmpty();
virtual void notifyRepeatingRequestError(long lastFrameNumber);
+ // utility function to convert AIDL SessionConfiguration to HIDL
+ // streamConfiguration. Also checks for sanity of SessionConfiguration and
+ // returns a non-ok binder::Status if the passed in session configuration
+ // isn't valid.
+ static binder::Status
+ convertToHALStreamCombination(const SessionConfiguration& sessionConfiguration,
+ const String8 &cameraId, const CameraMetadata &deviceInfo,
+ metadataGetter getMetadata, const std::vector<std::string> &physicalCameraIds,
+ hardware::camera::device::V3_4::StreamConfiguration &streamConfiguration,
+ bool *earlyExit);
/**
* Interface used by independent components of CameraDeviceClient.
*/
@@ -229,8 +258,6 @@
/** Preview callback related members */
sp<camera2::FrameProcessorBase> mFrameProcessor;
- static const int32_t FRAME_PROCESSOR_LISTENER_MIN_ID = 0;
- static const int32_t FRAME_PROCESSOR_LISTENER_MAX_ID = 0x7fffffffL;
std::vector<int32_t> mSupportedPhysicalRequestKeys;
@@ -239,10 +266,10 @@
/** Utility members */
binder::Status checkPidStatus(const char* checkLocation);
- binder::Status checkOperatingModeLocked(int operatingMode) const;
- binder::Status checkPhysicalCameraIdLocked(String8 physicalCameraId);
- binder::Status checkSurfaceTypeLocked(size_t numBufferProducers, bool deferredConsumer,
- int surfaceType) const;
+ static binder::Status checkOperatingMode(int operatingMode, const CameraMetadata &staticInfo,
+ const String8 &cameraId);
+ static binder::Status checkSurfaceType(size_t numBufferProducers, bool deferredConsumer,
+ int surfaceType);
static void mapStreamInfo(const OutputStreamInfo &streamInfo,
camera3_stream_rotation_t rotation, String8 physicalId,
hardware::camera::device::V3_4::Stream *stream /*out*/);
@@ -273,9 +300,9 @@
// Create a Surface from an IGraphicBufferProducer. Returns error if
// IGraphicBufferProducer's property doesn't match with streamInfo
- binder::Status createSurfaceFromGbp(OutputStreamInfo& streamInfo, bool isStreamInfoValid,
- sp<Surface>& surface, const sp<IGraphicBufferProducer>& gbp,
- const String8& physicalCameraId);
+ static binder::Status createSurfaceFromGbp(OutputStreamInfo& streamInfo, bool isStreamInfoValid,
+ sp<Surface>& surface, const sp<IGraphicBufferProducer>& gbp, const String8 &cameraId,
+ const CameraMetadata &physicalCameraMetadata);
// Utility method to insert the surface into SurfaceMap
@@ -285,7 +312,8 @@
// Check that the physicalCameraId passed in is spported by the camera
// device.
- bool checkPhysicalCameraId(const String8& physicalCameraId);
+ static binder::Status checkPhysicalCameraId(const std::vector<std::string> &physicalCameraIds,
+ const String8 &physicalCameraId, const String8 &logicalCameraId);
// IGraphicsBufferProducer binder -> Stream ID + Surface ID for output streams
KeyedVector<sp<IBinder>, StreamSurfaceId> mStreamMap;
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
new file mode 100644
index 0000000..1edfbf9
--- /dev/null
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
@@ -0,0 +1,311 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "CameraOfflineClient"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include "CameraOfflineSessionClient.h"
+#include "utils/CameraThreadState.h"
+#include <utils/Trace.h>
+
+namespace android {
+
+using binder::Status;
+
+status_t CameraOfflineSessionClient::initialize(sp<CameraProviderManager>, const String8&) {
+ ATRACE_CALL();
+
+ // Verify ops permissions
+ auto res = startCameraOps();
+ if (res != OK) {
+ return res;
+ }
+
+ if (mOfflineSession.get() == nullptr) {
+ ALOGE("%s: Camera %s: No valid offline session",
+ __FUNCTION__, mCameraIdStr.string());
+ return NO_INIT;
+ }
+
+ String8 threadName;
+ mFrameProcessor = new camera2::FrameProcessorBase(mOfflineSession);
+ threadName = String8::format("Offline-%s-FrameProc", mCameraIdStr.string());
+ mFrameProcessor->run(threadName.string());
+
+ mFrameProcessor->registerListener(camera2::FrameProcessorBase::FRAME_PROCESSOR_LISTENER_MIN_ID,
+ camera2::FrameProcessorBase::FRAME_PROCESSOR_LISTENER_MAX_ID,
+ /*listener*/this,
+ /*sendPartials*/true);
+
+ wp<NotificationListener> weakThis(this);
+ res = mOfflineSession->initialize(weakThis);
+ if (res != OK) {
+ ALOGE("%s: Camera %s: unable to initialize device: %s (%d)",
+ __FUNCTION__, mCameraIdStr.string(), strerror(-res), res);
+ return res;
+ }
+
+ return OK;
+}
+
+status_t CameraOfflineSessionClient::setRotateAndCropOverride(uint8_t /*rotateAndCrop*/) {
+ // Since we're not submitting more capture requests, changes to rotateAndCrop override
+ // make no difference.
+ return OK;
+}
+
+status_t CameraOfflineSessionClient::dump(int fd, const Vector<String16>& args) {
+ return BasicClient::dump(fd, args);
+}
+
+status_t CameraOfflineSessionClient::dumpClient(int fd, const Vector<String16>& args) {
+ String8 result;
+
+ result = " Offline session dump:\n";
+ write(fd, result.string(), result.size());
+
+ if (mOfflineSession.get() == nullptr) {
+ result = " *** Offline session is detached\n";
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+ }
+
+ mFrameProcessor->dump(fd, args);
+
+ auto res = mOfflineSession->dump(fd);
+ if (res != OK) {
+ result = String8::format(" Error dumping offline session: %s (%d)",
+ strerror(-res), res);
+ write(fd, result.string(), result.size());
+ }
+
+ return OK;
+}
+
+binder::Status CameraOfflineSessionClient::disconnect() {
+ Mutex::Autolock icl(mBinderSerializationLock);
+
+ binder::Status res = Status::ok();
+ if (mDisconnected) {
+ return res;
+ }
+ // Allow both client and the media server to disconnect at all times
+ int callingPid = CameraThreadState::getCallingPid();
+ if (callingPid != mClientPid &&
+ callingPid != mServicePid) {
+ return res;
+ }
+
+ mDisconnected = true;
+
+ sCameraService->removeByClient(this);
+ sCameraService->logDisconnectedOffline(mCameraIdStr, mClientPid, String8(mClientPackageName));
+
+ sp<IBinder> remote = getRemote();
+ if (remote != nullptr) {
+ remote->unlinkToDeath(sCameraService);
+ }
+
+ mFrameProcessor->removeListener(camera2::FrameProcessorBase::FRAME_PROCESSOR_LISTENER_MIN_ID,
+ camera2::FrameProcessorBase::FRAME_PROCESSOR_LISTENER_MAX_ID,
+ /*listener*/this);
+ mFrameProcessor->requestExit();
+ mFrameProcessor->join();
+
+ finishCameraOps();
+ ALOGI("%s: Disconnected client for offline camera %s for PID %d", __FUNCTION__,
+ mCameraIdStr.string(), mClientPid);
+
+ // client shouldn't be able to call into us anymore
+ mClientPid = 0;
+
+ if (mOfflineSession.get() != nullptr) {
+ auto ret = mOfflineSession->disconnect();
+ if (ret != OK) {
+ ALOGE("%s: Failed disconnecting from offline session %s (%d)", __FUNCTION__,
+ strerror(-ret), ret);
+ }
+ mOfflineSession = nullptr;
+ }
+
+ for (size_t i = 0; i < mCompositeStreamMap.size(); i++) {
+ auto ret = mCompositeStreamMap.valueAt(i)->deleteInternalStreams();
+ if (ret != OK) {
+ ALOGE("%s: Failed removing composite stream %s (%d)", __FUNCTION__,
+ strerror(-ret), ret);
+ }
+ }
+ mCompositeStreamMap.clear();
+
+ return res;
+}
+
+void CameraOfflineSessionClient::notifyError(int32_t errorCode,
+ const CaptureResultExtras& resultExtras) {
+ // Thread safe. Don't bother locking.
+ // Composites can have multiple internal streams. Error notifications coming from such internal
+ // streams may need to remain within camera service.
+ bool skipClientNotification = false;
+ for (size_t i = 0; i < mCompositeStreamMap.size(); i++) {
+ skipClientNotification |= mCompositeStreamMap.valueAt(i)->onError(errorCode, resultExtras);
+ }
+
+ if ((mRemoteCallback.get() != nullptr) && (!skipClientNotification)) {
+ mRemoteCallback->onDeviceError(errorCode, resultExtras);
+ }
+}
+
+status_t CameraOfflineSessionClient::startCameraOps() {
+ ATRACE_CALL();
+ {
+ ALOGV("%s: Start camera ops, package name = %s, client UID = %d",
+ __FUNCTION__, String8(mClientPackageName).string(), mClientUid);
+ }
+
+ if (mAppOpsManager != nullptr) {
+ // Notify app ops that the camera is not available
+ mOpsCallback = new OpsCallback(this);
+ int32_t res;
+ // TODO : possibly change this to OP_OFFLINE_CAMERA_SESSION
+ mAppOpsManager->startWatchingMode(AppOpsManager::OP_CAMERA,
+ mClientPackageName, mOpsCallback);
+ // TODO : possibly change this to OP_OFFLINE_CAMERA_SESSION
+ res = mAppOpsManager->startOpNoThrow(AppOpsManager::OP_CAMERA,
+ mClientUid, mClientPackageName, /*startIfModeDefault*/ false);
+
+ if (res == AppOpsManager::MODE_ERRORED) {
+ ALOGI("Offline Camera %s: Access for \"%s\" has been revoked",
+ mCameraIdStr.string(), String8(mClientPackageName).string());
+ return PERMISSION_DENIED;
+ }
+
+ if (res == AppOpsManager::MODE_IGNORED) {
+ ALOGI("Offline 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;
+ }
+ }
+
+ mOpsActive = true;
+
+ // Transition device state to OPEN
+ sCameraService->mUidPolicy->registerMonitorUid(mClientUid);
+
+ return OK;
+}
+
+status_t CameraOfflineSessionClient::finishCameraOps() {
+ ATRACE_CALL();
+
+ // 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) {
+ // TODO : possibly change this to OP_OFFLINE_CAMERA_SESSION
+ mAppOpsManager->finishOp(AppOpsManager::OP_CAMERA, mClientUid,
+ mClientPackageName);
+ mOpsActive = false;
+ }
+ }
+ // Always stop watching, even if no camera op is active
+ if (mOpsCallback != nullptr && mAppOpsManager != nullptr) {
+ mAppOpsManager->stopWatchingMode(mOpsCallback);
+ }
+ mOpsCallback.clear();
+
+ sCameraService->mUidPolicy->unregisterMonitorUid(mClientUid);
+
+ return OK;
+}
+
+void CameraOfflineSessionClient::onResultAvailable(const CaptureResult& result) {
+ ATRACE_CALL();
+ ALOGV("%s", __FUNCTION__);
+
+ if (mRemoteCallback.get() != NULL) {
+ mRemoteCallback->onResultReceived(result.mMetadata, result.mResultExtras,
+ result.mPhysicalMetadatas);
+ }
+
+ for (size_t i = 0; i < mCompositeStreamMap.size(); i++) {
+ mCompositeStreamMap.valueAt(i)->onResultAvailable(result);
+ }
+}
+
+void CameraOfflineSessionClient::notifyShutter(const CaptureResultExtras& resultExtras,
+ nsecs_t timestamp) {
+
+ if (mRemoteCallback.get() != nullptr) {
+ mRemoteCallback->onCaptureStarted(resultExtras, timestamp);
+ }
+
+ for (size_t i = 0; i < mCompositeStreamMap.size(); i++) {
+ mCompositeStreamMap.valueAt(i)->onShutter(resultExtras, timestamp);
+ }
+}
+
+void CameraOfflineSessionClient::notifyIdle() {
+ if (mRemoteCallback.get() != nullptr) {
+ mRemoteCallback->onDeviceIdle();
+ }
+}
+
+void CameraOfflineSessionClient::notifyAutoFocus(uint8_t newState, int triggerId) {
+ (void)newState;
+ (void)triggerId;
+
+ ALOGV("%s: Autofocus state now %d, last trigger %d",
+ __FUNCTION__, newState, triggerId);
+}
+
+void CameraOfflineSessionClient::notifyAutoExposure(uint8_t newState, int triggerId) {
+ (void)newState;
+ (void)triggerId;
+
+ ALOGV("%s: Autoexposure state now %d, last trigger %d",
+ __FUNCTION__, newState, triggerId);
+}
+
+void CameraOfflineSessionClient::notifyAutoWhitebalance(uint8_t newState, int triggerId) {
+ (void)newState;
+ (void)triggerId;
+
+ ALOGV("%s: Auto-whitebalance state now %d, last trigger %d", __FUNCTION__, newState,
+ triggerId);
+}
+
+void CameraOfflineSessionClient::notifyPrepared(int /*streamId*/) {
+ ALOGE("%s: Unexpected stream prepare notification in offline mode!", __FUNCTION__);
+ notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE,
+ CaptureResultExtras());
+}
+
+void CameraOfflineSessionClient::notifyRequestQueueEmpty() {
+ if (mRemoteCallback.get() != nullptr) {
+ mRemoteCallback->onRequestQueueEmpty();
+ }
+}
+
+void CameraOfflineSessionClient::notifyRepeatingRequestError(long /*lastFrameNumber*/) {
+ ALOGE("%s: Unexpected repeating request error in offline mode!", __FUNCTION__);
+ notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE,
+ CaptureResultExtras());
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
new file mode 100644
index 0000000..b67fcb3
--- /dev/null
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_SERVERS_CAMERA_PHOTOGRAPHY_CAMERAOFFLINESESSIONCLIENT_H
+#define ANDROID_SERVERS_CAMERA_PHOTOGRAPHY_CAMERAOFFLINESESSIONCLIENT_H
+
+#include <android/hardware/camera2/BnCameraOfflineSession.h>
+#include <android/hardware/camera2/ICameraDeviceCallbacks.h>
+#include "common/FrameProcessorBase.h"
+#include "common/CameraDeviceBase.h"
+#include "CameraService.h"
+#include "CompositeStream.h"
+
+namespace android {
+
+using android::hardware::camera2::ICameraDeviceCallbacks;
+using camera3::CompositeStream;
+
+// Client for offline session. Note that offline session client does not affect camera service's
+// client arbitration logic. It is camera HAL's decision to decide whether a normal camera
+// client is conflicting with existing offline client(s).
+// The other distinctive difference between offline clients and normal clients is that normal
+// clients are created through ICameraService binder calls, while the offline session client
+// is created through ICameraDeviceUser::switchToOffline call.
+class CameraOfflineSessionClient :
+ public CameraService::BasicClient,
+ public hardware::camera2::BnCameraOfflineSession,
+ public camera2::FrameProcessorBase::FilteredListener,
+ public NotificationListener
+{
+public:
+ CameraOfflineSessionClient(
+ const sp<CameraService>& cameraService,
+ sp<CameraOfflineSessionBase> session,
+ const KeyedVector<sp<IBinder>, sp<CompositeStream>>& offlineCompositeStreamMap,
+ const sp<ICameraDeviceCallbacks>& remoteCallback,
+ const String16& clientPackageName,
+ const std::unique_ptr<String16>& clientFeatureId,
+ const String8& cameraIdStr, int cameraFacing,
+ int clientPid, uid_t clientUid, int servicePid) :
+ CameraService::BasicClient(
+ cameraService,
+ IInterface::asBinder(remoteCallback),
+ clientPackageName, clientFeatureId,
+ cameraIdStr, cameraFacing, clientPid, clientUid, servicePid),
+ mRemoteCallback(remoteCallback), mOfflineSession(session),
+ mCompositeStreamMap(offlineCompositeStreamMap) {}
+
+ virtual ~CameraOfflineSessionClient() {}
+
+ sp<IBinder> asBinderWrapper() override {
+ return IInterface::asBinder(this);
+ }
+
+ binder::Status disconnect() override;
+
+ status_t dump(int /*fd*/, const Vector<String16>& /*args*/) override;
+
+ status_t dumpClient(int /*fd*/, const Vector<String16>& /*args*/) override;
+
+ status_t initialize(sp<CameraProviderManager> /*manager*/,
+ const String8& /*monitorTags*/) override;
+
+ status_t setRotateAndCropOverride(uint8_t rotateAndCrop) override;
+
+ // permissions management
+ status_t startCameraOps() override;
+ status_t finishCameraOps() override;
+
+ // FilteredResultListener API
+ void onResultAvailable(const CaptureResult& result) override;
+
+ // NotificationListener API
+ void notifyError(int32_t errorCode, const CaptureResultExtras& resultExtras) override;
+ void notifyShutter(const CaptureResultExtras& resultExtras, nsecs_t timestamp) override;
+ void notifyIdle() override;
+ void notifyAutoFocus(uint8_t newState, int triggerId) override;
+ void notifyAutoExposure(uint8_t newState, int triggerId) override;
+ void notifyAutoWhitebalance(uint8_t newState, int triggerId) override;
+ void notifyPrepared(int streamId) override;
+ void notifyRequestQueueEmpty() override;
+ void notifyRepeatingRequestError(long lastFrameNumber) override;
+
+private:
+ mutable Mutex mBinderSerializationLock;
+
+ sp<hardware::camera2::ICameraDeviceCallbacks> mRemoteCallback;
+
+ sp<CameraOfflineSessionBase> mOfflineSession;
+
+ sp<camera2::FrameProcessorBase> mFrameProcessor;
+
+ // Offline composite stream map, output surface -> composite stream
+ KeyedVector<sp<IBinder>, sp<CompositeStream>> mCompositeStreamMap;
+};
+
+} // namespace android
+
+#endif // ANDROID_SERVERS_CAMERA_PHOTOGRAPHY_CAMERAOFFLINESESSIONCLIENT_H
diff --git a/services/camera/libcameraservice/api2/CompositeStream.h b/services/camera/libcameraservice/api2/CompositeStream.h
index a401a82..de894f3 100644
--- a/services/camera/libcameraservice/api2/CompositeStream.h
+++ b/services/camera/libcameraservice/api2/CompositeStream.h
@@ -64,6 +64,10 @@
virtual status_t insertGbp(SurfaceMap* /*out*/outSurfaceMap,
Vector<int32_t>* /*out*/outputStreamIds, int32_t* /*out*/currentStreamId) = 0;
+ // Attach the internal composite stream ids.
+ virtual status_t insertCompositeStreamIds(
+ std::vector<int32_t>* compositeStreamIds /*out*/) = 0;
+
// Return composite stream id.
virtual int getStreamId() = 0;
diff --git a/services/camera/libcameraservice/api2/DepthCompositeStream.cpp b/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
index 0b91016..acad8c6 100644
--- a/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
@@ -20,7 +20,6 @@
#include "api1/client2/JpegProcessor.h"
#include "common/CameraProviderManager.h"
-#include "dlfcn.h"
#include <gui/Surface.h>
#include <utils/Log.h>
#include <utils/Trace.h>
@@ -43,9 +42,7 @@
mBlobBufferAcquired(false),
mProducerListener(new ProducerListener()),
mMaxJpegSize(-1),
- mIsLogicalCamera(false),
- mDepthPhotoLibHandle(nullptr),
- mDepthPhotoProcess(nullptr) {
+ mIsLogicalCamera(false) {
sp<CameraDeviceBase> cameraDevice = device.promote();
if (cameraDevice.get() != nullptr) {
CameraMetadata staticInfo = cameraDevice->info();
@@ -83,19 +80,6 @@
}
getSupportedDepthSizes(staticInfo, &mSupportedDepthSizes);
-
- mDepthPhotoLibHandle = dlopen(camera3::kDepthPhotoLibrary, RTLD_NOW | RTLD_LOCAL);
- if (mDepthPhotoLibHandle != nullptr) {
- mDepthPhotoProcess = reinterpret_cast<camera3::process_depth_photo_frame> (
- dlsym(mDepthPhotoLibHandle, camera3::kDepthPhotoProcessFunction));
- if (mDepthPhotoProcess == nullptr) {
- ALOGE("%s: Failed to link to depth photo process function: %s", __FUNCTION__,
- dlerror());
- }
- } else {
- ALOGE("%s: Failed to link to depth photo library: %s", __FUNCTION__, dlerror());
- }
-
}
}
@@ -108,11 +92,6 @@
mDepthSurface.clear();
mDepthConsumer = nullptr;
mDepthSurface = nullptr;
- if (mDepthPhotoLibHandle != nullptr) {
- dlclose(mDepthPhotoLibHandle);
- mDepthPhotoLibHandle = nullptr;
- }
- mDepthPhotoProcess = nullptr;
}
void DepthCompositeStream::compilePendingInputLocked() {
@@ -356,7 +335,7 @@
}
size_t actualJpegSize = 0;
- res = mDepthPhotoProcess(depthPhoto, finalJpegBufferSize, dstBuffer, &actualJpegSize);
+ res = processDepthPhotoFrame(depthPhoto, finalJpegBufferSize, dstBuffer, &actualJpegSize);
if (res != 0) {
ALOGE("%s: Depth photo processing failed: %s (%d)", __FUNCTION__, strerror(-res), res);
outputANW->cancelBuffer(mOutputSurface.get(), anb, /*fence*/ -1);
@@ -583,11 +562,6 @@
return NO_ERROR;
}
- if ((mDepthPhotoLibHandle == nullptr) || (mDepthPhotoProcess == nullptr)) {
- ALOGE("%s: Depth photo library is not present!", __FUNCTION__);
- return NO_INIT;
- }
-
if (mOutputSurface.get() == nullptr) {
ALOGE("%s: No valid output surface set!", __FUNCTION__);
return NO_INIT;
@@ -709,6 +683,18 @@
return NO_ERROR;
}
+status_t DepthCompositeStream::insertCompositeStreamIds(
+ std::vector<int32_t>* compositeStreamIds /*out*/) {
+ if (compositeStreamIds == nullptr) {
+ return BAD_VALUE;
+ }
+
+ compositeStreamIds->push_back(mDepthStreamId);
+ compositeStreamIds->push_back(mBlobStreamId);
+
+ return OK;
+}
+
void DepthCompositeStream::onResultError(const CaptureResultExtras& resultExtras) {
// Processing can continue even in case of result errors.
// At the moment depth composite stream processing relies mainly on static camera
diff --git a/services/camera/libcameraservice/api2/DepthCompositeStream.h b/services/camera/libcameraservice/api2/DepthCompositeStream.h
index 28a7826..1bf714d 100644
--- a/services/camera/libcameraservice/api2/DepthCompositeStream.h
+++ b/services/camera/libcameraservice/api2/DepthCompositeStream.h
@@ -56,6 +56,7 @@
status_t configureStream() override;
status_t insertGbp(SurfaceMap* /*out*/outSurfaceMap, Vector<int32_t>* /*out*/outputStreamIds,
int32_t* /*out*/currentStreamId) override;
+ status_t insertCompositeStreamIds(std::vector<int32_t>* compositeStreamIds /*out*/) override;
int getStreamId() override { return mBlobStreamId; }
// CpuConsumer listener implementation
@@ -126,8 +127,6 @@
std::vector<std::tuple<size_t, size_t>> mSupportedDepthSizes;
std::vector<float> mIntrinsicCalibration, mLensDistortion;
bool mIsLogicalCamera;
- void* mDepthPhotoLibHandle;
- process_depth_photo_frame mDepthPhotoProcess;
// Keep all incoming Depth buffer timestamps pending further processing.
std::vector<int64_t> mInputDepthBuffers;
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
index 9f15be0..d25e467 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
@@ -28,7 +28,7 @@
#include <utils/Log.h>
#include <utils/Trace.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/MediaCodecBuffer.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/MediaDefs.h>
@@ -67,6 +67,7 @@
mDequeuedOutputBufferCnt(0),
mLockedAppSegmentBufferCnt(0),
mCodecOutputCounter(0),
+ mQuality(-1),
mGridTimestampUs(0) {
}
@@ -503,6 +504,18 @@
return NO_ERROR;
}
+status_t HeicCompositeStream::insertCompositeStreamIds(
+ std::vector<int32_t>* compositeStreamIds /*out*/) {
+ if (compositeStreamIds == nullptr) {
+ return BAD_VALUE;
+ }
+
+ compositeStreamIds->push_back(mAppSegmentStreamId);
+ compositeStreamIds->push_back(mMainImageStreamId);
+
+ return OK;
+}
+
void HeicCompositeStream::onShutter(const CaptureResultExtras& resultExtras, nsecs_t timestamp) {
Mutex::Autolock l(mMutex);
if (mErrorState) {
@@ -525,6 +538,12 @@
mPendingInputFrames[it->first].orientation = it->second.first;
mPendingInputFrames[it->first].quality = it->second.second;
mSettingsByTimestamp.erase(it);
+
+ // Set encoder quality if no inflight encoding
+ if (mPendingInputFrames.size() == 1) {
+ int32_t newQuality = mPendingInputFrames.begin()->second.quality;
+ updateCodecQualityLocked(newQuality);
+ }
}
while (!mInputAppSegmentBuffers.empty()) {
@@ -851,17 +870,6 @@
strerror(-res), res);
return res;
}
- // Set encoder quality
- {
- sp<AMessage> qualityParams = new AMessage;
- qualityParams->setInt32(PARAMETER_KEY_VIDEO_BITRATE, inputFrame.quality);
- res = mCodec->setParameters(qualityParams);
- if (res != OK) {
- ALOGE("%s: Failed to set codec quality: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return res;
- }
- }
ssize_t trackId = inputFrame.muxer->addTrack(inputFrame.format);
if (trackId < 0) {
@@ -1148,16 +1156,30 @@
void HeicCompositeStream::releaseInputFramesLocked() {
auto it = mPendingInputFrames.begin();
+ bool inputFrameDone = false;
while (it != mPendingInputFrames.end()) {
auto& inputFrame = it->second;
if (inputFrame.error ||
(inputFrame.appSegmentWritten && inputFrame.pendingOutputTiles == 0)) {
releaseInputFrameLocked(&inputFrame);
it = mPendingInputFrames.erase(it);
+ inputFrameDone = true;
} else {
it++;
}
}
+
+ // Update codec quality based on first upcoming input frame.
+ // Note that when encoding is in surface mode, currently there is no
+ // way for camera service to synchronize quality setting on a per-frame
+ // basis: we don't get notification when codec is ready to consume a new
+ // input frame. So we update codec quality on a best-effort basis.
+ if (inputFrameDone) {
+ auto firstPendingFrame = mPendingInputFrames.begin();
+ if (firstPendingFrame != mPendingInputFrames.end()) {
+ updateCodecQualityLocked(firstPendingFrame->second.quality);
+ }
+ }
}
status_t HeicCompositeStream::initializeCodec(uint32_t width, uint32_t height,
@@ -1260,7 +1282,7 @@
outputFormat->setInt32(KEY_I_FRAME_INTERVAL, 0);
outputFormat->setInt32(KEY_COLOR_FORMAT,
useGrid ? COLOR_FormatYUV420Flexible : COLOR_FormatSurface);
- outputFormat->setInt32(KEY_FRAME_RATE, gridRows * gridCols);
+ outputFormat->setInt32(KEY_FRAME_RATE, useGrid ? gridRows * gridCols : kNoGridOpRate);
// This only serves as a hint to encoder when encoding is not real-time.
outputFormat->setInt32(KEY_OPERATING_RATE, useGrid ? kGridOpRate : kNoGridOpRate);
@@ -1546,6 +1568,20 @@
return maxAppsSegment * (2 + 0xFFFF) + sizeof(struct CameraBlob);
}
+void HeicCompositeStream::updateCodecQualityLocked(int32_t quality) {
+ if (quality != mQuality) {
+ sp<AMessage> qualityParams = new AMessage;
+ qualityParams->setInt32(PARAMETER_KEY_VIDEO_BITRATE, quality);
+ status_t res = mCodec->setParameters(qualityParams);
+ if (res != OK) {
+ ALOGE("%s: Failed to set codec quality: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ } else {
+ mQuality = quality;
+ }
+ }
+}
+
bool HeicCompositeStream::threadLoop() {
int64_t currentTs = INT64_MAX;
bool newInputAvailable = false;
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.h b/services/camera/libcameraservice/api2/HeicCompositeStream.h
index 04e7b83..8fc521e 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.h
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.h
@@ -55,6 +55,8 @@
status_t insertGbp(SurfaceMap* /*out*/outSurfaceMap, Vector<int32_t>* /*out*/outputStreamIds,
int32_t* /*out*/currentStreamId) override;
+ status_t insertCompositeStreamIds(std::vector<int32_t>* compositeStreamIds /*out*/) override;
+
void onShutter(const CaptureResultExtras& resultExtras, nsecs_t timestamp) override;
int getStreamId() override { return mMainImageStreamId; }
@@ -199,6 +201,7 @@
size_t top, size_t left, size_t width, size_t height);
void initCopyRowFunction(int32_t width);
static size_t calcAppSegmentMaxSize(const CameraMetadata& info);
+ void updateCodecQualityLocked(int32_t quality);
static const nsecs_t kWaitDuration = 10000000; // 10 ms
static const int32_t kDefaultJpegQuality = 99;
@@ -240,6 +243,7 @@
std::vector<CodecOutputBufferInfo> mCodecOutputBuffers;
std::queue<int64_t> mCodecOutputBufferTimestamps;
size_t mCodecOutputCounter;
+ int32_t mQuality;
// Keep all incoming Yuv buffer pending tiling and encoding (for HEVC YUV tiling only)
std::vector<int64_t> mInputYuvBuffers;
diff --git a/services/camera/libcameraservice/api2/HeicEncoderInfoManager.cpp b/services/camera/libcameraservice/api2/HeicEncoderInfoManager.cpp
index d7cc2bf..d36ca3b 100644
--- a/services/camera/libcameraservice/api2/HeicEncoderInfoManager.cpp
+++ b/services/camera/libcameraservice/api2/HeicEncoderInfoManager.cpp
@@ -91,6 +91,8 @@
// The "measured-frame-rate-WIDTHxHEIGHT-range" key is optional.
// Hardcode to some default value (3.33ms * tile count) based on resolution.
*stall = 3333333LL * width * height / (kGridWidth * kGridHeight);
+ *useHeic = chooseHeic;
+ *useGrid = enableGrid;
return true;
}
@@ -275,9 +277,13 @@
ALOGE("%s: Failed to get codec info for %s", __FUNCTION__, mime);
break;
}
+ ALOGV("%s: [%s] codec found", __FUNCTION__,
+ info->getCodecName());
// Filter out software ones as they may be too slow
if (!(info->getAttributes() & MediaCodecInfo::kFlagIsHardwareAccelerated)) {
+ ALOGV("%s: [%s] Filter out software ones as they may be too slow", __FUNCTION__,
+ info->getCodecName());
continue;
}
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 78feb3e..0a41776 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -44,13 +44,14 @@
const sp<CameraService>& cameraService,
const sp<TCamCallbacks>& remoteCallback,
const String16& clientPackageName,
+ const std::unique_ptr<String16>& clientFeatureId,
const String8& cameraId,
int api1CameraId,
int cameraFacing,
int clientPid,
uid_t clientUid,
int servicePid):
- TClientBase(cameraService, remoteCallback, clientPackageName,
+ TClientBase(cameraService, remoteCallback, clientPackageName, clientFeatureId,
cameraId, api1CameraId, cameraFacing, clientPid, clientUid, servicePid),
mSharedCameraCallbacks(remoteCallback),
mDeviceVersion(cameraService->getDeviceVersion(TClientBase::mCameraIdStr)),
@@ -110,7 +111,7 @@
return res;
}
- wp<CameraDeviceBase::NotificationListener> weakThis(this);
+ wp<NotificationListener> weakThis(this);
res = mDevice->setNotifyCallback(weakThis);
return OK;
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index 6693847..042f5aa 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -29,7 +29,7 @@
template <typename TClientBase>
class Camera2ClientBase :
public TClientBase,
- public CameraDeviceBase::NotificationListener
+ public NotificationListener
{
public:
typedef typename TClientBase::TCamCallbacks TCamCallbacks;
@@ -48,6 +48,7 @@
Camera2ClientBase(const sp<CameraService>& cameraService,
const sp<TCamCallbacks>& remoteCallback,
const String16& clientPackageName,
+ const std::unique_ptr<String16>& clientFeatureId,
const String8& cameraId,
int api1CameraId,
int cameraFacing,
@@ -60,7 +61,7 @@
virtual status_t dumpClient(int fd, const Vector<String16>& args);
/**
- * CameraDeviceBase::NotificationListener implementation
+ * NotificationListener implementation
*/
virtual void notifyError(int32_t errorCode,
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.cpp b/services/camera/libcameraservice/common/CameraDeviceBase.cpp
index 6c4e87f..0efe4bc 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.cpp
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.cpp
@@ -24,7 +24,4 @@
CameraDeviceBase::~CameraDeviceBase() {
}
-CameraDeviceBase::NotificationListener::~NotificationListener() {
-}
-
} // namespace android
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index 98c1b5e..3662a65 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -34,6 +34,9 @@
#include "gui/IGraphicBufferProducer.h"
#include "device3/Camera3StreamInterface.h"
#include "binder/Status.h"
+#include "FrameProducer.h"
+
+#include "CameraOfflineSessionBase.h"
namespace android {
@@ -46,16 +49,11 @@
* Base interface for version >= 2 camera device classes, which interface to
* camera HAL device versions >= 2.
*/
-class CameraDeviceBase : public virtual RefBase {
+class CameraDeviceBase : public virtual FrameProducer {
public:
virtual ~CameraDeviceBase();
/**
- * The device's camera ID
- */
- virtual const String8& getId() const = 0;
-
- /**
* The device vendor tag ID
*/
virtual metadata_vendor_id_t getVendorTagId() const = 0;
@@ -66,13 +64,9 @@
virtual status_t dump(int fd, const Vector<String16> &args) = 0;
/**
- * The device's static characteristics metadata buffer
- */
- virtual const CameraMetadata& info() const = 0;
- /**
* The physical camera device's static characteristics metadata buffer
*/
- virtual const CameraMetadata& info(const String8& physicalId) const = 0;
+ virtual const CameraMetadata& infoPhysical(const String8& physicalId) const = 0;
struct PhysicalCameraSettings {
std::string cameraId;
@@ -232,6 +226,12 @@
virtual status_t configureStreams(const CameraMetadata& sessionParams,
int operatingMode = 0) = 0;
+ /**
+ * Retrieve a list of all stream ids that were advertised as capable of
+ * supporting offline processing mode by Hal after the last stream configuration.
+ */
+ virtual void getOfflineStreamIds(std::vector<int> *offlineStreamIds) = 0;
+
// get the buffer producer of the input stream
virtual status_t getInputBufferProducer(
sp<IGraphicBufferProducer> *producer) = 0;
@@ -257,35 +257,6 @@
virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const = 0;
/**
- * Abstract class for HAL notification listeners
- */
- class NotificationListener : public virtual RefBase {
- public:
- // The set of notifications is a merge of the notifications required for
- // API1 and API2.
-
- // Required for API 1 and 2
- virtual void notifyError(int32_t errorCode,
- const CaptureResultExtras &resultExtras) = 0;
-
- // Required only for API2
- virtual void notifyIdle() = 0;
- virtual void notifyShutter(const CaptureResultExtras &resultExtras,
- nsecs_t timestamp) = 0;
- virtual void notifyPrepared(int streamId) = 0;
- virtual void notifyRequestQueueEmpty() = 0;
-
- // Required only for API1
- virtual void notifyAutoFocus(uint8_t newState, int triggerId) = 0;
- virtual void notifyAutoExposure(uint8_t newState, int triggerId) = 0;
- virtual void notifyAutoWhitebalance(uint8_t newState,
- int triggerId) = 0;
- virtual void notifyRepeatingRequestError(long lastFrameNumber) = 0;
- protected:
- virtual ~NotificationListener();
- };
-
- /**
* Connect HAL notifications to a listener. Overwrites previous
* listener. Set to NULL to stop receiving notifications.
*/
@@ -299,21 +270,6 @@
virtual bool willNotify3A() = 0;
/**
- * Wait for a new frame to be produced, with timeout in nanoseconds.
- * Returns TIMED_OUT when no frame produced within the specified duration
- * May be called concurrently to most methods, except for getNextFrame
- */
- virtual status_t waitForNextFrame(nsecs_t timeout) = 0;
-
- /**
- * Get next capture result frame from the result queue. Returns NOT_ENOUGH_DATA
- * if the queue is empty; caller takes ownership of the metadata buffer inside
- * the capture result object's metadata field.
- * May be called concurrently to most methods, except for waitForNextFrame.
- */
- virtual status_t getNextResult(CaptureResult *frame) = 0;
-
- /**
* Trigger auto-focus. The latest ID used in a trigger autofocus or cancel
* autofocus call will be returned by the HAL in all subsequent AF
* notifications.
@@ -383,6 +339,29 @@
* drop buffers for stream of streamId.
*/
virtual status_t dropStreamBuffers(bool /*dropping*/, int /*streamId*/) = 0;
+
+ /**
+ * Returns the maximum expected time it'll take for all currently in-flight
+ * requests to complete, based on their settings
+ */
+ virtual nsecs_t getExpectedInFlightDuration() = 0;
+
+ /**
+ * switch to offline session
+ */
+ virtual status_t switchToOffline(
+ const std::vector<int32_t>& streamsToKeep,
+ /*out*/ sp<CameraOfflineSessionBase>* session) = 0;
+
+ /**
+ * Set the current behavior for the ROTATE_AND_CROP control when in AUTO.
+ *
+ * The value must be one of the ROTATE_AND_CROP_* values besides AUTO,
+ * and defaults to NONE.
+ */
+ virtual status_t setRotateAndCropAutoBehavior(
+ camera_metadata_enum_android_scaler_rotate_and_crop_t rotateAndCropValue) = 0;
+
};
}; // namespace android
diff --git a/services/camera/libcameraservice/common/CameraOfflineSessionBase.cpp b/services/camera/libcameraservice/common/CameraOfflineSessionBase.cpp
new file mode 100644
index 0000000..ff673a9
--- /dev/null
+++ b/services/camera/libcameraservice/common/CameraOfflineSessionBase.cpp
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+#include "CameraOfflineSessionBase.h"
+
+namespace android {
+
+/**
+ * Base class destructors
+ */
+CameraOfflineSessionBase::~CameraOfflineSessionBase() {
+}
+
+} // namespace android
diff --git a/services/camera/libcameraservice/common/CameraOfflineSessionBase.h b/services/camera/libcameraservice/common/CameraOfflineSessionBase.h
new file mode 100644
index 0000000..1f835a9
--- /dev/null
+++ b/services/camera/libcameraservice/common/CameraOfflineSessionBase.h
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_SERVERS_CAMERA_CAMERAOFFLINESESSIONBASE_H
+#define ANDROID_SERVERS_CAMERA_CAMERAOFFLINESESSIONBASE_H
+
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/Timers.h>
+
+#include "camera/CaptureResult.h"
+#include "FrameProducer.h"
+
+namespace android {
+
+/**
+ * Abstract class for HAL notification listeners
+ */
+class NotificationListener : public virtual RefBase {
+ public:
+ // The set of notifications is a merge of the notifications required for
+ // API1 and API2.
+
+ // Required for API 1 and 2
+ virtual void notifyError(int32_t errorCode,
+ const CaptureResultExtras &resultExtras) = 0;
+
+ // Required only for API2
+ virtual void notifyIdle() = 0;
+ virtual void notifyShutter(const CaptureResultExtras &resultExtras,
+ nsecs_t timestamp) = 0;
+ virtual void notifyPrepared(int streamId) = 0;
+ virtual void notifyRequestQueueEmpty() = 0;
+
+ // Required only for API1
+ virtual void notifyAutoFocus(uint8_t newState, int triggerId) = 0;
+ virtual void notifyAutoExposure(uint8_t newState, int triggerId) = 0;
+ virtual void notifyAutoWhitebalance(uint8_t newState,
+ int triggerId) = 0;
+ virtual void notifyRepeatingRequestError(long lastFrameNumber) = 0;
+ protected:
+ virtual ~NotificationListener() {}
+};
+
+class CameraOfflineSessionBase : public virtual FrameProducer {
+ public:
+ virtual ~CameraOfflineSessionBase();
+
+ virtual status_t initialize(
+ wp<NotificationListener> listener) = 0;
+
+ virtual status_t disconnect() = 0;
+
+ virtual status_t dump(int fd) = 0;
+
+ // TODO: notification passing path
+}; // class CameraOfflineSessionBase
+
+} // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index fdb5657..cc369fa 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -37,15 +37,19 @@
#include <android-base/logging.h>
#include <cutils/properties.h>
#include <hwbinder/IPCThreadState.h>
+#include <utils/SessionConfigurationUtils.h>
#include <utils/Trace.h>
#include "api2/HeicCompositeStream.h"
+#include "device3/ZoomRatioMapper.h"
namespace android {
using namespace ::android::hardware::camera;
using namespace ::android::hardware::camera::common::V1_0;
using std::literals::chrono_literals::operator""s;
+using hardware::camera2::utils::CameraIdAndSessionConfiguration;
+using hardware::camera::provider::V2_6::CameraIdAndStreamCombination;
namespace {
const bool kEnableLazyHal(property_get_bool("ro.camera.enableLazyHal", false));
@@ -104,19 +108,30 @@
return OK;
}
-int CameraProviderManager::getCameraCount() const {
+std::pair<int, int> CameraProviderManager::getCameraCount() const {
std::lock_guard<std::mutex> lock(mInterfaceMutex);
- int count = 0;
+ int systemCameraCount = 0;
+ int publicCameraCount = 0;
for (auto& provider : mProviders) {
- for (auto& id : provider->mUniqueCameraIds) {
- // Hidden secure camera ids are not to be exposed to camera1 api.
- if (isPublicallyHiddenSecureCameraLocked(id)) {
+ for (auto &id : provider->mUniqueCameraIds) {
+ SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
+ if (getSystemCameraKindLocked(id, &deviceKind) != OK) {
+ ALOGE("%s: Invalid camera id %s, skipping", __FUNCTION__, id.c_str());
continue;
}
- count++;
+ switch(deviceKind) {
+ case SystemCameraKind::PUBLIC:
+ publicCameraCount++;
+ break;
+ case SystemCameraKind::SYSTEM_ONLY_CAMERA:
+ systemCameraCount++;
+ break;
+ default:
+ break;
+ }
}
}
- return count;
+ return std::make_pair(systemCameraCount, publicCameraCount);
}
std::vector<std::string> CameraProviderManager::getCameraDeviceIds() const {
@@ -130,25 +145,47 @@
return deviceIds;
}
+void CameraProviderManager::collectDeviceIdsLocked(const std::vector<std::string> deviceIds,
+ std::vector<std::string>& publicDeviceIds,
+ std::vector<std::string>& systemDeviceIds) const {
+ for (auto &deviceId : deviceIds) {
+ SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
+ if (getSystemCameraKindLocked(deviceId, &deviceKind) != OK) {
+ ALOGE("%s: Invalid camera id %s, skipping", __FUNCTION__, deviceId.c_str());
+ continue;
+ }
+ if (deviceKind == SystemCameraKind::SYSTEM_ONLY_CAMERA) {
+ systemDeviceIds.push_back(deviceId);
+ } else {
+ publicDeviceIds.push_back(deviceId);
+ }
+ }
+}
+
std::vector<std::string> CameraProviderManager::getAPI1CompatibleCameraDeviceIds() const {
std::lock_guard<std::mutex> lock(mInterfaceMutex);
+ std::vector<std::string> publicDeviceIds;
+ std::vector<std::string> systemDeviceIds;
std::vector<std::string> deviceIds;
for (auto& provider : mProviders) {
std::vector<std::string> providerDeviceIds = provider->mUniqueAPI1CompatibleCameraIds;
-
+ // Secure cameras should not be exposed through camera 1 api
+ providerDeviceIds.erase(std::remove_if(providerDeviceIds.begin(), providerDeviceIds.end(),
+ [this](const std::string& s) {
+ SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
+ if (getSystemCameraKindLocked(s, &deviceKind) != OK) {
+ ALOGE("%s: Invalid camera id %s, skipping", __FUNCTION__, s.c_str());
+ return true;
+ }
+ return deviceKind == SystemCameraKind::HIDDEN_SECURE_CAMERA;}),
+ providerDeviceIds.end());
// API1 app doesn't handle logical and physical camera devices well. So
// for each camera facing, only take the first id advertised by HAL in
// all [logical, physical1, physical2, ...] id combos, and filter out the rest.
filterLogicalCameraIdsLocked(providerDeviceIds);
- // Hidden secure camera ids are not to be exposed to camera1 api.
- providerDeviceIds.erase(std::remove_if(providerDeviceIds.begin(), providerDeviceIds.end(),
- [this](const std::string& s) {
- return this->isPublicallyHiddenSecureCameraLocked(s);}),
- providerDeviceIds.end());
- deviceIds.insert(deviceIds.end(), providerDeviceIds.begin(), providerDeviceIds.end());
+ collectDeviceIdsLocked(providerDeviceIds, publicDeviceIds, systemDeviceIds);
}
-
- std::sort(deviceIds.begin(), deviceIds.end(),
+ auto sortFunc =
[](const std::string& a, const std::string& b) -> bool {
uint32_t aUint = 0, bUint = 0;
bool aIsUint = base::ParseUint(a, &aUint);
@@ -164,7 +201,13 @@
}
// Simple string compare if both id are not uint
return a < b;
- });
+ };
+ // We put device ids for system cameras at the end since they will be pared
+ // off for processes not having system camera permissions.
+ std::sort(publicDeviceIds.begin(), publicDeviceIds.end(), sortFunc);
+ std::sort(systemDeviceIds.begin(), systemDeviceIds.end(), sortFunc);
+ deviceIds.insert(deviceIds.end(), publicDeviceIds.begin(), publicDeviceIds.end());
+ deviceIds.insert(deviceIds.end(), systemDeviceIds.begin(), systemDeviceIds.end());
return deviceIds;
}
@@ -193,6 +236,15 @@
return deviceInfo->hasFlashUnit();
}
+bool CameraProviderManager::supportNativeZoomRatio(const std::string &id) const {
+ std::lock_guard<std::mutex> lock(mInterfaceMutex);
+
+ auto deviceInfo = findDeviceInfoLocked(id);
+ if (deviceInfo == nullptr) return false;
+
+ return deviceInfo->supportNativeZoomRatio();
+}
+
status_t CameraProviderManager::getResourceCost(const std::string &id,
CameraResourceCost* cost) const {
std::lock_guard<std::mutex> lock(mInterfaceMutex);
@@ -218,7 +270,6 @@
const hardware::camera::device::V3_4::StreamConfiguration &configuration,
bool *status /*out*/) const {
std::lock_guard<std::mutex> lock(mInterfaceMutex);
-
auto deviceInfo = findDeviceInfoLocked(id);
if (deviceInfo == nullptr) {
return NAME_NOT_FOUND;
@@ -275,8 +326,11 @@
// Pass the camera ID to start interface so that it will save it to the map of ICameraProviders
// that are currently in use.
- const sp<provider::V2_4::ICameraProvider> interface =
- deviceInfo->mParentProvider->startProviderInterface();
+ sp<ProviderInfo> parentProvider = deviceInfo->mParentProvider.promote();
+ if (parentProvider == nullptr) {
+ return DEAD_OBJECT;
+ }
+ const sp<provider::V2_4::ICameraProvider> interface = parentProvider->startProviderInterface();
if (interface == nullptr) {
return DEAD_OBJECT;
}
@@ -329,8 +383,11 @@
if (deviceInfo == nullptr) return NAME_NOT_FOUND;
auto *deviceInfo3 = static_cast<ProviderInfo::DeviceInfo3*>(deviceInfo);
- const sp<provider::V2_4::ICameraProvider> provider =
- deviceInfo->mParentProvider->startProviderInterface();
+ sp<ProviderInfo> parentProvider = deviceInfo->mParentProvider.promote();
+ if (parentProvider == nullptr) {
+ return DEAD_OBJECT;
+ }
+ const sp<provider::V2_4::ICameraProvider> provider = parentProvider->startProviderInterface();
if (provider == nullptr) {
return DEAD_OBJECT;
}
@@ -372,8 +429,11 @@
if (deviceInfo == nullptr) return NAME_NOT_FOUND;
auto *deviceInfo1 = static_cast<ProviderInfo::DeviceInfo1*>(deviceInfo);
- const sp<provider::V2_4::ICameraProvider> provider =
- deviceInfo->mParentProvider->startProviderInterface();
+ sp<ProviderInfo> parentProvider = deviceInfo->mParentProvider.promote();
+ if (parentProvider == nullptr) {
+ return DEAD_OBJECT;
+ }
+ const sp<provider::V2_4::ICameraProvider> provider = parentProvider->startProviderInterface();
if (provider == nullptr) {
return DEAD_OBJECT;
}
@@ -544,15 +604,23 @@
}
}
-bool CameraProviderManager::ProviderInfo::DeviceInfo3::isPublicallyHiddenSecureCamera() {
+SystemCameraKind CameraProviderManager::ProviderInfo::DeviceInfo3::getSystemCameraKind() {
camera_metadata_entry_t entryCap;
entryCap = mCameraCharacteristics.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
- if (entryCap.count != 1) {
- // Do NOT hide this camera device if the capabilities specify anything more
- // than ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA.
- return false;
+ if (entryCap.count == 1 &&
+ entryCap.data.u8[0] == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA) {
+ return SystemCameraKind::HIDDEN_SECURE_CAMERA;
}
- return entryCap.data.u8[0] == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA;
+
+ // Go through the capabilities and check if it has
+ // ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA
+ for (size_t i = 0; i < entryCap.count; ++i) {
+ uint8_t capability = entryCap.data.u8[i];
+ if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA) {
+ return SystemCameraKind::SYSTEM_ONLY_CAMERA;
+ }
+ }
+ return SystemCameraKind::PUBLIC;
}
void CameraProviderManager::ProviderInfo::DeviceInfo3::getSupportedSizes(
@@ -659,31 +727,6 @@
}
}
-bool CameraProviderManager::ProviderInfo::DeviceInfo3::isDepthPhotoLibraryPresent() {
- static bool libraryPresent = false;
- static bool initialized = false;
- if (initialized) {
- return libraryPresent;
- } else {
- initialized = true;
- }
-
- void* depthLibHandle = dlopen(camera3::kDepthPhotoLibrary, RTLD_NOW | RTLD_LOCAL);
- if (depthLibHandle == nullptr) {
- return false;
- }
-
- auto processFunc = dlsym(depthLibHandle, camera3::kDepthPhotoProcessFunction);
- if (processFunc != nullptr) {
- libraryPresent = true;
- } else {
- libraryPresent = false;
- }
- dlclose(depthLibHandle);
-
- return libraryPresent;
-}
-
status_t CameraProviderManager::ProviderInfo::DeviceInfo3::addDynamicDepthTags() {
uint32_t depthExclTag = ANDROID_DEPTH_DEPTH_IS_EXCLUSIVE;
uint32_t depthSizesTag = ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS;
@@ -731,11 +774,6 @@
return OK;
}
- if(!isDepthPhotoLibraryPresent()) {
- // Depth photo processing library is not present, nothing more to do.
- return OK;
- }
-
std::vector<int32_t> dynamicDepthEntries;
for (const auto& it : supportedDynamicDepthSizes) {
int32_t entry[4] = {HAL_PIXEL_FORMAT_BLOB, static_cast<int32_t> (std::get<0>(it)),
@@ -899,6 +937,19 @@
return res;
}
+status_t CameraProviderManager::ProviderInfo::DeviceInfo3::addRotateCropTags() {
+ status_t res = OK;
+ auto& c = mCameraCharacteristics;
+
+ auto availableRotateCropEntry = c.find(ANDROID_SCALER_AVAILABLE_ROTATE_AND_CROP_MODES);
+ if (availableRotateCropEntry.count == 0) {
+ uint8_t defaultAvailableRotateCropEntry = ANDROID_SCALER_ROTATE_AND_CROP_NONE;
+ res = c.update(ANDROID_SCALER_AVAILABLE_ROTATE_AND_CROP_MODES,
+ &defaultAvailableRotateCropEntry, 1);
+ }
+ return res;
+}
+
status_t CameraProviderManager::ProviderInfo::DeviceInfo3::removeAvailableKeys(
CameraMetadata& c, const std::vector<uint32_t>& keys, uint32_t keyTag) {
status_t res = OK;
@@ -957,7 +1008,8 @@
if (sizeAvail) continue;
int64_t stall = 0;
- bool useHeic, useGrid;
+ bool useHeic = false;
+ bool useGrid = false;
if (camera3::HeicCompositeStream::isSizeSupportedByHeifEncoder(
halStreamConfigs.data.i32[i+1], halStreamConfigs.data.i32[i+2],
&useHeic, &useGrid, &stall)) {
@@ -1043,10 +1095,8 @@
return OK;
}
-bool CameraProviderManager::isLogicalCamera(const std::string& id,
+bool CameraProviderManager::isLogicalCameraLocked(const std::string& id,
std::vector<std::string>* physicalCameraIds) {
- std::lock_guard<std::mutex> lock(mInterfaceMutex);
-
auto deviceInfo = findDeviceInfoLocked(id);
if (deviceInfo == nullptr) return false;
@@ -1056,15 +1106,24 @@
return deviceInfo->mIsLogicalCamera;
}
-bool CameraProviderManager::isPublicallyHiddenSecureCamera(const std::string& id) const {
+bool CameraProviderManager::isLogicalCamera(const std::string& id,
+ std::vector<std::string>* physicalCameraIds) {
std::lock_guard<std::mutex> lock(mInterfaceMutex);
- return isPublicallyHiddenSecureCameraLocked(id);
+ return isLogicalCameraLocked(id, physicalCameraIds);
}
-bool CameraProviderManager::isPublicallyHiddenSecureCameraLocked(const std::string& id) const {
+status_t CameraProviderManager::getSystemCameraKind(const std::string& id,
+ SystemCameraKind *kind) const {
+ std::lock_guard<std::mutex> lock(mInterfaceMutex);
+ return getSystemCameraKindLocked(id, kind);
+}
+
+status_t CameraProviderManager::getSystemCameraKindLocked(const std::string& id,
+ SystemCameraKind *kind) const {
auto deviceInfo = findDeviceInfoLocked(id);
if (deviceInfo != nullptr) {
- return deviceInfo->mIsPublicallyHiddenSecureCamera;
+ *kind = deviceInfo->mSystemCameraKind;
+ return OK;
}
// If this is a hidden physical camera, we should return what kind of
// camera the enclosing logical camera is.
@@ -1073,10 +1132,10 @@
LOG_ALWAYS_FATAL_IF(id == isHiddenAndParent.second->mId,
"%s: hidden physical camera id %s and enclosing logical camera id %s are the same",
__FUNCTION__, id.c_str(), isHiddenAndParent.second->mId.c_str());
- return isPublicallyHiddenSecureCameraLocked(isHiddenAndParent.second->mId);
+ return getSystemCameraKindLocked(isHiddenAndParent.second->mId, kind);
}
- // Invalid camera id
- return true;
+ // Neither a hidden physical camera nor a logical camera
+ return NAME_NOT_FOUND;
}
bool CameraProviderManager::isHiddenPhysicalCamera(const std::string& cameraId) const {
@@ -1137,7 +1196,7 @@
}
sp<provider::V2_4::ICameraProvider> interface;
- interface = mServiceProxy->getService(newProvider);
+ interface = mServiceProxy->tryGetService(newProvider);
if (interface == nullptr) {
ALOGE("%s: Camera provider HAL '%s' is not actually available", __FUNCTION__,
@@ -1218,25 +1277,27 @@
mProviderName.c_str(), interface->isRemote());
// Determine minor version
- auto castResult = provider::V2_5::ICameraProvider::castFrom(interface);
- if (castResult.isOk()) {
- mMinorVersion = 5;
- } else {
- mMinorVersion = 4;
+ mMinorVersion = 4;
+ auto cast2_6 = provider::V2_6::ICameraProvider::castFrom(interface);
+ sp<provider::V2_6::ICameraProvider> interface2_6 = nullptr;
+ if (cast2_6.isOk()) {
+ interface2_6 = cast2_6;
+ if (interface2_6 != nullptr) {
+ mMinorVersion = 6;
+ }
}
-
- // cameraDeviceStatusChange callbacks may be called (and causing new devices added)
- // before setCallback returns
- hardware::Return<Status> status = interface->setCallback(this);
- if (!status.isOk()) {
- ALOGE("%s: Transaction error setting up callbacks with camera provider '%s': %s",
- __FUNCTION__, mProviderName.c_str(), status.description().c_str());
- return DEAD_OBJECT;
- }
- if (status != Status::OK) {
- ALOGE("%s: Unable to register callbacks with camera provider '%s'",
- __FUNCTION__, mProviderName.c_str());
- return mapToStatusT(status);
+ // We need to check again since cast2_6.isOk() succeeds even if the provider
+ // version isn't actually 2.6.
+ if (interface2_6 == nullptr){
+ auto cast2_5 =
+ provider::V2_5::ICameraProvider::castFrom(interface);
+ sp<provider::V2_5::ICameraProvider> interface2_5 = nullptr;
+ if (cast2_5.isOk()) {
+ interface2_5 = cast2_5;
+ if (interface != nullptr) {
+ mMinorVersion = 5;
+ }
+ }
}
hardware::Return<bool> linked = interface->linkToDeath(this, /*cookie*/ mId);
@@ -1267,6 +1328,7 @@
return res;
}
+ Status status;
// Get initial list of camera devices, if any
std::vector<std::string> devices;
hardware::Return<void> ret = interface->getCameraIdList([&status, this, &devices](
@@ -1298,6 +1360,14 @@
return mapToStatusT(status);
}
+ // Get list of concurrent streaming camera device combinations
+ if (mMinorVersion >= 6) {
+ res = getConcurrentCameraIdsInternalLocked(interface2_6);
+ if (res != OK) {
+ return res;
+ }
+ }
+
ret = interface->isSetTorchModeSupported(
[this](auto status, bool supported) {
if (status == Status::OK) {
@@ -1323,6 +1393,22 @@
}
}
+ // cameraDeviceStatusChange callbacks may be called (and causing new devices added)
+ // before setCallback returns. setCallback must be called after addDevice so that
+ // the physical camera status callback can look up available regular
+ // cameras.
+ hardware::Return<Status> st = interface->setCallback(this);
+ if (!st.isOk()) {
+ ALOGE("%s: Transaction error setting up callbacks with camera provider '%s': %s",
+ __FUNCTION__, mProviderName.c_str(), st.description().c_str());
+ return DEAD_OBJECT;
+ }
+ if (st != Status::OK) {
+ ALOGE("%s: Unable to register callbacks with camera provider '%s'",
+ __FUNCTION__, mProviderName.c_str());
+ return mapToStatusT(st);
+ }
+
ALOGI("Camera provider %s ready with %zu camera devices",
mProviderName.c_str(), mDevices.size());
@@ -1530,6 +1616,75 @@
return OK;
}
+status_t CameraProviderManager::ProviderInfo::getConcurrentCameraIdsInternalLocked(
+ sp<provider::V2_6::ICameraProvider> &interface2_6) {
+ if (interface2_6 == nullptr) {
+ ALOGE("%s: null interface provided", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ Status status = Status::OK;
+ hardware::Return<void> ret =
+ interface2_6->getConcurrentStreamingCameraIds([&status, this](
+ Status concurrentIdStatus, // TODO: Move all instances of hidl_string to 'using'
+ const hardware::hidl_vec<hardware::hidl_vec<hardware::hidl_string>>&
+ cameraDeviceIdCombinations) {
+ status = concurrentIdStatus;
+ if (status == Status::OK) {
+ mConcurrentCameraIdCombinations.clear();
+ for (auto& combination : cameraDeviceIdCombinations) {
+ std::unordered_set<std::string> deviceIds;
+ for (auto &cameraDeviceId : combination) {
+ deviceIds.insert(cameraDeviceId.c_str());
+ }
+ mConcurrentCameraIdCombinations.push_back(std::move(deviceIds));
+ }
+ } });
+ if (!ret.isOk()) {
+ ALOGE("%s: Transaction error in getting concurrent camera ID list from provider '%s'",
+ __FUNCTION__, mProviderName.c_str());
+ return DEAD_OBJECT;
+ }
+ if (status != Status::OK) {
+ ALOGE("%s: Unable to query for camera devices from provider '%s'",
+ __FUNCTION__, mProviderName.c_str());
+ return mapToStatusT(status);
+ }
+ return OK;
+}
+
+status_t CameraProviderManager::ProviderInfo::reCacheConcurrentStreamingCameraIdsLocked() {
+ if (mMinorVersion < 6) {
+ // Unsupported operation, nothing to do here
+ return OK;
+ }
+ // Check if the provider is currently active - not going to start it up for this notification
+ auto interface = mSavedInterface != nullptr ? mSavedInterface : mActiveInterface.promote();
+ if (interface == nullptr) {
+ ALOGE("%s: camera provider interface for %s is not valid", __FUNCTION__,
+ mProviderName.c_str());
+ return INVALID_OPERATION;
+ }
+ auto castResult = provider::V2_6::ICameraProvider::castFrom(interface);
+
+ if (castResult.isOk()) {
+ sp<provider::V2_6::ICameraProvider> interface2_6 = castResult;
+ if (interface2_6 != nullptr) {
+ return getConcurrentCameraIdsInternalLocked(interface2_6);
+ } else {
+ // This should not happen since mMinorVersion >= 6
+ ALOGE("%s: mMinorVersion was >= 6, but interface2_6 was nullptr", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+ }
+ return OK;
+}
+
+std::vector<std::unordered_set<std::string>>
+CameraProviderManager::ProviderInfo::getConcurrentCameraIdCombinations() {
+ std::lock_guard<std::mutex> lock(mLock);
+ return mConcurrentCameraIdCombinations;
+}
+
hardware::Return<void> CameraProviderManager::ProviderInfo::cameraDeviceStatusChange(
const hardware::hidl_string& cameraDeviceName,
CameraDeviceStatus newStatus) {
@@ -1563,6 +1718,10 @@
}
listener = mManager->getStatusListener();
initialized = mInitialized;
+ if (reCacheConcurrentStreamingCameraIdsLocked() != OK) {
+ ALOGE("%s: CameraProvider %s could not re-cache concurrent streaming camera id list ",
+ __FUNCTION__, mProviderName.c_str());
+ }
}
// Call without lock held to allow reentrancy into provider manager
// Don't send the callback if providerInfo hasn't been initialized.
@@ -1574,6 +1733,61 @@
return hardware::Void();
}
+hardware::Return<void> CameraProviderManager::ProviderInfo::physicalCameraDeviceStatusChange(
+ const hardware::hidl_string& cameraDeviceName,
+ const hardware::hidl_string& physicalCameraDeviceName,
+ CameraDeviceStatus newStatus) {
+ sp<StatusListener> listener;
+ std::string id;
+ bool initialized = false;
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ bool known = false;
+ for (auto& deviceInfo : mDevices) {
+ if (deviceInfo->mName == cameraDeviceName) {
+ id = deviceInfo->mId;
+
+ if (!deviceInfo->mIsLogicalCamera) {
+ ALOGE("%s: Invalid combination of camera id %s, physical id %s",
+ __FUNCTION__, id.c_str(), physicalCameraDeviceName.c_str());
+ return hardware::Void();
+ }
+ if (std::find(deviceInfo->mPhysicalIds.begin(), deviceInfo->mPhysicalIds.end(),
+ physicalCameraDeviceName) == deviceInfo->mPhysicalIds.end()) {
+ ALOGE("%s: Invalid combination of camera id %s, physical id %s",
+ __FUNCTION__, id.c_str(), physicalCameraDeviceName.c_str());
+ return hardware::Void();
+ }
+ ALOGI("Camera device %s physical device %s status is now %s, was %s",
+ cameraDeviceName.c_str(), physicalCameraDeviceName.c_str(),
+ deviceStatusToString(newStatus), deviceStatusToString(
+ deviceInfo->mPhysicalStatus[physicalCameraDeviceName]));
+ known = true;
+ break;
+ }
+ }
+ // Previously unseen device; status must not be NOT_PRESENT
+ if (!known) {
+ ALOGW("Camera provider %s says an unknown camera device %s-%s is not present. Curious.",
+ mProviderName.c_str(), cameraDeviceName.c_str(),
+ physicalCameraDeviceName.c_str());
+ return hardware::Void();
+ }
+ listener = mManager->getStatusListener();
+ initialized = mInitialized;
+ }
+ // Call without lock held to allow reentrancy into provider manager
+ // Don't send the callback if providerInfo hasn't been initialized.
+ // CameraService will initialize device status after provider is
+ // initialized
+ if (listener != nullptr && initialized) {
+ String8 physicalId(physicalCameraDeviceName.c_str());
+ listener->onDeviceStatusChanged(String8(id.c_str()),
+ physicalId, newStatus);
+ }
+ return hardware::Void();
+}
+
hardware::Return<void> CameraProviderManager::ProviderInfo::torchModeStatusChange(
const hardware::hidl_string& cameraDeviceName,
TorchModeStatus newStatus) {
@@ -1679,6 +1893,55 @@
return OK;
}
+status_t CameraProviderManager::ProviderInfo::isConcurrentSessionConfigurationSupported(
+ const hardware::hidl_vec<CameraIdAndStreamCombination> &halCameraIdsAndStreamCombinations,
+ bool *isSupported) {
+ status_t res = OK;
+ if (mMinorVersion >= 6) {
+ // Check if the provider is currently active - not going to start it up for this notification
+ auto interface = mSavedInterface != nullptr ? mSavedInterface : mActiveInterface.promote();
+ if (interface == nullptr) {
+ // TODO: This might be some other problem
+ return INVALID_OPERATION;
+ }
+ auto castResult = provider::V2_6::ICameraProvider::castFrom(interface);
+ if (castResult.isOk()) {
+ sp<provider::V2_6::ICameraProvider> interface_2_6 = castResult;
+ if (interface_2_6 != nullptr) {
+ Status callStatus;
+ auto cb =
+ [&isSupported, &callStatus](Status s, bool supported) {
+ callStatus = s;
+ *isSupported = supported; };
+
+ auto ret = interface_2_6->isConcurrentStreamCombinationSupported(
+ halCameraIdsAndStreamCombinations, cb);
+ if (ret.isOk()) {
+ switch (callStatus) {
+ case Status::OK:
+ // Expected case, do nothing.
+ res = OK;
+ break;
+ case Status::METHOD_NOT_SUPPORTED:
+ res = INVALID_OPERATION;
+ break;
+ default:
+ ALOGE("%s: Session configuration query failed: %d", __FUNCTION__,
+ callStatus);
+ res = UNKNOWN_ERROR;
+ }
+ } else {
+ ALOGE("%s: Unexpected binder error: %s", __FUNCTION__, ret.description().c_str());
+ res = UNKNOWN_ERROR;
+ }
+ return res;
+ }
+ }
+ }
+ // unsupported operation
+ return INVALID_OPERATION;
+}
+
template<class DeviceInfoT>
std::unique_ptr<CameraProviderManager::ProviderInfo::DeviceInfo>
CameraProviderManager::ProviderInfo::initializeDeviceInfo(
@@ -1791,7 +2054,10 @@
sp<InterfaceT> device;
ATRACE_CALL();
if (mSavedInterface == nullptr) {
- device = mParentProvider->startDeviceInterface<InterfaceT>(mName);
+ sp<ProviderInfo> parentProvider = mParentProvider.promote();
+ if (parentProvider != nullptr) {
+ device = parentProvider->startDeviceInterface<InterfaceT>(mName);
+ }
} else {
device = (InterfaceT *) mSavedInterface.get();
}
@@ -1966,7 +2232,7 @@
return;
}
- mIsPublicallyHiddenSecureCamera = isPublicallyHiddenSecureCamera();
+ mSystemCameraKind = getSystemCameraKind();
status_t res = fixupMonochromeTags();
if (OK != res) {
@@ -1984,6 +2250,18 @@
ALOGE("%s: Unable to derive HEIC tags based on camera and media capabilities: %s (%d)",
__FUNCTION__, strerror(-res), res);
}
+ res = addRotateCropTags();
+ if (OK != res) {
+ ALOGE("%s: Unable to add default SCALER_ROTATE_AND_CROP tags: %s (%d)", __FUNCTION__,
+ strerror(-res), res);
+ }
+
+ res = camera3::ZoomRatioMapper::overrideZoomRatioTags(
+ &mCameraCharacteristics, &mSupportNativeZoomRatio);
+ if (OK != res) {
+ ALOGE("%s: Unable to override zoomRatio related tags: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ }
camera_metadata_entry flashAvailable =
mCameraCharacteristics.find(ANDROID_FLASH_INFO_AVAILABLE);
@@ -2045,6 +2323,13 @@
CameraProviderManager::statusToString(status), status);
return;
}
+
+ res = camera3::ZoomRatioMapper::overrideZoomRatioTags(
+ &mPhysicalCameraCharacteristics[id], &mSupportNativeZoomRatio);
+ if (OK != res) {
+ ALOGE("%s: Unable to override zoomRatio related tags: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ }
}
}
@@ -2522,6 +2807,125 @@
return OK;
}
+// Expects to have mInterfaceMutex locked
+std::vector<std::unordered_set<std::string>>
+CameraProviderManager::getConcurrentCameraIds() const {
+ std::vector<std::unordered_set<std::string>> deviceIdCombinations;
+ std::lock_guard<std::mutex> lock(mInterfaceMutex);
+ for (auto &provider : mProviders) {
+ for (auto &combinations : provider->getConcurrentCameraIdCombinations()) {
+ deviceIdCombinations.push_back(combinations);
+ }
+ }
+ return deviceIdCombinations;
+}
+
+status_t CameraProviderManager::convertToHALStreamCombinationAndCameraIdsLocked(
+ const std::vector<CameraIdAndSessionConfiguration> &cameraIdsAndSessionConfigs,
+ hardware::hidl_vec<CameraIdAndStreamCombination> *halCameraIdsAndStreamCombinations,
+ bool *earlyExit) {
+ binder::Status bStatus = binder::Status::ok();
+ std::vector<CameraIdAndStreamCombination> halCameraIdsAndStreamsV;
+ bool shouldExit = false;
+ status_t res = OK;
+ for (auto &cameraIdAndSessionConfig : cameraIdsAndSessionConfigs) {
+ hardware::camera::device::V3_4::StreamConfiguration streamConfiguration;
+ CameraMetadata deviceInfo;
+ res = getCameraCharacteristicsLocked(cameraIdAndSessionConfig.mCameraId, &deviceInfo);
+ if (res != OK) {
+ return res;
+ }
+ metadataGetter getMetadata =
+ [this](const String8 &id) {
+ CameraMetadata physicalDeviceInfo;
+ getCameraCharacteristicsLocked(id.string(), &physicalDeviceInfo);
+ return physicalDeviceInfo;
+ };
+ std::vector<std::string> physicalCameraIds;
+ isLogicalCameraLocked(cameraIdAndSessionConfig.mCameraId, &physicalCameraIds);
+ bStatus =
+ SessionConfigurationUtils::convertToHALStreamCombination(
+ cameraIdAndSessionConfig.mSessionConfiguration,
+ String8(cameraIdAndSessionConfig.mCameraId.c_str()), deviceInfo, getMetadata,
+ physicalCameraIds, streamConfiguration, &shouldExit);
+ if (!bStatus.isOk()) {
+ ALOGE("%s: convertToHALStreamCombination failed", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if (shouldExit) {
+ *earlyExit = true;
+ return OK;
+ }
+ CameraIdAndStreamCombination halCameraIdAndStream;
+ halCameraIdAndStream.cameraId = cameraIdAndSessionConfig.mCameraId;
+ halCameraIdAndStream.streamConfiguration = streamConfiguration;
+ halCameraIdsAndStreamsV.push_back(halCameraIdAndStream);
+ }
+ *halCameraIdsAndStreamCombinations = halCameraIdsAndStreamsV;
+ return OK;
+}
+
+// Checks if the containing vector of sets has any set that contains all of the
+// camera ids in cameraIdsAndSessionConfigs.
+static bool checkIfSetContainsAll(
+ const std::vector<CameraIdAndSessionConfiguration> &cameraIdsAndSessionConfigs,
+ const std::vector<std::unordered_set<std::string>> &containingSets) {
+ for (auto &containingSet : containingSets) {
+ bool didHaveAll = true;
+ for (auto &cameraIdAndSessionConfig : cameraIdsAndSessionConfigs) {
+ if (containingSet.find(cameraIdAndSessionConfig.mCameraId) == containingSet.end()) {
+ // a camera id doesn't belong to this set, keep looking in other
+ // sets
+ didHaveAll = false;
+ break;
+ }
+ }
+ if (didHaveAll) {
+ // found a set that has all camera ids, lets return;
+ return true;
+ }
+ }
+ return false;
+}
+
+status_t CameraProviderManager::isConcurrentSessionConfigurationSupported(
+ const std::vector<CameraIdAndSessionConfiguration> &cameraIdsAndSessionConfigs,
+ bool *isSupported) {
+ std::lock_guard<std::mutex> lock(mInterfaceMutex);
+ // Check if all the devices are a subset of devices advertised by the
+ // same provider through getConcurrentStreamingCameraIds()
+ // TODO: we should also do a findDeviceInfoLocked here ?
+ for (auto &provider : mProviders) {
+ if (checkIfSetContainsAll(cameraIdsAndSessionConfigs,
+ provider->getConcurrentCameraIdCombinations())) {
+ // For each camera device in cameraIdsAndSessionConfigs collect
+ // the streamConfigs and create the HAL
+ // CameraIdAndStreamCombination, exit early if needed
+ hardware::hidl_vec<CameraIdAndStreamCombination> halCameraIdsAndStreamCombinations;
+ bool knowUnsupported = false;
+ status_t res = convertToHALStreamCombinationAndCameraIdsLocked(
+ cameraIdsAndSessionConfigs, &halCameraIdsAndStreamCombinations,
+ &knowUnsupported);
+ if (res != OK) {
+ ALOGE("%s unable to convert session configurations provided to HAL stream"
+ "combinations", __FUNCTION__);
+ return res;
+ }
+ if (knowUnsupported) {
+ // We got to know the streams aren't valid before doing the HAL
+ // call itself.
+ *isSupported = false;
+ return OK;
+ }
+ return provider->isConcurrentSessionConfigurationSupported(
+ halCameraIdsAndStreamCombinations, isSupported);
+ }
+ }
+ *isSupported = false;
+ //The set of camera devices were not found
+ return INVALID_OPERATION;
+}
+
status_t CameraProviderManager::getCameraCharacteristicsLocked(const std::string &id,
CameraMetadata* characteristics) const {
auto deviceInfo = findDeviceInfoLocked(id, /*minVersion*/ {3,0}, /*maxVersion*/ {5,0});
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 3a4655c..50044d8 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -23,12 +23,15 @@
#include <string>
#include <mutex>
+#include <camera/camera2/ConcurrentCamera.h>
#include <camera/CameraParameters2.h>
#include <camera/CameraMetadata.h>
#include <camera/CameraBase.h>
#include <utils/Errors.h>
#include <android/hardware/camera/common/1.0/types.h>
#include <android/hardware/camera/provider/2.5/ICameraProvider.h>
+#include <android/hardware/camera/provider/2.6/ICameraProviderCallback.h>
+#include <android/hardware/camera/provider/2.6/ICameraProvider.h>
#include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
#include <android/hidl/manager/1.0/IServiceNotification.h>
#include <camera/VendorTagDescriptor.h>
@@ -54,6 +57,26 @@
sp<VendorTagDescriptor>& descriptor);
};
+enum SystemCameraKind {
+ /**
+ * These camera devices are visible to all apps and system components alike
+ */
+ PUBLIC = 0,
+
+ /**
+ * These camera devices are visible only to processes having the
+ * android.permission.SYSTEM_CAMERA permission. They are not exposed to 3P
+ * apps.
+ */
+ SYSTEM_ONLY_CAMERA,
+
+ /**
+ * These camera devices are visible only to HAL clients (that try to connect
+ * on a hwbinder thread).
+ */
+ HIDDEN_SECURE_CAMERA
+};
+
/**
* A manager for all camera providers available on an Android device.
*
@@ -76,6 +99,10 @@
const std::string &serviceName,
const sp<hidl::manager::V1_0::IServiceNotification>
¬ification) = 0;
+ // Will not wait for service to start if it's not already running
+ virtual sp<hardware::camera::provider::V2_4::ICameraProvider> tryGetService(
+ const std::string &serviceName) = 0;
+ // Will block for service if it exists but isn't running
virtual sp<hardware::camera::provider::V2_4::ICameraProvider> getService(
const std::string &serviceName) = 0;
virtual hardware::hidl_vec<hardware::hidl_string> listServices() = 0;
@@ -92,6 +119,10 @@
return hardware::camera::provider::V2_4::ICameraProvider::registerForNotifications(
serviceName, notification);
}
+ virtual sp<hardware::camera::provider::V2_4::ICameraProvider> tryGetService(
+ const std::string &serviceName) override {
+ return hardware::camera::provider::V2_4::ICameraProvider::tryGetService(serviceName);
+ }
virtual sp<hardware::camera::provider::V2_4::ICameraProvider> getService(
const std::string &serviceName) override {
return hardware::camera::provider::V2_4::ICameraProvider::getService(serviceName);
@@ -108,6 +139,9 @@
virtual void onDeviceStatusChanged(const String8 &cameraId,
hardware::camera::common::V1_0::CameraDeviceStatus newStatus) = 0;
+ virtual void onDeviceStatusChanged(const String8 &cameraId,
+ const String8 &physicalCameraId,
+ hardware::camera::common::V1_0::CameraDeviceStatus newStatus) = 0;
virtual void onTorchStatusChanged(const String8 &cameraId,
hardware::camera::common::V1_0::TorchModeStatus newStatus) = 0;
virtual void onNewProviderRegistered() = 0;
@@ -132,10 +166,10 @@
ServiceInteractionProxy *proxy = &sHardwareServiceInteractionProxy);
/**
- * Retrieve the total number of available cameras. This value may change dynamically as cameras
- * are added or removed.
+ * Retrieve the total number of available cameras.
+ * This value may change dynamically as cameras are added or removed.
*/
- int getCameraCount() const;
+ std::pair<int, int> getCameraCount() const;
std::vector<std::string> getCameraDeviceIds() const;
@@ -159,6 +193,11 @@
bool hasFlashUnit(const std::string &id) const;
/**
+ * Return true if the camera device has native zoom ratio support.
+ */
+ bool supportNativeZoomRatio(const std::string &id) const;
+
+ /**
* Return the resource cost of this camera device
*/
status_t getResourceCost(const std::string &id,
@@ -177,6 +216,12 @@
status_t getCameraCharacteristics(const std::string &id,
CameraMetadata* characteristics) const;
+ status_t isConcurrentSessionConfigurationSupported(
+ const std::vector<hardware::camera2::utils::CameraIdAndSessionConfiguration>
+ &cameraIdsAndSessionConfigs,
+ bool *isSupported);
+
+ std::vector<std::unordered_set<std::string>> getConcurrentCameraIds() const;
/**
* Check for device support of specific stream combination.
*/
@@ -272,7 +317,7 @@
*/
bool isLogicalCamera(const std::string& id, std::vector<std::string>* physicalCameraIds);
- bool isPublicallyHiddenSecureCamera(const std::string& id) const;
+ status_t getSystemCameraKind(const std::string& id, SystemCameraKind *kind) const;
bool isHiddenPhysicalCamera(const std::string& cameraId) const;
static const float kDepthARTolerance;
@@ -309,7 +354,7 @@
std::mutex mProviderInterfaceMapLock;
struct ProviderInfo :
- virtual public hardware::camera::provider::V2_4::ICameraProviderCallback,
+ virtual public hardware::camera::provider::V2_6::ICameraProviderCallback,
virtual public hardware::hidl_death_recipient
{
const std::string mProviderName;
@@ -347,12 +392,16 @@
status_t dump(int fd, const Vector<String16>& args) const;
// ICameraProviderCallbacks interface - these lock the parent mInterfaceMutex
- virtual hardware::Return<void> cameraDeviceStatusChange(
+ hardware::Return<void> cameraDeviceStatusChange(
const hardware::hidl_string& cameraDeviceName,
hardware::camera::common::V1_0::CameraDeviceStatus newStatus) override;
- virtual hardware::Return<void> torchModeStatusChange(
+ hardware::Return<void> torchModeStatusChange(
const hardware::hidl_string& cameraDeviceName,
hardware::camera::common::V1_0::TorchModeStatus newStatus) override;
+ hardware::Return<void> physicalCameraDeviceStatusChange(
+ const hardware::hidl_string& cameraDeviceName,
+ const hardware::hidl_string& physicalCameraDeviceName,
+ hardware::camera::common::V1_0::CameraDeviceStatus newStatus) override;
// hidl_death_recipient interface - this locks the parent mInterfaceMutex
virtual void serviceDied(uint64_t cookie, const wp<hidl::base::V1_0::IBase>& who) override;
@@ -369,6 +418,17 @@
hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState>
newDeviceState);
+ std::vector<std::unordered_set<std::string>> getConcurrentCameraIdCombinations();
+
+ /**
+ * Query the camera provider for concurrent stream configuration support
+ */
+ status_t isConcurrentSessionConfigurationSupported(
+ const hardware::hidl_vec<
+ hardware::camera::provider::V2_6::CameraIdAndStreamCombination>
+ &halCameraIdsAndStreamCombinations,
+ bool *isSupported);
+
// Basic device information, common to all camera devices
struct DeviceInfo {
const std::string mName; // Full instance name
@@ -379,15 +439,18 @@
std::vector<std::string> mPhysicalIds;
hardware::CameraInfo mInfo;
sp<IBase> mSavedInterface;
- bool mIsPublicallyHiddenSecureCamera = false;
+ SystemCameraKind mSystemCameraKind = SystemCameraKind::PUBLIC;
const hardware::camera::common::V1_0::CameraResourceCost mResourceCost;
hardware::camera::common::V1_0::CameraDeviceStatus mStatus;
+ std::map<std::string, hardware::camera::common::V1_0::CameraDeviceStatus>
+ mPhysicalStatus;
- sp<ProviderInfo> mParentProvider;
+ wp<ProviderInfo> mParentProvider;
bool hasFlashUnit() const { return mHasFlashUnit; }
+ bool supportNativeZoomRatio() const { return mSupportNativeZoomRatio; }
virtual status_t setTorchMode(bool enabled) = 0;
virtual status_t getCameraInfo(hardware::CameraInfo *info) const = 0;
virtual bool isAPI1Compatible() const = 0;
@@ -421,10 +484,11 @@
mIsLogicalCamera(false), mResourceCost(resourceCost),
mStatus(hardware::camera::common::V1_0::CameraDeviceStatus::PRESENT),
mParentProvider(parentProvider), mHasFlashUnit(false),
- mPublicCameraIds(publicCameraIds) {}
+ mSupportNativeZoomRatio(false), mPublicCameraIds(publicCameraIds) {}
virtual ~DeviceInfo();
protected:
- bool mHasFlashUnit;
+ bool mHasFlashUnit; // const after constructor
+ bool mSupportNativeZoomRatio; // const after constructor
const std::vector<std::string>& mPublicCameraIds;
template<class InterfaceT>
@@ -497,9 +561,12 @@
CameraMetadata mCameraCharacteristics;
std::unordered_map<std::string, CameraMetadata> mPhysicalCameraCharacteristics;
void queryPhysicalCameraIds();
- bool isPublicallyHiddenSecureCamera();
+ SystemCameraKind getSystemCameraKind();
status_t fixupMonochromeTags();
status_t addDynamicDepthTags();
+ status_t deriveHeicTags();
+ status_t addRotateCropTags();
+
static void getSupportedSizes(const CameraMetadata& ch, uint32_t tag,
android_pixel_format_t format,
std::vector<std::tuple<size_t, size_t>> *sizes /*out*/);
@@ -510,7 +577,6 @@
void getSupportedDynamicDepthDurations(const std::vector<int64_t>& depthDurations,
const std::vector<int64_t>& blobDurations,
std::vector<int64_t> *dynamicDepthDurations /*out*/);
- static bool isDepthPhotoLibraryPresent();
static void getSupportedDynamicDepthSizes(
const std::vector<std::tuple<size_t, size_t>>& blobSizes,
const std::vector<std::tuple<size_t, size_t>>& depthSizes,
@@ -523,7 +589,6 @@
std::vector<int64_t>* stallDurations,
const camera_metadata_entry& halStreamConfigs,
const camera_metadata_entry& halStreamDurations);
- status_t deriveHeicTags();
};
private:
@@ -536,6 +601,8 @@
bool mInitialized = false;
+ std::vector<std::unordered_set<std::string>> mConcurrentCameraIdCombinations;
+
// Templated method to instantiate the right kind of DeviceInfo and call the
// right CameraProvider getCameraDeviceInterface_* method.
template<class DeviceInfoT>
@@ -559,6 +626,12 @@
static metadata_vendor_id_t generateVendorTagId(const std::string &name);
void removeDevice(std::string id);
+
+ // Expects to have mLock locked
+ status_t reCacheConcurrentStreamingCameraIdsLocked();
+ // Expects to have mLock locked
+ status_t getConcurrentCameraIdsInternalLocked(
+ sp<hardware::camera::provider::V2_6::ICameraProvider> &interface2_6);
};
// Utility to find a DeviceInfo by ID; pointer is only valid while mInterfaceMutex is held
@@ -572,6 +645,8 @@
status_t addProviderLocked(const std::string& newProvider);
+ bool isLogicalCameraLocked(const std::string& id, std::vector<std::string>* physicalCameraIds);
+
status_t removeProvider(const std::string& provider);
sp<StatusListener> getStatusListener() const;
@@ -594,15 +669,21 @@
status_t getCameraCharacteristicsLocked(const std::string &id,
CameraMetadata* characteristics) const;
-
- bool isPublicallyHiddenSecureCameraLocked(const std::string& id) const;
-
void filterLogicalCameraIdsLocked(std::vector<std::string>& deviceIds) const;
- bool isPublicallyHiddenSecureCameraLocked(const std::string& id);
+ status_t getSystemCameraKindLocked(const std::string& id, SystemCameraKind *kind) const;
+ std::pair<bool, ProviderInfo::DeviceInfo *> isHiddenPhysicalCameraInternal(const std::string& cameraId) const;
- std::pair<bool, CameraProviderManager::ProviderInfo::DeviceInfo *>
- isHiddenPhysicalCameraInternal(const std::string& cameraId) const;
+ void collectDeviceIdsLocked(const std::vector<std::string> deviceIds,
+ std::vector<std::string>& normalDeviceIds,
+ std::vector<std::string>& systemCameraDeviceIds) const;
+
+ status_t convertToHALStreamCombinationAndCameraIdsLocked(
+ const std::vector<hardware::camera2::utils::CameraIdAndSessionConfiguration>
+ &cameraIdsAndSessionConfigs,
+ hardware::hidl_vec<hardware::camera::provider::V2_6::CameraIdAndStreamCombination>
+ *halCameraIdsAndStreamCombinations,
+ bool *earlyExit);
};
} // namespace android
diff --git a/services/camera/libcameraservice/common/DepthPhotoProcessor.cpp b/services/camera/libcameraservice/common/DepthPhotoProcessor.cpp
index 94541d8..c995670 100644
--- a/services/camera/libcameraservice/common/DepthPhotoProcessor.cpp
+++ b/services/camera/libcameraservice/common/DepthPhotoProcessor.cpp
@@ -410,7 +410,7 @@
return DepthMap::FromData(depthParams, items);
}
-extern "C" int processDepthPhotoFrame(DepthPhotoInputFrame inputFrame, size_t depthPhotoBufferSize,
+int processDepthPhotoFrame(DepthPhotoInputFrame inputFrame, size_t depthPhotoBufferSize,
void* depthPhotoBuffer /*out*/, size_t* depthPhotoActualSize /*out*/) {
if ((inputFrame.mMainJpegBuffer == nullptr) || (inputFrame.mDepthMapBuffer == nullptr) ||
(depthPhotoBuffer == nullptr) || (depthPhotoActualSize == nullptr)) {
diff --git a/services/camera/libcameraservice/common/DepthPhotoProcessor.h b/services/camera/libcameraservice/common/DepthPhotoProcessor.h
index ba5ca9e..09b6935 100644
--- a/services/camera/libcameraservice/common/DepthPhotoProcessor.h
+++ b/services/camera/libcameraservice/common/DepthPhotoProcessor.h
@@ -64,9 +64,7 @@
mOrientation(DepthPhotoOrientation::DEPTH_ORIENTATION_0_DEGREES) {}
};
-static const char *kDepthPhotoLibrary = "libdepthphoto.so";
-static const char *kDepthPhotoProcessFunction = "processDepthPhotoFrame";
-typedef int (*process_depth_photo_frame) (DepthPhotoInputFrame /*inputFrame*/,
+int processDepthPhotoFrame(DepthPhotoInputFrame /*inputFrame*/,
size_t /*depthPhotoBufferSize*/, void* /*depthPhotoBuffer out*/,
size_t* /*depthPhotoActualSize out*/);
diff --git a/services/camera/libcameraservice/common/FrameProcessorBase.cpp b/services/camera/libcameraservice/common/FrameProcessorBase.cpp
index 3d56cd2..e259379 100644
--- a/services/camera/libcameraservice/common/FrameProcessorBase.cpp
+++ b/services/camera/libcameraservice/common/FrameProcessorBase.cpp
@@ -18,20 +18,21 @@
#define ATRACE_TAG ATRACE_TAG_CAMERA
//#define LOG_NDEBUG 0
+#include <map>
#include <utils/Log.h>
#include <utils/Trace.h>
+#include "common/FrameProducer.h"
#include "common/FrameProcessorBase.h"
-#include "common/CameraDeviceBase.h"
namespace android {
namespace camera2 {
-FrameProcessorBase::FrameProcessorBase(wp<CameraDeviceBase> device) :
+FrameProcessorBase::FrameProcessorBase(wp<FrameProducer> device) :
Thread(/*canCallJava*/false),
mDevice(device),
mNumPartialResults(1) {
- sp<CameraDeviceBase> cameraDevice = device.promote();
+ sp<FrameProducer> cameraDevice = device.promote();
if (cameraDevice != 0) {
CameraMetadata staticInfo = cameraDevice->info();
camera_metadata_entry_t entry = staticInfo.find(ANDROID_REQUEST_PARTIAL_RESULT_COUNT);
@@ -115,7 +116,7 @@
bool FrameProcessorBase::threadLoop() {
status_t res;
- sp<CameraDeviceBase> device;
+ sp<FrameProducer> device;
{
device = mDevice.promote();
if (device == 0) return false;
@@ -132,7 +133,7 @@
return true;
}
-void FrameProcessorBase::processNewFrames(const sp<CameraDeviceBase> &device) {
+void FrameProcessorBase::processNewFrames(const sp<FrameProducer> &device) {
status_t res;
ATRACE_CALL();
CaptureResult result;
@@ -142,7 +143,7 @@
while ( (res = device->getNextResult(&result)) == OK) {
// TODO: instead of getting frame number from metadata, we should read
- // this from result.mResultExtras when CameraDeviceBase interface is fixed.
+ // this from result.mResultExtras when FrameProducer interface is fixed.
camera_metadata_entry_t entry;
entry = result.mMetadata.find(ANDROID_REQUEST_FRAME_COUNT);
@@ -174,14 +175,14 @@
}
bool FrameProcessorBase::processSingleFrame(CaptureResult &result,
- const sp<CameraDeviceBase> &device) {
+ const sp<FrameProducer> &device) {
ALOGV("%s: Camera %s: Process single frame (is empty? %d)",
__FUNCTION__, device->getId().string(), result.mMetadata.isEmpty());
return processListeners(result, device) == OK;
}
status_t FrameProcessorBase::processListeners(const CaptureResult &result,
- const sp<CameraDeviceBase> &device) {
+ const sp<FrameProducer> &device) {
ATRACE_CALL();
camera_metadata_ro_entry_t entry;
diff --git a/services/camera/libcameraservice/common/FrameProcessorBase.h b/services/camera/libcameraservice/common/FrameProcessorBase.h
index ae6d15d..be1ebc6 100644
--- a/services/camera/libcameraservice/common/FrameProcessorBase.h
+++ b/services/camera/libcameraservice/common/FrameProcessorBase.h
@@ -27,22 +27,25 @@
namespace android {
-class CameraDeviceBase;
+class FrameProducer;
namespace camera2 {
/* Output frame metadata processing thread. This thread waits for new
- * frames from the device, and analyzes them as necessary.
+ * frames from the frame producer, and analyzes them as necessary.
*/
class FrameProcessorBase: public Thread {
public:
- explicit FrameProcessorBase(wp<CameraDeviceBase> device);
+ explicit FrameProcessorBase(wp<FrameProducer> device);
virtual ~FrameProcessorBase();
struct FilteredListener: virtual public RefBase {
virtual void onResultAvailable(const CaptureResult &result) = 0;
};
+ static const int32_t FRAME_PROCESSOR_LISTENER_MIN_ID = 0;
+ static const int32_t FRAME_PROCESSOR_LISTENER_MAX_ID = 0x7fffffffL;
+
// Register a listener for a range of IDs [minId, maxId). Multiple listeners
// can be listening to the same range. Registering the same listener with
// the same range of IDs has no effect.
@@ -56,7 +59,7 @@
void dump(int fd, const Vector<String16>& args);
protected:
static const nsecs_t kWaitDuration = 10000000; // 10 ms
- wp<CameraDeviceBase> mDevice;
+ wp<FrameProducer> mDevice;
virtual bool threadLoop();
@@ -74,13 +77,13 @@
// Number of partial result the HAL will potentially send.
int32_t mNumPartialResults;
- void processNewFrames(const sp<CameraDeviceBase> &device);
+ void processNewFrames(const sp<FrameProducer> &device);
virtual bool processSingleFrame(CaptureResult &result,
- const sp<CameraDeviceBase> &device);
+ const sp<FrameProducer> &device);
status_t processListeners(const CaptureResult &result,
- const sp<CameraDeviceBase> &device);
+ const sp<FrameProducer> &device);
CameraMetadata mLastFrame;
std::vector<PhysicalCaptureResultInfo> mLastPhysicalFrames;
diff --git a/services/camera/libcameraservice/common/FrameProducer.h b/services/camera/libcameraservice/common/FrameProducer.h
new file mode 100644
index 0000000..a14b3d6
--- /dev/null
+++ b/services/camera/libcameraservice/common/FrameProducer.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SERVERS_CAMERA_FRAMEPRODUCER_H
+#define ANDROID_SERVERS_CAMERA_FRAMEPRODUCER_H
+
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/Timers.h>
+
+#include "camera/CameraMetadata.h"
+#include "camera/CaptureResult.h"
+
+namespace android {
+
+/**
+ * Abstract class for HAL frame producers
+ */
+class FrameProducer : public virtual RefBase {
+ public:
+ /**
+ * Retrieve the static characteristics metadata buffer
+ */
+ virtual const CameraMetadata& info() const = 0;
+
+ /**
+ * Retrieve the device camera ID
+ */
+ virtual const String8& getId() const = 0;
+
+ /**
+ * Wait for a new frame to be produced, with timeout in nanoseconds.
+ * Returns TIMED_OUT when no frame produced within the specified duration
+ * May be called concurrently to most methods, except for getNextFrame
+ */
+ virtual status_t waitForNextFrame(nsecs_t timeout) = 0;
+
+ /**
+ * Get next capture result frame from the result queue. Returns NOT_ENOUGH_DATA
+ * if the queue is empty; caller takes ownership of the metadata buffer inside
+ * the capture result object's metadata field.
+ * May be called concurrently to most methods, except for waitForNextFrame.
+ */
+ virtual status_t getNextResult(CaptureResult *frame) = 0;
+
+}; // class FrameProducer
+
+} // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp b/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp
index 522d521..62ef681 100644
--- a/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp
+++ b/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp
@@ -165,8 +165,12 @@
mem = mHidlMemPoolMap.at(data);
}
sp<CameraHeapMemory> heapMem(static_cast<CameraHeapMemory *>(mem->handle));
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
VideoNativeHandleMetadata* md = (VideoNativeHandleMetadata*)
- heapMem->mBuffers[bufferIndex]->pointer();
+ heapMem->mBuffers[bufferIndex]->unsecurePointer();
md->pHandle = const_cast<native_handle_t*>(frameData.getNativeHandle());
sDataCbTimestamp(timestamp, (int32_t) msgType, mem, bufferIndex, this);
return hardware::Void();
@@ -192,8 +196,12 @@
hidl_msg.bufferIndex, mem->mNumBufs);
return hardware::Void();
}
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
VideoNativeHandleMetadata* md = (VideoNativeHandleMetadata*)
- mem->mBuffers[hidl_msg.bufferIndex]->pointer();
+ mem->mBuffers[hidl_msg.bufferIndex]->unsecurePointer();
md->pHandle = const_cast<native_handle_t*>(hidl_msg.frameData.getNativeHandle());
msgs.push_back({hidl_msg.timestamp, mem->mBuffers[hidl_msg.bufferIndex]});
@@ -578,7 +586,11 @@
int bufferIndex = offset / size;
if (CC_LIKELY(mHidlDevice != nullptr)) {
if (size == sizeof(VideoNativeHandleMetadata)) {
- VideoNativeHandleMetadata* md = (VideoNativeHandleMetadata*) mem->pointer();
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
+ VideoNativeHandleMetadata* md = (VideoNativeHandleMetadata*) mem->unsecurePointer();
// Caching the handle here because md->pHandle will be subject to HAL's edit
native_handle_t* nh = md->pHandle;
hidl_handle frame = nh;
@@ -605,7 +617,11 @@
if (size == sizeof(VideoNativeHandleMetadata)) {
uint32_t heapId = heap->getHeapID();
uint32_t bufferIndex = offset / size;
- VideoNativeHandleMetadata* md = (VideoNativeHandleMetadata*) mem->pointer();
+ // TODO: Using unsecurePointer() has some associated security pitfalls
+ // (see declaration for details).
+ // Either document why it is safe in this case or address the
+ // issue (e.g. by copying).
+ VideoNativeHandleMetadata* md = (VideoNativeHandleMetadata*) mem->unsecurePointer();
// Caching the handle here because md->pHandle will be subject to HAL's edit
native_handle_t* nh = md->pHandle;
VideoFrameMessage msg;
diff --git a/services/camera/libcameraservice/device3/BufferUtils.cpp b/services/camera/libcameraservice/device3/BufferUtils.cpp
new file mode 100644
index 0000000..cc29390
--- /dev/null
+++ b/services/camera/libcameraservice/device3/BufferUtils.cpp
@@ -0,0 +1,277 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "Camera3-BufUtils"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+//#define LOG_NNDEBUG 0 // Per-frame verbose logging
+
+#include <inttypes.h>
+
+#include <utils/Log.h>
+
+#include "device3/BufferUtils.h"
+
+namespace android {
+namespace camera3 {
+
+camera3_buffer_status_t mapHidlBufferStatus(hardware::camera::device::V3_2::BufferStatus status) {
+ using hardware::camera::device::V3_2::BufferStatus;
+
+ switch (status) {
+ case BufferStatus::OK: return CAMERA3_BUFFER_STATUS_OK;
+ case BufferStatus::ERROR: return CAMERA3_BUFFER_STATUS_ERROR;
+ }
+ return CAMERA3_BUFFER_STATUS_ERROR;
+}
+
+void BufferRecords::takeInflightBufferMap(BufferRecords& other) {
+ std::lock_guard<std::mutex> oLock(other.mInflightLock);
+ std::lock_guard<std::mutex> lock(mInflightLock);
+ if (mInflightBufferMap.size() > 0) {
+ ALOGE("%s: inflight map is set in non-empty state!", __FUNCTION__);
+ }
+ mInflightBufferMap = std::move(other.mInflightBufferMap);
+ other.mInflightBufferMap.clear();
+}
+
+void BufferRecords::takeRequestedBufferMap(BufferRecords& other) {
+ std::lock_guard<std::mutex> oLock(other.mRequestedBuffersLock);
+ std::lock_guard<std::mutex> lock(mRequestedBuffersLock);
+ if (mRequestedBufferMap.size() > 0) {
+ ALOGE("%s: requested buffer map is set in non-empty state!", __FUNCTION__);
+ }
+ mRequestedBufferMap = std::move(other.mRequestedBufferMap);
+ other.mRequestedBufferMap.clear();
+}
+
+void BufferRecords::takeBufferCaches(BufferRecords& other, const std::vector<int32_t>& streams) {
+ std::lock_guard<std::mutex> oLock(other.mBufferIdMapLock);
+ std::lock_guard<std::mutex> lock(mBufferIdMapLock);
+ if (mBufferIdMaps.size() > 0) {
+ ALOGE("%s: buffer ID map is set in non-empty state!", __FUNCTION__);
+ }
+ for (auto streamId : streams) {
+ mBufferIdMaps.insert({streamId, std::move(other.mBufferIdMaps.at(streamId))});
+ }
+ other.mBufferIdMaps.clear();
+}
+
+std::pair<bool, uint64_t> BufferRecords::getBufferId(
+ const buffer_handle_t& buf, int streamId) {
+ std::lock_guard<std::mutex> lock(mBufferIdMapLock);
+
+ BufferIdMap& bIdMap = mBufferIdMaps.at(streamId);
+ auto it = bIdMap.find(buf);
+ if (it == bIdMap.end()) {
+ bIdMap[buf] = mNextBufferId++;
+ ALOGV("stream %d now have %zu buffer caches, buf %p",
+ streamId, bIdMap.size(), buf);
+ return std::make_pair(true, mNextBufferId - 1);
+ } else {
+ return std::make_pair(false, it->second);
+ }
+}
+
+void BufferRecords::tryCreateBufferCache(int streamId) {
+ std::lock_guard<std::mutex> lock(mBufferIdMapLock);
+ if (mBufferIdMaps.count(streamId) == 0) {
+ mBufferIdMaps.emplace(streamId, BufferIdMap{});
+ }
+}
+
+void BufferRecords::removeInactiveBufferCaches(const std::set<int32_t>& activeStreams) {
+ std::lock_guard<std::mutex> lock(mBufferIdMapLock);
+ for(auto it = mBufferIdMaps.begin(); it != mBufferIdMaps.end();) {
+ int streamId = it->first;
+ bool active = activeStreams.count(streamId) > 0;
+ if (!active) {
+ it = mBufferIdMaps.erase(it);
+ } else {
+ ++it;
+ }
+ }
+}
+
+uint64_t BufferRecords::removeOneBufferCache(int streamId, const native_handle_t* handle) {
+ std::lock_guard<std::mutex> lock(mBufferIdMapLock);
+ uint64_t bufferId = BUFFER_ID_NO_BUFFER;
+ auto mapIt = mBufferIdMaps.find(streamId);
+ if (mapIt == mBufferIdMaps.end()) {
+ // streamId might be from a deleted stream here
+ ALOGI("%s: stream %d has been removed",
+ __FUNCTION__, streamId);
+ return BUFFER_ID_NO_BUFFER;
+ }
+ BufferIdMap& bIdMap = mapIt->second;
+ auto it = bIdMap.find(handle);
+ if (it == bIdMap.end()) {
+ ALOGW("%s: cannot find buffer %p in stream %d",
+ __FUNCTION__, handle, streamId);
+ return BUFFER_ID_NO_BUFFER;
+ } else {
+ bufferId = it->second;
+ bIdMap.erase(it);
+ ALOGV("%s: stream %d now have %zu buffer caches after removing buf %p",
+ __FUNCTION__, streamId, bIdMap.size(), handle);
+ }
+ return bufferId;
+}
+
+std::vector<uint64_t> BufferRecords::clearBufferCaches(int streamId) {
+ std::lock_guard<std::mutex> lock(mBufferIdMapLock);
+ std::vector<uint64_t> ret;
+ auto mapIt = mBufferIdMaps.find(streamId);
+ if (mapIt == mBufferIdMaps.end()) {
+ ALOGE("%s: streamId %d not found!", __FUNCTION__, streamId);
+ return ret;
+ }
+ BufferIdMap& bIdMap = mapIt->second;
+ ret.reserve(bIdMap.size());
+ for (const auto& it : bIdMap) {
+ ret.push_back(it.second);
+ }
+ bIdMap.clear();
+ return ret;
+}
+
+bool BufferRecords::isStreamCached(int streamId) {
+ std::lock_guard<std::mutex> lock(mBufferIdMapLock);
+ return mBufferIdMaps.find(streamId) != mBufferIdMaps.end();
+}
+
+bool BufferRecords::verifyBufferIds(
+ int32_t streamId, std::vector<uint64_t>& bufIds) {
+ std::lock_guard<std::mutex> lock(mBufferIdMapLock);
+ camera3::BufferIdMap& bIdMap = mBufferIdMaps.at(streamId);
+ if (bIdMap.size() != bufIds.size()) {
+ ALOGE("%s: stream ID %d buffer cache number mismatch: %zu/%zu (service/HAL)",
+ __FUNCTION__, streamId, bIdMap.size(), bufIds.size());
+ return false;
+ }
+ std::vector<uint64_t> internalBufIds;
+ internalBufIds.reserve(bIdMap.size());
+ for (const auto& pair : bIdMap) {
+ internalBufIds.push_back(pair.second);
+ }
+ std::sort(bufIds.begin(), bufIds.end());
+ std::sort(internalBufIds.begin(), internalBufIds.end());
+ for (size_t i = 0; i < bufIds.size(); i++) {
+ if (bufIds[i] != internalBufIds[i]) {
+ ALOGE("%s: buffer cache mismatch! Service %" PRIu64 ", HAL %" PRIu64,
+ __FUNCTION__, internalBufIds[i], bufIds[i]);
+ return false;
+ }
+ }
+ return true;
+}
+
+void BufferRecords::getInflightBufferKeys(
+ std::vector<std::pair<int32_t, int32_t>>* out) {
+ std::lock_guard<std::mutex> lock(mInflightLock);
+ out->clear();
+ out->reserve(mInflightBufferMap.size());
+ for (auto& pair : mInflightBufferMap) {
+ uint64_t key = pair.first;
+ int32_t streamId = key & 0xFFFFFFFF;
+ int32_t frameNumber = (key >> 32) & 0xFFFFFFFF;
+ out->push_back(std::make_pair(frameNumber, streamId));
+ }
+ return;
+}
+
+status_t BufferRecords::pushInflightBuffer(
+ int32_t frameNumber, int32_t streamId, buffer_handle_t *buffer) {
+ std::lock_guard<std::mutex> lock(mInflightLock);
+ uint64_t key = static_cast<uint64_t>(frameNumber) << 32 | static_cast<uint64_t>(streamId);
+ mInflightBufferMap[key] = buffer;
+ return OK;
+}
+
+status_t BufferRecords::popInflightBuffer(
+ int32_t frameNumber, int32_t streamId,
+ /*out*/ buffer_handle_t **buffer) {
+ std::lock_guard<std::mutex> lock(mInflightLock);
+
+ uint64_t key = static_cast<uint64_t>(frameNumber) << 32 | static_cast<uint64_t>(streamId);
+ auto it = mInflightBufferMap.find(key);
+ if (it == mInflightBufferMap.end()) return NAME_NOT_FOUND;
+ if (buffer != nullptr) {
+ *buffer = it->second;
+ }
+ mInflightBufferMap.erase(it);
+ return OK;
+}
+
+void BufferRecords::popInflightBuffers(
+ const std::vector<std::pair<int32_t, int32_t>>& buffers) {
+ for (const auto& pair : buffers) {
+ int32_t frameNumber = pair.first;
+ int32_t streamId = pair.second;
+ popInflightBuffer(frameNumber, streamId, nullptr);
+ }
+}
+
+status_t BufferRecords::pushInflightRequestBuffer(
+ uint64_t bufferId, buffer_handle_t* buf, int32_t streamId) {
+ std::lock_guard<std::mutex> lock(mRequestedBuffersLock);
+ auto pair = mRequestedBufferMap.insert({bufferId, {streamId, buf}});
+ if (!pair.second) {
+ ALOGE("%s: bufId %" PRIu64 " is already inflight!",
+ __FUNCTION__, bufferId);
+ return BAD_VALUE;
+ }
+ return OK;
+}
+
+// Find and pop a buffer_handle_t based on bufferId
+status_t BufferRecords::popInflightRequestBuffer(
+ uint64_t bufferId,
+ /*out*/ buffer_handle_t** buffer,
+ /*optional out*/ int32_t* streamId) {
+ if (buffer == nullptr) {
+ ALOGE("%s: buffer (%p) must not be null", __FUNCTION__, buffer);
+ return BAD_VALUE;
+ }
+ std::lock_guard<std::mutex> lock(mRequestedBuffersLock);
+ auto it = mRequestedBufferMap.find(bufferId);
+ if (it == mRequestedBufferMap.end()) {
+ ALOGE("%s: bufId %" PRIu64 " is not inflight!",
+ __FUNCTION__, bufferId);
+ return BAD_VALUE;
+ }
+ *buffer = it->second.second;
+ if (streamId != nullptr) {
+ *streamId = it->second.first;
+ }
+ mRequestedBufferMap.erase(it);
+ return OK;
+}
+
+void BufferRecords::getInflightRequestBufferKeys(
+ std::vector<uint64_t>* out) {
+ std::lock_guard<std::mutex> lock(mRequestedBuffersLock);
+ out->clear();
+ out->reserve(mRequestedBufferMap.size());
+ for (auto& pair : mRequestedBufferMap) {
+ out->push_back(pair.first);
+ }
+ return;
+}
+
+
+} // camera3
+} // namespace android
diff --git a/services/camera/libcameraservice/device3/BufferUtils.h b/services/camera/libcameraservice/device3/BufferUtils.h
new file mode 100644
index 0000000..452a908
--- /dev/null
+++ b/services/camera/libcameraservice/device3/BufferUtils.h
@@ -0,0 +1,167 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_SERVERS_CAMERA3_BUFFER_UTILS_H
+#define ANDROID_SERVERS_CAMERA3_BUFFER_UTILS_H
+
+#include <unordered_map>
+#include <mutex>
+#include <set>
+
+#include <cutils/native_handle.h>
+
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+
+// TODO: remove legacy camera3.h references
+#include "hardware/camera3.h"
+
+#include <device3/Camera3OutputInterface.h>
+
+namespace android {
+
+namespace camera3 {
+
+ struct BufferHasher {
+ size_t operator()(const buffer_handle_t& buf) const {
+ if (buf == nullptr)
+ return 0;
+
+ size_t result = 1;
+ result = 31 * result + buf->numFds;
+ for (int i = 0; i < buf->numFds; i++) {
+ result = 31 * result + buf->data[i];
+ }
+ return result;
+ }
+ };
+
+ struct BufferComparator {
+ bool operator()(const buffer_handle_t& buf1, const buffer_handle_t& buf2) const {
+ if (buf1->numFds == buf2->numFds) {
+ for (int i = 0; i < buf1->numFds; i++) {
+ if (buf1->data[i] != buf2->data[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+ };
+
+ // Per stream buffer native handle -> bufId map
+ typedef std::unordered_map<const buffer_handle_t, uint64_t,
+ BufferHasher, BufferComparator> BufferIdMap;
+
+ // streamId -> BufferIdMap
+ typedef std::unordered_map<int, BufferIdMap> BufferIdMaps;
+
+ // Map of inflight buffers sent along in capture requests.
+ // Key is composed by (frameNumber << 32 | streamId)
+ typedef std::unordered_map<uint64_t, buffer_handle_t*> InflightBufferMap;
+
+ // Map of inflight buffers dealt by requestStreamBuffers API
+ typedef std::unordered_map<uint64_t, std::pair<int32_t, buffer_handle_t*>> RequestedBufferMap;
+
+ // A struct containing all buffer tracking information like inflight buffers
+ // and buffer ID caches
+ class BufferRecords : public BufferRecordsInterface {
+
+ public:
+ BufferRecords() {}
+
+ BufferRecords(BufferRecords&& other) :
+ mBufferIdMaps(other.mBufferIdMaps),
+ mNextBufferId(other.mNextBufferId),
+ mInflightBufferMap(other.mInflightBufferMap),
+ mRequestedBufferMap(other.mRequestedBufferMap) {}
+
+ virtual ~BufferRecords() {}
+
+ // Helper methods to help moving buffer records
+ void takeInflightBufferMap(BufferRecords& other);
+ void takeRequestedBufferMap(BufferRecords& other);
+ void takeBufferCaches(BufferRecords& other, const std::vector<int32_t>& streams);
+
+ // method to extract buffer's unique ID
+ // return pair of (newlySeenBuffer?, bufferId)
+ virtual std::pair<bool, uint64_t> getBufferId(
+ const buffer_handle_t& buf, int streamId) override;
+
+ void tryCreateBufferCache(int streamId);
+
+ void removeInactiveBufferCaches(const std::set<int32_t>& activeStreams);
+
+ // Return the removed buffer ID if input cache is found.
+ // Otherwise return BUFFER_ID_NO_BUFFER
+ uint64_t removeOneBufferCache(int streamId, const native_handle_t* handle);
+
+ // Clear all caches for input stream, but do not remove the stream
+ // Removed buffers' ID are returned
+ std::vector<uint64_t> clearBufferCaches(int streamId);
+
+ bool isStreamCached(int streamId);
+
+ // Return true if the input caches match what we have; otherwise false
+ bool verifyBufferIds(int32_t streamId, std::vector<uint64_t>& inBufIds);
+
+ // Get a vector of (frameNumber, streamId) pair of currently inflight
+ // buffers
+ void getInflightBufferKeys(std::vector<std::pair<int32_t, int32_t>>* out);
+
+ status_t pushInflightBuffer(int32_t frameNumber, int32_t streamId,
+ buffer_handle_t *buffer);
+
+ // Find a buffer_handle_t based on frame number and stream ID
+ virtual status_t popInflightBuffer(int32_t frameNumber, int32_t streamId,
+ /*out*/ buffer_handle_t **buffer) override;
+
+ // Pop inflight buffers based on pairs of (frameNumber,streamId)
+ void popInflightBuffers(const std::vector<std::pair<int32_t, int32_t>>& buffers);
+
+ // Get a vector of bufferId of currently inflight buffers
+ void getInflightRequestBufferKeys(std::vector<uint64_t>* out);
+
+ // Register a bufId (streamId, buffer_handle_t) to inflight request buffer
+ virtual status_t pushInflightRequestBuffer(
+ uint64_t bufferId, buffer_handle_t* buf, int32_t streamId) override;
+
+ // Find a buffer_handle_t based on bufferId
+ virtual status_t popInflightRequestBuffer(uint64_t bufferId,
+ /*out*/ buffer_handle_t** buffer,
+ /*optional out*/ int32_t* streamId = nullptr) override;
+
+ private:
+ std::mutex mBufferIdMapLock;
+ BufferIdMaps mBufferIdMaps;
+ uint64_t mNextBufferId = 1; // 0 means no buffer
+
+ std::mutex mInflightLock;
+ InflightBufferMap mInflightBufferMap;
+
+ std::mutex mRequestedBuffersLock;
+ RequestedBufferMap mRequestedBufferMap;
+ }; // class BufferRecords
+
+ static const uint64_t BUFFER_ID_NO_BUFFER = 0;
+
+ camera3_buffer_status_t mapHidlBufferStatus(
+ hardware::camera::device::V3_2::BufferStatus status);
+} // namespace camera3
+
+} // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 4227a3b..f29431c 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -61,6 +61,7 @@
#include "CameraService.h"
#include "utils/CameraThreadState.h"
+#include <algorithm>
#include <tuple>
using namespace android::camera3;
@@ -132,6 +133,7 @@
session->close();
return res;
}
+ mSupportNativeZoomRatio = manager->supportNativeZoomRatio(mId.string());
std::vector<std::string> physicalCameraIds;
bool isLogical = manager->isLogicalCamera(mId.string(), &physicalCameraIds);
@@ -146,8 +148,11 @@
return res;
}
- if (DistortionMapper::isDistortionSupported(mPhysicalDeviceInfoMap[physicalId])) {
- mDistortionMappers[physicalId].setupStaticInfo(mPhysicalDeviceInfoMap[physicalId]);
+ bool usePrecorrectArray =
+ DistortionMapper::isDistortionSupported(mPhysicalDeviceInfoMap[physicalId]);
+ if (usePrecorrectArray) {
+ res = mDistortionMappers[physicalId].setupStaticInfo(
+ mPhysicalDeviceInfoMap[physicalId]);
if (res != OK) {
SET_ERR_L("Unable to read camera %s's calibration fields for distortion "
"correction", physicalId.c_str());
@@ -155,6 +160,10 @@
return res;
}
}
+
+ mZoomRatioMappers[physicalId] = ZoomRatioMapper(
+ &mPhysicalDeviceInfoMap[physicalId],
+ mSupportNativeZoomRatio, usePrecorrectArray);
}
}
@@ -206,7 +215,15 @@
ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
}
- mInterface = new HalInterface(session, queue, mUseHalBufManager);
+ camera_metadata_entry_t capabilities = mDeviceInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+ for (size_t i = 0; i < capabilities.count; i++) {
+ uint8_t capability = capabilities.data.u8[i];
+ if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING) {
+ mSupportOfflineProcessing = true;
+ }
+ }
+
+ mInterface = new HalInterface(session, queue, mUseHalBufManager, mSupportOfflineProcessing);
std::string providerType;
mVendorTagId = manager->getProviderTagIdLocked(mId.string());
mTagMonitor.initialize(mVendorTagId);
@@ -227,9 +244,8 @@
maxVersion.get_major(), maxVersion.get_minor());
bool isMonochrome = false;
- camera_metadata_entry_t entry = mDeviceInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
- for (size_t i = 0; i < entry.count; i++) {
- uint8_t capability = entry.data.u8[i];
+ for (size_t i = 0; i < capabilities.count; i++) {
+ uint8_t capability = capabilities.data.u8[i];
if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME) {
isMonochrome = true;
}
@@ -323,13 +339,22 @@
}
}
- if (DistortionMapper::isDistortionSupported(mDeviceInfo)) {
+ bool usePrecorrectArray = DistortionMapper::isDistortionSupported(mDeviceInfo);
+ if (usePrecorrectArray) {
res = mDistortionMappers[mId.c_str()].setupStaticInfo(mDeviceInfo);
if (res != OK) {
SET_ERR_L("Unable to read necessary calibration fields for distortion correction");
return res;
}
}
+
+ mZoomRatioMappers[mId.c_str()] = ZoomRatioMapper(&mDeviceInfo,
+ mSupportNativeZoomRatio, usePrecorrectArray);
+
+ if (RotateAndCropMapper::isNeeded(&mDeviceInfo)) {
+ mRotateAndCropMappers.emplace(mId.c_str(), &mDeviceInfo);
+ }
+
return OK;
}
@@ -339,100 +364,103 @@
status_t Camera3Device::disconnectImpl() {
ATRACE_CALL();
- Mutex::Autolock il(mInterfaceLock);
-
ALOGI("%s: E", __FUNCTION__);
status_t res = OK;
std::vector<wp<Camera3StreamInterface>> streams;
- nsecs_t maxExpectedDuration = getExpectedInFlightDuration();
{
- Mutex::Autolock l(mLock);
- if (mStatus == STATUS_UNINITIALIZED) return res;
+ Mutex::Autolock il(mInterfaceLock);
+ nsecs_t maxExpectedDuration = getExpectedInFlightDuration();
+ {
+ Mutex::Autolock l(mLock);
+ if (mStatus == STATUS_UNINITIALIZED) return res;
- if (mStatus == STATUS_ACTIVE ||
- (mStatus == STATUS_ERROR && mRequestThread != NULL)) {
- res = mRequestThread->clearRepeatingRequests();
- if (res != OK) {
- SET_ERR_L("Can't stop streaming");
- // Continue to close device even in case of error
- } else {
- res = waitUntilStateThenRelock(/*active*/ false, maxExpectedDuration);
+ if (mStatus == STATUS_ACTIVE ||
+ (mStatus == STATUS_ERROR && mRequestThread != NULL)) {
+ res = mRequestThread->clearRepeatingRequests();
if (res != OK) {
- SET_ERR_L("Timeout waiting for HAL to drain (% " PRIi64 " ns)",
- maxExpectedDuration);
+ SET_ERR_L("Can't stop streaming");
// Continue to close device even in case of error
+ } else {
+ res = waitUntilStateThenRelock(/*active*/ false, maxExpectedDuration);
+ if (res != OK) {
+ SET_ERR_L("Timeout waiting for HAL to drain (% " PRIi64 " ns)",
+ maxExpectedDuration);
+ // Continue to close device even in case of error
+ }
}
}
- }
- if (mStatus == STATUS_ERROR) {
- CLOGE("Shutting down in an error state");
- }
+ if (mStatus == STATUS_ERROR) {
+ CLOGE("Shutting down in an error state");
+ }
- if (mStatusTracker != NULL) {
- mStatusTracker->requestExit();
- }
+ if (mStatusTracker != NULL) {
+ mStatusTracker->requestExit();
+ }
- if (mRequestThread != NULL) {
- mRequestThread->requestExit();
- }
+ if (mRequestThread != NULL) {
+ mRequestThread->requestExit();
+ }
- streams.reserve(mOutputStreams.size() + (mInputStream != nullptr ? 1 : 0));
- for (size_t i = 0; i < mOutputStreams.size(); i++) {
- streams.push_back(mOutputStreams[i]);
- }
- if (mInputStream != nullptr) {
- streams.push_back(mInputStream);
+ streams.reserve(mOutputStreams.size() + (mInputStream != nullptr ? 1 : 0));
+ for (size_t i = 0; i < mOutputStreams.size(); i++) {
+ streams.push_back(mOutputStreams[i]);
+ }
+ if (mInputStream != nullptr) {
+ streams.push_back(mInputStream);
+ }
}
}
-
- // Joining done without holding mLock, otherwise deadlocks may ensue
- // as the threads try to access parent state
+ // Joining done without holding mLock and mInterfaceLock, otherwise deadlocks may ensue
+ // as the threads try to access parent state (b/143513518)
if (mRequestThread != NULL && mStatus != STATUS_ERROR) {
// HAL may be in a bad state, so waiting for request thread
// (which may be stuck in the HAL processCaptureRequest call)
// could be dangerous.
+ // give up mInterfaceLock here and then lock it again. Could this lead
+ // to other deadlocks
mRequestThread->join();
}
-
- if (mStatusTracker != NULL) {
- mStatusTracker->join();
- }
-
- HalInterface* interface;
{
- Mutex::Autolock l(mLock);
- mRequestThread.clear();
- Mutex::Autolock stLock(mTrackerLock);
- mStatusTracker.clear();
- interface = mInterface.get();
- }
+ Mutex::Autolock il(mInterfaceLock);
+ if (mStatusTracker != NULL) {
+ mStatusTracker->join();
+ }
- // Call close without internal mutex held, as the HAL close may need to
- // wait on assorted callbacks,etc, to complete before it can return.
- interface->close();
+ HalInterface* interface;
+ {
+ Mutex::Autolock l(mLock);
+ mRequestThread.clear();
+ Mutex::Autolock stLock(mTrackerLock);
+ mStatusTracker.clear();
+ interface = mInterface.get();
+ }
- flushInflightRequests();
+ // Call close without internal mutex held, as the HAL close may need to
+ // wait on assorted callbacks,etc, to complete before it can return.
+ interface->close();
- {
- Mutex::Autolock l(mLock);
- mInterface->clear();
- mOutputStreams.clear();
- mInputStream.clear();
- mDeletedStreams.clear();
- mBufferManager.clear();
- internalUpdateStatusLocked(STATUS_UNINITIALIZED);
- }
+ flushInflightRequests();
- for (auto& weakStream : streams) {
- sp<Camera3StreamInterface> stream = weakStream.promote();
- if (stream != nullptr) {
- ALOGE("%s: Stream %d leaked! strong reference (%d)!",
- __FUNCTION__, stream->getId(), stream->getStrongCount() - 1);
+ {
+ Mutex::Autolock l(mLock);
+ mInterface->clear();
+ mOutputStreams.clear();
+ mInputStream.clear();
+ mDeletedStreams.clear();
+ mBufferManager.clear();
+ internalUpdateStatusLocked(STATUS_UNINITIALIZED);
+ }
+
+ for (auto& weakStream : streams) {
+ sp<Camera3StreamInterface> stream = weakStream.promote();
+ if (stream != nullptr) {
+ ALOGE("%s: Stream %d leaked! strong reference (%d)!",
+ __FUNCTION__, stream->getId(), stream->getStrongCount() - 1);
+ }
}
}
-
ALOGI("%s: X", __FUNCTION__);
return res;
}
@@ -553,14 +581,6 @@
return OK;
}
-camera3_buffer_status_t Camera3Device::mapHidlBufferStatus(BufferStatus status) {
- switch (status) {
- case BufferStatus::OK: return CAMERA3_BUFFER_STATUS_OK;
- case BufferStatus::ERROR: return CAMERA3_BUFFER_STATUS_ERROR;
- }
- return CAMERA3_BUFFER_STATUS_ERROR;
-}
-
int Camera3Device::mapToFrameworkFormat(
hardware::graphics::common::V1_0::PixelFormat pixelFormat) {
return static_cast<uint32_t>(pixelFormat);
@@ -797,7 +817,7 @@
return OK;
}
-const CameraMetadata& Camera3Device::info(const String8& physicalId) const {
+const CameraMetadata& Camera3Device::infoPhysical(const String8& physicalId) const {
ALOGVV("%s: E", __FUNCTION__);
if (CC_UNLIKELY(mStatus == STATUS_UNINITIALIZED ||
mStatus == STATUS_ERROR)) {
@@ -820,7 +840,7 @@
const CameraMetadata& Camera3Device::info() const {
String8 emptyId;
- return info(emptyId);
+ return infoPhysical(emptyId);
}
status_t Camera3Device::checkStatusOkToCaptureLocked() {
@@ -868,17 +888,12 @@
// Setup burst Id and request Id
newRequest->mResultExtras.burstId = burstId++;
- if (metadataIt->begin()->metadata.exists(ANDROID_REQUEST_ID)) {
- if (metadataIt->begin()->metadata.find(ANDROID_REQUEST_ID).count == 0) {
- CLOGE("RequestID entry exists; but must not be empty in metadata");
- return BAD_VALUE;
- }
- newRequest->mResultExtras.requestId = metadataIt->begin()->metadata.find(
- ANDROID_REQUEST_ID).data.i32[0];
- } else {
+ auto requestIdEntry = metadataIt->begin()->metadata.find(ANDROID_REQUEST_ID);
+ if (requestIdEntry.count == 0) {
CLOGE("RequestID does not exist in metadata");
return BAD_VALUE;
}
+ newRequest->mResultExtras.requestId = requestIdEntry.data.i32[0];
requestList->push_back(newRequest);
@@ -980,230 +995,18 @@
hardware::Return<void> Camera3Device::requestStreamBuffers(
const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
requestStreamBuffers_cb _hidl_cb) {
- using hardware::camera::device::V3_5::BufferRequestStatus;
- using hardware::camera::device::V3_5::StreamBufferRet;
- using hardware::camera::device::V3_5::StreamBufferRequestError;
-
- std::lock_guard<std::mutex> lock(mRequestBufferInterfaceLock);
-
- hardware::hidl_vec<StreamBufferRet> bufRets;
- if (!mUseHalBufManager) {
- ALOGE("%s: Camera %s does not support HAL buffer management",
- __FUNCTION__, mId.string());
- _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
- return hardware::Void();
- }
-
- SortedVector<int32_t> streamIds;
- ssize_t sz = streamIds.setCapacity(bufReqs.size());
- if (sz < 0 || static_cast<size_t>(sz) != bufReqs.size()) {
- ALOGE("%s: failed to allocate memory for %zu buffer requests",
- __FUNCTION__, bufReqs.size());
- _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
- return hardware::Void();
- }
-
- if (bufReqs.size() > mOutputStreams.size()) {
- ALOGE("%s: too many buffer requests (%zu > # of output streams %zu)",
- __FUNCTION__, bufReqs.size(), mOutputStreams.size());
- _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
- return hardware::Void();
- }
-
- // Check for repeated streamId
- for (const auto& bufReq : bufReqs) {
- if (streamIds.indexOf(bufReq.streamId) != NAME_NOT_FOUND) {
- ALOGE("%s: Stream %d appear multiple times in buffer requests",
- __FUNCTION__, bufReq.streamId);
- _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
- return hardware::Void();
- }
- streamIds.add(bufReq.streamId);
- }
-
- if (!mRequestBufferSM.startRequestBuffer()) {
- ALOGE("%s: request buffer disallowed while camera service is configuring",
- __FUNCTION__);
- _hidl_cb(BufferRequestStatus::FAILED_CONFIGURING, bufRets);
- return hardware::Void();
- }
-
- bufRets.resize(bufReqs.size());
-
- bool allReqsSucceeds = true;
- bool oneReqSucceeds = false;
- for (size_t i = 0; i < bufReqs.size(); i++) {
- const auto& bufReq = bufReqs[i];
- auto& bufRet = bufRets[i];
- int32_t streamId = bufReq.streamId;
- sp<Camera3OutputStreamInterface> outputStream = mOutputStreams.get(streamId);
- if (outputStream == nullptr) {
- ALOGE("%s: Output stream id %d not found!", __FUNCTION__, streamId);
- hardware::hidl_vec<StreamBufferRet> emptyBufRets;
- _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, emptyBufRets);
- mRequestBufferSM.endRequestBuffer();
- return hardware::Void();
- }
-
- if (outputStream->isAbandoned()) {
- bufRet.val.error(StreamBufferRequestError::STREAM_DISCONNECTED);
- allReqsSucceeds = false;
- continue;
- }
-
- bufRet.streamId = streamId;
- size_t handOutBufferCount = outputStream->getOutstandingBuffersCount();
- uint32_t numBuffersRequested = bufReq.numBuffersRequested;
- size_t totalHandout = handOutBufferCount + numBuffersRequested;
- uint32_t maxBuffers = outputStream->asHalStream()->max_buffers;
- if (totalHandout > maxBuffers) {
- // Not able to allocate enough buffer. Exit early for this stream
- ALOGE("%s: request too much buffers for stream %d: at HAL: %zu + requesting: %d"
- " > max: %d", __FUNCTION__, streamId, handOutBufferCount,
- numBuffersRequested, maxBuffers);
- bufRet.val.error(StreamBufferRequestError::MAX_BUFFER_EXCEEDED);
- allReqsSucceeds = false;
- continue;
- }
-
- hardware::hidl_vec<StreamBuffer> tmpRetBuffers(numBuffersRequested);
- bool currentReqSucceeds = true;
- std::vector<camera3_stream_buffer_t> streamBuffers(numBuffersRequested);
- size_t numAllocatedBuffers = 0;
- size_t numPushedInflightBuffers = 0;
- for (size_t b = 0; b < numBuffersRequested; b++) {
- camera3_stream_buffer_t& sb = streamBuffers[b];
- // Since this method can run concurrently with request thread
- // We need to update the wait duration everytime we call getbuffer
- nsecs_t waitDuration = kBaseGetBufferWait + getExpectedInFlightDuration();
- status_t res = outputStream->getBuffer(&sb, waitDuration);
- if (res != OK) {
- if (res == NO_INIT || res == DEAD_OBJECT) {
- ALOGV("%s: Can't get output buffer for stream %d: %s (%d)",
- __FUNCTION__, streamId, strerror(-res), res);
- bufRet.val.error(StreamBufferRequestError::STREAM_DISCONNECTED);
- } else {
- ALOGE("%s: Can't get output buffer for stream %d: %s (%d)",
- __FUNCTION__, streamId, strerror(-res), res);
- if (res == TIMED_OUT || res == NO_MEMORY) {
- bufRet.val.error(StreamBufferRequestError::NO_BUFFER_AVAILABLE);
- } else {
- bufRet.val.error(StreamBufferRequestError::UNKNOWN_ERROR);
- }
- }
- currentReqSucceeds = false;
- break;
- }
- numAllocatedBuffers++;
-
- buffer_handle_t *buffer = sb.buffer;
- auto pair = mInterface->getBufferId(*buffer, streamId);
- bool isNewBuffer = pair.first;
- uint64_t bufferId = pair.second;
- StreamBuffer& hBuf = tmpRetBuffers[b];
-
- hBuf.streamId = streamId;
- hBuf.bufferId = bufferId;
- hBuf.buffer = (isNewBuffer) ? *buffer : nullptr;
- hBuf.status = BufferStatus::OK;
- hBuf.releaseFence = nullptr;
-
- native_handle_t *acquireFence = nullptr;
- if (sb.acquire_fence != -1) {
- acquireFence = native_handle_create(1,0);
- acquireFence->data[0] = sb.acquire_fence;
- }
- hBuf.acquireFence.setTo(acquireFence, /*shouldOwn*/true);
- hBuf.releaseFence = nullptr;
-
- res = mInterface->pushInflightRequestBuffer(bufferId, buffer, streamId);
- if (res != OK) {
- ALOGE("%s: Can't get register request buffers for stream %d: %s (%d)",
- __FUNCTION__, streamId, strerror(-res), res);
- bufRet.val.error(StreamBufferRequestError::UNKNOWN_ERROR);
- currentReqSucceeds = false;
- break;
- }
- numPushedInflightBuffers++;
- }
- if (currentReqSucceeds) {
- bufRet.val.buffers(std::move(tmpRetBuffers));
- oneReqSucceeds = true;
- } else {
- allReqsSucceeds = false;
- for (size_t b = 0; b < numPushedInflightBuffers; b++) {
- StreamBuffer& hBuf = tmpRetBuffers[b];
- buffer_handle_t* buffer;
- status_t res = mInterface->popInflightRequestBuffer(hBuf.bufferId, &buffer);
- if (res != OK) {
- SET_ERR("%s: popInflightRequestBuffer failed for stream %d: %s (%d)",
- __FUNCTION__, streamId, strerror(-res), res);
- }
- }
- for (size_t b = 0; b < numAllocatedBuffers; b++) {
- camera3_stream_buffer_t& sb = streamBuffers[b];
- sb.acquire_fence = -1;
- sb.status = CAMERA3_BUFFER_STATUS_ERROR;
- }
- returnOutputBuffers(streamBuffers.data(), numAllocatedBuffers, 0);
- }
- }
-
- _hidl_cb(allReqsSucceeds ? BufferRequestStatus::OK :
- oneReqSucceeds ? BufferRequestStatus::FAILED_PARTIAL :
- BufferRequestStatus::FAILED_UNKNOWN,
- bufRets);
- mRequestBufferSM.endRequestBuffer();
+ RequestBufferStates states {
+ mId, mRequestBufferInterfaceLock, mUseHalBufManager, mOutputStreams,
+ *this, *mInterface, *this};
+ camera3::requestStreamBuffers(states, bufReqs, _hidl_cb);
return hardware::Void();
}
hardware::Return<void> Camera3Device::returnStreamBuffers(
const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers) {
- if (!mUseHalBufManager) {
- ALOGE("%s: Camera %s does not support HAL buffer managerment",
- __FUNCTION__, mId.string());
- return hardware::Void();
- }
-
- for (const auto& buf : buffers) {
- if (buf.bufferId == HalInterface::BUFFER_ID_NO_BUFFER) {
- ALOGE("%s: cannot return a buffer without bufferId", __FUNCTION__);
- continue;
- }
-
- buffer_handle_t* buffer;
- status_t res = mInterface->popInflightRequestBuffer(buf.bufferId, &buffer);
-
- if (res != OK) {
- ALOGE("%s: cannot find in-flight buffer %" PRIu64 " for stream %d",
- __FUNCTION__, buf.bufferId, buf.streamId);
- continue;
- }
-
- camera3_stream_buffer_t streamBuffer;
- streamBuffer.buffer = buffer;
- streamBuffer.status = CAMERA3_BUFFER_STATUS_ERROR;
- streamBuffer.acquire_fence = -1;
- streamBuffer.release_fence = -1;
-
- if (buf.releaseFence == nullptr) {
- streamBuffer.release_fence = -1;
- } else if (buf.releaseFence->numFds == 1) {
- streamBuffer.release_fence = dup(buf.releaseFence->data[0]);
- } else {
- ALOGE("%s: Invalid release fence, fd count is %d, not 1",
- __FUNCTION__, buf.releaseFence->numFds);
- continue;
- }
-
- sp<Camera3StreamInterface> stream = mOutputStreams.get(buf.streamId);
- if (stream == nullptr) {
- ALOGE("%s: Output stream id %d not found!", __FUNCTION__, buf.streamId);
- continue;
- }
- streamBuffer.stream = stream->asHalStream();
- returnOutputBuffers(&streamBuffer, /*size*/1, /*timestamp*/ 0);
- }
+ ReturnBufferStates states {
+ mId, mUseHalBufManager, mOutputStreams, *mInterface};
+ camera3::returnStreamBuffers(states, buffers);
return hardware::Void();
}
@@ -1220,6 +1023,12 @@
ALOGW("%s: received capture result in error state.", __FUNCTION__);
}
+ sp<NotificationListener> listener;
+ {
+ std::lock_guard<std::mutex> l(mOutputLock);
+ listener = mListener.promote();
+ }
+
if (mProcessCaptureResultLock.tryLock() != OK) {
// This should never happen; it indicates a wrong client implementation
// that doesn't follow the contract. But, we can be tolerant here.
@@ -1232,8 +1041,22 @@
return hardware::Void();
}
}
+ CaptureOutputStates states {
+ mId,
+ mInFlightLock, mInFlightMap,
+ mOutputLock, mResultQueue, mResultSignal,
+ mNextShutterFrameNumber,
+ mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+ mNextResultFrameNumber,
+ mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+ mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
+ mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
+ mTagMonitor, mInputStream, mOutputStreams, listener, *this, *this, *mInterface
+ };
+
for (const auto& result : results) {
- processOneCaptureResultLocked(result.v3_2, result.physicalCameraMetadata);
+ processOneCaptureResultLocked(states, result.v3_2, result.physicalCameraMetadata);
}
mProcessCaptureResultLock.unlock();
return hardware::Void();
@@ -1256,6 +1079,12 @@
ALOGW("%s: received capture result in error state.", __FUNCTION__);
}
+ sp<NotificationListener> listener;
+ {
+ std::lock_guard<std::mutex> l(mOutputLock);
+ listener = mListener.promote();
+ }
+
if (mProcessCaptureResultLock.tryLock() != OK) {
// This should never happen; it indicates a wrong client implementation
// that doesn't follow the contract. But, we can be tolerant here.
@@ -1268,186 +1097,28 @@
return hardware::Void();
}
}
+
+ CaptureOutputStates states {
+ mId,
+ mInFlightLock, mInFlightMap,
+ mOutputLock, mResultQueue, mResultSignal,
+ mNextShutterFrameNumber,
+ mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+ mNextResultFrameNumber,
+ mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+ mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
+ mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
+ mTagMonitor, mInputStream, mOutputStreams, listener, *this, *this, *mInterface
+ };
+
for (const auto& result : results) {
- processOneCaptureResultLocked(result, noPhysMetadata);
+ processOneCaptureResultLocked(states, result, noPhysMetadata);
}
mProcessCaptureResultLock.unlock();
return hardware::Void();
}
-status_t Camera3Device::readOneCameraMetadataLocked(
- uint64_t fmqResultSize, hardware::camera::device::V3_2::CameraMetadata& resultMetadata,
- const hardware::camera::device::V3_2::CameraMetadata& result) {
- if (fmqResultSize > 0) {
- resultMetadata.resize(fmqResultSize);
- if (mResultMetadataQueue == nullptr) {
- return NO_MEMORY; // logged in initialize()
- }
- if (!mResultMetadataQueue->read(resultMetadata.data(), fmqResultSize)) {
- ALOGE("%s: Cannot read camera metadata from fmq, size = %" PRIu64,
- __FUNCTION__, fmqResultSize);
- return INVALID_OPERATION;
- }
- } else {
- resultMetadata.setToExternal(const_cast<uint8_t *>(result.data()),
- result.size());
- }
-
- if (resultMetadata.size() != 0) {
- status_t res;
- const camera_metadata_t* metadata =
- reinterpret_cast<const camera_metadata_t*>(resultMetadata.data());
- size_t expected_metadata_size = resultMetadata.size();
- if ((res = validate_camera_metadata_structure(metadata, &expected_metadata_size)) != OK) {
- ALOGE("%s: Invalid camera metadata received by camera service from HAL: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return INVALID_OPERATION;
- }
- }
-
- return OK;
-}
-
-void Camera3Device::processOneCaptureResultLocked(
- const hardware::camera::device::V3_2::CaptureResult& result,
- const hardware::hidl_vec<
- hardware::camera::device::V3_4::PhysicalCameraMetadata> physicalCameraMetadata) {
- camera3_capture_result r;
- status_t res;
- r.frame_number = result.frameNumber;
-
- // Read and validate the result metadata.
- hardware::camera::device::V3_2::CameraMetadata resultMetadata;
- res = readOneCameraMetadataLocked(result.fmqResultSize, resultMetadata, result.result);
- if (res != OK) {
- ALOGE("%s: Frame %d: Failed to read capture result metadata",
- __FUNCTION__, result.frameNumber);
- return;
- }
- r.result = reinterpret_cast<const camera_metadata_t*>(resultMetadata.data());
-
- // Read and validate physical camera metadata
- size_t physResultCount = physicalCameraMetadata.size();
- std::vector<const char*> physCamIds(physResultCount);
- std::vector<const camera_metadata_t *> phyCamMetadatas(physResultCount);
- std::vector<hardware::camera::device::V3_2::CameraMetadata> physResultMetadata;
- physResultMetadata.resize(physResultCount);
- for (size_t i = 0; i < physicalCameraMetadata.size(); i++) {
- res = readOneCameraMetadataLocked(physicalCameraMetadata[i].fmqMetadataSize,
- physResultMetadata[i], physicalCameraMetadata[i].metadata);
- if (res != OK) {
- ALOGE("%s: Frame %d: Failed to read capture result metadata for camera %s",
- __FUNCTION__, result.frameNumber,
- physicalCameraMetadata[i].physicalCameraId.c_str());
- return;
- }
- physCamIds[i] = physicalCameraMetadata[i].physicalCameraId.c_str();
- phyCamMetadatas[i] = reinterpret_cast<const camera_metadata_t*>(
- physResultMetadata[i].data());
- }
- r.num_physcam_metadata = physResultCount;
- r.physcam_ids = physCamIds.data();
- r.physcam_metadata = phyCamMetadatas.data();
-
- std::vector<camera3_stream_buffer_t> outputBuffers(result.outputBuffers.size());
- std::vector<buffer_handle_t> outputBufferHandles(result.outputBuffers.size());
- for (size_t i = 0; i < result.outputBuffers.size(); i++) {
- auto& bDst = outputBuffers[i];
- const StreamBuffer &bSrc = result.outputBuffers[i];
-
- sp<Camera3StreamInterface> stream = mOutputStreams.get(bSrc.streamId);
- if (stream == nullptr) {
- ALOGE("%s: Frame %d: Buffer %zu: Invalid output stream id %d",
- __FUNCTION__, result.frameNumber, i, bSrc.streamId);
- return;
- }
- bDst.stream = stream->asHalStream();
-
- bool noBufferReturned = false;
- buffer_handle_t *buffer = nullptr;
- if (mUseHalBufManager) {
- // This is suspicious most of the time but can be correct during flush where HAL
- // has to return capture result before a buffer is requested
- if (bSrc.bufferId == HalInterface::BUFFER_ID_NO_BUFFER) {
- if (bSrc.status == BufferStatus::OK) {
- ALOGE("%s: Frame %d: Buffer %zu: No bufferId for stream %d",
- __FUNCTION__, result.frameNumber, i, bSrc.streamId);
- // Still proceeds so other buffers can be returned
- }
- noBufferReturned = true;
- }
- if (noBufferReturned) {
- res = OK;
- } else {
- res = mInterface->popInflightRequestBuffer(bSrc.bufferId, &buffer);
- }
- } else {
- res = mInterface->popInflightBuffer(result.frameNumber, bSrc.streamId, &buffer);
- }
-
- if (res != OK) {
- ALOGE("%s: Frame %d: Buffer %zu: No in-flight buffer for stream %d",
- __FUNCTION__, result.frameNumber, i, bSrc.streamId);
- return;
- }
-
- bDst.buffer = buffer;
- bDst.status = mapHidlBufferStatus(bSrc.status);
- bDst.acquire_fence = -1;
- if (bSrc.releaseFence == nullptr) {
- bDst.release_fence = -1;
- } else if (bSrc.releaseFence->numFds == 1) {
- if (noBufferReturned) {
- ALOGE("%s: got releaseFence without output buffer!", __FUNCTION__);
- }
- bDst.release_fence = dup(bSrc.releaseFence->data[0]);
- } else {
- ALOGE("%s: Frame %d: Invalid release fence for buffer %zu, fd count is %d, not 1",
- __FUNCTION__, result.frameNumber, i, bSrc.releaseFence->numFds);
- return;
- }
- }
- r.num_output_buffers = outputBuffers.size();
- r.output_buffers = outputBuffers.data();
-
- camera3_stream_buffer_t inputBuffer;
- if (result.inputBuffer.streamId == -1) {
- r.input_buffer = nullptr;
- } else {
- if (mInputStream->getId() != result.inputBuffer.streamId) {
- ALOGE("%s: Frame %d: Invalid input stream id %d", __FUNCTION__,
- result.frameNumber, result.inputBuffer.streamId);
- return;
- }
- inputBuffer.stream = mInputStream->asHalStream();
- buffer_handle_t *buffer;
- res = mInterface->popInflightBuffer(result.frameNumber, result.inputBuffer.streamId,
- &buffer);
- if (res != OK) {
- ALOGE("%s: Frame %d: Input buffer: No in-flight buffer for stream %d",
- __FUNCTION__, result.frameNumber, result.inputBuffer.streamId);
- return;
- }
- inputBuffer.buffer = buffer;
- inputBuffer.status = mapHidlBufferStatus(result.inputBuffer.status);
- inputBuffer.acquire_fence = -1;
- if (result.inputBuffer.releaseFence == nullptr) {
- inputBuffer.release_fence = -1;
- } else if (result.inputBuffer.releaseFence->numFds == 1) {
- inputBuffer.release_fence = dup(result.inputBuffer.releaseFence->data[0]);
- } else {
- ALOGE("%s: Frame %d: Invalid release fence for input buffer, fd count is %d, not 1",
- __FUNCTION__, result.frameNumber, result.inputBuffer.releaseFence->numFds);
- return;
- }
- r.input_buffer = &inputBuffer;
- }
-
- r.partial_result = result.partialResult;
-
- processCaptureResult(&r);
-}
-
hardware::Return<void> Camera3Device::notify(
const hardware::hidl_vec<hardware::camera::device::V3_2::NotifyMsg>& msgs) {
// Ideally we should grab mLock, but that can lead to deadlock, and
@@ -1460,55 +1131,31 @@
ALOGW("%s: received notify message in error state.", __FUNCTION__);
}
+ sp<NotificationListener> listener;
+ {
+ std::lock_guard<std::mutex> l(mOutputLock);
+ listener = mListener.promote();
+ }
+
+ CaptureOutputStates states {
+ mId,
+ mInFlightLock, mInFlightMap,
+ mOutputLock, mResultQueue, mResultSignal,
+ mNextShutterFrameNumber,
+ mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+ mNextResultFrameNumber,
+ mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+ mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
+ mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
+ mTagMonitor, mInputStream, mOutputStreams, listener, *this, *this, *mInterface
+ };
for (const auto& msg : msgs) {
- notify(msg);
+ camera3::notify(states, msg);
}
return hardware::Void();
}
-void Camera3Device::notify(
- const hardware::camera::device::V3_2::NotifyMsg& msg) {
-
- camera3_notify_msg m;
- switch (msg.type) {
- case MsgType::ERROR:
- m.type = CAMERA3_MSG_ERROR;
- m.message.error.frame_number = msg.msg.error.frameNumber;
- if (msg.msg.error.errorStreamId >= 0) {
- sp<Camera3StreamInterface> stream = mOutputStreams.get(msg.msg.error.errorStreamId);
- if (stream == nullptr) {
- ALOGE("%s: Frame %d: Invalid error stream id %d", __FUNCTION__,
- m.message.error.frame_number, msg.msg.error.errorStreamId);
- return;
- }
- m.message.error.error_stream = stream->asHalStream();
- } else {
- m.message.error.error_stream = nullptr;
- }
- switch (msg.msg.error.errorCode) {
- case ErrorCode::ERROR_DEVICE:
- m.message.error.error_code = CAMERA3_MSG_ERROR_DEVICE;
- break;
- case ErrorCode::ERROR_REQUEST:
- m.message.error.error_code = CAMERA3_MSG_ERROR_REQUEST;
- break;
- case ErrorCode::ERROR_RESULT:
- m.message.error.error_code = CAMERA3_MSG_ERROR_RESULT;
- break;
- case ErrorCode::ERROR_BUFFER:
- m.message.error.error_code = CAMERA3_MSG_ERROR_BUFFER;
- break;
- }
- break;
- case MsgType::SHUTTER:
- m.type = CAMERA3_MSG_SHUTTER;
- m.message.shutter.frame_number = msg.msg.shutter.frameNumber;
- m.message.shutter.timestamp = msg.msg.shutter.timestamp;
- break;
- }
- notify(&m);
-}
-
status_t Camera3Device::captureList(const List<const PhysicalCameraSettingsList> &requestsList,
const std::list<const SurfaceMap> &surfaceMaps,
int64_t *lastFrameNumber) {
@@ -1662,56 +1309,6 @@
return OK;
}
-status_t Camera3Device::StreamSet::add(
- int streamId, sp<camera3::Camera3OutputStreamInterface> stream) {
- if (stream == nullptr) {
- ALOGE("%s: cannot add null stream", __FUNCTION__);
- return BAD_VALUE;
- }
- std::lock_guard<std::mutex> lock(mLock);
- return mData.add(streamId, stream);
-}
-
-ssize_t Camera3Device::StreamSet::remove(int streamId) {
- std::lock_guard<std::mutex> lock(mLock);
- return mData.removeItem(streamId);
-}
-
-sp<camera3::Camera3OutputStreamInterface>
-Camera3Device::StreamSet::get(int streamId) {
- std::lock_guard<std::mutex> lock(mLock);
- ssize_t idx = mData.indexOfKey(streamId);
- if (idx == NAME_NOT_FOUND) {
- return nullptr;
- }
- return mData.editValueAt(idx);
-}
-
-sp<camera3::Camera3OutputStreamInterface>
-Camera3Device::StreamSet::operator[] (size_t index) {
- std::lock_guard<std::mutex> lock(mLock);
- return mData.editValueAt(index);
-}
-
-size_t Camera3Device::StreamSet::size() const {
- std::lock_guard<std::mutex> lock(mLock);
- return mData.size();
-}
-
-void Camera3Device::StreamSet::clear() {
- std::lock_guard<std::mutex> lock(mLock);
- return mData.clear();
-}
-
-std::vector<int> Camera3Device::StreamSet::getStreamIds() {
- std::lock_guard<std::mutex> lock(mLock);
- std::vector<int> streamIds(mData.size());
- for (size_t i = 0; i < mData.size(); i++) {
- streamIds[i] = mData.keyAt(i);
- }
- return streamIds;
-}
-
status_t Camera3Device::createStream(sp<Surface> consumer,
uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
@@ -2116,6 +1713,15 @@
set_camera_metadata_vendor_id(rawRequest, mVendorTagId);
mRequestTemplateCache[templateId].acquire(rawRequest);
+ // Override the template request with zoomRatioMapper
+ res = mZoomRatioMappers[mId.c_str()].initZoomRatioInTemplate(
+ &mRequestTemplateCache[templateId]);
+ if (res != OK) {
+ CLOGE("Failed to update zoom ratio for template %d: %s (%d)",
+ templateId, strerror(-res), res);
+ return res;
+ }
+
*request = mRequestTemplateCache[templateId];
mLastTemplateId = templateId;
}
@@ -2264,7 +1870,7 @@
status_t Camera3Device::setNotifyCallback(wp<NotificationListener> listener) {
ATRACE_CALL();
- Mutex::Autolock l(mOutputLock);
+ std::lock_guard<std::mutex> l(mOutputLock);
if (listener != NULL && mListener != NULL) {
ALOGW("%s: Replacing old callback listener", __FUNCTION__);
@@ -2282,17 +1888,12 @@
status_t Camera3Device::waitForNextFrame(nsecs_t timeout) {
ATRACE_CALL();
- status_t res;
- Mutex::Autolock l(mOutputLock);
+ std::unique_lock<std::mutex> l(mOutputLock);
while (mResultQueue.empty()) {
- res = mResultSignal.waitRelative(mOutputLock, timeout);
- if (res == TIMED_OUT) {
- return res;
- } else if (res != OK) {
- ALOGW("%s: Camera %s: No frame in %" PRId64 " ns: %s (%d)",
- __FUNCTION__, mId.string(), timeout, strerror(-res), res);
- return res;
+ auto st = mResultSignal.wait_for(l, std::chrono::nanoseconds(timeout));
+ if (st == std::cv_status::timeout) {
+ return TIMED_OUT;
}
}
return OK;
@@ -2300,7 +1901,7 @@
status_t Camera3Device::getNextResult(CaptureResult *frame) {
ATRACE_CALL();
- Mutex::Autolock l(mOutputLock);
+ std::lock_guard<std::mutex> l(mOutputLock);
if (mResultQueue.empty()) {
return NOT_ENOUGH_DATA;
@@ -2496,7 +2097,7 @@
sp<NotificationListener> listener;
{
- Mutex::Autolock l(mOutputLock);
+ std::lock_guard<std::mutex> l(mOutputLock);
listener = mListener.promote();
}
if (idle && listener != NULL) {
@@ -2621,7 +2222,7 @@
const PhysicalCameraSettingsList &request, const SurfaceMap &surfaceMap) {
ATRACE_CALL();
- sp<CaptureRequest> newRequest = new CaptureRequest;
+ sp<CaptureRequest> newRequest = new CaptureRequest();
newRequest->mSettingsList = request;
camera_metadata_entry_t inputStreams =
@@ -2692,18 +2293,16 @@
newRequest->mSettingsList.begin()->metadata.erase(ANDROID_REQUEST_OUTPUT_STREAMS);
newRequest->mBatchSize = 1;
- return newRequest;
-}
-
-bool Camera3Device::isOpaqueInputSizeSupported(uint32_t width, uint32_t height) {
- for (uint32_t i = 0; i < mSupportedOpaqueInputSizes.size(); i++) {
- Size size = mSupportedOpaqueInputSizes[i];
- if (size.width == width && size.height == height) {
- return true;
- }
+ auto rotateAndCropEntry =
+ newRequest->mSettingsList.begin()->metadata.find(ANDROID_SCALER_ROTATE_AND_CROP);
+ if (rotateAndCropEntry.count > 0 &&
+ rotateAndCropEntry.data.u8[0] == ANDROID_SCALER_ROTATE_AND_CROP_AUTO) {
+ newRequest->mRotateAndCropAuto = true;
+ } else {
+ newRequest->mRotateAndCropAuto = false;
}
- return false;
+ return newRequest;
}
void Camera3Device::cancelStreamsConfigurationLocked() {
@@ -2802,6 +2401,27 @@
mOperatingMode = operatingMode;
}
+ // In case called from configureStreams, abort queued input buffers not belonging to
+ // any pending requests.
+ if (mInputStream != NULL && notifyRequestThread) {
+ while (true) {
+ camera3_stream_buffer_t inputBuffer;
+ status_t res = mInputStream->getInputBuffer(&inputBuffer,
+ /*respectHalLimit*/ false);
+ if (res != OK) {
+ // Exhausted acquiring all input buffers.
+ break;
+ }
+
+ inputBuffer.status = CAMERA3_BUFFER_STATUS_ERROR;
+ res = mInputStream->returnInputBuffer(inputBuffer);
+ if (res != OK) {
+ ALOGE("%s: %d: couldn't return input buffer while clearing input queue: "
+ "%s (%d)", __FUNCTION__, __LINE__, strerror(-res), res);
+ }
+ }
+ }
+
if (!mNeedConfig) {
ALOGV("%s: Skipping config, no stream changes", __FUNCTION__);
return OK;
@@ -3117,14 +2737,15 @@
int32_t numBuffers, CaptureResultExtras resultExtras, bool hasInput,
bool hasAppCallback, nsecs_t maxExpectedDuration,
std::set<String8>& physicalCameraIds, bool isStillCapture,
- bool isZslCapture, const SurfaceMap& outputSurfaces) {
+ bool isZslCapture, bool rotateAndCropAuto, const std::set<std::string>& cameraIdsWithZoom,
+ const SurfaceMap& outputSurfaces) {
ATRACE_CALL();
- Mutex::Autolock l(mInFlightLock);
+ std::lock_guard<std::mutex> l(mInFlightLock);
ssize_t res;
res = mInFlightMap.add(frameNumber, InFlightRequest(numBuffers, resultExtras, hasInput,
hasAppCallback, maxExpectedDuration, physicalCameraIds, isStillCapture, isZslCapture,
- outputSurfaces));
+ rotateAndCropAuto, cameraIdsWithZoom, outputSurfaces));
if (res < 0) return res;
if (mInFlightMap.size() == 1) {
@@ -3140,79 +2761,7 @@
return OK;
}
-void Camera3Device::returnOutputBuffers(
- const camera3_stream_buffer_t *outputBuffers, size_t numBuffers,
- nsecs_t timestamp, bool timestampIncreasing,
- const SurfaceMap& outputSurfaces,
- const CaptureResultExtras &inResultExtras) {
-
- for (size_t i = 0; i < numBuffers; i++)
- {
- if (outputBuffers[i].buffer == nullptr) {
- if (!mUseHalBufManager) {
- // With HAL buffer management API, HAL sometimes will have to return buffers that
- // has not got a output buffer handle filled yet. This is though illegal if HAL
- // buffer management API is not being used.
- ALOGE("%s: cannot return a null buffer!", __FUNCTION__);
- }
- continue;
- }
-
- Camera3StreamInterface *stream = Camera3Stream::cast(outputBuffers[i].stream);
- int streamId = stream->getId();
- const auto& it = outputSurfaces.find(streamId);
- status_t res = OK;
- if (it != outputSurfaces.end()) {
- res = stream->returnBuffer(
- outputBuffers[i], timestamp, timestampIncreasing, it->second,
- inResultExtras.frameNumber);
- } else {
- res = stream->returnBuffer(
- outputBuffers[i], timestamp, timestampIncreasing, std::vector<size_t> (),
- inResultExtras.frameNumber);
- }
-
- // Note: stream may be deallocated at this point, if this buffer was
- // the last reference to it.
- if (res == NO_INIT || res == DEAD_OBJECT) {
- ALOGV("Can't return buffer to its stream: %s (%d)", strerror(-res), res);
- } else if (res != OK) {
- ALOGE("Can't return buffer to its stream: %s (%d)", strerror(-res), res);
- }
-
- // Long processing consumers can cause returnBuffer timeout for shared stream
- // If that happens, cancel the buffer and send a buffer error to client
- if (it != outputSurfaces.end() && res == TIMED_OUT &&
- outputBuffers[i].status == CAMERA3_BUFFER_STATUS_OK) {
- // cancel the buffer
- camera3_stream_buffer_t sb = outputBuffers[i];
- sb.status = CAMERA3_BUFFER_STATUS_ERROR;
- stream->returnBuffer(sb, /*timestamp*/0, timestampIncreasing, std::vector<size_t> (),
- inResultExtras.frameNumber);
-
- // notify client buffer error
- sp<NotificationListener> listener;
- {
- Mutex::Autolock l(mOutputLock);
- listener = mListener.promote();
- }
-
- if (listener != nullptr) {
- CaptureResultExtras extras = inResultExtras;
- extras.errorStreamId = streamId;
- listener->notifyError(
- hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_BUFFER,
- extras);
- }
- }
- }
-}
-
-void Camera3Device::removeInFlightMapEntryLocked(int idx) {
- ATRACE_CALL();
- nsecs_t duration = mInFlightMap.valueAt(idx).maxExpectedDuration;
- mInFlightMap.removeItemsAt(idx, 1);
-
+void Camera3Device::onInflightEntryRemovedLocked(nsecs_t duration) {
// Indicate idle inFlightMap to the status tracker
if (mInFlightMap.size() == 0) {
mRequestBufferSM.onInflightMapEmpty();
@@ -3226,50 +2775,7 @@
mExpectedInflightDuration -= duration;
}
-void Camera3Device::removeInFlightRequestIfReadyLocked(int idx) {
-
- const InFlightRequest &request = mInFlightMap.valueAt(idx);
- const uint32_t frameNumber = mInFlightMap.keyAt(idx);
-
- nsecs_t sensorTimestamp = request.sensorTimestamp;
- nsecs_t shutterTimestamp = request.shutterTimestamp;
-
- // Check if it's okay to remove the request from InFlightMap:
- // In the case of a successful request:
- // all input and output buffers, all result metadata, shutter callback
- // arrived.
- // In the case of a unsuccessful request:
- // all input and output buffers arrived.
- if (request.numBuffersLeft == 0 &&
- (request.skipResultMetadata ||
- (request.haveResultMetadata && shutterTimestamp != 0))) {
- if (request.stillCapture) {
- ATRACE_ASYNC_END("still capture", frameNumber);
- }
-
- ATRACE_ASYNC_END("frame capture", frameNumber);
-
- // Sanity check - if sensor timestamp matches shutter timestamp in the
- // case of request having callback.
- if (request.hasCallback && request.requestStatus == OK &&
- sensorTimestamp != shutterTimestamp) {
- SET_ERR("sensor timestamp (%" PRId64
- ") for frame %d doesn't match shutter timestamp (%" PRId64 ")",
- sensorTimestamp, frameNumber, shutterTimestamp);
- }
-
- // for an unsuccessful request, it may have pending output buffers to
- // return.
- assert(request.requestStatus != OK ||
- request.pendingOutputBuffers.size() == 0);
- returnOutputBuffers(request.pendingOutputBuffers.array(),
- request.pendingOutputBuffers.size(), 0, /*timestampIncreasing*/true,
- request.outputSurfaces, request.resultExtras);
-
- removeInFlightMapEntryLocked(idx);
- ALOGVV("%s: removed frame %d from InFlightMap", __FUNCTION__, frameNumber);
- }
-
+void Camera3Device::checkInflightMapLengthLocked() {
// Sanity check - if we have too many in-flight frames with long total inflight duration,
// something has likely gone wrong. This might still be legit only if application send in
// a long burst of long exposure requests.
@@ -3286,712 +2792,32 @@
}
}
+void Camera3Device::onInflightMapFlushedLocked() {
+ mExpectedInflightDuration = 0;
+}
+
+void Camera3Device::removeInFlightMapEntryLocked(int idx) {
+ ATRACE_CALL();
+ nsecs_t duration = mInFlightMap.valueAt(idx).maxExpectedDuration;
+ mInFlightMap.removeItemsAt(idx, 1);
+
+ onInflightEntryRemovedLocked(duration);
+}
+
+
void Camera3Device::flushInflightRequests() {
ATRACE_CALL();
- { // First return buffers cached in mInFlightMap
- Mutex::Autolock l(mInFlightLock);
- for (size_t idx = 0; idx < mInFlightMap.size(); idx++) {
- const InFlightRequest &request = mInFlightMap.valueAt(idx);
- returnOutputBuffers(request.pendingOutputBuffers.array(),
- request.pendingOutputBuffers.size(), 0,
- /*timestampIncreasing*/true, request.outputSurfaces,
- request.resultExtras);
- }
- mInFlightMap.clear();
- mExpectedInflightDuration = 0;
- }
-
- // Then return all inflight buffers not returned by HAL
- std::vector<std::pair<int32_t, int32_t>> inflightKeys;
- mInterface->getInflightBufferKeys(&inflightKeys);
-
- // Inflight buffers for HAL buffer manager
- std::vector<uint64_t> inflightRequestBufferKeys;
- mInterface->getInflightRequestBufferKeys(&inflightRequestBufferKeys);
-
- // (streamId, frameNumber, buffer_handle_t*) tuple for all inflight buffers.
- // frameNumber will be -1 for buffers from HAL buffer manager
- std::vector<std::tuple<int32_t, int32_t, buffer_handle_t*>> inflightBuffers;
- inflightBuffers.reserve(inflightKeys.size() + inflightRequestBufferKeys.size());
-
- for (auto& pair : inflightKeys) {
- int32_t frameNumber = pair.first;
- int32_t streamId = pair.second;
- buffer_handle_t* buffer;
- status_t res = mInterface->popInflightBuffer(frameNumber, streamId, &buffer);
- if (res != OK) {
- ALOGE("%s: Frame %d: No in-flight buffer for stream %d",
- __FUNCTION__, frameNumber, streamId);
- continue;
- }
- inflightBuffers.push_back(std::make_tuple(streamId, frameNumber, buffer));
- }
-
- for (auto& bufferId : inflightRequestBufferKeys) {
- int32_t streamId = -1;
- buffer_handle_t* buffer = nullptr;
- status_t res = mInterface->popInflightRequestBuffer(bufferId, &buffer, &streamId);
- if (res != OK) {
- ALOGE("%s: cannot find in-flight buffer %" PRIu64, __FUNCTION__, bufferId);
- continue;
- }
- inflightBuffers.push_back(std::make_tuple(streamId, /*frameNumber*/-1, buffer));
- }
-
- int32_t inputStreamId = (mInputStream != nullptr) ? mInputStream->getId() : -1;
- for (auto& tuple : inflightBuffers) {
- status_t res = OK;
- int32_t streamId = std::get<0>(tuple);
- int32_t frameNumber = std::get<1>(tuple);
- buffer_handle_t* buffer = std::get<2>(tuple);
-
- camera3_stream_buffer_t streamBuffer;
- streamBuffer.buffer = buffer;
- streamBuffer.status = CAMERA3_BUFFER_STATUS_ERROR;
- streamBuffer.acquire_fence = -1;
- streamBuffer.release_fence = -1;
-
- // First check if the buffer belongs to deleted stream
- bool streamDeleted = false;
- for (auto& stream : mDeletedStreams) {
- if (streamId == stream->getId()) {
- streamDeleted = true;
- // Return buffer to deleted stream
- camera3_stream* halStream = stream->asHalStream();
- streamBuffer.stream = halStream;
- switch (halStream->stream_type) {
- case CAMERA3_STREAM_OUTPUT:
- res = stream->returnBuffer(streamBuffer, /*timestamp*/ 0,
- /*timestampIncreasing*/true, std::vector<size_t> (), frameNumber);
- if (res != OK) {
- ALOGE("%s: Can't return output buffer for frame %d to"
- " stream %d: %s (%d)", __FUNCTION__,
- frameNumber, streamId, strerror(-res), res);
- }
- break;
- case CAMERA3_STREAM_INPUT:
- res = stream->returnInputBuffer(streamBuffer);
- if (res != OK) {
- ALOGE("%s: Can't return input buffer for frame %d to"
- " stream %d: %s (%d)", __FUNCTION__,
- frameNumber, streamId, strerror(-res), res);
- }
- break;
- default: // Bi-direcitonal stream is deprecated
- ALOGE("%s: stream %d has unknown stream type %d",
- __FUNCTION__, streamId, halStream->stream_type);
- break;
- }
- break;
- }
- }
- if (streamDeleted) {
- continue;
- }
-
- // Then check against configured streams
- if (streamId == inputStreamId) {
- streamBuffer.stream = mInputStream->asHalStream();
- res = mInputStream->returnInputBuffer(streamBuffer);
- if (res != OK) {
- ALOGE("%s: Can't return input buffer for frame %d to"
- " stream %d: %s (%d)", __FUNCTION__,
- frameNumber, streamId, strerror(-res), res);
- }
- } else {
- sp<Camera3StreamInterface> stream = mOutputStreams.get(streamId);
- if (stream == nullptr) {
- ALOGE("%s: Output stream id %d not found!", __FUNCTION__, streamId);
- continue;
- }
- streamBuffer.stream = stream->asHalStream();
- returnOutputBuffers(&streamBuffer, /*size*/1, /*timestamp*/ 0);
- }
- }
-}
-
-void Camera3Device::insertResultLocked(CaptureResult *result,
- uint32_t frameNumber) {
- if (result == nullptr) return;
-
- camera_metadata_t *meta = const_cast<camera_metadata_t *>(
- result->mMetadata.getAndLock());
- set_camera_metadata_vendor_id(meta, mVendorTagId);
- result->mMetadata.unlock(meta);
-
- if (result->mMetadata.update(ANDROID_REQUEST_FRAME_COUNT,
- (int32_t*)&frameNumber, 1) != OK) {
- SET_ERR("Failed to set frame number %d in metadata", frameNumber);
- return;
- }
-
- if (result->mMetadata.update(ANDROID_REQUEST_ID, &result->mResultExtras.requestId, 1) != OK) {
- SET_ERR("Failed to set request ID in metadata for frame %d", frameNumber);
- return;
- }
-
- // Update vendor tag id for physical metadata
- for (auto& physicalMetadata : result->mPhysicalMetadatas) {
- camera_metadata_t *pmeta = const_cast<camera_metadata_t *>(
- physicalMetadata.mPhysicalCameraMetadata.getAndLock());
- set_camera_metadata_vendor_id(pmeta, mVendorTagId);
- physicalMetadata.mPhysicalCameraMetadata.unlock(pmeta);
- }
-
- // Valid result, insert into queue
- List<CaptureResult>::iterator queuedResult =
- mResultQueue.insert(mResultQueue.end(), CaptureResult(*result));
- ALOGVV("%s: result requestId = %" PRId32 ", frameNumber = %" PRId64
- ", burstId = %" PRId32, __FUNCTION__,
- queuedResult->mResultExtras.requestId,
- queuedResult->mResultExtras.frameNumber,
- queuedResult->mResultExtras.burstId);
-
- mResultSignal.signal();
-}
-
-
-void Camera3Device::sendPartialCaptureResult(const camera_metadata_t * partialResult,
- const CaptureResultExtras &resultExtras, uint32_t frameNumber) {
- ATRACE_CALL();
- Mutex::Autolock l(mOutputLock);
-
- CaptureResult captureResult;
- captureResult.mResultExtras = resultExtras;
- captureResult.mMetadata = partialResult;
-
- // Fix up result metadata for monochrome camera.
- status_t res = fixupMonochromeTags(mDeviceInfo, captureResult.mMetadata);
- if (res != OK) {
- SET_ERR("Failed to override result metadata: %s (%d)", strerror(-res), res);
- return;
- }
-
- insertResultLocked(&captureResult, frameNumber);
-}
-
-
-void Camera3Device::sendCaptureResult(CameraMetadata &pendingMetadata,
- CaptureResultExtras &resultExtras,
- CameraMetadata &collectedPartialResult,
- uint32_t frameNumber,
- bool reprocess, bool zslStillCapture,
- const std::vector<PhysicalCaptureResultInfo>& physicalMetadatas) {
- ATRACE_CALL();
- if (pendingMetadata.isEmpty())
- return;
-
- Mutex::Autolock l(mOutputLock);
-
- // TODO: need to track errors for tighter bounds on expected frame number
- if (reprocess) {
- if (frameNumber < mNextReprocessResultFrameNumber) {
- SET_ERR("Out-of-order reprocess capture result metadata submitted! "
- "(got frame number %d, expecting %d)",
- frameNumber, mNextReprocessResultFrameNumber);
- return;
- }
- mNextReprocessResultFrameNumber = frameNumber + 1;
- } else if (zslStillCapture) {
- if (frameNumber < mNextZslStillResultFrameNumber) {
- SET_ERR("Out-of-order ZSL still capture result metadata submitted! "
- "(got frame number %d, expecting %d)",
- frameNumber, mNextZslStillResultFrameNumber);
- return;
- }
- mNextZslStillResultFrameNumber = frameNumber + 1;
- } else {
- if (frameNumber < mNextResultFrameNumber) {
- SET_ERR("Out-of-order capture result metadata submitted! "
- "(got frame number %d, expecting %d)",
- frameNumber, mNextResultFrameNumber);
- return;
- }
- mNextResultFrameNumber = frameNumber + 1;
- }
-
- CaptureResult captureResult;
- captureResult.mResultExtras = resultExtras;
- captureResult.mMetadata = pendingMetadata;
- captureResult.mPhysicalMetadatas = physicalMetadatas;
-
- // Append any previous partials to form a complete result
- if (mUsePartialResult && !collectedPartialResult.isEmpty()) {
- captureResult.mMetadata.append(collectedPartialResult);
- }
-
- captureResult.mMetadata.sort();
-
- // Check that there's a timestamp in the result metadata
- camera_metadata_entry timestamp = captureResult.mMetadata.find(ANDROID_SENSOR_TIMESTAMP);
- if (timestamp.count == 0) {
- SET_ERR("No timestamp provided by HAL for frame %d!",
- frameNumber);
- return;
- }
- for (auto& physicalMetadata : captureResult.mPhysicalMetadatas) {
- camera_metadata_entry timestamp =
- physicalMetadata.mPhysicalCameraMetadata.find(ANDROID_SENSOR_TIMESTAMP);
- if (timestamp.count == 0) {
- SET_ERR("No timestamp provided by HAL for physical camera %s frame %d!",
- String8(physicalMetadata.mPhysicalCameraId).c_str(), frameNumber);
- return;
- }
- }
-
- // Fix up some result metadata to account for HAL-level distortion correction
- status_t res =
- mDistortionMappers[mId.c_str()].correctCaptureResult(&captureResult.mMetadata);
- if (res != OK) {
- SET_ERR("Unable to correct capture result metadata for frame %d: %s (%d)",
- frameNumber, strerror(res), res);
- return;
- }
- for (auto& physicalMetadata : captureResult.mPhysicalMetadatas) {
- String8 cameraId8(physicalMetadata.mPhysicalCameraId);
- if (mDistortionMappers.find(cameraId8.c_str()) == mDistortionMappers.end()) {
- continue;
- }
- res = mDistortionMappers[cameraId8.c_str()].correctCaptureResult(
- &physicalMetadata.mPhysicalCameraMetadata);
- if (res != OK) {
- SET_ERR("Unable to correct physical capture result metadata for frame %d: %s (%d)",
- frameNumber, strerror(res), res);
- return;
- }
- }
-
- // Fix up result metadata for monochrome camera.
- res = fixupMonochromeTags(mDeviceInfo, captureResult.mMetadata);
- if (res != OK) {
- SET_ERR("Failed to override result metadata: %s (%d)", strerror(-res), res);
- return;
- }
- for (auto& physicalMetadata : captureResult.mPhysicalMetadatas) {
- String8 cameraId8(physicalMetadata.mPhysicalCameraId);
- res = fixupMonochromeTags(mPhysicalDeviceInfoMap.at(cameraId8.c_str()),
- physicalMetadata.mPhysicalCameraMetadata);
- if (res != OK) {
- SET_ERR("Failed to override result metadata: %s (%d)", strerror(-res), res);
- return;
- }
- }
-
- std::unordered_map<std::string, CameraMetadata> monitoredPhysicalMetadata;
- for (auto& m : physicalMetadatas) {
- monitoredPhysicalMetadata.emplace(String8(m.mPhysicalCameraId).string(),
- CameraMetadata(m.mPhysicalCameraMetadata));
- }
- mTagMonitor.monitorMetadata(TagMonitor::RESULT,
- frameNumber, timestamp.data.i64[0], captureResult.mMetadata,
- monitoredPhysicalMetadata);
-
- insertResultLocked(&captureResult, frameNumber);
-}
-
-/**
- * Camera HAL device callback methods
- */
-
-void Camera3Device::processCaptureResult(const camera3_capture_result *result) {
- ATRACE_CALL();
-
- status_t res;
-
- uint32_t frameNumber = result->frame_number;
- if (result->result == NULL && result->num_output_buffers == 0 &&
- result->input_buffer == NULL) {
- SET_ERR("No result data provided by HAL for frame %d",
- frameNumber);
- return;
- }
-
- if (!mUsePartialResult &&
- result->result != NULL &&
- result->partial_result != 1) {
- SET_ERR("Result is malformed for frame %d: partial_result %u must be 1"
- " if partial result is not supported",
- frameNumber, result->partial_result);
- return;
- }
-
- bool isPartialResult = false;
- CameraMetadata collectedPartialResult;
- bool hasInputBufferInRequest = false;
-
- // Get shutter timestamp and resultExtras from list of in-flight requests,
- // where it was added by the shutter notification for this frame. If the
- // shutter timestamp isn't received yet, append the output buffers to the
- // in-flight request and they will be returned when the shutter timestamp
- // arrives. Update the in-flight status and remove the in-flight entry if
- // all result data and shutter timestamp have been received.
- nsecs_t shutterTimestamp = 0;
-
- {
- Mutex::Autolock l(mInFlightLock);
- ssize_t idx = mInFlightMap.indexOfKey(frameNumber);
- if (idx == NAME_NOT_FOUND) {
- SET_ERR("Unknown frame number for capture result: %d",
- frameNumber);
- return;
- }
- InFlightRequest &request = mInFlightMap.editValueAt(idx);
- ALOGVV("%s: got InFlightRequest requestId = %" PRId32
- ", frameNumber = %" PRId64 ", burstId = %" PRId32
- ", partialResultCount = %d, hasCallback = %d",
- __FUNCTION__, request.resultExtras.requestId,
- request.resultExtras.frameNumber, request.resultExtras.burstId,
- result->partial_result, request.hasCallback);
- // Always update the partial count to the latest one if it's not 0
- // (buffers only). When framework aggregates adjacent partial results
- // into one, the latest partial count will be used.
- if (result->partial_result != 0)
- request.resultExtras.partialResultCount = result->partial_result;
-
- // Check if this result carries only partial metadata
- if (mUsePartialResult && result->result != NULL) {
- if (result->partial_result > mNumPartialResults || result->partial_result < 1) {
- SET_ERR("Result is malformed for frame %d: partial_result %u must be in"
- " the range of [1, %d] when metadata is included in the result",
- frameNumber, result->partial_result, mNumPartialResults);
- return;
- }
- isPartialResult = (result->partial_result < mNumPartialResults);
- if (isPartialResult && result->num_physcam_metadata) {
- SET_ERR("Result is malformed for frame %d: partial_result not allowed for"
- " physical camera result", frameNumber);
- return;
- }
- if (isPartialResult) {
- request.collectedPartialResult.append(result->result);
- }
-
- if (isPartialResult && request.hasCallback) {
- // Send partial capture result
- sendPartialCaptureResult(result->result, request.resultExtras,
- frameNumber);
- }
- }
-
- shutterTimestamp = request.shutterTimestamp;
- hasInputBufferInRequest = request.hasInputBuffer;
-
- // Did we get the (final) result metadata for this capture?
- if (result->result != NULL && !isPartialResult) {
- if (request.physicalCameraIds.size() != result->num_physcam_metadata) {
- SET_ERR("Requested physical Camera Ids %d not equal to number of metadata %d",
- request.physicalCameraIds.size(), result->num_physcam_metadata);
- return;
- }
- if (request.haveResultMetadata) {
- SET_ERR("Called multiple times with metadata for frame %d",
- frameNumber);
- return;
- }
- for (uint32_t i = 0; i < result->num_physcam_metadata; i++) {
- String8 physicalId(result->physcam_ids[i]);
- std::set<String8>::iterator cameraIdIter =
- request.physicalCameraIds.find(physicalId);
- if (cameraIdIter != request.physicalCameraIds.end()) {
- request.physicalCameraIds.erase(cameraIdIter);
- } else {
- SET_ERR("Total result for frame %d has already returned for camera %s",
- frameNumber, physicalId.c_str());
- return;
- }
- }
- if (mUsePartialResult &&
- !request.collectedPartialResult.isEmpty()) {
- collectedPartialResult.acquire(
- request.collectedPartialResult);
- }
- request.haveResultMetadata = true;
- }
-
- uint32_t numBuffersReturned = result->num_output_buffers;
- if (result->input_buffer != NULL) {
- if (hasInputBufferInRequest) {
- numBuffersReturned += 1;
- } else {
- ALOGW("%s: Input buffer should be NULL if there is no input"
- " buffer sent in the request",
- __FUNCTION__);
- }
- }
- request.numBuffersLeft -= numBuffersReturned;
- if (request.numBuffersLeft < 0) {
- SET_ERR("Too many buffers returned for frame %d",
- frameNumber);
- return;
- }
-
- camera_metadata_ro_entry_t entry;
- res = find_camera_metadata_ro_entry(result->result,
- ANDROID_SENSOR_TIMESTAMP, &entry);
- if (res == OK && entry.count == 1) {
- request.sensorTimestamp = entry.data.i64[0];
- }
-
- // If shutter event isn't received yet, append the output buffers to
- // the in-flight request. Otherwise, return the output buffers to
- // streams.
- if (shutterTimestamp == 0) {
- request.pendingOutputBuffers.appendArray(result->output_buffers,
- result->num_output_buffers);
- } else {
- bool timestampIncreasing = !(request.zslCapture || request.hasInputBuffer);
- returnOutputBuffers(result->output_buffers,
- result->num_output_buffers, shutterTimestamp, timestampIncreasing,
- request.outputSurfaces, request.resultExtras);
- }
-
- if (result->result != NULL && !isPartialResult) {
- for (uint32_t i = 0; i < result->num_physcam_metadata; i++) {
- CameraMetadata physicalMetadata;
- physicalMetadata.append(result->physcam_metadata[i]);
- request.physicalMetadatas.push_back({String16(result->physcam_ids[i]),
- physicalMetadata});
- }
- if (shutterTimestamp == 0) {
- request.pendingMetadata = result->result;
- request.collectedPartialResult = collectedPartialResult;
- } else if (request.hasCallback) {
- CameraMetadata metadata;
- metadata = result->result;
- sendCaptureResult(metadata, request.resultExtras,
- collectedPartialResult, frameNumber,
- hasInputBufferInRequest, request.zslCapture && request.stillCapture,
- request.physicalMetadatas);
- }
- }
-
- removeInFlightRequestIfReadyLocked(idx);
- } // scope for mInFlightLock
-
- if (result->input_buffer != NULL) {
- if (hasInputBufferInRequest) {
- Camera3Stream *stream =
- Camera3Stream::cast(result->input_buffer->stream);
- res = stream->returnInputBuffer(*(result->input_buffer));
- // Note: stream may be deallocated at this point, if this buffer was the
- // last reference to it.
- if (res != OK) {
- ALOGE("%s: RequestThread: Can't return input buffer for frame %d to"
- " its stream:%s (%d)", __FUNCTION__,
- frameNumber, strerror(-res), res);
- }
- } else {
- ALOGW("%s: Input buffer should be NULL if there is no input"
- " buffer sent in the request, skipping input buffer return.",
- __FUNCTION__);
- }
- }
-}
-
-void Camera3Device::notify(const camera3_notify_msg *msg) {
- ATRACE_CALL();
sp<NotificationListener> listener;
{
- Mutex::Autolock l(mOutputLock);
+ std::lock_guard<std::mutex> l(mOutputLock);
listener = mListener.promote();
}
- if (msg == NULL) {
- SET_ERR("HAL sent NULL notify message!");
- return;
- }
+ FlushInflightReqStates states {
+ mId, mInFlightLock, mInFlightMap, mUseHalBufManager,
+ listener, *this, *mInterface, *this};
- switch (msg->type) {
- case CAMERA3_MSG_ERROR: {
- notifyError(msg->message.error, listener);
- break;
- }
- case CAMERA3_MSG_SHUTTER: {
- notifyShutter(msg->message.shutter, listener);
- break;
- }
- default:
- SET_ERR("Unknown notify message from HAL: %d",
- msg->type);
- }
-}
-
-void Camera3Device::notifyError(const camera3_error_msg_t &msg,
- sp<NotificationListener> listener) {
- ATRACE_CALL();
- // Map camera HAL error codes to ICameraDeviceCallback error codes
- // Index into this with the HAL error code
- static const int32_t halErrorMap[CAMERA3_MSG_NUM_ERRORS] = {
- // 0 = Unused error code
- hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_INVALID_ERROR,
- // 1 = CAMERA3_MSG_ERROR_DEVICE
- hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE,
- // 2 = CAMERA3_MSG_ERROR_REQUEST
- hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST,
- // 3 = CAMERA3_MSG_ERROR_RESULT
- hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_RESULT,
- // 4 = CAMERA3_MSG_ERROR_BUFFER
- hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_BUFFER
- };
-
- int32_t errorCode =
- ((msg.error_code >= 0) &&
- (msg.error_code < CAMERA3_MSG_NUM_ERRORS)) ?
- halErrorMap[msg.error_code] :
- hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_INVALID_ERROR;
-
- int streamId = 0;
- String16 physicalCameraId;
- if (msg.error_stream != NULL) {
- Camera3Stream *stream =
- Camera3Stream::cast(msg.error_stream);
- streamId = stream->getId();
- physicalCameraId = String16(stream->physicalCameraId());
- }
- ALOGV("Camera %s: %s: HAL error, frame %d, stream %d: %d",
- mId.string(), __FUNCTION__, msg.frame_number,
- streamId, msg.error_code);
-
- CaptureResultExtras resultExtras;
- switch (errorCode) {
- case hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE:
- // SET_ERR calls notifyError
- SET_ERR("Camera HAL reported serious device error");
- break;
- case hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST:
- case hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_RESULT:
- case hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_BUFFER:
- {
- Mutex::Autolock l(mInFlightLock);
- ssize_t idx = mInFlightMap.indexOfKey(msg.frame_number);
- if (idx >= 0) {
- InFlightRequest &r = mInFlightMap.editValueAt(idx);
- r.requestStatus = msg.error_code;
- resultExtras = r.resultExtras;
- bool logicalDeviceResultError = false;
- if (hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_RESULT ==
- errorCode) {
- if (physicalCameraId.size() > 0) {
- String8 cameraId(physicalCameraId);
- if (r.physicalCameraIds.find(cameraId) == r.physicalCameraIds.end()) {
- ALOGE("%s: Reported result failure for physical camera device: %s "
- " which is not part of the respective request!",
- __FUNCTION__, cameraId.string());
- break;
- }
- resultExtras.errorPhysicalCameraId = physicalCameraId;
- } else {
- logicalDeviceResultError = true;
- }
- }
-
- if (logicalDeviceResultError
- || hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST ==
- errorCode) {
- r.skipResultMetadata = true;
- }
- if (logicalDeviceResultError) {
- // In case of missing result check whether the buffers
- // returned. If they returned, then remove inflight
- // request.
- // TODO: should we call this for ERROR_CAMERA_REQUEST as well?
- // otherwise we are depending on HAL to send the buffers back after
- // calling notifyError. Not sure if that's in the spec.
- removeInFlightRequestIfReadyLocked(idx);
- }
- } else {
- resultExtras.frameNumber = msg.frame_number;
- ALOGE("Camera %s: %s: cannot find in-flight request on "
- "frame %" PRId64 " error", mId.string(), __FUNCTION__,
- resultExtras.frameNumber);
- }
- }
- resultExtras.errorStreamId = streamId;
- if (listener != NULL) {
- listener->notifyError(errorCode, resultExtras);
- } else {
- ALOGE("Camera %s: %s: no listener available", mId.string(), __FUNCTION__);
- }
- break;
- default:
- // SET_ERR calls notifyError
- SET_ERR("Unknown error message from HAL: %d", msg.error_code);
- break;
- }
-}
-
-void Camera3Device::notifyShutter(const camera3_shutter_msg_t &msg,
- sp<NotificationListener> listener) {
- ATRACE_CALL();
- ssize_t idx;
-
- // Set timestamp for the request in the in-flight tracking
- // and get the request ID to send upstream
- {
- Mutex::Autolock l(mInFlightLock);
- idx = mInFlightMap.indexOfKey(msg.frame_number);
- if (idx >= 0) {
- InFlightRequest &r = mInFlightMap.editValueAt(idx);
-
- // Verify ordering of shutter notifications
- {
- Mutex::Autolock l(mOutputLock);
- // TODO: need to track errors for tighter bounds on expected frame number.
- if (r.hasInputBuffer) {
- if (msg.frame_number < mNextReprocessShutterFrameNumber) {
- SET_ERR("Reprocess shutter notification out-of-order. Expected "
- "notification for frame %d, got frame %d",
- mNextReprocessShutterFrameNumber, msg.frame_number);
- return;
- }
- mNextReprocessShutterFrameNumber = msg.frame_number + 1;
- } else if (r.zslCapture && r.stillCapture) {
- if (msg.frame_number < mNextZslStillShutterFrameNumber) {
- SET_ERR("ZSL still capture shutter notification out-of-order. Expected "
- "notification for frame %d, got frame %d",
- mNextZslStillShutterFrameNumber, msg.frame_number);
- return;
- }
- mNextZslStillShutterFrameNumber = msg.frame_number + 1;
- } else {
- if (msg.frame_number < mNextShutterFrameNumber) {
- SET_ERR("Shutter notification out-of-order. Expected "
- "notification for frame %d, got frame %d",
- mNextShutterFrameNumber, msg.frame_number);
- return;
- }
- mNextShutterFrameNumber = msg.frame_number + 1;
- }
- }
-
- r.shutterTimestamp = msg.timestamp;
- if (r.hasCallback) {
- ALOGVV("Camera %s: %s: Shutter fired for frame %d (id %d) at %" PRId64,
- mId.string(), __FUNCTION__,
- msg.frame_number, r.resultExtras.requestId, msg.timestamp);
- // Call listener, if any
- if (listener != NULL) {
- listener->notifyShutter(r.resultExtras, msg.timestamp);
- }
- // send pending result and buffers
- sendCaptureResult(r.pendingMetadata, r.resultExtras,
- r.collectedPartialResult, msg.frame_number,
- r.hasInputBuffer, r.zslCapture && r.stillCapture,
- r.physicalMetadatas);
- }
- bool timestampIncreasing = !(r.zslCapture || r.hasInputBuffer);
- returnOutputBuffers(r.pendingOutputBuffers.array(),
- r.pendingOutputBuffers.size(), r.shutterTimestamp, timestampIncreasing,
- r.outputSurfaces, r.resultExtras);
- r.pendingOutputBuffers.clear();
-
- removeInFlightRequestIfReadyLocked(idx);
- }
- }
- if (idx < 0) {
- SET_ERR("Shutter notification for non-existent frame number %d",
- msg.frame_number);
- }
+ camera3::flushInflightRequests(states);
}
CameraMetadata Camera3Device::getLatestRequestLocked() {
@@ -4006,7 +2832,6 @@
return retVal;
}
-
void Camera3Device::monitorMetadata(TagMonitor::eventSource source,
int64_t frameNumber, nsecs_t timestamp, const CameraMetadata& metadata,
const std::unordered_map<std::string, CameraMetadata>& physicalMetadata) {
@@ -4022,13 +2847,18 @@
Camera3Device::HalInterface::HalInterface(
sp<ICameraDeviceSession> &session,
std::shared_ptr<RequestMetadataQueue> queue,
- bool useHalBufManager) :
+ bool useHalBufManager, bool supportOfflineProcessing) :
mHidlSession(session),
mRequestMetadataQueue(queue),
mUseHalBufManager(useHalBufManager),
- mIsReconfigurationQuerySupported(true) {
+ mIsReconfigurationQuerySupported(true),
+ mSupportOfflineProcessing(supportOfflineProcessing) {
// Check with hardware service manager if we can downcast these interfaces
// Somewhat expensive, so cache the results at startup
+ auto castResult_3_6 = device::V3_6::ICameraDeviceSession::castFrom(mHidlSession);
+ if (castResult_3_6.isOk()) {
+ mHidlSession_3_6 = castResult_3_6;
+ }
auto castResult_3_5 = device::V3_5::ICameraDeviceSession::castFrom(mHidlSession);
if (castResult_3_5.isOk()) {
mHidlSession_3_5 = castResult_3_5;
@@ -4043,18 +2873,22 @@
}
}
-Camera3Device::HalInterface::HalInterface() : mUseHalBufManager(false) {}
+Camera3Device::HalInterface::HalInterface() :
+ mUseHalBufManager(false),
+ mSupportOfflineProcessing(false) {}
Camera3Device::HalInterface::HalInterface(const HalInterface& other) :
mHidlSession(other.mHidlSession),
mRequestMetadataQueue(other.mRequestMetadataQueue),
- mUseHalBufManager(other.mUseHalBufManager) {}
+ mUseHalBufManager(other.mUseHalBufManager),
+ mSupportOfflineProcessing(other.mSupportOfflineProcessing) {}
bool Camera3Device::HalInterface::valid() {
return (mHidlSession != nullptr);
}
void Camera3Device::HalInterface::clear() {
+ mHidlSession_3_6.clear();
mHidlSession_3_5.clear();
mHidlSession_3_4.clear();
mHidlSession_3_3.clear();
@@ -4232,20 +3066,10 @@
activeStreams.insert(streamId);
// Create Buffer ID map if necessary
- if (mBufferIdMaps.count(streamId) == 0) {
- mBufferIdMaps.emplace(streamId, BufferIdMap{});
- }
+ mBufferRecords.tryCreateBufferCache(streamId);
}
// remove BufferIdMap for deleted streams
- for(auto it = mBufferIdMaps.begin(); it != mBufferIdMaps.end();) {
- int streamId = it->first;
- bool active = activeStreams.count(streamId) > 0;
- if (!active) {
- it = mBufferIdMaps.erase(it);
- } else {
- ++it;
- }
- }
+ mBufferRecords.removeInactiveBufferCaches(activeStreams);
StreamConfigurationMode operationMode;
res = mapToStreamConfigurationMode(
@@ -4263,6 +3087,7 @@
// Invoke configureStreams
device::V3_3::HalStreamConfiguration finalConfiguration;
device::V3_4::HalStreamConfiguration finalConfiguration3_4;
+ device::V3_6::HalStreamConfiguration finalConfiguration3_6;
common::V1_0::Status status;
auto configStream34Cb = [&status, &finalConfiguration3_4]
@@ -4271,6 +3096,12 @@
status = s;
};
+ auto configStream36Cb = [&status, &finalConfiguration3_6]
+ (common::V1_0::Status s, const device::V3_6::HalStreamConfiguration& halConfiguration) {
+ finalConfiguration3_6 = halConfiguration;
+ status = s;
+ };
+
auto postprocConfigStream34 = [&finalConfiguration, &finalConfiguration3_4]
(hardware::Return<void>& err) -> status_t {
if (!err.isOk()) {
@@ -4284,8 +3115,32 @@
return OK;
};
+ auto postprocConfigStream36 = [&finalConfiguration, &finalConfiguration3_6]
+ (hardware::Return<void>& err) -> status_t {
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+ return DEAD_OBJECT;
+ }
+ finalConfiguration.streams.resize(finalConfiguration3_6.streams.size());
+ for (size_t i = 0; i < finalConfiguration3_6.streams.size(); i++) {
+ finalConfiguration.streams[i] = finalConfiguration3_6.streams[i].v3_4.v3_3;
+ }
+ return OK;
+ };
+
// See which version of HAL we have
- if (mHidlSession_3_5 != nullptr) {
+ if (mHidlSession_3_6 != nullptr) {
+ ALOGV("%s: v3.6 device found", __FUNCTION__);
+ device::V3_5::StreamConfiguration requestedConfiguration3_5;
+ requestedConfiguration3_5.v3_4 = requestedConfiguration3_4;
+ requestedConfiguration3_5.streamConfigCounter = mNextStreamConfigCounter++;
+ auto err = mHidlSession_3_6->configureStreams_3_6(
+ requestedConfiguration3_5, configStream36Cb);
+ res = postprocConfigStream36(err);
+ if (res != OK) {
+ return res;
+ }
+ } else if (mHidlSession_3_5 != nullptr) {
ALOGV("%s: v3.5 device found", __FUNCTION__);
device::V3_5::StreamConfiguration requestedConfiguration3_5;
requestedConfiguration3_5.v3_4 = requestedConfiguration3_4;
@@ -4367,11 +3222,16 @@
return INVALID_OPERATION;
}
device::V3_3::HalStream &src = finalConfiguration.streams[realIdx];
+ device::V3_6::HalStream &src_36 = finalConfiguration3_6.streams[realIdx];
Camera3Stream* dstStream = Camera3Stream::cast(dst);
int overrideFormat = mapToFrameworkFormat(src.v3_2.overrideFormat);
android_dataspace overrideDataSpace = mapToFrameworkDataspace(src.overrideDataSpace);
+ if (mHidlSession_3_6 != nullptr) {
+ dstStream->setOfflineProcessingSupport(src_36.supportOffline);
+ }
+
if (dstStream->getOriginalFormat() != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
dstStream->setFormatOverride(false);
dstStream->setDataSpaceOverride(false);
@@ -4435,7 +3295,6 @@
captureRequest->fmqSettingsSize = 0;
{
- std::lock_guard<std::mutex> lock(mInflightLock);
if (request->input_buffer != nullptr) {
int32_t streamId = Camera3Stream::cast(request->input_buffer->stream)->getId();
buffer_handle_t buf = *(request->input_buffer->buffer);
@@ -4455,7 +3314,7 @@
captureRequest->inputBuffer.acquireFence = acquireFence;
captureRequest->inputBuffer.releaseFence = nullptr;
- pushInflightBufferLocked(captureRequest->frameNumber, streamId,
+ mBufferRecords.pushInflightBuffer(captureRequest->frameNumber, streamId,
request->input_buffer->buffer);
inflightBuffers->push_back(std::make_pair(captureRequest->frameNumber, streamId));
} else {
@@ -4496,7 +3355,8 @@
// Output buffers are empty when using HAL buffer manager
if (!mUseHalBufManager) {
- pushInflightBufferLocked(captureRequest->frameNumber, streamId, src->buffer);
+ mBufferRecords.pushInflightBuffer(
+ captureRequest->frameNumber, streamId, src->buffer);
inflightBuffers->push_back(std::make_pair(captureRequest->frameNumber, streamId));
}
}
@@ -4553,7 +3413,7 @@
/*out*/&handlesCreated, /*out*/&inflightBuffers);
}
if (res != OK) {
- popInflightBuffers(inflightBuffers);
+ mBufferRecords.popInflightBuffers(inflightBuffers);
cleanupNativeHandles(&handlesCreated);
return res;
}
@@ -4561,10 +3421,10 @@
std::vector<device::V3_2::BufferCache> cachesToRemove;
{
- std::lock_guard<std::mutex> lock(mBufferIdMapLock);
+ std::lock_guard<std::mutex> lock(mFreedBuffersLock);
for (auto& pair : mFreedBuffers) {
// The stream might have been removed since onBufferFreed
- if (mBufferIdMaps.find(pair.first) != mBufferIdMaps.end()) {
+ if (mBufferRecords.isStreamCached(pair.first)) {
cachesToRemove.push_back({pair.first, pair.second});
}
}
@@ -4671,7 +3531,7 @@
cleanupNativeHandles(&handlesCreated);
}
} else {
- popInflightBuffers(inflightBuffers);
+ mBufferRecords.popInflightBuffers(inflightBuffers);
cleanupNativeHandles(&handlesCreated);
}
return res;
@@ -4730,72 +3590,94 @@
}
}
+status_t Camera3Device::HalInterface::switchToOffline(
+ const std::vector<int32_t>& streamsToKeep,
+ /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
+ /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession,
+ /*out*/camera3::BufferRecords* bufferRecords) {
+ ATRACE_NAME("CameraHal::switchToOffline");
+ if (!valid() || mHidlSession_3_6 == nullptr) {
+ ALOGE("%s called on invalid camera!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ if (offlineSessionInfo == nullptr || offlineSession == nullptr || bufferRecords == nullptr) {
+ ALOGE("%s: output arguments must not be null!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ common::V1_0::Status status = common::V1_0::Status::INTERNAL_ERROR;
+ auto resultCallback =
+ [&status, &offlineSessionInfo, &offlineSession] (auto s, auto info, auto session) {
+ status = s;
+ *offlineSessionInfo = info;
+ *offlineSession = session;
+ };
+ auto err = mHidlSession_3_6->switchToOffline(streamsToKeep, resultCallback);
+
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+ return DEAD_OBJECT;
+ }
+
+ status_t ret = CameraProviderManager::mapToStatusT(status);
+ if (ret != OK) {
+ return ret;
+ }
+
+ // TODO: assert no ongoing requestBuffer/returnBuffer call here
+ // TODO: update RequestBufferStateMachine to block requestBuffer/returnBuffer once HAL
+ // returns from switchToOffline.
+
+
+ // Validate buffer caches
+ std::vector<int32_t> streams;
+ streams.reserve(offlineSessionInfo->offlineStreams.size());
+ for (auto offlineStream : offlineSessionInfo->offlineStreams) {
+ int32_t id = offlineStream.id;
+ streams.push_back(id);
+ // Verify buffer caches
+ std::vector<uint64_t> bufIds(offlineStream.circulatingBufferIds.begin(),
+ offlineStream.circulatingBufferIds.end());
+ if (!verifyBufferIds(id, bufIds)) {
+ ALOGE("%s: stream ID %d buffer cache records mismatch!", __FUNCTION__, id);
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ // Move buffer records
+ bufferRecords->takeBufferCaches(mBufferRecords, streams);
+ bufferRecords->takeInflightBufferMap(mBufferRecords);
+ bufferRecords->takeRequestedBufferMap(mBufferRecords);
+ return ret;
+}
+
void Camera3Device::HalInterface::getInflightBufferKeys(
std::vector<std::pair<int32_t, int32_t>>* out) {
- std::lock_guard<std::mutex> lock(mInflightLock);
- out->clear();
- out->reserve(mInflightBufferMap.size());
- for (auto& pair : mInflightBufferMap) {
- uint64_t key = pair.first;
- int32_t streamId = key & 0xFFFFFFFF;
- int32_t frameNumber = (key >> 32) & 0xFFFFFFFF;
- out->push_back(std::make_pair(frameNumber, streamId));
- }
+ mBufferRecords.getInflightBufferKeys(out);
return;
}
void Camera3Device::HalInterface::getInflightRequestBufferKeys(
std::vector<uint64_t>* out) {
- std::lock_guard<std::mutex> lock(mRequestedBuffersLock);
- out->clear();
- out->reserve(mRequestedBuffers.size());
- for (auto& pair : mRequestedBuffers) {
- out->push_back(pair.first);
- }
+ mBufferRecords.getInflightRequestBufferKeys(out);
return;
}
-status_t Camera3Device::HalInterface::pushInflightBufferLocked(
- int32_t frameNumber, int32_t streamId, buffer_handle_t *buffer) {
- uint64_t key = static_cast<uint64_t>(frameNumber) << 32 | static_cast<uint64_t>(streamId);
- mInflightBufferMap[key] = buffer;
- return OK;
+bool Camera3Device::HalInterface::verifyBufferIds(
+ int32_t streamId, std::vector<uint64_t>& bufIds) {
+ return mBufferRecords.verifyBufferIds(streamId, bufIds);
}
status_t Camera3Device::HalInterface::popInflightBuffer(
int32_t frameNumber, int32_t streamId,
/*out*/ buffer_handle_t **buffer) {
- std::lock_guard<std::mutex> lock(mInflightLock);
-
- uint64_t key = static_cast<uint64_t>(frameNumber) << 32 | static_cast<uint64_t>(streamId);
- auto it = mInflightBufferMap.find(key);
- if (it == mInflightBufferMap.end()) return NAME_NOT_FOUND;
- if (buffer != nullptr) {
- *buffer = it->second;
- }
- mInflightBufferMap.erase(it);
- return OK;
-}
-
-void Camera3Device::HalInterface::popInflightBuffers(
- const std::vector<std::pair<int32_t, int32_t>>& buffers) {
- for (const auto& pair : buffers) {
- int32_t frameNumber = pair.first;
- int32_t streamId = pair.second;
- popInflightBuffer(frameNumber, streamId, nullptr);
- }
+ return mBufferRecords.popInflightBuffer(frameNumber, streamId, buffer);
}
status_t Camera3Device::HalInterface::pushInflightRequestBuffer(
uint64_t bufferId, buffer_handle_t* buf, int32_t streamId) {
- std::lock_guard<std::mutex> lock(mRequestedBuffersLock);
- auto pair = mRequestedBuffers.insert({bufferId, {streamId, buf}});
- if (!pair.second) {
- ALOGE("%s: bufId %" PRIu64 " is already inflight!",
- __FUNCTION__, bufferId);
- return BAD_VALUE;
- }
- return OK;
+ return mBufferRecords.pushInflightRequestBuffer(bufferId, buf, streamId);
}
// Find and pop a buffer_handle_t based on bufferId
@@ -4803,81 +3685,29 @@
uint64_t bufferId,
/*out*/ buffer_handle_t** buffer,
/*optional out*/ int32_t* streamId) {
- if (buffer == nullptr) {
- ALOGE("%s: buffer (%p) must not be null", __FUNCTION__, buffer);
- return BAD_VALUE;
- }
- std::lock_guard<std::mutex> lock(mRequestedBuffersLock);
- auto it = mRequestedBuffers.find(bufferId);
- if (it == mRequestedBuffers.end()) {
- ALOGE("%s: bufId %" PRIu64 " is not inflight!",
- __FUNCTION__, bufferId);
- return BAD_VALUE;
- }
- *buffer = it->second.second;
- if (streamId != nullptr) {
- *streamId = it->second.first;
- }
- mRequestedBuffers.erase(it);
- return OK;
+ return mBufferRecords.popInflightRequestBuffer(bufferId, buffer, streamId);
}
std::pair<bool, uint64_t> Camera3Device::HalInterface::getBufferId(
const buffer_handle_t& buf, int streamId) {
- std::lock_guard<std::mutex> lock(mBufferIdMapLock);
-
- BufferIdMap& bIdMap = mBufferIdMaps.at(streamId);
- auto it = bIdMap.find(buf);
- if (it == bIdMap.end()) {
- bIdMap[buf] = mNextBufferId++;
- ALOGV("stream %d now have %zu buffer caches, buf %p",
- streamId, bIdMap.size(), buf);
- return std::make_pair(true, mNextBufferId - 1);
- } else {
- return std::make_pair(false, it->second);
- }
+ return mBufferRecords.getBufferId(buf, streamId);
}
void Camera3Device::HalInterface::onBufferFreed(
int streamId, const native_handle_t* handle) {
- std::lock_guard<std::mutex> lock(mBufferIdMapLock);
- uint64_t bufferId = BUFFER_ID_NO_BUFFER;
- auto mapIt = mBufferIdMaps.find(streamId);
- if (mapIt == mBufferIdMaps.end()) {
- // streamId might be from a deleted stream here
- ALOGI("%s: stream %d has been removed",
- __FUNCTION__, streamId);
- return;
+ uint32_t bufferId = mBufferRecords.removeOneBufferCache(streamId, handle);
+ std::lock_guard<std::mutex> lock(mFreedBuffersLock);
+ if (bufferId != BUFFER_ID_NO_BUFFER) {
+ mFreedBuffers.push_back(std::make_pair(streamId, bufferId));
}
- BufferIdMap& bIdMap = mapIt->second;
- auto it = bIdMap.find(handle);
- if (it == bIdMap.end()) {
- ALOGW("%s: cannot find buffer %p in stream %d",
- __FUNCTION__, handle, streamId);
- return;
- } else {
- bufferId = it->second;
- bIdMap.erase(it);
- ALOGV("%s: stream %d now have %zu buffer caches after removing buf %p",
- __FUNCTION__, streamId, bIdMap.size(), handle);
- }
- mFreedBuffers.push_back(std::make_pair(streamId, bufferId));
}
void Camera3Device::HalInterface::onStreamReConfigured(int streamId) {
- std::lock_guard<std::mutex> lock(mBufferIdMapLock);
- auto mapIt = mBufferIdMaps.find(streamId);
- if (mapIt == mBufferIdMaps.end()) {
- ALOGE("%s: streamId %d not found!", __FUNCTION__, streamId);
- return;
- }
-
- BufferIdMap& bIdMap = mapIt->second;
- for (const auto& it : bIdMap) {
- uint64_t bufferId = it.second;
+ std::vector<uint64_t> bufIds = mBufferRecords.clearBufferCaches(streamId);
+ std::lock_guard<std::mutex> lock(mFreedBuffersLock);
+ for (auto bufferId : bufIds) {
mFreedBuffers.push_back(std::make_pair(streamId, bufferId));
}
- bIdMap.clear();
}
/**
@@ -4902,6 +3732,7 @@
mLatestRequestId(NAME_NOT_FOUND),
mCurrentAfTriggerId(0),
mCurrentPreCaptureTriggerId(0),
+ mRotateAndCropOverride(ANDROID_SCALER_ROTATE_AND_CROP_NONE),
mRepeatingLastFrameNumber(
hardware::camera2::ICameraDeviceUser::NO_IN_FLIGHT_REPEATING_FRAMES),
mPrepareVideoStream(false),
@@ -5082,6 +3913,7 @@
ALOGW("%s: %d: couldn't get input buffer while clearing the request "
"list: %s (%d)", __FUNCTION__, __LINE__, strerror(-res), res);
} else {
+ inputBuffer.status = CAMERA3_BUFFER_STATUS_ERROR;
res = (*it)->mInputStream->returnInputBuffer(inputBuffer);
if (res != OK) {
ALOGE("%s: %d: couldn't return input buffer while clearing the request "
@@ -5106,6 +3938,7 @@
*lastFrameNumber = mRepeatingLastFrameNumber;
}
mRepeatingLastFrameNumber = hardware::camera2::ICameraDeviceUser::NO_IN_FLIGHT_REPEATING_FRAMES;
+ mRequestSignal.signal();
return OK;
}
@@ -5371,6 +4204,9 @@
bool Camera3Device::RequestThread::threadLoop() {
ATRACE_CALL();
status_t res;
+ // Any function called from threadLoop() must not hold mInterfaceLock since
+ // it could lead to deadlocks (disconnect() -> hold mInterfaceMutex -> wait for request thread
+ // to finish -> request thread waits on mInterfaceMutex) http://b/143513518
// Handle paused state.
if (waitIfPaused()) {
@@ -5499,6 +4335,7 @@
Mutex::Autolock l(mRequestLock);
mNextRequests.clear();
}
+ mRequestSubmittedSignal.signal();
return submitRequestSuccess;
}
@@ -5529,12 +4366,16 @@
bool triggersMixedIn = (triggerCount > 0 || mPrevTriggers > 0);
mPrevTriggers = triggerCount;
+ bool rotateAndCropChanged = overrideAutoRotateAndCrop(captureRequest);
+
// If the request is the same as last, or we had triggers last time
- bool newRequest = (mPrevRequest != captureRequest || triggersMixedIn) &&
+ bool newRequest =
+ (mPrevRequest != captureRequest || triggersMixedIn || rotateAndCropChanged) &&
// Request settings are all the same within one batch, so only treat the first
// request in a batch as new
!(batchedRequest && i > 0);
if (newRequest) {
+ std::set<std::string> cameraIdsWithZoom;
/**
* HAL workaround:
* Insert a dummy trigger ID if a trigger is set but no trigger ID is
@@ -5567,6 +4408,43 @@
return INVALID_OPERATION;
}
}
+
+ for (it = captureRequest->mSettingsList.begin();
+ it != captureRequest->mSettingsList.end(); it++) {
+ if (parent->mZoomRatioMappers.find(it->cameraId) ==
+ parent->mZoomRatioMappers.end()) {
+ continue;
+ }
+
+ camera_metadata_entry_t e = it->metadata.find(ANDROID_CONTROL_ZOOM_RATIO);
+ if (e.count > 0 && e.data.f[0] != 1.0f) {
+ cameraIdsWithZoom.insert(it->cameraId);
+ }
+
+ res = parent->mZoomRatioMappers[it->cameraId].updateCaptureRequest(
+ &(it->metadata));
+ if (res != OK) {
+ SET_ERR("RequestThread: Unable to correct capture requests "
+ "for zoom ratio for request %d: %s (%d)",
+ halRequest->frame_number, strerror(-res), res);
+ return INVALID_OPERATION;
+ }
+ }
+ if (captureRequest->mRotateAndCropAuto) {
+ for (it = captureRequest->mSettingsList.begin();
+ it != captureRequest->mSettingsList.end(); it++) {
+ auto mapper = parent->mRotateAndCropMappers.find(it->cameraId);
+ if (mapper != parent->mRotateAndCropMappers.end()) {
+ res = mapper->second.updateCaptureRequest(&(it->metadata));
+ if (res != OK) {
+ SET_ERR("RequestThread: Unable to correct capture requests "
+ "for rotate-and-crop for request %d: %s (%d)",
+ halRequest->frame_number, strerror(-res), res);
+ return INVALID_OPERATION;
+ }
+ }
+ }
+ }
}
}
@@ -5577,6 +4455,7 @@
captureRequest->mSettingsList.begin()->metadata.sort();
halRequest->settings = captureRequest->mSettingsList.begin()->metadata.getAndLock();
mPrevRequest = captureRequest;
+ mPrevCameraIdsWithZoom = cameraIdsWithZoom;
ALOGVV("%s: Request settings are NEW", __FUNCTION__);
IF_ALOGV() {
@@ -5765,6 +4644,7 @@
hasCallback,
calculateMaxExpectedDuration(halRequest->settings),
requestedPhysicalCameras, isStillCapture, isZslCapture,
+ captureRequest->mRotateAndCropAuto, mPrevCameraIdsWithZoom,
(mUseHalBufManager) ? uniqueSurfaceIdMap :
SurfaceMap{});
ALOGVV("%s: registered in flight requestId = %" PRId32 ", frameNumber = %" PRId64
@@ -5878,9 +4758,52 @@
mStreamIdsToBeDrained = streamIds;
}
+status_t Camera3Device::RequestThread::switchToOffline(
+ const std::vector<int32_t>& streamsToKeep,
+ /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
+ /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession,
+ /*out*/camera3::BufferRecords* bufferRecords) {
+ Mutex::Autolock l(mRequestLock);
+ clearRepeatingRequestsLocked(/*lastFrameNumber*/nullptr);
+
+ // Wait until request thread is fully stopped
+ // TBD: check if request thread is being paused by other APIs (shouldn't be)
+
+ // We could also check for mRepeatingRequests.empty(), but the API interface
+ // is serialized by Camera3Device::mInterfaceLock so no one should be able to submit any
+ // new requests during the call; hence skip that check.
+ bool queueEmpty = mNextRequests.empty() && mRequestQueue.empty();
+ while (!queueEmpty) {
+ status_t res = mRequestSubmittedSignal.waitRelative(mRequestLock, kRequestSubmitTimeout);
+ if (res == TIMED_OUT) {
+ ALOGE("%s: request thread failed to submit one request within timeout!", __FUNCTION__);
+ return res;
+ } else if (res != OK) {
+ ALOGE("%s: request thread failed to submit a request: %s (%d)!",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+ queueEmpty = mNextRequests.empty() && mRequestQueue.empty();
+ }
+
+ return mInterface->switchToOffline(
+ streamsToKeep, offlineSessionInfo, offlineSession, bufferRecords);
+}
+
+status_t Camera3Device::RequestThread::setRotateAndCropAutoBehavior(
+ camera_metadata_enum_android_scaler_rotate_and_crop_t rotateAndCropValue) {
+ ATRACE_CALL();
+ Mutex::Autolock l(mTriggerMutex);
+ if (rotateAndCropValue == ANDROID_SCALER_ROTATE_AND_CROP_AUTO) {
+ return BAD_VALUE;
+ }
+ mRotateAndCropOverride = rotateAndCropValue;
+ return OK;
+}
+
nsecs_t Camera3Device::getExpectedInFlightDuration() {
ATRACE_CALL();
- Mutex::Autolock al(mInFlightLock);
+ std::lock_guard<std::mutex> l(mInFlightLock);
return mExpectedInflightDuration > kMinInflightDuration ?
mExpectedInflightDuration : kMinInflightDuration;
}
@@ -5966,7 +4889,7 @@
{
sp<Camera3Device> parent = mParent.promote();
if (parent != NULL) {
- Mutex::Autolock l(parent->mInFlightLock);
+ std::lock_guard<std::mutex> l(parent->mInFlightLock);
ssize_t idx = parent->mInFlightMap.indexOfKey(captureRequest->mResultExtras.frameNumber);
if (idx >= 0) {
ALOGV("%s: Remove inflight request from queue: frameNumber %" PRId64,
@@ -6393,6 +5316,32 @@
return OK;
}
+bool Camera3Device::RequestThread::overrideAutoRotateAndCrop(
+ const sp<CaptureRequest> &request) {
+ ATRACE_CALL();
+
+ if (request->mRotateAndCropAuto) {
+ Mutex::Autolock l(mTriggerMutex);
+ CameraMetadata &metadata = request->mSettingsList.begin()->metadata;
+
+ auto rotateAndCropEntry = metadata.find(ANDROID_SCALER_ROTATE_AND_CROP);
+ if (rotateAndCropEntry.count > 0) {
+ if (rotateAndCropEntry.data.u8[0] == mRotateAndCropOverride) {
+ return false;
+ } else {
+ rotateAndCropEntry.data.u8[0] = mRotateAndCropOverride;
+ return true;
+ }
+ } else {
+ uint8_t rotateAndCrop_u8 = mRotateAndCropOverride;
+ metadata.update(ANDROID_SCALER_ROTATE_AND_CROP,
+ &rotateAndCrop_u8, 1);
+ return true;
+ }
+ }
+ return false;
+}
+
/**
* PreparerThread inner class methods
*/
@@ -6655,6 +5604,7 @@
void Camera3Device::RequestBufferStateMachine::onStreamsConfigured() {
std::lock_guard<std::mutex> lock(mLock);
+ mSwitchedToOffline = false;
mStatus = RB_STATUS_READY;
return;
}
@@ -6697,6 +5647,20 @@
return;
}
+bool Camera3Device::RequestBufferStateMachine::onSwitchToOfflineSuccess() {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mRequestBufferOngoing) {
+ ALOGE("%s: HAL must not be requesting buffer after HAL returns switchToOffline!",
+ __FUNCTION__);
+ return false;
+ }
+ mSwitchedToOffline = true;
+ mInflightMapEmpty = true;
+ mRequestThreadPaused = true;
+ mStatus = RB_STATUS_STOPPED;
+ return true;
+}
+
void Camera3Device::RequestBufferStateMachine::notifyTrackerLocked(bool active) {
sp<StatusTracker> statusTracker = mStatusTracker.promote();
if (statusTracker != nullptr) {
@@ -6716,75 +5680,288 @@
return false;
}
-status_t Camera3Device::fixupMonochromeTags(const CameraMetadata& deviceInfo,
- CameraMetadata& resultMetadata) {
- status_t res = OK;
- if (!mNeedFixupMonochromeTags) {
- return res;
+bool Camera3Device::startRequestBuffer() {
+ return mRequestBufferSM.startRequestBuffer();
+}
+
+void Camera3Device::endRequestBuffer() {
+ mRequestBufferSM.endRequestBuffer();
+}
+
+nsecs_t Camera3Device::getWaitDuration() {
+ return kBaseGetBufferWait + getExpectedInFlightDuration();
+}
+
+void Camera3Device::getInflightBufferKeys(std::vector<std::pair<int32_t, int32_t>>* out) {
+ mInterface->getInflightBufferKeys(out);
+}
+
+void Camera3Device::getInflightRequestBufferKeys(std::vector<uint64_t>* out) {
+ mInterface->getInflightRequestBufferKeys(out);
+}
+
+std::vector<sp<Camera3StreamInterface>> Camera3Device::getAllStreams() {
+ std::vector<sp<Camera3StreamInterface>> ret;
+ bool hasInputStream = mInputStream != nullptr;
+ ret.reserve(mOutputStreams.size() + mDeletedStreams.size() + ((hasInputStream) ? 1 : 0));
+ if (hasInputStream) {
+ ret.push_back(mInputStream);
+ }
+ for (size_t i = 0; i < mOutputStreams.size(); i++) {
+ ret.push_back(mOutputStreams[i]);
+ }
+ for (size_t i = 0; i < mDeletedStreams.size(); i++) {
+ ret.push_back(mDeletedStreams[i]);
+ }
+ return ret;
+}
+
+status_t Camera3Device::switchToOffline(
+ const std::vector<int32_t>& streamsToKeep,
+ /*out*/ sp<CameraOfflineSessionBase>* session) {
+ ATRACE_CALL();
+ if (session == nullptr) {
+ ALOGE("%s: session must not be null", __FUNCTION__);
+ return BAD_VALUE;
}
- // Remove tags that are not applicable to monochrome camera.
- int32_t tagsToRemove[] = {
- ANDROID_SENSOR_GREEN_SPLIT,
- ANDROID_SENSOR_NEUTRAL_COLOR_POINT,
- ANDROID_COLOR_CORRECTION_MODE,
- ANDROID_COLOR_CORRECTION_TRANSFORM,
- ANDROID_COLOR_CORRECTION_GAINS,
- };
- for (auto tag : tagsToRemove) {
- res = resultMetadata.erase(tag);
- if (res != OK) {
- ALOGE("%s: Failed to remove tag %d for monochrome camera", __FUNCTION__, tag);
- return res;
+ Mutex::Autolock il(mInterfaceLock);
+
+ bool hasInputStream = mInputStream != nullptr;
+ int32_t inputStreamId = hasInputStream ? mInputStream->getId() : -1;
+ bool inputStreamSupportsOffline = hasInputStream ?
+ mInputStream->getOfflineProcessingSupport() : false;
+ auto outputStreamIds = mOutputStreams.getStreamIds();
+ auto streamIds = outputStreamIds;
+ if (hasInputStream) {
+ streamIds.push_back(mInputStream->getId());
+ }
+
+ // Check all streams in streamsToKeep supports offline mode
+ for (auto id : streamsToKeep) {
+ if (std::find(streamIds.begin(), streamIds.end(), id) == streamIds.end()) {
+ ALOGE("%s: Unknown stream ID %d", __FUNCTION__, id);
+ return BAD_VALUE;
+ } else if (id == inputStreamId) {
+ if (!inputStreamSupportsOffline) {
+ ALOGE("%s: input stream %d cannot be switched to offline",
+ __FUNCTION__, id);
+ return BAD_VALUE;
+ }
+ } else {
+ sp<camera3::Camera3OutputStreamInterface> stream = mOutputStreams.get(id);
+ if (!stream->getOfflineProcessingSupport()) {
+ ALOGE("%s: output stream %d cannot be switched to offline",
+ __FUNCTION__, id);
+ return BAD_VALUE;
+ }
}
}
- // ANDROID_SENSOR_DYNAMIC_BLACK_LEVEL
- camera_metadata_entry blEntry = resultMetadata.find(ANDROID_SENSOR_DYNAMIC_BLACK_LEVEL);
- for (size_t i = 1; i < blEntry.count; i++) {
- blEntry.data.f[i] = blEntry.data.f[0];
+ // TODO: block surface sharing and surface group streams until we can support them
+
+ // Stop repeating request, wait until all remaining requests are submitted, then call into
+ // HAL switchToOffline
+ hardware::camera::device::V3_6::CameraOfflineSessionInfo offlineSessionInfo;
+ sp<hardware::camera::device::V3_6::ICameraOfflineSession> offlineSession;
+ camera3::BufferRecords bufferRecords;
+ status_t ret = mRequestThread->switchToOffline(
+ streamsToKeep, &offlineSessionInfo, &offlineSession, &bufferRecords);
+
+ if (ret != OK) {
+ SET_ERR("Switch to offline failed: %s (%d)", strerror(-ret), ret);
+ return ret;
}
- // ANDROID_SENSOR_NOISE_PROFILE
- camera_metadata_entry npEntry = resultMetadata.find(ANDROID_SENSOR_NOISE_PROFILE);
- if (npEntry.count > 0 && npEntry.count % 2 == 0) {
- double np[] = {npEntry.data.d[0], npEntry.data.d[1]};
- res = resultMetadata.update(ANDROID_SENSOR_NOISE_PROFILE, np, 2);
- if (res != OK) {
- ALOGE("%s: Failed to update SENSOR_NOISE_PROFILE: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return res;
+ bool succ = mRequestBufferSM.onSwitchToOfflineSuccess();
+ if (!succ) {
+ SET_ERR("HAL must not be calling requestStreamBuffers call");
+ // TODO: block ALL callbacks from HAL till app configured new streams?
+ return UNKNOWN_ERROR;
+ }
+
+ // Verify offlineSessionInfo
+ std::vector<int32_t> offlineStreamIds;
+ offlineStreamIds.reserve(offlineSessionInfo.offlineStreams.size());
+ for (auto offlineStream : offlineSessionInfo.offlineStreams) {
+ // verify stream IDs
+ int32_t id = offlineStream.id;
+ if (std::find(streamIds.begin(), streamIds.end(), id) == streamIds.end()) {
+ SET_ERR("stream ID %d not found!", id);
+ return UNKNOWN_ERROR;
+ }
+
+ // When not using HAL buf manager, only allow streams requested by app to be preserved
+ if (!mUseHalBufManager) {
+ if (std::find(streamsToKeep.begin(), streamsToKeep.end(), id) == streamsToKeep.end()) {
+ SET_ERR("stream ID %d must not be switched to offline!", id);
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ offlineStreamIds.push_back(id);
+ sp<Camera3StreamInterface> stream = (id == inputStreamId) ?
+ static_cast<sp<Camera3StreamInterface>>(mInputStream) :
+ static_cast<sp<Camera3StreamInterface>>(mOutputStreams.get(id));
+ // Verify number of outstanding buffers
+ if (stream->getOutstandingBuffersCount() != offlineStream.numOutstandingBuffers) {
+ SET_ERR("Offline stream %d # of remaining buffer mismatch: (%zu,%d) (service/HAL)",
+ id, stream->getOutstandingBuffersCount(), offlineStream.numOutstandingBuffers);
+ return UNKNOWN_ERROR;
}
}
- // ANDROID_STATISTICS_LENS_SHADING_MAP
- camera_metadata_ro_entry lsSizeEntry = deviceInfo.find(ANDROID_LENS_INFO_SHADING_MAP_SIZE);
- camera_metadata_entry lsEntry = resultMetadata.find(ANDROID_STATISTICS_LENS_SHADING_MAP);
- if (lsSizeEntry.count == 2 && lsEntry.count > 0
- && (int32_t)lsEntry.count == 4 * lsSizeEntry.data.i32[0] * lsSizeEntry.data.i32[1]) {
- for (int32_t i = 0; i < lsSizeEntry.data.i32[0] * lsSizeEntry.data.i32[1]; i++) {
- lsEntry.data.f[4*i+1] = lsEntry.data.f[4*i];
- lsEntry.data.f[4*i+2] = lsEntry.data.f[4*i];
- lsEntry.data.f[4*i+3] = lsEntry.data.f[4*i];
+ // Verify all streams to be deleted don't have any outstanding buffers
+ if (hasInputStream && std::find(offlineStreamIds.begin(), offlineStreamIds.end(),
+ inputStreamId) == offlineStreamIds.end()) {
+ if (mInputStream->hasOutstandingBuffers()) {
+ SET_ERR("Input stream %d still has %zu outstanding buffer!",
+ inputStreamId, mInputStream->getOutstandingBuffersCount());
+ return UNKNOWN_ERROR;
}
}
- // ANDROID_TONEMAP_CURVE_BLUE
- // ANDROID_TONEMAP_CURVE_GREEN
- // ANDROID_TONEMAP_CURVE_RED
- camera_metadata_entry tcbEntry = resultMetadata.find(ANDROID_TONEMAP_CURVE_BLUE);
- camera_metadata_entry tcgEntry = resultMetadata.find(ANDROID_TONEMAP_CURVE_GREEN);
- camera_metadata_entry tcrEntry = resultMetadata.find(ANDROID_TONEMAP_CURVE_RED);
- if (tcbEntry.count > 0
- && tcbEntry.count == tcgEntry.count
- && tcbEntry.count == tcrEntry.count) {
- for (size_t i = 0; i < tcbEntry.count; i++) {
- tcbEntry.data.f[i] = tcrEntry.data.f[i];
- tcgEntry.data.f[i] = tcrEntry.data.f[i];
+ for (const auto& outStreamId : outputStreamIds) {
+ if (std::find(offlineStreamIds.begin(), offlineStreamIds.end(),
+ outStreamId) == offlineStreamIds.end()) {
+ auto outStream = mOutputStreams.get(outStreamId);
+ if (outStream->hasOutstandingBuffers()) {
+ SET_ERR("Output stream %d still has %zu outstanding buffer!",
+ outStreamId, outStream->getOutstandingBuffersCount());
+ return UNKNOWN_ERROR;
+ }
}
}
- return res;
+ InFlightRequestMap offlineReqs;
+ // Verify inflight requests and their pending buffers
+ {
+ std::lock_guard<std::mutex> l(mInFlightLock);
+ for (auto offlineReq : offlineSessionInfo.offlineRequests) {
+ int idx = mInFlightMap.indexOfKey(offlineReq.frameNumber);
+ if (idx == NAME_NOT_FOUND) {
+ SET_ERR("Offline request frame number %d not found!", offlineReq.frameNumber);
+ return UNKNOWN_ERROR;
+ }
+
+ const auto& inflightReq = mInFlightMap.valueAt(idx);
+ // TODO: check specific stream IDs
+ size_t numBuffersLeft = static_cast<size_t>(inflightReq.numBuffersLeft);
+ if (numBuffersLeft != offlineReq.pendingStreams.size()) {
+ SET_ERR("Offline request # of remaining buffer mismatch: (%d,%d) (service/HAL)",
+ inflightReq.numBuffersLeft, offlineReq.pendingStreams.size());
+ return UNKNOWN_ERROR;
+ }
+ offlineReqs.add(offlineReq.frameNumber, inflightReq);
+ }
+ }
+
+ // Create Camera3OfflineSession and transfer object ownership
+ // (streams, inflight requests, buffer caches)
+ camera3::StreamSet offlineStreamSet;
+ sp<camera3::Camera3Stream> inputStream;
+ for (auto offlineStream : offlineSessionInfo.offlineStreams) {
+ int32_t id = offlineStream.id;
+ if (mInputStream != nullptr && id == mInputStream->getId()) {
+ inputStream = mInputStream;
+ } else {
+ offlineStreamSet.add(id, mOutputStreams.get(id));
+ }
+ }
+
+ // TODO: check if we need to lock before copying states
+ // though technically no other thread should be talking to Camera3Device at this point
+ Camera3OfflineStates offlineStates(
+ mTagMonitor, mVendorTagId, mUseHalBufManager, mNeedFixupMonochromeTags,
+ mUsePartialResult, mNumPartialResults, mNextResultFrameNumber,
+ mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+ mNextShutterFrameNumber, mNextReprocessShutterFrameNumber,
+ mNextZslStillShutterFrameNumber, mDeviceInfo, mPhysicalDeviceInfoMap,
+ mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers);
+
+ *session = new Camera3OfflineSession(mId, inputStream, offlineStreamSet,
+ std::move(bufferRecords), offlineReqs, offlineStates, offlineSession);
+
+ // Delete all streams that has been transferred to offline session
+ Mutex::Autolock l(mLock);
+ for (auto offlineStream : offlineSessionInfo.offlineStreams) {
+ int32_t id = offlineStream.id;
+ if (mInputStream != nullptr && id == mInputStream->getId()) {
+ mInputStream.clear();
+ } else {
+ mOutputStreams.remove(id);
+ }
+ }
+
+ // disconnect all other streams and switch to UNCONFIGURED state
+ if (mInputStream != nullptr) {
+ ret = mInputStream->disconnect();
+ if (ret != OK) {
+ SET_ERR_L("disconnect input stream failed!");
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ for (auto streamId : mOutputStreams.getStreamIds()) {
+ sp<Camera3StreamInterface> stream = mOutputStreams.get(streamId);
+ ret = stream->disconnect();
+ if (ret != OK) {
+ SET_ERR_L("disconnect output stream %d failed!", streamId);
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ mInputStream.clear();
+ mOutputStreams.clear();
+ mNeedConfig = true;
+ internalUpdateStatusLocked(STATUS_UNCONFIGURED);
+ mOperatingMode = NO_MODE;
+ mIsConstrainedHighSpeedConfiguration = false;
+
+ return OK;
+ // TO be done by CameraDeviceClient/Camera3OfflineSession
+ // register the offline client to camera service
+ // Setup result passthing threads etc
+ // Initialize offline session so HAL can start sending callback to it (result Fmq)
+ // TODO: check how many onIdle callback will be sent
+ // Java side to make sure the CameraCaptureSession is properly closed
+}
+
+void Camera3Device::getOfflineStreamIds(std::vector<int> *offlineStreamIds) {
+ ATRACE_CALL();
+
+ if (offlineStreamIds == nullptr) {
+ return;
+ }
+
+ Mutex::Autolock il(mInterfaceLock);
+
+ auto streamIds = mOutputStreams.getStreamIds();
+ bool hasInputStream = mInputStream != nullptr;
+ if (hasInputStream && mInputStream->getOfflineProcessingSupport()) {
+ offlineStreamIds->push_back(mInputStream->getId());
+ }
+
+ for (const auto & streamId : streamIds) {
+ sp<camera3::Camera3OutputStreamInterface> stream = mOutputStreams.get(streamId);
+ // Streams that use the camera buffer manager are currently not supported in
+ // offline mode
+ if (stream->getOfflineProcessingSupport() &&
+ (stream->getStreamSetId() == CAMERA3_STREAM_SET_ID_INVALID)) {
+ offlineStreamIds->push_back(streamId);
+ }
+ }
+}
+
+status_t Camera3Device::setRotateAndCropAutoBehavior(
+ camera_metadata_enum_android_scaler_rotate_and_crop_t rotateAndCropValue) {
+ ATRACE_CALL();
+ Mutex::Autolock il(mInterfaceLock);
+ Mutex::Autolock l(mLock);
+ if (mRequestThread == nullptr) {
+ return INVALID_OPERATION;
+ }
+ return mRequestThread->setRotateAndCropAutoBehavior(rotateAndCropValue);
}
}; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index cae34ce..0069fb3 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -34,6 +34,7 @@
#include <android/hardware/camera/device/3.3/ICameraDeviceSession.h>
#include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
#include <android/hardware/camera/device/3.5/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.6/ICameraDeviceSession.h>
#include <android/hardware/camera/device/3.2/ICameraDeviceCallback.h>
#include <android/hardware/camera/device/3.4/ICameraDeviceCallback.h>
#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
@@ -42,9 +43,15 @@
#include <camera/CaptureResult.h>
#include "common/CameraDeviceBase.h"
+#include "device3/BufferUtils.h"
#include "device3/StatusTracker.h"
#include "device3/Camera3BufferManager.h"
#include "device3/DistortionMapper.h"
+#include "device3/ZoomRatioMapper.h"
+#include "device3/RotateAndCropMapper.h"
+#include "device3/InFlightRequest.h"
+#include "device3/Camera3OutputInterface.h"
+#include "device3/Camera3OfflineSession.h"
#include "utils/TagMonitor.h"
#include "utils/LatencyHistogram.h"
#include <camera_metadata_hidden.h>
@@ -67,7 +74,11 @@
*/
class Camera3Device :
public CameraDeviceBase,
- virtual public hardware::camera::device::V3_5::ICameraDeviceCallback {
+ virtual public hardware::camera::device::V3_5::ICameraDeviceCallback,
+ public camera3::SetErrorInterface,
+ public camera3::InflightRequestUpdateInterface,
+ public camera3::RequestBufferInterface,
+ public camera3::FlushBufferInterface {
public:
explicit Camera3Device(const String8& id);
@@ -87,7 +98,7 @@
status_t disconnect() override;
status_t dump(int fd, const Vector<String16> &args) override;
const CameraMetadata& info() const override;
- const CameraMetadata& info(const String8& physicalId) const override;
+ const CameraMetadata& infoPhysical(const String8& physicalId) const override;
// Capture and setStreamingRequest will configure streams if currently in
// idle state
@@ -140,6 +151,8 @@
status_t getInputBufferProducer(
sp<IGraphicBufferProducer> *producer) override;
+ void getOfflineStreamIds(std::vector<int> *offlineStreamIds) override;
+
status_t createDefaultRequest(int templateId, CameraMetadata *request) override;
// Transitions to the idle state on success
@@ -194,6 +207,30 @@
*/
status_t dropStreamBuffers(bool dropping, int streamId) override;
+ nsecs_t getExpectedInFlightDuration() override;
+
+ status_t switchToOffline(const std::vector<int32_t>& streamsToKeep,
+ /*out*/ sp<CameraOfflineSessionBase>* session) override;
+
+ // RequestBufferInterface
+ bool startRequestBuffer() override;
+ void endRequestBuffer() override;
+ nsecs_t getWaitDuration() override;
+
+ // FlushBufferInterface
+ void getInflightBufferKeys(std::vector<std::pair<int32_t, int32_t>>* out) override;
+ void getInflightRequestBufferKeys(std::vector<uint64_t>* out) override;
+ std::vector<sp<camera3::Camera3StreamInterface>> getAllStreams() override;
+
+ /**
+ * Set the current behavior for the ROTATE_AND_CROP control when in AUTO.
+ *
+ * The value must be one of the ROTATE_AND_CROP_* values besides AUTO,
+ * and defaults to NONE.
+ */
+ status_t setRotateAndCropAutoBehavior(
+ camera_metadata_enum_android_scaler_rotate_and_crop_t rotateAndCropValue);
+
/**
* Helper functions to map between framework and HIDL values
*/
@@ -206,8 +243,6 @@
// Returns a negative error code if the passed-in operation mode is not valid.
static status_t mapToStreamConfigurationMode(camera3_stream_configuration_mode_t operationMode,
/*out*/ hardware::camera::device::V3_2::StreamConfigurationMode *mode);
- static camera3_buffer_status_t mapHidlBufferStatus(
- hardware::camera::device::V3_2::BufferStatus status);
static int mapToFrameworkFormat(hardware::graphics::common::V1_0::PixelFormat pixelFormat);
static android_dataspace mapToFrameworkDataspace(
hardware::camera::device::V3_2::DataspaceFlags);
@@ -222,7 +257,6 @@
// internal typedefs
using RequestMetadataQueue = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>;
- using ResultMetadataQueue = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>;
static const size_t kDumpLockAttempts = 10;
static const size_t kDumpSleepDuration = 100000; // 0.10 sec
@@ -244,7 +278,6 @@
// A lock to enforce serialization on the input/configure side
// of the public interface.
- // Only locked by public methods inherited from CameraDeviceBase.
// Not locked by methods guarded by mOutputLock, since they may act
// concurrently to the input/configure side of the interface.
// Must be locked before mLock if both will be locked by a method
@@ -276,11 +309,12 @@
* Adapter for legacy HAL / HIDL HAL interface calls; calls either into legacy HALv3 or the
* HIDL HALv3 interfaces.
*/
- class HalInterface : public camera3::Camera3StreamBufferFreedListener {
+ class HalInterface : public camera3::Camera3StreamBufferFreedListener,
+ public camera3::BufferRecordsInterface {
public:
HalInterface(sp<hardware::camera::device::V3_2::ICameraDeviceSession> &session,
std::shared_ptr<RequestMetadataQueue> queue,
- bool useHalBufManager);
+ bool useHalBufManager, bool supportOfflineProcessing);
HalInterface(const HalInterface &other);
HalInterface();
@@ -314,22 +348,31 @@
bool isReconfigurationRequired(CameraMetadata& oldSessionParams,
CameraMetadata& newSessionParams);
- // method to extract buffer's unique ID
- // return pair of (newlySeenBuffer?, bufferId)
- std::pair<bool, uint64_t> getBufferId(const buffer_handle_t& buf, int streamId);
+ // Upon successful return, HalInterface will return buffer maps needed for offline
+ // processing, and clear all its internal buffer maps.
+ status_t switchToOffline(
+ const std::vector<int32_t>& streamsToKeep,
+ /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
+ /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession,
+ /*out*/camera3::BufferRecords* bufferRecords);
- // Find a buffer_handle_t based on frame number and stream ID
+ /////////////////////////////////////////////////////////////////////
+ // Implements BufferRecordsInterface
+
+ std::pair<bool, uint64_t> getBufferId(
+ const buffer_handle_t& buf, int streamId) override;
+
status_t popInflightBuffer(int32_t frameNumber, int32_t streamId,
- /*out*/ buffer_handle_t **buffer);
+ /*out*/ buffer_handle_t **buffer) override;
- // Register a bufId (streamId, buffer_handle_t) to inflight request buffer
status_t pushInflightRequestBuffer(
- uint64_t bufferId, buffer_handle_t* buf, int32_t streamId);
+ uint64_t bufferId, buffer_handle_t* buf, int32_t streamId) override;
- // Find a buffer_handle_t based on bufferId
status_t popInflightRequestBuffer(uint64_t bufferId,
/*out*/ buffer_handle_t** buffer,
- /*optional out*/ int32_t* streamId = nullptr);
+ /*optional out*/ int32_t* streamId = nullptr) override;
+
+ /////////////////////////////////////////////////////////////////////
// Get a vector of (frameNumber, streamId) pair of currently inflight
// buffers
@@ -340,7 +383,6 @@
void onStreamReConfigured(int streamId);
- static const uint64_t BUFFER_ID_NO_BUFFER = 0;
private:
// Always valid
sp<hardware::camera::device::V3_2::ICameraDeviceSession> mHidlSession;
@@ -350,11 +392,11 @@
sp<hardware::camera::device::V3_4::ICameraDeviceSession> mHidlSession_3_4;
// Valid if ICameraDeviceSession is @3.5 or newer
sp<hardware::camera::device::V3_5::ICameraDeviceSession> mHidlSession_3_5;
+ // Valid if ICameraDeviceSession is @3.6 or newer
+ sp<hardware::camera::device::V3_6::ICameraDeviceSession> mHidlSession_3_6;
std::shared_ptr<RequestMetadataQueue> mRequestMetadataQueue;
- std::mutex mInflightLock;
-
// The output HIDL request still depends on input camera3_capture_request_t
// Do not free input camera3_capture_request_t before output HIDL request
status_t wrapAsHidlRequest(camera3_capture_request_t* in,
@@ -368,65 +410,33 @@
// Pop inflight buffers based on pairs of (frameNumber,streamId)
void popInflightBuffers(const std::vector<std::pair<int32_t, int32_t>>& buffers);
- // Cache of buffer handles keyed off (frameNumber << 32 | streamId)
- std::unordered_map<uint64_t, buffer_handle_t*> mInflightBufferMap;
+ // Return true if the input caches match what we have; otherwise false
+ bool verifyBufferIds(int32_t streamId, std::vector<uint64_t>& inBufIds);
// Delete and optionally close native handles and clear the input vector afterward
static void cleanupNativeHandles(
std::vector<native_handle_t*> *handles, bool closeFd = false);
- struct BufferHasher {
- size_t operator()(const buffer_handle_t& buf) const {
- if (buf == nullptr)
- return 0;
-
- size_t result = 1;
- result = 31 * result + buf->numFds;
- for (int i = 0; i < buf->numFds; i++) {
- result = 31 * result + buf->data[i];
- }
- return result;
- }
- };
-
- struct BufferComparator {
- bool operator()(const buffer_handle_t& buf1, const buffer_handle_t& buf2) const {
- if (buf1->numFds == buf2->numFds) {
- for (int i = 0; i < buf1->numFds; i++) {
- if (buf1->data[i] != buf2->data[i]) {
- return false;
- }
- }
- return true;
- }
- return false;
- }
- };
-
- std::mutex mBufferIdMapLock; // protecting mBufferIdMaps and mNextBufferId
- typedef std::unordered_map<const buffer_handle_t, uint64_t,
- BufferHasher, BufferComparator> BufferIdMap;
- // stream ID -> per stream buffer ID map
- std::unordered_map<int, BufferIdMap> mBufferIdMaps;
- uint64_t mNextBufferId = 1; // 0 means no buffer
-
virtual void onBufferFreed(int streamId, const native_handle_t* handle) override;
+ std::mutex mFreedBuffersLock;
std::vector<std::pair<int, uint64_t>> mFreedBuffers;
- // Buffers given to HAL through requestStreamBuffer API
- std::mutex mRequestedBuffersLock;
- std::unordered_map<uint64_t, std::pair<int32_t, buffer_handle_t*>> mRequestedBuffers;
+ // Keep track of buffer cache and inflight buffer records
+ camera3::BufferRecords mBufferRecords;
uint32_t mNextStreamConfigCounter = 1;
const bool mUseHalBufManager;
bool mIsReconfigurationQuerySupported;
+
+ const bool mSupportOfflineProcessing;
};
sp<HalInterface> mInterface;
CameraMetadata mDeviceInfo;
+ bool mSupportNativeZoomRatio;
std::unordered_map<std::string, CameraMetadata> mPhysicalDeviceInfoMap;
CameraMetadata mRequestTemplateCache[CAMERA3_TEMPLATE_COUNT];
@@ -456,24 +466,7 @@
// Tracking cause of fatal errors when in STATUS_ERROR
String8 mErrorCause;
- // Synchronized mapping of stream IDs to stream instances
- class StreamSet {
- public:
- status_t add(int streamId, sp<camera3::Camera3OutputStreamInterface>);
- ssize_t remove(int streamId);
- sp<camera3::Camera3OutputStreamInterface> get(int streamId);
- // get by (underlying) vector index
- sp<camera3::Camera3OutputStreamInterface> operator[] (size_t index);
- size_t size() const;
- std::vector<int> getStreamIds();
- void clear();
-
- private:
- mutable std::mutex mLock;
- KeyedVector<int, sp<camera3::Camera3OutputStreamInterface>> mData;
- };
-
- StreamSet mOutputStreams;
+ camera3::StreamSet mOutputStreams;
sp<camera3::Camera3Stream> mInputStream;
int mNextStreamId;
bool mNeedConfig;
@@ -517,6 +510,10 @@
int mBatchSize;
// Whether this request is from a repeating or repeating burst.
bool mRepeating;
+ // Whether this request has ROTATE_AND_CROP_AUTO set, so needs both
+ // overriding of ROTATE_AND_CROP value and adjustment of coordinates
+ // in several other controls in both the request and the result
+ bool mRotateAndCropAuto;
};
typedef List<sp<CaptureRequest> > RequestList;
@@ -562,15 +559,6 @@
const hardware::hidl_vec<
hardware::camera::device::V3_2::StreamBuffer>& buffers) override;
- // Handle one capture result. Assume that mProcessCaptureResultLock is held.
- void processOneCaptureResultLocked(
- const hardware::camera::device::V3_2::CaptureResult& result,
- const hardware::hidl_vec<
- hardware::camera::device::V3_4::PhysicalCameraMetadata> physicalCameraMetadata);
- status_t readOneCameraMetadataLocked(uint64_t fmqResultSize,
- hardware::camera::device::V3_2::CameraMetadata& resultMetadata,
- const hardware::camera::device::V3_2::CameraMetadata& result);
-
// Handle one notify message
void notify(const hardware::camera::device::V3_2::NotifyMsg& msg);
@@ -693,11 +681,20 @@
* error message to indicate why. Only the first call's message will be
* used. The message is also sent to the log.
*/
- void setErrorState(const char *fmt, ...);
+ void setErrorState(const char *fmt, ...) override;
+ void setErrorStateLocked(const char *fmt, ...) override;
void setErrorStateV(const char *fmt, va_list args);
- void setErrorStateLocked(const char *fmt, ...);
void setErrorStateLockedV(const char *fmt, va_list args);
+ /////////////////////////////////////////////////////////////////////
+ // Implements InflightRequestUpdateInterface
+
+ void onInflightEntryRemovedLocked(nsecs_t duration) override;
+ void checkInflightMapLengthLocked() override;
+ void onInflightMapFlushedLocked() override;
+
+ /////////////////////////////////////////////////////////////////////
+
/**
* Debugging trylock/spin method
* Try to acquire a lock a few times with sleeps between before giving up.
@@ -705,12 +702,6 @@
bool tryLockSpinRightRound(Mutex& lock);
/**
- * Helper function to determine if an input size for implementation defined
- * format is supported.
- */
- bool isOpaqueInputSizeSupported(uint32_t width, uint32_t height);
-
- /**
* Helper function to get the largest Jpeg resolution (in area)
* Return Size(0, 0) if static metatdata is invalid
*/
@@ -840,6 +831,15 @@
void signalPipelineDrain(const std::vector<int>& streamIds);
+ status_t switchToOffline(
+ const std::vector<int32_t>& streamsToKeep,
+ /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
+ /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession,
+ /*out*/camera3::BufferRecords* bufferRecords);
+
+ status_t setRotateAndCropAutoBehavior(
+ camera_metadata_enum_android_scaler_rotate_and_crop_t rotateAndCropValue);
+
protected:
virtual bool threadLoop();
@@ -856,10 +856,16 @@
// HAL workaround: Make sure a trigger ID always exists if
// a trigger does
- status_t addDummyTriggerIds(const sp<CaptureRequest> &request);
+ status_t addDummyTriggerIds(const sp<CaptureRequest> &request);
+
+ // Override rotate_and_crop control if needed; returns true if the current value was changed
+ bool overrideAutoRotateAndCrop(const sp<CaptureRequest> &request);
static const nsecs_t kRequestTimeout = 50e6; // 50 ms
+ // TODO: does this need to be adjusted for long exposure requests?
+ static const nsecs_t kRequestSubmitTimeout = 200e6; // 200 ms
+
// Used to prepare a batch of requests.
struct NextRequest {
sp<CaptureRequest> captureRequest;
@@ -934,6 +940,7 @@
Mutex mRequestLock;
Condition mRequestSignal;
+ Condition mRequestSubmittedSignal;
RequestList mRequestQueue;
RequestList mRepeatingRequests;
// The next batch of requests being prepped for submission to the HAL, no longer
@@ -956,6 +963,7 @@
sp<CaptureRequest> mPrevRequest;
int32_t mPrevTriggers;
+ std::set<std::string> mPrevCameraIdsWithZoom;
uint32_t mFrameNumber;
@@ -973,6 +981,7 @@
TriggerMap mTriggerReplacedMap;
uint32_t mCurrentAfTriggerId;
uint32_t mCurrentPreCaptureTriggerId;
+ camera_metadata_enum_android_scaler_rotate_and_crop_t mRotateAndCropOverride;
int64_t mRepeatingLastFrameNumber;
@@ -994,127 +1003,18 @@
/**
* In-flight queue for tracking completion of capture requests.
*/
+ std::mutex mInFlightLock;
+ camera3::InFlightRequestMap mInFlightMap;
+ nsecs_t mExpectedInflightDuration = 0;
+ // End of mInFlightLock protection scope
- struct InFlightRequest {
- // Set by notify() SHUTTER call.
- nsecs_t shutterTimestamp;
- // Set by process_capture_result().
- nsecs_t sensorTimestamp;
- int requestStatus;
- // Set by process_capture_result call with valid metadata
- bool haveResultMetadata;
- // Decremented by calls to process_capture_result with valid output
- // and input buffers
- int numBuffersLeft;
- CaptureResultExtras resultExtras;
- // If this request has any input buffer
- bool hasInputBuffer;
-
- // The last metadata that framework receives from HAL and
- // not yet send out because the shutter event hasn't arrived.
- // It's added by process_capture_result and sent when framework
- // receives the shutter event.
- CameraMetadata pendingMetadata;
-
- // The metadata of the partial results that framework receives from HAL so far
- // and has sent out.
- CameraMetadata collectedPartialResult;
-
- // Buffers are added by process_capture_result when output buffers
- // return from HAL but framework has not yet received the shutter
- // event. They will be returned to the streams when framework receives
- // the shutter event.
- Vector<camera3_stream_buffer_t> pendingOutputBuffers;
-
- // Whether this inflight request's shutter and result callback are to be
- // called. The policy is that if the request is the last one in the constrained
- // high speed recording request list, this flag will be true. If the request list
- // is not for constrained high speed recording, this flag will also be true.
- bool hasCallback;
-
- // Maximum expected frame duration for this request.
- // For manual captures, equal to the max of requested exposure time and frame duration
- // For auto-exposure modes, equal to 1/(lower end of target FPS range)
- nsecs_t maxExpectedDuration;
-
- // Whether the result metadata for this request is to be skipped. The
- // result metadata should be skipped in the case of
- // REQUEST/RESULT error.
- bool skipResultMetadata;
-
- // The physical camera ids being requested.
- std::set<String8> physicalCameraIds;
-
- // Map of physicalCameraId <-> Metadata
- std::vector<PhysicalCaptureResultInfo> physicalMetadatas;
-
- // Indicates a still capture request.
- bool stillCapture;
-
- // Indicates a ZSL capture request
- bool zslCapture;
-
- // What shared surfaces an output should go to
- SurfaceMap outputSurfaces;
-
- // Default constructor needed by KeyedVector
- InFlightRequest() :
- shutterTimestamp(0),
- sensorTimestamp(0),
- requestStatus(OK),
- haveResultMetadata(false),
- numBuffersLeft(0),
- hasInputBuffer(false),
- hasCallback(true),
- maxExpectedDuration(kDefaultExpectedDuration),
- skipResultMetadata(false),
- stillCapture(false),
- zslCapture(false) {
- }
-
- InFlightRequest(int numBuffers, CaptureResultExtras extras, bool hasInput,
- bool hasAppCallback, nsecs_t maxDuration,
- const std::set<String8>& physicalCameraIdSet, bool isStillCapture,
- bool isZslCapture,
- const SurfaceMap& outSurfaces = SurfaceMap{}) :
- shutterTimestamp(0),
- sensorTimestamp(0),
- requestStatus(OK),
- haveResultMetadata(false),
- numBuffersLeft(numBuffers),
- resultExtras(extras),
- hasInputBuffer(hasInput),
- hasCallback(hasAppCallback),
- maxExpectedDuration(maxDuration),
- skipResultMetadata(false),
- physicalCameraIds(physicalCameraIdSet),
- stillCapture(isStillCapture),
- zslCapture(isZslCapture),
- outputSurfaces(outSurfaces) {
- }
- };
-
- // Map from frame number to the in-flight request state
- typedef KeyedVector<uint32_t, InFlightRequest> InFlightMap;
-
-
- Mutex mInFlightLock; // Protects mInFlightMap and
- // mExpectedInflightDuration
- InFlightMap mInFlightMap;
- nsecs_t mExpectedInflightDuration = 0;
- int mInFlightStatusId;
+ int mInFlightStatusId; // const after initialize
status_t registerInFlight(uint32_t frameNumber,
int32_t numBuffers, CaptureResultExtras resultExtras, bool hasInput,
bool callback, nsecs_t maxExpectedDuration, std::set<String8>& physicalCameraIds,
- bool isStillCapture, bool isZslCapture,
- const SurfaceMap& outputSurfaces);
-
- /**
- * Returns the maximum expected time it'll take for all currently in-flight
- * requests to complete, based on their settings
- */
- nsecs_t getExpectedInFlightDuration();
+ bool isStillCapture, bool isZslCapture, bool rotateAndCropAuto,
+ const std::set<std::string>& cameraIdsWithZoom, const SurfaceMap& outputSurfaces);
/**
* Tracking for idle detection
@@ -1186,7 +1086,7 @@
*/
// Lock for output side of device
- Mutex mOutputLock;
+ std::mutex mOutputLock;
/**** Scope for mOutputLock ****/
// the minimal frame number of the next non-reprocess result
@@ -1201,60 +1101,18 @@
uint32_t mNextReprocessShutterFrameNumber;
// the minimal frame number of the next ZSL still capture shutter
uint32_t mNextZslStillShutterFrameNumber;
- List<CaptureResult> mResultQueue;
- Condition mResultSignal;
- wp<NotificationListener> mListener;
+ std::list<CaptureResult> mResultQueue;
+ std::condition_variable mResultSignal;
+ wp<NotificationListener> mListener;
/**** End scope for mOutputLock ****/
- /**
- * Callback functions from HAL device
- */
- void processCaptureResult(const camera3_capture_result *result);
-
- void notify(const camera3_notify_msg *msg);
-
- // Specific notify handlers
- void notifyError(const camera3_error_msg_t &msg,
- sp<NotificationListener> listener);
- void notifyShutter(const camera3_shutter_msg_t &msg,
- sp<NotificationListener> listener);
-
- // helper function to return the output buffers to the streams.
- void returnOutputBuffers(const camera3_stream_buffer_t *outputBuffers,
- size_t numBuffers, nsecs_t timestamp, bool timestampIncreasing = true,
- // The following arguments are only meant for surface sharing use case
- const SurfaceMap& outputSurfaces = SurfaceMap{},
- // Used to send buffer error callback when failing to return buffer
- const CaptureResultExtras &resultExtras = CaptureResultExtras{});
-
- // Send a partial capture result.
- void sendPartialCaptureResult(const camera_metadata_t * partialResult,
- const CaptureResultExtras &resultExtras, uint32_t frameNumber);
-
- // Send a total capture result given the pending metadata and result extras,
- // partial results, and the frame number to the result queue.
- void sendCaptureResult(CameraMetadata &pendingMetadata,
- CaptureResultExtras &resultExtras,
- CameraMetadata &collectedPartialResult, uint32_t frameNumber,
- bool reprocess, bool zslStillCapture,
- const std::vector<PhysicalCaptureResultInfo>& physicalMetadatas);
-
- bool isLastFullResult(const InFlightRequest& inFlightRequest);
-
- // Insert the result to the result queue after updating frame number and overriding AE
- // trigger cancel.
- // mOutputLock must be held when calling this function.
- void insertResultLocked(CaptureResult *result, uint32_t frameNumber);
-
/**** Scope for mInFlightLock ****/
// Remove the in-flight map entry of the given index from mInFlightMap.
// It must only be called with mInFlightLock held.
void removeInFlightMapEntryLocked(int idx);
- // Remove the in-flight request of the given index from mInFlightMap
- // if it's no longer needed. It must only be called with mInFlightLock held.
- void removeInFlightRequestIfReadyLocked(int idx);
+
// Remove all in-flight requests and return all buffers.
// This is used after HAL interface is closed to cleanup any request/buffers
// not returned by HAL.
@@ -1270,6 +1128,16 @@
// logical camera and its physical subcameras.
std::unordered_map<std::string, camera3::DistortionMapper> mDistortionMappers;
+ /**
+ * Zoom ratio mapper support
+ */
+ std::unordered_map<std::string, camera3::ZoomRatioMapper> mZoomRatioMappers;
+
+ /**
+ * RotateAndCrop mapper support
+ */
+ std::unordered_map<std::string, camera3::RotateAndCropMapper> mRotateAndCropMappers;
+
// Debug tracker for metadata tag value changes
// - Enabled with the -m <taglist> option to dumpsys, such as
// dumpsys -m android.control.aeState,android.control.aeMode
@@ -1347,6 +1215,10 @@
void onSubmittingRequest();
void onRequestThreadPaused();
+ // Events triggered by successful switchToOffline call
+ // Return true is there is no ongoing requestBuffer call.
+ bool onSwitchToOfflineSuccess();
+
private:
void notifyTrackerLocked(bool active);
@@ -1360,6 +1232,7 @@
bool mRequestThreadPaused = true;
bool mInflightMapEmpty = true;
bool mRequestBufferOngoing = false;
+ bool mSwitchedToOffline = false;
wp<camera3::StatusTracker> mStatusTracker;
int mRequestBufferStatusId;
@@ -1367,7 +1240,9 @@
// Fix up result metadata for monochrome camera.
bool mNeedFixupMonochromeTags;
- status_t fixupMonochromeTags(const CameraMetadata& deviceInfo, CameraMetadata& resultMetadata);
+
+ // Whether HAL supports offline processing capability.
+ bool mSupportOfflineProcessing = false;
}; // class Camera3Device
}; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.cpp b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
index fc83684..cb59a76 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
@@ -71,7 +71,8 @@
res = mConsumer->acquireBuffer(&bufferItem, /*waitForFence*/false);
if (res != OK) {
- ALOGE("%s: Stream %d: Can't acquire next output buffer: %s (%d)",
+ // This may or may not be an error condition depending on caller.
+ ALOGV("%s: Stream %d: Can't acquire next output buffer: %s (%d)",
__FUNCTION__, mId, strerror(-res), res);
return res;
}
diff --git a/services/camera/libcameraservice/device3/Camera3OfflineSession.cpp b/services/camera/libcameraservice/device3/Camera3OfflineSession.cpp
new file mode 100644
index 0000000..5942868
--- /dev/null
+++ b/services/camera/libcameraservice/device3/Camera3OfflineSession.cpp
@@ -0,0 +1,470 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "Camera3-OffLnSsn"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+//#define LOG_NNDEBUG 0 // Per-frame verbose logging
+
+#ifdef LOG_NNDEBUG
+#define ALOGVV(...) ALOGV(__VA_ARGS__)
+#else
+#define ALOGVV(...) ((void)0)
+#endif
+
+#include <inttypes.h>
+
+#include <utils/Trace.h>
+
+#include <android/hardware/camera2/ICameraDeviceCallbacks.h>
+
+#include "device3/Camera3OfflineSession.h"
+#include "device3/Camera3OutputStream.h"
+#include "device3/Camera3InputStream.h"
+#include "device3/Camera3SharedOutputStream.h"
+#include "utils/CameraTraces.h"
+
+using namespace android::camera3;
+using namespace android::hardware::camera;
+
+namespace android {
+
+Camera3OfflineSession::Camera3OfflineSession(const String8 &id,
+ const sp<camera3::Camera3Stream>& inputStream,
+ const camera3::StreamSet& offlineStreamSet,
+ camera3::BufferRecords&& bufferRecords,
+ const camera3::InFlightRequestMap& offlineReqs,
+ const Camera3OfflineStates& offlineStates,
+ sp<hardware::camera::device::V3_6::ICameraOfflineSession> offlineSession) :
+ mId(id),
+ mInputStream(inputStream),
+ mOutputStreams(offlineStreamSet),
+ mBufferRecords(std::move(bufferRecords)),
+ mOfflineReqs(offlineReqs),
+ mSession(offlineSession),
+ mTagMonitor(offlineStates.mTagMonitor),
+ mVendorTagId(offlineStates.mVendorTagId),
+ mUseHalBufManager(offlineStates.mUseHalBufManager),
+ mNeedFixupMonochromeTags(offlineStates.mNeedFixupMonochromeTags),
+ mUsePartialResult(offlineStates.mUsePartialResult),
+ mNumPartialResults(offlineStates.mNumPartialResults),
+ mNextResultFrameNumber(offlineStates.mNextResultFrameNumber),
+ mNextReprocessResultFrameNumber(offlineStates.mNextReprocessResultFrameNumber),
+ mNextZslStillResultFrameNumber(offlineStates.mNextZslStillResultFrameNumber),
+ mNextShutterFrameNumber(offlineStates.mNextShutterFrameNumber),
+ mNextReprocessShutterFrameNumber(offlineStates.mNextReprocessShutterFrameNumber),
+ mNextZslStillShutterFrameNumber(offlineStates.mNextZslStillShutterFrameNumber),
+ mDeviceInfo(offlineStates.mDeviceInfo),
+ mPhysicalDeviceInfoMap(offlineStates.mPhysicalDeviceInfoMap),
+ mDistortionMappers(offlineStates.mDistortionMappers),
+ mZoomRatioMappers(offlineStates.mZoomRatioMappers),
+ mRotateAndCropMappers(offlineStates.mRotateAndCropMappers),
+ mStatus(STATUS_UNINITIALIZED) {
+ ATRACE_CALL();
+ ALOGV("%s: Created offline session for camera %s", __FUNCTION__, mId.string());
+}
+
+Camera3OfflineSession::~Camera3OfflineSession() {
+ ATRACE_CALL();
+ ALOGV("%s: Tearing down offline session for camera id %s", __FUNCTION__, mId.string());
+ disconnectImpl();
+}
+
+const String8& Camera3OfflineSession::getId() const {
+ return mId;
+}
+
+status_t Camera3OfflineSession::initialize(wp<NotificationListener> listener) {
+ ATRACE_CALL();
+
+ if (mSession == nullptr) {
+ ALOGE("%s: HIDL session is null!", __FUNCTION__);
+ return DEAD_OBJECT;
+ }
+
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+
+ mListener = listener;
+
+ // setup result FMQ
+ std::unique_ptr<ResultMetadataQueue>& resQueue = mResultMetadataQueue;
+ auto resultQueueRet = mSession->getCaptureResultMetadataQueue(
+ [&resQueue](const auto& descriptor) {
+ resQueue = std::make_unique<ResultMetadataQueue>(descriptor);
+ if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) {
+ ALOGE("HAL returns empty result metadata fmq, not use it");
+ resQueue = nullptr;
+ // Don't use resQueue onwards.
+ }
+ });
+ if (!resultQueueRet.isOk()) {
+ ALOGE("Transaction error when getting result metadata queue from camera session: %s",
+ resultQueueRet.description().c_str());
+ return DEAD_OBJECT;
+ }
+ mStatus = STATUS_ACTIVE;
+ }
+
+ mSession->setCallback(this);
+
+ return OK;
+}
+
+status_t Camera3OfflineSession::dump(int /*fd*/) {
+ ATRACE_CALL();
+ std::lock_guard<std::mutex> il(mInterfaceLock);
+ return OK;
+}
+
+status_t Camera3OfflineSession::disconnect() {
+ ATRACE_CALL();
+ return disconnectImpl();
+}
+
+status_t Camera3OfflineSession::disconnectImpl() {
+ ATRACE_CALL();
+ std::lock_guard<std::mutex> il(mInterfaceLock);
+
+ sp<NotificationListener> listener;
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mStatus == STATUS_CLOSED) {
+ return OK; // don't close twice
+ } else if (mStatus == STATUS_ERROR) {
+ ALOGE("%s: offline session %s shutting down in error state",
+ __FUNCTION__, mId.string());
+ }
+ listener = mListener.promote();
+ }
+
+ ALOGV("%s: E", __FUNCTION__);
+
+ {
+ std::lock_guard<std::mutex> lock(mRequestBufferInterfaceLock);
+ mAllowRequestBuffer = false;
+ }
+
+ std::vector<wp<Camera3StreamInterface>> streams;
+ streams.reserve(mOutputStreams.size() + (mInputStream != nullptr ? 1 : 0));
+ for (size_t i = 0; i < mOutputStreams.size(); i++) {
+ streams.push_back(mOutputStreams[i]);
+ }
+ if (mInputStream != nullptr) {
+ streams.push_back(mInputStream);
+ }
+
+ if (mSession != nullptr) {
+ mSession->close();
+ }
+
+ FlushInflightReqStates states {
+ mId, mOfflineReqsLock, mOfflineReqs, mUseHalBufManager,
+ listener, *this, mBufferRecords, *this};
+
+ camera3::flushInflightRequests(states);
+
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ mSession.clear();
+ mOutputStreams.clear();
+ mInputStream.clear();
+ mStatus = STATUS_CLOSED;
+ }
+
+ for (auto& weakStream : streams) {
+ sp<Camera3StreamInterface> stream = weakStream.promote();
+ if (stream != nullptr) {
+ ALOGE("%s: Stream %d leaked! strong reference (%d)!",
+ __FUNCTION__, stream->getId(), stream->getStrongCount() - 1);
+ }
+ }
+
+ ALOGV("%s: X", __FUNCTION__);
+ return OK;
+}
+
+status_t Camera3OfflineSession::waitForNextFrame(nsecs_t timeout) {
+ ATRACE_CALL();
+ std::unique_lock<std::mutex> lk(mOutputLock);
+
+ while (mResultQueue.empty()) {
+ auto st = mResultSignal.wait_for(lk, std::chrono::nanoseconds(timeout));
+ if (st == std::cv_status::timeout) {
+ return TIMED_OUT;
+ }
+ }
+ return OK;
+}
+
+status_t Camera3OfflineSession::getNextResult(CaptureResult* frame) {
+ ATRACE_CALL();
+ std::lock_guard<std::mutex> l(mOutputLock);
+
+ if (mResultQueue.empty()) {
+ return NOT_ENOUGH_DATA;
+ }
+
+ if (frame == nullptr) {
+ ALOGE("%s: argument cannot be NULL", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ CaptureResult &result = *(mResultQueue.begin());
+ frame->mResultExtras = result.mResultExtras;
+ frame->mMetadata.acquire(result.mMetadata);
+ frame->mPhysicalMetadatas = std::move(result.mPhysicalMetadatas);
+ mResultQueue.erase(mResultQueue.begin());
+
+ return OK;
+}
+
+hardware::Return<void> Camera3OfflineSession::processCaptureResult_3_4(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_4::CaptureResult>& results) {
+ sp<NotificationListener> listener;
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mStatus != STATUS_ACTIVE) {
+ ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
+ return hardware::Void();
+ }
+ listener = mListener.promote();
+ }
+
+ CaptureOutputStates states {
+ mId,
+ mOfflineReqsLock, mOfflineReqs,
+ mOutputLock, mResultQueue, mResultSignal,
+ mNextShutterFrameNumber,
+ mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+ mNextResultFrameNumber,
+ mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+ mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
+ mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
+ mTagMonitor, mInputStream, mOutputStreams, listener, *this, *this, mBufferRecords
+ };
+
+ std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
+ for (const auto& result : results) {
+ processOneCaptureResultLocked(states, result.v3_2, result.physicalCameraMetadata);
+ }
+ return hardware::Void();
+}
+
+hardware::Return<void> Camera3OfflineSession::processCaptureResult(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_2::CaptureResult>& results) {
+ // TODO: changed impl to call into processCaptureResult_3_4 instead?
+ // might need to figure how to reduce copy though.
+ sp<NotificationListener> listener;
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mStatus != STATUS_ACTIVE) {
+ ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
+ return hardware::Void();
+ }
+ listener = mListener.promote();
+ }
+
+ hardware::hidl_vec<hardware::camera::device::V3_4::PhysicalCameraMetadata> noPhysMetadata;
+
+ CaptureOutputStates states {
+ mId,
+ mOfflineReqsLock, mOfflineReqs,
+ mOutputLock, mResultQueue, mResultSignal,
+ mNextShutterFrameNumber,
+ mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+ mNextResultFrameNumber,
+ mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+ mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
+ mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
+ mTagMonitor, mInputStream, mOutputStreams, listener, *this, *this, mBufferRecords
+ };
+
+ std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
+ for (const auto& result : results) {
+ processOneCaptureResultLocked(states, result, noPhysMetadata);
+ }
+ return hardware::Void();
+}
+
+hardware::Return<void> Camera3OfflineSession::notify(
+ const hardware::hidl_vec<hardware::camera::device::V3_2::NotifyMsg>& msgs) {
+ sp<NotificationListener> listener;
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mStatus != STATUS_ACTIVE) {
+ ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
+ return hardware::Void();
+ }
+ listener = mListener.promote();
+ }
+
+ CaptureOutputStates states {
+ mId,
+ mOfflineReqsLock, mOfflineReqs,
+ mOutputLock, mResultQueue, mResultSignal,
+ mNextShutterFrameNumber,
+ mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+ mNextResultFrameNumber,
+ mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+ mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
+ mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
+ mTagMonitor, mInputStream, mOutputStreams, listener, *this, *this, mBufferRecords
+ };
+ for (const auto& msg : msgs) {
+ camera3::notify(states, msg);
+ }
+ return hardware::Void();
+}
+
+hardware::Return<void> Camera3OfflineSession::requestStreamBuffers(
+ const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
+ requestStreamBuffers_cb _hidl_cb) {
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mStatus != STATUS_ACTIVE) {
+ ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
+ return hardware::Void();
+ }
+ }
+
+ RequestBufferStates states {
+ mId, mRequestBufferInterfaceLock, mUseHalBufManager, mOutputStreams,
+ *this, mBufferRecords, *this};
+ camera3::requestStreamBuffers(states, bufReqs, _hidl_cb);
+ return hardware::Void();
+}
+
+hardware::Return<void> Camera3OfflineSession::returnStreamBuffers(
+ const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers) {
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mStatus != STATUS_ACTIVE) {
+ ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
+ return hardware::Void();
+ }
+ }
+
+ ReturnBufferStates states {
+ mId, mUseHalBufManager, mOutputStreams, mBufferRecords};
+ camera3::returnStreamBuffers(states, buffers);
+ return hardware::Void();
+}
+
+void Camera3OfflineSession::setErrorState(const char *fmt, ...) {
+ ATRACE_CALL();
+ std::lock_guard<std::mutex> lock(mLock);
+ va_list args;
+ va_start(args, fmt);
+
+ setErrorStateLockedV(fmt, args);
+
+ va_end(args);
+
+ //FIXME: automatically disconnect here?
+}
+
+void Camera3OfflineSession::setErrorStateLocked(const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+
+ setErrorStateLockedV(fmt, args);
+
+ va_end(args);
+}
+
+void Camera3OfflineSession::setErrorStateLockedV(const char *fmt, va_list args) {
+ // Print out all error messages to log
+ String8 errorCause = String8::formatV(fmt, args);
+ ALOGE("Camera %s: %s", mId.string(), errorCause.string());
+
+ // But only do error state transition steps for the first error
+ if (mStatus == STATUS_ERROR || mStatus == STATUS_UNINITIALIZED) return;
+
+ mErrorCause = errorCause;
+
+ mStatus = STATUS_ERROR;
+
+ // Notify upstream about a device error
+ sp<NotificationListener> listener = mListener.promote();
+ if (listener != NULL) {
+ listener->notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE,
+ CaptureResultExtras());
+ }
+
+ // Save stack trace. View by dumping it later.
+ CameraTraces::saveTrace();
+}
+
+void Camera3OfflineSession::onInflightEntryRemovedLocked(nsecs_t /*duration*/) {
+ if (mOfflineReqs.size() == 0) {
+ std::lock_guard<std::mutex> lock(mRequestBufferInterfaceLock);
+ mAllowRequestBuffer = false;
+ }
+}
+
+void Camera3OfflineSession::checkInflightMapLengthLocked() {
+ // Intentional empty impl.
+}
+
+void Camera3OfflineSession::onInflightMapFlushedLocked() {
+ // Intentional empty impl.
+}
+
+bool Camera3OfflineSession::startRequestBuffer() {
+ return mAllowRequestBuffer;
+}
+
+void Camera3OfflineSession::endRequestBuffer() {
+ // Intentional empty impl.
+}
+
+nsecs_t Camera3OfflineSession::getWaitDuration() {
+ const nsecs_t kBaseGetBufferWait = 3000000000; // 3 sec.
+ return kBaseGetBufferWait;
+}
+
+void Camera3OfflineSession::getInflightBufferKeys(std::vector<std::pair<int32_t, int32_t>>* out) {
+ mBufferRecords.getInflightBufferKeys(out);
+}
+
+void Camera3OfflineSession::getInflightRequestBufferKeys(std::vector<uint64_t>* out) {
+ mBufferRecords.getInflightRequestBufferKeys(out);
+}
+
+std::vector<sp<Camera3StreamInterface>> Camera3OfflineSession::getAllStreams() {
+ std::vector<sp<Camera3StreamInterface>> ret;
+ bool hasInputStream = mInputStream != nullptr;
+ ret.reserve(mOutputStreams.size() + ((hasInputStream) ? 1 : 0));
+ if (hasInputStream) {
+ ret.push_back(mInputStream);
+ }
+ for (size_t i = 0; i < mOutputStreams.size(); i++) {
+ ret.push_back(mOutputStreams[i]);
+ }
+ return ret;
+}
+
+const CameraMetadata& Camera3OfflineSession::info() const {
+ return mDeviceInfo;
+}
+
+}; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3OfflineSession.h b/services/camera/libcameraservice/device3/Camera3OfflineSession.h
new file mode 100644
index 0000000..208f70d
--- /dev/null
+++ b/services/camera/libcameraservice/device3/Camera3OfflineSession.h
@@ -0,0 +1,293 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_SERVERS_CAMERA3OFFLINESESSION_H
+#define ANDROID_SERVERS_CAMERA3OFFLINESESSION_H
+
+#include <memory>
+#include <mutex>
+
+#include <utils/String8.h>
+#include <utils/String16.h>
+
+#include <android/hardware/camera/device/3.6/ICameraOfflineSession.h>
+
+#include <fmq/MessageQueue.h>
+
+#include "common/CameraOfflineSessionBase.h"
+
+#include "device3/Camera3BufferManager.h"
+#include "device3/DistortionMapper.h"
+#include "device3/InFlightRequest.h"
+#include "device3/Camera3OutputUtils.h"
+#include "device3/RotateAndCropMapper.h"
+#include "device3/ZoomRatioMapper.h"
+#include "utils/TagMonitor.h"
+#include "utils/LatencyHistogram.h"
+#include <camera_metadata_hidden.h>
+
+namespace android {
+
+namespace camera3 {
+
+class Camera3Stream;
+class Camera3OutputStreamInterface;
+class Camera3StreamInterface;
+
+} // namespace camera3
+
+
+// An immutable struct containing general states that will be copied from Camera3Device to
+// Camera3OfflineSession
+struct Camera3OfflineStates {
+ Camera3OfflineStates(
+ const TagMonitor& tagMonitor, const metadata_vendor_id_t vendorTagId,
+ const bool useHalBufManager, const bool needFixupMonochromeTags,
+ const bool usePartialResult, const uint32_t numPartialResults,
+ const uint32_t nextResultFN, const uint32_t nextReprocResultFN,
+ const uint32_t nextZslResultFN, const uint32_t nextShutterFN,
+ const uint32_t nextReprocShutterFN, const uint32_t nextZslShutterFN,
+ const CameraMetadata& deviceInfo,
+ const std::unordered_map<std::string, CameraMetadata>& physicalDeviceInfoMap,
+ const std::unordered_map<std::string, camera3::DistortionMapper>& distortionMappers,
+ const std::unordered_map<std::string, camera3::ZoomRatioMapper>& zoomRatioMappers,
+ const std::unordered_map<std::string, camera3::RotateAndCropMapper>&
+ rotateAndCropMappers) :
+ mTagMonitor(tagMonitor), mVendorTagId(vendorTagId),
+ mUseHalBufManager(useHalBufManager), mNeedFixupMonochromeTags(needFixupMonochromeTags),
+ mUsePartialResult(usePartialResult), mNumPartialResults(numPartialResults),
+ mNextResultFrameNumber(nextResultFN),
+ mNextReprocessResultFrameNumber(nextReprocResultFN),
+ mNextZslStillResultFrameNumber(nextZslResultFN),
+ mNextShutterFrameNumber(nextShutterFN),
+ mNextReprocessShutterFrameNumber(nextReprocShutterFN),
+ mNextZslStillShutterFrameNumber(nextZslShutterFN),
+ mDeviceInfo(deviceInfo),
+ mPhysicalDeviceInfoMap(physicalDeviceInfoMap),
+ mDistortionMappers(distortionMappers),
+ mZoomRatioMappers(zoomRatioMappers),
+ mRotateAndCropMappers(rotateAndCropMappers) {}
+
+ const TagMonitor& mTagMonitor;
+ const metadata_vendor_id_t mVendorTagId;
+
+ const bool mUseHalBufManager;
+ const bool mNeedFixupMonochromeTags;
+
+ const bool mUsePartialResult;
+ const uint32_t mNumPartialResults;
+
+ // the minimal frame number of the next non-reprocess result
+ const uint32_t mNextResultFrameNumber;
+ // the minimal frame number of the next reprocess result
+ const uint32_t mNextReprocessResultFrameNumber;
+ // the minimal frame number of the next ZSL still capture result
+ const uint32_t mNextZslStillResultFrameNumber;
+ // the minimal frame number of the next non-reprocess shutter
+ const uint32_t mNextShutterFrameNumber;
+ // the minimal frame number of the next reprocess shutter
+ const uint32_t mNextReprocessShutterFrameNumber;
+ // the minimal frame number of the next ZSL still capture shutter
+ const uint32_t mNextZslStillShutterFrameNumber;
+
+ const CameraMetadata& mDeviceInfo;
+
+ const std::unordered_map<std::string, CameraMetadata>& mPhysicalDeviceInfoMap;
+
+ const std::unordered_map<std::string, camera3::DistortionMapper>& mDistortionMappers;
+
+ const std::unordered_map<std::string, camera3::ZoomRatioMapper>& mZoomRatioMappers;
+
+ const std::unordered_map<std::string, camera3::RotateAndCropMapper>& mRotateAndCropMappers;
+};
+
+/**
+ * Camera3OfflineSession for offline session defined in HIDL ICameraOfflineSession@3.6 or higher
+ */
+class Camera3OfflineSession :
+ public CameraOfflineSessionBase,
+ virtual public hardware::camera::device::V3_5::ICameraDeviceCallback,
+ public camera3::SetErrorInterface,
+ public camera3::InflightRequestUpdateInterface,
+ public camera3::RequestBufferInterface,
+ public camera3::FlushBufferInterface {
+ public:
+
+ // initialize by Camera3Device.
+ explicit Camera3OfflineSession(const String8& id,
+ const sp<camera3::Camera3Stream>& inputStream,
+ const camera3::StreamSet& offlineStreamSet,
+ camera3::BufferRecords&& bufferRecords,
+ const camera3::InFlightRequestMap& offlineReqs,
+ const Camera3OfflineStates& offlineStates,
+ sp<hardware::camera::device::V3_6::ICameraOfflineSession> offlineSession);
+
+ virtual ~Camera3OfflineSession();
+
+ virtual status_t initialize(wp<NotificationListener> listener) override;
+
+ /**
+ * CameraOfflineSessionBase interface
+ */
+ status_t disconnect() override;
+ status_t dump(int fd) override;
+
+ /**
+ * FrameProducer interface
+ */
+ const String8& getId() const override;
+ const CameraMetadata& info() const override;
+ status_t waitForNextFrame(nsecs_t timeout) override;
+ status_t getNextResult(CaptureResult *frame) override;
+
+ // TODO: methods for notification (error/idle/finished etc) passing
+
+ /**
+ * End of CameraOfflineSessionBase interface
+ */
+
+ /**
+ * HIDL ICameraDeviceCallback interface
+ */
+
+ /**
+ * Implementation of android::hardware::camera::device::V3_5::ICameraDeviceCallback
+ */
+
+ hardware::Return<void> processCaptureResult_3_4(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_4::CaptureResult>& results) override;
+ hardware::Return<void> processCaptureResult(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_2::CaptureResult>& results) override;
+ hardware::Return<void> notify(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_2::NotifyMsg>& msgs) override;
+
+ hardware::Return<void> requestStreamBuffers(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_5::BufferRequest>& bufReqs,
+ requestStreamBuffers_cb _hidl_cb) override;
+
+ hardware::Return<void> returnStreamBuffers(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_2::StreamBuffer>& buffers) override;
+
+ /**
+ * End of CameraOfflineSessionBase interface
+ */
+
+ private:
+ // Camera device ID
+ const String8 mId;
+ sp<camera3::Camera3Stream> mInputStream;
+ camera3::StreamSet mOutputStreams;
+ camera3::BufferRecords mBufferRecords;
+
+ std::mutex mOfflineReqsLock;
+ camera3::InFlightRequestMap mOfflineReqs;
+
+ sp<hardware::camera::device::V3_6::ICameraOfflineSession> mSession;
+
+ TagMonitor mTagMonitor;
+ const metadata_vendor_id_t mVendorTagId;
+
+ const bool mUseHalBufManager;
+ const bool mNeedFixupMonochromeTags;
+
+ const bool mUsePartialResult;
+ const uint32_t mNumPartialResults;
+
+ std::mutex mOutputLock;
+ std::list<CaptureResult> mResultQueue;
+ std::condition_variable mResultSignal;
+ // the minimal frame number of the next non-reprocess result
+ uint32_t mNextResultFrameNumber;
+ // the minimal frame number of the next reprocess result
+ uint32_t mNextReprocessResultFrameNumber;
+ // the minimal frame number of the next ZSL still capture result
+ uint32_t mNextZslStillResultFrameNumber;
+ // the minimal frame number of the next non-reprocess shutter
+ uint32_t mNextShutterFrameNumber;
+ // the minimal frame number of the next reprocess shutter
+ uint32_t mNextReprocessShutterFrameNumber;
+ // the minimal frame number of the next ZSL still capture shutter
+ uint32_t mNextZslStillShutterFrameNumber;
+ // End of mOutputLock scope
+
+ const CameraMetadata mDeviceInfo;
+ std::unordered_map<std::string, CameraMetadata> mPhysicalDeviceInfoMap;
+
+ std::unordered_map<std::string, camera3::DistortionMapper> mDistortionMappers;
+
+ std::unordered_map<std::string, camera3::ZoomRatioMapper> mZoomRatioMappers;
+
+ std::unordered_map<std::string, camera3::RotateAndCropMapper> mRotateAndCropMappers;
+
+ mutable std::mutex mLock;
+
+ enum Status {
+ STATUS_UNINITIALIZED = 0,
+ STATUS_ACTIVE,
+ STATUS_ERROR,
+ STATUS_CLOSED
+ } mStatus;
+
+ wp<NotificationListener> mListener;
+ // End of mLock protect scope
+
+ std::mutex mProcessCaptureResultLock;
+ // FMQ to write result on. Must be guarded by mProcessCaptureResultLock.
+ std::unique_ptr<ResultMetadataQueue> mResultMetadataQueue;
+
+ // Tracking cause of fatal errors when in STATUS_ERROR
+ String8 mErrorCause;
+
+ // Lock to ensure requestStreamBuffers() callbacks are serialized
+ std::mutex mRequestBufferInterfaceLock;
+ // allow request buffer until all requests are processed or disconnectImpl is called
+ bool mAllowRequestBuffer = true;
+
+ // For client methods such as disconnect/dump
+ std::mutex mInterfaceLock;
+
+ // SetErrorInterface
+ void setErrorState(const char *fmt, ...) override;
+ void setErrorStateLocked(const char *fmt, ...) override;
+
+ // InflightRequestUpdateInterface
+ void onInflightEntryRemovedLocked(nsecs_t duration) override;
+ void checkInflightMapLengthLocked() override;
+ void onInflightMapFlushedLocked() override;
+
+ // RequestBufferInterface
+ bool startRequestBuffer() override;
+ void endRequestBuffer() override;
+ nsecs_t getWaitDuration() override;
+
+ // FlushBufferInterface
+ void getInflightBufferKeys(std::vector<std::pair<int32_t, int32_t>>* out) override;
+ void getInflightRequestBufferKeys(std::vector<uint64_t>* out) override;
+ std::vector<sp<camera3::Camera3StreamInterface>> getAllStreams() override;
+
+ void setErrorStateLockedV(const char *fmt, va_list args);
+
+ status_t disconnectImpl();
+}; // class Camera3OfflineSession
+
+}; // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/device3/Camera3OutputInterface.h b/services/camera/libcameraservice/device3/Camera3OutputInterface.h
new file mode 100644
index 0000000..8817833
--- /dev/null
+++ b/services/camera/libcameraservice/device3/Camera3OutputInterface.h
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_SERVERS_CAMERA3_OUTPUT_INTERFACE_H
+#define ANDROID_SERVERS_CAMERA3_OUTPUT_INTERFACE_H
+
+#include <memory>
+
+#include <cutils/native_handle.h>
+
+#include <utils/Timers.h>
+
+#include "device3/Camera3StreamInterface.h"
+
+namespace android {
+
+namespace camera3 {
+
+ /**
+ * Interfaces used by result/notification path shared between Camera3Device and
+ * Camera3OfflineSession
+ */
+ class SetErrorInterface {
+ public:
+ // Switch device into error state and send a ERROR_DEVICE notification
+ virtual void setErrorState(const char *fmt, ...) = 0;
+ // Same as setErrorState except this method assumes callers holds the main object lock
+ virtual void setErrorStateLocked(const char *fmt, ...) = 0;
+
+ virtual ~SetErrorInterface() {}
+ };
+
+ // Interface used by callback path to update buffer records
+ class BufferRecordsInterface {
+ public:
+ // method to extract buffer's unique ID
+ // return pair of (newlySeenBuffer?, bufferId)
+ virtual std::pair<bool, uint64_t> getBufferId(const buffer_handle_t& buf, int streamId) = 0;
+
+ // Find a buffer_handle_t based on frame number and stream ID
+ virtual status_t popInflightBuffer(int32_t frameNumber, int32_t streamId,
+ /*out*/ buffer_handle_t **buffer) = 0;
+
+ // Register a bufId (streamId, buffer_handle_t) to inflight request buffer
+ virtual status_t pushInflightRequestBuffer(
+ uint64_t bufferId, buffer_handle_t* buf, int32_t streamId) = 0;
+
+ // Find a buffer_handle_t based on bufferId
+ virtual status_t popInflightRequestBuffer(uint64_t bufferId,
+ /*out*/ buffer_handle_t** buffer,
+ /*optional out*/ int32_t* streamId = nullptr) = 0;
+
+ virtual ~BufferRecordsInterface() {}
+ };
+
+ class InflightRequestUpdateInterface {
+ public:
+ // Caller must hold the lock proctecting InflightRequestMap
+ // duration: the maxExpectedDuration of the removed entry
+ virtual void onInflightEntryRemovedLocked(nsecs_t duration) = 0;
+
+ virtual void checkInflightMapLengthLocked() = 0;
+
+ virtual void onInflightMapFlushedLocked() = 0;
+
+ virtual ~InflightRequestUpdateInterface() {}
+ };
+
+ class RequestBufferInterface {
+ public:
+ // Return if the state machine currently allows for requestBuffers.
+ // If this returns true, caller must call endRequestBuffer() later to signal end of a
+ // request buffer transaction.
+ virtual bool startRequestBuffer() = 0;
+
+ virtual void endRequestBuffer() = 0;
+
+ // Returns how long should implementation wait for a buffer returned
+ virtual nsecs_t getWaitDuration() = 0;
+
+ virtual ~RequestBufferInterface() {}
+ };
+
+ class FlushBufferInterface {
+ public:
+ virtual void getInflightBufferKeys(std::vector<std::pair<int32_t, int32_t>>* out) = 0;
+
+ virtual void getInflightRequestBufferKeys(std::vector<uint64_t>* out) = 0;
+
+ virtual std::vector<sp<Camera3StreamInterface>> getAllStreams() = 0;
+
+ virtual ~FlushBufferInterface() {}
+ };
+} // namespace camera3
+
+} // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.cpp b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.cpp
new file mode 100644
index 0000000..64af91e
--- /dev/null
+++ b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.cpp
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "Camera3-OutStrmIntf"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+//#define LOG_NNDEBUG 0 // Per-frame verbose logging
+
+
+#include "Camera3OutputStreamInterface.h"
+
+namespace android {
+
+namespace camera3 {
+
+status_t StreamSet::add(
+ int streamId, sp<camera3::Camera3OutputStreamInterface> stream) {
+ if (stream == nullptr) {
+ ALOGE("%s: cannot add null stream", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ std::lock_guard<std::mutex> lock(mLock);
+ return mData.add(streamId, stream);
+}
+
+ssize_t StreamSet::remove(int streamId) {
+ std::lock_guard<std::mutex> lock(mLock);
+ return mData.removeItem(streamId);
+}
+
+sp<camera3::Camera3OutputStreamInterface> StreamSet::get(int streamId) {
+ std::lock_guard<std::mutex> lock(mLock);
+ ssize_t idx = mData.indexOfKey(streamId);
+ if (idx == NAME_NOT_FOUND) {
+ return nullptr;
+ }
+ return mData.editValueAt(idx);
+}
+
+sp<camera3::Camera3OutputStreamInterface> StreamSet::operator[] (size_t index) {
+ std::lock_guard<std::mutex> lock(mLock);
+ return mData.editValueAt(index);
+}
+
+size_t StreamSet::size() const {
+ std::lock_guard<std::mutex> lock(mLock);
+ return mData.size();
+}
+
+void StreamSet::clear() {
+ std::lock_guard<std::mutex> lock(mLock);
+ return mData.clear();
+}
+
+std::vector<int> StreamSet::getStreamIds() {
+ std::lock_guard<std::mutex> lock(mLock);
+ std::vector<int> streamIds(mData.size());
+ for (size_t i = 0; i < mData.size(); i++) {
+ streamIds[i] = mData.keyAt(i);
+ }
+ return streamIds;
+}
+
+StreamSet::StreamSet(const StreamSet& other) {
+ std::lock_guard<std::mutex> lock(other.mLock);
+ mData = other.mData;
+}
+
+} // namespace camera3
+
+} // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
index 2bde949..7f5c87a 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
@@ -97,6 +97,26 @@
virtual const String8& getPhysicalCameraId() const = 0;
};
+// Helper class to organize a synchronized mapping of stream IDs to stream instances
+class StreamSet {
+ public:
+ status_t add(int streamId, sp<camera3::Camera3OutputStreamInterface>);
+ ssize_t remove(int streamId);
+ sp<camera3::Camera3OutputStreamInterface> get(int streamId);
+ // get by (underlying) vector index
+ sp<camera3::Camera3OutputStreamInterface> operator[] (size_t index);
+ size_t size() const;
+ std::vector<int> getStreamIds();
+ void clear();
+
+ StreamSet() {};
+ StreamSet(const StreamSet& other);
+
+ private:
+ mutable std::mutex mLock;
+ KeyedVector<int, sp<camera3::Camera3OutputStreamInterface>> mData;
+};
+
} // namespace camera3
} // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
new file mode 100644
index 0000000..238356e
--- /dev/null
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
@@ -0,0 +1,1430 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "Camera3-OutputUtils"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+//#define LOG_NNDEBUG 0 // Per-frame verbose logging
+
+#ifdef LOG_NNDEBUG
+#define ALOGVV(...) ALOGV(__VA_ARGS__)
+#else
+#define ALOGVV(...) ((void)0)
+#endif
+
+// Convenience macros for transitioning to the error state
+#define SET_ERR(fmt, ...) states.setErrIntf.setErrorState( \
+ "%s: " fmt, __FUNCTION__, \
+ ##__VA_ARGS__)
+
+#include <inttypes.h>
+
+#include <utils/Log.h>
+#include <utils/SortedVector.h>
+#include <utils/Trace.h>
+
+#include <android/hardware/camera2/ICameraDeviceCallbacks.h>
+
+#include <android/hardware/camera/device/3.4/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.5/ICameraDeviceSession.h>
+
+#include <camera_metadata_hidden.h>
+
+#include "device3/Camera3OutputUtils.h"
+
+using namespace android::camera3;
+using namespace android::hardware::camera;
+
+namespace android {
+namespace camera3 {
+
+status_t fixupMonochromeTags(
+ CaptureOutputStates& states,
+ const CameraMetadata& deviceInfo,
+ CameraMetadata& resultMetadata) {
+ status_t res = OK;
+ if (!states.needFixupMonoChrome) {
+ return res;
+ }
+
+ // Remove tags that are not applicable to monochrome camera.
+ int32_t tagsToRemove[] = {
+ ANDROID_SENSOR_GREEN_SPLIT,
+ ANDROID_SENSOR_NEUTRAL_COLOR_POINT,
+ ANDROID_COLOR_CORRECTION_MODE,
+ ANDROID_COLOR_CORRECTION_TRANSFORM,
+ ANDROID_COLOR_CORRECTION_GAINS,
+ };
+ for (auto tag : tagsToRemove) {
+ res = resultMetadata.erase(tag);
+ if (res != OK) {
+ ALOGE("%s: Failed to remove tag %d for monochrome camera", __FUNCTION__, tag);
+ return res;
+ }
+ }
+
+ // ANDROID_SENSOR_DYNAMIC_BLACK_LEVEL
+ camera_metadata_entry blEntry = resultMetadata.find(ANDROID_SENSOR_DYNAMIC_BLACK_LEVEL);
+ for (size_t i = 1; i < blEntry.count; i++) {
+ blEntry.data.f[i] = blEntry.data.f[0];
+ }
+
+ // ANDROID_SENSOR_NOISE_PROFILE
+ camera_metadata_entry npEntry = resultMetadata.find(ANDROID_SENSOR_NOISE_PROFILE);
+ if (npEntry.count > 0 && npEntry.count % 2 == 0) {
+ double np[] = {npEntry.data.d[0], npEntry.data.d[1]};
+ res = resultMetadata.update(ANDROID_SENSOR_NOISE_PROFILE, np, 2);
+ if (res != OK) {
+ ALOGE("%s: Failed to update SENSOR_NOISE_PROFILE: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+ }
+
+ // ANDROID_STATISTICS_LENS_SHADING_MAP
+ camera_metadata_ro_entry lsSizeEntry = deviceInfo.find(ANDROID_LENS_INFO_SHADING_MAP_SIZE);
+ camera_metadata_entry lsEntry = resultMetadata.find(ANDROID_STATISTICS_LENS_SHADING_MAP);
+ if (lsSizeEntry.count == 2 && lsEntry.count > 0
+ && (int32_t)lsEntry.count == 4 * lsSizeEntry.data.i32[0] * lsSizeEntry.data.i32[1]) {
+ for (int32_t i = 0; i < lsSizeEntry.data.i32[0] * lsSizeEntry.data.i32[1]; i++) {
+ lsEntry.data.f[4*i+1] = lsEntry.data.f[4*i];
+ lsEntry.data.f[4*i+2] = lsEntry.data.f[4*i];
+ lsEntry.data.f[4*i+3] = lsEntry.data.f[4*i];
+ }
+ }
+
+ // ANDROID_TONEMAP_CURVE_BLUE
+ // ANDROID_TONEMAP_CURVE_GREEN
+ // ANDROID_TONEMAP_CURVE_RED
+ camera_metadata_entry tcbEntry = resultMetadata.find(ANDROID_TONEMAP_CURVE_BLUE);
+ camera_metadata_entry tcgEntry = resultMetadata.find(ANDROID_TONEMAP_CURVE_GREEN);
+ camera_metadata_entry tcrEntry = resultMetadata.find(ANDROID_TONEMAP_CURVE_RED);
+ if (tcbEntry.count > 0
+ && tcbEntry.count == tcgEntry.count
+ && tcbEntry.count == tcrEntry.count) {
+ for (size_t i = 0; i < tcbEntry.count; i++) {
+ tcbEntry.data.f[i] = tcrEntry.data.f[i];
+ tcgEntry.data.f[i] = tcrEntry.data.f[i];
+ }
+ }
+
+ return res;
+}
+
+void insertResultLocked(CaptureOutputStates& states, CaptureResult *result, uint32_t frameNumber) {
+ if (result == nullptr) return;
+
+ camera_metadata_t *meta = const_cast<camera_metadata_t *>(
+ result->mMetadata.getAndLock());
+ set_camera_metadata_vendor_id(meta, states.vendorTagId);
+ result->mMetadata.unlock(meta);
+
+ if (result->mMetadata.update(ANDROID_REQUEST_FRAME_COUNT,
+ (int32_t*)&frameNumber, 1) != OK) {
+ SET_ERR("Failed to set frame number %d in metadata", frameNumber);
+ return;
+ }
+
+ if (result->mMetadata.update(ANDROID_REQUEST_ID, &result->mResultExtras.requestId, 1) != OK) {
+ SET_ERR("Failed to set request ID in metadata for frame %d", frameNumber);
+ return;
+ }
+
+ // Update vendor tag id for physical metadata
+ for (auto& physicalMetadata : result->mPhysicalMetadatas) {
+ camera_metadata_t *pmeta = const_cast<camera_metadata_t *>(
+ physicalMetadata.mPhysicalCameraMetadata.getAndLock());
+ set_camera_metadata_vendor_id(pmeta, states.vendorTagId);
+ physicalMetadata.mPhysicalCameraMetadata.unlock(pmeta);
+ }
+
+ // Valid result, insert into queue
+ std::list<CaptureResult>::iterator queuedResult =
+ states.resultQueue.insert(states.resultQueue.end(), CaptureResult(*result));
+ ALOGV("%s: result requestId = %" PRId32 ", frameNumber = %" PRId64
+ ", burstId = %" PRId32, __FUNCTION__,
+ queuedResult->mResultExtras.requestId,
+ queuedResult->mResultExtras.frameNumber,
+ queuedResult->mResultExtras.burstId);
+
+ states.resultSignal.notify_one();
+}
+
+
+void sendPartialCaptureResult(CaptureOutputStates& states,
+ const camera_metadata_t * partialResult,
+ const CaptureResultExtras &resultExtras, uint32_t frameNumber) {
+ ATRACE_CALL();
+ std::lock_guard<std::mutex> l(states.outputLock);
+
+ CaptureResult captureResult;
+ captureResult.mResultExtras = resultExtras;
+ captureResult.mMetadata = partialResult;
+
+ // Fix up result metadata for monochrome camera.
+ status_t res = fixupMonochromeTags(states, states.deviceInfo, captureResult.mMetadata);
+ if (res != OK) {
+ SET_ERR("Failed to override result metadata: %s (%d)", strerror(-res), res);
+ return;
+ }
+
+ insertResultLocked(states, &captureResult, frameNumber);
+}
+
+void sendCaptureResult(
+ CaptureOutputStates& states,
+ CameraMetadata &pendingMetadata,
+ CaptureResultExtras &resultExtras,
+ CameraMetadata &collectedPartialResult,
+ uint32_t frameNumber,
+ bool reprocess, bool zslStillCapture, bool rotateAndCropAuto,
+ const std::set<std::string>& cameraIdsWithZoom,
+ const std::vector<PhysicalCaptureResultInfo>& physicalMetadatas) {
+ ATRACE_CALL();
+ if (pendingMetadata.isEmpty())
+ return;
+
+ std::lock_guard<std::mutex> l(states.outputLock);
+
+ // TODO: need to track errors for tighter bounds on expected frame number
+ if (reprocess) {
+ if (frameNumber < states.nextReprocResultFrameNum) {
+ SET_ERR("Out-of-order reprocess capture result metadata submitted! "
+ "(got frame number %d, expecting %d)",
+ frameNumber, states.nextReprocResultFrameNum);
+ return;
+ }
+ states.nextReprocResultFrameNum = frameNumber + 1;
+ } else if (zslStillCapture) {
+ if (frameNumber < states.nextZslResultFrameNum) {
+ SET_ERR("Out-of-order ZSL still capture result metadata submitted! "
+ "(got frame number %d, expecting %d)",
+ frameNumber, states.nextZslResultFrameNum);
+ return;
+ }
+ states.nextZslResultFrameNum = frameNumber + 1;
+ } else {
+ if (frameNumber < states.nextResultFrameNum) {
+ SET_ERR("Out-of-order capture result metadata submitted! "
+ "(got frame number %d, expecting %d)",
+ frameNumber, states.nextResultFrameNum);
+ return;
+ }
+ states.nextResultFrameNum = frameNumber + 1;
+ }
+
+ CaptureResult captureResult;
+ captureResult.mResultExtras = resultExtras;
+ captureResult.mMetadata = pendingMetadata;
+ captureResult.mPhysicalMetadatas = physicalMetadatas;
+
+ // Append any previous partials to form a complete result
+ if (states.usePartialResult && !collectedPartialResult.isEmpty()) {
+ captureResult.mMetadata.append(collectedPartialResult);
+ }
+
+ captureResult.mMetadata.sort();
+
+ // Check that there's a timestamp in the result metadata
+ camera_metadata_entry timestamp = captureResult.mMetadata.find(ANDROID_SENSOR_TIMESTAMP);
+ if (timestamp.count == 0) {
+ SET_ERR("No timestamp provided by HAL for frame %d!",
+ frameNumber);
+ return;
+ }
+ for (auto& physicalMetadata : captureResult.mPhysicalMetadatas) {
+ camera_metadata_entry timestamp =
+ physicalMetadata.mPhysicalCameraMetadata.find(ANDROID_SENSOR_TIMESTAMP);
+ if (timestamp.count == 0) {
+ SET_ERR("No timestamp provided by HAL for physical camera %s frame %d!",
+ String8(physicalMetadata.mPhysicalCameraId).c_str(), frameNumber);
+ return;
+ }
+ }
+
+ // Fix up some result metadata to account for HAL-level distortion correction
+ status_t res =
+ states.distortionMappers[states.cameraId.c_str()].correctCaptureResult(
+ &captureResult.mMetadata);
+ if (res != OK) {
+ SET_ERR("Unable to correct capture result metadata for frame %d: %s (%d)",
+ frameNumber, strerror(-res), res);
+ return;
+ }
+
+ // Fix up result metadata to account for zoom ratio availabilities between
+ // HAL and app.
+ bool zoomRatioIs1 = cameraIdsWithZoom.find(states.cameraId.c_str()) == cameraIdsWithZoom.end();
+ res = states.zoomRatioMappers[states.cameraId.c_str()].updateCaptureResult(
+ &captureResult.mMetadata, zoomRatioIs1);
+ if (res != OK) {
+ SET_ERR("Failed to update capture result zoom ratio metadata for frame %d: %s (%d)",
+ frameNumber, strerror(-res), res);
+ return;
+ }
+
+ // Fix up result metadata to account for rotateAndCrop in AUTO mode
+ if (rotateAndCropAuto) {
+ auto mapper = states.rotateAndCropMappers.find(states.cameraId.c_str());
+ if (mapper != states.rotateAndCropMappers.end()) {
+ res = mapper->second.updateCaptureResult(
+ &captureResult.mMetadata);
+ if (res != OK) {
+ SET_ERR("Unable to correct capture result rotate-and-crop for frame %d: %s (%d)",
+ frameNumber, strerror(-res), res);
+ return;
+ }
+ }
+ }
+
+ for (auto& physicalMetadata : captureResult.mPhysicalMetadatas) {
+ String8 cameraId8(physicalMetadata.mPhysicalCameraId);
+ auto mapper = states.distortionMappers.find(cameraId8.c_str());
+ if (mapper != states.distortionMappers.end()) {
+ res = mapper->second.correctCaptureResult(
+ &physicalMetadata.mPhysicalCameraMetadata);
+ if (res != OK) {
+ SET_ERR("Unable to correct physical capture result metadata for frame %d: %s (%d)",
+ frameNumber, strerror(-res), res);
+ return;
+ }
+ }
+
+ zoomRatioIs1 = cameraIdsWithZoom.find(cameraId8.c_str()) == cameraIdsWithZoom.end();
+ res = states.zoomRatioMappers[cameraId8.c_str()].updateCaptureResult(
+ &physicalMetadata.mPhysicalCameraMetadata, zoomRatioIs1);
+ if (res != OK) {
+ SET_ERR("Failed to update camera %s's physical zoom ratio metadata for "
+ "frame %d: %s(%d)", cameraId8.c_str(), frameNumber, strerror(-res), res);
+ return;
+ }
+ }
+
+ // Fix up result metadata for monochrome camera.
+ res = fixupMonochromeTags(states, states.deviceInfo, captureResult.mMetadata);
+ if (res != OK) {
+ SET_ERR("Failed to override result metadata: %s (%d)", strerror(-res), res);
+ return;
+ }
+ for (auto& physicalMetadata : captureResult.mPhysicalMetadatas) {
+ String8 cameraId8(physicalMetadata.mPhysicalCameraId);
+ res = fixupMonochromeTags(states,
+ states.physicalDeviceInfoMap.at(cameraId8.c_str()),
+ physicalMetadata.mPhysicalCameraMetadata);
+ if (res != OK) {
+ SET_ERR("Failed to override result metadata: %s (%d)", strerror(-res), res);
+ return;
+ }
+ }
+
+ std::unordered_map<std::string, CameraMetadata> monitoredPhysicalMetadata;
+ for (auto& m : physicalMetadatas) {
+ monitoredPhysicalMetadata.emplace(String8(m.mPhysicalCameraId).string(),
+ CameraMetadata(m.mPhysicalCameraMetadata));
+ }
+ states.tagMonitor.monitorMetadata(TagMonitor::RESULT,
+ frameNumber, timestamp.data.i64[0], captureResult.mMetadata,
+ monitoredPhysicalMetadata);
+
+ insertResultLocked(states, &captureResult, frameNumber);
+}
+
+// Reading one camera metadata from result argument via fmq or from the result
+// Assuming the fmq is protected by a lock already
+status_t readOneCameraMetadataLocked(
+ std::unique_ptr<ResultMetadataQueue>& fmq,
+ uint64_t fmqResultSize,
+ hardware::camera::device::V3_2::CameraMetadata& resultMetadata,
+ const hardware::camera::device::V3_2::CameraMetadata& result) {
+ if (fmqResultSize > 0) {
+ resultMetadata.resize(fmqResultSize);
+ if (fmq == nullptr) {
+ return NO_MEMORY; // logged in initialize()
+ }
+ if (!fmq->read(resultMetadata.data(), fmqResultSize)) {
+ ALOGE("%s: Cannot read camera metadata from fmq, size = %" PRIu64,
+ __FUNCTION__, fmqResultSize);
+ return INVALID_OPERATION;
+ }
+ } else {
+ resultMetadata.setToExternal(const_cast<uint8_t *>(result.data()),
+ result.size());
+ }
+
+ if (resultMetadata.size() != 0) {
+ status_t res;
+ const camera_metadata_t* metadata =
+ reinterpret_cast<const camera_metadata_t*>(resultMetadata.data());
+ size_t expected_metadata_size = resultMetadata.size();
+ if ((res = validate_camera_metadata_structure(metadata, &expected_metadata_size)) != OK) {
+ ALOGE("%s: Invalid camera metadata received by camera service from HAL: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return INVALID_OPERATION;
+ }
+ }
+
+ return OK;
+}
+
+void removeInFlightMapEntryLocked(CaptureOutputStates& states, int idx) {
+ ATRACE_CALL();
+ InFlightRequestMap& inflightMap = states.inflightMap;
+ nsecs_t duration = inflightMap.valueAt(idx).maxExpectedDuration;
+ inflightMap.removeItemsAt(idx, 1);
+
+ states.inflightIntf.onInflightEntryRemovedLocked(duration);
+}
+
+void removeInFlightRequestIfReadyLocked(CaptureOutputStates& states, int idx) {
+ InFlightRequestMap& inflightMap = states.inflightMap;
+ const InFlightRequest &request = inflightMap.valueAt(idx);
+ const uint32_t frameNumber = inflightMap.keyAt(idx);
+
+ nsecs_t sensorTimestamp = request.sensorTimestamp;
+ nsecs_t shutterTimestamp = request.shutterTimestamp;
+
+ // Check if it's okay to remove the request from InFlightMap:
+ // In the case of a successful request:
+ // all input and output buffers, all result metadata, shutter callback
+ // arrived.
+ // In the case of a unsuccessful request:
+ // all input and output buffers arrived.
+ if (request.numBuffersLeft == 0 &&
+ (request.skipResultMetadata ||
+ (request.haveResultMetadata && shutterTimestamp != 0))) {
+ if (request.stillCapture) {
+ ATRACE_ASYNC_END("still capture", frameNumber);
+ }
+
+ ATRACE_ASYNC_END("frame capture", frameNumber);
+
+ // Sanity check - if sensor timestamp matches shutter timestamp in the
+ // case of request having callback.
+ if (request.hasCallback && request.requestStatus == OK &&
+ sensorTimestamp != shutterTimestamp) {
+ SET_ERR("sensor timestamp (%" PRId64
+ ") for frame %d doesn't match shutter timestamp (%" PRId64 ")",
+ sensorTimestamp, frameNumber, shutterTimestamp);
+ }
+
+ // for an unsuccessful request, it may have pending output buffers to
+ // return.
+ assert(request.requestStatus != OK ||
+ request.pendingOutputBuffers.size() == 0);
+
+ returnOutputBuffers(
+ states.useHalBufManager, states.listener,
+ request.pendingOutputBuffers.array(),
+ request.pendingOutputBuffers.size(), 0, /*timestampIncreasing*/true,
+ request.outputSurfaces, request.resultExtras);
+
+ removeInFlightMapEntryLocked(states, idx);
+ ALOGVV("%s: removed frame %d from InFlightMap", __FUNCTION__, frameNumber);
+ }
+
+ states.inflightIntf.checkInflightMapLengthLocked();
+}
+
+void processCaptureResult(CaptureOutputStates& states, const camera3_capture_result *result) {
+ ATRACE_CALL();
+
+ status_t res;
+
+ uint32_t frameNumber = result->frame_number;
+ if (result->result == NULL && result->num_output_buffers == 0 &&
+ result->input_buffer == NULL) {
+ SET_ERR("No result data provided by HAL for frame %d",
+ frameNumber);
+ return;
+ }
+
+ if (!states.usePartialResult &&
+ result->result != NULL &&
+ result->partial_result != 1) {
+ SET_ERR("Result is malformed for frame %d: partial_result %u must be 1"
+ " if partial result is not supported",
+ frameNumber, result->partial_result);
+ return;
+ }
+
+ bool isPartialResult = false;
+ CameraMetadata collectedPartialResult;
+ bool hasInputBufferInRequest = false;
+
+ // Get shutter timestamp and resultExtras from list of in-flight requests,
+ // where it was added by the shutter notification for this frame. If the
+ // shutter timestamp isn't received yet, append the output buffers to the
+ // in-flight request and they will be returned when the shutter timestamp
+ // arrives. Update the in-flight status and remove the in-flight entry if
+ // all result data and shutter timestamp have been received.
+ nsecs_t shutterTimestamp = 0;
+ {
+ std::lock_guard<std::mutex> l(states.inflightLock);
+ ssize_t idx = states.inflightMap.indexOfKey(frameNumber);
+ if (idx == NAME_NOT_FOUND) {
+ SET_ERR("Unknown frame number for capture result: %d",
+ frameNumber);
+ return;
+ }
+ InFlightRequest &request = states.inflightMap.editValueAt(idx);
+ ALOGVV("%s: got InFlightRequest requestId = %" PRId32
+ ", frameNumber = %" PRId64 ", burstId = %" PRId32
+ ", partialResultCount = %d, hasCallback = %d",
+ __FUNCTION__, request.resultExtras.requestId,
+ request.resultExtras.frameNumber, request.resultExtras.burstId,
+ result->partial_result, request.hasCallback);
+ // Always update the partial count to the latest one if it's not 0
+ // (buffers only). When framework aggregates adjacent partial results
+ // into one, the latest partial count will be used.
+ if (result->partial_result != 0)
+ request.resultExtras.partialResultCount = result->partial_result;
+
+ // Check if this result carries only partial metadata
+ if (states.usePartialResult && result->result != NULL) {
+ if (result->partial_result > states.numPartialResults || result->partial_result < 1) {
+ SET_ERR("Result is malformed for frame %d: partial_result %u must be in"
+ " the range of [1, %d] when metadata is included in the result",
+ frameNumber, result->partial_result, states.numPartialResults);
+ return;
+ }
+ isPartialResult = (result->partial_result < states.numPartialResults);
+ if (isPartialResult && result->num_physcam_metadata) {
+ SET_ERR("Result is malformed for frame %d: partial_result not allowed for"
+ " physical camera result", frameNumber);
+ return;
+ }
+ if (isPartialResult) {
+ request.collectedPartialResult.append(result->result);
+ }
+
+ if (isPartialResult && request.hasCallback) {
+ // Send partial capture result
+ sendPartialCaptureResult(states, result->result, request.resultExtras,
+ frameNumber);
+ }
+ }
+
+ shutterTimestamp = request.shutterTimestamp;
+ hasInputBufferInRequest = request.hasInputBuffer;
+
+ // Did we get the (final) result metadata for this capture?
+ if (result->result != NULL && !isPartialResult) {
+ if (request.physicalCameraIds.size() != result->num_physcam_metadata) {
+ SET_ERR("Expected physical Camera metadata count %d not equal to actual count %d",
+ request.physicalCameraIds.size(), result->num_physcam_metadata);
+ return;
+ }
+ if (request.haveResultMetadata) {
+ SET_ERR("Called multiple times with metadata for frame %d",
+ frameNumber);
+ return;
+ }
+ for (uint32_t i = 0; i < result->num_physcam_metadata; i++) {
+ String8 physicalId(result->physcam_ids[i]);
+ std::set<String8>::iterator cameraIdIter =
+ request.physicalCameraIds.find(physicalId);
+ if (cameraIdIter != request.physicalCameraIds.end()) {
+ request.physicalCameraIds.erase(cameraIdIter);
+ } else {
+ SET_ERR("Total result for frame %d has already returned for camera %s",
+ frameNumber, physicalId.c_str());
+ return;
+ }
+ }
+ if (states.usePartialResult &&
+ !request.collectedPartialResult.isEmpty()) {
+ collectedPartialResult.acquire(
+ request.collectedPartialResult);
+ }
+ request.haveResultMetadata = true;
+ }
+
+ uint32_t numBuffersReturned = result->num_output_buffers;
+ if (result->input_buffer != NULL) {
+ if (hasInputBufferInRequest) {
+ numBuffersReturned += 1;
+ } else {
+ ALOGW("%s: Input buffer should be NULL if there is no input"
+ " buffer sent in the request",
+ __FUNCTION__);
+ }
+ }
+ request.numBuffersLeft -= numBuffersReturned;
+ if (request.numBuffersLeft < 0) {
+ SET_ERR("Too many buffers returned for frame %d",
+ frameNumber);
+ return;
+ }
+
+ camera_metadata_ro_entry_t entry;
+ res = find_camera_metadata_ro_entry(result->result,
+ ANDROID_SENSOR_TIMESTAMP, &entry);
+ if (res == OK && entry.count == 1) {
+ request.sensorTimestamp = entry.data.i64[0];
+ }
+
+ // If shutter event isn't received yet, append the output buffers to
+ // the in-flight request. Otherwise, return the output buffers to
+ // streams.
+ if (shutterTimestamp == 0) {
+ request.pendingOutputBuffers.appendArray(result->output_buffers,
+ result->num_output_buffers);
+ } else {
+ bool timestampIncreasing = !(request.zslCapture || request.hasInputBuffer);
+ returnOutputBuffers(states.useHalBufManager, states.listener,
+ result->output_buffers, result->num_output_buffers,
+ shutterTimestamp, timestampIncreasing,
+ request.outputSurfaces, request.resultExtras);
+ }
+
+ if (result->result != NULL && !isPartialResult) {
+ for (uint32_t i = 0; i < result->num_physcam_metadata; i++) {
+ CameraMetadata physicalMetadata;
+ physicalMetadata.append(result->physcam_metadata[i]);
+ request.physicalMetadatas.push_back({String16(result->physcam_ids[i]),
+ physicalMetadata});
+ }
+ if (shutterTimestamp == 0) {
+ request.pendingMetadata = result->result;
+ request.collectedPartialResult = collectedPartialResult;
+ } else if (request.hasCallback) {
+ CameraMetadata metadata;
+ metadata = result->result;
+ sendCaptureResult(states, metadata, request.resultExtras,
+ collectedPartialResult, frameNumber,
+ hasInputBufferInRequest, request.zslCapture && request.stillCapture,
+ request.rotateAndCropAuto, request.cameraIdsWithZoom,
+ request.physicalMetadatas);
+ }
+ }
+ removeInFlightRequestIfReadyLocked(states, idx);
+ } // scope for states.inFlightLock
+
+ if (result->input_buffer != NULL) {
+ if (hasInputBufferInRequest) {
+ Camera3Stream *stream =
+ Camera3Stream::cast(result->input_buffer->stream);
+ res = stream->returnInputBuffer(*(result->input_buffer));
+ // Note: stream may be deallocated at this point, if this buffer was the
+ // last reference to it.
+ if (res != OK) {
+ ALOGE("%s: RequestThread: Can't return input buffer for frame %d to"
+ " its stream:%s (%d)", __FUNCTION__,
+ frameNumber, strerror(-res), res);
+ }
+ } else {
+ ALOGW("%s: Input buffer should be NULL if there is no input"
+ " buffer sent in the request, skipping input buffer return.",
+ __FUNCTION__);
+ }
+ }
+}
+
+void processOneCaptureResultLocked(
+ CaptureOutputStates& states,
+ const hardware::camera::device::V3_2::CaptureResult& result,
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_4::PhysicalCameraMetadata> physicalCameraMetadata) {
+ using hardware::camera::device::V3_2::StreamBuffer;
+ using hardware::camera::device::V3_2::BufferStatus;
+ std::unique_ptr<ResultMetadataQueue>& fmq = states.fmq;
+ BufferRecordsInterface& bufferRecords = states.bufferRecordsIntf;
+ camera3_capture_result r;
+ status_t res;
+ r.frame_number = result.frameNumber;
+
+ // Read and validate the result metadata.
+ hardware::camera::device::V3_2::CameraMetadata resultMetadata;
+ res = readOneCameraMetadataLocked(
+ fmq, result.fmqResultSize,
+ resultMetadata, result.result);
+ if (res != OK) {
+ ALOGE("%s: Frame %d: Failed to read capture result metadata",
+ __FUNCTION__, result.frameNumber);
+ return;
+ }
+ r.result = reinterpret_cast<const camera_metadata_t*>(resultMetadata.data());
+
+ // Read and validate physical camera metadata
+ size_t physResultCount = physicalCameraMetadata.size();
+ std::vector<const char*> physCamIds(physResultCount);
+ std::vector<const camera_metadata_t *> phyCamMetadatas(physResultCount);
+ std::vector<hardware::camera::device::V3_2::CameraMetadata> physResultMetadata;
+ physResultMetadata.resize(physResultCount);
+ for (size_t i = 0; i < physicalCameraMetadata.size(); i++) {
+ res = readOneCameraMetadataLocked(fmq, physicalCameraMetadata[i].fmqMetadataSize,
+ physResultMetadata[i], physicalCameraMetadata[i].metadata);
+ if (res != OK) {
+ ALOGE("%s: Frame %d: Failed to read capture result metadata for camera %s",
+ __FUNCTION__, result.frameNumber,
+ physicalCameraMetadata[i].physicalCameraId.c_str());
+ return;
+ }
+ physCamIds[i] = physicalCameraMetadata[i].physicalCameraId.c_str();
+ phyCamMetadatas[i] = reinterpret_cast<const camera_metadata_t*>(
+ physResultMetadata[i].data());
+ }
+ r.num_physcam_metadata = physResultCount;
+ r.physcam_ids = physCamIds.data();
+ r.physcam_metadata = phyCamMetadatas.data();
+
+ std::vector<camera3_stream_buffer_t> outputBuffers(result.outputBuffers.size());
+ std::vector<buffer_handle_t> outputBufferHandles(result.outputBuffers.size());
+ for (size_t i = 0; i < result.outputBuffers.size(); i++) {
+ auto& bDst = outputBuffers[i];
+ const StreamBuffer &bSrc = result.outputBuffers[i];
+
+ sp<Camera3StreamInterface> stream = states.outputStreams.get(bSrc.streamId);
+ if (stream == nullptr) {
+ ALOGE("%s: Frame %d: Buffer %zu: Invalid output stream id %d",
+ __FUNCTION__, result.frameNumber, i, bSrc.streamId);
+ return;
+ }
+ bDst.stream = stream->asHalStream();
+
+ bool noBufferReturned = false;
+ buffer_handle_t *buffer = nullptr;
+ if (states.useHalBufManager) {
+ // This is suspicious most of the time but can be correct during flush where HAL
+ // has to return capture result before a buffer is requested
+ if (bSrc.bufferId == BUFFER_ID_NO_BUFFER) {
+ if (bSrc.status == BufferStatus::OK) {
+ ALOGE("%s: Frame %d: Buffer %zu: No bufferId for stream %d",
+ __FUNCTION__, result.frameNumber, i, bSrc.streamId);
+ // Still proceeds so other buffers can be returned
+ }
+ noBufferReturned = true;
+ }
+ if (noBufferReturned) {
+ res = OK;
+ } else {
+ res = bufferRecords.popInflightRequestBuffer(bSrc.bufferId, &buffer);
+ }
+ } else {
+ res = bufferRecords.popInflightBuffer(result.frameNumber, bSrc.streamId, &buffer);
+ }
+
+ if (res != OK) {
+ ALOGE("%s: Frame %d: Buffer %zu: No in-flight buffer for stream %d",
+ __FUNCTION__, result.frameNumber, i, bSrc.streamId);
+ return;
+ }
+
+ bDst.buffer = buffer;
+ bDst.status = mapHidlBufferStatus(bSrc.status);
+ bDst.acquire_fence = -1;
+ if (bSrc.releaseFence == nullptr) {
+ bDst.release_fence = -1;
+ } else if (bSrc.releaseFence->numFds == 1) {
+ if (noBufferReturned) {
+ ALOGE("%s: got releaseFence without output buffer!", __FUNCTION__);
+ }
+ bDst.release_fence = dup(bSrc.releaseFence->data[0]);
+ } else {
+ ALOGE("%s: Frame %d: Invalid release fence for buffer %zu, fd count is %d, not 1",
+ __FUNCTION__, result.frameNumber, i, bSrc.releaseFence->numFds);
+ return;
+ }
+ }
+ r.num_output_buffers = outputBuffers.size();
+ r.output_buffers = outputBuffers.data();
+
+ camera3_stream_buffer_t inputBuffer;
+ if (result.inputBuffer.streamId == -1) {
+ r.input_buffer = nullptr;
+ } else {
+ if (states.inputStream->getId() != result.inputBuffer.streamId) {
+ ALOGE("%s: Frame %d: Invalid input stream id %d", __FUNCTION__,
+ result.frameNumber, result.inputBuffer.streamId);
+ return;
+ }
+ inputBuffer.stream = states.inputStream->asHalStream();
+ buffer_handle_t *buffer;
+ res = bufferRecords.popInflightBuffer(result.frameNumber, result.inputBuffer.streamId,
+ &buffer);
+ if (res != OK) {
+ ALOGE("%s: Frame %d: Input buffer: No in-flight buffer for stream %d",
+ __FUNCTION__, result.frameNumber, result.inputBuffer.streamId);
+ return;
+ }
+ inputBuffer.buffer = buffer;
+ inputBuffer.status = mapHidlBufferStatus(result.inputBuffer.status);
+ inputBuffer.acquire_fence = -1;
+ if (result.inputBuffer.releaseFence == nullptr) {
+ inputBuffer.release_fence = -1;
+ } else if (result.inputBuffer.releaseFence->numFds == 1) {
+ inputBuffer.release_fence = dup(result.inputBuffer.releaseFence->data[0]);
+ } else {
+ ALOGE("%s: Frame %d: Invalid release fence for input buffer, fd count is %d, not 1",
+ __FUNCTION__, result.frameNumber, result.inputBuffer.releaseFence->numFds);
+ return;
+ }
+ r.input_buffer = &inputBuffer;
+ }
+
+ r.partial_result = result.partialResult;
+
+ processCaptureResult(states, &r);
+}
+
+void returnOutputBuffers(
+ bool useHalBufManager,
+ sp<NotificationListener> listener,
+ const camera3_stream_buffer_t *outputBuffers, size_t numBuffers,
+ nsecs_t timestamp, bool timestampIncreasing,
+ const SurfaceMap& outputSurfaces,
+ const CaptureResultExtras &inResultExtras) {
+
+ for (size_t i = 0; i < numBuffers; i++)
+ {
+ if (outputBuffers[i].buffer == nullptr) {
+ if (!useHalBufManager) {
+ // With HAL buffer management API, HAL sometimes will have to return buffers that
+ // has not got a output buffer handle filled yet. This is though illegal if HAL
+ // buffer management API is not being used.
+ ALOGE("%s: cannot return a null buffer!", __FUNCTION__);
+ }
+ continue;
+ }
+
+ Camera3StreamInterface *stream = Camera3Stream::cast(outputBuffers[i].stream);
+ int streamId = stream->getId();
+ const auto& it = outputSurfaces.find(streamId);
+ status_t res = OK;
+ if (it != outputSurfaces.end()) {
+ res = stream->returnBuffer(
+ outputBuffers[i], timestamp, timestampIncreasing, it->second,
+ inResultExtras.frameNumber);
+ } else {
+ res = stream->returnBuffer(
+ outputBuffers[i], timestamp, timestampIncreasing, std::vector<size_t> (),
+ inResultExtras.frameNumber);
+ }
+
+ // Note: stream may be deallocated at this point, if this buffer was
+ // the last reference to it.
+ if (res == NO_INIT || res == DEAD_OBJECT) {
+ ALOGV("Can't return buffer to its stream: %s (%d)", strerror(-res), res);
+ } else if (res != OK) {
+ ALOGE("Can't return buffer to its stream: %s (%d)", strerror(-res), res);
+ }
+
+ // Long processing consumers can cause returnBuffer timeout for shared stream
+ // If that happens, cancel the buffer and send a buffer error to client
+ if (it != outputSurfaces.end() && res == TIMED_OUT &&
+ outputBuffers[i].status == CAMERA3_BUFFER_STATUS_OK) {
+ // cancel the buffer
+ camera3_stream_buffer_t sb = outputBuffers[i];
+ sb.status = CAMERA3_BUFFER_STATUS_ERROR;
+ stream->returnBuffer(sb, /*timestamp*/0, timestampIncreasing, std::vector<size_t> (),
+ inResultExtras.frameNumber);
+
+ if (listener != nullptr) {
+ CaptureResultExtras extras = inResultExtras;
+ extras.errorStreamId = streamId;
+ listener->notifyError(
+ hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_BUFFER,
+ extras);
+ }
+ }
+ }
+}
+
+void notifyShutter(CaptureOutputStates& states, const camera3_shutter_msg_t &msg) {
+ ATRACE_CALL();
+ ssize_t idx;
+
+ // Set timestamp for the request in the in-flight tracking
+ // and get the request ID to send upstream
+ {
+ std::lock_guard<std::mutex> l(states.inflightLock);
+ InFlightRequestMap& inflightMap = states.inflightMap;
+ idx = inflightMap.indexOfKey(msg.frame_number);
+ if (idx >= 0) {
+ InFlightRequest &r = inflightMap.editValueAt(idx);
+
+ // Verify ordering of shutter notifications
+ {
+ std::lock_guard<std::mutex> l(states.outputLock);
+ // TODO: need to track errors for tighter bounds on expected frame number.
+ if (r.hasInputBuffer) {
+ if (msg.frame_number < states.nextReprocShutterFrameNum) {
+ SET_ERR("Reprocess shutter notification out-of-order. Expected "
+ "notification for frame %d, got frame %d",
+ states.nextReprocShutterFrameNum, msg.frame_number);
+ return;
+ }
+ states.nextReprocShutterFrameNum = msg.frame_number + 1;
+ } else if (r.zslCapture && r.stillCapture) {
+ if (msg.frame_number < states.nextZslShutterFrameNum) {
+ SET_ERR("ZSL still capture shutter notification out-of-order. Expected "
+ "notification for frame %d, got frame %d",
+ states.nextZslShutterFrameNum, msg.frame_number);
+ return;
+ }
+ states.nextZslShutterFrameNum = msg.frame_number + 1;
+ } else {
+ if (msg.frame_number < states.nextShutterFrameNum) {
+ SET_ERR("Shutter notification out-of-order. Expected "
+ "notification for frame %d, got frame %d",
+ states.nextShutterFrameNum, msg.frame_number);
+ return;
+ }
+ states.nextShutterFrameNum = msg.frame_number + 1;
+ }
+ }
+
+ r.shutterTimestamp = msg.timestamp;
+ if (r.hasCallback) {
+ ALOGVV("Camera %s: %s: Shutter fired for frame %d (id %d) at %" PRId64,
+ states.cameraId.string(), __FUNCTION__,
+ msg.frame_number, r.resultExtras.requestId, msg.timestamp);
+ // Call listener, if any
+ if (states.listener != nullptr) {
+ states.listener->notifyShutter(r.resultExtras, msg.timestamp);
+ }
+ // send pending result and buffers
+ sendCaptureResult(states,
+ r.pendingMetadata, r.resultExtras,
+ r.collectedPartialResult, msg.frame_number,
+ r.hasInputBuffer, r.zslCapture && r.stillCapture,
+ r.rotateAndCropAuto, r.cameraIdsWithZoom, r.physicalMetadatas);
+ }
+ bool timestampIncreasing = !(r.zslCapture || r.hasInputBuffer);
+ returnOutputBuffers(
+ states.useHalBufManager, states.listener,
+ r.pendingOutputBuffers.array(),
+ r.pendingOutputBuffers.size(), r.shutterTimestamp, timestampIncreasing,
+ r.outputSurfaces, r.resultExtras);
+ r.pendingOutputBuffers.clear();
+
+ removeInFlightRequestIfReadyLocked(states, idx);
+ }
+ }
+ if (idx < 0) {
+ SET_ERR("Shutter notification for non-existent frame number %d",
+ msg.frame_number);
+ }
+}
+
+void notifyError(CaptureOutputStates& states, const camera3_error_msg_t &msg) {
+ ATRACE_CALL();
+ // Map camera HAL error codes to ICameraDeviceCallback error codes
+ // Index into this with the HAL error code
+ static const int32_t halErrorMap[CAMERA3_MSG_NUM_ERRORS] = {
+ // 0 = Unused error code
+ hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_INVALID_ERROR,
+ // 1 = CAMERA3_MSG_ERROR_DEVICE
+ hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE,
+ // 2 = CAMERA3_MSG_ERROR_REQUEST
+ hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST,
+ // 3 = CAMERA3_MSG_ERROR_RESULT
+ hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_RESULT,
+ // 4 = CAMERA3_MSG_ERROR_BUFFER
+ hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_BUFFER
+ };
+
+ int32_t errorCode =
+ ((msg.error_code >= 0) &&
+ (msg.error_code < CAMERA3_MSG_NUM_ERRORS)) ?
+ halErrorMap[msg.error_code] :
+ hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_INVALID_ERROR;
+
+ int streamId = 0;
+ String16 physicalCameraId;
+ if (msg.error_stream != nullptr) {
+ Camera3Stream *stream =
+ Camera3Stream::cast(msg.error_stream);
+ streamId = stream->getId();
+ physicalCameraId = String16(stream->physicalCameraId());
+ }
+ ALOGV("Camera %s: %s: HAL error, frame %d, stream %d: %d",
+ states.cameraId.string(), __FUNCTION__, msg.frame_number,
+ streamId, msg.error_code);
+
+ CaptureResultExtras resultExtras;
+ switch (errorCode) {
+ case hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE:
+ // SET_ERR calls into listener to notify application
+ SET_ERR("Camera HAL reported serious device error");
+ break;
+ case hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST:
+ case hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_RESULT:
+ case hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_BUFFER:
+ {
+ std::lock_guard<std::mutex> l(states.inflightLock);
+ ssize_t idx = states.inflightMap.indexOfKey(msg.frame_number);
+ if (idx >= 0) {
+ InFlightRequest &r = states.inflightMap.editValueAt(idx);
+ r.requestStatus = msg.error_code;
+ resultExtras = r.resultExtras;
+ bool logicalDeviceResultError = false;
+ if (hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_RESULT ==
+ errorCode) {
+ if (physicalCameraId.size() > 0) {
+ String8 cameraId(physicalCameraId);
+ auto iter = r.physicalCameraIds.find(cameraId);
+ if (iter == r.physicalCameraIds.end()) {
+ ALOGE("%s: Reported result failure for physical camera device: %s "
+ " which is not part of the respective request!",
+ __FUNCTION__, cameraId.string());
+ break;
+ }
+ r.physicalCameraIds.erase(iter);
+ resultExtras.errorPhysicalCameraId = physicalCameraId;
+ } else {
+ logicalDeviceResultError = true;
+ }
+ }
+
+ if (logicalDeviceResultError
+ || hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST ==
+ errorCode) {
+ r.skipResultMetadata = true;
+ }
+ if (logicalDeviceResultError) {
+ // In case of missing result check whether the buffers
+ // returned. If they returned, then remove inflight
+ // request.
+ // TODO: should we call this for ERROR_CAMERA_REQUEST as well?
+ // otherwise we are depending on HAL to send the buffers back after
+ // calling notifyError. Not sure if that's in the spec.
+ removeInFlightRequestIfReadyLocked(states, idx);
+ }
+ } else {
+ resultExtras.frameNumber = msg.frame_number;
+ ALOGE("Camera %s: %s: cannot find in-flight request on "
+ "frame %" PRId64 " error", states.cameraId.string(), __FUNCTION__,
+ resultExtras.frameNumber);
+ }
+ }
+ resultExtras.errorStreamId = streamId;
+ if (states.listener != nullptr) {
+ states.listener->notifyError(errorCode, resultExtras);
+ } else {
+ ALOGE("Camera %s: %s: no listener available",
+ states.cameraId.string(), __FUNCTION__);
+ }
+ break;
+ default:
+ // SET_ERR calls notifyError
+ SET_ERR("Unknown error message from HAL: %d", msg.error_code);
+ break;
+ }
+}
+
+void notify(CaptureOutputStates& states, const camera3_notify_msg *msg) {
+ switch (msg->type) {
+ case CAMERA3_MSG_ERROR: {
+ notifyError(states, msg->message.error);
+ break;
+ }
+ case CAMERA3_MSG_SHUTTER: {
+ notifyShutter(states, msg->message.shutter);
+ break;
+ }
+ default:
+ SET_ERR("Unknown notify message from HAL: %d",
+ msg->type);
+ }
+}
+
+void notify(CaptureOutputStates& states,
+ const hardware::camera::device::V3_2::NotifyMsg& msg) {
+ using android::hardware::camera::device::V3_2::MsgType;
+ using android::hardware::camera::device::V3_2::ErrorCode;
+
+ ATRACE_CALL();
+ camera3_notify_msg m;
+ switch (msg.type) {
+ case MsgType::ERROR:
+ m.type = CAMERA3_MSG_ERROR;
+ m.message.error.frame_number = msg.msg.error.frameNumber;
+ if (msg.msg.error.errorStreamId >= 0) {
+ sp<Camera3StreamInterface> stream =
+ states.outputStreams.get(msg.msg.error.errorStreamId);
+ if (stream == nullptr) {
+ ALOGE("%s: Frame %d: Invalid error stream id %d", __FUNCTION__,
+ m.message.error.frame_number, msg.msg.error.errorStreamId);
+ return;
+ }
+ m.message.error.error_stream = stream->asHalStream();
+ } else {
+ m.message.error.error_stream = nullptr;
+ }
+ switch (msg.msg.error.errorCode) {
+ case ErrorCode::ERROR_DEVICE:
+ m.message.error.error_code = CAMERA3_MSG_ERROR_DEVICE;
+ break;
+ case ErrorCode::ERROR_REQUEST:
+ m.message.error.error_code = CAMERA3_MSG_ERROR_REQUEST;
+ break;
+ case ErrorCode::ERROR_RESULT:
+ m.message.error.error_code = CAMERA3_MSG_ERROR_RESULT;
+ break;
+ case ErrorCode::ERROR_BUFFER:
+ m.message.error.error_code = CAMERA3_MSG_ERROR_BUFFER;
+ break;
+ }
+ break;
+ case MsgType::SHUTTER:
+ m.type = CAMERA3_MSG_SHUTTER;
+ m.message.shutter.frame_number = msg.msg.shutter.frameNumber;
+ m.message.shutter.timestamp = msg.msg.shutter.timestamp;
+ break;
+ }
+ notify(states, &m);
+}
+
+void requestStreamBuffers(RequestBufferStates& states,
+ const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
+ hardware::camera::device::V3_5::ICameraDeviceCallback::requestStreamBuffers_cb _hidl_cb) {
+ using android::hardware::camera::device::V3_2::BufferStatus;
+ using android::hardware::camera::device::V3_2::StreamBuffer;
+ using android::hardware::camera::device::V3_5::BufferRequestStatus;
+ using android::hardware::camera::device::V3_5::StreamBufferRet;
+ using android::hardware::camera::device::V3_5::StreamBufferRequestError;
+
+ std::lock_guard<std::mutex> lock(states.reqBufferLock);
+
+ hardware::hidl_vec<StreamBufferRet> bufRets;
+ if (!states.useHalBufManager) {
+ ALOGE("%s: Camera %s does not support HAL buffer management",
+ __FUNCTION__, states.cameraId.string());
+ _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
+ return;
+ }
+
+ SortedVector<int32_t> streamIds;
+ ssize_t sz = streamIds.setCapacity(bufReqs.size());
+ if (sz < 0 || static_cast<size_t>(sz) != bufReqs.size()) {
+ ALOGE("%s: failed to allocate memory for %zu buffer requests",
+ __FUNCTION__, bufReqs.size());
+ _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
+ return;
+ }
+
+ if (bufReqs.size() > states.outputStreams.size()) {
+ ALOGE("%s: too many buffer requests (%zu > # of output streams %zu)",
+ __FUNCTION__, bufReqs.size(), states.outputStreams.size());
+ _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
+ return;
+ }
+
+ // Check for repeated streamId
+ for (const auto& bufReq : bufReqs) {
+ if (streamIds.indexOf(bufReq.streamId) != NAME_NOT_FOUND) {
+ ALOGE("%s: Stream %d appear multiple times in buffer requests",
+ __FUNCTION__, bufReq.streamId);
+ _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
+ return;
+ }
+ streamIds.add(bufReq.streamId);
+ }
+
+ if (!states.reqBufferIntf.startRequestBuffer()) {
+ ALOGE("%s: request buffer disallowed while camera service is configuring",
+ __FUNCTION__);
+ _hidl_cb(BufferRequestStatus::FAILED_CONFIGURING, bufRets);
+ return;
+ }
+
+ bufRets.resize(bufReqs.size());
+
+ bool allReqsSucceeds = true;
+ bool oneReqSucceeds = false;
+ for (size_t i = 0; i < bufReqs.size(); i++) {
+ const auto& bufReq = bufReqs[i];
+ auto& bufRet = bufRets[i];
+ int32_t streamId = bufReq.streamId;
+ sp<Camera3OutputStreamInterface> outputStream = states.outputStreams.get(streamId);
+ if (outputStream == nullptr) {
+ ALOGE("%s: Output stream id %d not found!", __FUNCTION__, streamId);
+ hardware::hidl_vec<StreamBufferRet> emptyBufRets;
+ _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, emptyBufRets);
+ states.reqBufferIntf.endRequestBuffer();
+ return;
+ }
+
+ if (outputStream->isAbandoned()) {
+ bufRet.val.error(StreamBufferRequestError::STREAM_DISCONNECTED);
+ allReqsSucceeds = false;
+ continue;
+ }
+
+ bufRet.streamId = streamId;
+ size_t handOutBufferCount = outputStream->getOutstandingBuffersCount();
+ uint32_t numBuffersRequested = bufReq.numBuffersRequested;
+ size_t totalHandout = handOutBufferCount + numBuffersRequested;
+ uint32_t maxBuffers = outputStream->asHalStream()->max_buffers;
+ if (totalHandout > maxBuffers) {
+ // Not able to allocate enough buffer. Exit early for this stream
+ ALOGE("%s: request too much buffers for stream %d: at HAL: %zu + requesting: %d"
+ " > max: %d", __FUNCTION__, streamId, handOutBufferCount,
+ numBuffersRequested, maxBuffers);
+ bufRet.val.error(StreamBufferRequestError::MAX_BUFFER_EXCEEDED);
+ allReqsSucceeds = false;
+ continue;
+ }
+
+ hardware::hidl_vec<StreamBuffer> tmpRetBuffers(numBuffersRequested);
+ bool currentReqSucceeds = true;
+ std::vector<camera3_stream_buffer_t> streamBuffers(numBuffersRequested);
+ size_t numAllocatedBuffers = 0;
+ size_t numPushedInflightBuffers = 0;
+ for (size_t b = 0; b < numBuffersRequested; b++) {
+ camera3_stream_buffer_t& sb = streamBuffers[b];
+ // Since this method can run concurrently with request thread
+ // We need to update the wait duration everytime we call getbuffer
+ nsecs_t waitDuration = states.reqBufferIntf.getWaitDuration();
+ status_t res = outputStream->getBuffer(&sb, waitDuration);
+ if (res != OK) {
+ if (res == NO_INIT || res == DEAD_OBJECT) {
+ ALOGV("%s: Can't get output buffer for stream %d: %s (%d)",
+ __FUNCTION__, streamId, strerror(-res), res);
+ bufRet.val.error(StreamBufferRequestError::STREAM_DISCONNECTED);
+ } else {
+ ALOGE("%s: Can't get output buffer for stream %d: %s (%d)",
+ __FUNCTION__, streamId, strerror(-res), res);
+ if (res == TIMED_OUT || res == NO_MEMORY) {
+ bufRet.val.error(StreamBufferRequestError::NO_BUFFER_AVAILABLE);
+ } else {
+ bufRet.val.error(StreamBufferRequestError::UNKNOWN_ERROR);
+ }
+ }
+ currentReqSucceeds = false;
+ break;
+ }
+ numAllocatedBuffers++;
+
+ buffer_handle_t *buffer = sb.buffer;
+ auto pair = states.bufferRecordsIntf.getBufferId(*buffer, streamId);
+ bool isNewBuffer = pair.first;
+ uint64_t bufferId = pair.second;
+ StreamBuffer& hBuf = tmpRetBuffers[b];
+
+ hBuf.streamId = streamId;
+ hBuf.bufferId = bufferId;
+ hBuf.buffer = (isNewBuffer) ? *buffer : nullptr;
+ hBuf.status = BufferStatus::OK;
+ hBuf.releaseFence = nullptr;
+
+ native_handle_t *acquireFence = nullptr;
+ if (sb.acquire_fence != -1) {
+ acquireFence = native_handle_create(1,0);
+ acquireFence->data[0] = sb.acquire_fence;
+ }
+ hBuf.acquireFence.setTo(acquireFence, /*shouldOwn*/true);
+ hBuf.releaseFence = nullptr;
+
+ res = states.bufferRecordsIntf.pushInflightRequestBuffer(bufferId, buffer, streamId);
+ if (res != OK) {
+ ALOGE("%s: Can't get register request buffers for stream %d: %s (%d)",
+ __FUNCTION__, streamId, strerror(-res), res);
+ bufRet.val.error(StreamBufferRequestError::UNKNOWN_ERROR);
+ currentReqSucceeds = false;
+ break;
+ }
+ numPushedInflightBuffers++;
+ }
+ if (currentReqSucceeds) {
+ bufRet.val.buffers(std::move(tmpRetBuffers));
+ oneReqSucceeds = true;
+ } else {
+ allReqsSucceeds = false;
+ for (size_t b = 0; b < numPushedInflightBuffers; b++) {
+ StreamBuffer& hBuf = tmpRetBuffers[b];
+ buffer_handle_t* buffer;
+ status_t res = states.bufferRecordsIntf.popInflightRequestBuffer(
+ hBuf.bufferId, &buffer);
+ if (res != OK) {
+ SET_ERR("%s: popInflightRequestBuffer failed for stream %d: %s (%d)",
+ __FUNCTION__, streamId, strerror(-res), res);
+ }
+ }
+ for (size_t b = 0; b < numAllocatedBuffers; b++) {
+ camera3_stream_buffer_t& sb = streamBuffers[b];
+ sb.acquire_fence = -1;
+ sb.status = CAMERA3_BUFFER_STATUS_ERROR;
+ }
+ returnOutputBuffers(states.useHalBufManager, /*listener*/nullptr,
+ streamBuffers.data(), numAllocatedBuffers, 0);
+ }
+ }
+
+ _hidl_cb(allReqsSucceeds ? BufferRequestStatus::OK :
+ oneReqSucceeds ? BufferRequestStatus::FAILED_PARTIAL :
+ BufferRequestStatus::FAILED_UNKNOWN,
+ bufRets);
+ states.reqBufferIntf.endRequestBuffer();
+}
+
+void returnStreamBuffers(ReturnBufferStates& states,
+ const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers) {
+ if (!states.useHalBufManager) {
+ ALOGE("%s: Camera %s does not support HAL buffer managerment",
+ __FUNCTION__, states.cameraId.string());
+ return;
+ }
+
+ for (const auto& buf : buffers) {
+ if (buf.bufferId == BUFFER_ID_NO_BUFFER) {
+ ALOGE("%s: cannot return a buffer without bufferId", __FUNCTION__);
+ continue;
+ }
+
+ buffer_handle_t* buffer;
+ status_t res = states.bufferRecordsIntf.popInflightRequestBuffer(buf.bufferId, &buffer);
+
+ if (res != OK) {
+ ALOGE("%s: cannot find in-flight buffer %" PRIu64 " for stream %d",
+ __FUNCTION__, buf.bufferId, buf.streamId);
+ continue;
+ }
+
+ camera3_stream_buffer_t streamBuffer;
+ streamBuffer.buffer = buffer;
+ streamBuffer.status = CAMERA3_BUFFER_STATUS_ERROR;
+ streamBuffer.acquire_fence = -1;
+ streamBuffer.release_fence = -1;
+
+ if (buf.releaseFence == nullptr) {
+ streamBuffer.release_fence = -1;
+ } else if (buf.releaseFence->numFds == 1) {
+ streamBuffer.release_fence = dup(buf.releaseFence->data[0]);
+ } else {
+ ALOGE("%s: Invalid release fence, fd count is %d, not 1",
+ __FUNCTION__, buf.releaseFence->numFds);
+ continue;
+ }
+
+ sp<Camera3StreamInterface> stream = states.outputStreams.get(buf.streamId);
+ if (stream == nullptr) {
+ ALOGE("%s: Output stream id %d not found!", __FUNCTION__, buf.streamId);
+ continue;
+ }
+ streamBuffer.stream = stream->asHalStream();
+ returnOutputBuffers(states.useHalBufManager, /*listener*/nullptr,
+ &streamBuffer, /*size*/1, /*timestamp*/ 0);
+ }
+}
+
+void flushInflightRequests(FlushInflightReqStates& states) {
+ ATRACE_CALL();
+ { // First return buffers cached in mInFlightMap
+ std::lock_guard<std::mutex> l(states.inflightLock);
+ for (size_t idx = 0; idx < states.inflightMap.size(); idx++) {
+ const InFlightRequest &request = states.inflightMap.valueAt(idx);
+ returnOutputBuffers(
+ states.useHalBufManager, states.listener,
+ request.pendingOutputBuffers.array(),
+ request.pendingOutputBuffers.size(), 0,
+ /*timestampIncreasing*/true, request.outputSurfaces,
+ request.resultExtras);
+ }
+ states.inflightMap.clear();
+ states.inflightIntf.onInflightMapFlushedLocked();
+ }
+
+ // Then return all inflight buffers not returned by HAL
+ std::vector<std::pair<int32_t, int32_t>> inflightKeys;
+ states.flushBufferIntf.getInflightBufferKeys(&inflightKeys);
+
+ // Inflight buffers for HAL buffer manager
+ std::vector<uint64_t> inflightRequestBufferKeys;
+ states.flushBufferIntf.getInflightRequestBufferKeys(&inflightRequestBufferKeys);
+
+ // (streamId, frameNumber, buffer_handle_t*) tuple for all inflight buffers.
+ // frameNumber will be -1 for buffers from HAL buffer manager
+ std::vector<std::tuple<int32_t, int32_t, buffer_handle_t*>> inflightBuffers;
+ inflightBuffers.reserve(inflightKeys.size() + inflightRequestBufferKeys.size());
+
+ for (auto& pair : inflightKeys) {
+ int32_t frameNumber = pair.first;
+ int32_t streamId = pair.second;
+ buffer_handle_t* buffer;
+ status_t res = states.bufferRecordsIntf.popInflightBuffer(frameNumber, streamId, &buffer);
+ if (res != OK) {
+ ALOGE("%s: Frame %d: No in-flight buffer for stream %d",
+ __FUNCTION__, frameNumber, streamId);
+ continue;
+ }
+ inflightBuffers.push_back(std::make_tuple(streamId, frameNumber, buffer));
+ }
+
+ for (auto& bufferId : inflightRequestBufferKeys) {
+ int32_t streamId = -1;
+ buffer_handle_t* buffer = nullptr;
+ status_t res = states.bufferRecordsIntf.popInflightRequestBuffer(
+ bufferId, &buffer, &streamId);
+ if (res != OK) {
+ ALOGE("%s: cannot find in-flight buffer %" PRIu64, __FUNCTION__, bufferId);
+ continue;
+ }
+ inflightBuffers.push_back(std::make_tuple(streamId, /*frameNumber*/-1, buffer));
+ }
+
+ std::vector<sp<Camera3StreamInterface>> streams = states.flushBufferIntf.getAllStreams();
+
+ for (auto& tuple : inflightBuffers) {
+ status_t res = OK;
+ int32_t streamId = std::get<0>(tuple);
+ int32_t frameNumber = std::get<1>(tuple);
+ buffer_handle_t* buffer = std::get<2>(tuple);
+
+ camera3_stream_buffer_t streamBuffer;
+ streamBuffer.buffer = buffer;
+ streamBuffer.status = CAMERA3_BUFFER_STATUS_ERROR;
+ streamBuffer.acquire_fence = -1;
+ streamBuffer.release_fence = -1;
+
+ for (auto& stream : streams) {
+ if (streamId == stream->getId()) {
+ // Return buffer to deleted stream
+ camera3_stream* halStream = stream->asHalStream();
+ streamBuffer.stream = halStream;
+ switch (halStream->stream_type) {
+ case CAMERA3_STREAM_OUTPUT:
+ res = stream->returnBuffer(streamBuffer, /*timestamp*/ 0,
+ /*timestampIncreasing*/true, std::vector<size_t> (), frameNumber);
+ if (res != OK) {
+ ALOGE("%s: Can't return output buffer for frame %d to"
+ " stream %d: %s (%d)", __FUNCTION__,
+ frameNumber, streamId, strerror(-res), res);
+ }
+ break;
+ case CAMERA3_STREAM_INPUT:
+ res = stream->returnInputBuffer(streamBuffer);
+ if (res != OK) {
+ ALOGE("%s: Can't return input buffer for frame %d to"
+ " stream %d: %s (%d)", __FUNCTION__,
+ frameNumber, streamId, strerror(-res), res);
+ }
+ break;
+ default: // Bi-direcitonal stream is deprecated
+ ALOGE("%s: stream %d has unknown stream type %d",
+ __FUNCTION__, streamId, halStream->stream_type);
+ break;
+ }
+ break;
+ }
+ }
+ }
+}
+
+} // camera3
+} // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.h b/services/camera/libcameraservice/device3/Camera3OutputUtils.h
new file mode 100644
index 0000000..fbb47f8
--- /dev/null
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.h
@@ -0,0 +1,145 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_SERVERS_CAMERA3_OUTPUT_UTILS_H
+#define ANDROID_SERVERS_CAMERA3_OUTPUT_UTILS_H
+
+#include <memory>
+#include <mutex>
+
+#include <cutils/native_handle.h>
+
+#include <fmq/MessageQueue.h>
+
+#include <common/CameraDeviceBase.h>
+
+#include "device3/BufferUtils.h"
+#include "device3/DistortionMapper.h"
+#include "device3/ZoomRatioMapper.h"
+#include "device3/RotateAndCropMapper.h"
+#include "device3/InFlightRequest.h"
+#include "device3/Camera3Stream.h"
+#include "device3/Camera3OutputStreamInterface.h"
+#include "utils/TagMonitor.h"
+
+namespace android {
+
+using ResultMetadataQueue = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>;
+
+namespace camera3 {
+
+ /**
+ * Helper methods shared between Camera3Device/Camera3OfflineSession for HAL callbacks
+ */
+ // helper function to return the output buffers to output streams.
+ void returnOutputBuffers(
+ bool useHalBufManager,
+ sp<NotificationListener> listener, // Only needed when outputSurfaces is not empty
+ const camera3_stream_buffer_t *outputBuffers,
+ size_t numBuffers, nsecs_t timestamp, bool timestampIncreasing = true,
+ // The following arguments are only meant for surface sharing use case
+ const SurfaceMap& outputSurfaces = SurfaceMap{},
+ // Used to send buffer error callback when failing to return buffer
+ const CaptureResultExtras &resultExtras = CaptureResultExtras{});
+
+ // Camera3Device/Camera3OfflineSession internal states used in notify/processCaptureResult
+ // callbacks
+ struct CaptureOutputStates {
+ const String8& cameraId;
+ std::mutex& inflightLock;
+ InFlightRequestMap& inflightMap; // end of inflightLock scope
+ std::mutex& outputLock;
+ std::list<CaptureResult>& resultQueue;
+ std::condition_variable& resultSignal;
+ uint32_t& nextShutterFrameNum;
+ uint32_t& nextReprocShutterFrameNum;
+ uint32_t& nextZslShutterFrameNum;
+ uint32_t& nextResultFrameNum;
+ uint32_t& nextReprocResultFrameNum;
+ uint32_t& nextZslResultFrameNum; // end of outputLock scope
+ const bool useHalBufManager;
+ const bool usePartialResult;
+ const bool needFixupMonoChrome;
+ const uint32_t numPartialResults;
+ const metadata_vendor_id_t vendorTagId;
+ const CameraMetadata& deviceInfo;
+ const std::unordered_map<std::string, CameraMetadata>& physicalDeviceInfoMap;
+ std::unique_ptr<ResultMetadataQueue>& fmq;
+ std::unordered_map<std::string, camera3::DistortionMapper>& distortionMappers;
+ std::unordered_map<std::string, camera3::ZoomRatioMapper>& zoomRatioMappers;
+ std::unordered_map<std::string, camera3::RotateAndCropMapper>& rotateAndCropMappers;
+ TagMonitor& tagMonitor;
+ sp<Camera3Stream> inputStream;
+ StreamSet& outputStreams;
+ sp<NotificationListener> listener;
+ SetErrorInterface& setErrIntf;
+ InflightRequestUpdateInterface& inflightIntf;
+ BufferRecordsInterface& bufferRecordsIntf;
+ };
+
+ // Handle one capture result. Assume callers hold the lock to serialize all
+ // processCaptureResult calls
+ void processOneCaptureResultLocked(
+ CaptureOutputStates& states,
+ const hardware::camera::device::V3_2::CaptureResult& result,
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_4::PhysicalCameraMetadata> physicalCameraMetadata);
+
+ // Handle one notify message
+ void notify(CaptureOutputStates& states,
+ const hardware::camera::device::V3_2::NotifyMsg& msg);
+
+ struct RequestBufferStates {
+ const String8& cameraId;
+ std::mutex& reqBufferLock; // lock to serialize request buffer calls
+ const bool useHalBufManager;
+ StreamSet& outputStreams;
+ SetErrorInterface& setErrIntf;
+ BufferRecordsInterface& bufferRecordsIntf;
+ RequestBufferInterface& reqBufferIntf;
+ };
+
+ void requestStreamBuffers(RequestBufferStates& states,
+ const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
+ hardware::camera::device::V3_5::ICameraDeviceCallback::requestStreamBuffers_cb _hidl_cb);
+
+ struct ReturnBufferStates {
+ const String8& cameraId;
+ const bool useHalBufManager;
+ StreamSet& outputStreams;
+ BufferRecordsInterface& bufferRecordsIntf;
+ };
+
+ void returnStreamBuffers(ReturnBufferStates& states,
+ const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers);
+
+ struct FlushInflightReqStates {
+ const String8& cameraId;
+ std::mutex& inflightLock;
+ InFlightRequestMap& inflightMap; // end of inflightLock scope
+ const bool useHalBufManager;
+ sp<NotificationListener> listener;
+ InflightRequestUpdateInterface& inflightIntf;
+ BufferRecordsInterface& bufferRecordsIntf;
+ FlushBufferInterface& flushBufferIntf;
+ };
+
+ void flushInflightRequests(FlushInflightReqStates& states);
+} // namespace camera3
+
+} // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
index b5e37c2..e645e05 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
@@ -65,6 +65,12 @@
const std::vector<size_t> &removedSurfaceIds,
KeyedVector<sp<Surface>, size_t> *outputMap/*out*/);
+ virtual bool getOfflineProcessingSupport() const {
+ // As per Camera spec. shared streams currently do not support
+ // offline mode.
+ return false;
+ }
+
private:
static const size_t kMaxOutputs = 4;
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index fd9b4b0..7916ddb 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -70,7 +70,7 @@
mFormatOverridden(false),
mOriginalFormat(format),
mDataSpaceOverridden(false),
- mOriginalDataSpace(HAL_DATASPACE_UNKNOWN),
+ mOriginalDataSpace(dataSpace),
mPhysicalCameraId(physicalCameraId),
mLastTimestamp(0) {
@@ -137,9 +137,6 @@
void Camera3Stream::setDataSpaceOverride(bool dataSpaceOverridden) {
mDataSpaceOverridden = dataSpaceOverridden;
- if (dataSpaceOverridden && mOriginalDataSpace == HAL_DATASPACE_UNKNOWN) {
- mOriginalDataSpace = camera3_stream::data_space;
- }
}
bool Camera3Stream::isDataSpaceOverridden() const {
@@ -154,6 +151,14 @@
return mPhysicalCameraId;
}
+void Camera3Stream::setOfflineProcessingSupport(bool support) {
+ mSupportOfflineProcessing = support;
+}
+
+bool Camera3Stream::getOfflineProcessingSupport() const {
+ return mSupportOfflineProcessing;
+}
+
status_t Camera3Stream::forceToIdle() {
ATRACE_CALL();
Mutex::Autolock l(mLock);
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index 67afd0f..d768d3d 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -167,6 +167,9 @@
android_dataspace getOriginalDataSpace() const;
const String8& physicalCameraId() const;
+ void setOfflineProcessingSupport(bool) override;
+ bool getOfflineProcessingSupport() const override;
+
camera3_stream* asHalStream() override {
return this;
}
@@ -588,10 +591,12 @@
//Keep track of original dataSpace in case it gets overridden
bool mDataSpaceOverridden;
- android_dataspace mOriginalDataSpace;
+ const android_dataspace mOriginalDataSpace;
String8 mPhysicalCameraId;
nsecs_t mLastTimestamp;
+
+ bool mSupportOfflineProcessing = false;
}; // class Camera3Stream
}; // namespace camera3
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index 73f501a..667e3bb 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -23,6 +23,7 @@
#include "Camera3StreamBufferListener.h"
#include "Camera3StreamBufferFreedListener.h"
+struct camera3_stream;
struct camera3_stream_buffer;
namespace android {
@@ -54,6 +55,7 @@
android_dataspace dataSpace;
uint64_t consumerUsage;
bool finalized = false;
+ bool supportsOffline = false;
OutputStreamInfo() :
width(-1), height(-1), format(-1), dataSpace(HAL_DATASPACE_UNKNOWN),
consumerUsage(0) {}
@@ -99,6 +101,12 @@
virtual android_dataspace getOriginalDataSpace() const = 0;
/**
+ * Offline processing
+ */
+ virtual void setOfflineProcessingSupport(bool support) = 0;
+ virtual bool getOfflineProcessingSupport() const = 0;
+
+ /**
* Get a HAL3 handle for the stream, without starting stream configuration.
*/
virtual camera3_stream* asHalStream() = 0;
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
index 3089181..5c6c518 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
@@ -498,7 +498,7 @@
mInputSlots[bufferItem.mSlot].mFrameNumber = bufferItem.mFrameNumber;
} else {
SP_LOGE("%s: Invalid input graphic buffer!", __FUNCTION__);
- res = BAD_VALUE;
+ mOnFrameAvailableRes.store(BAD_VALUE);
return;
}
bufferId = bufferItem.mGraphicBuffer->getId();
@@ -543,6 +543,11 @@
mOnFrameAvailableRes.store(res);
}
+void Camera3StreamSplitter::onFrameReplaced(const BufferItem& item) {
+ ATRACE_CALL();
+ onFrameAvailable(item);
+}
+
void Camera3StreamSplitter::decrementBufRefCountLocked(uint64_t id, size_t surfaceId) {
ATRACE_CALL();
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
index 960f7aa..4eb455a 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
@@ -102,6 +102,13 @@
void onFrameAvailable(const BufferItem& item) override;
// From IConsumerListener
+ //
+ // Similar to onFrameAvailable, but buffer item is indeed replacing a buffer
+ // in the buffer queue. This can happen when buffer queue is in droppable
+ // mode.
+ void onFrameReplaced(const BufferItem& item) override;
+
+ // From IConsumerListener
// We don't care about released buffers because we detach each buffer as
// soon as we acquire it. See the comment for onBufferReleased below for
// some clarifying notes about the name.
diff --git a/services/camera/libcameraservice/device3/CoordinateMapper.cpp b/services/camera/libcameraservice/device3/CoordinateMapper.cpp
new file mode 100644
index 0000000..a0bbe54
--- /dev/null
+++ b/services/camera/libcameraservice/device3/CoordinateMapper.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#include <system/camera_metadata_tags.h>
+
+#include "device3/CoordinateMapper.h"
+
+namespace android {
+
+namespace camera3 {
+
+/**
+ * Metadata keys to correct when adjusting coordinates for distortion correction
+ * or for crop and rotate
+ */
+
+// Both capture request and result
+constexpr std::array<uint32_t, 3> CoordinateMapper::kMeteringRegionsToCorrect = {
+ ANDROID_CONTROL_AF_REGIONS,
+ ANDROID_CONTROL_AE_REGIONS,
+ ANDROID_CONTROL_AWB_REGIONS
+};
+
+// Both capture request and result, not applicable to crop and rotate
+constexpr std::array<uint32_t, 1> CoordinateMapper::kRectsToCorrect = {
+ ANDROID_SCALER_CROP_REGION,
+};
+
+// Only for capture result
+constexpr std::array<uint32_t, 2> CoordinateMapper::kResultPointsToCorrectNoClamp = {
+ ANDROID_STATISTICS_FACE_RECTANGLES, // Says rectangles, is really points
+ ANDROID_STATISTICS_FACE_LANDMARKS,
+};
+
+} // namespace camera3
+
+} // namespace android
diff --git a/services/camera/libcameraservice/device3/CoordinateMapper.h b/services/camera/libcameraservice/device3/CoordinateMapper.h
new file mode 100644
index 0000000..5164856
--- /dev/null
+++ b/services/camera/libcameraservice/device3/CoordinateMapper.h
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_SERVERS_COORDINATEMAPPER_H
+#define ANDROID_SERVERS_COORDINATEMAPPER_H
+
+#include <array>
+
+namespace android {
+
+namespace camera3 {
+
+class CoordinateMapper {
+ // Right now only stores metadata tags containing 2D coordinates
+ // to be corrected.
+protected:
+ // Metadata key lists to correct
+
+ // Both capture request and result
+ static const std::array<uint32_t, 3> kMeteringRegionsToCorrect;
+
+ // Both capture request and result
+ static const std::array<uint32_t, 1> kRectsToCorrect;
+
+ // Only for capture results; don't clamp
+ static const std::array<uint32_t, 2> kResultPointsToCorrectNoClamp;
+}; // class CoordinateMapper
+
+} // namespace camera3
+
+} // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/device3/DistortionMapper.cpp b/services/camera/libcameraservice/device3/DistortionMapper.cpp
index ae7af8e..8132225 100644
--- a/services/camera/libcameraservice/device3/DistortionMapper.cpp
+++ b/services/camera/libcameraservice/device3/DistortionMapper.cpp
@@ -27,41 +27,14 @@
namespace camera3 {
-/**
- * Metadata keys to correct when adjusting coordinates for distortion correction
- */
-
-// Both capture request and result
-constexpr std::array<uint32_t, 3> DistortionMapper::kMeteringRegionsToCorrect = {
- ANDROID_CONTROL_AF_REGIONS,
- ANDROID_CONTROL_AE_REGIONS,
- ANDROID_CONTROL_AWB_REGIONS
-};
-
-// Only capture request
-constexpr std::array<uint32_t, 1> DistortionMapper::kRequestRectsToCorrect = {
- ANDROID_SCALER_CROP_REGION,
-};
-
-// Only for capture result
-constexpr std::array<uint32_t, 1> DistortionMapper::kResultRectsToCorrect = {
- ANDROID_SCALER_CROP_REGION,
-};
-
-// Only for capture result
-constexpr std::array<uint32_t, 2> DistortionMapper::kResultPointsToCorrectNoClamp = {
- ANDROID_STATISTICS_FACE_RECTANGLES, // Says rectangles, is really points
- ANDROID_STATISTICS_FACE_LANDMARKS,
-};
-
DistortionMapper::DistortionMapper() : mValidMapping(false), mValidGrids(false) {
}
-bool DistortionMapper::isDistortionSupported(const CameraMetadata &result) {
+bool DistortionMapper::isDistortionSupported(const CameraMetadata &deviceInfo) {
bool isDistortionCorrectionSupported = false;
camera_metadata_ro_entry_t distortionCorrectionModes =
- result.find(ANDROID_DISTORTION_CORRECTION_AVAILABLE_MODES);
+ deviceInfo.find(ANDROID_DISTORTION_CORRECTION_AVAILABLE_MODES);
for (size_t i = 0; i < distortionCorrectionModes.count; i++) {
if (distortionCorrectionModes.data.u8[i] !=
ANDROID_DISTORTION_CORRECTION_MODE_OFF) {
@@ -124,7 +97,7 @@
if (res != OK) return res;
}
}
- for (auto rect : kRequestRectsToCorrect) {
+ for (auto rect : kRectsToCorrect) {
e = request->find(rect);
res = mapCorrectedRectToRaw(e.data.i32, e.count / 4, /*clamp*/true);
if (res != OK) return res;
@@ -160,7 +133,7 @@
if (res != OK) return res;
}
}
- for (auto rect : kResultRectsToCorrect) {
+ for (auto rect : kRectsToCorrect) {
e = result->find(rect);
res = mapRawRectToCorrected(e.data.i32, e.count / 4, /*clamp*/true);
if (res != OK) return res;
@@ -390,7 +363,6 @@
return OK;
}
-
status_t DistortionMapper::mapCorrectedRectToRaw(int32_t *rects, int rectCount, bool clamp,
bool simple) const {
if (!mValidMapping) return INVALID_OPERATION;
diff --git a/services/camera/libcameraservice/device3/DistortionMapper.h b/services/camera/libcameraservice/device3/DistortionMapper.h
index 4c0a1a6..7dcb67b 100644
--- a/services/camera/libcameraservice/device3/DistortionMapper.h
+++ b/services/camera/libcameraservice/device3/DistortionMapper.h
@@ -22,6 +22,7 @@
#include <mutex>
#include "camera/CameraMetadata.h"
+#include "device3/CoordinateMapper.h"
namespace android {
@@ -31,10 +32,19 @@
* Utilities to transform between raw (distorted) and warped (corrected) coordinate systems
* for cameras that support geometric distortion
*/
-class DistortionMapper {
+class DistortionMapper : private CoordinateMapper {
public:
DistortionMapper();
+ DistortionMapper(const DistortionMapper& other) :
+ mValidMapping(other.mValidMapping), mValidGrids(other.mValidGrids),
+ mFx(other.mFx), mFy(other.mFy), mCx(other.mCx), mCy(other.mCy), mS(other.mS),
+ mInvFx(other.mInvFx), mInvFy(other.mInvFy), mK(other.mK),
+ mArrayWidth(other.mArrayWidth), mArrayHeight(other.mArrayHeight),
+ mActiveWidth(other.mActiveWidth), mActiveHeight(other.mActiveHeight),
+ mArrayDiffX(other.mArrayDiffX), mArrayDiffY(other.mArrayDiffY),
+ mCorrectedGrid(other.mCorrectedGrid), mDistortedGrid(other.mDistortedGrid) {}
+
/**
* Check whether distortion correction is supported by the camera HAL
*/
@@ -150,20 +160,6 @@
// Fuzziness for float inequality tests
constexpr static float kFloatFuzz = 1e-4;
- // Metadata key lists to correct
-
- // Both capture request and result
- static const std::array<uint32_t, 3> kMeteringRegionsToCorrect;
-
- // Only capture request
- static const std::array<uint32_t, 1> kRequestRectsToCorrect;
-
- // Only capture result
- static const std::array<uint32_t, 1> kResultRectsToCorrect;
-
- // Only for capture results; don't clamp
- static const std::array<uint32_t, 2> kResultPointsToCorrectNoClamp;
-
// Single implementation for various mapCorrectedToRaw methods
template<typename T>
status_t mapCorrectedToRawImpl(T* coordPairs, int coordCount, bool clamp, bool simple) const;
@@ -186,7 +182,7 @@
// pre-calculated inverses for speed
float mInvFx, mInvFy;
// radial/tangential distortion parameters
- float mK[5];
+ std::array<float, 5> mK;
// pre-correction active array dimensions
float mArrayWidth, mArrayHeight;
diff --git a/services/camera/libcameraservice/device3/InFlightRequest.h b/services/camera/libcameraservice/device3/InFlightRequest.h
new file mode 100644
index 0000000..424043b
--- /dev/null
+++ b/services/camera/libcameraservice/device3/InFlightRequest.h
@@ -0,0 +1,153 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_SERVERS_CAMERA3_INFLIGHT_REQUEST_H
+#define ANDROID_SERVERS_CAMERA3_INFLIGHT_REQUEST_H
+
+#include <set>
+
+#include <camera/CaptureResult.h>
+#include <camera/CameraMetadata.h>
+#include <utils/String8.h>
+#include <utils/Timers.h>
+
+#include "hardware/camera3.h"
+
+#include "common/CameraDeviceBase.h"
+
+namespace android {
+
+namespace camera3 {
+
+struct InFlightRequest {
+ // Set by notify() SHUTTER call.
+ nsecs_t shutterTimestamp;
+ // Set by process_capture_result().
+ nsecs_t sensorTimestamp;
+ int requestStatus;
+ // Set by process_capture_result call with valid metadata
+ bool haveResultMetadata;
+ // Decremented by calls to process_capture_result with valid output
+ // and input buffers
+ int numBuffersLeft;
+ CaptureResultExtras resultExtras;
+ // If this request has any input buffer
+ bool hasInputBuffer;
+
+ // The last metadata that framework receives from HAL and
+ // not yet send out because the shutter event hasn't arrived.
+ // It's added by process_capture_result and sent when framework
+ // receives the shutter event.
+ CameraMetadata pendingMetadata;
+
+ // The metadata of the partial results that framework receives from HAL so far
+ // and has sent out.
+ CameraMetadata collectedPartialResult;
+
+ // Buffers are added by process_capture_result when output buffers
+ // return from HAL but framework has not yet received the shutter
+ // event. They will be returned to the streams when framework receives
+ // the shutter event.
+ Vector<camera3_stream_buffer_t> pendingOutputBuffers;
+
+ // Whether this inflight request's shutter and result callback are to be
+ // called. The policy is that if the request is the last one in the constrained
+ // high speed recording request list, this flag will be true. If the request list
+ // is not for constrained high speed recording, this flag will also be true.
+ bool hasCallback;
+
+ // Maximum expected frame duration for this request.
+ // For manual captures, equal to the max of requested exposure time and frame duration
+ // For auto-exposure modes, equal to 1/(lower end of target FPS range)
+ nsecs_t maxExpectedDuration;
+
+ // Whether the result metadata for this request is to be skipped. The
+ // result metadata should be skipped in the case of
+ // REQUEST/RESULT error.
+ bool skipResultMetadata;
+
+ // The physical camera ids being requested.
+ std::set<String8> physicalCameraIds;
+
+ // Map of physicalCameraId <-> Metadata
+ std::vector<PhysicalCaptureResultInfo> physicalMetadatas;
+
+ // Indicates a still capture request.
+ bool stillCapture;
+
+ // Indicates a ZSL capture request
+ bool zslCapture;
+
+ // Indicates that ROTATE_AND_CROP was set to AUTO
+ bool rotateAndCropAuto;
+
+ // Requested camera ids (both logical and physical) with zoomRatio != 1.0f
+ std::set<std::string> cameraIdsWithZoom;
+
+ // What shared surfaces an output should go to
+ SurfaceMap outputSurfaces;
+
+ // TODO: dedupe
+ static const nsecs_t kDefaultExpectedDuration = 100000000; // 100 ms
+
+ // Default constructor needed by KeyedVector
+ InFlightRequest() :
+ shutterTimestamp(0),
+ sensorTimestamp(0),
+ requestStatus(OK),
+ haveResultMetadata(false),
+ numBuffersLeft(0),
+ hasInputBuffer(false),
+ hasCallback(true),
+ maxExpectedDuration(kDefaultExpectedDuration),
+ skipResultMetadata(false),
+ stillCapture(false),
+ zslCapture(false),
+ rotateAndCropAuto(false) {
+ }
+
+ InFlightRequest(int numBuffers, CaptureResultExtras extras, bool hasInput,
+ bool hasAppCallback, nsecs_t maxDuration,
+ const std::set<String8>& physicalCameraIdSet, bool isStillCapture,
+ bool isZslCapture, bool rotateAndCropAuto, const std::set<std::string>& idsWithZoom,
+ const SurfaceMap& outSurfaces = SurfaceMap{}) :
+ shutterTimestamp(0),
+ sensorTimestamp(0),
+ requestStatus(OK),
+ haveResultMetadata(false),
+ numBuffersLeft(numBuffers),
+ resultExtras(extras),
+ hasInputBuffer(hasInput),
+ hasCallback(hasAppCallback),
+ maxExpectedDuration(maxDuration),
+ skipResultMetadata(false),
+ physicalCameraIds(physicalCameraIdSet),
+ stillCapture(isStillCapture),
+ zslCapture(isZslCapture),
+ rotateAndCropAuto(rotateAndCropAuto),
+ cameraIdsWithZoom(idsWithZoom),
+ outputSurfaces(outSurfaces) {
+ }
+};
+
+// Map from frame number to the in-flight request state
+typedef KeyedVector<uint32_t, InFlightRequest> InFlightRequestMap;
+
+} // namespace camera3
+
+} // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/device3/RotateAndCropMapper.cpp b/services/camera/libcameraservice/device3/RotateAndCropMapper.cpp
new file mode 100644
index 0000000..3718f54
--- /dev/null
+++ b/services/camera/libcameraservice/device3/RotateAndCropMapper.cpp
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Camera3-RotCropMapper"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <algorithm>
+#include <cmath>
+
+#include "device3/RotateAndCropMapper.h"
+
+namespace android {
+
+namespace camera3 {
+
+bool RotateAndCropMapper::isNeeded(const CameraMetadata* deviceInfo) {
+ auto entry = deviceInfo->find(ANDROID_SCALER_AVAILABLE_ROTATE_AND_CROP_MODES);
+ for (size_t i = 0; i < entry.count; i++) {
+ if (entry.data.u8[i] == ANDROID_SCALER_ROTATE_AND_CROP_AUTO) return true;
+ }
+ return false;
+}
+
+RotateAndCropMapper::RotateAndCropMapper(const CameraMetadata* deviceInfo) {
+ auto entry = deviceInfo->find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+ if (entry.count != 4) return;
+
+ mArrayWidth = entry.data.i32[2];
+ mArrayHeight = entry.data.i32[3];
+ mArrayAspect = static_cast<float>(mArrayWidth) / mArrayHeight;
+ mRotateAspect = 1.f/mArrayAspect;
+}
+
+/**
+ * Adjust capture request when rotate and crop AUTO is enabled
+ */
+status_t RotateAndCropMapper::updateCaptureRequest(CameraMetadata *request) {
+ auto entry = request->find(ANDROID_SCALER_ROTATE_AND_CROP);
+ if (entry.count == 0) return OK;
+ uint8_t rotateMode = entry.data.u8[0];
+ if (rotateMode == ANDROID_SCALER_ROTATE_AND_CROP_NONE) return OK;
+
+ int32_t cx = 0;
+ int32_t cy = 0;
+ int32_t cw = mArrayWidth;
+ int32_t ch = mArrayHeight;
+ entry = request->find(ANDROID_SCALER_CROP_REGION);
+ if (entry.count == 4) {
+ cx = entry.data.i32[0];
+ cy = entry.data.i32[1];
+ cw = entry.data.i32[2];
+ ch = entry.data.i32[3];
+ }
+
+ // User inputs are relative to the rotated-and-cropped view, so convert back
+ // to active array coordinates. To be more specific, the application is
+ // calculating coordinates based on the crop rectangle and the active array,
+ // even though the view the user sees is the cropped-and-rotated one. So we
+ // need to adjust the coordinates so that a point that would be on the
+ // top-left corner of the crop region is mapped to the top-left corner of
+ // the rotated-and-cropped fov within the crop region, and the same for the
+ // bottom-right corner.
+ //
+ // Since the zoom ratio control scales everything uniformly (so an app does
+ // not need to adjust anything if it wants to put a metering region on the
+ // top-left quadrant of the preview FOV, when changing zoomRatio), it does
+ // not need to be factored into this calculation at all.
+ //
+ // ->+x active array aw
+ // |+--------------------------------------------------------------------+
+ // v| |
+ // +y| a 1 cw 2 b |
+ // | +=========*HHHHHHHHHHHHHHH*===========+ |
+ // | I H rw H I |
+ // | I H H I |
+ // | I H H I |
+ //ah | ch I H rh H I crop region |
+ // | I H H I |
+ // | I H H I |
+ // | I H rotate region H I |
+ // | +=========*HHHHHHHHHHHHHHH*===========+ |
+ // | d 4 3 c |
+ // | |
+ // +--------------------------------------------------------------------+
+ //
+ // aw , ah = active array width,height
+ // cw , ch = crop region width,height
+ // rw , rh = rotated-and-cropped region width,height
+ // aw / ah = array aspect = rh / rw = 1 / rotated aspect
+ // Coordinate mappings:
+ // ROTATE_AND_CROP_90: point a -> point 2
+ // point c -> point 4 = +x -> +y, +y -> -x
+ // ROTATE_AND_CROP_180: point a -> point c
+ // point c -> point a = +x -> -x, +y -> -y
+ // ROTATE_AND_CROP_270: point a -> point 4
+ // point c -> point 2 = +x -> -y, +y -> +x
+
+ float cropAspect = static_cast<float>(cw) / ch;
+ float transformMat[4] = {0, 0,
+ 0, 0};
+ float xShift = 0;
+ float yShift = 0;
+
+ if (rotateMode == ANDROID_SCALER_ROTATE_AND_CROP_180) {
+ transformMat[0] = -1;
+ transformMat[3] = -1;
+ xShift = cw;
+ yShift = ch;
+ } else {
+ float rw = cropAspect > mRotateAspect ?
+ ch * mRotateAspect : // pillarbox, not full width
+ cw; // letterbox or 1:1, full width
+ float rh = cropAspect >= mRotateAspect ?
+ ch : // pillarbox or 1:1, full height
+ cw / mRotateAspect; // letterbox, not full height
+ switch (rotateMode) {
+ case ANDROID_SCALER_ROTATE_AND_CROP_90:
+ transformMat[1] = -rw / ch; // +y -> -x
+ transformMat[2] = rh / cw; // +x -> +y
+ xShift = (cw + rw) / 2; // left edge of crop to right edge of rotated
+ yShift = (ch - rh) / 2; // top edge of crop to top edge of rotated
+ break;
+ case ANDROID_SCALER_ROTATE_AND_CROP_270:
+ transformMat[1] = rw / ch; // +y -> +x
+ transformMat[2] = -rh / cw; // +x -> -y
+ xShift = (cw - rw) / 2; // left edge of crop to left edge of rotated
+ yShift = (ch + rh) / 2; // top edge of crop to bottom edge of rotated
+ break;
+ default:
+ ALOGE("%s: Unexpected rotate mode: %d", __FUNCTION__, rotateMode);
+ return BAD_VALUE;
+ }
+ }
+
+ for (auto regionTag : kMeteringRegionsToCorrect) {
+ entry = request->find(regionTag);
+ for (size_t i = 0; i < entry.count; i += 5) {
+ int32_t weight = entry.data.i32[i + 4];
+ if (weight == 0) {
+ continue;
+ }
+ transformPoints(entry.data.i32 + i, 2, transformMat, xShift, yShift, cx, cy);
+ swapRectToMinFirst(entry.data.i32 + i);
+ }
+ }
+
+ return OK;
+}
+
+/**
+ * Adjust capture result when rotate and crop AUTO is enabled
+ */
+status_t RotateAndCropMapper::updateCaptureResult(CameraMetadata *result) {
+ auto entry = result->find(ANDROID_SCALER_ROTATE_AND_CROP);
+ if (entry.count == 0) return OK;
+ uint8_t rotateMode = entry.data.u8[0];
+ if (rotateMode == ANDROID_SCALER_ROTATE_AND_CROP_NONE) return OK;
+
+ int32_t cx = 0;
+ int32_t cy = 0;
+ int32_t cw = mArrayWidth;
+ int32_t ch = mArrayHeight;
+ entry = result->find(ANDROID_SCALER_CROP_REGION);
+ if (entry.count == 4) {
+ cx = entry.data.i32[0];
+ cy = entry.data.i32[1];
+ cw = entry.data.i32[2];
+ ch = entry.data.i32[3];
+ }
+
+ // HAL inputs are relative to the full active array, so convert back to
+ // rotated-and-cropped coordinates for apps. To be more specific, the
+ // application is calculating coordinates based on the crop rectangle and
+ // the active array, even though the view the user sees is the
+ // cropped-and-rotated one. So we need to adjust the coordinates so that a
+ // point that would be on the top-left corner of the rotate-and-cropped
+ // region is mapped to the top-left corner of the crop region, and the same
+ // for the bottom-right corner.
+ //
+ // Since the zoom ratio control scales everything uniformly (so an app does
+ // not need to adjust anything if it wants to put a metering region on the
+ // top-left quadrant of the preview FOV, when changing zoomRatio), it does
+ // not need to be factored into this calculation at all.
+ //
+ // Also note that round-tripping between original request and final result
+ // fields can't be perfect, since the intermediate values have to be
+ // integers on a smaller range than the original crop region range. That
+ // means that multiple input values map to a single output value in
+ // adjusting a request, so when adjusting a result, the original answer may
+ // not be obtainable. Given that aspect ratios are rarely > 16/9, the
+ // round-trip values should generally only be off by 1 at most.
+ //
+ // ->+x active array aw
+ // |+--------------------------------------------------------------------+
+ // v| |
+ // +y| a 1 cw 2 b |
+ // | +=========*HHHHHHHHHHHHHHH*===========+ |
+ // | I H rw H I |
+ // | I H H I |
+ // | I H H I |
+ //ah | ch I H rh H I crop region |
+ // | I H H I |
+ // | I H H I |
+ // | I H rotate region H I |
+ // | +=========*HHHHHHHHHHHHHHH*===========+ |
+ // | d 4 3 c |
+ // | |
+ // +--------------------------------------------------------------------+
+ //
+ // aw , ah = active array width,height
+ // cw , ch = crop region width,height
+ // rw , rh = rotated-and-cropped region width,height
+ // aw / ah = array aspect = rh / rw = 1 / rotated aspect
+ // Coordinate mappings:
+ // ROTATE_AND_CROP_90: point 2 -> point a
+ // point 4 -> point c = +x -> -y, +y -> +x
+ // ROTATE_AND_CROP_180: point c -> point a
+ // point a -> point c = +x -> -x, +y -> -y
+ // ROTATE_AND_CROP_270: point 4 -> point a
+ // point 2 -> point c = +x -> +y, +y -> -x
+
+ float cropAspect = static_cast<float>(cw) / ch;
+ float transformMat[4] = {0, 0,
+ 0, 0};
+ float xShift = 0;
+ float yShift = 0;
+ float rx = 0; // top-left corner of rotated region
+ float ry = 0;
+ if (rotateMode == ANDROID_SCALER_ROTATE_AND_CROP_180) {
+ transformMat[0] = -1;
+ transformMat[3] = -1;
+ xShift = cw;
+ yShift = ch;
+ rx = cx;
+ ry = cy;
+ } else {
+ float rw = cropAspect > mRotateAspect ?
+ ch * mRotateAspect : // pillarbox, not full width
+ cw; // letterbox or 1:1, full width
+ float rh = cropAspect >= mRotateAspect ?
+ ch : // pillarbox or 1:1, full height
+ cw / mRotateAspect; // letterbox, not full height
+ rx = cx + (cw - rw) / 2;
+ ry = cy + (ch - rh) / 2;
+ switch (rotateMode) {
+ case ANDROID_SCALER_ROTATE_AND_CROP_90:
+ transformMat[1] = ch / rw; // +y -> +x
+ transformMat[2] = -cw / rh; // +x -> -y
+ xShift = -(cw - rw) / 2; // left edge of rotated to left edge of cropped
+ yShift = ry - cy + ch; // top edge of rotated to bottom edge of cropped
+ break;
+ case ANDROID_SCALER_ROTATE_AND_CROP_270:
+ transformMat[1] = -ch / rw; // +y -> -x
+ transformMat[2] = cw / rh; // +x -> +y
+ xShift = (cw + rw) / 2; // left edge of rotated to left edge of cropped
+ yShift = (ch - rh) / 2; // top edge of rotated to bottom edge of cropped
+ break;
+ default:
+ ALOGE("%s: Unexpected rotate mode: %d", __FUNCTION__, rotateMode);
+ return BAD_VALUE;
+ }
+ }
+
+ for (auto regionTag : kMeteringRegionsToCorrect) {
+ entry = result->find(regionTag);
+ for (size_t i = 0; i < entry.count; i += 5) {
+ int32_t weight = entry.data.i32[i + 4];
+ if (weight == 0) {
+ continue;
+ }
+ transformPoints(entry.data.i32 + i, 2, transformMat, xShift, yShift, rx, ry);
+ swapRectToMinFirst(entry.data.i32 + i);
+ }
+ }
+
+ for (auto pointsTag: kResultPointsToCorrectNoClamp) {
+ entry = result->find(pointsTag);
+ transformPoints(entry.data.i32, entry.count / 2, transformMat, xShift, yShift, rx, ry);
+ if (pointsTag == ANDROID_STATISTICS_FACE_RECTANGLES) {
+ for (size_t i = 0; i < entry.count; i += 4) {
+ swapRectToMinFirst(entry.data.i32 + i);
+ }
+ }
+ }
+
+ return OK;
+}
+
+void RotateAndCropMapper::transformPoints(int32_t* pts, size_t count, float transformMat[4],
+ float xShift, float yShift, float ox, float oy) {
+ for (size_t i = 0; i < count * 2; i += 2) {
+ float x0 = pts[i] - ox;
+ float y0 = pts[i + 1] - oy;
+ int32_t nx = std::round(transformMat[0] * x0 + transformMat[1] * y0 + xShift + ox);
+ int32_t ny = std::round(transformMat[2] * x0 + transformMat[3] * y0 + yShift + oy);
+
+ pts[i] = std::min(std::max(nx, 0), mArrayWidth);
+ pts[i + 1] = std::min(std::max(ny, 0), mArrayHeight);
+ }
+}
+
+void RotateAndCropMapper::swapRectToMinFirst(int32_t* rect) {
+ if (rect[0] > rect[2]) {
+ auto tmp = rect[0];
+ rect[0] = rect[2];
+ rect[2] = tmp;
+ }
+ if (rect[1] > rect[3]) {
+ auto tmp = rect[1];
+ rect[1] = rect[3];
+ rect[3] = tmp;
+ }
+}
+
+} // namespace camera3
+
+} // namespace android
diff --git a/services/camera/libcameraservice/device3/RotateAndCropMapper.h b/services/camera/libcameraservice/device3/RotateAndCropMapper.h
new file mode 100644
index 0000000..459e27f
--- /dev/null
+++ b/services/camera/libcameraservice/device3/RotateAndCropMapper.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SERVERS_ROTATEANDCROPMAPPER_H
+#define ANDROID_SERVERS_ROTATEANDCROPMAPPER_H
+
+#include <utils/Errors.h>
+#include <array>
+#include <mutex>
+
+#include "camera/CameraMetadata.h"
+#include "device3/CoordinateMapper.h"
+
+namespace android {
+
+namespace camera3 {
+
+/**
+ * Utilities to transform between unrotated and rotated-and-cropped coordinate systems
+ * for cameras that support SCALER_ROTATE_AND_CROP controls in AUTO mode.
+ */
+class RotateAndCropMapper : private CoordinateMapper {
+ public:
+ static bool isNeeded(const CameraMetadata* deviceInfo);
+
+ RotateAndCropMapper(const CameraMetadata* deviceInfo);
+
+ /**
+ * Adjust capture request assuming rotate and crop AUTO is enabled
+ */
+ status_t updateCaptureRequest(CameraMetadata *request);
+
+ /**
+ * Adjust capture result assuming rotate and crop AUTO is enabled
+ */
+ status_t updateCaptureResult(CameraMetadata *result);
+
+ private:
+ // Transform count's worth of x,y points passed in with 2x2 matrix + translate with transform
+ // origin (cx,cy)
+ void transformPoints(int32_t* pts, size_t count, float transformMat[4],
+ float xShift, float yShift, float cx, float cy);
+ // Take two corners of a rect as (x1,y1,x2,y2) and swap x and y components
+ // if needed so that x1 < x2, y1 < y2.
+ void swapRectToMinFirst(int32_t* rect);
+
+ int32_t mArrayWidth, mArrayHeight;
+ float mArrayAspect, mRotateAspect;
+}; // class RotateAndCroMapper
+
+} // namespace camera3
+
+} // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp b/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
new file mode 100644
index 0000000..84da45a
--- /dev/null
+++ b/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
@@ -0,0 +1,370 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "Camera3-ZoomRatioMapper"
+//#define LOG_NDEBUG 0
+
+#include <algorithm>
+
+#include "device3/ZoomRatioMapper.h"
+
+namespace android {
+
+namespace camera3 {
+
+
+status_t ZoomRatioMapper::initZoomRatioInTemplate(CameraMetadata *request) {
+ camera_metadata_entry_t entry;
+ entry = request->find(ANDROID_CONTROL_ZOOM_RATIO);
+ float defaultZoomRatio = 1.0f;
+ if (entry.count == 0) {
+ return request->update(ANDROID_CONTROL_ZOOM_RATIO, &defaultZoomRatio, 1);
+ }
+ return OK;
+}
+
+status_t ZoomRatioMapper::overrideZoomRatioTags(
+ CameraMetadata* deviceInfo, bool* supportNativeZoomRatio) {
+ if (deviceInfo == nullptr || supportNativeZoomRatio == nullptr) {
+ return BAD_VALUE;
+ }
+
+ camera_metadata_entry_t entry;
+ entry = deviceInfo->find(ANDROID_CONTROL_ZOOM_RATIO_RANGE);
+ if (entry.count != 2 && entry.count != 0) return BAD_VALUE;
+
+ // Hal has zoom ratio support
+ if (entry.count == 2) {
+ *supportNativeZoomRatio = true;
+ return OK;
+ }
+
+ // Hal has no zoom ratio support
+ *supportNativeZoomRatio = false;
+
+ entry = deviceInfo->find(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM);
+ if (entry.count != 1) {
+ ALOGI("%s: Camera device doesn't support SCALER_AVAILABLE_MAX_DIGITAL_ZOOM key!",
+ __FUNCTION__);
+ return OK;
+ }
+
+ float zoomRange[] = {1.0f, entry.data.f[0]};
+ status_t res = deviceInfo->update(ANDROID_CONTROL_ZOOM_RATIO_RANGE, zoomRange, 2);
+ if (res != OK) {
+ ALOGE("%s: Failed to update CONTROL_ZOOM_RATIO_RANGE key: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+
+ std::vector<int32_t> requestKeys;
+ entry = deviceInfo->find(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS);
+ if (entry.count > 0) {
+ requestKeys.insert(requestKeys.end(), entry.data.i32, entry.data.i32 + entry.count);
+ }
+ requestKeys.push_back(ANDROID_CONTROL_ZOOM_RATIO);
+ res = deviceInfo->update(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS,
+ requestKeys.data(), requestKeys.size());
+ if (res != OK) {
+ ALOGE("%s: Failed to update REQUEST_AVAILABLE_REQUEST_KEYS: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+
+ std::vector<int32_t> resultKeys;
+ entry = deviceInfo->find(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS);
+ if (entry.count > 0) {
+ resultKeys.insert(resultKeys.end(), entry.data.i32, entry.data.i32 + entry.count);
+ }
+ resultKeys.push_back(ANDROID_CONTROL_ZOOM_RATIO);
+ res = deviceInfo->update(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS,
+ resultKeys.data(), resultKeys.size());
+ if (res != OK) {
+ ALOGE("%s: Failed to update REQUEST_AVAILABLE_RESULT_KEYS: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+
+ std::vector<int32_t> charKeys;
+ entry = deviceInfo->find(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS);
+ if (entry.count > 0) {
+ charKeys.insert(charKeys.end(), entry.data.i32, entry.data.i32 + entry.count);
+ }
+ charKeys.push_back(ANDROID_CONTROL_ZOOM_RATIO_RANGE);
+ res = deviceInfo->update(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,
+ charKeys.data(), charKeys.size());
+ if (res != OK) {
+ ALOGE("%s: Failed to update REQUEST_AVAILABLE_CHARACTERISTICS_KEYS: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+
+ return OK;
+}
+
+ZoomRatioMapper::ZoomRatioMapper(const CameraMetadata* deviceInfo,
+ bool supportNativeZoomRatio, bool usePrecorrectArray) {
+ camera_metadata_ro_entry_t entry;
+
+ entry = deviceInfo->find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
+ if (entry.count != 4) return;
+ int32_t arrayW = entry.data.i32[2];
+ int32_t arrayH = entry.data.i32[3];
+
+ entry = deviceInfo->find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+ if (entry.count != 4) return;
+ int32_t activeW = entry.data.i32[2];
+ int32_t activeH = entry.data.i32[3];
+
+ if (usePrecorrectArray) {
+ mArrayWidth = arrayW;
+ mArrayHeight = arrayH;
+ } else {
+ mArrayWidth = activeW;
+ mArrayHeight = activeH;
+ }
+ mHalSupportsZoomRatio = supportNativeZoomRatio;
+
+ ALOGV("%s: array size: %d x %d, mHalSupportsZoomRatio %d",
+ __FUNCTION__, mArrayWidth, mArrayHeight, mHalSupportsZoomRatio);
+ mIsValid = true;
+}
+
+status_t ZoomRatioMapper::updateCaptureRequest(CameraMetadata* request) {
+ if (!mIsValid) return INVALID_OPERATION;
+
+ status_t res = OK;
+ bool zoomRatioIs1 = true;
+ camera_metadata_entry_t entry;
+
+ entry = request->find(ANDROID_CONTROL_ZOOM_RATIO);
+ if (entry.count == 1 && entry.data.f[0] != 1.0f) {
+ zoomRatioIs1 = false;
+ }
+
+ if (mHalSupportsZoomRatio && zoomRatioIs1) {
+ res = separateZoomFromCropLocked(request, false/*isResult*/);
+ } else if (!mHalSupportsZoomRatio && !zoomRatioIs1) {
+ res = combineZoomAndCropLocked(request, false/*isResult*/);
+ }
+
+ // If CONTROL_ZOOM_RATIO is in request, but HAL doesn't support
+ // CONTROL_ZOOM_RATIO, remove it from the request.
+ if (!mHalSupportsZoomRatio && entry.count == 1) {
+ request->erase(ANDROID_CONTROL_ZOOM_RATIO);
+ }
+
+ return res;
+}
+
+status_t ZoomRatioMapper::updateCaptureResult(CameraMetadata* result, bool requestedZoomRatioIs1) {
+ if (!mIsValid) return INVALID_OPERATION;
+
+ status_t res = OK;
+
+ if (mHalSupportsZoomRatio && requestedZoomRatioIs1) {
+ res = combineZoomAndCropLocked(result, true/*isResult*/);
+ } else if (!mHalSupportsZoomRatio && !requestedZoomRatioIs1) {
+ res = separateZoomFromCropLocked(result, true/*isResult*/);
+ } else {
+ camera_metadata_entry_t entry = result->find(ANDROID_CONTROL_ZOOM_RATIO);
+ if (entry.count == 0) {
+ float zoomRatio1x = 1.0f;
+ result->update(ANDROID_CONTROL_ZOOM_RATIO, &zoomRatio1x, 1);
+ }
+ }
+
+ return res;
+}
+
+float ZoomRatioMapper::deriveZoomRatio(const CameraMetadata* metadata) {
+ float zoomRatio = 1.0;
+
+ camera_metadata_ro_entry_t entry;
+ entry = metadata->find(ANDROID_SCALER_CROP_REGION);
+ if (entry.count != 4) return zoomRatio;
+
+ // Center of the preCorrection/active size
+ float arrayCenterX = mArrayWidth / 2.0;
+ float arrayCenterY = mArrayHeight / 2.0;
+
+ // Re-map crop region to coordinate system centered to (arrayCenterX,
+ // arrayCenterY).
+ float cropRegionLeft = arrayCenterX - entry.data.i32[0] ;
+ float cropRegionTop = arrayCenterY - entry.data.i32[1];
+ float cropRegionRight = entry.data.i32[0] + entry.data.i32[2] - arrayCenterX;
+ float cropRegionBottom = entry.data.i32[1] + entry.data.i32[3] - arrayCenterY;
+
+ // Calculate the scaling factor for left, top, bottom, right
+ float zoomRatioLeft = std::max(mArrayWidth / (2 * cropRegionLeft), 1.0f);
+ float zoomRatioTop = std::max(mArrayHeight / (2 * cropRegionTop), 1.0f);
+ float zoomRatioRight = std::max(mArrayWidth / (2 * cropRegionRight), 1.0f);
+ float zoomRatioBottom = std::max(mArrayHeight / (2 * cropRegionBottom), 1.0f);
+
+ // Use minimum scaling factor to handle letterboxing or pillarboxing
+ zoomRatio = std::min(std::min(zoomRatioLeft, zoomRatioRight),
+ std::min(zoomRatioTop, zoomRatioBottom));
+
+ ALOGV("%s: derived zoomRatio is %f", __FUNCTION__, zoomRatio);
+ return zoomRatio;
+}
+
+status_t ZoomRatioMapper::separateZoomFromCropLocked(CameraMetadata* metadata, bool isResult) {
+ status_t res;
+ float zoomRatio = deriveZoomRatio(metadata);
+
+ // Update zoomRatio metadata tag
+ res = metadata->update(ANDROID_CONTROL_ZOOM_RATIO, &zoomRatio, 1);
+ if (res != OK) {
+ ALOGE("%s: Failed to update ANDROID_CONTROL_ZOOM_RATIO: %s(%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+
+ // Scale regions using zoomRatio
+ camera_metadata_entry_t entry;
+ for (auto region : kMeteringRegionsToCorrect) {
+ entry = metadata->find(region);
+ for (size_t j = 0; j < entry.count; j += 5) {
+ int32_t weight = entry.data.i32[j + 4];
+ if (weight == 0) {
+ continue;
+ }
+ // Top-left is inclusively clamped
+ scaleCoordinates(entry.data.i32 + j, 1, zoomRatio, ClampInclusive);
+ // Bottom-right is exclusively clamped
+ scaleCoordinates(entry.data.i32 + j + 2, 1, zoomRatio, ClampExclusive);
+ }
+ }
+
+ for (auto rect : kRectsToCorrect) {
+ entry = metadata->find(rect);
+ scaleRects(entry.data.i32, entry.count / 4, zoomRatio);
+ }
+
+ if (isResult) {
+ for (auto pts : kResultPointsToCorrectNoClamp) {
+ entry = metadata->find(pts);
+ scaleCoordinates(entry.data.i32, entry.count / 2, zoomRatio, ClampOff);
+ }
+ }
+
+ return OK;
+}
+
+status_t ZoomRatioMapper::combineZoomAndCropLocked(CameraMetadata* metadata, bool isResult) {
+ float zoomRatio = 1.0f;
+ camera_metadata_entry_t entry;
+ entry = metadata->find(ANDROID_CONTROL_ZOOM_RATIO);
+ if (entry.count == 1) {
+ zoomRatio = entry.data.f[0];
+ }
+
+ // Unscale regions with zoomRatio
+ status_t res;
+ for (auto region : kMeteringRegionsToCorrect) {
+ entry = metadata->find(region);
+ for (size_t j = 0; j < entry.count; j += 5) {
+ int32_t weight = entry.data.i32[j + 4];
+ if (weight == 0) {
+ continue;
+ }
+ // Top-left is inclusively clamped
+ scaleCoordinates(entry.data.i32 + j, 1, 1.0 / zoomRatio, ClampInclusive);
+ // Bottom-right is exclusively clamped
+ scaleCoordinates(entry.data.i32 + j + 2, 1, 1.0 / zoomRatio, ClampExclusive);
+ }
+ }
+ for (auto rect : kRectsToCorrect) {
+ entry = metadata->find(rect);
+ scaleRects(entry.data.i32, entry.count / 4, 1.0 / zoomRatio);
+ }
+ if (isResult) {
+ for (auto pts : kResultPointsToCorrectNoClamp) {
+ entry = metadata->find(pts);
+ scaleCoordinates(entry.data.i32, entry.count / 2, 1.0 / zoomRatio, ClampOff);
+ }
+ }
+
+ zoomRatio = 1.0;
+ res = metadata->update(ANDROID_CONTROL_ZOOM_RATIO, &zoomRatio, 1);
+ if (res != OK) {
+ return res;
+ }
+
+ return OK;
+}
+
+void ZoomRatioMapper::scaleCoordinates(int32_t* coordPairs, int coordCount,
+ float scaleRatio, ClampMode clamp) {
+ for (int i = 0; i < coordCount * 2; i += 2) {
+ float x = coordPairs[i];
+ float y = coordPairs[i + 1];
+ float xCentered = x - mArrayWidth / 2;
+ float yCentered = y - mArrayHeight / 2;
+ float scaledX = xCentered * scaleRatio;
+ float scaledY = yCentered * scaleRatio;
+ scaledX += mArrayWidth / 2;
+ scaledY += mArrayHeight / 2;
+ // Clamp to within activeArray/preCorrectionActiveArray
+ coordPairs[i] = static_cast<int32_t>(scaledX);
+ coordPairs[i+1] = static_cast<int32_t>(scaledY);
+ if (clamp != ClampOff) {
+ int32_t right, bottom;
+ if (clamp == ClampInclusive) {
+ right = mArrayWidth - 1;
+ bottom = mArrayHeight - 1;
+ } else {
+ right = mArrayWidth;
+ bottom = mArrayHeight;
+ }
+ coordPairs[i] =
+ std::min(right, std::max(0, coordPairs[i]));
+ coordPairs[i+1] =
+ std::min(bottom, std::max(0, coordPairs[i+1]));
+ }
+ ALOGV("%s: coordinates: %d, %d", __FUNCTION__, coordPairs[i], coordPairs[i+1]);
+ }
+}
+
+void ZoomRatioMapper::scaleRects(int32_t* rects, int rectCount,
+ float scaleRatio) {
+ for (int i = 0; i < rectCount * 4; i += 4) {
+ // Map from (l, t, width, height) to (l, t, r, b).
+ // [l, t] is inclusive, and [r, b] is exclusive.
+ int32_t coords[4] = {
+ rects[i],
+ rects[i + 1],
+ rects[i] + rects[i + 2],
+ rects[i + 1] + rects[i + 3]
+ };
+
+ // top-left
+ scaleCoordinates(coords, 1, scaleRatio, ClampInclusive);
+ // bottom-right
+ scaleCoordinates(coords+2, 1, scaleRatio, ClampExclusive);
+
+ // Map back to (l, t, width, height)
+ rects[i] = coords[0];
+ rects[i + 1] = coords[1];
+ rects[i + 2] = coords[2] - coords[0];
+ rects[i + 3] = coords[3] - coords[1];
+ }
+}
+
+} // namespace camera3
+
+} // namespace android
diff --git a/services/camera/libcameraservice/device3/ZoomRatioMapper.h b/services/camera/libcameraservice/device3/ZoomRatioMapper.h
new file mode 100644
index 0000000..aa3d913
--- /dev/null
+++ b/services/camera/libcameraservice/device3/ZoomRatioMapper.h
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_SERVERS_ZOOMRATIOMAPPER_H
+#define ANDROID_SERVERS_ZOOMRATIOMAPPER_H
+
+#include <utils/Errors.h>
+#include <array>
+
+#include "camera/CameraMetadata.h"
+#include "device3/CoordinateMapper.h"
+
+namespace android {
+
+namespace camera3 {
+
+/**
+ * Utilities to convert between the new zoomRatio and existing cropRegion
+ * metadata tags. Note that this class does conversions in 2 scenarios:
+ * - HAL supports zoomRatio and the application uses cropRegion, or
+ * - HAL doesn't support zoomRatio, but the application uses zoomRatio
+ */
+class ZoomRatioMapper : private CoordinateMapper {
+ public:
+ ZoomRatioMapper() = default;
+ ZoomRatioMapper(const CameraMetadata *deviceInfo,
+ bool supportNativeZoomRatio, bool usePrecorrectArray);
+ ZoomRatioMapper(const ZoomRatioMapper& other) :
+ mHalSupportsZoomRatio(other.mHalSupportsZoomRatio),
+ mArrayWidth(other.mArrayWidth), mArrayHeight(other.mArrayHeight),
+ mIsValid(other.mIsValid) {}
+
+ /**
+ * Initialize request template with valid zoomRatio if necessary.
+ */
+ static status_t initZoomRatioInTemplate(CameraMetadata *request);
+
+ /**
+ * Override zoomRatio related tags in the static metadata.
+ */
+ static status_t overrideZoomRatioTags(
+ CameraMetadata* deviceInfo, bool* supportNativeZoomRatio);
+
+ /**
+ * Update capture request to handle both cropRegion and zoomRatio.
+ */
+ status_t updateCaptureRequest(CameraMetadata *request);
+
+ /**
+ * Update capture result to handle both cropRegion and zoomRatio.
+ */
+ status_t updateCaptureResult(CameraMetadata *request, bool requestedZoomRatioIs1);
+
+ public: // Visible for testing. Do not use concurently.
+ enum ClampMode {
+ ClampOff,
+ ClampInclusive,
+ ClampExclusive,
+ };
+
+ void scaleCoordinates(int32_t* coordPairs, int coordCount,
+ float scaleRatio, ClampMode clamp);
+
+ bool isValid() { return mIsValid; }
+ private:
+ // const after construction
+ bool mHalSupportsZoomRatio;
+ // active array / pre-correction array dimension
+ int32_t mArrayWidth, mArrayHeight;
+
+ bool mIsValid = false;
+
+ float deriveZoomRatio(const CameraMetadata* metadata);
+ void scaleRects(int32_t* rects, int rectCount, float scaleRatio);
+
+ status_t separateZoomFromCropLocked(CameraMetadata* metadata, bool isResult);
+ status_t combineZoomAndCropLocked(CameraMetadata* metadata, bool isResult);
+};
+
+} // namespace camera3
+
+} // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/hidl/AidlCameraServiceListener.cpp b/services/camera/libcameraservice/hidl/AidlCameraServiceListener.cpp
index 110ef8e..8e619e1 100644
--- a/services/camera/libcameraservice/hidl/AidlCameraServiceListener.cpp
+++ b/services/camera/libcameraservice/hidl/AidlCameraServiceListener.cpp
@@ -25,6 +25,7 @@
namespace implementation {
using hardware::cameraservice::utils::conversion::convertToHidlCameraDeviceStatus;
+typedef frameworks::cameraservice::service::V2_1::ICameraServiceListener HCameraServiceListener2_1;
binder::Status H2BCameraServiceListener::onStatusChanged(
int32_t status, const ::android::String16& cameraId) {
@@ -40,6 +41,29 @@
return binder::Status::ok();
}
+binder::Status H2BCameraServiceListener::onPhysicalCameraStatusChanged(
+ int32_t status, const ::android::String16& cameraId,
+ const ::android::String16& physicalCameraId) {
+ auto cast2_1 = HCameraServiceListener2_1::castFrom(mBase);
+ sp<HCameraServiceListener2_1> interface2_1 = nullptr;
+ if (cast2_1.isOk()) {
+ interface2_1 = cast2_1;
+ if (interface2_1 != nullptr) {
+ HCameraDeviceStatus hCameraDeviceStatus = convertToHidlCameraDeviceStatus(status);
+ V2_1::PhysicalCameraStatusAndId cameraStatusAndId;
+ cameraStatusAndId.deviceStatus = hCameraDeviceStatus;
+ cameraStatusAndId.cameraId = String8(cameraId).string();
+ cameraStatusAndId.physicalCameraId = String8(physicalCameraId).string();
+ auto ret = interface2_1->onPhysicalCameraStatusChanged(cameraStatusAndId);
+ if (!ret.isOk()) {
+ ALOGE("%s OnPhysicalCameraStatusChanged callback failed due to %s",__FUNCTION__,
+ ret.description().c_str());
+ }
+ }
+ }
+ return binder::Status::ok();
+}
+
::android::binder::Status H2BCameraServiceListener::onTorchStatusChanged(
int32_t, const ::android::String16&) {
// We don't implement onTorchStatusChanged
diff --git a/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h b/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h
index b9e5857..7148035 100644
--- a/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h
+++ b/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h
@@ -19,6 +19,7 @@
#include <android/frameworks/cameraservice/common/2.0/types.h>
#include <android/frameworks/cameraservice/service/2.0/ICameraServiceListener.h>
+#include <android/frameworks/cameraservice/service/2.1/ICameraServiceListener.h>
#include <android/frameworks/cameraservice/device/2.0/types.h>
#include <android/hardware/BnCameraServiceListener.h>
#include <android/hardware/BpCameraServiceListener.h>
@@ -46,10 +47,13 @@
~H2BCameraServiceListener() { }
virtual ::android::binder::Status onStatusChanged(int32_t status,
- const ::android::String16& cameraId) override;
+ const ::android::String16& cameraId) override;
+ virtual ::android::binder::Status onPhysicalCameraStatusChanged(int32_t status,
+ const ::android::String16& cameraId,
+ const ::android::String16& physicalCameraId) override;
virtual ::android::binder::Status onTorchStatusChanged(
- int32_t status, const ::android::String16& cameraId) override;
+ int32_t status, const ::android::String16& cameraId) override;
virtual binder::Status onCameraAccessPrioritiesChanged() {
// TODO: no implementation yet.
return binder::Status::ok();
diff --git a/services/camera/libcameraservice/hidl/Convert.cpp b/services/camera/libcameraservice/hidl/Convert.cpp
index 866c3b5..597147b 100644
--- a/services/camera/libcameraservice/hidl/Convert.cpp
+++ b/services/camera/libcameraservice/hidl/Convert.cpp
@@ -197,6 +197,23 @@
return;
}
+void convertToHidl(const std::vector<hardware::CameraStatus> &src,
+ hidl_vec<frameworks::cameraservice::service::V2_1::CameraStatusAndId>* dst) {
+ dst->resize(src.size());
+ size_t i = 0;
+ for (const auto &statusAndId : src) {
+ auto &a = (*dst)[i++];
+ a.v2_0.cameraId = statusAndId.cameraId.c_str();
+ a.v2_0.deviceStatus = convertToHidlCameraDeviceStatus(statusAndId.status);
+ size_t numUnvailPhysicalCameras = statusAndId.unavailablePhysicalIds.size();
+ a.unavailPhysicalCameraIds.resize(numUnvailPhysicalCameras);
+ for (size_t j = 0; j < numUnvailPhysicalCameras; j++) {
+ a.unavailPhysicalCameraIds[j] = statusAndId.unavailablePhysicalIds[j].c_str();
+ }
+ }
+ return;
+}
+
void convertToHidl(
const hardware::camera2::utils::SubmitInfo &submitInfo,
frameworks::cameraservice::device::V2_0::SubmitInfo *hSubmitInfo) {
diff --git a/services/camera/libcameraservice/hidl/Convert.h b/services/camera/libcameraservice/hidl/Convert.h
index 79683f6..82ffc48 100644
--- a/services/camera/libcameraservice/hidl/Convert.h
+++ b/services/camera/libcameraservice/hidl/Convert.h
@@ -23,6 +23,7 @@
#include <android/frameworks/cameraservice/device/2.0/ICameraDeviceUser.h>
#include <android/frameworks/cameraservice/common/2.0/types.h>
#include <android/frameworks/cameraservice/service/2.0/types.h>
+#include <android/frameworks/cameraservice/service/2.1/types.h>
#include <android/frameworks/cameraservice/device/2.0/types.h>
#include <android/hardware/camera/common/1.0/types.h>
#include <android/hardware/camera2/ICameraDeviceUser.h>
@@ -79,6 +80,9 @@
void convertToHidl(const std::vector<hardware::CameraStatus> &src,
hidl_vec<HCameraStatusAndId>* dst);
+void convertToHidl(const std::vector<hardware::CameraStatus> &src,
+ hidl_vec<frameworks::cameraservice::service::V2_1::CameraStatusAndId>* dst);
+
void convertToHidl(const hardware::camera2::utils::SubmitInfo &submitInfo,
HSubmitInfo *hSubmitInfo);
diff --git a/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.cpp b/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.cpp
index 675ad24..bf89ca5 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.cpp
+++ b/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.cpp
@@ -201,8 +201,9 @@
return HStatus::ILLEGAL_ARGUMENT;
}
+ std::vector<int> offlineStreamIds;
binder::Status ret = mDeviceRemote->endConfigure(convertFromHidl(operatingMode),
- cameraMetadata);
+ cameraMetadata, &offlineStreamIds);
return B2HStatus(ret);
}
diff --git a/services/camera/libcameraservice/hidl/HidlCameraService.cpp b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
index 74cfe42..a46133e 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraService.cpp
+++ b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
@@ -103,7 +103,7 @@
}
sp<hardware::camera2::ICameraDeviceCallbacks> callbacks = hybridCallbacks;
binder::Status serviceRet = mAidlICameraService->connectDevice(
- callbacks, String16(cameraId.c_str()), String16(""),
+ callbacks, String16(cameraId.c_str()), String16(""), std::unique_ptr<String16>(),
hardware::ICameraService::USE_CALLING_UID, /*out*/&deviceRemote);
HStatus status = HStatus::NO_ERROR;
if (!serviceRet.isOk()) {
@@ -154,15 +154,50 @@
Return<void> HidlCameraService::addListener(const sp<HCameraServiceListener>& hCsListener,
addListener_cb _hidl_cb) {
- if (mAidlICameraService == nullptr) {
- _hidl_cb(HStatus::UNKNOWN_ERROR, {});
+ std::vector<hardware::CameraStatus> cameraStatusAndIds{};
+ HStatus status = addListenerInternal<HCameraServiceListener>(
+ hCsListener, &cameraStatusAndIds);
+ if (status != HStatus::NO_ERROR) {
+ _hidl_cb(status, {});
return Void();
}
- if (hCsListener == nullptr) {
- ALOGE("%s listener must not be NULL", __FUNCTION__);
- _hidl_cb(HStatus::ILLEGAL_ARGUMENT, {});
+
+ hidl_vec<HCameraStatusAndId> hCameraStatusAndIds;
+ //Convert cameraStatusAndIds to HIDL and call callback
+ convertToHidl(cameraStatusAndIds, &hCameraStatusAndIds);
+ _hidl_cb(status, hCameraStatusAndIds);
+
+ return Void();
+}
+
+Return<void> HidlCameraService::addListener_2_1(const sp<HCameraServiceListener2_1>& hCsListener,
+ addListener_2_1_cb _hidl_cb) {
+ std::vector<hardware::CameraStatus> cameraStatusAndIds{};
+ HStatus status = addListenerInternal<HCameraServiceListener2_1>(
+ hCsListener, &cameraStatusAndIds);
+ if (status != HStatus::NO_ERROR) {
+ _hidl_cb(status, {});
return Void();
}
+
+ hidl_vec<frameworks::cameraservice::service::V2_1::CameraStatusAndId> hCameraStatusAndIds;
+ //Convert cameraStatusAndIds to HIDL and call callback
+ convertToHidl(cameraStatusAndIds, &hCameraStatusAndIds);
+ _hidl_cb(status, hCameraStatusAndIds);
+
+ return Void();
+}
+
+template<class T>
+HStatus HidlCameraService::addListenerInternal(const sp<T>& hCsListener,
+ std::vector<hardware::CameraStatus>* cameraStatusAndIds) {
+ if (mAidlICameraService == nullptr) {
+ return HStatus::UNKNOWN_ERROR;
+ }
+ if (hCsListener == nullptr || cameraStatusAndIds == nullptr) {
+ ALOGE("%s listener and cameraStatusAndIds must not be NULL", __FUNCTION__);
+ return HStatus::ILLEGAL_ARGUMENT;
+ }
sp<hardware::ICameraServiceListener> csListener = nullptr;
// Check the cache for previously registered callbacks
{
@@ -177,25 +212,27 @@
} else {
ALOGE("%s: Trying to add a listener %p already registered",
__FUNCTION__, hCsListener.get());
- _hidl_cb(HStatus::ILLEGAL_ARGUMENT, {});
- return Void();
+ return HStatus::ILLEGAL_ARGUMENT;
}
}
- std::vector<hardware::CameraStatus> cameraStatusAndIds{};
binder::Status serviceRet =
- mAidlICameraService->addListenerHelper(csListener, &cameraStatusAndIds, true);
+ mAidlICameraService->addListenerHelper(csListener, cameraStatusAndIds, true);
HStatus status = HStatus::NO_ERROR;
if (!serviceRet.isOk()) {
- ALOGE("%s: Unable to add camera device status listener", __FUNCTION__);
- status = B2HStatus(serviceRet);
- _hidl_cb(status, {});
- return Void();
+ ALOGE("%s: Unable to add camera device status listener", __FUNCTION__);
+ status = B2HStatus(serviceRet);
+ return status;
}
- hidl_vec<HCameraStatusAndId> hCameraStatusAndIds;
- //Convert cameraStatusAndIds to HIDL and call callback
- convertToHidl(cameraStatusAndIds, &hCameraStatusAndIds);
- _hidl_cb(status, hCameraStatusAndIds);
- return Void();
+ cameraStatusAndIds->erase(std::remove_if(cameraStatusAndIds->begin(), cameraStatusAndIds->end(),
+ [this](const hardware::CameraStatus& s) {
+ bool supportsHAL3 = false;
+ binder::Status sRet =
+ mAidlICameraService->supportsCameraApi(String16(s.cameraId),
+ hardware::ICameraService::API_VERSION_2, &supportsHAL3);
+ return !sRet.isOk() || !supportsHAL3;
+ }), cameraStatusAndIds->end());
+
+ return HStatus::NO_ERROR;
}
Return<HStatus> HidlCameraService::removeListener(const sp<HCameraServiceListener>& hCsListener) {
diff --git a/services/camera/libcameraservice/hidl/HidlCameraService.h b/services/camera/libcameraservice/hidl/HidlCameraService.h
index eead0bc..097f4c5 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraService.h
+++ b/services/camera/libcameraservice/hidl/HidlCameraService.h
@@ -21,7 +21,7 @@
#include <thread>
#include <android/frameworks/cameraservice/common/2.0/types.h>
-#include <android/frameworks/cameraservice/service/2.0/ICameraService.h>
+#include <android/frameworks/cameraservice/service/2.1/ICameraService.h>
#include <android/frameworks/cameraservice/service/2.0/types.h>
#include <android/frameworks/cameraservice/device/2.0/types.h>
@@ -42,8 +42,9 @@
using HCameraDeviceCallback = frameworks::cameraservice::device::V2_0::ICameraDeviceCallback;
using HCameraMetadata = frameworks::cameraservice::service::V2_0::CameraMetadata;
-using HCameraService = frameworks::cameraservice::service::V2_0::ICameraService;
+using HCameraService = frameworks::cameraservice::service::V2_1::ICameraService;
using HCameraServiceListener = frameworks::cameraservice::service::V2_0::ICameraServiceListener;
+using HCameraServiceListener2_1 = frameworks::cameraservice::service::V2_1::ICameraServiceListener;
using HStatus = frameworks::cameraservice::common::V2_0::Status;
using HCameraStatusAndId = frameworks::cameraservice::service::V2_0::CameraStatusAndId;
@@ -66,6 +67,9 @@
Return<void> getCameraVendorTagSections(getCameraVendorTagSections_cb _hidl_cb) override;
+ Return<void> addListener_2_1(const sp<HCameraServiceListener2_1>& listener,
+ addListener_2_1_cb _hidl_cb) override;
+
// This method should only be called by the cameraservers main thread to
// instantiate the hidl cameraserver.
static sp<HidlCameraService> getInstance(android::CameraService *cs);
@@ -76,6 +80,11 @@
sp<hardware::ICameraServiceListener> searchListenerCacheLocked(
sp<HCameraServiceListener> listener, /*removeIfFound*/ bool shouldRemove = false);
+
+ template<class T>
+ HStatus addListenerInternal(const sp<T>& listener,
+ std::vector<hardware::CameraStatus>* cameraStatusAndIds);
+
void addToListenerCacheLocked(sp<HCameraServiceListener> hListener,
sp<hardware::ICameraServiceListener> csListener);
diff --git a/services/camera/libcameraservice/tests/Android.mk b/services/camera/libcameraservice/tests/Android.mk
index b4e7c32..fa5d69e 100644
--- a/services/camera/libcameraservice/tests/Android.mk
+++ b/services/camera/libcameraservice/tests/Android.mk
@@ -23,18 +23,23 @@
libcameraservice \
libhidlbase \
liblog \
- libhidltransport \
libcamera_client \
libcamera_metadata \
+ libui \
libutils \
libjpeg \
libexif \
android.hardware.camera.common@1.0 \
android.hardware.camera.provider@2.4 \
android.hardware.camera.provider@2.5 \
+ android.hardware.camera.provider@2.6 \
android.hardware.camera.device@1.0 \
android.hardware.camera.device@3.2 \
- android.hardware.camera.device@3.4
+ android.hardware.camera.device@3.4 \
+ android.hidl.token@1.0-utils
+
+LOCAL_STATIC_LIBRARIES := \
+ libgmock
LOCAL_C_INCLUDES += \
system/media/private/camera/include \
diff --git a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
index 78d737d..a8f6889 100644
--- a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
+++ b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
@@ -183,6 +183,7 @@
sp<TestICameraProvider> mTestCameraProvider;
TestInteractionProxy() {}
+
void setProvider(sp<TestICameraProvider> provider) {
mTestCameraProvider = provider;
}
@@ -199,13 +200,31 @@
return true;
}
+ virtual sp<hardware::camera::provider::V2_4::ICameraProvider> tryGetService(
+ const std::string &serviceName) override {
+ // If no provider has been given, act like the HAL isn't available and return null.
+ if (mTestCameraProvider == nullptr) return nullptr;
+ return getService(serviceName);
+ }
+
virtual sp<hardware::camera::provider::V2_4::ICameraProvider> getService(
const std::string &serviceName) override {
+ // If no provider has been given, fail; in reality, getService would
+ // block for HALs that don't start correctly, so we should never use
+ // getService when we don't have a valid HAL running
+ if (mTestCameraProvider == nullptr) {
+ ADD_FAILURE() << "getService called with no valid provider; would block indefinitely";
+ // Real getService would block, but that's bad in unit tests. So
+ // just record an error and return nullptr
+ return nullptr;
+ }
mLastRequestedServiceNames.push_back(serviceName);
return mTestCameraProvider;
}
virtual hardware::hidl_vec<hardware::hidl_string> listServices() override {
+ // Always provide a list even if there's no actual provider yet, to
+ // simulate stuck HAL situations as well
hardware::hidl_vec<hardware::hidl_string> ret = {"test/0"};
return ret;
}
@@ -217,6 +236,8 @@
void onDeviceStatusChanged(const String8 &,
hardware::camera::common::V1_0::CameraDeviceStatus) override {}
+ void onDeviceStatusChanged(const String8 &, const String8 &,
+ hardware::camera::common::V1_0::CameraDeviceStatus) override {}
void onTorchStatusChanged(const String8 &,
hardware::camera::common::V1_0::TorchModeStatus) override {}
void onNewProviderRegistered() override {}
@@ -438,3 +459,52 @@
<< "Unable to change device state";
}
+
+// Test that CameraProviderManager doesn't get stuck when the camera HAL isn't really working
+TEST(CameraProviderManagerTest, BadHalStartupTest) {
+
+ std::vector<hardware::hidl_string> deviceNames;
+ deviceNames.push_back("device@3.2/test/0");
+ deviceNames.push_back("device@1.0/test/0");
+ deviceNames.push_back("device@3.2/test/1");
+ hardware::hidl_vec<common::V1_0::VendorTagSection> vendorSection;
+ status_t res;
+
+ sp<CameraProviderManager> providerManager = new CameraProviderManager();
+ sp<TestStatusListener> statusListener = new TestStatusListener();
+ TestInteractionProxy serviceProxy;
+ sp<TestICameraProvider> provider = new TestICameraProvider(deviceNames,
+ vendorSection);
+
+ // Not setting up provider in the service proxy yet, to test cases where a
+ // HAL isn't starting right
+ res = providerManager->initialize(statusListener, &serviceProxy);
+ ASSERT_EQ(res, OK) << "Unable to initialize provider manager";
+
+ // Now set up provider and trigger a registration
+ serviceProxy.setProvider(provider);
+ int numProviders = static_cast<int>(serviceProxy.listServices().size());
+
+ hardware::hidl_string testProviderFqInterfaceName =
+ "android.hardware.camera.provider@2.4::ICameraProvider";
+ hardware::hidl_string testProviderInstanceName = "test/0";
+ serviceProxy.mManagerNotificationInterface->onRegistration(
+ testProviderFqInterfaceName,
+ testProviderInstanceName, false);
+
+ // Check that new provider is called once for all the init methods
+ EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::SET_CALLBACK], numProviders) <<
+ "Only one call to setCallback per provider expected during register";
+ EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::GET_VENDOR_TAGS], numProviders) <<
+ "Only one call to getVendorTags per provider expected during register";
+ EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::IS_SET_TORCH_MODE_SUPPORTED],
+ numProviders) <<
+ "Only one call to isSetTorchModeSupported per provider expected during init";
+ EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::GET_CAMERA_ID_LIST], numProviders) <<
+ "Only one call to getCameraIdList per provider expected during init";
+ EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::NOTIFY_DEVICE_STATE], numProviders) <<
+ "Only one call to notifyDeviceState per provider expected during init";
+
+ ASSERT_EQ(serviceProxy.mLastRequestedServiceNames.back(), testProviderInstanceName) <<
+ "Incorrect instance requested from service manager";
+}
diff --git a/services/camera/libcameraservice/tests/DepthProcessorTest.cpp b/services/camera/libcameraservice/tests/DepthProcessorTest.cpp
index 2162514..673c149 100644
--- a/services/camera/libcameraservice/tests/DepthProcessorTest.cpp
+++ b/services/camera/libcameraservice/tests/DepthProcessorTest.cpp
@@ -20,7 +20,6 @@
#include <array>
#include <random>
-#include <dlfcn.h>
#include <gtest/gtest.h>
#include "../common/DepthPhotoProcessor.h"
@@ -36,19 +35,6 @@
static const size_t kTestBufferDepthSize (kTestBufferWidth * kTestBufferHeight);
static const size_t kSeed = 1234;
-void linkToDepthPhotoLibrary(void **libHandle /*out*/,
- process_depth_photo_frame *processFrameFunc /*out*/) {
- ASSERT_NE(libHandle, nullptr);
- ASSERT_NE(processFrameFunc, nullptr);
-
- *libHandle = dlopen(kDepthPhotoLibrary, RTLD_NOW | RTLD_LOCAL);
- if (*libHandle != nullptr) {
- *processFrameFunc = reinterpret_cast<camera3::process_depth_photo_frame> (
- dlsym(*libHandle, kDepthPhotoProcessFunction));
- ASSERT_NE(*processFrameFunc, nullptr);
- }
-}
-
void generateColorJpegBuffer(int jpegQuality, ExifOrientation orientationValue, bool includeExif,
bool switchDimensions, std::vector<uint8_t> *colorJpegBuffer /*out*/) {
ASSERT_NE(colorJpegBuffer, nullptr);
@@ -91,26 +77,9 @@
}
}
-TEST(DepthProcessorTest, LinkToLibray) {
- void *libHandle;
- process_depth_photo_frame processFunc;
- linkToDepthPhotoLibrary(&libHandle, &processFunc);
- if (libHandle != nullptr) {
- dlclose(libHandle);
- }
-}
-
TEST(DepthProcessorTest, BadInput) {
- void *libHandle;
int jpegQuality = 95;
- process_depth_photo_frame processFunc;
- linkToDepthPhotoLibrary(&libHandle, &processFunc);
- if (libHandle == nullptr) {
- // Depth library no present, nothing more to test.
- return;
- }
-
DepthPhotoInputFrame inputFrame;
// Worst case both depth and confidence maps have the same size as the main color image.
inputFrame.mMaxJpegSize = inputFrame.mMainJpegSize * 3;
@@ -128,37 +97,27 @@
inputFrame.mMainJpegWidth = kTestBufferWidth;
inputFrame.mMainJpegHeight = kTestBufferHeight;
inputFrame.mJpegQuality = jpegQuality;
- ASSERT_NE(processFunc(inputFrame, depthPhotoBuffer.size(), depthPhotoBuffer.data(),
+ ASSERT_NE(processDepthPhotoFrame(inputFrame, depthPhotoBuffer.size(), depthPhotoBuffer.data(),
&actualDepthPhotoSize), 0);
inputFrame.mMainJpegBuffer = reinterpret_cast<const char*> (colorJpegBuffer.data());
inputFrame.mMainJpegSize = colorJpegBuffer.size();
- ASSERT_NE(processFunc(inputFrame, depthPhotoBuffer.size(), depthPhotoBuffer.data(),
+ ASSERT_NE(processDepthPhotoFrame(inputFrame, depthPhotoBuffer.size(), depthPhotoBuffer.data(),
&actualDepthPhotoSize), 0);
inputFrame.mDepthMapBuffer = depth16Buffer.data();
inputFrame.mDepthMapWidth = inputFrame.mDepthMapStride = kTestBufferWidth;
inputFrame.mDepthMapHeight = kTestBufferHeight;
- ASSERT_NE(processFunc(inputFrame, depthPhotoBuffer.size(), nullptr,
+ ASSERT_NE(processDepthPhotoFrame(inputFrame, depthPhotoBuffer.size(), nullptr,
&actualDepthPhotoSize), 0);
- ASSERT_NE(processFunc(inputFrame, depthPhotoBuffer.size(), depthPhotoBuffer.data(), nullptr),
- 0);
-
- dlclose(libHandle);
+ ASSERT_NE(processDepthPhotoFrame(inputFrame, depthPhotoBuffer.size(), depthPhotoBuffer.data(),
+ nullptr), 0);
}
TEST(DepthProcessorTest, BasicDepthPhotoValidation) {
- void *libHandle;
int jpegQuality = 95;
- process_depth_photo_frame processFunc;
- linkToDepthPhotoLibrary(&libHandle, &processFunc);
- if (libHandle == nullptr) {
- // Depth library no present, nothing more to test.
- return;
- }
-
std::vector<uint8_t> colorJpegBuffer;
generateColorJpegBuffer(jpegQuality, ExifOrientation::ORIENTATION_UNDEFINED,
/*includeExif*/ false, /*switchDimensions*/ false, &colorJpegBuffer);
@@ -180,7 +139,7 @@
std::vector<uint8_t> depthPhotoBuffer(inputFrame.mMaxJpegSize);
size_t actualDepthPhotoSize = 0;
- ASSERT_EQ(processFunc(inputFrame, depthPhotoBuffer.size(), depthPhotoBuffer.data(),
+ ASSERT_EQ(processDepthPhotoFrame(inputFrame, depthPhotoBuffer.size(), depthPhotoBuffer.data(),
&actualDepthPhotoSize), 0);
ASSERT_TRUE((actualDepthPhotoSize > 0) && (depthPhotoBuffer.size() >= actualDepthPhotoSize));
@@ -196,21 +155,11 @@
ASSERT_EQ(NV12Compressor::findJpegSize(depthPhotoBuffer.data() + mainJpegSize,
actualDepthPhotoSize - mainJpegSize, &depthMapSize), OK);
ASSERT_TRUE((depthMapSize > 0) && (depthMapSize < (actualDepthPhotoSize - mainJpegSize)));
-
- dlclose(libHandle);
}
TEST(DepthProcessorTest, TestDepthPhotoExifOrientation) {
- void *libHandle;
int jpegQuality = 95;
- process_depth_photo_frame processFunc;
- linkToDepthPhotoLibrary(&libHandle, &processFunc);
- if (libHandle == nullptr) {
- // Depth library no present, nothing more to test.
- return;
- }
-
ExifOrientation exifOrientations[] = { ExifOrientation::ORIENTATION_UNDEFINED,
ExifOrientation::ORIENTATION_0_DEGREES, ExifOrientation::ORIENTATION_90_DEGREES,
ExifOrientation::ORIENTATION_180_DEGREES, ExifOrientation::ORIENTATION_270_DEGREES };
@@ -242,8 +191,8 @@
std::vector<uint8_t> depthPhotoBuffer(inputFrame.mMaxJpegSize);
size_t actualDepthPhotoSize = 0;
- ASSERT_EQ(processFunc(inputFrame, depthPhotoBuffer.size(), depthPhotoBuffer.data(),
- &actualDepthPhotoSize), 0);
+ ASSERT_EQ(processDepthPhotoFrame(inputFrame, depthPhotoBuffer.size(),
+ depthPhotoBuffer.data(), &actualDepthPhotoSize), 0);
ASSERT_TRUE((actualDepthPhotoSize > 0) &&
(depthPhotoBuffer.size() >= actualDepthPhotoSize));
@@ -281,21 +230,11 @@
ASSERT_EQ(confidenceJpegExifOrientation, exifOrientation);
}
}
-
- dlclose(libHandle);
}
TEST(DepthProcessorTest, TestDephtPhotoPhysicalRotation) {
- void *libHandle;
int jpegQuality = 95;
- process_depth_photo_frame processFunc;
- linkToDepthPhotoLibrary(&libHandle, &processFunc);
- if (libHandle == nullptr) {
- // Depth library no present, nothing more to test.
- return;
- }
-
// In case of physical rotation, the EXIF orientation must always be 0.
auto exifOrientation = ExifOrientation::ORIENTATION_0_DEGREES;
DepthPhotoOrientation depthOrientations[] = {
@@ -339,8 +278,8 @@
std::vector<uint8_t> depthPhotoBuffer(inputFrame.mMaxJpegSize);
size_t actualDepthPhotoSize = 0;
- ASSERT_EQ(processFunc(inputFrame, depthPhotoBuffer.size(), depthPhotoBuffer.data(),
- &actualDepthPhotoSize), 0);
+ ASSERT_EQ(processDepthPhotoFrame(inputFrame, depthPhotoBuffer.size(),
+ depthPhotoBuffer.data(), &actualDepthPhotoSize), 0);
ASSERT_TRUE((actualDepthPhotoSize > 0) &&
(depthPhotoBuffer.size() >= actualDepthPhotoSize));
@@ -377,6 +316,4 @@
ASSERT_EQ(confidenceMapWidth, expectedWidth);
ASSERT_EQ(confidenceMapHeight, expectedHeight);
}
-
- dlclose(libHandle);
}
diff --git a/services/camera/libcameraservice/tests/RotateAndCropMapperTest.cpp b/services/camera/libcameraservice/tests/RotateAndCropMapperTest.cpp
new file mode 100644
index 0000000..c638d40
--- /dev/null
+++ b/services/camera/libcameraservice/tests/RotateAndCropMapperTest.cpp
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "RotateAndCropMapperTest"
+
+#include <functional>
+#include <random>
+
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+
+#include "../device3/RotateAndCropMapper.h"
+
+namespace rotateAndCropMapperTest {
+
+using namespace android;
+using namespace android::camera3;
+
+using ::testing::ElementsAreArray;
+using ::testing::Each;
+using ::testing::AllOf;
+using ::testing::Ge;
+using ::testing::Le;
+
+#define EXPECT_EQUAL_WITHIN_N(vec, array, N, msg) \
+{ \
+ std::vector<int32_t> vec_diff; \
+ std::transform(vec.begin(), vec.end(), array, \
+ std::back_inserter(vec_diff), std::minus()); \
+ EXPECT_THAT(vec_diff, Each(AllOf(Ge(-N), Le(N)))) << msg; \
+}
+
+int32_t testActiveArray[] = {100, 100, 4000, 3000};
+
+std::vector<uint8_t> basicModes = {
+ ANDROID_SCALER_ROTATE_AND_CROP_NONE,
+ ANDROID_SCALER_ROTATE_AND_CROP_90,
+ ANDROID_SCALER_ROTATE_AND_CROP_AUTO
+};
+
+CameraMetadata setupDeviceInfo(int32_t activeArray[4], std::vector<uint8_t> availableCropModes ) {
+ CameraMetadata deviceInfo;
+
+ deviceInfo.update(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,
+ activeArray, 4);
+
+ deviceInfo.update(ANDROID_SCALER_AVAILABLE_ROTATE_AND_CROP_MODES,
+ availableCropModes.data(), availableCropModes.size());
+
+ return deviceInfo;
+}
+
+TEST(RotationMapperTest, Initialization) {
+ CameraMetadata deviceInfo = setupDeviceInfo(testActiveArray,
+ {ANDROID_SCALER_ROTATE_AND_CROP_NONE});
+
+ ASSERT_FALSE(RotateAndCropMapper::isNeeded(&deviceInfo));
+
+ deviceInfo.update(ANDROID_SCALER_AVAILABLE_ROTATE_AND_CROP_MODES,
+ basicModes.data(), 3);
+
+ ASSERT_TRUE(RotateAndCropMapper::isNeeded(&deviceInfo));
+}
+
+TEST(RotationMapperTest, IdentityTransform) {
+ status_t res;
+
+ CameraMetadata deviceInfo = setupDeviceInfo(testActiveArray,
+ basicModes);
+
+ RotateAndCropMapper mapper(&deviceInfo);
+
+ CameraMetadata request;
+ uint8_t mode = ANDROID_SCALER_ROTATE_AND_CROP_NONE;
+ auto full_crop = std::vector<int32_t>{0,0, testActiveArray[2], testActiveArray[3]};
+ auto full_region = std::vector<int32_t>{0,0, testActiveArray[2], testActiveArray[3], 1};
+ request.update(ANDROID_SCALER_ROTATE_AND_CROP,
+ &mode, 1);
+ request.update(ANDROID_SCALER_CROP_REGION,
+ full_crop.data(), full_crop.size());
+ request.update(ANDROID_CONTROL_AE_REGIONS,
+ full_region.data(), full_region.size());
+
+ // Map to HAL
+
+ res = mapper.updateCaptureRequest(&request);
+ ASSERT_TRUE(res == OK);
+
+ auto e = request.find(ANDROID_CONTROL_AE_REGIONS);
+ EXPECT_THAT(full_region, ElementsAreArray(e.data.i32, e.count));
+
+ e = request.find(ANDROID_SCALER_CROP_REGION);
+ EXPECT_THAT(full_crop, ElementsAreArray(e.data.i32, e.count));
+
+ // Add fields in HAL
+
+ CameraMetadata result(request);
+
+ auto face = std::vector<int32_t> {300,300,500,500};
+ result.update(ANDROID_STATISTICS_FACE_RECTANGLES,
+ face.data(), face.size());
+
+ // Map to app
+
+ res = mapper.updateCaptureResult(&result);
+ ASSERT_TRUE(res == OK);
+
+ e = result.find(ANDROID_CONTROL_AE_REGIONS);
+ EXPECT_THAT(full_region, ElementsAreArray(e.data.i32, e.count));
+
+ e = result.find(ANDROID_SCALER_CROP_REGION);
+ EXPECT_THAT(full_crop, ElementsAreArray(e.data.i32, e.count));
+
+ e = result.find(ANDROID_STATISTICS_FACE_RECTANGLES);
+ EXPECT_THAT(face, ElementsAreArray(e.data.i32, e.count));
+}
+
+TEST(RotationMapperTest, Transform90) {
+ status_t res;
+
+ CameraMetadata deviceInfo = setupDeviceInfo(testActiveArray,
+ basicModes);
+
+ RotateAndCropMapper mapper(&deviceInfo);
+
+ CameraMetadata request;
+ uint8_t mode = ANDROID_SCALER_ROTATE_AND_CROP_90;
+ auto full_crop = std::vector<int32_t> {0,0, testActiveArray[2], testActiveArray[3]};
+ auto full_region = std::vector<int32_t> {0,0, testActiveArray[2], testActiveArray[3], 1};
+ request.update(ANDROID_SCALER_ROTATE_AND_CROP,
+ &mode, 1);
+ request.update(ANDROID_SCALER_CROP_REGION,
+ full_crop.data(), full_crop.size());
+ request.update(ANDROID_CONTROL_AE_REGIONS,
+ full_region.data(), full_region.size());
+
+ // Map to HAL
+
+ res = mapper.updateCaptureRequest(&request);
+ ASSERT_TRUE(res == OK);
+
+ auto e = request.find(ANDROID_CONTROL_AE_REGIONS);
+ float aspectRatio = static_cast<float>(full_crop[2]) / full_crop[3];
+ int32_t rw = full_crop[3] / aspectRatio;
+ int32_t rh = full_crop[3];
+ auto rotated_region = std::vector<int32_t> {
+ full_crop[0] + (full_crop[2] - rw) / 2, full_crop[1],
+ full_crop[0] + (full_crop[2] + rw) / 2, full_crop[1] + full_crop[3],
+ 1
+ };
+ EXPECT_THAT(rotated_region, ElementsAreArray(e.data.i32, e.count))
+ << "Rotated AE region isn't right";
+
+ e = request.find(ANDROID_SCALER_CROP_REGION);
+ EXPECT_THAT(full_crop, ElementsAreArray(e.data.i32, e.count))
+ << "Rotated crop region isn't right";
+
+ // Add fields in HAL
+
+ CameraMetadata result(request);
+
+ auto face = std::vector<int32_t> {
+ rotated_region[0] + rw / 4, rotated_region[1] + rh / 4,
+ rotated_region[2] - rw / 4, rotated_region[3] - rh / 4};
+ result.update(ANDROID_STATISTICS_FACE_RECTANGLES,
+ face.data(), face.size());
+
+ auto landmarks = std::vector<int32_t> {
+ rotated_region[0], rotated_region[1],
+ rotated_region[2], rotated_region[3],
+ rotated_region[0] + rw / 4, rotated_region[1] + rh / 4,
+ rotated_region[0] + rw / 2, rotated_region[1] + rh / 2,
+ rotated_region[2] - rw / 4, rotated_region[3] - rh / 4
+ };
+ result.update(ANDROID_STATISTICS_FACE_LANDMARKS,
+ landmarks.data(), landmarks.size());
+
+ // Map to app
+
+ res = mapper.updateCaptureResult(&result);
+ ASSERT_TRUE(res == OK);
+
+ // Round-trip results can't be exact since we've gone from a large int range -> small int range
+ // and back, leading to quantization. For 4/3 aspect ratio, no more than +-1 error expected
+ e = result.find(ANDROID_CONTROL_AE_REGIONS);
+ EXPECT_EQUAL_WITHIN_N(full_region, e.data.i32, 1, "Round-tripped AE region isn't right");
+
+ e = result.find(ANDROID_SCALER_CROP_REGION);
+ EXPECT_EQUAL_WITHIN_N(full_crop, e.data.i32, 1, "Round-tripped crop region isn't right");
+
+ auto full_face = std::vector<int32_t> {
+ full_crop[0] + full_crop[2]/4, full_crop[1] + full_crop[3]/4,
+ full_crop[0] + 3*full_crop[2]/4, full_crop[1] + 3*full_crop[3]/4
+ };
+ e = result.find(ANDROID_STATISTICS_FACE_RECTANGLES);
+ EXPECT_EQUAL_WITHIN_N(full_face, e.data.i32, 1, "App-side face rectangle isn't right");
+
+ auto full_landmarks = std::vector<int32_t> {
+ full_crop[0], full_crop[1] + full_crop[3],
+ full_crop[0] + full_crop[2], full_crop[1],
+ full_crop[0] + full_crop[2]/4, full_crop[1] + 3*full_crop[3]/4,
+ full_crop[0] + full_crop[2]/2, full_crop[1] + full_crop[3]/2,
+ full_crop[0] + 3*full_crop[2]/4, full_crop[1] + full_crop[3]/4
+ };
+ e = result.find(ANDROID_STATISTICS_FACE_LANDMARKS);
+ EXPECT_EQUAL_WITHIN_N(full_landmarks, e.data.i32, 1, "App-side face landmarks aren't right");
+}
+
+TEST(RotationMapperTest, Transform270) {
+ status_t res;
+
+ CameraMetadata deviceInfo = setupDeviceInfo(testActiveArray,
+ basicModes);
+
+ RotateAndCropMapper mapper(&deviceInfo);
+
+ CameraMetadata request;
+ uint8_t mode = ANDROID_SCALER_ROTATE_AND_CROP_270;
+ auto full_crop = std::vector<int32_t> {0,0, testActiveArray[2], testActiveArray[3]};
+ auto full_region = std::vector<int32_t> {0,0, testActiveArray[2], testActiveArray[3], 1};
+ request.update(ANDROID_SCALER_ROTATE_AND_CROP,
+ &mode, 1);
+ request.update(ANDROID_SCALER_CROP_REGION,
+ full_crop.data(), full_crop.size());
+ request.update(ANDROID_CONTROL_AE_REGIONS,
+ full_region.data(), full_region.size());
+
+ // Map to HAL
+
+ res = mapper.updateCaptureRequest(&request);
+ ASSERT_TRUE(res == OK);
+
+ auto e = request.find(ANDROID_CONTROL_AE_REGIONS);
+ float aspectRatio = static_cast<float>(full_crop[2]) / full_crop[3];
+ int32_t rw = full_crop[3] / aspectRatio;
+ int32_t rh = full_crop[3];
+ auto rotated_region = std::vector<int32_t> {
+ full_crop[0] + (full_crop[2] - rw) / 2, full_crop[1],
+ full_crop[0] + (full_crop[2] + rw) / 2, full_crop[1] + full_crop[3],
+ 1
+ };
+ EXPECT_THAT(rotated_region, ElementsAreArray(e.data.i32, e.count))
+ << "Rotated AE region isn't right";
+
+ e = request.find(ANDROID_SCALER_CROP_REGION);
+ EXPECT_THAT(full_crop, ElementsAreArray(e.data.i32, e.count))
+ << "Rotated crop region isn't right";
+
+ // Add fields in HAL
+
+ CameraMetadata result(request);
+
+ auto face = std::vector<int32_t> {
+ rotated_region[0] + rw / 4, rotated_region[1] + rh / 4,
+ rotated_region[2] - rw / 4, rotated_region[3] - rh / 4};
+ result.update(ANDROID_STATISTICS_FACE_RECTANGLES,
+ face.data(), face.size());
+
+ auto landmarks = std::vector<int32_t> {
+ rotated_region[0], rotated_region[1],
+ rotated_region[2], rotated_region[3],
+ rotated_region[0] + rw / 4, rotated_region[1] + rh / 4,
+ rotated_region[0] + rw / 2, rotated_region[1] + rh / 2,
+ rotated_region[2] - rw / 4, rotated_region[3] - rh / 4
+ };
+ result.update(ANDROID_STATISTICS_FACE_LANDMARKS,
+ landmarks.data(), landmarks.size());
+
+ // Map to app
+
+ res = mapper.updateCaptureResult(&result);
+ ASSERT_TRUE(res == OK);
+
+ // Round-trip results can't be exact since we've gone from a large int range -> small int range
+ // and back, leading to quantization. For 4/3 aspect ratio, no more than +-1 error expected
+
+ e = result.find(ANDROID_CONTROL_AE_REGIONS);
+ EXPECT_EQUAL_WITHIN_N(full_region, e.data.i32, 1, "Round-tripped AE region isn't right");
+
+ e = result.find(ANDROID_SCALER_CROP_REGION);
+ EXPECT_EQUAL_WITHIN_N(full_crop, e.data.i32, 1, "Round-tripped crop region isn't right");
+
+ auto full_face = std::vector<int32_t> {
+ full_crop[0] + full_crop[2]/4, full_crop[1] + full_crop[3]/4,
+ full_crop[0] + 3*full_crop[2]/4, full_crop[1] + 3*full_crop[3]/4
+ };
+ e = result.find(ANDROID_STATISTICS_FACE_RECTANGLES);
+ EXPECT_EQUAL_WITHIN_N(full_face, e.data.i32, 1, "App-side face rectangle isn't right");
+
+ auto full_landmarks = std::vector<int32_t> {
+ full_crop[0] + full_crop[2], full_crop[1],
+ full_crop[0], full_crop[1] + full_crop[3],
+ full_crop[0] + 3*full_crop[2]/4, full_crop[1] + full_crop[3]/4,
+ full_crop[0] + full_crop[2]/2, full_crop[1] + full_crop[3]/2,
+ full_crop[0] + full_crop[2]/4, full_crop[1] + 3*full_crop[3]/4
+ };
+ e = result.find(ANDROID_STATISTICS_FACE_LANDMARKS);
+ EXPECT_EQUAL_WITHIN_N(full_landmarks, e.data.i32, 1, "App-side face landmarks aren't right");
+}
+
+TEST(RotationMapperTest, Transform180) {
+ status_t res;
+
+ CameraMetadata deviceInfo = setupDeviceInfo(testActiveArray,
+ basicModes);
+
+ RotateAndCropMapper mapper(&deviceInfo);
+
+ CameraMetadata request;
+ uint8_t mode = ANDROID_SCALER_ROTATE_AND_CROP_180;
+ auto full_crop = std::vector<int32_t> {0,0, testActiveArray[2], testActiveArray[3]};
+ auto full_region = std::vector<int32_t> {0,0, testActiveArray[2], testActiveArray[3], 1};
+ request.update(ANDROID_SCALER_ROTATE_AND_CROP,
+ &mode, 1);
+ request.update(ANDROID_SCALER_CROP_REGION,
+ full_crop.data(), full_crop.size());
+ request.update(ANDROID_CONTROL_AE_REGIONS,
+ full_region.data(), full_region.size());
+
+ // Map to HAL
+
+ res = mapper.updateCaptureRequest(&request);
+ ASSERT_TRUE(res == OK);
+
+ auto e = request.find(ANDROID_CONTROL_AE_REGIONS);
+ auto rotated_region = full_region;
+ EXPECT_THAT(rotated_region, ElementsAreArray(e.data.i32, e.count))
+ << "Rotated AE region isn't right";
+
+ e = request.find(ANDROID_SCALER_CROP_REGION);
+ EXPECT_THAT(full_crop, ElementsAreArray(e.data.i32, e.count))
+ << "Rotated crop region isn't right";
+
+ // Add fields in HAL
+
+ CameraMetadata result(request);
+
+ float rw = full_region[2] - full_region[0];
+ float rh = full_region[3] - full_region[1];
+ auto face = std::vector<int32_t> {
+ rotated_region[0] + (int)(rw / 4), rotated_region[1] + (int)(rh / 4),
+ rotated_region[2] - (int)(rw / 4), rotated_region[3] - (int)(rh / 4)
+ };
+ result.update(ANDROID_STATISTICS_FACE_RECTANGLES,
+ face.data(), face.size());
+
+ auto landmarks = std::vector<int32_t> {
+ rotated_region[0], rotated_region[1],
+ rotated_region[2], rotated_region[3],
+ rotated_region[0] + (int)(rw / 4), rotated_region[1] + (int)(rh / 4),
+ rotated_region[0] + (int)(rw / 2), rotated_region[1] + (int)(rh / 2),
+ rotated_region[2] - (int)(rw / 4), rotated_region[3] - (int)(rh / 4)
+ };
+ result.update(ANDROID_STATISTICS_FACE_LANDMARKS,
+ landmarks.data(), landmarks.size());
+
+ // Map to app
+
+ res = mapper.updateCaptureResult(&result);
+ ASSERT_TRUE(res == OK);
+
+ e = result.find(ANDROID_CONTROL_AE_REGIONS);
+ EXPECT_THAT(full_region, ElementsAreArray(e.data.i32, e.count))
+ << "Round-tripped AE region isn't right";
+
+ e = result.find(ANDROID_SCALER_CROP_REGION);
+ EXPECT_THAT(full_crop, ElementsAreArray(e.data.i32, e.count))
+ << "Round-tripped crop region isn't right";
+
+ auto full_face = std::vector<int32_t> {
+ full_crop[0] + full_crop[2]/4, full_crop[1] + full_crop[3]/4,
+ full_crop[0] + 3*full_crop[2]/4, full_crop[1] + 3*full_crop[3]/4
+ };
+ e = result.find(ANDROID_STATISTICS_FACE_RECTANGLES);
+ EXPECT_EQUAL_WITHIN_N(full_face, e.data.i32, 1, "App-side face rectangle isn't right");
+
+ auto full_landmarks = std::vector<int32_t> {
+ full_crop[0] + full_crop[2], full_crop[1] + full_crop[3],
+ full_crop[0], full_crop[1],
+ full_crop[0] + 3*full_crop[2]/4, full_crop[1] + 3*full_crop[3]/4,
+ full_crop[0] + full_crop[2]/2, full_crop[1] + full_crop[3]/2,
+ full_crop[0] + full_crop[2]/4, full_crop[1] + full_crop[3]/4
+ };
+ e = result.find(ANDROID_STATISTICS_FACE_LANDMARKS);
+ EXPECT_EQUAL_WITHIN_N(full_landmarks, e.data.i32, 1, "App-side face landmarks aren't right");
+}
+
+
+} // namespace rotateAndCropMapperTest
diff --git a/services/camera/libcameraservice/tests/ZoomRatioTest.cpp b/services/camera/libcameraservice/tests/ZoomRatioTest.cpp
new file mode 100644
index 0000000..300da09
--- /dev/null
+++ b/services/camera/libcameraservice/tests/ZoomRatioTest.cpp
@@ -0,0 +1,457 @@
+/*
+ * 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.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "ZoomRatioMapperTest"
+
+#include <gtest/gtest.h>
+#include <utils/Errors.h>
+
+#include "../device3/ZoomRatioMapper.h"
+
+using namespace std;
+using namespace android;
+using namespace android::camera3;
+
+constexpr int kMaxAllowedPixelError = 1;
+constexpr float kMaxAllowedRatioError = 0.1;
+
+constexpr int32_t testActiveArraySize[] = {100, 100, 1024, 768};
+constexpr int32_t testPreCorrActiveArraySize[] = {90, 90, 1044, 788};
+
+constexpr int32_t testDefaultCropSize[][4] = {
+ {0, 0, 1024, 768}, // active array default crop
+ {0, 0, 1044, 788}, // preCorrection active array default crop
+};
+
+constexpr int32_t test2xCropRegion[][4] = {
+ {256, 192, 512, 384}, // active array 2x zoom crop
+ {261, 197, 522, 394}, // preCorrection active array default crop
+};
+
+constexpr int32_t testLetterBoxSize[][4] = {
+ {0, 96, 1024, 576}, // active array 2x zoom crop
+ {0, 106, 1024, 576}, // preCorrection active array default crop
+};
+
+status_t setupTestMapper(ZoomRatioMapper *m, float maxDigitalZoom,
+ const int32_t activeArray[4], const int32_t preCorrectArray[4],
+ bool hasZoomRatioRange, float zoomRatioRange[2],
+ bool usePreCorrectArray) {
+ CameraMetadata deviceInfo;
+
+ deviceInfo.update(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE, activeArray, 4);
+ deviceInfo.update(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE, preCorrectArray, 4);
+ deviceInfo.update(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM, &maxDigitalZoom, 1);
+ if (hasZoomRatioRange) {
+ deviceInfo.update(ANDROID_CONTROL_ZOOM_RATIO_RANGE, zoomRatioRange, 2);
+ }
+
+ bool supportNativeZoomRatio;
+ status_t res = ZoomRatioMapper::overrideZoomRatioTags(&deviceInfo, &supportNativeZoomRatio);
+ if (res != OK) {
+ return res;
+ }
+
+ *m = ZoomRatioMapper(&deviceInfo, hasZoomRatioRange, usePreCorrectArray);
+ return OK;
+}
+
+TEST(ZoomRatioTest, Initialization) {
+ CameraMetadata deviceInfo;
+ status_t res;
+ camera_metadata_entry_t entry;
+
+ deviceInfo.update(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE,
+ testPreCorrActiveArraySize, 4);
+ deviceInfo.update(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE, testActiveArraySize, 4);
+
+ // Test initialization from devices not supporting zoomRange
+ float maxDigitalZoom = 4.0f;
+ ZoomRatioMapper mapperNoZoomRange;
+ deviceInfo.update(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM, &maxDigitalZoom, 1);
+ bool supportNativeZoomRatio;
+ res = ZoomRatioMapper::overrideZoomRatioTags(&deviceInfo, &supportNativeZoomRatio);
+ ASSERT_EQ(res, OK);
+ ASSERT_EQ(supportNativeZoomRatio, false);
+ mapperNoZoomRange = ZoomRatioMapper(&deviceInfo,
+ supportNativeZoomRatio, true/*usePreCorrectArray*/);
+ ASSERT_TRUE(mapperNoZoomRange.isValid());
+ mapperNoZoomRange = ZoomRatioMapper(&deviceInfo,
+ supportNativeZoomRatio, false/*usePreCorrectArray*/);
+ ASSERT_TRUE(mapperNoZoomRange.isValid());
+
+ entry = deviceInfo.find(ANDROID_CONTROL_ZOOM_RATIO_RANGE);
+ ASSERT_EQ(entry.count, 2U);
+ ASSERT_EQ(entry.data.f[0], 1.0);
+ ASSERT_EQ(entry.data.f[1], maxDigitalZoom);
+
+ entry = deviceInfo.find(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS);
+ ASSERT_GT(entry.count, 0U);
+ ASSERT_NE(std::find(entry.data.i32, entry.data.i32 + entry.count,
+ ANDROID_CONTROL_ZOOM_RATIO_RANGE), entry.data.i32 + entry.count);
+
+ entry = deviceInfo.find(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS);
+ ASSERT_GT(entry.count, 0U);
+ ASSERT_NE(std::find(entry.data.i32, entry.data.i32 + entry.count,
+ ANDROID_CONTROL_ZOOM_RATIO), entry.data.i32 + entry.count);
+
+ entry = deviceInfo.find(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS);
+ ASSERT_GT(entry.count, 0U);
+ ASSERT_NE(std::find(entry.data.i32, entry.data.i32 + entry.count,
+ ANDROID_CONTROL_ZOOM_RATIO), entry.data.i32 + entry.count);
+
+ // Test initialization from devices supporting zoomRange
+ float ratioRange[2] = {0.2f, maxDigitalZoom};
+ deviceInfo.update(ANDROID_CONTROL_ZOOM_RATIO_RANGE, ratioRange, 2);
+ res = ZoomRatioMapper::overrideZoomRatioTags(&deviceInfo, &supportNativeZoomRatio);
+ ASSERT_EQ(res, OK);
+ ASSERT_EQ(supportNativeZoomRatio, true);
+ ZoomRatioMapper mapperWithZoomRange;
+ mapperWithZoomRange = ZoomRatioMapper(&deviceInfo,
+ supportNativeZoomRatio, true/*usePreCorrectArray*/);
+ ASSERT_TRUE(mapperWithZoomRange.isValid());
+ mapperWithZoomRange = ZoomRatioMapper(&deviceInfo,
+ supportNativeZoomRatio, false/*usePreCorrectArray*/);
+ ASSERT_TRUE(mapperWithZoomRange.isValid());
+
+ entry = deviceInfo.find(ANDROID_CONTROL_ZOOM_RATIO_RANGE);
+ ASSERT_EQ(entry.count, 2U);
+ ASSERT_EQ(entry.data.f[0], ratioRange[0]);
+ ASSERT_EQ(entry.data.f[1], ratioRange[1]);
+
+ // Test default zoom ratio in template
+ CameraMetadata requestTemplate;
+ res = ZoomRatioMapper::initZoomRatioInTemplate(&requestTemplate);
+ ASSERT_EQ(res, OK);
+ entry = requestTemplate.find(ANDROID_CONTROL_ZOOM_RATIO);
+ ASSERT_EQ(entry.count, 1U);
+ ASSERT_EQ(entry.data.f[0], 1.0f);
+
+ float customRatio = 0.5f;
+ res = requestTemplate.update(ANDROID_CONTROL_ZOOM_RATIO, &customRatio, 1);
+ ASSERT_EQ(res, OK);
+ res = ZoomRatioMapper::initZoomRatioInTemplate(&requestTemplate);
+ ASSERT_EQ(res, OK);
+ entry = requestTemplate.find(ANDROID_CONTROL_ZOOM_RATIO);
+ ASSERT_EQ(entry.count, 1U);
+ ASSERT_EQ(entry.data.f[0], customRatio);
+}
+
+void subScaleCoordinatesTest(bool usePreCorrectArray) {
+ ZoomRatioMapper mapper;
+ float maxDigitalZoom = 4.0f;
+ float zoomRatioRange[2];
+ ASSERT_EQ(OK, setupTestMapper(&mapper, maxDigitalZoom,
+ testActiveArraySize, testPreCorrActiveArraySize,
+ false/*hasZoomRatioRange*/, zoomRatioRange,
+ usePreCorrectArray));
+
+ size_t index = 0;
+ int32_t width = testActiveArraySize[2];
+ int32_t height = testActiveArraySize[3];
+ if (usePreCorrectArray) {
+ index = 1;
+ width = testPreCorrActiveArraySize[2];
+ height = testPreCorrActiveArraySize[3];
+ }
+
+ std::array<int32_t, 16> originalCoords = {
+ 0, 0, // top-left
+ width, 0, // top-right
+ 0, height, // bottom-left
+ width, height, // bottom-right
+ width / 2, height / 2, // center
+ width / 4, height / 4, // top-left after 2x
+ width / 3, height * 2 / 3, // bottom-left after 3x zoom
+ width * 7 / 8, height / 2, // middle-right after 1.33x zoom
+ };
+
+ // Verify 1.0x zoom doesn't change the coordinates
+ auto coords = originalCoords;
+ mapper.scaleCoordinates(coords.data(), coords.size()/2, 1.0f, ZoomRatioMapper::ClampOff);
+ for (size_t i = 0; i < coords.size(); i++) {
+ EXPECT_EQ(coords[i], originalCoords[i]);
+ }
+
+ // Verify 2.0x zoom work as expected (no clamping)
+ std::array<float, 16> expected2xCoords = {
+ - width / 2.0f, - height / 2.0f,// top-left
+ width * 3 / 2.0f, - height / 2.0f, // top-right
+ - width / 2.0f, height * 3 / 2.0f, // bottom-left
+ width * 3 / 2.0f, height * 3 / 2.0f, // bottom-right
+ width / 2.0f, height / 2.0f, // center
+ 0, 0, // top-left after 2x
+ width / 6.0f, height - height / 6.0f, // bottom-left after 3x zoom
+ width + width / 4.0f, height / 2.0f, // middle-right after 1.33x zoom
+ };
+ coords = originalCoords;
+ mapper.scaleCoordinates(coords.data(), coords.size()/2, 2.0f, ZoomRatioMapper::ClampOff);
+ for (size_t i = 0; i < coords.size(); i++) {
+ EXPECT_LE(std::abs(coords[i] - expected2xCoords[i]), kMaxAllowedPixelError);
+ }
+
+ // Verify 2.0x zoom work as expected (with inclusive clamping)
+ std::array<float, 16> expected2xCoordsClampedInc = {
+ 0, 0, // top-left
+ static_cast<float>(width) - 1, 0, // top-right
+ 0, static_cast<float>(height) - 1, // bottom-left
+ static_cast<float>(width) - 1, static_cast<float>(height) - 1, // bottom-right
+ width / 2.0f, height / 2.0f, // center
+ 0, 0, // top-left after 2x
+ width / 6.0f, height - height / 6.0f , // bottom-left after 3x zoom
+ static_cast<float>(width) - 1, height / 2.0f, // middle-right after 1.33x zoom
+ };
+ coords = originalCoords;
+ mapper.scaleCoordinates(coords.data(), coords.size()/2, 2.0f, ZoomRatioMapper::ClampInclusive);
+ for (size_t i = 0; i < coords.size(); i++) {
+ EXPECT_LE(std::abs(coords[i] - expected2xCoordsClampedInc[i]), kMaxAllowedPixelError);
+ }
+
+ // Verify 2.0x zoom work as expected (with exclusive clamping)
+ std::array<float, 16> expected2xCoordsClampedExc = {
+ 0, 0, // top-left
+ static_cast<float>(width), 0, // top-right
+ 0, static_cast<float>(height), // bottom-left
+ static_cast<float>(width), static_cast<float>(height), // bottom-right
+ width / 2.0f, height / 2.0f, // center
+ 0, 0, // top-left after 2x
+ width / 6.0f, height - height / 6.0f , // bottom-left after 3x zoom
+ static_cast<float>(width), height / 2.0f, // middle-right after 1.33x zoom
+ };
+ coords = originalCoords;
+ mapper.scaleCoordinates(coords.data(), coords.size()/2, 2.0f, ZoomRatioMapper::ClampExclusive);
+ for (size_t i = 0; i < coords.size(); i++) {
+ EXPECT_LE(std::abs(coords[i] - expected2xCoordsClampedExc[i]), kMaxAllowedPixelError);
+ }
+
+ // Verify 0.33x zoom work as expected
+ std::array<float, 16> expectedZoomOutCoords = {
+ width / 3.0f, height / 3.0f, // top-left
+ width * 2 / 3.0f, height / 3.0f, // top-right
+ width / 3.0f, height * 2 / 3.0f, // bottom-left
+ width * 2 / 3.0f, height * 2 / 3.0f, // bottom-right
+ width / 2.0f, height / 2.0f, // center
+ width * 5 / 12.0f, height * 5 / 12.0f, // top-left after 2x
+ width * 4 / 9.0f, height * 5 / 9.0f, // bottom-left after 3x zoom-in
+ width * 5 / 8.0f, height / 2.0f, // middle-right after 1.33x zoom-in
+ };
+ coords = originalCoords;
+ mapper.scaleCoordinates(coords.data(), coords.size()/2, 1.0f/3, ZoomRatioMapper::ClampOff);
+ for (size_t i = 0; i < coords.size(); i++) {
+ EXPECT_LE(std::abs(coords[i] - expectedZoomOutCoords[i]), kMaxAllowedPixelError);
+ }
+}
+
+TEST(ZoomRatioTest, scaleCoordinatesTest) {
+ subScaleCoordinatesTest(false/*usePreCorrectArray*/);
+ subScaleCoordinatesTest(true/*usePreCorrectArray*/);
+}
+
+void subCropOverMaxDigitalZoomTest(bool usePreCorrectArray) {
+ status_t res;
+ ZoomRatioMapper mapper;
+ float noZoomRatioRange[2];
+ res = setupTestMapper(&mapper, 4.0/*maxDigitalZoom*/,
+ testActiveArraySize, testPreCorrActiveArraySize,
+ false/*hasZoomRatioRange*/, noZoomRatioRange,
+ usePreCorrectArray);
+ ASSERT_EQ(res, OK);
+
+ CameraMetadata metadata;
+ camera_metadata_entry_t entry;
+
+ size_t index = usePreCorrectArray ? 1 : 0;
+ metadata.update(ANDROID_SCALER_CROP_REGION, testDefaultCropSize[index], 4);
+ res = mapper.updateCaptureRequest(&metadata);
+ ASSERT_EQ(res, OK);
+ entry = metadata.find(ANDROID_SCALER_CROP_REGION);
+ ASSERT_EQ(entry.count, 4U);
+ for (int i = 0; i < 4; i ++) {
+ EXPECT_EQ(entry.data.i32[i], testDefaultCropSize[index][i]);
+ }
+
+ metadata.update(ANDROID_SCALER_CROP_REGION, test2xCropRegion[index], 4);
+ res = mapper.updateCaptureResult(&metadata, true/*requestedZoomRatioIs1*/);
+ ASSERT_EQ(res, OK);
+ entry = metadata.find(ANDROID_SCALER_CROP_REGION);
+ ASSERT_EQ(entry.count, 4U);
+ for (int i = 0; i < 4; i ++) {
+ EXPECT_EQ(entry.data.i32[i], test2xCropRegion[index][i]);
+ }
+ entry = metadata.find(ANDROID_CONTROL_ZOOM_RATIO);
+ ASSERT_TRUE(entry.count == 0 || (entry.count == 1 && entry.data.f[0] == 1.0f));
+}
+
+TEST(ZoomRatioTest, CropOverMaxDigitalZoomTest) {
+ subCropOverMaxDigitalZoomTest(false/*usePreCorrectArray*/);
+ subCropOverMaxDigitalZoomTest(true/*usePreCorrectArray*/);
+}
+
+void subCropOverZoomRangeTest(bool usePreCorrectArray) {
+ status_t res;
+ ZoomRatioMapper mapper;
+ float zoomRatioRange[2] = {0.5f, 4.0f};
+ res = setupTestMapper(&mapper, 4.0/*maxDigitalZoom*/,
+ testActiveArraySize, testPreCorrActiveArraySize,
+ true/*hasZoomRatioRange*/, zoomRatioRange,
+ usePreCorrectArray);
+ ASSERT_EQ(res, OK);
+
+ CameraMetadata metadata;
+ camera_metadata_entry_t entry;
+
+ size_t index = usePreCorrectArray ? 1 : 0;
+
+ // 2x zoom crop region, zoomRatio is 1.0f
+ metadata.update(ANDROID_SCALER_CROP_REGION, test2xCropRegion[index], 4);
+ res = mapper.updateCaptureRequest(&metadata);
+ ASSERT_EQ(res, OK);
+ entry = metadata.find(ANDROID_SCALER_CROP_REGION);
+ ASSERT_EQ(entry.count, 4U);
+ for (int i = 0; i < 4; i++) {
+ EXPECT_EQ(entry.data.i32[i], testDefaultCropSize[index][i]);
+ }
+ entry = metadata.find(ANDROID_CONTROL_ZOOM_RATIO);
+ EXPECT_NEAR(entry.data.f[0], 2.0f, kMaxAllowedRatioError);
+
+ res = mapper.updateCaptureResult(&metadata, true/*requestedZoomRatioIs1*/);
+ ASSERT_EQ(res, OK);
+ entry = metadata.find(ANDROID_CONTROL_ZOOM_RATIO);
+ EXPECT_NEAR(entry.data.f[0], 1.0f, kMaxAllowedRatioError);
+ entry = metadata.find(ANDROID_SCALER_CROP_REGION);
+ ASSERT_EQ(entry.count, 4U);
+ for (int i = 0; i < 4; i++) {
+ EXPECT_EQ(entry.data.i32[i], test2xCropRegion[index][i]);
+ }
+
+ // Letter boxing crop region, zoomRatio is 1.0
+ float zoomRatio = 1.0f;
+ metadata.update(ANDROID_CONTROL_ZOOM_RATIO, &zoomRatio, 1);
+ metadata.update(ANDROID_SCALER_CROP_REGION, testLetterBoxSize[index], 4);
+ res = mapper.updateCaptureRequest(&metadata);
+ ASSERT_EQ(res, OK);
+ entry = metadata.find(ANDROID_SCALER_CROP_REGION);
+ ASSERT_EQ(entry.count, 4U);
+ for (int i = 0; i < 4; i++) {
+ EXPECT_EQ(entry.data.i32[i], testLetterBoxSize[index][i]);
+ }
+ entry = metadata.find(ANDROID_CONTROL_ZOOM_RATIO);
+ EXPECT_NEAR(entry.data.f[0], 1.0f, kMaxAllowedRatioError);
+
+ res = mapper.updateCaptureResult(&metadata, true/*requestedZoomRatioIs1*/);
+ ASSERT_EQ(res, OK);
+ entry = metadata.find(ANDROID_SCALER_CROP_REGION);
+ ASSERT_EQ(entry.count, 4U);
+ for (int i = 0; i < 4; i++) {
+ EXPECT_EQ(entry.data.i32[i], testLetterBoxSize[index][i]);
+ }
+ entry = metadata.find(ANDROID_CONTROL_ZOOM_RATIO);
+ EXPECT_NEAR(entry.data.f[0], 1.0f, kMaxAllowedRatioError);
+}
+
+TEST(ZoomRatioTest, CropOverZoomRangeTest) {
+ subCropOverZoomRangeTest(false/*usePreCorrectArray*/);
+ subCropOverZoomRangeTest(true/*usePreCorrectArray*/);
+}
+
+void subZoomOverMaxDigitalZoomTest(bool usePreCorrectArray) {
+ status_t res;
+ ZoomRatioMapper mapper;
+ float noZoomRatioRange[2];
+ res = setupTestMapper(&mapper, 4.0/*maxDigitalZoom*/,
+ testActiveArraySize, testPreCorrActiveArraySize,
+ false/*hasZoomRatioRange*/, noZoomRatioRange,
+ usePreCorrectArray);
+ ASSERT_EQ(res, OK);
+
+ CameraMetadata metadata;
+ float zoomRatio = 3.0f;
+ camera_metadata_entry_t entry;
+
+ size_t index = usePreCorrectArray ? 1 : 0;
+
+ // Full active array crop, zoomRatio is 3.0f
+ metadata.update(ANDROID_SCALER_CROP_REGION, testDefaultCropSize[index], 4);
+ metadata.update(ANDROID_CONTROL_ZOOM_RATIO, &zoomRatio, 1);
+ res = mapper.updateCaptureRequest(&metadata);
+ ASSERT_EQ(res, OK);
+ entry = metadata.find(ANDROID_SCALER_CROP_REGION);
+ ASSERT_EQ(entry.count, 4U);
+ std::array<float, 4> expectedCrop = {
+ testDefaultCropSize[index][2] / 3.0f, /*x*/
+ testDefaultCropSize[index][3] / 3.0f, /*y*/
+ testDefaultCropSize[index][2] / 3.0f, /*width*/
+ testDefaultCropSize[index][3] / 3.0f, /*height*/
+ };
+ for (int i = 0; i < 4; i++) {
+ EXPECT_LE(std::abs(entry.data.i32[i] - expectedCrop[i]), kMaxAllowedPixelError);
+ }
+
+ entry = metadata.find(ANDROID_CONTROL_ZOOM_RATIO);
+ if (entry.count == 1) {
+ EXPECT_NEAR(entry.data.f[0], 1.0f, kMaxAllowedRatioError);
+ }
+}
+
+TEST(ZoomRatioTest, ZoomOverMaxDigitalZoomTest) {
+ subZoomOverMaxDigitalZoomTest(false/*usePreCorrectArray*/);
+ subZoomOverMaxDigitalZoomTest(true/*usePreCorrectArray*/);
+}
+
+void subZoomOverZoomRangeTest(bool usePreCorrectArray) {
+ status_t res;
+ ZoomRatioMapper mapper;
+ float zoomRatioRange[2] = {1.0f, 4.0f};
+ res = setupTestMapper(&mapper, 4.0/*maxDigitalZoom*/,
+ testActiveArraySize, testPreCorrActiveArraySize,
+ true/*hasZoomRatioRange*/, zoomRatioRange,
+ usePreCorrectArray);
+ ASSERT_EQ(res, OK);
+
+ CameraMetadata metadata;
+ float zoomRatio = 3.0f;
+ camera_metadata_entry_t entry;
+ size_t index = usePreCorrectArray ? 1 : 0;
+
+ // Full active array crop, zoomRatio is 3.0f
+ metadata.update(ANDROID_SCALER_CROP_REGION, testDefaultCropSize[index], 4);
+ metadata.update(ANDROID_CONTROL_ZOOM_RATIO, &zoomRatio, 1);
+ res = mapper.updateCaptureRequest(&metadata);
+ ASSERT_EQ(res, OK);
+ entry = metadata.find(ANDROID_SCALER_CROP_REGION);
+ ASSERT_EQ(entry.count, 4U);
+ for (int i = 0; i < 4; i ++) {
+ EXPECT_EQ(entry.data.i32[i], testDefaultCropSize[index][i]);
+ }
+ entry = metadata.find(ANDROID_CONTROL_ZOOM_RATIO);
+ ASSERT_EQ(entry.data.f[0], zoomRatio);
+
+ res = mapper.updateCaptureResult(&metadata, false/*requestedZoomRatioIs1*/);
+ ASSERT_EQ(res, OK);
+ entry = metadata.find(ANDROID_SCALER_CROP_REGION);
+ ASSERT_EQ(entry.count, 4U);
+ for (int i = 0; i < 4; i ++) {
+ EXPECT_EQ(entry.data.i32[i], testDefaultCropSize[index][i]);
+ }
+ entry = metadata.find(ANDROID_CONTROL_ZOOM_RATIO);
+ ASSERT_EQ(entry.data.f[0], zoomRatio);
+}
+
+TEST(ZoomRatioTest, ZoomOverZoomRangeTest) {
+ subZoomOverZoomRangeTest(false/*usePreCorrectArray*/);
+ subZoomOverZoomRangeTest(true/*usePreCorrectArray*/);
+}
diff --git a/services/camera/libcameraservice/utils/CameraThreadState.cpp b/services/camera/libcameraservice/utils/CameraThreadState.cpp
index b9e344b..2352b80 100644
--- a/services/camera/libcameraservice/utils/CameraThreadState.cpp
+++ b/services/camera/libcameraservice/utils/CameraThreadState.cpp
@@ -17,33 +17,34 @@
#include "CameraThreadState.h"
#include <binder/IPCThreadState.h>
#include <hwbinder/IPCThreadState.h>
+#include <binderthreadstate/CallerUtils.h>
#include <unistd.h>
namespace android {
int CameraThreadState::getCallingUid() {
- if (hardware::IPCThreadState::self()->isServingCall()) {
+ if (getCurrentServingCall() == BinderCallType::HWBINDER) {
return hardware::IPCThreadState::self()->getCallingUid();
}
return IPCThreadState::self()->getCallingUid();
}
int CameraThreadState::getCallingPid() {
- if (hardware::IPCThreadState::self()->isServingCall()) {
+ if (getCurrentServingCall() == BinderCallType::HWBINDER) {
return hardware::IPCThreadState::self()->getCallingPid();
}
return IPCThreadState::self()->getCallingPid();
}
int64_t CameraThreadState::clearCallingIdentity() {
- if (hardware::IPCThreadState::self()->isServingCall()) {
+ if (getCurrentServingCall() == BinderCallType::HWBINDER) {
return hardware::IPCThreadState::self()->clearCallingIdentity();
}
return IPCThreadState::self()->clearCallingIdentity();
}
void CameraThreadState::restoreCallingIdentity(int64_t token) {
- if (hardware::IPCThreadState::self()->isServingCall()) {
+ if (getCurrentServingCall() == BinderCallType::HWBINDER) {
hardware::IPCThreadState::self()->restoreCallingIdentity(token);
} else {
IPCThreadState::self()->restoreCallingIdentity(token);
diff --git a/services/camera/libcameraservice/utils/ClientManager.h b/services/camera/libcameraservice/utils/ClientManager.h
index ec6f01c..35d25bf 100644
--- a/services/camera/libcameraservice/utils/ClientManager.h
+++ b/services/camera/libcameraservice/utils/ClientManager.h
@@ -35,7 +35,7 @@
public:
/**
* Choosing to set mIsVendorClient through a parameter instead of calling
- * hardware::IPCThreadState::self()->isServingCall() to protect against the
+ * getCurrentServingCall() == BinderCallType::HWBINDER to protect against the
* case where the construction is offloaded to another thread which isn't a
* hwbinder thread.
*/
@@ -237,7 +237,7 @@
// We don't use the usual copy constructor here since we want to remember
// whether a client is a vendor client or not. This could have been wiped
// off in the incoming priority argument since an AIDL thread might have
- // called hardware::IPCThreadState::self()->isServingCall() after refreshing
+ // called getCurrentServingCall() == BinderCallType::HWBINDER after refreshing
// priorities for old clients through ProcessInfoService::getProcessStatesScoresFromPids().
mPriority.setScore(priority.getScore());
mPriority.setState(priority.getState());
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
new file mode 100644
index 0000000..888671c
--- /dev/null
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "SessionConfigurationUtils.h"
+#include "../api2/CameraDeviceClient.h"
+
+namespace android {
+
+binder::Status
+SessionConfigurationUtils::convertToHALStreamCombination(
+ const SessionConfiguration& sessionConfiguration,
+ const String8 &logicalCameraId, const CameraMetadata &deviceInfo,
+ metadataGetter getMetadata, const std::vector<std::string> &physicalCameraIds,
+ hardware::camera::device::V3_4::StreamConfiguration &streamConfiguration, bool *earlyExit) {
+ // TODO: http://b/148329298 Move the other dependencies from
+ // CameraDeviceClient into SessionConfigurationUtils.
+ return CameraDeviceClient::convertToHALStreamCombination(sessionConfiguration, logicalCameraId,
+ deviceInfo, getMetadata, physicalCameraIds, streamConfiguration, earlyExit);
+}
+
+}// namespace android
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
new file mode 100644
index 0000000..fb519d9
--- /dev/null
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_SERVERS_CAMERA_SESSION_CONFIGURATION_UTILS_H
+#define ANDROID_SERVERS_CAMERA_SESSION_CONFIGURATION_UTILS_H
+
+#include <android/hardware/camera2/BnCameraDeviceUser.h>
+#include <android/hardware/camera2/ICameraDeviceCallbacks.h>
+#include <camera/camera2/OutputConfiguration.h>
+#include <camera/camera2/SessionConfiguration.h>
+#include <camera/camera2/SubmitInfo.h>
+#include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
+
+#include <stdint.h>
+
+namespace android {
+
+typedef std::function<CameraMetadata (const String8 &)> metadataGetter;
+
+class SessionConfigurationUtils {
+public:
+ // utility function to convert AIDL SessionConfiguration to HIDL
+ // streamConfiguration. Also checks for sanity of SessionConfiguration and
+ // returns a non-ok binder::Status if the passed in session configuration
+ // isn't valid.
+ static binder::Status
+ convertToHALStreamCombination(const SessionConfiguration& sessionConfiguration,
+ const String8 &cameraId, const CameraMetadata &deviceInfo,
+ metadataGetter getMetadata, const std::vector<std::string> &physicalCameraIds,
+ hardware::camera::device::V3_4::StreamConfiguration &streamConfiguration,
+ bool *earlyExit);
+};
+
+} // android
+#endif
diff --git a/services/camera/libcameraservice/utils/TagMonitor.cpp b/services/camera/libcameraservice/utils/TagMonitor.cpp
index 4037a66..262f962 100644
--- a/services/camera/libcameraservice/utils/TagMonitor.cpp
+++ b/services/camera/libcameraservice/utils/TagMonitor.cpp
@@ -33,6 +33,16 @@
mVendorTagId(CAMERA_METADATA_INVALID_VENDOR_ID)
{}
+TagMonitor::TagMonitor(const TagMonitor& other):
+ mMonitoringEnabled(other.mMonitoringEnabled.load()),
+ mMonitoredTagList(other.mMonitoredTagList),
+ mLastMonitoredRequestValues(other.mLastMonitoredRequestValues),
+ mLastMonitoredResultValues(other.mLastMonitoredResultValues),
+ mLastMonitoredPhysicalRequestKeys(other.mLastMonitoredPhysicalRequestKeys),
+ mLastMonitoredPhysicalResultKeys(other.mLastMonitoredPhysicalResultKeys),
+ mMonitoringEvents(other.mMonitoringEvents),
+ mVendorTagId(other.mVendorTagId) {}
+
const String16 TagMonitor::kMonitorOption = String16("-m");
const char* TagMonitor::k3aTags =
diff --git a/services/camera/libcameraservice/utils/TagMonitor.h b/services/camera/libcameraservice/utils/TagMonitor.h
index 1b7b033..413f502 100644
--- a/services/camera/libcameraservice/utils/TagMonitor.h
+++ b/services/camera/libcameraservice/utils/TagMonitor.h
@@ -50,6 +50,8 @@
TagMonitor();
+ TagMonitor(const TagMonitor& other);
+
void initialize(metadata_vendor_id_t id) { mVendorTagId = id; }
// Parse tag name list (comma-separated) and if valid, enable monitoring
diff --git a/services/mediaanalytics/Android.bp b/services/mediaanalytics/Android.bp
deleted file mode 100644
index 72f4b52..0000000
--- a/services/mediaanalytics/Android.bp
+++ /dev/null
@@ -1,68 +0,0 @@
-// Media Statistics service
-//
-
-cc_binary {
- name: "mediametrics",
-
- srcs: [
- "main_mediametrics.cpp",
- "MediaAnalyticsService.cpp",
- "iface_statsd.cpp",
- "statsd_audiopolicy.cpp",
- "statsd_audiorecord.cpp",
- "statsd_audiothread.cpp",
- "statsd_audiotrack.cpp",
- "statsd_codec.cpp",
- "statsd_drm.cpp",
- "statsd_extractor.cpp",
- "statsd_nuplayer.cpp",
- "statsd_recorder.cpp",
- ],
-
- proto: {
- type: "lite",
- },
-
- shared_libs: [
- "libcutils",
- "liblog",
- "libmedia",
- "libutils",
- "libbinder",
- "libdl",
- "libgui",
- "libmedia",
- "libmediautils",
- "libmediametrics",
- "libstagefright_foundation",
- "libstatslog",
- "libutils",
- "libprotobuf-cpp-lite",
- ],
-
- static_libs: [
- "libplatformprotos",
- "libregistermsext",
- ],
-
- include_dirs: [
- "frameworks/av/media/libstagefright/include",
- "frameworks/av/media/libstagefright/rtsp",
- "frameworks/av/media/libstagefright/webm",
- "frameworks/av/include/media",
- "frameworks/av/include/camera",
- "frameworks/native/include/media/openmax",
- "frameworks/native/include/media/hardware",
- "external/tremolo/Tremolo",
- ],
-
- init_rc: ["mediametrics.rc"],
-
- cflags: [
- "-Werror",
- "-Wall",
- "-Wno-error=deprecated-declarations",
- ],
- clang: true,
-
-}
diff --git a/services/mediaanalytics/MediaAnalyticsService.cpp b/services/mediaanalytics/MediaAnalyticsService.cpp
deleted file mode 100644
index 0e7edfd..0000000
--- a/services/mediaanalytics/MediaAnalyticsService.cpp
+++ /dev/null
@@ -1,756 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-// Proxy for media player implementations
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MediaAnalyticsService"
-#include <utils/Log.h>
-
-#include <stdint.h>
-#include <inttypes.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <dirent.h>
-#include <pthread.h>
-#include <unistd.h>
-
-#include <string.h>
-#include <pwd.h>
-
-#include <cutils/atomic.h>
-#include <cutils/properties.h> // for property_get
-
-#include <utils/misc.h>
-
-#include <android/content/pm/IPackageManagerNative.h>
-
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <binder/MemoryHeapBase.h>
-#include <binder/MemoryBase.h>
-#include <gui/Surface.h>
-#include <utils/Errors.h> // for status_t
-#include <utils/List.h>
-#include <utils/String8.h>
-#include <utils/SystemClock.h>
-#include <utils/Timers.h>
-#include <utils/Vector.h>
-
-#include <media/IMediaHTTPService.h>
-#include <media/IRemoteDisplay.h>
-#include <media/IRemoteDisplayClient.h>
-#include <media/MediaPlayerInterface.h>
-#include <media/mediarecorder.h>
-#include <media/MediaMetadataRetrieverInterface.h>
-#include <media/Metadata.h>
-#include <media/AudioTrack.h>
-#include <media/MemoryLeakTrackUtil.h>
-#include <media/stagefright/MediaCodecList.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/Utils.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/ALooperRoster.h>
-#include <mediautils/BatteryNotifier.h>
-
-//#include <memunreachable/memunreachable.h>
-#include <system/audio.h>
-
-#include <private/android_filesystem_config.h>
-
-#include "MediaAnalyticsService.h"
-
-namespace android {
-
-// individual records kept in memory: age or count
-// age: <= 28 hours (1 1/6 days)
-// count: hard limit of # records
-// (0 for either of these disables that threshold)
-//
-static constexpr nsecs_t kMaxRecordAgeNs = 28 * 3600 * (1000*1000*1000ll);
-// 2019/6: average daily per device is currently 375-ish;
-// setting this to 2000 is large enough to catch most devices
-// we'll lose some data on very very media-active devices, but only for
-// the gms collection; statsd will have already covered those for us.
-// This also retains enough information to help with bugreports
-static constexpr int kMaxRecords = 2000;
-
-// max we expire in a single call, to constrain how long we hold the
-// mutex, which also constrains how long a client might wait.
-static constexpr int kMaxExpiredAtOnce = 50;
-
-// TODO: need to look at tuning kMaxRecords and friends for low-memory devices
-
-static const char *kServiceName = "media.metrics";
-
-void MediaAnalyticsService::instantiate() {
- defaultServiceManager()->addService(
- String16(kServiceName), new MediaAnalyticsService());
-}
-
-MediaAnalyticsService::MediaAnalyticsService()
- : mMaxRecords(kMaxRecords),
- mMaxRecordAgeNs(kMaxRecordAgeNs),
- mMaxRecordsExpiredAtOnce(kMaxExpiredAtOnce),
- mDumpProto(MediaAnalyticsItem::PROTO_V1),
- mDumpProtoDefault(MediaAnalyticsItem::PROTO_V1) {
-
- ALOGD("MediaAnalyticsService created");
-
- mItemsSubmitted = 0;
- mItemsFinalized = 0;
- mItemsDiscarded = 0;
- mItemsDiscardedExpire = 0;
- mItemsDiscardedCount = 0;
-
- mLastSessionID = 0;
- // recover any persistency we set up
- // etc
-}
-
-MediaAnalyticsService::~MediaAnalyticsService() {
- ALOGD("MediaAnalyticsService destroyed");
-
- while (mItems.size() > 0) {
- MediaAnalyticsItem * oitem = *(mItems.begin());
- mItems.erase(mItems.begin());
- delete oitem;
- mItemsDiscarded++;
- mItemsDiscardedCount++;
- }
-}
-
-
-MediaAnalyticsItem::SessionID_t MediaAnalyticsService::generateUniqueSessionID() {
- // generate a new sessionid
-
- Mutex::Autolock _l(mLock_ids);
- return (++mLastSessionID);
-}
-
-// caller surrenders ownership of 'item'
-MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(MediaAnalyticsItem *item, bool forcenew)
-{
- UNUSED(forcenew);
-
- // fill in a sessionID if we do not yet have one
- if (item->getSessionID() <= MediaAnalyticsItem::SessionIDNone) {
- item->setSessionID(generateUniqueSessionID());
- }
-
- // we control these, generally not trusting user input
- nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
- // round nsecs to seconds
- now = ((now + 500000000) / 1000000000) * 1000000000;
- item->setTimestamp(now);
- int pid = IPCThreadState::self()->getCallingPid();
- int uid = IPCThreadState::self()->getCallingUid();
-
- int uid_given = item->getUid();
- int pid_given = item->getPid();
-
- // although we do make exceptions for some trusted client uids
- bool isTrusted = false;
-
- ALOGV("caller has uid=%d, embedded uid=%d", uid, uid_given);
-
- switch (uid) {
- case AID_MEDIA:
- case AID_MEDIA_CODEC:
- case AID_MEDIA_EX:
- case AID_MEDIA_DRM:
- // trusted source, only override default values
- isTrusted = true;
- if (uid_given == (-1)) {
- item->setUid(uid);
- }
- if (pid_given == (-1)) {
- item->setPid(pid);
- }
- break;
- default:
- isTrusted = false;
- item->setPid(pid);
- item->setUid(uid);
- break;
- }
-
- // Overwrite package name and version if the caller was untrusted.
- if (!isTrusted) {
- setPkgInfo(item, item->getUid(), true, true);
- } else if (item->getPkgName().empty()) {
- // empty, so fill out both parts
- setPkgInfo(item, item->getUid(), true, true);
- } else {
- // trusted, provided a package, do nothing
- }
-
- ALOGV("given uid %d; sanitized uid: %d sanitized pkg: %s "
- "sanitized pkg version: %" PRId64,
- uid_given, item->getUid(),
- item->getPkgName().c_str(),
- item->getPkgVersionCode());
-
- mItemsSubmitted++;
-
- // validate the record; we discard if we don't like it
- if (contentValid(item, isTrusted) == false) {
- delete item;
- return MediaAnalyticsItem::SessionIDInvalid;
- }
-
- // XXX: if we have a sessionid in the new record, look to make
- // sure it doesn't appear in the finalized list.
-
- if (item->count() == 0) {
- ALOGV("dropping empty record...");
- delete item;
- item = NULL;
- return MediaAnalyticsItem::SessionIDInvalid;
- }
-
- // save the new record
- //
- // send a copy to statsd
- dump2Statsd(item);
-
- // and keep our copy for dumpsys
- MediaAnalyticsItem::SessionID_t id = item->getSessionID();
- saveItem(item);
- mItemsFinalized++;
-
- return id;
-}
-
-
-status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)
-{
- const size_t SIZE = 512;
- char buffer[SIZE];
- String8 result;
-
- if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
- snprintf(buffer, SIZE, "Permission Denial: "
- "can't dump MediaAnalyticsService from pid=%d, uid=%d\n",
- IPCThreadState::self()->getCallingPid(),
- IPCThreadState::self()->getCallingUid());
- result.append(buffer);
- write(fd, result.string(), result.size());
- return NO_ERROR;
- }
-
- // crack any parameters
- String16 protoOption("-proto");
- int chosenProto = mDumpProtoDefault;
- String16 clearOption("-clear");
- bool clear = false;
- String16 sinceOption("-since");
- nsecs_t ts_since = 0;
- String16 helpOption("-help");
- String16 onlyOption("-only");
- std::string only;
- int n = args.size();
-
- for (int i = 0; i < n; i++) {
- String8 myarg(args[i]);
- if (args[i] == clearOption) {
- clear = true;
- } else if (args[i] == protoOption) {
- i++;
- if (i < n) {
- String8 value(args[i]);
- int proto = MediaAnalyticsItem::PROTO_V0;
- char *endp;
- const char *p = value.string();
- proto = strtol(p, &endp, 10);
- if (endp != p || *endp == '\0') {
- if (proto < MediaAnalyticsItem::PROTO_FIRST) {
- proto = MediaAnalyticsItem::PROTO_FIRST;
- } else if (proto > MediaAnalyticsItem::PROTO_LAST) {
- proto = MediaAnalyticsItem::PROTO_LAST;
- }
- chosenProto = proto;
- } else {
- result.append("unable to parse value for -proto\n\n");
- }
- } else {
- result.append("missing value for -proto\n\n");
- }
- } else if (args[i] == sinceOption) {
- i++;
- if (i < n) {
- String8 value(args[i]);
- char *endp;
- const char *p = value.string();
- ts_since = strtoll(p, &endp, 10);
- if (endp == p || *endp != '\0') {
- ts_since = 0;
- }
- } else {
- ts_since = 0;
- }
- // command line is milliseconds; internal units are nano-seconds
- ts_since *= 1000*1000;
- } else if (args[i] == onlyOption) {
- i++;
- if (i < n) {
- String8 value(args[i]);
- only = value.string();
- }
- } else if (args[i] == helpOption) {
- result.append("Recognized parameters:\n");
- result.append("-help this help message\n");
- result.append("-proto # dump using protocol #");
- result.append("-clear clears out saved records\n");
- result.append("-only X process records for component X\n");
- result.append("-since X include records since X\n");
- result.append(" (X is milliseconds since the UNIX epoch)\n");
- write(fd, result.string(), result.size());
- return NO_ERROR;
- }
- }
-
- Mutex::Autolock _l(mLock);
- // mutex between insertion and dumping the contents
-
- mDumpProto = chosenProto;
-
- // we ALWAYS dump this piece
- snprintf(buffer, SIZE, "Dump of the %s process:\n", kServiceName);
- result.append(buffer);
-
- dumpHeaders(result, ts_since);
-
- dumpRecent(result, ts_since, only.c_str());
-
-
- if (clear) {
- // remove everything from the finalized queue
- while (mItems.size() > 0) {
- MediaAnalyticsItem * oitem = *(mItems.begin());
- mItems.erase(mItems.begin());
- delete oitem;
- mItemsDiscarded++;
- }
-
- // shall we clear the summary data too?
-
- }
-
- write(fd, result.string(), result.size());
- return NO_ERROR;
-}
-
-// dump headers
-void MediaAnalyticsService::dumpHeaders(String8 &result, nsecs_t ts_since)
-{
- const size_t SIZE = 512;
- char buffer[SIZE];
-
- snprintf(buffer, SIZE, "Protocol Version: %d\n", mDumpProto);
- result.append(buffer);
-
- int enabled = MediaAnalyticsItem::isEnabled();
- if (enabled) {
- snprintf(buffer, SIZE, "Metrics gathering: enabled\n");
- } else {
- snprintf(buffer, SIZE, "Metrics gathering: DISABLED via property\n");
- }
- result.append(buffer);
-
- snprintf(buffer, SIZE,
- "Since Boot: Submissions: %8" PRId64
- " Accepted: %8" PRId64 "\n",
- mItemsSubmitted, mItemsFinalized);
- result.append(buffer);
- snprintf(buffer, SIZE,
- "Records Discarded: %8" PRId64
- " (by Count: %" PRId64 " by Expiration: %" PRId64 ")\n",
- mItemsDiscarded, mItemsDiscardedCount, mItemsDiscardedExpire);
- result.append(buffer);
- if (ts_since != 0) {
- snprintf(buffer, SIZE,
- "Emitting Queue entries more recent than: %" PRId64 "\n",
- (int64_t) ts_since);
- result.append(buffer);
- }
-}
-
-// the recent, detailed queues
-void MediaAnalyticsService::dumpRecent(String8 &result, nsecs_t ts_since, const char * only)
-{
- const size_t SIZE = 512;
- char buffer[SIZE];
-
- if (only != NULL && *only == '\0') {
- only = NULL;
- }
-
- // show the recently recorded records
- snprintf(buffer, sizeof(buffer), "\nFinalized Metrics (oldest first):\n");
- result.append(buffer);
- result.append(this->dumpQueue(ts_since, only));
-
- // show who is connected and injecting records?
- // talk about # records fed to the 'readers'
- // talk about # records we discarded, perhaps "discarded w/o reading" too
-}
-
-// caller has locked mLock...
-String8 MediaAnalyticsService::dumpQueue() {
- return dumpQueue((nsecs_t) 0, NULL);
-}
-
-String8 MediaAnalyticsService::dumpQueue(nsecs_t ts_since, const char * only) {
- String8 result;
- int slot = 0;
-
- if (mItems.empty()) {
- result.append("empty\n");
- } else {
- List<MediaAnalyticsItem *>::iterator it = mItems.begin();
- for (; it != mItems.end(); it++) {
- nsecs_t when = (*it)->getTimestamp();
- if (when < ts_since) {
- continue;
- }
- if (only != NULL &&
- strcmp(only, (*it)->getKey().c_str()) != 0) {
- ALOGV("Omit '%s', it's not '%s'", (*it)->getKey().c_str(), only);
- continue;
- }
- std::string entry = (*it)->toString(mDumpProto);
- result.appendFormat("%5d: %s\n", slot, entry.c_str());
- slot++;
- }
- }
-
- return result;
-}
-
-//
-// Our Cheap in-core, non-persistent records management.
-
-
-// we hold mLock when we get here
-// if item != NULL, it's the item we just inserted
-// true == more items eligible to be recovered
-bool MediaAnalyticsService::expirations_l(MediaAnalyticsItem *item)
-{
- bool more = false;
- int handled = 0;
-
- // keep removing old records the front until we're in-bounds (count)
- // since we invoke this with each insertion, it should be 0/1 iterations.
- if (mMaxRecords > 0) {
- while (mItems.size() > (size_t) mMaxRecords) {
- MediaAnalyticsItem * oitem = *(mItems.begin());
- if (oitem == item) {
- break;
- }
- if (handled >= mMaxRecordsExpiredAtOnce) {
- // unlikely in this loop
- more = true;
- break;
- }
- handled++;
- mItems.erase(mItems.begin());
- delete oitem;
- mItemsDiscarded++;
- mItemsDiscardedCount++;
- }
- }
-
- // keep removing old records the front until we're in-bounds (age)
- // limited to mMaxRecordsExpiredAtOnce items per invocation.
- if (mMaxRecordAgeNs > 0) {
- nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
- while (mItems.size() > 0) {
- MediaAnalyticsItem * oitem = *(mItems.begin());
- nsecs_t when = oitem->getTimestamp();
- if (oitem == item) {
- break;
- }
- // careful about timejumps too
- if ((now > when) && (now-when) <= mMaxRecordAgeNs) {
- // this (and the rest) are recent enough to keep
- break;
- }
- if (handled >= mMaxRecordsExpiredAtOnce) {
- // this represents "one too many"; tell caller there are
- // more to be reclaimed.
- more = true;
- break;
- }
- handled++;
- mItems.erase(mItems.begin());
- delete oitem;
- mItemsDiscarded++;
- mItemsDiscardedExpire++;
- }
- }
-
- // we only indicate whether there's more to clean;
- // caller chooses whether to schedule further cleanup.
- return more;
-}
-
-// process expirations in bite sized chunks, allowing new insertions through
-// runs in a pthread specifically started for this (which then exits)
-bool MediaAnalyticsService::processExpirations()
-{
- bool more;
- do {
- sleep(1);
- {
- Mutex::Autolock _l(mLock);
- more = expirations_l(NULL);
- if (!more) {
- break;
- }
- }
- } while (more);
- return true; // value is for std::future thread synchronization
-}
-
-// insert appropriately into queue
-void MediaAnalyticsService::saveItem(MediaAnalyticsItem * item)
-{
-
- Mutex::Autolock _l(mLock);
- // mutex between insertion and dumping the contents
-
- // we want to dump 'in FIFO order', so insert at the end
- mItems.push_back(item);
-
- // clean old stuff from the queue
- bool more = expirations_l(item);
-
- // consider scheduling some asynchronous cleaning, if not running
- if (more) {
- if (!mExpireFuture.valid()
- || mExpireFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
-
- mExpireFuture = std::async(std::launch::async, [this]()
- {return this->processExpirations();});
- }
- }
-}
-
-static std::string allowedKeys[] =
-{
- "audiopolicy",
- "audiorecord",
- "audiothread",
- "audiotrack",
- "codec",
- "extractor",
- "nuplayer",
-};
-
-static const int nAllowedKeys = sizeof(allowedKeys) / sizeof(allowedKeys[0]);
-
-// are the contents good
-bool MediaAnalyticsService::contentValid(MediaAnalyticsItem *item, bool isTrusted) {
-
- // untrusted uids can only send us a limited set of keys
- if (isTrusted == false) {
- // restrict to a specific set of keys
- std::string key = item->getKey();
-
- size_t i;
- for(i = 0; i < nAllowedKeys; i++) {
- if (key == allowedKeys[i]) {
- break;
- }
- }
- if (i == nAllowedKeys) {
- ALOGD("Ignoring (key): %s", item->toString().c_str());
- return false;
- }
- }
-
- // internal consistency
-
- return true;
-}
-
-// are we rate limited, normally false
-bool MediaAnalyticsService::rateLimited(MediaAnalyticsItem *) {
-
- return false;
-}
-
-// how long we hold package info before we re-fetch it
-#define PKG_EXPIRATION_NS (30*60*1000000000ll) // 30 minutes, in nsecs
-
-// give me the package name, perhaps going to find it
-// manages its own mutex operations internally
-void MediaAnalyticsService::setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion)
-{
- ALOGV("asking for packagename to go with uid=%d", uid);
-
- if (!setName && !setVersion) {
- // setting nothing? strange
- return;
- }
-
- nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
- struct UidToPkgMap mapping;
- mapping.uid = (uid_t)(-1);
-
- {
- Mutex::Autolock _l(mLock_mappings);
- int i = mPkgMappings.indexOfKey(uid);
- if (i >= 0) {
- mapping = mPkgMappings.valueAt(i);
- ALOGV("Expiration? uid %d expiration %" PRId64 " now %" PRId64,
- uid, mapping.expiration, now);
- if (mapping.expiration <= now) {
- // purge the stale entry and fall into re-fetching
- ALOGV("entry for uid %d expired, now= %" PRId64 "", uid, now);
- mPkgMappings.removeItemsAt(i);
- mapping.uid = (uid_t)(-1);
- }
- }
- }
-
- // if we did not find it
- if (mapping.uid == (uid_t)(-1)) {
- std::string pkg;
- std::string installer = "";
- int64_t versionCode = 0;
-
- struct passwd *pw = getpwuid(uid);
- if (pw) {
- pkg = pw->pw_name;
- }
-
- // find the proper value
-
- sp<IBinder> binder = NULL;
- sp<IServiceManager> sm = defaultServiceManager();
- if (sm == NULL) {
- ALOGE("defaultServiceManager failed");
- } else {
- binder = sm->getService(String16("package_native"));
- if (binder == NULL) {
- ALOGE("getService package_native failed");
- }
- }
-
- if (binder != NULL) {
- sp<content::pm::IPackageManagerNative> package_mgr =
- interface_cast<content::pm::IPackageManagerNative>(binder);
- binder::Status status;
-
- std::vector<int> uids;
- std::vector<std::string> names;
-
- uids.push_back(uid);
-
- status = package_mgr->getNamesForUids(uids, &names);
- if (!status.isOk()) {
- ALOGE("package_native::getNamesForUids failed: %s",
- status.exceptionMessage().c_str());
- } else {
- if (!names[0].empty()) {
- pkg = names[0].c_str();
- }
- }
-
- // strip any leading "shared:" strings that came back
- if (pkg.compare(0, 7, "shared:") == 0) {
- pkg.erase(0, 7);
- }
-
- // determine how pkg was installed and the versionCode
- //
- if (pkg.empty()) {
- // no name for us to manage
- } else if (strchr(pkg.c_str(), '.') == NULL) {
- // not of form 'com.whatever...'; assume internal and ok
- } else if (strncmp(pkg.c_str(), "android.", 8) == 0) {
- // android.* packages are assumed fine
- } else {
- String16 pkgName16(pkg.c_str());
- status = package_mgr->getInstallerForPackage(pkgName16, &installer);
- if (!status.isOk()) {
- ALOGE("package_native::getInstallerForPackage failed: %s",
- status.exceptionMessage().c_str());
- }
-
- // skip if we didn't get an installer
- if (status.isOk()) {
- status = package_mgr->getVersionCodeForPackage(pkgName16, &versionCode);
- if (!status.isOk()) {
- ALOGE("package_native::getVersionCodeForPackage failed: %s",
- status.exceptionMessage().c_str());
- }
- }
-
-
- ALOGV("package '%s' installed by '%s' versioncode %" PRId64 " / %" PRIx64,
- pkg.c_str(), installer.c_str(), versionCode, versionCode);
-
- if (strncmp(installer.c_str(), "com.android.", 12) == 0) {
- // from play store, we keep info
- } else if (strncmp(installer.c_str(), "com.google.", 11) == 0) {
- // some google source, we keep info
- } else if (strcmp(installer.c_str(), "preload") == 0) {
- // preloads, we keep the info
- } else if (installer.c_str()[0] == '\0') {
- // sideload (no installer); do not report
- pkg = "";
- versionCode = 0;
- } else {
- // unknown installer; do not report
- pkg = "";
- versionCode = 0;
- }
- }
- }
-
- // add it to the map, to save a subsequent lookup
- if (!pkg.empty()) {
- Mutex::Autolock _l(mLock_mappings);
- ALOGV("Adding uid %d pkg '%s'", uid, pkg.c_str());
- ssize_t i = mPkgMappings.indexOfKey(uid);
- if (i < 0) {
- mapping.uid = uid;
- mapping.pkg = pkg;
- mapping.installer = installer.c_str();
- mapping.versionCode = versionCode;
- mapping.expiration = now + PKG_EXPIRATION_NS;
- ALOGV("expiration for uid %d set to %" PRId64 "", uid, mapping.expiration);
-
- mPkgMappings.add(uid, mapping);
- }
- }
- }
-
- if (mapping.uid != (uid_t)(-1)) {
- if (setName) {
- item->setPkgName(mapping.pkg);
- }
- if (setVersion) {
- item->setPkgVersionCode(mapping.versionCode);
- }
- }
-}
-
-} // namespace android
diff --git a/services/mediaanalytics/MediaAnalyticsService.h b/services/mediaanalytics/MediaAnalyticsService.h
deleted file mode 100644
index 6c9cbaa..0000000
--- a/services/mediaanalytics/MediaAnalyticsService.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#ifndef ANDROID_MEDIAANALYTICSSERVICE_H
-#define ANDROID_MEDIAANALYTICSSERVICE_H
-
-#include <arpa/inet.h>
-
-#include <utils/threads.h>
-#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
-#include <utils/String8.h>
-#include <utils/List.h>
-
-#include <future>
-
-#include <media/IMediaAnalyticsService.h>
-
-namespace android {
-
-class MediaAnalyticsService : public BnMediaAnalyticsService
-{
-
- public:
-
- // on this side, caller surrenders ownership
- virtual int64_t submit(MediaAnalyticsItem *item, bool forcenew);
-
- static void instantiate();
- virtual status_t dump(int fd, const Vector<String16>& args);
-
- MediaAnalyticsService();
- virtual ~MediaAnalyticsService();
-
- bool processExpirations();
-
- private:
- MediaAnalyticsItem::SessionID_t generateUniqueSessionID();
-
- // statistics about our analytics
- int64_t mItemsSubmitted;
- int64_t mItemsFinalized;
- int64_t mItemsDiscarded;
- int64_t mItemsDiscardedExpire;
- int64_t mItemsDiscardedCount;
- MediaAnalyticsItem::SessionID_t mLastSessionID;
-
- // partitioned a bit so we don't over serialize
- mutable Mutex mLock;
- mutable Mutex mLock_ids;
- mutable Mutex mLock_mappings;
-
- // limit how many records we'll retain
- // by count (in each queue (open, finalized))
- int32_t mMaxRecords;
- // by time (none older than this long agan
- nsecs_t mMaxRecordAgeNs;
- // max to expire per expirations_l() invocation
- int32_t mMaxRecordsExpiredAtOnce;
- //
- // # of sets of summaries
- int32_t mMaxRecordSets;
- // nsecs until we start a new record set
- nsecs_t mNewSetInterval;
-
- // input validation after arrival from client
- bool contentValid(MediaAnalyticsItem *item, bool isTrusted);
- bool rateLimited(MediaAnalyticsItem *);
-
- // (oldest at front) so it prints nicely for dumpsys
- List<MediaAnalyticsItem *> mItems;
- void saveItem(MediaAnalyticsItem *);
-
- bool expirations_l(MediaAnalyticsItem *);
- std::future<bool> mExpireFuture;
-
- // support for generating output
- int mDumpProto;
- int mDumpProtoDefault;
- String8 dumpQueue();
- String8 dumpQueue(nsecs_t, const char *only);
-
- void dumpHeaders(String8 &result, nsecs_t ts_since);
- void dumpSummaries(String8 &result, nsecs_t ts_since, const char * only);
- void dumpRecent(String8 &result, nsecs_t ts_since, const char * only);
-
- // mapping uids to package names
- struct UidToPkgMap {
- uid_t uid;
- std::string pkg;
- std::string installer;
- int64_t versionCode;
- nsecs_t expiration;
- };
-
- KeyedVector<uid_t,struct UidToPkgMap> mPkgMappings;
- void setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion);
-
-};
-
-// hook to send things off to the statsd subsystem
-extern bool dump2Statsd(MediaAnalyticsItem *item);
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_MEDIAANALYTICSSERVICE_H
diff --git a/services/mediaanalytics/OWNERS b/services/mediaanalytics/OWNERS
deleted file mode 100644
index 9af258b..0000000
--- a/services/mediaanalytics/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-essick@google.com
diff --git a/services/mediaanalytics/iface_statsd.cpp b/services/mediaanalytics/iface_statsd.cpp
deleted file mode 100644
index 6845f06..0000000
--- a/services/mediaanalytics/iface_statsd.cpp
+++ /dev/null
@@ -1,92 +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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "iface_statsd"
-#include <utils/Log.h>
-
-#include <stdint.h>
-#include <inttypes.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <dirent.h>
-#include <pthread.h>
-#include <unistd.h>
-
-#include <string.h>
-#include <pwd.h>
-
-#include "MediaAnalyticsService.h"
-#include "iface_statsd.h"
-
-#include <statslog.h>
-
-namespace android {
-
-// set of routines that crack a MediaAnalyticsItem
-// and send it off to statsd with the appropriate hooks
-//
-// each MediaAnalyticsItem type (extractor, codec, nuplayer, etc)
-// has its own routine to handle this.
-//
-
-bool enabled_statsd = true;
-
-struct statsd_hooks {
- const char *key;
- bool (*handler)(MediaAnalyticsItem *);
-};
-
-// keep this sorted, so we can do binary searches
-struct statsd_hooks statsd_handlers[] =
-{
- { "audiopolicy", statsd_audiopolicy },
- { "audiorecord", statsd_audiorecord },
- { "audiothread", statsd_audiothread },
- { "audiotrack", statsd_audiotrack },
- { "codec", statsd_codec},
- { "drm.vendor.Google.WidevineCDM", statsd_widevineCDM },
- { "extractor", statsd_extractor },
- { "mediadrm", statsd_mediadrm },
- { "nuplayer", statsd_nuplayer },
- { "nuplayer2", statsd_nuplayer },
- { "recorder", statsd_recorder },
-};
-
-
-// give me a record, i'll look at the type and upload appropriately
-bool dump2Statsd(MediaAnalyticsItem *item) {
- if (item == NULL) return false;
-
- // get the key
- std::string key = item->getKey();
-
- if (!enabled_statsd) {
- ALOGV("statsd logging disabled for record key=%s", key.c_str());
- return false;
- }
-
- int i;
- for(i = 0;i < sizeof(statsd_handlers) / sizeof(statsd_handlers[0]) ; i++) {
- if (key == statsd_handlers[i].key) {
- return (*statsd_handlers[i].handler)(item);
- }
- }
- return false;
-}
-
-} // namespace android
diff --git a/services/mediaanalytics/iface_statsd.h b/services/mediaanalytics/iface_statsd.h
deleted file mode 100644
index f85d303..0000000
--- a/services/mediaanalytics/iface_statsd.h
+++ /dev/null
@@ -1,34 +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.
- */
-
-namespace android {
-
-extern bool enabled_statsd;
-
-// component specific dumpers
-extern bool statsd_audiopolicy(MediaAnalyticsItem *);
-extern bool statsd_audiorecord(MediaAnalyticsItem *);
-extern bool statsd_audiothread(MediaAnalyticsItem *);
-extern bool statsd_audiotrack(MediaAnalyticsItem *);
-extern bool statsd_codec(MediaAnalyticsItem *);
-extern bool statsd_extractor(MediaAnalyticsItem *);
-extern bool statsd_nuplayer(MediaAnalyticsItem *);
-extern bool statsd_recorder(MediaAnalyticsItem *);
-
-extern bool statsd_mediadrm(MediaAnalyticsItem *);
-extern bool statsd_widevineCDM(MediaAnalyticsItem *);
-
-} // namespace android
diff --git a/services/mediaanalytics/main_mediametrics.cpp b/services/mediaanalytics/main_mediametrics.cpp
deleted file mode 100644
index 8020a03..0000000
--- a/services/mediaanalytics/main_mediametrics.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "mediametrics"
-//#define LOG_NDEBUG 0
-
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
-#include <binder/IServiceManager.h>
-#include <utils/Log.h>
-//#include "RegisterExtensions.h"
-
-// from LOCAL_C_INCLUDES
-#include "MediaAnalyticsService.h"
-
-using namespace android;
-
-int main(int argc __unused, char **argv __unused)
-{
- signal(SIGPIPE, SIG_IGN);
-
- // to match the service name
- // we're replacing "/system/bin/mediametrics" with "media.metrics"
- // we add a ".", but discard the path components: we finish with a shorter string
- strcpy(argv[0], "media.metrics");
-
- sp<ProcessState> proc(ProcessState::self());
- sp<IServiceManager> sm(defaultServiceManager());
- ALOGI("ServiceManager: %p", sm.get());
-
- MediaAnalyticsService::instantiate();
-
- ProcessState::self()->startThreadPool();
- IPCThreadState::self()->joinThreadPool();
-}
diff --git a/services/mediaanalytics/statsd_audiopolicy.cpp b/services/mediaanalytics/statsd_audiopolicy.cpp
deleted file mode 100644
index 06c4dde..0000000
--- a/services/mediaanalytics/statsd_audiopolicy.cpp
+++ /dev/null
@@ -1,133 +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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "statsd_audiopolicy"
-#include <utils/Log.h>
-
-#include <dirent.h>
-#include <inttypes.h>
-#include <pthread.h>
-#include <pwd.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <statslog.h>
-
-#include "MediaAnalyticsService.h"
-#include "frameworks/base/core/proto/android/stats/mediametrics/mediametrics.pb.h"
-#include "iface_statsd.h"
-
-namespace android {
-
-bool statsd_audiopolicy(MediaAnalyticsItem *item)
-{
- if (item == NULL) return false;
-
- // these go into the statsd wrapper
- nsecs_t timestamp = item->getTimestamp();
- std::string pkgName = item->getPkgName();
- int64_t pkgVersionCode = item->getPkgVersionCode();
- int64_t mediaApexVersion = 0;
-
-
- // the rest into our own proto
- //
- ::android::stats::mediametrics::AudioPolicyData metrics_proto;
-
- // flesh out the protobuf we'll hand off with our data
- //
- //int32 char kAudioPolicyStatus[] = "android.media.audiopolicy.status";
- int32_t status = -1;
- if (item->getInt32("android.media.audiopolicy.status", &status)) {
- metrics_proto.set_status(status);
- }
- //string char kAudioPolicyRqstSrc[] = "android.media.audiopolicy.rqst.src";
- char *rqst_src = NULL;
- if (item->getCString("android.media.audiopolicy.rqst.src", &rqst_src)) {
- metrics_proto.set_request_source(rqst_src);
- }
- //string char kAudioPolicyRqstPkg[] = "android.media.audiopolicy.rqst.pkg";
- char *rqst_pkg = NULL;
- if (item->getCString("android.media.audiopolicy.rqst.pkg", &rqst_pkg)) {
- metrics_proto.set_request_package(rqst_pkg);
- }
- //int32 char kAudioPolicyRqstSession[] = "android.media.audiopolicy.rqst.session";
- int32_t rqst_session = -1;
- if (item->getInt32("android.media.audiopolicy.rqst.session", &rqst_session)) {
- metrics_proto.set_request_session(rqst_session);
- }
- //string char kAudioPolicyRqstDevice[] = "android.media.audiopolicy.rqst.device";
- char *rqst_device = NULL;
- if (item->getCString("android.media.audiopolicy.rqst.device", &rqst_device)) {
- metrics_proto.set_request_device(rqst_device);
- }
-
- //string char kAudioPolicyActiveSrc[] = "android.media.audiopolicy.active.src";
- char *active_src = NULL;
- if (item->getCString("android.media.audiopolicy.active.src", &active_src)) {
- metrics_proto.set_active_source(active_src);
- }
- //string char kAudioPolicyActivePkg[] = "android.media.audiopolicy.active.pkg";
- char *active_pkg = NULL;
- if (item->getCString("android.media.audiopolicy.active.pkg", &active_pkg)) {
- metrics_proto.set_active_package(active_pkg);
- }
- //int32 char kAudioPolicyActiveSession[] = "android.media.audiopolicy.active.session";
- int32_t active_session = -1;
- if (item->getInt32("android.media.audiopolicy.active.session", &active_session)) {
- metrics_proto.set_active_session(active_session);
- }
- //string char kAudioPolicyActiveDevice[] = "android.media.audiopolicy.active.device";
- char *active_device = NULL;
- if (item->getCString("android.media.audiopolicy.active.device", &active_device)) {
- metrics_proto.set_active_device(active_device);
- }
-
-
- std::string serialized;
- if (!metrics_proto.SerializeToString(&serialized)) {
- ALOGE("Failed to serialize audipolicy metrics");
- return false;
- }
-
- if (enabled_statsd) {
- android::util::BytesField bf_serialized( serialized.c_str(), serialized.size());
- (void)android::util::stats_write(android::util::MEDIAMETRICS_AUDIOPOLICY_REPORTED,
- timestamp, pkgName.c_str(), pkgVersionCode,
- mediaApexVersion,
- bf_serialized);
-
- } else {
- ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
- }
-
- // must free the strings that we were given
- free(rqst_src);
- free(rqst_pkg);
- free(rqst_device);
- free(active_src);
- free(active_pkg);
- free(active_device);
-
- return true;
-}
-
-};
diff --git a/services/mediaanalytics/statsd_audiorecord.cpp b/services/mediaanalytics/statsd_audiorecord.cpp
deleted file mode 100644
index c9edb27..0000000
--- a/services/mediaanalytics/statsd_audiorecord.cpp
+++ /dev/null
@@ -1,164 +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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "statsd_audiorecord"
-#include <utils/Log.h>
-
-#include <dirent.h>
-#include <inttypes.h>
-#include <pthread.h>
-#include <pwd.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <statslog.h>
-
-#include "MediaAnalyticsService.h"
-#include "frameworks/base/core/proto/android/stats/mediametrics/mediametrics.pb.h"
-#include "iface_statsd.h"
-
-namespace android {
-
-bool statsd_audiorecord(MediaAnalyticsItem *item)
-{
- if (item == NULL) return false;
-
- // these go into the statsd wrapper
- nsecs_t timestamp = item->getTimestamp();
- std::string pkgName = item->getPkgName();
- int64_t pkgVersionCode = item->getPkgVersionCode();
- int64_t mediaApexVersion = 0;
-
-
- // the rest into our own proto
- //
- ::android::stats::mediametrics::AudioRecordData metrics_proto;
-
- // flesh out the protobuf we'll hand off with our data
- //
- char *encoding = NULL;
- if (item->getCString("android.media.audiorecord.encoding", &encoding)) {
- metrics_proto.set_encoding(encoding);
- }
-
- char *source = NULL;
- if (item->getCString("android.media.audiorecord.source", &source)) {
- metrics_proto.set_source(source);
- }
-
- int32_t latency = -1;
- if (item->getInt32("android.media.audiorecord.latency", &latency)) {
- metrics_proto.set_latency(latency);
- }
-
- int32_t samplerate = -1;
- if (item->getInt32("android.media.audiorecord.samplerate", &samplerate)) {
- metrics_proto.set_samplerate(samplerate);
- }
-
- int32_t channels = -1;
- if (item->getInt32("android.media.audiorecord.channels", &channels)) {
- metrics_proto.set_channels(channels);
- }
-
- int64_t createdMs = -1;
- if (item->getInt64("android.media.audiorecord.createdMs", &createdMs)) {
- metrics_proto.set_created_millis(createdMs);
- }
-
- int64_t durationMs = -1;
- if (item->getInt64("android.media.audiorecord.durationMs", &durationMs)) {
- metrics_proto.set_duration_millis(durationMs);
- }
-
- int32_t count = -1;
- if (item->getInt32("android.media.audiorecord.n", &count)) {
- metrics_proto.set_count(count);
- }
-
- int32_t errcode = -1;
- if (item->getInt32("android.media.audiorecord.errcode", &errcode)) {
- metrics_proto.set_error_code(errcode);
- } else if (item->getInt32("android.media.audiorecord.lastError.code", &errcode)) {
- metrics_proto.set_error_code(errcode);
- }
-
- char *errfunc = NULL;
- if (item->getCString("android.media.audiorecord.errfunc", &errfunc)) {
- metrics_proto.set_error_function(errfunc);
- } else if (item->getCString("android.media.audiorecord.lastError.at", &errfunc)) {
- metrics_proto.set_error_function(errfunc);
- }
-
- // portId (int32)
- int32_t port_id = -1;
- if (item->getInt32("android.media.audiorecord.portId", &port_id)) {
- metrics_proto.set_port_id(count);
- }
- // frameCount (int32)
- int32_t frameCount = -1;
- if (item->getInt32("android.media.audiorecord.frameCount", &frameCount)) {
- metrics_proto.set_frame_count(frameCount);
- }
- // attributes (string)
- char *attributes = NULL;
- if (item->getCString("android.media.audiorecord.attributes", &attributes)) {
- metrics_proto.set_attributes(attributes);
- }
- // channelMask (int64)
- int64_t channelMask = -1;
- if (item->getInt64("android.media.audiorecord.channelMask", &channelMask)) {
- metrics_proto.set_channel_mask(channelMask);
- }
- // startcount (int64)
- int64_t startcount = -1;
- if (item->getInt64("android.media.audiorecord.startcount", &startcount)) {
- metrics_proto.set_start_count(startcount);
- }
-
-
- std::string serialized;
- if (!metrics_proto.SerializeToString(&serialized)) {
- ALOGE("Failed to serialize audiorecord metrics");
- return false;
- }
-
- if (enabled_statsd) {
- android::util::BytesField bf_serialized( serialized.c_str(), serialized.size());
- (void)android::util::stats_write(android::util::MEDIAMETRICS_AUDIORECORD_REPORTED,
- timestamp, pkgName.c_str(), pkgVersionCode,
- mediaApexVersion,
- bf_serialized);
-
- } else {
- ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
- }
-
- // must free the strings that we were given
- free(encoding);
- free(source);
- free(errfunc);
- free(attributes);
-
- return true;
-}
-
-};
diff --git a/services/mediaanalytics/statsd_audiothread.cpp b/services/mediaanalytics/statsd_audiothread.cpp
deleted file mode 100644
index 8232424..0000000
--- a/services/mediaanalytics/statsd_audiothread.cpp
+++ /dev/null
@@ -1,217 +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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "statsd_audiothread"
-#include <utils/Log.h>
-
-#include <dirent.h>
-#include <inttypes.h>
-#include <pthread.h>
-#include <pwd.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <statslog.h>
-
-#include "MediaAnalyticsService.h"
-#include "frameworks/base/core/proto/android/stats/mediametrics/mediametrics.pb.h"
-#include "iface_statsd.h"
-
-namespace android {
-
-bool statsd_audiothread(MediaAnalyticsItem *item)
-{
- if (item == NULL) return false;
-
- // these go into the statsd wrapper
- nsecs_t timestamp = item->getTimestamp();
- std::string pkgName = item->getPkgName();
- int64_t pkgVersionCode = item->getPkgVersionCode();
- int64_t mediaApexVersion = 0;
-
-
- // the rest into our own proto
- //
- ::android::stats::mediametrics::AudioThreadData metrics_proto;
-
-#define MM_PREFIX "android.media.audiothread."
-
- // flesh out the protobuf we'll hand off with our data
- //
- char *mytype = NULL;
- if (item->getCString(MM_PREFIX "type", &mytype)) {
- metrics_proto.set_type(mytype);
- }
- int32_t framecount = -1;
- if (item->getInt32(MM_PREFIX "framecount", &framecount)) {
- metrics_proto.set_framecount(framecount);
- }
- int32_t samplerate = -1;
- if (item->getInt32(MM_PREFIX "samplerate", &samplerate)) {
- metrics_proto.set_samplerate(samplerate);
- }
- char *workhist = NULL;
- if (item->getCString(MM_PREFIX "workMs.hist", &workhist)) {
- metrics_proto.set_work_millis_hist(workhist);
- }
- char *latencyhist = NULL;
- if (item->getCString(MM_PREFIX "latencyMs.hist", &latencyhist)) {
- metrics_proto.set_latency_millis_hist(latencyhist);
- }
- char *warmuphist = NULL;
- if (item->getCString(MM_PREFIX "warmupMs.hist", &warmuphist)) {
- metrics_proto.set_warmup_millis_hist(warmuphist);
- }
- int64_t underruns = -1;
- if (item->getInt64(MM_PREFIX "underruns", &underruns)) {
- metrics_proto.set_underruns(underruns);
- }
- int64_t overruns = -1;
- if (item->getInt64(MM_PREFIX "overruns", &overruns)) {
- metrics_proto.set_overruns(overruns);
- }
- int64_t activeMs = -1;
- if (item->getInt64(MM_PREFIX "activeMs", &activeMs)) {
- metrics_proto.set_active_millis(activeMs);
- }
- int64_t durationMs = -1;
- if (item->getInt64(MM_PREFIX "durationMs", &durationMs)) {
- metrics_proto.set_duration_millis(durationMs);
- }
-
- // item->setInt32(MM_PREFIX "id", (int32_t)mId); // IO handle
- int32_t id = -1;
- if (item->getInt32(MM_PREFIX "id", &id)) {
- metrics_proto.set_id(id);
- }
- // item->setInt32(MM_PREFIX "portId", (int32_t)mPortId);
- int32_t port_id = -1;
- if (item->getInt32(MM_PREFIX "portId", &id)) {
- metrics_proto.set_port_id(port_id);
- }
- // item->setCString(MM_PREFIX "type", threadTypeToString(mType));
- char *type = NULL;
- if (item->getCString(MM_PREFIX "type", &type)) {
- metrics_proto.set_type(type);
- }
- // item->setInt32(MM_PREFIX "sampleRate", (int32_t)mSampleRate);
- int32_t sample_rate = -1;
- if (item->getInt32(MM_PREFIX "sampleRate", &sample_rate)) {
- metrics_proto.set_sample_rate(sample_rate);
- }
- // item->setInt64(MM_PREFIX "channelMask", (int64_t)mChannelMask);
- int32_t channel_mask = -1;
- if (item->getInt32(MM_PREFIX "channelMask", &channel_mask)) {
- metrics_proto.set_channel_mask(channel_mask);
- }
- // item->setCString(MM_PREFIX "encoding", toString(mFormat).c_str());
- char *encoding = NULL;
- if (item->getCString(MM_PREFIX "encoding", &encoding)) {
- metrics_proto.set_encoding(encoding);
- }
- // item->setInt32(MM_PREFIX "frameCount", (int32_t)mFrameCount);
- int32_t frame_count = -1;
- if (item->getInt32(MM_PREFIX "frameCount", &frame_count)) {
- metrics_proto.set_frame_count(frame_count);
- }
- // item->setCString(MM_PREFIX "outDevice", toString(mOutDevice).c_str());
- char *outDevice = NULL;
- if (item->getCString(MM_PREFIX "outDevice", &outDevice)) {
- metrics_proto.set_output_device(outDevice);
- }
- // item->setCString(MM_PREFIX "inDevice", toString(mInDevice).c_str());
- char *inDevice = NULL;
- if (item->getCString(MM_PREFIX "inDevice", &inDevice)) {
- metrics_proto.set_input_device(inDevice);
- }
- // item->setDouble(MM_PREFIX "ioJitterMs.mean", mIoJitterMs.getMean());
- double iojitters_ms_mean = -1;
- if (item->getDouble(MM_PREFIX "ioJitterMs.mean", &iojitters_ms_mean)) {
- metrics_proto.set_io_jitter_mean_millis(iojitters_ms_mean);
- }
- // item->setDouble(MM_PREFIX "ioJitterMs.std", mIoJitterMs.getStdDev());
- double iojitters_ms_std = -1;
- if (item->getDouble(MM_PREFIX "ioJitterMs.std", &iojitters_ms_std)) {
- metrics_proto.set_io_jitter_stddev_millis(iojitters_ms_std);
- }
- // item->setDouble(MM_PREFIX "processTimeMs.mean", mProcessTimeMs.getMean());
- double process_time_ms_mean = -1;
- if (item->getDouble(MM_PREFIX "processTimeMs.mean", &process_time_ms_mean)) {
- metrics_proto.set_process_time_mean_millis(process_time_ms_mean);
- }
- // item->setDouble(MM_PREFIX "processTimeMs.std", mProcessTimeMs.getStdDev());
- double process_time_ms_std = -1;
- if (item->getDouble(MM_PREFIX "processTimeMs.std", &process_time_ms_std)) {
- metrics_proto.set_process_time_stddev_millis(process_time_ms_std);
- }
- // item->setDouble(MM_PREFIX "timestampJitterMs.mean", tsjitter.getMean());
- double timestamp_jitter_ms_mean = -1;
- if (item->getDouble(MM_PREFIX "timestampJitterMs.mean", ×tamp_jitter_ms_mean)) {
- metrics_proto.set_timestamp_jitter_mean_millis(timestamp_jitter_ms_mean);
- }
- // item->setDouble(MM_PREFIX "timestampJitterMs.std", tsjitter.getStdDev());
- double timestamp_jitter_ms_stddev = -1;
- if (item->getDouble(MM_PREFIX "timestampJitterMs.std", ×tamp_jitter_ms_stddev)) {
- metrics_proto.set_timestamp_jitter_stddev_millis(timestamp_jitter_ms_stddev);
- }
- // item->setDouble(MM_PREFIX "latencyMs.mean", mLatencyMs.getMean());
- double latency_ms_mean = -1;
- if (item->getDouble(MM_PREFIX "latencyMs.mean", &latency_ms_mean)) {
- metrics_proto.set_latency_mean_millis(latency_ms_mean);
- }
- // item->setDouble(MM_PREFIX "latencyMs.std", mLatencyMs.getStdDev());
- double latency_ms_stddev = -1;
- if (item->getDouble(MM_PREFIX "latencyMs.std", &latency_ms_stddev)) {
- metrics_proto.set_latency_stddev_millis(latency_ms_stddev);
- }
-
-
- std::string serialized;
- if (!metrics_proto.SerializeToString(&serialized)) {
- ALOGE("Failed to serialize audiothread metrics");
- return false;
- }
-
- if (enabled_statsd) {
- android::util::BytesField bf_serialized( serialized.c_str(), serialized.size());
- (void)android::util::stats_write(android::util::MEDIAMETRICS_AUDIOTHREAD_REPORTED,
- timestamp, pkgName.c_str(), pkgVersionCode,
- mediaApexVersion,
- bf_serialized);
-
- } else {
- ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
- }
-
- // must free the strings that we were given
- free(mytype);
- free(workhist);
- free(latencyhist);
- free(warmuphist);
- free(type);
- free(encoding);
- free(inDevice);
- free(outDevice);
-
- return true;
-}
-
-};
diff --git a/services/mediaanalytics/statsd_audiotrack.cpp b/services/mediaanalytics/statsd_audiotrack.cpp
deleted file mode 100644
index f250ced..0000000
--- a/services/mediaanalytics/statsd_audiotrack.cpp
+++ /dev/null
@@ -1,156 +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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "statsd_audiotrack"
-#include <utils/Log.h>
-
-#include <dirent.h>
-#include <inttypes.h>
-#include <pthread.h>
-#include <pwd.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <statslog.h>
-
-#include "MediaAnalyticsService.h"
-#include "frameworks/base/core/proto/android/stats/mediametrics/mediametrics.pb.h"
-#include "iface_statsd.h"
-
-namespace android {
-
-bool statsd_audiotrack(MediaAnalyticsItem *item)
-{
- if (item == NULL) return false;
-
- // these go into the statsd wrapper
- nsecs_t timestamp = item->getTimestamp();
- std::string pkgName = item->getPkgName();
- int64_t pkgVersionCode = item->getPkgVersionCode();
- int64_t mediaApexVersion = 0;
-
-
- // the rest into our own proto
- //
- ::android::stats::mediametrics::AudioTrackData metrics_proto;
-
- // flesh out the protobuf we'll hand off with our data
- //
-
- // static constexpr char kAudioTrackStreamType[] = "android.media.audiotrack.streamtype";
- // optional string streamType;
- char *streamtype = NULL;
- if (item->getCString("android.media.audiotrack.streamtype", &streamtype)) {
- metrics_proto.set_stream_type(streamtype);
- }
-
- // static constexpr char kAudioTrackContentType[] = "android.media.audiotrack.type";
- // optional string contentType;
- char *contenttype = NULL;
- if (item->getCString("android.media.audiotrack.type", &contenttype)) {
- metrics_proto.set_content_type(contenttype);
- }
-
- // static constexpr char kAudioTrackUsage[] = "android.media.audiotrack.usage";
- // optional string trackUsage;
- char *trackusage = NULL;
- if (item->getCString("android.media.audiotrack.usage", &trackusage)) {
- metrics_proto.set_track_usage(trackusage);
- }
-
- // static constexpr char kAudioTrackSampleRate[] = "android.media.audiotrack.samplerate";
- // optional int32 samplerate;
- int32_t samplerate = -1;
- if (item->getInt32("android.media.audiotrack.samplerate", &samplerate)) {
- metrics_proto.set_sample_rate(samplerate);
- }
-
- // static constexpr char kAudioTrackChannelMask[] = "android.media.audiotrack.channelmask";
- // optional int64 channelMask;
- int64_t channelMask = -1;
- if (item->getInt64("android.media.audiotrack.channelmask", &channelMask)) {
- metrics_proto.set_channel_mask(channelMask);
- }
-
- // NB: These are not yet exposed as public Java API constants.
- // static constexpr char kAudioTrackUnderrunFrames[] = "android.media.audiotrack.underrunframes";
- // optional int32 underrunframes;
- int32_t underrunframes = -1;
- if (item->getInt32("android.media.audiotrack.underrunframes", &underrunframes)) {
- metrics_proto.set_underrun_frames(underrunframes);
- }
-
- // static constexpr char kAudioTrackStartupGlitch[] = "android.media.audiotrack.glitch.startup";
- // optional int32 startupglitch;
- int32_t startupglitch = -1;
- if (item->getInt32("android.media.audiotrack.glitch.startup", &startupglitch)) {
- metrics_proto.set_startup_glitch(startupglitch);
- }
-
- // portId (int32)
- int32_t port_id = -1;
- if (item->getInt32("android.media.audiotrack.portId", &port_id)) {
- metrics_proto.set_port_id(port_id);
- }
- // encoding (string)
- char *encoding = NULL;
- if (item->getCString("android.media.audiotrack.encoding", &encoding)) {
- metrics_proto.set_encoding(encoding);
- }
- // frameCount (int32)
- int32_t frame_count = -1;
- if (item->getInt32("android.media.audiotrack.frameCount", &frame_count)) {
- metrics_proto.set_frame_count(frame_count);
- }
- // attributes (string)
- char *attributes = NULL;
- if (item->getCString("android.media.audiotrack.attributes", &attributes)) {
- metrics_proto.set_attributes(attributes);
- }
-
- std::string serialized;
- if (!metrics_proto.SerializeToString(&serialized)) {
- ALOGE("Failed to serialize audiotrack metrics");
- return false;
- }
-
- if (enabled_statsd) {
- android::util::BytesField bf_serialized( serialized.c_str(), serialized.size());
- (void)android::util::stats_write(android::util::MEDIAMETRICS_AUDIOTRACK_REPORTED,
- timestamp, pkgName.c_str(), pkgVersionCode,
- mediaApexVersion,
- bf_serialized);
-
- } else {
- ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
- }
-
- // must free the strings that we were given
- free(streamtype);
- free(contenttype);
- free(trackusage);
- free(encoding);
- free(attributes);
-
- return true;
-}
-
-};
diff --git a/services/mediaanalytics/statsd_codec.cpp b/services/mediaanalytics/statsd_codec.cpp
deleted file mode 100644
index dc8e4ef..0000000
--- a/services/mediaanalytics/statsd_codec.cpp
+++ /dev/null
@@ -1,185 +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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "statsd_codec"
-#include <utils/Log.h>
-
-#include <dirent.h>
-#include <inttypes.h>
-#include <pthread.h>
-#include <pwd.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <statslog.h>
-
-#include "MediaAnalyticsService.h"
-#include "frameworks/base/core/proto/android/stats/mediametrics/mediametrics.pb.h"
-#include "iface_statsd.h"
-
-namespace android {
-
-bool statsd_codec(MediaAnalyticsItem *item)
-{
- if (item == NULL) return false;
-
- // these go into the statsd wrapper
- nsecs_t timestamp = item->getTimestamp();
- std::string pkgName = item->getPkgName();
- int64_t pkgVersionCode = item->getPkgVersionCode();
- int64_t mediaApexVersion = 0;
-
-
- // the rest into our own proto
- //
- ::android::stats::mediametrics::CodecData metrics_proto;
-
- // flesh out the protobuf we'll hand off with our data
- //
- // android.media.mediacodec.codec string
- char *codec = NULL;
- if (item->getCString("android.media.mediacodec.codec", &codec)) {
- metrics_proto.set_codec(codec);
- }
- // android.media.mediacodec.mime string
- char *mime = NULL;
- if (item->getCString("android.media.mediacodec.mime", &mime)) {
- metrics_proto.set_mime(mime);
- }
- // android.media.mediacodec.mode string
- char *mode = NULL;
- if ( item->getCString("android.media.mediacodec.mode", &mode)) {
- metrics_proto.set_mode(mode);
- }
- // android.media.mediacodec.encoder int32
- int32_t encoder = -1;
- if ( item->getInt32("android.media.mediacodec.encoder", &encoder)) {
- metrics_proto.set_encoder(encoder);
- }
- // android.media.mediacodec.secure int32
- int32_t secure = -1;
- if ( item->getInt32("android.media.mediacodec.secure", &secure)) {
- metrics_proto.set_secure(secure);
- }
- // android.media.mediacodec.width int32
- int32_t width = -1;
- if ( item->getInt32("android.media.mediacodec.width", &width)) {
- metrics_proto.set_width(width);
- }
- // android.media.mediacodec.height int32
- int32_t height = -1;
- if ( item->getInt32("android.media.mediacodec.height", &height)) {
- metrics_proto.set_height(height);
- }
- // android.media.mediacodec.rotation-degrees int32
- int32_t rotation = -1;
- if ( item->getInt32("android.media.mediacodec.rotation-degrees", &rotation)) {
- metrics_proto.set_rotation(rotation);
- }
- // 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);
- }
- // android.media.mediacodec.profile int32
- int32_t profile = -1;
- if ( item->getInt32("android.media.mediacodec.profile", &profile)) {
- metrics_proto.set_profile(profile);
- }
- // android.media.mediacodec.level int32
- int32_t level = -1;
- if ( item->getInt32("android.media.mediacodec.level", &level)) {
- metrics_proto.set_level(level);
- }
- // android.media.mediacodec.maxwidth int32
- int32_t maxwidth = -1;
- if ( item->getInt32("android.media.mediacodec.maxwidth", &maxwidth)) {
- metrics_proto.set_max_width(maxwidth);
- }
- // android.media.mediacodec.maxheight int32
- int32_t maxheight = -1;
- if ( item->getInt32("android.media.mediacodec.maxheight", &maxheight)) {
- metrics_proto.set_max_height(maxheight);
- }
- // android.media.mediacodec.errcode int32
- int32_t errcode = -1;
- if ( item->getInt32("android.media.mediacodec.errcode", &errcode)) {
- metrics_proto.set_error_code(errcode);
- }
- // android.media.mediacodec.errstate string
- char *errstate = NULL;
- if ( item->getCString("android.media.mediacodec.errstate", &errstate)) {
- metrics_proto.set_error_state(errstate);
- }
- // android.media.mediacodec.latency.max int64
- int64_t latency_max = -1;
- if ( item->getInt64("android.media.mediacodec.latency.max", &latency_max)) {
- metrics_proto.set_latency_max(latency_max);
- }
- // android.media.mediacodec.latency.min int64
- int64_t latency_min = -1;
- if ( item->getInt64("android.media.mediacodec.latency.min", &latency_min)) {
- metrics_proto.set_latency_min(latency_min);
- }
- // android.media.mediacodec.latency.avg int64
- int64_t latency_avg = -1;
- if ( item->getInt64("android.media.mediacodec.latency.avg", &latency_avg)) {
- metrics_proto.set_latency_avg(latency_avg);
- }
- // android.media.mediacodec.latency.n int64
- int64_t latency_count = -1;
- if ( item->getInt64("android.media.mediacodec.latency.n", &latency_count)) {
- metrics_proto.set_latency_count(latency_count);
- }
- // android.media.mediacodec.latency.unknown int64
- int64_t latency_unknown = -1;
- if ( item->getInt64("android.media.mediacodec.latency.unknown", &latency_unknown)) {
- metrics_proto.set_latency_unknown(latency_unknown);
- }
- // android.media.mediacodec.latency.hist NOT EMITTED
-
- std::string serialized;
- if (!metrics_proto.SerializeToString(&serialized)) {
- ALOGE("Failed to serialize codec metrics");
- return false;
- }
-
- if (enabled_statsd) {
- android::util::BytesField bf_serialized( serialized.c_str(), serialized.size());
- (void)android::util::stats_write(android::util::MEDIAMETRICS_CODEC_REPORTED,
- timestamp, pkgName.c_str(), pkgVersionCode,
- mediaApexVersion,
- bf_serialized);
-
- } else {
- ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
- }
-
- // must free the strings that we were given
- free(codec);
- free(mime);
- free(mode);
- free(errstate);
-
- return true;
-}
-
-};
diff --git a/services/mediaanalytics/statsd_drm.cpp b/services/mediaanalytics/statsd_drm.cpp
deleted file mode 100644
index 902483a..0000000
--- a/services/mediaanalytics/statsd_drm.cpp
+++ /dev/null
@@ -1,107 +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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "statsd_drm"
-#include <utils/Log.h>
-
-#include <stdint.h>
-#include <inttypes.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <dirent.h>
-#include <pthread.h>
-#include <unistd.h>
-
-#include <string.h>
-#include <pwd.h>
-
-#include "MediaAnalyticsService.h"
-#include "iface_statsd.h"
-
-#include <statslog.h>
-
-namespace android {
-
-// mediadrm
-bool statsd_mediadrm(MediaAnalyticsItem *item)
-{
- if (item == NULL) return false;
-
- nsecs_t timestamp = item->getTimestamp();
- std::string pkgName = item->getPkgName();
- int64_t pkgVersionCode = item->getPkgVersionCode();
- int64_t mediaApexVersion = 0;
-
- char *vendor = NULL;
- (void) item->getCString("vendor", &vendor);
- char *description = NULL;
- (void) item->getCString("description", &description);
- char *serialized_metrics = NULL;
- (void) item->getCString("serialized_metrics", &serialized_metrics);
-
- if (enabled_statsd) {
- android::util::BytesField bf_serialized(serialized_metrics ? serialized_metrics : NULL,
- serialized_metrics ? strlen(serialized_metrics)
- : 0);
- android::util::stats_write(android::util::MEDIAMETRICS_MEDIADRM_REPORTED,
- timestamp, pkgName.c_str(), pkgVersionCode,
- mediaApexVersion,
- vendor, description,
- bf_serialized);
- } else {
- ALOGV("NOT sending: mediadrm private data (len=%zu)",
- serialized_metrics ? strlen(serialized_metrics) : 0);
- }
-
- free(vendor);
- free(description);
- free(serialized_metrics);
- return true;
-}
-
-// widevineCDM
-bool statsd_widevineCDM(MediaAnalyticsItem *item)
-{
- if (item == NULL) return false;
-
- nsecs_t timestamp = item->getTimestamp();
- std::string pkgName = item->getPkgName();
- int64_t pkgVersionCode = item->getPkgVersionCode();
- int64_t mediaApexVersion = 0;
-
- char *serialized_metrics = NULL;
- (void) item->getCString("serialized_metrics", &serialized_metrics);
-
- if (enabled_statsd) {
- android::util::BytesField bf_serialized(serialized_metrics ? serialized_metrics : NULL,
- serialized_metrics ? strlen(serialized_metrics)
- : 0);
- android::util::stats_write(android::util::MEDIAMETRICS_DRM_WIDEVINE_REPORTED,
- timestamp, pkgName.c_str(), pkgVersionCode,
- mediaApexVersion,
- bf_serialized);
- } else {
- ALOGV("NOT sending: widevine private data (len=%zu)",
- serialized_metrics ? strlen(serialized_metrics) : 0);
- }
-
- free(serialized_metrics);
- return true;
-}
-
-} // namespace android
diff --git a/services/mediaanalytics/statsd_extractor.cpp b/services/mediaanalytics/statsd_extractor.cpp
deleted file mode 100644
index 395c912..0000000
--- a/services/mediaanalytics/statsd_extractor.cpp
+++ /dev/null
@@ -1,98 +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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "statsd_extractor"
-#include <utils/Log.h>
-
-#include <dirent.h>
-#include <inttypes.h>
-#include <pthread.h>
-#include <pwd.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <statslog.h>
-
-#include "MediaAnalyticsService.h"
-#include "frameworks/base/core/proto/android/stats/mediametrics/mediametrics.pb.h"
-#include "iface_statsd.h"
-
-namespace android {
-
-bool statsd_extractor(MediaAnalyticsItem *item)
-{
- if (item == NULL) return false;
-
- // these go into the statsd wrapper
- nsecs_t timestamp = item->getTimestamp();
- std::string pkgName = item->getPkgName();
- int64_t pkgVersionCode = item->getPkgVersionCode();
- int64_t mediaApexVersion = 0;
-
-
- // the rest into our own proto
- //
- ::android::stats::mediametrics::ExtractorData metrics_proto;
-
- // flesh out the protobuf we'll hand off with our data
- //
-
- // android.media.mediaextractor.fmt string
- char *fmt = NULL;
- if (item->getCString("android.media.mediaextractor.fmt", &fmt)) {
- metrics_proto.set_format(fmt);
- }
- // android.media.mediaextractor.mime string
- char *mime = NULL;
- if (item->getCString("android.media.mediaextractor.mime", &mime)) {
- metrics_proto.set_mime(mime);
- }
- // android.media.mediaextractor.ntrk int32
- int32_t ntrk = -1;
- if (item->getInt32("android.media.mediaextractor.ntrk", &ntrk)) {
- metrics_proto.set_tracks(ntrk);
- }
-
- std::string serialized;
- if (!metrics_proto.SerializeToString(&serialized)) {
- ALOGE("Failed to serialize extractor metrics");
- return false;
- }
-
- if (enabled_statsd) {
- android::util::BytesField bf_serialized( serialized.c_str(), serialized.size());
- (void)android::util::stats_write(android::util::MEDIAMETRICS_EXTRACTOR_REPORTED,
- timestamp, pkgName.c_str(), pkgVersionCode,
- mediaApexVersion,
- bf_serialized);
-
- } else {
- ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
- }
-
- // must free the strings that we were given
- free(fmt);
- free(mime);
-
- return true;
-}
-
-};
diff --git a/services/mediaanalytics/statsd_nuplayer.cpp b/services/mediaanalytics/statsd_nuplayer.cpp
deleted file mode 100644
index 5ec118a..0000000
--- a/services/mediaanalytics/statsd_nuplayer.cpp
+++ /dev/null
@@ -1,178 +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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "statsd_nuplayer"
-#include <utils/Log.h>
-
-#include <dirent.h>
-#include <inttypes.h>
-#include <pthread.h>
-#include <pwd.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <statslog.h>
-
-#include "MediaAnalyticsService.h"
-#include "frameworks/base/core/proto/android/stats/mediametrics/mediametrics.pb.h"
-#include "iface_statsd.h"
-
-namespace android {
-
-/*
- * handles nuplayer AND nuplayer2
- * checks for the union of what the two players generate
- */
-bool statsd_nuplayer(MediaAnalyticsItem *item)
-{
- if (item == NULL) return false;
-
- // these go into the statsd wrapper
- nsecs_t timestamp = item->getTimestamp();
- std::string pkgName = item->getPkgName();
- int64_t pkgVersionCode = item->getPkgVersionCode();
- int64_t mediaApexVersion = 0;
-
-
- // the rest into our own proto
- //
- ::android::stats::mediametrics::NuPlayerData metrics_proto;
-
- // flesh out the protobuf we'll hand off with our data
- //
-
- // differentiate between nuplayer and nuplayer2
- metrics_proto.set_whichplayer(item->getKey().c_str());
-
- char *video_mime = NULL;
- if (item->getCString("android.media.mediaplayer.video.mime", &video_mime)) {
- metrics_proto.set_video_mime(video_mime);
- }
- char *video_codec = NULL;
- if (item->getCString("android.media.mediaplayer.video.codec", &video_codec)) {
- metrics_proto.set_video_codec(video_codec);
- }
-
- int32_t width = -1;
- if (item->getInt32("android.media.mediaplayer.width", &width)) {
- metrics_proto.set_width(width);
- }
- int32_t height = -1;
- if (item->getInt32("android.media.mediaplayer.height", &height)) {
- metrics_proto.set_height(height);
- }
-
- int64_t frames = -1;
- if (item->getInt64("android.media.mediaplayer.frames", &frames)) {
- metrics_proto.set_frames(frames);
- }
- int64_t frames_dropped = -1;
- if (item->getInt64("android.media.mediaplayer.dropped", &frames_dropped)) {
- metrics_proto.set_frames_dropped(frames_dropped);
- }
- int64_t frames_dropped_startup = -1;
- if (item->getInt64("android.media.mediaplayer.startupdropped", &frames_dropped_startup)) {
- metrics_proto.set_frames_dropped_startup(frames_dropped_startup);
- }
- double fps = -1.0;
- if (item->getDouble("android.media.mediaplayer.fps", &fps)) {
- metrics_proto.set_framerate(fps);
- }
-
- char *audio_mime = NULL;
- if (item->getCString("android.media.mediaplayer.audio.mime", &audio_mime)) {
- metrics_proto.set_audio_mime(audio_mime);
- }
- char *audio_codec = NULL;
- if (item->getCString("android.media.mediaplayer.audio.codec", &audio_codec)) {
- metrics_proto.set_audio_codec(audio_codec);
- }
-
- int64_t duration_ms = -1;
- if (item->getInt64("android.media.mediaplayer.durationMs", &duration_ms)) {
- metrics_proto.set_duration_millis(duration_ms);
- }
- int64_t playing_ms = -1;
- if (item->getInt64("android.media.mediaplayer.playingMs", &playing_ms)) {
- metrics_proto.set_playing_millis(playing_ms);
- }
-
- int32_t err = -1;
- if (item->getInt32("android.media.mediaplayer.err", &err)) {
- metrics_proto.set_error(err);
- }
- int32_t error_code = -1;
- if (item->getInt32("android.media.mediaplayer.errcode", &error_code)) {
- metrics_proto.set_error_code(error_code);
- }
- char *error_state = NULL;
- if (item->getCString("android.media.mediaplayer.errstate", &error_state)) {
- metrics_proto.set_error_state(error_state);
- }
-
- char *data_source_type = NULL;
- if (item->getCString("android.media.mediaplayer.dataSource", &data_source_type)) {
- metrics_proto.set_data_source_type(data_source_type);
- }
-
- int64_t rebufferingMs = -1;
- if (item->getInt64("android.media.mediaplayer.rebufferingMs", &rebufferingMs)) {
- metrics_proto.set_rebuffering_millis(rebufferingMs);
- }
- int32_t rebuffers = -1;
- if (item->getInt32("android.media.mediaplayer.rebuffers", &rebuffers)) {
- metrics_proto.set_rebuffers(rebuffers);
- }
- int32_t rebufferExit = -1;
- if (item->getInt32("android.media.mediaplayer.rebufferExit", &rebufferExit)) {
- metrics_proto.set_rebuffer_at_exit(rebufferExit);
- }
-
-
- std::string serialized;
- if (!metrics_proto.SerializeToString(&serialized)) {
- ALOGE("Failed to serialize nuplayer metrics");
- return false;
- }
-
- if (enabled_statsd) {
- android::util::BytesField bf_serialized( serialized.c_str(), serialized.size());
- (void)android::util::stats_write(android::util::MEDIAMETRICS_NUPLAYER_REPORTED,
- timestamp, pkgName.c_str(), pkgVersionCode,
- mediaApexVersion,
- bf_serialized);
-
- } else {
- ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
- }
-
- // must free the strings that we were given
- free(video_mime);
- free(video_codec);
- free(audio_mime);
- free(audio_codec);
- free(error_state);
- free(data_source_type);
-
- return true;
-}
-
-};
diff --git a/services/mediaanalytics/statsd_recorder.cpp b/services/mediaanalytics/statsd_recorder.cpp
deleted file mode 100644
index 4d981b4..0000000
--- a/services/mediaanalytics/statsd_recorder.cpp
+++ /dev/null
@@ -1,193 +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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "statsd_recorder"
-#include <utils/Log.h>
-
-#include <dirent.h>
-#include <inttypes.h>
-#include <pthread.h>
-#include <pwd.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <statslog.h>
-
-#include "MediaAnalyticsService.h"
-#include "frameworks/base/core/proto/android/stats/mediametrics/mediametrics.pb.h"
-#include "iface_statsd.h"
-
-namespace android {
-
-bool statsd_recorder(MediaAnalyticsItem *item)
-{
- if (item == NULL) return false;
-
- // these go into the statsd wrapper
- nsecs_t timestamp = item->getTimestamp();
- std::string pkgName = item->getPkgName();
- int64_t pkgVersionCode = item->getPkgVersionCode();
- int64_t mediaApexVersion = 0;
-
-
- // the rest into our own proto
- //
- ::android::stats::mediametrics::RecorderData metrics_proto;
-
- // flesh out the protobuf we'll hand off with our data
- //
-
- // string kRecorderAudioMime = "android.media.mediarecorder.audio.mime";
- char *audio_mime = NULL;
- if (item->getCString("android.media.mediarecorder.audio.mime", &audio_mime)) {
- metrics_proto.set_audio_mime(audio_mime);
- }
- // string kRecorderVideoMime = "android.media.mediarecorder.video.mime";
- char *video_mime = NULL;
- if (item->getCString("android.media.mediarecorder.video.mime", &video_mime)) {
- metrics_proto.set_video_mime(video_mime);
- }
- // int32 kRecorderVideoProfile = "android.media.mediarecorder.video-encoder-profile";
- int32_t videoProfile = -1;
- if (item->getInt32("android.media.mediarecorder.video-encoder-profile", &videoProfile)) {
- metrics_proto.set_video_profile(videoProfile);
- }
- // int32 kRecorderVideoLevel = "android.media.mediarecorder.video-encoder-level";
- int32_t videoLevel = -1;
- if (item->getInt32("android.media.mediarecorder.video-encoder-level", &videoLevel)) {
- metrics_proto.set_video_level(videoLevel);
- }
- // int32 kRecorderWidth = "android.media.mediarecorder.width";
- int32_t width = -1;
- if (item->getInt32("android.media.mediarecorder.width", &width)) {
- metrics_proto.set_width(width);
- }
- // int32 kRecorderHeight = "android.media.mediarecorder.height";
- int32_t height = -1;
- if (item->getInt32("android.media.mediarecorder.height", &height)) {
- metrics_proto.set_height(height);
- }
- // int32 kRecorderRotation = "android.media.mediarecorder.rotation";
- int32_t rotation = -1; // default to 0?
- if (item->getInt32("android.media.mediarecorder.rotation", &rotation)) {
- metrics_proto.set_rotation(rotation);
- }
- // int32 kRecorderFrameRate = "android.media.mediarecorder.frame-rate";
- int32_t framerate = -1;
- if (item->getInt32("android.media.mediarecorder.frame-rate", &framerate)) {
- metrics_proto.set_framerate(framerate);
- }
-
- // int32 kRecorderCaptureFps = "android.media.mediarecorder.capture-fps";
- int32_t captureFps = -1;
- if (item->getInt32("android.media.mediarecorder.capture-fps", &captureFps)) {
- metrics_proto.set_capture_fps(captureFps);
- }
- // double kRecorderCaptureFpsEnable = "android.media.mediarecorder.capture-fpsenable";
- double captureFpsEnable = -1;
- if (item->getDouble("android.media.mediarecorder.capture-fpsenable", &captureFpsEnable)) {
- metrics_proto.set_capture_fps_enable(captureFpsEnable);
- }
-
- // int64 kRecorderDurationMs = "android.media.mediarecorder.durationMs";
- int64_t durationMs = -1;
- if (item->getInt64("android.media.mediarecorder.durationMs", &durationMs)) {
- metrics_proto.set_duration_millis(durationMs);
- }
- // int64 kRecorderPaused = "android.media.mediarecorder.pausedMs";
- int64_t pausedMs = -1;
- if (item->getInt64("android.media.mediarecorder.pausedMs", &pausedMs)) {
- metrics_proto.set_paused_millis(pausedMs);
- }
- // int32 kRecorderNumPauses = "android.media.mediarecorder.NPauses";
- int32_t pausedCount = -1;
- if (item->getInt32("android.media.mediarecorder.NPauses", &pausedCount)) {
- metrics_proto.set_paused_count(pausedCount);
- }
-
- // int32 kRecorderAudioBitrate = "android.media.mediarecorder.audio-bitrate";
- int32_t audioBitrate = -1;
- if (item->getInt32("android.media.mediarecorder.audio-bitrate", &audioBitrate)) {
- metrics_proto.set_audio_bitrate(audioBitrate);
- }
- // int32 kRecorderAudioChannels = "android.media.mediarecorder.audio-channels";
- int32_t audioChannels = -1;
- if (item->getInt32("android.media.mediarecorder.audio-channels", &audioChannels)) {
- metrics_proto.set_audio_channels(audioChannels);
- }
- // int32 kRecorderAudioSampleRate = "android.media.mediarecorder.audio-samplerate";
- int32_t audioSampleRate = -1;
- if (item->getInt32("android.media.mediarecorder.audio-samplerate", &audioSampleRate)) {
- metrics_proto.set_audio_samplerate(audioSampleRate);
- }
-
- // int32 kRecorderMovieTimescale = "android.media.mediarecorder.movie-timescale";
- int32_t movieTimescale = -1;
- if (item->getInt32("android.media.mediarecorder.movie-timescale", &movieTimescale)) {
- metrics_proto.set_movie_timescale(movieTimescale);
- }
- // int32 kRecorderAudioTimescale = "android.media.mediarecorder.audio-timescale";
- int32_t audioTimescale = -1;
- if (item->getInt32("android.media.mediarecorder.audio-timescale", &audioTimescale)) {
- metrics_proto.set_audio_timescale(audioTimescale);
- }
- // int32 kRecorderVideoTimescale = "android.media.mediarecorder.video-timescale";
- int32_t videoTimescale = -1;
- if (item->getInt32("android.media.mediarecorder.video-timescale", &videoTimescale)) {
- metrics_proto.set_video_timescale(videoTimescale);
- }
-
- // int32 kRecorderVideoBitrate = "android.media.mediarecorder.video-bitrate";
- int32_t videoBitRate = -1;
- if (item->getInt32("android.media.mediarecorder.video-bitrate", &videoBitRate)) {
- metrics_proto.set_video_bitrate(videoBitRate);
- }
- // int32 kRecorderVideoIframeInterval = "android.media.mediarecorder.video-iframe-interval";
- int32_t iFrameInterval = -1;
- if (item->getInt32("android.media.mediarecorder.video-iframe-interval", &iFrameInterval)) {
- metrics_proto.set_iframe_interval(iFrameInterval);
- }
-
- std::string serialized;
- if (!metrics_proto.SerializeToString(&serialized)) {
- ALOGE("Failed to serialize recorder metrics");
- return false;
- }
-
- if (enabled_statsd) {
- android::util::BytesField bf_serialized( serialized.c_str(), serialized.size());
- (void)android::util::stats_write(android::util::MEDIAMETRICS_RECORDER_REPORTED,
- timestamp, pkgName.c_str(), pkgVersionCode,
- mediaApexVersion,
- bf_serialized);
-
- } else {
- ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
- }
-
- // must free the strings that we were given
- free(audio_mime);
- free(video_mime);
-
- return true;
-}
-
-};
diff --git a/services/mediacodec/Android.bp b/services/mediacodec/Android.bp
index 2f3cad9..4bf103c 100644
--- a/services/mediacodec/Android.bp
+++ b/services/mediacodec/Android.bp
@@ -10,17 +10,11 @@
"libavservices_minijail",
"libbase",
"libhidlbase",
- "libhidltransport",
- "libhwbinder",
"liblog",
"libmedia_codecserviceregistrant",
],
target: {
- vendor: {
- exclude_shared_libs: ["libavservices_minijail"],
- shared_libs: ["libavservices_minijail_vendor"],
- },
android: {
product_variables: {
malloc_not_svelte: {
@@ -58,10 +52,100 @@
src: "seccomp_policy/mediaswcodec-arm64.policy",
},
x86: {
+ src: "seccomp_policy/mediaswcodec-x86.policy",
+ },
+ x86_64: {
+ src: "seccomp_policy/mediaswcodec-x86_64.policy",
+ },
+ },
+ required: [
+ "crash_dump.policy",
+ "code_coverage.policy",
+ ],
+}
+
+// media.codec -- the one that handles vendor & HW codecs
+
+cc_binary {
+ name: "android.hardware.media.omx@1.0-service",
+ relative_install_path: "hw",
+ vendor: true,
+
+ srcs: [
+ "main_codecservice.cpp",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ "liblog",
+ "libbase",
+ "libavservices_minijail",
+ "libcutils",
+ "libhidlbase",
+ "libstagefright_omx",
+ "libstagefright_xmlparser",
+ "android.hardware.media.omx@1.0",
+ "android.hidl.memory@1.0",
+ ],
+
+ runtime_libs: [
+ "libstagefright_soft_aacdec",
+ "libstagefright_soft_aacenc",
+ "libstagefright_soft_amrdec",
+ "libstagefright_soft_amrnbenc",
+ "libstagefright_soft_amrwbenc",
+ "libstagefright_soft_avcdec",
+ "libstagefright_soft_avcenc",
+ "libstagefright_soft_flacdec",
+ "libstagefright_soft_flacenc",
+ "libstagefright_soft_g711dec",
+ "libstagefright_soft_gsmdec",
+ "libstagefright_soft_hevcdec",
+ "libstagefright_soft_mp3dec",
+ "libstagefright_soft_mpeg2dec",
+ "libstagefright_soft_mpeg4dec",
+ "libstagefright_soft_mpeg4enc",
+ "libstagefright_soft_opusdec",
+ "libstagefright_soft_rawdec",
+ "libstagefright_soft_vorbisdec",
+ "libstagefright_soft_vpxdec",
+ "libstagefright_soft_vpxenc",
+ "libstagefright_softomx_plugin",
+ ],
+
+ // OMX interfaces force this to stay in 32-bit mode;
+ compile_multilib: "32",
+
+ init_rc: ["android.hardware.media.omx@1.0-service.rc"],
+
+ required: [
+ "mediacodec.policy",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ "-Wno-error=deprecated-declarations",
+ ],
+}
+
+
+prebuilt_etc {
+ name: "mediacodec.policy",
+ sub_dir: "seccomp_policy",
+ arch: {
+ arm: {
+ src: "seccomp_policy/mediacodec-arm.policy",
+ },
+ arm64: {
+ src: "seccomp_policy/mediacodec-arm64.policy",
+ },
+ x86: {
src: "seccomp_policy/mediacodec-x86.policy",
},
x86_64: {
- src: "seccomp_policy/mediacodec-x86.policy",
+ src: "seccomp_policy/mediacodec-x86_64.policy",
},
},
required: [
diff --git a/services/mediacodec/Android.mk b/services/mediacodec/Android.mk
deleted file mode 100644
index 15bc503..0000000
--- a/services/mediacodec/Android.mk
+++ /dev/null
@@ -1,93 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-_software_codecs := \
- libstagefright_soft_aacdec \
- libstagefright_soft_aacenc \
- libstagefright_soft_amrdec \
- libstagefright_soft_amrnbenc \
- libstagefright_soft_amrwbenc \
- libstagefright_soft_avcdec \
- libstagefright_soft_avcenc \
- libstagefright_soft_flacdec \
- libstagefright_soft_flacenc \
- libstagefright_soft_g711dec \
- libstagefright_soft_gsmdec \
- libstagefright_soft_hevcdec \
- libstagefright_soft_mp3dec \
- libstagefright_soft_mpeg2dec \
- libstagefright_soft_mpeg4dec \
- libstagefright_soft_mpeg4enc \
- libstagefright_soft_opusdec \
- libstagefright_soft_rawdec \
- libstagefright_soft_vorbisdec \
- libstagefright_soft_vpxdec \
- libstagefright_soft_vpxenc \
- libstagefright_softomx_plugin \
-
-# service executable
-include $(CLEAR_VARS)
-# seccomp is not required for coverage build.
-ifneq ($(NATIVE_COVERAGE),true)
-LOCAL_REQUIRED_MODULES_arm := mediacodec.policy
-LOCAL_REQUIRED_MODULES_x86 := mediacodec.policy
-endif
-LOCAL_SRC_FILES := main_codecservice.cpp
-LOCAL_SHARED_LIBRARIES := \
- libbinder \
- libutils \
- liblog \
- libbase \
- libavservices_minijail_vendor \
- libcutils \
- libhwbinder \
- libhidlbase \
- libhidltransport \
- libstagefright_omx \
- libstagefright_xmlparser \
- android.hardware.media.omx@1.0 \
- android.hidl.memory@1.0
-
-LOCAL_MODULE := android.hardware.media.omx@1.0-service
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_VENDOR_MODULE := true
-LOCAL_32_BIT_ONLY := true
-# Since this is 32-bit-only module, only 32-bit version of the codecs are installed.
-# TODO(b/72343507): eliminate the need for manually adding .vendor suffix. This should be done
-# by the build system.
-LOCAL_REQUIRED_MODULES += \
-$(foreach codec,$(_software_codecs),\
- $(eval _vendor_suffix := $(if $(BOARD_VNDK_VERSION),.vendor))\
- $(codec)$(_vendor_suffix)\
-)
-_software_codecs :=
-LOCAL_INIT_RC := android.hardware.media.omx@1.0-service.rc
-
-include $(BUILD_EXECUTABLE)
-
-####################################################################
-
-# service seccomp policy
-ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), x86 x86_64 arm arm64))
-include $(CLEAR_VARS)
-LOCAL_MODULE := mediacodec.policy
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/seccomp_policy
-LOCAL_REQUIRED_MODULES := crash_dump.policy code_coverage.policy
-# mediacodec runs in 32-bit combatibility mode. For 64 bit architectures,
-# use the 32 bit policy
-ifdef TARGET_2ND_ARCH
- ifneq ($(TARGET_TRANSLATE_2ND_ARCH),true)
- LOCAL_SRC_FILES := seccomp_policy/mediacodec-$(TARGET_2ND_ARCH).policy
- else
- LOCAL_SRC_FILES := seccomp_policy/mediacodec-$(TARGET_ARCH).policy
- endif
-else
- LOCAL_SRC_FILES := seccomp_policy/mediacodec-$(TARGET_ARCH).policy
-endif
-include $(BUILD_PREBUILT)
-endif
-
-####################################################################
-
-
-include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/services/mediacodec/registrant/Android.bp b/services/mediacodec/registrant/Android.bp
index fa5bc4a..0441cfa 100644
--- a/services/mediacodec/registrant/Android.bp
+++ b/services/mediacodec/registrant/Android.bp
@@ -9,11 +9,14 @@
"libmedia_headers",
],
+ defaults: [
+ "libcodec2-hidl-defaults",
+ ],
shared_libs: [
- "android.hardware.media.c2@1.0",
"libbase",
"libcodec2_hidl@1.0",
"libcodec2_vndk",
+ "libhidlbase",
"libutils",
],
diff --git a/services/mediacodec/registrant/CodecServiceRegistrant.cpp b/services/mediacodec/registrant/CodecServiceRegistrant.cpp
index 706ebee..83d233e 100644
--- a/services/mediacodec/registrant/CodecServiceRegistrant.cpp
+++ b/services/mediacodec/registrant/CodecServiceRegistrant.cpp
@@ -18,21 +18,410 @@
#define LOG_TAG "CodecServiceRegistrant"
#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <C2Component.h>
#include <C2PlatformSupport.h>
-#include <codec2/hidl/1.0/ComponentStore.h>
+#include <codec2/hidl/1.1/ComponentStore.h>
+#include <codec2/hidl/1.1/Configurable.h>
+#include <codec2/hidl/1.1/types.h>
+#include <hidl/HidlSupport.h>
#include <media/CodecServiceRegistrant.h>
+namespace /* unnamed */ {
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+using namespace ::android::hardware::media::c2::V1_1;
+using namespace ::android::hardware::media::c2::V1_1::utils;
+
+constexpr c2_status_t C2_TRANSACTION_FAILED = C2_CORRUPTED;
+
+// Converter from IComponentStore to C2ComponentStore.
+class H2C2ComponentStore : public C2ComponentStore {
+protected:
+ sp<IComponentStore> mStore;
+ sp<IConfigurable> mConfigurable;
+public:
+ explicit H2C2ComponentStore(sp<IComponentStore> const& store)
+ : mStore{store},
+ mConfigurable{[store]() -> sp<IConfigurable>{
+ if (!store) {
+ return nullptr;
+ }
+ Return<sp<IConfigurable>> transResult =
+ store->getConfigurable();
+ return transResult.isOk() ?
+ static_cast<sp<IConfigurable>>(transResult) :
+ nullptr;
+ }()} {
+ if (!mConfigurable) {
+ LOG(ERROR) << "Preferred store is corrupted.";
+ }
+ }
+
+ virtual ~H2C2ComponentStore() override = default;
+
+ virtual c2_status_t config_sm(
+ std::vector<C2Param*> const ¶ms,
+ std::vector<std::unique_ptr<C2SettingResult>>* const failures
+ ) override {
+ Params hidlParams;
+ if (!createParamsBlob(&hidlParams, params)) {
+ LOG(ERROR) << "config -- bad input.";
+ return C2_TRANSACTION_FAILED;
+ }
+ c2_status_t status{};
+ Return<void> transResult = mConfigurable->config(
+ hidlParams,
+ true,
+ [&status, ¶ms, failures](
+ Status s,
+ const hidl_vec<SettingResult> f,
+ const Params& o) {
+ status = static_cast<c2_status_t>(s);
+ if (status != C2_OK && status != C2_BAD_INDEX) {
+ LOG(DEBUG) << "config -- call failed: "
+ << status << ".";
+ }
+ size_t i = failures->size();
+ failures->resize(i + f.size());
+ for (const SettingResult& sf : f) {
+ if (!objcpy(&(*failures)[i++], sf)) {
+ LOG(ERROR) << "config -- "
+ << "invalid SettingResult returned.";
+ return;
+ }
+ }
+ if (!updateParamsFromBlob(params, o)) {
+ LOG(ERROR) << "config -- "
+ << "failed to parse returned params.";
+ status = C2_CORRUPTED;
+ }
+ });
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "config -- transaction failed.";
+ return C2_TRANSACTION_FAILED;
+ }
+ return status;
+ };
+
+ virtual c2_status_t copyBuffer(
+ std::shared_ptr<C2GraphicBuffer>,
+ std::shared_ptr<C2GraphicBuffer>) override {
+ LOG(ERROR) << "copyBuffer -- not supported.";
+ return C2_OMITTED;
+ }
+
+ virtual c2_status_t createComponent(
+ C2String, std::shared_ptr<C2Component> *const component) override {
+ component->reset();
+ LOG(ERROR) << "createComponent -- not supported.";
+ return C2_OMITTED;
+ }
+
+ virtual c2_status_t createInterface(
+ C2String, std::shared_ptr<C2ComponentInterface> *const interface) {
+ interface->reset();
+ LOG(ERROR) << "createInterface -- not supported.";
+ return C2_OMITTED;
+ }
+
+ virtual c2_status_t query_sm(
+ const std::vector<C2Param *> &stackParams,
+ const std::vector<C2Param::Index> &heapParamIndices,
+ std::vector<std::unique_ptr<C2Param>> *const heapParams) const
+ override {
+ hidl_vec<ParamIndex> indices(
+ stackParams.size() + heapParamIndices.size());
+ size_t numIndices = 0;
+ for (C2Param* const& stackParam : stackParams) {
+ if (!stackParam) {
+ LOG(WARNING) << "query -- null stack param encountered.";
+ continue;
+ }
+ indices[numIndices++] = static_cast<ParamIndex>(stackParam->index());
+ }
+ size_t numStackIndices = numIndices;
+ for (const C2Param::Index& index : heapParamIndices) {
+ indices[numIndices++] =
+ static_cast<ParamIndex>(static_cast<uint32_t>(index));
+ }
+ indices.resize(numIndices);
+ if (heapParams) {
+ heapParams->reserve(heapParams->size() + numIndices);
+ }
+ c2_status_t status;
+ Return<void> transResult = mConfigurable->query(
+ indices,
+ true,
+ [&status, &numStackIndices, &stackParams, heapParams](
+ Status s, const Params& p) {
+ status = static_cast<c2_status_t>(s);
+ if (status != C2_OK && status != C2_BAD_INDEX) {
+ LOG(DEBUG) << "query -- call failed: "
+ << status << ".";
+ return;
+ }
+ std::vector<C2Param*> paramPointers;
+ if (!parseParamsBlob(¶mPointers, p)) {
+ LOG(ERROR) << "query -- error while parsing params.";
+ status = C2_CORRUPTED;
+ return;
+ }
+ size_t i = 0;
+ for (auto it = paramPointers.begin();
+ it != paramPointers.end(); ) {
+ C2Param* paramPointer = *it;
+ if (numStackIndices > 0) {
+ --numStackIndices;
+ if (!paramPointer) {
+ LOG(WARNING) << "query -- null stack param.";
+ ++it;
+ continue;
+ }
+ for (; i < stackParams.size() && !stackParams[i]; ) {
+ ++i;
+ }
+ if (i >= stackParams.size()) {
+ LOG(ERROR) << "query -- unexpected error.";
+ status = C2_CORRUPTED;
+ return;
+ }
+ if (stackParams[i]->index() != paramPointer->index()) {
+ LOG(WARNING) << "query -- param skipped: "
+ "index = "
+ << stackParams[i]->index() << ".";
+ stackParams[i++]->invalidate();
+ continue;
+ }
+ if (!stackParams[i++]->updateFrom(*paramPointer)) {
+ LOG(WARNING) << "query -- param update failed: "
+ "index = "
+ << paramPointer->index() << ".";
+ }
+ } else {
+ if (!paramPointer) {
+ LOG(WARNING) << "query -- null heap param.";
+ ++it;
+ continue;
+ }
+ if (!heapParams) {
+ LOG(WARNING) << "query -- "
+ "unexpected extra stack param.";
+ } else {
+ heapParams->emplace_back(
+ C2Param::Copy(*paramPointer));
+ }
+ }
+ ++it;
+ }
+ });
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "query -- transaction failed.";
+ return C2_TRANSACTION_FAILED;
+ }
+ return status;
+ }
+
+ virtual c2_status_t querySupportedParams_nb(
+ std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const {
+ c2_status_t status;
+ Return<void> transResult = mConfigurable->querySupportedParams(
+ std::numeric_limits<uint32_t>::min(),
+ std::numeric_limits<uint32_t>::max(),
+ [&status, params](
+ Status s,
+ const hidl_vec<ParamDescriptor>& p) {
+ status = static_cast<c2_status_t>(s);
+ if (status != C2_OK) {
+ LOG(DEBUG) << "querySupportedParams -- call failed: "
+ << status << ".";
+ return;
+ }
+ size_t i = params->size();
+ params->resize(i + p.size());
+ for (const ParamDescriptor& sp : p) {
+ if (!objcpy(&(*params)[i++], sp)) {
+ LOG(ERROR) << "querySupportedParams -- "
+ << "invalid returned ParamDescriptor.";
+ return;
+ }
+ }
+ });
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "querySupportedParams -- transaction failed.";
+ return C2_TRANSACTION_FAILED;
+ }
+ return status;
+ }
+
+ virtual c2_status_t querySupportedValues_sm(
+ std::vector<C2FieldSupportedValuesQuery> &fields) const {
+ hidl_vec<FieldSupportedValuesQuery> inFields(fields.size());
+ for (size_t i = 0; i < fields.size(); ++i) {
+ if (!objcpy(&inFields[i], fields[i])) {
+ LOG(ERROR) << "querySupportedValues -- bad input";
+ return C2_TRANSACTION_FAILED;
+ }
+ }
+
+ c2_status_t status;
+ Return<void> transResult = mConfigurable->querySupportedValues(
+ inFields,
+ true,
+ [&status, &inFields, &fields](
+ Status s,
+ const hidl_vec<FieldSupportedValuesQueryResult>& r) {
+ status = static_cast<c2_status_t>(s);
+ if (status != C2_OK) {
+ LOG(DEBUG) << "querySupportedValues -- call failed: "
+ << status << ".";
+ return;
+ }
+ if (r.size() != fields.size()) {
+ LOG(ERROR) << "querySupportedValues -- "
+ "input and output lists "
+ "have different sizes.";
+ status = C2_CORRUPTED;
+ return;
+ }
+ for (size_t i = 0; i < fields.size(); ++i) {
+ if (!objcpy(&fields[i], inFields[i], r[i])) {
+ LOG(ERROR) << "querySupportedValues -- "
+ "invalid returned value.";
+ status = C2_CORRUPTED;
+ return;
+ }
+ }
+ });
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "querySupportedValues -- transaction failed.";
+ return C2_TRANSACTION_FAILED;
+ }
+ return status;
+ }
+
+ virtual C2String getName() const {
+ C2String outName;
+ Return<void> transResult = mConfigurable->getName(
+ [&outName](const hidl_string& name) {
+ outName = name.c_str();
+ });
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "getName -- transaction failed.";
+ }
+ return outName;
+ }
+
+ virtual std::shared_ptr<C2ParamReflector> getParamReflector() const
+ override {
+ struct SimpleParamReflector : public C2ParamReflector {
+ virtual std::unique_ptr<C2StructDescriptor> describe(
+ C2Param::CoreIndex coreIndex) const {
+ hidl_vec<ParamIndex> indices(1);
+ indices[0] = static_cast<ParamIndex>(coreIndex.coreIndex());
+ std::unique_ptr<C2StructDescriptor> descriptor;
+ Return<void> transResult = mBase->getStructDescriptors(
+ indices,
+ [&descriptor](
+ Status s,
+ const hidl_vec<StructDescriptor>& sd) {
+ c2_status_t status = static_cast<c2_status_t>(s);
+ if (status != C2_OK) {
+ LOG(DEBUG) << "SimpleParamReflector -- "
+ "getStructDescriptors() failed: "
+ << status << ".";
+ descriptor.reset();
+ return;
+ }
+ if (sd.size() != 1) {
+ LOG(DEBUG) << "SimpleParamReflector -- "
+ "getStructDescriptors() "
+ "returned vector of size "
+ << sd.size() << ". "
+ "It should be 1.";
+ descriptor.reset();
+ return;
+ }
+ if (!objcpy(&descriptor, sd[0])) {
+ LOG(DEBUG) << "SimpleParamReflector -- "
+ "getStructDescriptors() returned "
+ "corrupted data.";
+ descriptor.reset();
+ return;
+ }
+ });
+ return descriptor;
+ }
+
+ explicit SimpleParamReflector(sp<IComponentStore> base)
+ : mBase(base) { }
+
+ sp<IComponentStore> mBase;
+ };
+
+ return std::make_shared<SimpleParamReflector>(mStore);
+ }
+
+ virtual std::vector<std::shared_ptr<const C2Component::Traits>>
+ listComponents() override {
+ LOG(ERROR) << "listComponents -- not supported.";
+ return {};
+ }
+};
+
+bool ionPropertiesDefined() {
+ using namespace ::android::base;
+ std::string heapMask =
+ GetProperty("ro.com.android.media.swcodec.ion.heapmask", "undefined");
+ std::string flags =
+ GetProperty("ro.com.android.media.swcodec.ion.flags", "undefined");
+ std::string align =
+ GetProperty("ro.com.android.media.swcodec.ion.align", "undefined");
+ if (heapMask != "undefined" ||
+ flags != "undefined" ||
+ align != "undefined") {
+ LOG(INFO)
+ << "Some system properties for mediaswcodec ION usage are set: "
+ << "heapmask = " << heapMask << ", "
+ << "flags = " << flags << ", "
+ << "align = " << align << ". "
+ << "Preferred Codec2 store is defaulted to \"software\".";
+ return true;
+ }
+ return false;
+}
+
+} // unnamed namespace
+
extern "C" void RegisterCodecServices() {
- using namespace ::android::hardware::media::c2::V1_0;
+ using namespace ::android::hardware::media::c2::V1_1;
LOG(INFO) << "Creating software Codec2 service...";
- android::sp<IComponentStore> store =
- new utils::ComponentStore(
- android::GetCodec2PlatformComponentStore());
+ sp<ComponentStore> store =
+ new ComponentStore(::android::GetCodec2PlatformComponentStore());
if (store == nullptr) {
LOG(ERROR) <<
"Cannot create software Codec2 service.";
} else {
+ if (!ionPropertiesDefined()) {
+ std::string preferredStoreName = "default";
+ sp<IComponentStore> preferredStore =
+ IComponentStore::getService(preferredStoreName.c_str());
+ if (preferredStore) {
+ ::android::SetPreferredCodec2ComponentStore(
+ std::make_shared<H2C2ComponentStore>(preferredStore));
+ LOG(INFO) <<
+ "Preferred Codec2 store is set to \"" <<
+ preferredStoreName << "\".";
+ } else {
+ LOG(INFO) <<
+ "Preferred Codec2 store is defaulted to \"software\".";
+ }
+ }
if (store->registerAsService("software") != android::OK) {
LOG(ERROR) <<
"Cannot register software Codec2 service.";
diff --git a/services/mediacodec/seccomp_policy/mediacodec-arm.policy b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
index 835f8bb..b4a9ff6 100644
--- a/services/mediacodec/seccomp_policy/mediacodec-arm.policy
+++ b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
@@ -23,7 +23,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
mprotect: 1
madvise: 1
diff --git a/services/mediacodec/seccomp_policy/mediacodec-arm64.policy b/services/mediacodec/seccomp_policy/mediacodec-arm64.policy
new file mode 100644
index 0000000..b4a9ff6
--- /dev/null
+++ b/services/mediacodec/seccomp_policy/mediacodec-arm64.policy
@@ -0,0 +1,63 @@
+# Organized by frequency of systemcall - in descending order for
+# best performance.
+futex: 1
+ioctl: 1
+write: 1
+prctl: 1
+clock_gettime: 1
+getpriority: 1
+read: 1
+close: 1
+writev: 1
+dup: 1
+ppoll: 1
+mmap2: 1
+getrandom: 1
+memfd_create: 1
+ftruncate: 1
+ftruncate64: 1
+
+# mremap: Ensure |flags| are (MREMAP_MAYMOVE | MREMAP_FIXED) TODO: Once minijail
+# parser support for '<' is in this needs to be modified to also prevent
+# |old_address| and |new_address| from touching the exception vector page, which
+# 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 || arg3 == MREMAP_MAYMOVE
+munmap: 1
+mprotect: 1
+madvise: 1
+openat: 1
+sigaltstack: 1
+clone: 1
+setpriority: 1
+getuid32: 1
+fstat64: 1
+fstatfs64: 1
+pread64: 1
+faccessat: 1
+readlinkat: 1
+exit: 1
+rt_sigprocmask: 1
+set_tid_address: 1
+restart_syscall: 1
+exit_group: 1
+rt_sigreturn: 1
+pipe2: 1
+gettimeofday: 1
+sched_yield: 1
+nanosleep: 1
+lseek: 1
+_llseek: 1
+sched_get_priority_max: 1
+sched_get_priority_min: 1
+statfs64: 1
+sched_setscheduler: 1
+fstatat64: 1
+ugetrlimit: 1
+getdents64: 1
+getrandom: 1
+
+@include /system/etc/seccomp_policy/crash_dump.arm.policy
+
+@include /system/etc/seccomp_policy/code_coverage.arm.policy
diff --git a/services/mediacodec/seccomp_policy/mediacodec-x86_64.policy b/services/mediacodec/seccomp_policy/mediacodec-x86_64.policy
new file mode 100644
index 0000000..a9d32d6
--- /dev/null
+++ b/services/mediacodec/seccomp_policy/mediacodec-x86_64.policy
@@ -0,0 +1,72 @@
+# Copyright (C) 2017 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.
+
+read: 1
+mprotect: 1
+prctl: 1
+openat: 1
+open: 1
+getuid32: 1
+getuid: 1
+getrlimit: 1
+writev: 1
+ioctl: 1
+close: 1
+mmap2: 1
+mmap: 1
+fstat64: 1
+fstat: 1
+stat64: 1
+statfs64: 1
+madvise: 1
+fstatat64: 1
+newfstatat: 1
+futex: 1
+munmap: 1
+faccessat: 1
+_llseek: 1
+lseek: 1
+clone: 1
+sigaltstack: 1
+setpriority: 1
+restart_syscall: 1
+exit: 1
+exit_group: 1
+rt_sigreturn: 1
+ugetrlimit: 1
+readlink: 1
+readlinkat: 1
+_llseek: 1
+fstatfs64: 1
+fstatfs: 1
+pread64: 1
+mremap: 1
+dup: 1
+set_tid_address: 1
+write: 1
+nanosleep: 1
+sched_setscheduler: 1
+uname: 1
+memfd_create: 1
+ftruncate: 1
+ftruncate64: 1
+
+# Required by AddressSanitizer
+gettid: 1
+sched_yield: 1
+getpid: 1
+gettid: 1
+
+@include /system/etc/seccomp_policy/crash_dump.x86.policy
+@include /system/etc/seccomp_policy/code_coverage.x86.policy
diff --git a/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy b/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy
index 93b4852..9058f10 100644
--- a/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy
+++ b/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy
@@ -31,7 +31,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
getuid32: 1
@@ -85,4 +85,4 @@
getegid32: 1
getgroups32: 1
-@include /system/etc/seccomp_policy/code_coverage.arm.policy
+@include /apex/com.android.media.swcodec/etc/seccomp_policy/code_coverage.arm.policy
diff --git a/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy b/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy
index bb05770..4c51a9c 100644
--- a/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy
+++ b/services/mediacodec/seccomp_policy/mediaswcodec-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
@@ -79,4 +79,4 @@
getegid: 1
getgroups: 1
-@include /system/etc/seccomp_policy/code_coverage.arm64.policy
+@include /apex/com.android.media.swcodec/etc/seccomp_policy/code_coverage.arm64.policy
diff --git a/services/mediacodec/seccomp_policy/mediaswcodec-x86.policy b/services/mediacodec/seccomp_policy/mediaswcodec-x86.policy
deleted file mode 120000
index ab2592a..0000000
--- a/services/mediacodec/seccomp_policy/mediaswcodec-x86.policy
+++ /dev/null
@@ -1 +0,0 @@
-mediacodec-x86.policy
\ No newline at end of file
diff --git a/services/mediacodec/seccomp_policy/mediaswcodec-x86.policy b/services/mediacodec/seccomp_policy/mediaswcodec-x86.policy
new file mode 100644
index 0000000..eb71e28
--- /dev/null
+++ b/services/mediacodec/seccomp_policy/mediaswcodec-x86.policy
@@ -0,0 +1,72 @@
+# Copyright (C) 2017 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.
+
+read: 1
+mprotect: 1
+prctl: 1
+openat: 1
+open: 1
+getuid32: 1
+getuid: 1
+getrlimit: 1
+writev: 1
+ioctl: 1
+close: 1
+mmap2: 1
+mmap: 1
+fstat64: 1
+fstat: 1
+stat64: 1
+statfs64: 1
+madvise: 1
+fstatat64: 1
+newfstatat: 1
+futex: 1
+munmap: 1
+faccessat: 1
+_llseek: 1
+lseek: 1
+clone: 1
+sigaltstack: 1
+setpriority: 1
+restart_syscall: 1
+exit: 1
+exit_group: 1
+rt_sigreturn: 1
+ugetrlimit: 1
+readlink: 1
+readlinkat: 1
+_llseek: 1
+fstatfs64: 1
+fstatfs: 1
+pread64: 1
+mremap: 1
+dup: 1
+set_tid_address: 1
+write: 1
+nanosleep: 1
+sched_setscheduler: 1
+uname: 1
+memfd_create: 1
+ftruncate: 1
+ftruncate64: 1
+
+# Required by AddressSanitizer
+gettid: 1
+sched_yield: 1
+getpid: 1
+gettid: 1
+
+@include /apex/com.android.media.swcodec/etc/seccomp_policy/crash_dump.x86.policy
+@include /apex/com.android.media.swcodec/etc/seccomp_policy/code_coverage.x86.policy
diff --git a/services/mediacodec/seccomp_policy/mediaswcodec-x86_64.policy b/services/mediacodec/seccomp_policy/mediaswcodec-x86_64.policy
deleted file mode 120000
index ab2592a..0000000
--- a/services/mediacodec/seccomp_policy/mediaswcodec-x86_64.policy
+++ /dev/null
@@ -1 +0,0 @@
-mediacodec-x86.policy
\ No newline at end of file
diff --git a/services/mediacodec/seccomp_policy/mediaswcodec-x86_64.policy b/services/mediacodec/seccomp_policy/mediaswcodec-x86_64.policy
new file mode 100644
index 0000000..e72d4db
--- /dev/null
+++ b/services/mediacodec/seccomp_policy/mediaswcodec-x86_64.policy
@@ -0,0 +1,72 @@
+# Copyright (C) 2017 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.
+
+read: 1
+mprotect: 1
+prctl: 1
+openat: 1
+open: 1
+getuid32: 1
+getuid: 1
+getrlimit: 1
+writev: 1
+ioctl: 1
+close: 1
+mmap2: 1
+mmap: 1
+fstat64: 1
+fstat: 1
+stat64: 1
+statfs64: 1
+madvise: 1
+fstatat64: 1
+newfstatat: 1
+futex: 1
+munmap: 1
+faccessat: 1
+_llseek: 1
+lseek: 1
+clone: 1
+sigaltstack: 1
+setpriority: 1
+restart_syscall: 1
+exit: 1
+exit_group: 1
+rt_sigreturn: 1
+ugetrlimit: 1
+readlink: 1
+readlinkat: 1
+_llseek: 1
+fstatfs64: 1
+fstatfs: 1
+pread64: 1
+mremap: 1
+dup: 1
+set_tid_address: 1
+write: 1
+nanosleep: 1
+sched_setscheduler: 1
+uname: 1
+memfd_create: 1
+ftruncate: 1
+ftruncate64: 1
+
+# Required by AddressSanitizer
+gettid: 1
+sched_yield: 1
+getpid: 1
+gettid: 1
+
+@include /apex/com.android.media.swcodec/etc/seccomp_policy/crash_dump.x86_64.policy
+@include /apex/com.android.media.swcodec/etc/seccomp_policy/code_coverage.x86_64.policy
diff --git a/services/mediadrm/Android.mk b/services/mediadrm/Android.mk
deleted file mode 100644
index 227a29d..0000000
--- a/services/mediadrm/Android.mk
+++ /dev/null
@@ -1,49 +0,0 @@
-# Copyright 2014 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- MediaDrmService.cpp \
- main_mediadrmserver.cpp
-
-LOCAL_SHARED_LIBRARIES:= \
- libbinder \
- liblog \
- libmediadrm \
- libutils \
- libhidlbase \
- libhidlmemory \
- libhidltransport \
- android.hardware.drm@1.0 \
- android.hardware.drm@1.1 \
- android.hardware.drm@1.2
-
-LOCAL_CFLAGS += -Wall -Wextra -Werror
-
-LOCAL_MODULE:= mediadrmserver
-
-# TODO: Some legacy DRM plugins only support 32-bit. They need to be migrated to
-# 64-bit. (b/18948909) Once all of a device's legacy DRM plugins support 64-bit,
-# that device can turn on TARGET_ENABLE_MEDIADRM_64 to build this service as
-# 64-bit.
-ifneq ($(TARGET_ENABLE_MEDIADRM_64), true)
-LOCAL_32_BIT_ONLY := true
-endif
-
-LOCAL_INIT_RC := mediadrmserver.rc
-
-include $(BUILD_EXECUTABLE)
diff --git a/services/mediadrm/MediaDrmService.cpp b/services/mediadrm/MediaDrmService.cpp
deleted file mode 100644
index 5afd079..0000000
--- a/services/mediadrm/MediaDrmService.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
-**
-** Copyright 2008, 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.
-*/
-
-// Proxy for media player implementations
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MediaDrmService"
-
-#include "MediaDrmService.h"
-#include <binder/IServiceManager.h>
-#include <utils/Log.h>
-
-#include <mediadrm/CryptoHal.h>
-#include <mediadrm/DrmHal.h>
-
-namespace android {
-
-void MediaDrmService::instantiate() {
- defaultServiceManager()->addService(
- String16("media.drm"), new MediaDrmService());
-}
-
-sp<ICrypto> MediaDrmService::makeCrypto() {
- return new CryptoHal;
-}
-
-sp<IDrm> MediaDrmService::makeDrm() {
- return new DrmHal;
-}
-
-} // namespace android
diff --git a/services/mediadrm/MediaDrmService.h b/services/mediadrm/MediaDrmService.h
deleted file mode 100644
index 3607201..0000000
--- a/services/mediadrm/MediaDrmService.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
-**
-** Copyright 2008, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef ANDROID_MEDIADRMSERVICE_H
-#define ANDROID_MEDIADRMSERVICE_H
-
-#include <arpa/inet.h>
-
-#include <utils/threads.h>
-
-#include <media/Metadata.h>
-#include <media/stagefright/foundation/ABase.h>
-#include <mediadrm/IMediaDrmService.h>
-
-namespace android {
-
-class MediaDrmService : public BnMediaDrmService
-{
-public:
- static void instantiate();
-
- // IMediaDrmService interface
- virtual sp<ICrypto> makeCrypto();
- virtual sp<IDrm> makeDrm();
-private:
- MediaDrmService() {}
- virtual ~MediaDrmService() {}
-};
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_MEDIADRMSERVICE_H
diff --git a/services/mediadrm/OWNERS b/services/mediadrm/OWNERS
deleted file mode 100644
index 6d3b533..0000000
--- a/services/mediadrm/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-jtinker@google.com
-marcone@google.com
diff --git a/services/mediadrm/main_mediadrmserver.cpp b/services/mediadrm/main_mediadrmserver.cpp
deleted file mode 100644
index b767b8c..0000000
--- a/services/mediadrm/main_mediadrmserver.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
-**
-** Copyright 2008, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#define LOG_TAG "mediaserver"
-//#define LOG_NDEBUG 0
-
-#include <fcntl.h>
-#include <sys/prctl.h>
-#include <sys/wait.h>
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
-#include <binder/IServiceManager.h>
-#include <cutils/properties.h>
-#include <utils/Log.h>
-#include "MediaDrmService.h"
-
-using namespace android;
-
-int main()
-{
- signal(SIGPIPE, SIG_IGN);
-
- sp<ProcessState> proc(ProcessState::self());
- sp<IServiceManager> sm = defaultServiceManager();
- ALOGI("ServiceManager: %p", sm.get());
- MediaDrmService::instantiate();
- ProcessState::self()->startThreadPool();
- IPCThreadState::self()->joinThreadPool();
-}
diff --git a/services/mediadrm/mediadrmserver.rc b/services/mediadrm/mediadrmserver.rc
deleted file mode 100644
index 359c2cf..0000000
--- a/services/mediadrm/mediadrmserver.rc
+++ /dev/null
@@ -1,6 +0,0 @@
-service mediadrm /system/bin/mediadrmserver
- class main
- user media
- group mediadrm drmrpc
- ioprio rt 4
- writepid /dev/cpuset/foreground/tasks
diff --git a/services/mediaextractor/Android.bp b/services/mediaextractor/Android.bp
index 0c701d7..548b7f6 100644
--- a/services/mediaextractor/Android.bp
+++ b/services/mediaextractor/Android.bp
@@ -8,10 +8,16 @@
srcs: ["MediaExtractorService.cpp"],
shared_libs: [
+ "libdatasource",
"libmedia",
"libstagefright",
+ "libstagefright_foundation",
"libbinder",
"libutils",
+ "liblog",
+ ],
+ header_libs: [
+ "libmediametrics_headers",
],
}
@@ -28,6 +34,9 @@
"liblog",
"libavservices_minijail",
],
+ header_libs: [
+ "bionic_libc_platform_headers",
+ ],
target: {
android: {
product_variables: {
@@ -47,6 +56,8 @@
"-Wall",
"-Werror",
],
+
+ required: ["mediaextractor.policy"],
}
prebuilt_etc {
diff --git a/services/mediaextractor/MediaExtractorService.cpp b/services/mediaextractor/MediaExtractorService.cpp
index 36e084b..9992d1c 100644
--- a/services/mediaextractor/MediaExtractorService.cpp
+++ b/services/mediaextractor/MediaExtractorService.cpp
@@ -20,8 +20,8 @@
#include <utils/Vector.h>
+#include <datasource/DataSourceFactory.h>
#include <media/DataSource.h>
-#include <media/stagefright/DataSourceFactory.h>
#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MediaExtractorFactory.h>
#include <media/stagefright/RemoteDataSource.h>
@@ -29,48 +29,56 @@
namespace android {
-MediaExtractorService::MediaExtractorService()
- : BnMediaExtractorService() {
+MediaExtractorService::MediaExtractorService() {
MediaExtractorFactory::LoadExtractors();
}
-sp<IMediaExtractor> MediaExtractorService::makeExtractor(
- const sp<IDataSource> &remoteSource, const char *mime) {
- ALOGV("@@@ MediaExtractorService::makeExtractor for %s", mime);
+MediaExtractorService::~MediaExtractorService() {
+ ALOGE("should not be in ~MediaExtractorService");
+}
+
+::android::binder::Status MediaExtractorService::makeExtractor(
+ const ::android::sp<::android::IDataSource>& remoteSource,
+ const ::std::unique_ptr< ::std::string> &mime,
+ ::android::sp<::android::IMediaExtractor>* _aidl_return) {
+ ALOGV("@@@ MediaExtractorService::makeExtractor for %s", mime.get()->c_str());
sp<DataSource> localSource = CreateDataSourceFromIDataSource(remoteSource);
- sp<IMediaExtractor> extractor = MediaExtractorFactory::CreateFromService(localSource, mime);
+ MediaBuffer::useSharedMemory();
+ sp<IMediaExtractor> extractor = MediaExtractorFactory::CreateFromService(
+ localSource,
+ mime.get() ? mime.get()->c_str() : nullptr);
ALOGV("extractor service created %p (%s)",
extractor.get(),
extractor == nullptr ? "" : extractor->name());
if (extractor != nullptr) {
- registerMediaExtractor(extractor, localSource, mime);
- return extractor;
+ registerMediaExtractor(extractor, localSource, mime.get() ? mime.get()->c_str() : nullptr);
}
- return nullptr;
+ *_aidl_return = extractor;
+ return binder::Status::ok();
}
-sp<IDataSource> MediaExtractorService::makeIDataSource(int fd, int64_t offset, int64_t length)
-{
- sp<DataSource> source = DataSourceFactory::CreateFromFd(fd, offset, length);
- return CreateIDataSourceFromDataSource(source);
+::android::binder::Status MediaExtractorService::makeIDataSource(
+ base::unique_fd fd,
+ int64_t offset,
+ int64_t length,
+ ::android::sp<::android::IDataSource>* _aidl_return) {
+ sp<DataSource> source = DataSourceFactory::getInstance()->CreateFromFd(fd.release(), offset, length);
+ *_aidl_return = CreateIDataSourceFromDataSource(source);
+ return binder::Status::ok();
}
-std::unordered_set<std::string> MediaExtractorService::getSupportedTypes() {
- return MediaExtractorFactory::getSupportedTypes();
+::android::binder::Status MediaExtractorService::getSupportedTypes(
+ ::std::vector<::std::string>* _aidl_return) {
+ *_aidl_return = MediaExtractorFactory::getSupportedTypes();
+ return binder::Status::ok();
}
status_t MediaExtractorService::dump(int fd, const Vector<String16>& args) {
return MediaExtractorFactory::dump(fd, args) || dumpExtractors(fd, args);
}
-status_t MediaExtractorService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
- uint32_t flags)
-{
- return BnMediaExtractorService::onTransact(code, data, reply, flags);
-}
-
} // namespace android
diff --git a/services/mediaextractor/MediaExtractorService.h b/services/mediaextractor/MediaExtractorService.h
index c9cebcf..1b40bf9 100644
--- a/services/mediaextractor/MediaExtractorService.h
+++ b/services/mediaextractor/MediaExtractorService.h
@@ -18,31 +18,33 @@
#define ANDROID_MEDIA_EXTRACTOR_SERVICE_H
#include <binder/BinderService.h>
-#include <media/IMediaExtractorService.h>
-#include <media/IMediaExtractor.h>
+#include <android/BnMediaExtractorService.h>
+#include <android/IMediaExtractor.h>
namespace android {
class MediaExtractorService : public BinderService<MediaExtractorService>, public BnMediaExtractorService
{
- friend class BinderService<MediaExtractorService>; // for MediaExtractorService()
public:
MediaExtractorService();
- virtual ~MediaExtractorService() { }
- virtual void onFirstRef() { }
+ virtual ~MediaExtractorService();
static const char* getServiceName() { return "media.extractor"; }
- virtual sp<IMediaExtractor> makeExtractor(const sp<IDataSource> &source, const char *mime);
+ virtual ::android::binder::Status makeExtractor(
+ const ::android::sp<::android::IDataSource>& source,
+ const ::std::unique_ptr< ::std::string> &mime,
+ ::android::sp<::android::IMediaExtractor>* _aidl_return);
- virtual sp<IDataSource> makeIDataSource(int fd, int64_t offset, int64_t length);
+ virtual ::android::binder::Status makeIDataSource(
+ base::unique_fd fd,
+ int64_t offset,
+ int64_t length,
+ ::android::sp<::android::IDataSource>* _aidl_return);
- virtual std::unordered_set<std::string> getSupportedTypes();
+ virtual ::android::binder::Status getSupportedTypes(::std::vector<::std::string>* _aidl_return);
- virtual status_t dump(int fd, const Vector<String16>& args);
-
- virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
- uint32_t flags);
+ virtual status_t dump(int fd, const Vector<String16>& args);
private:
Mutex mLock;
diff --git a/services/mediaextractor/main_extractorservice.cpp b/services/mediaextractor/main_extractorservice.cpp
index 3c4125b..afb7692 100644
--- a/services/mediaextractor/main_extractorservice.cpp
+++ b/services/mediaextractor/main_extractorservice.cpp
@@ -28,6 +28,8 @@
#include <android-base/properties.h>
#include <utils/misc.h>
+#include <bionic/reserved_signals.h>
+
// from LOCAL_C_INCLUDES
#include "MediaExtractorService.h"
#include "MediaUtils.h"
@@ -49,6 +51,10 @@
signal(SIGPIPE, SIG_IGN);
+ // Do not assist platform profilers (relevant only on debug builds).
+ // Otherwise, the signal handler can violate the seccomp policy.
+ signal(BIONIC_SIGNAL_PROFILER, SIG_IGN);
+
//b/62255959: this forces libutis.so to dlopen vendor version of libutils.so
//before minijail is on. This is dirty but required since some syscalls such
//as pread64 are used by linker but aren't allowed in the minijail. By
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
index 38f9be6..e1f7fe7 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
@@ -41,13 +41,24 @@
getgroups32: 1
nanosleep: 1
getrandom: 1
+timer_create: 1
+timer_settime: 1
+timer_delete: 1
# for dynamically loading extractors
pread64: 1
+# mremap: Ensure |flags| are (MREMAP_MAYMOVE | MREMAP_FIXED) TODO: Once minijail
+# parser support for '<' is in this needs to be modified to also prevent
+# |old_address| and |new_address| from touching the exception vector page, which
+# 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 || arg3 == MREMAP_MAYMOVE
+
# for FileSource
readlinkat: 1
_llseek: 1
-@include /system/etc/seccomp_policy/crash_dump.arm.policy
-@include /system/etc/seccomp_policy/code_coverage.arm.policy
+@include /apex/com.android.media/etc/seccomp_policy/crash_dump.arm.policy
+@include /apex/com.android.media/etc/seccomp_policy/code_coverage.arm.policy
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
index 8fd8787..9bbd53b 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
@@ -30,6 +30,9 @@
getrlimit: 1
nanosleep: 1
getrandom: 1
+timer_create: 1
+timer_settime: 1
+timer_delete: 1
# for FileSource
readlinkat: 1
@@ -43,5 +46,5 @@
# Required by Sanitizers
sched_yield: 1
-@include /system/etc/seccomp_policy/crash_dump.arm64.policy
-@include /system/etc/seccomp_policy/code_coverage.arm64.policy
+@include /apex/com.android.media/etc/seccomp_policy/crash_dump.arm64.policy
+@include /apex/com.android.media/etc/seccomp_policy/code_coverage.arm64.policy
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy b/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
index 05915d1..5b37627 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
@@ -39,6 +39,9 @@
getgroups32: 1
nanosleep: 1
getrandom: 1
+timer_create: 1
+timer_settime: 1
+timer_delete: 1
# for dynamically loading extractors
getdents64: 1
@@ -56,5 +59,5 @@
getpid: 1
gettid: 1
-@include /system/etc/seccomp_policy/crash_dump.x86.policy
-@include /system/etc/seccomp_policy/code_coverage.x86.policy
+@include /apex/com.android.media/etc/seccomp_policy/crash_dump.x86.policy
+@include /apex/com.android.media/etc/seccomp_policy/code_coverage.x86.policy
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-x86_64.policy b/services/mediaextractor/seccomp_policy/mediaextractor-x86_64.policy
index e6a55d0..51df1a2 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-x86_64.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-x86_64.policy
@@ -34,6 +34,9 @@
getrlimit: 1
nanosleep: 1
getrandom: 1
+timer_create: 1
+timer_settime: 1
+timer_delete: 1
# for dynamically loading extractors
getdents64: 1
@@ -50,5 +53,5 @@
getpid: 1
gettid: 1
-@include /system/etc/seccomp_policy/crash_dump.x86_64.policy
-@include /system/etc/seccomp_policy/code_coverage.x86_64.policy
+@include /apex/com.android.media/etc/seccomp_policy/crash_dump.x86_64.policy
+@include /apex/com.android.media/etc/seccomp_policy/code_coverage.x86_64.policy
diff --git a/services/medialog/Android.bp b/services/medialog/Android.bp
index bee5d25..74b63d5 100644
--- a/services/medialog/Android.bp
+++ b/services/medialog/Android.bp
@@ -6,6 +6,10 @@
"MediaLogService.cpp",
],
+ header_libs: [
+ "libmedia_headers",
+ ],
+
shared_libs: [
"libaudioutils",
"libbinder",
diff --git a/services/mediametrics/AnalyticsActions.h b/services/mediametrics/AnalyticsActions.h
new file mode 100644
index 0000000..5568c91
--- /dev/null
+++ b/services/mediametrics/AnalyticsActions.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <media/MediaMetricsItem.h>
+#include <mutex>
+
+namespace android::mediametrics {
+
+/**
+ * AnalyticsActions consists of a map of pairs <trigger, action> which
+ * are evaluated for a given incoming MediaMetrics item.
+ *
+ * A vector of Actions are returned from getActionsForItem() which
+ * should be executed outside of any locks.
+ *
+ * Mediametrics assumes weak consistency, which is fine as the analytics database
+ * is generally strictly increasing in size (until gc removes values that are
+ * supposedly no longer needed).
+ */
+
+class AnalyticsActions {
+public:
+
+ using Elem = mediametrics::Item::Prop::Elem;
+ /**
+ * Trigger: a pair consisting of
+ * std::string: A wildcard url specifying a property in the item,
+ * where '*' indicates 0 or more arbitrary characters
+ * for the item key match.
+ * Elem: A value that needs to match exactly.
+ *
+ * Trigger is used in a map sort; default less with std::string as primary key.
+ * The wildcard accepts a string with '*' as being 0 or more arbitrary
+ * characters for the item key match. A wildcard is preferred over general
+ * regexp for simple fast lookup.
+ *
+ * TODO: incorporate a regexp option.
+ */
+ using Trigger = std::pair<std::string, Elem>;
+
+ /**
+ * Function: The function to be executed.
+ */
+ using Function = std::function<
+ void(const std::shared_ptr<const mediametrics::Item>& item)>;
+
+ /**
+ * Action: An action to execute. This is a shared pointer to Function.
+ */
+ using Action = std::shared_ptr<Function>;
+
+ /**
+ * Adds a new action.
+ *
+ * \param url references a property in the item with wildcards
+ * \param value references a value (cast to Elem automatically)
+ * so be careful of the type. It must be one of
+ * the types acceptable to Elem.
+ * \param action is a function or lambda to execute if the url matches value
+ * in the item.
+ */
+ template <typename T, typename U, typename A>
+ void addAction(T&& url, U&& value, A&& action) {
+ std::lock_guard l(mLock);
+ mFilters[ { std::forward<T>(url), std::forward<U>(value) } ]
+ = std::forward<A>(action);
+ }
+
+ // TODO: remove an action.
+
+ /**
+ * Get all the actions triggered for a particular item.
+ *
+ * \param item to be analyzed for actions.
+ */
+ std::vector<Action>
+ getActionsForItem(const std::shared_ptr<const mediametrics::Item>& item) {
+ std::vector<Action> actions;
+ std::lock_guard l(mLock);
+
+ // Essentially the code looks like this:
+ /*
+ for (auto &[trigger, action] : mFilters) {
+ if (isMatch(trigger, item)) {
+ actions.push_back(action);
+ }
+ }
+ */
+
+ // Optimization: there should only be one match for a non-wildcard url.
+ auto it = mFilters.upper_bound( {item->getKey(), std::monostate{} });
+ if (it != mFilters.end()) {
+ const auto &[trigger, action] = *it;
+ if (isMatch(trigger, item)) {
+ actions.push_back(action);
+ }
+ }
+
+ // Optimization: for wildcard URLs we go backwards until there is no
+ // match with the prefix before the wildcard.
+ while (it != mFilters.begin()) { // this walks backwards, cannot start at begin.
+ const auto &[trigger, action] = *--it; // look backwards
+ int ret = isWildcardMatch(trigger, item);
+ if (ret == mediametrics::Item::RECURSIVE_WILDCARD_CHECK_MATCH_FOUND) {
+ actions.push_back(action); // match found.
+ } else if (ret == mediametrics::Item::RECURSIVE_WILDCARD_CHECK_NO_MATCH_NO_WILDCARD) {
+ break; // no match before wildcard.
+ }
+ // a wildcard was encountered when matching prefix, so we should check again.
+ }
+ return actions;
+ }
+
+private:
+
+ static inline bool isMatch(const Trigger& trigger,
+ const std::shared_ptr<const mediametrics::Item>& item) {
+ const auto& [key, elem] = trigger;
+ if (!startsWith(key, item->getKey())) return false;
+ // The trigger key is in format (item key).propName, so + 1 skips '.' delimeter.
+ const char *propName = key.c_str() + item->getKey().size() + 1;
+ return item->hasPropElem(propName, elem);
+ }
+
+ static inline int isWildcardMatch(const Trigger& trigger,
+ const std::shared_ptr<const mediametrics::Item>& item) {
+ const auto& [key, elem] = trigger;
+ return item->recursiveWildcardCheckElem(key.c_str(), elem);
+ }
+
+ mutable std::mutex mLock;
+ std::map<Trigger, Action> mFilters; // GUARDED_BY mLock
+};
+
+} // namespace android::mediametrics
diff --git a/services/mediametrics/AnalyticsState.h b/services/mediametrics/AnalyticsState.h
new file mode 100644
index 0000000..290ed21
--- /dev/null
+++ b/services/mediametrics/AnalyticsState.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "TimeMachine.h"
+#include "TransactionLog.h"
+
+namespace android::mediametrics {
+
+/**
+ * AnalyticsState consists of a TimeMachine and TransactionLog for a set
+ * of MediaMetrics Items.
+ *
+ * One can add new Items with the submit() method.
+ *
+ * The AnalyticsState may be cleared or duplicated to preserve state after crashes
+ * in services are detected.
+ *
+ * As its members may not be moveable due to mutexes, we use this encapsulation
+ * with a shared pointer in order to save it or duplicate it.
+ */
+class AnalyticsState {
+public:
+ /**
+ * Returns success if AnalyticsState accepts the item.
+ *
+ * A trusted source can create a new key, an untrusted source
+ * can only modify the key if the uid will match that authorized
+ * on the existing key.
+ *
+ * \param item the item to be submitted.
+ * \param isTrusted whether the transaction comes from a trusted source.
+ * In this case, a trusted source is verified by binder
+ * UID to be a system service by MediaMetrics service.
+ * Do not use true if you haven't really checked!
+ *
+ * \return NO_ERROR on success or
+ * PERMISSION_DENIED if the item cannot be put into the AnalyticsState.
+ */
+ status_t submit(const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted) {
+ return mTimeMachine.put(item, isTrusted) ?: mTransactionLog.put(item);
+ }
+
+ /**
+ * Returns the TimeMachine.
+ *
+ * The TimeMachine object is internally locked, so access is safe and defined,
+ * but multiple threaded access may change results after calling.
+ */
+ TimeMachine& timeMachine() { return mTimeMachine; }
+ const TimeMachine& timeMachine() const { return mTimeMachine; }
+
+ /**
+ * Returns the TransactionLog.
+ *
+ * The TransactionLog object is internally locked, so access is safe and defined,
+ * but multiple threaded access may change results after calling.
+ */
+ TransactionLog& transactionLog() { return mTransactionLog; }
+ const TransactionLog& transactionLog() const { return mTransactionLog; }
+
+ /**
+ * Returns a pair consisting of the dump string, and the number of lines in the string.
+ *
+ * The number of lines in the returned pair is used as an optimization
+ * for subsequent line limiting.
+ *
+ * The TimeMachine and the TransactionLog are dumped separately under
+ * different locks, so may not be 100% consistent with the last data
+ * delivered.
+ *
+ * \param lines the maximum number of lines in the string returned.
+ */
+ std::pair<std::string, int32_t> dump(int32_t lines = INT32_MAX) const {
+ std::stringstream ss;
+ int32_t ll = lines;
+
+ if (ll > 0) {
+ ss << "TransactionLog:\n";
+ --ll;
+ }
+ if (ll > 0) {
+ auto [s, l] = mTransactionLog.dump(ll);
+ ss << s;
+ ll -= l;
+ }
+ if (ll > 0) {
+ ss << "TimeMachine:\n";
+ --ll;
+ }
+ if (ll > 0) {
+ auto [s, l] = mTimeMachine.dump(ll);
+ ss << s;
+ ll -= l;
+ }
+ return { ss.str(), lines - ll };
+ }
+
+ /**
+ * Clears the AnalyticsState.
+ */
+ void clear() {
+ mTimeMachine.clear();
+ mTransactionLog.clear();
+ }
+
+private:
+ // Note: TimeMachine and TransactionLog are individually locked.
+ // Access to these objects under multiple threads will be weakly synchronized,
+ // which is acceptable as modifications only increase the history (or with GC,
+ // eliminates very old history).
+
+ TimeMachine mTimeMachine;
+ TransactionLog mTransactionLog;
+};
+
+} // namespace android::mediametrics
diff --git a/services/mediametrics/Android.bp b/services/mediametrics/Android.bp
new file mode 100644
index 0000000..ec59ec1
--- /dev/null
+++ b/services/mediametrics/Android.bp
@@ -0,0 +1,78 @@
+// Media Statistics service
+//
+
+cc_binary {
+ name: "mediametrics",
+
+ srcs: [
+ "main_mediametrics.cpp",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "liblog",
+ "libmediametricsservice",
+ "libmediautils",
+ "libutils",
+ ],
+ header_libs: [
+ "libmediametrics_headers",
+ ],
+
+ init_rc: [
+ "mediametrics.rc",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+}
+
+cc_library_shared {
+ name: "libmediametricsservice",
+
+ srcs: [
+ "AudioAnalytics.cpp",
+ "iface_statsd.cpp",
+ "MediaMetricsService.cpp",
+ "statsd_audiopolicy.cpp",
+ "statsd_audiorecord.cpp",
+ "statsd_audiothread.cpp",
+ "statsd_audiotrack.cpp",
+ "statsd_codec.cpp",
+ "statsd_drm.cpp",
+ "statsd_extractor.cpp",
+ "statsd_nuplayer.cpp",
+ "statsd_recorder.cpp",
+ ],
+
+ proto: {
+ type: "lite",
+ },
+
+ shared_libs: [
+ "libbinder",
+ "liblog",
+ "libmediametrics",
+ "libmediautils",
+ "libprotobuf-cpp-lite",
+ "libstatslog",
+ "libutils",
+ ],
+
+ static_libs: [
+ "libplatformprotos",
+ ],
+
+ include_dirs: [
+ "system/media/audio_utils/include",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+}
diff --git a/services/mediametrics/AudioAnalytics.cpp b/services/mediametrics/AudioAnalytics.cpp
new file mode 100644
index 0000000..126e501
--- /dev/null
+++ b/services/mediametrics/AudioAnalytics.cpp
@@ -0,0 +1,153 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AudioAnalytics"
+#include <utils/Log.h>
+
+#include "AudioAnalytics.h"
+
+#include <audio_utils/clock.h> // clock conversions
+
+namespace android::mediametrics {
+
+AudioAnalytics::AudioAnalytics()
+{
+ ALOGD("%s", __func__);
+
+ // Add action to save AnalyticsState if audioserver is restarted.
+ // This triggers on an item of "audio.flinger"
+ // with a property "event" set to "AudioFlinger" (the constructor).
+ mActions.addAction(
+ AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
+ std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
+ std::make_shared<AnalyticsActions::Function>(
+ [this](const std::shared_ptr<const android::mediametrics::Item> &item){
+ ALOGW("(key=%s) Audioflinger constructor event detected", item->getKey().c_str());
+ mPreviousAnalyticsState.set(std::make_shared<AnalyticsState>(
+ *mAnalyticsState.get()));
+ // Note: get returns shared_ptr temp, whose lifetime is extended
+ // to end of full expression.
+ mAnalyticsState->clear(); // TODO: filter the analytics state.
+ // Perhaps report this.
+ }));
+
+ // Check underruns
+ mActions.addAction(
+ AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
+ std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_UNDERRUN),
+ std::make_shared<AnalyticsActions::Function>(
+ [this](const std::shared_ptr<const android::mediametrics::Item> &item){
+ std::string threadId = item->getKey().substr(
+ sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) - 1);
+ std::string outputDevices;
+ mAnalyticsState->timeMachine().get(
+ item->getKey(), AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
+ ALOGD("(key=%s) Thread underrun event detected on io handle:%s device:%s",
+ item->getKey().c_str(), threadId.c_str(), outputDevices.c_str());
+ if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) {
+ // report this for Bluetooth
+ }
+ }));
+
+ // Check latencies, playback and startup
+ mActions.addAction(
+ AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_LATENCYMS,
+ std::monostate{}, // accept any value
+ std::make_shared<AnalyticsActions::Function>(
+ [this](const std::shared_ptr<const android::mediametrics::Item> &item){
+ double latencyMs{};
+ double startupMs{};
+ if (!item->get(AMEDIAMETRICS_PROP_LATENCYMS, &latencyMs)
+ || !item->get(AMEDIAMETRICS_PROP_STARTUPMS, &startupMs)) return;
+
+ std::string trackId = item->getKey().substr(
+ sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK) - 1);
+ std::string thread = getThreadFromTrack(item->getKey());
+ std::string outputDevices;
+ mAnalyticsState->timeMachine().get(
+ thread, AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
+ ALOGD("(key=%s) Track latencyMs:%lf startupMs:%lf detected on port:%s device:%s",
+ item->getKey().c_str(), latencyMs, startupMs,
+ trackId.c_str(), outputDevices.c_str());
+ if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) {
+ // report this for Bluetooth
+ }
+ }));
+}
+
+AudioAnalytics::~AudioAnalytics()
+{
+ ALOGD("%s", __func__);
+}
+
+status_t AudioAnalytics::submit(
+ const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted)
+{
+ if (!startsWith(item->getKey(), AMEDIAMETRICS_KEY_PREFIX_AUDIO)) return BAD_VALUE;
+ status_t status = mAnalyticsState->submit(item, isTrusted);
+ if (status != NO_ERROR) return status; // may not be permitted.
+
+ // Only if the item was successfully submitted (permission)
+ // do we check triggered actions.
+ checkActions(item);
+ return NO_ERROR;
+}
+
+std::pair<std::string, int32_t> AudioAnalytics::dump(int32_t lines) const
+{
+ std::stringstream ss;
+ int32_t ll = lines;
+
+ if (ll > 0) {
+ auto [s, l] = mAnalyticsState->dump(ll);
+ ss << s;
+ ll -= l;
+ }
+ if (ll > 0) {
+ ss << "Prior audioserver state:\n";
+ --ll;
+ }
+ if (ll > 0) {
+ auto [s, l] = mPreviousAnalyticsState->dump(ll);
+ ss << s;
+ ll -= l;
+ }
+ return { ss.str(), lines - ll };
+}
+
+void AudioAnalytics::checkActions(const std::shared_ptr<const mediametrics::Item>& item)
+{
+ auto actions = mActions.getActionsForItem(item); // internally locked.
+ // Execute actions with no lock held.
+ for (const auto& action : actions) {
+ (*action)(item);
+ }
+}
+
+// HELPER METHODS
+
+std::string AudioAnalytics::getThreadFromTrack(const std::string& track) const
+{
+ int32_t threadId_int32{};
+ if (mAnalyticsState->timeMachine().get(
+ track, AMEDIAMETRICS_PROP_THREADID, &threadId_int32) != NO_ERROR) {
+ return {};
+ }
+ return std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(threadId_int32);
+}
+
+} // namespace android
diff --git a/services/mediametrics/AudioAnalytics.h b/services/mediametrics/AudioAnalytics.h
new file mode 100644
index 0000000..4a42e22
--- /dev/null
+++ b/services/mediametrics/AudioAnalytics.h
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "AnalyticsActions.h"
+#include "AnalyticsState.h"
+#include "Wrap.h"
+
+namespace android::mediametrics {
+
+class AudioAnalytics
+{
+public:
+ AudioAnalytics();
+ ~AudioAnalytics();
+
+ /**
+ * Returns success if AudioAnalytics recognizes item.
+ *
+ * AudioAnalytics requires the item key to start with "audio.".
+ *
+ * A trusted source can create a new key, an untrusted source
+ * can only modify the key if the uid will match that authorized
+ * on the existing key.
+ *
+ * \param item the item to be submitted.
+ * \param isTrusted whether the transaction comes from a trusted source.
+ * In this case, a trusted source is verified by binder
+ * UID to be a system service by MediaMetrics service.
+ * Do not use true if you haven't really checked!
+ *
+ * \return NO_ERROR on success,
+ * PERMISSION_DENIED if the item cannot be put into the AnalyticsState,
+ * BAD_VALUE if the item key does not start with "audio.".
+ */
+ status_t submit(const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted);
+
+ /**
+ * Returns a pair consisting of the dump string, and the number of lines in the string.
+ *
+ * The number of lines in the returned pair is used as an optimization
+ * for subsequent line limiting.
+ *
+ * The TimeMachine and the TransactionLog are dumped separately under
+ * different locks, so may not be 100% consistent with the last data
+ * delivered.
+ *
+ * \param lines the maximum number of lines in the string returned.
+ */
+ std::pair<std::string, int32_t> dump(int32_t lines = INT32_MAX) const;
+
+private:
+
+ /**
+ * Checks for any pending actions for a particular item.
+ *
+ * \param item to check against the current AnalyticsActions.
+ */
+ void checkActions(const std::shared_ptr<const mediametrics::Item>& item);
+
+ // HELPER METHODS
+ /**
+ * Return the audio thread associated with an audio track name.
+ * e.g. "audio.track.32" -> "audio.thread.10" if the associated
+ * threadId for the audio track is 10.
+ */
+ std::string getThreadFromTrack(const std::string& track) const;
+
+ // Actions is individually locked
+ AnalyticsActions mActions;
+
+ // AnalyticsState is individually locked, and we use SharedPtrWrap
+ // to allow safe access even if the shared pointer changes underneath.
+
+ SharedPtrWrap<AnalyticsState> mAnalyticsState;
+ SharedPtrWrap<AnalyticsState> mPreviousAnalyticsState;
+};
+
+} // namespace android::mediametrics
diff --git a/services/mediametrics/MediaMetricsService.cpp b/services/mediametrics/MediaMetricsService.cpp
new file mode 100644
index 0000000..a6fefd2
--- /dev/null
+++ b/services/mediametrics/MediaMetricsService.cpp
@@ -0,0 +1,471 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaMetricsService"
+#include <utils/Log.h>
+
+#include "MediaMetricsService.h"
+
+#include <pwd.h> //getpwuid
+
+#include <android/content/pm/IPackageManagerNative.h> // package info
+#include <audio_utils/clock.h> // clock conversions
+#include <binder/IPCThreadState.h> // get calling uid
+#include <cutils/properties.h> // for property_get
+#include <private/android_filesystem_config.h> // UID
+
+namespace android {
+
+using namespace mediametrics;
+
+// individual records kept in memory: age or count
+// age: <= 28 hours (1 1/6 days)
+// count: hard limit of # records
+// (0 for either of these disables that threshold)
+//
+static constexpr nsecs_t kMaxRecordAgeNs = 28 * 3600 * NANOS_PER_SECOND;
+// 2019/6: average daily per device is currently 375-ish;
+// setting this to 2000 is large enough to catch most devices
+// we'll lose some data on very very media-active devices, but only for
+// the gms collection; statsd will have already covered those for us.
+// This also retains enough information to help with bugreports
+static constexpr size_t kMaxRecords = 2000;
+
+// max we expire in a single call, to constrain how long we hold the
+// mutex, which also constrains how long a client might wait.
+static constexpr size_t kMaxExpiredAtOnce = 50;
+
+// TODO: need to look at tuning kMaxRecords and friends for low-memory devices
+
+/* static */
+nsecs_t MediaMetricsService::roundTime(nsecs_t timeNs)
+{
+ return (timeNs + NANOS_PER_SECOND / 2) / NANOS_PER_SECOND * NANOS_PER_SECOND;
+}
+
+/* static */
+bool MediaMetricsService::useUidForPackage(
+ const std::string& package, const std::string& installer)
+{
+ if (strchr(package.c_str(), '.') == NULL) {
+ return false; // not of form 'com.whatever...'; assume internal and ok
+ } else if (strncmp(package.c_str(), "android.", 8) == 0) {
+ return false; // android.* packages are assumed fine
+ } else if (strncmp(installer.c_str(), "com.android.", 12) == 0) {
+ return false; // from play store
+ } else if (strncmp(installer.c_str(), "com.google.", 11) == 0) {
+ return false; // some google source
+ } else if (strcmp(installer.c_str(), "preload") == 0) {
+ return false; // preloads
+ } else {
+ return true; // we're not sure where it came from, use uid only.
+ }
+}
+
+MediaMetricsService::MediaMetricsService()
+ : mMaxRecords(kMaxRecords),
+ mMaxRecordAgeNs(kMaxRecordAgeNs),
+ mMaxRecordsExpiredAtOnce(kMaxExpiredAtOnce)
+{
+ ALOGD("%s", __func__);
+}
+
+MediaMetricsService::~MediaMetricsService()
+{
+ ALOGD("%s", __func__);
+ // the class destructor clears anyhow, but we enforce clearing items first.
+ mItemsDiscarded += mItems.size();
+ mItems.clear();
+}
+
+status_t MediaMetricsService::submitInternal(mediametrics::Item *item, bool release)
+{
+ // calling PID is 0 for one-way calls.
+ const pid_t pid = IPCThreadState::self()->getCallingPid();
+ const pid_t pid_given = item->getPid();
+ const uid_t uid = IPCThreadState::self()->getCallingUid();
+ const uid_t uid_given = item->getUid();
+
+ //ALOGD("%s: caller pid=%d uid=%d, item pid=%d uid=%d", __func__,
+ // (int)pid, (int)uid, (int) pid_given, (int)uid_given);
+
+ bool isTrusted;
+ switch (uid) {
+ case AID_AUDIOSERVER:
+ case AID_BLUETOOTH:
+ case AID_CAMERA:
+ case AID_DRM:
+ case AID_MEDIA:
+ case AID_MEDIA_CODEC:
+ case AID_MEDIA_EX:
+ case AID_MEDIA_DRM:
+ // case AID_SHELL: // DEBUG ONLY - used for mediametrics_tests to add new keys
+ case AID_SYSTEM:
+ // trusted source, only override default values
+ isTrusted = true;
+ if (uid_given == (uid_t)-1) {
+ item->setUid(uid);
+ }
+ if (pid_given == (pid_t)-1) {
+ item->setPid(pid); // if one-way then this is 0.
+ }
+ break;
+ default:
+ isTrusted = false;
+ item->setPid(pid); // always use calling pid, if one-way then this is 0.
+ item->setUid(uid);
+ break;
+ }
+
+ // Overwrite package name and version if the caller was untrusted or empty
+ if (!isTrusted || item->getPkgName().empty()) {
+ const uid_t uid = item->getUid();
+ mediautils::UidInfo::Info info = mUidInfo.getInfo(uid);
+ if (useUidForPackage(info.package, info.installer)) {
+ // remove uid information of unknown installed packages.
+ // TODO: perhaps this can be done just before uploading to Westworld.
+ item->setPkgName(std::to_string(uid));
+ item->setPkgVersionCode(0);
+ } else {
+ item->setPkgName(info.package);
+ item->setPkgVersionCode(info.versionCode);
+ }
+ }
+
+ ALOGV("%s: isTrusted:%d given uid %d; sanitized uid: %d sanitized pkg: %s "
+ "sanitized pkg version: %lld",
+ __func__,
+ (int)isTrusted,
+ uid_given, item->getUid(),
+ item->getPkgName().c_str(),
+ (long long)item->getPkgVersionCode());
+
+ mItemsSubmitted++;
+
+ // validate the record; we discard if we don't like it
+ if (isContentValid(item, isTrusted) == false) {
+ if (release) delete item;
+ return PERMISSION_DENIED;
+ }
+
+ // XXX: if we have a sessionid in the new record, look to make
+ // sure it doesn't appear in the finalized list.
+
+ if (item->count() == 0) {
+ ALOGV("%s: dropping empty record...", __func__);
+ if (release) delete item;
+ return BAD_VALUE;
+ }
+
+ if (!isTrusted || item->getTimestamp() == 0) {
+ // Westworld logs two times for events: ElapsedRealTimeNs (BOOTTIME) and
+ // WallClockTimeNs (REALTIME), but currently logs REALTIME to cloud.
+ //
+ // For consistency and correlation with other logging mechanisms
+ // we use REALTIME here.
+ const int64_t now = systemTime(SYSTEM_TIME_REALTIME);
+ item->setTimestamp(now);
+ }
+
+ // now attach either the item or its dup to a const shared pointer
+ std::shared_ptr<const mediametrics::Item> sitem(release ? item : item->dup());
+
+ (void)mAudioAnalytics.submit(sitem, isTrusted);
+
+ extern bool dump2Statsd(const std::shared_ptr<const mediametrics::Item>& item);
+ (void)dump2Statsd(sitem); // failure should be logged in function.
+ saveItem(sitem);
+ return NO_ERROR;
+}
+
+status_t MediaMetricsService::dump(int fd, const Vector<String16>& args)
+{
+ String8 result;
+
+ if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
+ result.appendFormat("Permission Denial: "
+ "can't dump MediaMetricsService from pid=%d, uid=%d\n",
+ IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid());
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+ }
+
+ // crack any parameters
+ const String16 protoOption("--proto");
+ const String16 clearOption("--clear");
+ bool clear = false;
+ const String16 sinceOption("--since");
+ nsecs_t ts_since = 0;
+ const String16 helpOption("--help");
+ const String16 onlyOption("--only");
+ std::string only;
+ const int n = args.size();
+ for (int i = 0; i < n; i++) {
+ if (args[i] == clearOption) {
+ clear = true;
+ } else if (args[i] == protoOption) {
+ i++;
+ if (i < n) {
+ // ignore
+ } else {
+ result.append("missing value for -proto\n\n");
+ }
+ } else if (args[i] == sinceOption) {
+ i++;
+ if (i < n) {
+ String8 value(args[i]);
+ char *endp;
+ const char *p = value.string();
+ ts_since = strtoll(p, &endp, 10);
+ if (endp == p || *endp != '\0') {
+ ts_since = 0;
+ }
+ } else {
+ ts_since = 0;
+ }
+ // command line is milliseconds; internal units are nano-seconds
+ ts_since *= NANOS_PER_MILLISECOND;
+ } else if (args[i] == onlyOption) {
+ i++;
+ if (i < n) {
+ String8 value(args[i]);
+ only = value.string();
+ }
+ } else if (args[i] == helpOption) {
+ // TODO: consider function area dumping.
+ // dumpsys media.metrics audiotrack,codec
+ // or dumpsys media.metrics audiotrack codec
+
+ result.append("Recognized parameters:\n");
+ result.append("--help this help message\n");
+ result.append("--proto # dump using protocol #");
+ result.append("--clear clears out saved records\n");
+ result.append("--only X process records for component X\n");
+ result.append("--since X include records since X\n");
+ result.append(" (X is milliseconds since the UNIX epoch)\n");
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+ }
+ }
+
+ {
+ std::lock_guard _l(mLock);
+
+ result.appendFormat("Dump of the %s process:\n", kServiceName);
+ dumpHeaders_l(result, ts_since);
+ dumpRecent_l(result, ts_since, only.c_str());
+
+ if (clear) {
+ mItemsDiscarded += mItems.size();
+ mItems.clear();
+ // shall we clear the summary data too?
+ }
+ // TODO: maybe consider a better way of dumping audio analytics info.
+ constexpr int32_t linesToDump = 1000;
+ auto [ dumpString, lines ] = mAudioAnalytics.dump(linesToDump);
+ result.append(dumpString.c_str());
+ if (lines == linesToDump) {
+ result.append("-- some lines may be truncated --\n");
+ }
+ }
+
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+// dump headers
+void MediaMetricsService::dumpHeaders_l(String8 &result, nsecs_t ts_since)
+{
+ if (mediametrics::Item::isEnabled()) {
+ result.append("Metrics gathering: enabled\n");
+ } else {
+ result.append("Metrics gathering: DISABLED via property\n");
+ }
+ result.appendFormat(
+ "Since Boot: Submissions: %lld Accepted: %lld\n",
+ (long long)mItemsSubmitted.load(), (long long)mItemsFinalized);
+ result.appendFormat(
+ "Records Discarded: %lld (by Count: %lld by Expiration: %lld)\n",
+ (long long)mItemsDiscarded, (long long)mItemsDiscardedCount,
+ (long long)mItemsDiscardedExpire);
+ if (ts_since != 0) {
+ result.appendFormat(
+ "Emitting Queue entries more recent than: %lld\n",
+ (long long)ts_since);
+ }
+}
+
+void MediaMetricsService::dumpRecent_l(
+ String8 &result, nsecs_t ts_since, const char * only)
+{
+ if (only != nullptr && *only == '\0') {
+ only = nullptr;
+ }
+ result.append("\nFinalized Metrics (oldest first):\n");
+ dumpQueue_l(result, ts_since, only);
+
+ // show who is connected and injecting records?
+ // talk about # records fed to the 'readers'
+ // talk about # records we discarded, perhaps "discarded w/o reading" too
+}
+
+void MediaMetricsService::dumpQueue_l(String8 &result) {
+ dumpQueue_l(result, (nsecs_t) 0, nullptr /* only */);
+}
+
+void MediaMetricsService::dumpQueue_l(
+ String8 &result, nsecs_t ts_since, const char * only) {
+ int slot = 0;
+
+ if (mItems.empty()) {
+ result.append("empty\n");
+ } else {
+ for (const auto &item : mItems) {
+ nsecs_t when = item->getTimestamp();
+ if (when < ts_since) {
+ continue;
+ }
+ // TODO: Only should be a set<string>
+ if (only != nullptr &&
+ item->getKey() /* std::string */ != only) {
+ ALOGV("%s: omit '%s', it's not '%s'",
+ __func__, item->getKey().c_str(), only);
+ continue;
+ }
+ result.appendFormat("%5d: %s\n",
+ slot, item->toString().c_str());
+ slot++;
+ }
+ }
+}
+
+//
+// Our Cheap in-core, non-persistent records management.
+
+// if item != NULL, it's the item we just inserted
+// true == more items eligible to be recovered
+bool MediaMetricsService::expirations_l(const std::shared_ptr<const mediametrics::Item>& item)
+{
+ bool more = false;
+
+ // check queue size
+ size_t overlimit = 0;
+ if (mMaxRecords > 0 && mItems.size() > mMaxRecords) {
+ overlimit = mItems.size() - mMaxRecords;
+ if (overlimit > mMaxRecordsExpiredAtOnce) {
+ more = true;
+ overlimit = mMaxRecordsExpiredAtOnce;
+ }
+ }
+
+ // check queue times
+ size_t expired = 0;
+ if (!more && mMaxRecordAgeNs > 0) {
+ const nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
+ // we check one at a time, skip search would be more efficient.
+ size_t i = overlimit;
+ for (; i < mItems.size(); ++i) {
+ auto &oitem = mItems[i];
+ nsecs_t when = oitem->getTimestamp();
+ if (oitem.get() == item.get()) {
+ break;
+ }
+ if (now > when && (now - when) <= mMaxRecordAgeNs) {
+ break; // Note SYSTEM_TIME_REALTIME may not be monotonic.
+ }
+ if (i >= mMaxRecordsExpiredAtOnce) {
+ // this represents "one too many"; tell caller there are
+ // more to be reclaimed.
+ more = true;
+ break;
+ }
+ }
+ expired = i - overlimit;
+ }
+
+ if (const size_t toErase = overlimit + expired;
+ toErase > 0) {
+ mItemsDiscardedCount += overlimit;
+ mItemsDiscardedExpire += expired;
+ mItemsDiscarded += toErase;
+ mItems.erase(mItems.begin(), mItems.begin() + toErase); // erase from front
+ }
+ return more;
+}
+
+void MediaMetricsService::processExpirations()
+{
+ bool more;
+ do {
+ sleep(1);
+ std::lock_guard _l(mLock);
+ more = expirations_l(nullptr);
+ } while (more);
+}
+
+void MediaMetricsService::saveItem(const std::shared_ptr<const mediametrics::Item>& item)
+{
+ std::lock_guard _l(mLock);
+ // we assume the items are roughly in time order.
+ mItems.emplace_back(item);
+ ++mItemsFinalized;
+ if (expirations_l(item)
+ && (!mExpireFuture.valid()
+ || mExpireFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready)) {
+ mExpireFuture = std::async(std::launch::async, [this] { processExpirations(); });
+ }
+}
+
+/* static */
+bool MediaMetricsService::isContentValid(const mediametrics::Item *item, bool isTrusted)
+{
+ if (isTrusted) return true;
+ // untrusted uids can only send us a limited set of keys
+ const std::string &key = item->getKey();
+ if (startsWith(key, "audio.")) return true;
+ if (startsWith(key, "drm.vendor.")) return true;
+ // the list of allowedKey uses statsd_handlers
+ // in iface_statsd.cpp as reference
+ // drmmanager is from a trusted uid, therefore not needed here
+ for (const char *allowedKey : {
+ // legacy audio
+ "audiopolicy",
+ "audiorecord",
+ "audiothread",
+ "audiotrack",
+ // other media
+ "codec",
+ "extractor",
+ "mediadrm",
+ "nuplayer",
+ }) {
+ if (key == allowedKey) {
+ return true;
+ }
+ }
+ ALOGD("%s: invalid key: %s", __func__, item->toString().c_str());
+ return false;
+}
+
+// are we rate limited, normally false
+bool MediaMetricsService::isRateLimited(mediametrics::Item *) const
+{
+ return false;
+}
+
+} // namespace android
diff --git a/services/mediametrics/MediaMetricsService.h b/services/mediametrics/MediaMetricsService.h
new file mode 100644
index 0000000..935bee2
--- /dev/null
+++ b/services/mediametrics/MediaMetricsService.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <atomic>
+#include <deque>
+#include <future>
+#include <mutex>
+#include <unordered_map>
+
+// IMediaMetricsService must include Vector, String16, Errors
+#include <media/IMediaMetricsService.h>
+#include <mediautils/ServiceUtilities.h>
+#include <utils/String8.h>
+
+#include "AudioAnalytics.h"
+
+namespace android {
+
+class MediaMetricsService : public BnMediaMetricsService
+{
+public:
+ MediaMetricsService();
+ ~MediaMetricsService() override;
+
+ /**
+ * Submits the indicated record to the mediaanalytics service.
+ *
+ * \param item the item to submit.
+ * \return status failure, which is negative on binder transaction failure.
+ * As the transaction is one-way, remote failures will not be reported.
+ */
+ status_t submit(mediametrics::Item *item) override {
+ return submitInternal(item, false /* release */);
+ }
+
+ status_t submitBuffer(const char *buffer, size_t length) override {
+ mediametrics::Item *item = new mediametrics::Item();
+ return item->readFromByteString(buffer, length)
+ ?: submitInternal(item, true /* release */);
+ }
+
+ status_t dump(int fd, const Vector<String16>& args) override;
+
+ static constexpr const char * const kServiceName = "media.metrics";
+
+ /**
+ * Rounds time to the nearest second.
+ */
+ static nsecs_t roundTime(nsecs_t timeNs);
+
+ /**
+ * Returns true if we should use uid for package name when uploading to WestWorld.
+ */
+ static bool useUidForPackage(const std::string& package, const std::string& installer);
+
+protected:
+
+ // Internal call where release is true if ownership of item is transferred
+ // to the service (that is, the service will eventually delete the item).
+ status_t submitInternal(mediametrics::Item *item, bool release) override;
+
+private:
+ void processExpirations();
+ // input validation after arrival from client
+ static bool isContentValid(const mediametrics::Item *item, bool isTrusted);
+ bool isRateLimited(mediametrics::Item *) const;
+ void saveItem(const std::shared_ptr<const mediametrics::Item>& item);
+
+ // The following methods are GUARDED_BY(mLock)
+ bool expirations_l(const std::shared_ptr<const mediametrics::Item>& item);
+
+ // support for generating output
+ void dumpQueue_l(String8 &result);
+ void dumpQueue_l(String8 &result, nsecs_t, const char *only);
+ void dumpHeaders_l(String8 &result, nsecs_t ts_since);
+ void dumpSummaries_l(String8 &result, nsecs_t ts_since, const char * only);
+ void dumpRecent_l(String8 &result, nsecs_t ts_since, const char * only);
+
+ // The following variables accessed without mLock
+
+ // limit how many records we'll retain
+ // by count (in each queue (open, finalized))
+ const size_t mMaxRecords;
+ // by time (none older than this)
+ const nsecs_t mMaxRecordAgeNs;
+ // max to expire per expirations_l() invocation
+ const size_t mMaxRecordsExpiredAtOnce;
+
+ std::atomic<int64_t> mItemsSubmitted{}; // accessed outside of lock.
+
+ mediautils::UidInfo mUidInfo; // mUidInfo can be accessed without lock (locked internally)
+
+ mediametrics::AudioAnalytics mAudioAnalytics;
+
+ std::mutex mLock;
+ // statistics about our analytics
+ int64_t mItemsFinalized = 0; // GUARDED_BY(mLock)
+ int64_t mItemsDiscarded = 0; // GUARDED_BY(mLock)
+ int64_t mItemsDiscardedExpire = 0; // GUARDED_BY(mLock)
+ int64_t mItemsDiscardedCount = 0; // GUARDED_BY(mLock)
+
+ // If we have a worker thread to garbage collect
+ std::future<void> mExpireFuture; // GUARDED_BY(mLock)
+
+ // Our item queue, generally (oldest at front)
+ // TODO: Make separate class, use segmented queue, write lock only end.
+ // Note: Another analytics module might have ownership of an item longer than the log.
+ std::deque<std::shared_ptr<const mediametrics::Item>> mItems; // GUARDED_BY(mLock)
+};
+
+} // namespace android
diff --git a/services/mediametrics/OWNERS b/services/mediametrics/OWNERS
new file mode 100644
index 0000000..e37a1f8
--- /dev/null
+++ b/services/mediametrics/OWNERS
@@ -0,0 +1,2 @@
+essick@google.com
+hunga@google.com
diff --git a/services/mediametrics/TEST_MAPPING b/services/mediametrics/TEST_MAPPING
new file mode 100644
index 0000000..01e9e46
--- /dev/null
+++ b/services/mediametrics/TEST_MAPPING
@@ -0,0 +1,10 @@
+{
+ "presubmit": [
+ {
+ "name": "mediametrics_tests"
+ },
+ {
+ "name": "CtsNativeMediaMetricsTestCases"
+ }
+ ]
+}
diff --git a/services/mediametrics/TimeMachine.h b/services/mediametrics/TimeMachine.h
new file mode 100644
index 0000000..a4c3693
--- /dev/null
+++ b/services/mediametrics/TimeMachine.h
@@ -0,0 +1,550 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <any>
+#include <map>
+#include <sstream>
+#include <string>
+#include <variant>
+#include <vector>
+
+#include <media/MediaMetricsItem.h>
+#include <utils/Timers.h>
+
+namespace android::mediametrics {
+
+// define a way of printing the monostate
+inline std::ostream & operator<< (std::ostream& s,
+ std::monostate const& v __unused) {
+ s << "none_item";
+ return s;
+}
+
+// define a way of printing a std::pair.
+template <typename T, typename U>
+std::ostream & operator<< (std::ostream& s,
+ const std::pair<T, U>& v) {
+ s << "{ " << v.first << ", " << v.second << " }";
+ return s;
+}
+
+// define a way of printing a variant
+// see https://en.cppreference.com/w/cpp/utility/variant/visit
+template <typename T0, typename ... Ts>
+std::ostream & operator<< (std::ostream& s,
+ std::variant<T0, Ts...> const& v) {
+ std::visit([&s](auto && arg){ s << std::forward<decltype(arg)>(arg); }, v);
+ return s;
+}
+
+/**
+ * The TimeMachine is used to record timing changes of MediaAnalyticItem
+ * properties.
+ *
+ * Any URL that ends with '#' (AMEDIAMETRICS_PROP_SUFFIX_CHAR_DUPLICATES_ALLOWED)
+ * will have a time sequence that keeps duplicates.
+ *
+ * The TimeMachine is NOT thread safe.
+ */
+class TimeMachine final { // made final as we have copy constructor instead of dup() override.
+public:
+ using Elem = Item::Prop::Elem; // use the Item property element.
+ using PropertyHistory = std::multimap<int64_t /* time */, Elem>;
+
+private:
+
+ // KeyHistory contains no lock.
+ // Access is through the TimeMachine, and a hash-striped lock is used
+ // before calling into KeyHistory.
+ class KeyHistory {
+ public:
+ template <typename T>
+ KeyHistory(T key, pid_t pid, uid_t uid, int64_t time)
+ : mKey(key)
+ , mPid(pid)
+ , mUid(uid)
+ , mCreationTime(time)
+ , mLastModificationTime(time)
+ {
+ putValue(BUNDLE_PID, (int32_t)pid, time);
+ putValue(BUNDLE_UID, (int32_t)uid, time);
+ }
+
+ KeyHistory(const KeyHistory &other) = default;
+
+ status_t checkPermission(uid_t uidCheck) const {
+ return uidCheck != (uid_t)-1 && uidCheck != mUid ? PERMISSION_DENIED : NO_ERROR;
+ }
+
+ template <typename T>
+ status_t getValue(const std::string &property, T* value, int64_t time = 0) const {
+ if (time == 0) time = systemTime(SYSTEM_TIME_REALTIME);
+ const auto tsptr = mPropertyMap.find(property);
+ if (tsptr == mPropertyMap.end()) return BAD_VALUE;
+ const auto& timeSequence = tsptr->second;
+ auto eptr = timeSequence.upper_bound(time);
+ if (eptr == timeSequence.begin()) return BAD_VALUE;
+ --eptr;
+ if (eptr == timeSequence.end()) return BAD_VALUE;
+ const T* vptr = std::get_if<T>(&eptr->second);
+ if (vptr == nullptr) return BAD_VALUE;
+ *value = *vptr;
+ return NO_ERROR;
+ }
+
+ template <typename T>
+ status_t getValue(const std::string &property, T defaultValue, int64_t time = 0) const {
+ T value;
+ return getValue(property, &value, time) != NO_ERROR ? defaultValue : value;
+ }
+
+ void putProp(
+ const std::string &name, const mediametrics::Item::Prop &prop, int64_t time = 0) {
+ //alternatively: prop.visit([&](auto value) { putValue(name, value, time); });
+ putValue(name, prop.get(), time);
+ }
+
+ template <typename T>
+ void putValue(const std::string &property,
+ T&& e, int64_t time = 0) {
+ if (time == 0) time = systemTime(SYSTEM_TIME_REALTIME);
+ mLastModificationTime = time;
+ if (mPropertyMap.size() >= kKeyMaxProperties &&
+ !mPropertyMap.count(property)) {
+ ALOGV("%s: too many properties, rejecting %s", __func__, property.c_str());
+ return;
+ }
+ auto& timeSequence = mPropertyMap[property];
+ Elem el{std::forward<T>(e)};
+ if (timeSequence.empty() // no elements
+ || property.back() == AMEDIAMETRICS_PROP_SUFFIX_CHAR_DUPLICATES_ALLOWED
+ || timeSequence.rbegin()->second != el) { // value changed
+ timeSequence.emplace(time, std::move(el));
+
+ if (timeSequence.size() > kTimeSequenceMaxElements) {
+ ALOGV("%s: restricting maximum elements (discarding oldest) for %s",
+ __func__, property.c_str());
+ timeSequence.erase(timeSequence.begin());
+ }
+ }
+ }
+
+ std::pair<std::string, int32_t> dump(int32_t lines, int64_t time) const {
+ std::stringstream ss;
+ int32_t ll = lines;
+ for (auto& tsPair : mPropertyMap) {
+ if (ll <= 0) break;
+ ss << dump(mKey, tsPair, time);
+ --ll;
+ }
+ return { ss.str(), lines - ll };
+ }
+
+ int64_t getLastModificationTime() const { return mLastModificationTime; }
+
+ private:
+ static std::string dump(
+ const std::string &key,
+ const std::pair<std::string /* prop */, PropertyHistory>& tsPair,
+ int64_t time) {
+ const auto timeSequence = tsPair.second;
+ auto eptr = timeSequence.lower_bound(time);
+ if (eptr == timeSequence.end()) {
+ return tsPair.first + "={};\n";
+ }
+ std::stringstream ss;
+ ss << key << "." << tsPair.first << "={";
+
+ time_string_t last_timestring{}; // last timestring used.
+ while (true) {
+ const time_string_t timestring = mediametrics::timeStringFromNs(eptr->first);
+ // find common prefix offset.
+ const size_t offset = commonTimePrefixPosition(timestring.time,
+ last_timestring.time);
+ last_timestring = timestring;
+ ss << "(" << (offset == 0 ? "" : "~") << ×tring.time[offset]
+ << ") " << eptr->second;
+ if (++eptr == timeSequence.end()) {
+ break;
+ }
+ ss << ", ";
+ }
+ ss << "};\n";
+ return ss.str();
+ }
+
+ const std::string mKey;
+ const pid_t mPid __unused;
+ const uid_t mUid;
+ const int64_t mCreationTime __unused;
+
+ int64_t mLastModificationTime;
+ std::map<std::string /* property */, PropertyHistory> mPropertyMap;
+ };
+
+ using History = std::map<std::string /* key */, std::shared_ptr<KeyHistory>>;
+
+ static inline constexpr size_t kTimeSequenceMaxElements = 100;
+ static inline constexpr size_t kKeyMaxProperties = 100;
+ static inline constexpr size_t kKeyLowWaterMark = 500;
+ static inline constexpr size_t kKeyHighWaterMark = 1000;
+
+ // Estimated max data space usage is 3KB * kKeyHighWaterMark.
+
+public:
+
+ TimeMachine() = default;
+ TimeMachine(size_t keyLowWaterMark, size_t keyHighWaterMark)
+ : mKeyLowWaterMark(keyLowWaterMark)
+ , mKeyHighWaterMark(keyHighWaterMark) {
+ LOG_ALWAYS_FATAL_IF(keyHighWaterMark <= keyLowWaterMark,
+ "%s: required that keyHighWaterMark:%zu > keyLowWaterMark:%zu",
+ __func__, keyHighWaterMark, keyLowWaterMark);
+ }
+
+ // The TimeMachine copy constructor/assignment uses a deep copy,
+ // though the snapshot is not instantaneous nor isochronous.
+ //
+ // If there are concurrent operations ongoing in the other TimeMachine
+ // then there may be some history more recent than others (a time shear).
+ // This is expected to be a benign addition in history as small number of
+ // future elements are incorporated.
+ TimeMachine(const TimeMachine& other) {
+ *this = other;
+ }
+ TimeMachine& operator=(const TimeMachine& other) {
+ std::lock_guard lock(mLock);
+ mHistory.clear();
+
+ {
+ std::lock_guard lock2(other.mLock);
+ mHistory = other.mHistory;
+ }
+
+ // Now that we safely have our own shared pointers, let's dup them
+ // to ensure they are decoupled. We do this by acquiring the other lock.
+ for (const auto &[lkey, lhist] : mHistory) {
+ std::lock_guard lock2(other.getLockForKey(lkey));
+ mHistory[lkey] = std::make_shared<KeyHistory>(*lhist);
+ }
+ return *this;
+ }
+
+ /**
+ * Put all the properties from an item into the Time Machine log.
+ */
+ status_t put(const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted = false) {
+ const int64_t time = item->getTimestamp();
+ const std::string &key = item->getKey();
+
+ ALOGV("%s(%zu, %zu): key: %s isTrusted:%d size:%zu",
+ __func__, mKeyLowWaterMark, mKeyHighWaterMark,
+ key.c_str(), (int)isTrusted, item->count());
+ std::shared_ptr<KeyHistory> keyHistory;
+ {
+ std::vector<std::any> garbage;
+ std::lock_guard lock(mLock);
+
+ auto it = mHistory.find(key);
+ if (it == mHistory.end()) {
+ if (!isTrusted) return PERMISSION_DENIED;
+
+ (void)gc_l(garbage);
+
+ // no keylock needed here as we are sole owner
+ // until placed on mHistory.
+ keyHistory = std::make_shared<KeyHistory>(
+ key, item->getPid(), item->getUid(), time);
+ mHistory[key] = keyHistory;
+ } else {
+ keyHistory = it->second;
+ }
+ }
+
+ // deferred contains remote properties (for other keys) to do later.
+ std::vector<const mediametrics::Item::Prop *> deferred;
+ {
+ // handle local properties
+ std::lock_guard lock(getLockForKey(key));
+ if (!isTrusted) {
+ status_t status = keyHistory->checkPermission(item->getUid());
+ if (status != NO_ERROR) return status;
+ }
+
+ for (const auto &prop : *item) {
+ const std::string &name = prop.getName();
+ if (name.size() == 0 || name[0] == '_') continue;
+
+ // Cross key settings are with [key]property
+ if (name[0] == '[') {
+ if (!isTrusted) continue;
+ deferred.push_back(&prop);
+ } else {
+ keyHistory->putProp(name, prop, time);
+ }
+ }
+ }
+
+ // handle remote properties, if any
+ for (const auto propptr : deferred) {
+ const auto &prop = *propptr;
+ const std::string &name = prop.getName();
+ size_t end = name.find_first_of(']'); // TODO: handle nested [] or escape?
+ if (end == 0) continue;
+ std::string remoteKey = name.substr(1, end - 1);
+ std::string remoteName = name.substr(end + 1);
+ if (remoteKey.size() == 0 || remoteName.size() == 0) continue;
+ std::shared_ptr<KeyHistory> remoteKeyHistory;
+ {
+ std::lock_guard lock(mLock);
+ auto it = mHistory.find(remoteKey);
+ if (it == mHistory.end()) continue;
+ remoteKeyHistory = it->second;
+ }
+ std::lock_guard(getLockForKey(remoteKey));
+ remoteKeyHistory->putProp(remoteName, prop, time);
+ }
+ return NO_ERROR;
+ }
+
+ template <typename T>
+ status_t get(const std::string &key, const std::string &property,
+ T* value, int32_t uidCheck = -1, int64_t time = 0) const {
+ std::shared_ptr<KeyHistory> keyHistory;
+ {
+ std::lock_guard lock(mLock);
+ const auto it = mHistory.find(key);
+ if (it == mHistory.end()) return BAD_VALUE;
+ keyHistory = it->second;
+ }
+ std::lock_guard lock(getLockForKey(key));
+ return keyHistory->checkPermission(uidCheck)
+ ?: keyHistory->getValue(property, value, time);
+ }
+
+ /**
+ * Individual property put.
+ *
+ * Put takes in a time (if none is provided then SYSTEM_TIME_REALTIME is used).
+ */
+ template <typename T>
+ status_t put(const std::string &url, T &&e, int64_t time = 0) {
+ std::string key;
+ std::string prop;
+ std::shared_ptr<KeyHistory> keyHistory =
+ getKeyHistoryFromUrl(url, &key, &prop);
+ if (keyHistory == nullptr) return BAD_VALUE;
+ if (time == 0) time = systemTime(SYSTEM_TIME_REALTIME);
+ std::lock_guard lock(getLockForKey(key));
+ keyHistory->putValue(prop, std::forward<T>(e), time);
+ return NO_ERROR;
+ }
+
+ /**
+ * Individual property get
+ */
+ template <typename T>
+ status_t get(const std::string &url, T* value, int32_t uidCheck, int64_t time = 0) const {
+ std::string key;
+ std::string prop;
+ std::shared_ptr<KeyHistory> keyHistory =
+ getKeyHistoryFromUrl(url, &key, &prop);
+ if (keyHistory == nullptr) return BAD_VALUE;
+
+ std::lock_guard lock(getLockForKey(key));
+ return keyHistory->checkPermission(uidCheck)
+ ?: keyHistory->getValue(prop, value, time);
+ }
+
+ /**
+ * Individual property get with default
+ */
+ template <typename T>
+ T get(const std::string &url, const T &defaultValue, int32_t uidCheck,
+ int64_t time = 0) const {
+ T value;
+ return get(url, &value, uidCheck, time) == NO_ERROR
+ ? value : defaultValue;
+ }
+
+ /**
+ * Returns number of keys in the Time Machine.
+ */
+ size_t size() const {
+ std::lock_guard lock(mLock);
+ return mHistory.size();
+ }
+
+ /**
+ * Clears all properties from the Time Machine.
+ */
+ void clear() {
+ std::lock_guard lock(mLock);
+ mHistory.clear();
+ }
+
+ /**
+ * Returns a pair consisting of the TimeMachine state as a string
+ * and the number of lines in the string.
+ *
+ * The number of lines in the returned pair is used as an optimization
+ * for subsequent line limiting.
+ *
+ * \param lines the maximum number of lines in the string returned.
+ * \param key selects only that key.
+ * \param time to start the dump from.
+ */
+ std::pair<std::string, int32_t> dump(
+ int32_t lines = INT32_MAX, const std::string &key = {}, int64_t time = 0) const {
+ std::lock_guard lock(mLock);
+ if (!key.empty()) { // use std::regex
+ const auto it = mHistory.find(key);
+ if (it == mHistory.end()) return {};
+ std::lock_guard lock(getLockForKey(it->first));
+ return it->second->dump(lines, time);
+ }
+
+ std::stringstream ss;
+ int32_t ll = lines;
+ for (const auto &[lkey, lhist] : mHistory) {
+ std::lock_guard lock(getLockForKey(lkey));
+ if (lines <= 0) break;
+ auto [s, l] = lhist->dump(ll, time);
+ ss << s;
+ ll -= l;
+ }
+ return { ss.str(), lines - ll };
+ }
+
+private:
+
+ // Obtains the lock for a KeyHistory.
+ std::mutex &getLockForKey(const std::string &key) const {
+ return mKeyLocks[std::hash<std::string>{}(key) % std::size(mKeyLocks)];
+ }
+
+ // Finds a KeyHistory from a URL. Returns nullptr if not found.
+ std::shared_ptr<KeyHistory> getKeyHistoryFromUrl(
+ std::string url, std::string* key, std::string *prop) const {
+ std::lock_guard lock(mLock);
+
+ auto it = mHistory.upper_bound(url);
+ if (it == mHistory.begin()) {
+ return nullptr;
+ }
+ --it; // go to the actual key, if it exists.
+
+ const std::string& itKey = it->first;
+ if (strncmp(itKey.c_str(), url.c_str(), itKey.size())) {
+ return nullptr;
+ }
+ if (key) *key = itKey;
+ if (prop) *prop = url.substr(itKey.size() + 1);
+ return it->second;
+ }
+
+ // GUARDED_BY mLock
+ /**
+ * Garbage collects if the TimeMachine size exceeds the high water mark.
+ *
+ * This GC operation limits the number of keys stored (not the size of properties
+ * stored in each key).
+ *
+ * \param garbage a type-erased vector of elements to be destroyed
+ * outside of lock. Move large items to be destroyed here.
+ *
+ * \return true if garbage collection was done.
+ */
+ bool gc_l(std::vector<std::any>& garbage) {
+ // TODO: something better than this for garbage collection.
+ if (mHistory.size() < mKeyHighWaterMark) return false;
+
+ ALOGD("%s: garbage collection", __func__);
+
+ // erase everything explicitly expired.
+ std::multimap<int64_t, std::string> accessList;
+ // use a stale vector with precise type to avoid type erasure overhead in garbage
+ std::vector<std::shared_ptr<KeyHistory>> stale;
+
+ for (auto it = mHistory.begin(); it != mHistory.end();) {
+ const std::string& key = it->first;
+ std::shared_ptr<KeyHistory> &keyHist = it->second;
+
+ std::lock_guard lock(getLockForKey(it->first));
+ int64_t expireTime = keyHist->getValue("_expire", -1 /* default */);
+ if (expireTime != -1) {
+ stale.emplace_back(std::move(it->second));
+ it = mHistory.erase(it);
+ } else {
+ accessList.emplace(keyHist->getLastModificationTime(), key);
+ ++it;
+ }
+ }
+
+ if (mHistory.size() > mKeyLowWaterMark) {
+ const size_t toDelete = mHistory.size() - mKeyLowWaterMark;
+ auto it = accessList.begin();
+ for (size_t i = 0; i < toDelete; ++i) {
+ auto it2 = mHistory.find(it->second);
+ stale.emplace_back(std::move(it2->second));
+ mHistory.erase(it2);
+ ++it;
+ }
+ }
+ garbage.emplace_back(std::move(accessList));
+ garbage.emplace_back(std::move(stale));
+
+ ALOGD("%s(%zu, %zu): key size:%zu",
+ __func__, mKeyLowWaterMark, mKeyHighWaterMark,
+ mHistory.size());
+ return true;
+ }
+
+ const size_t mKeyLowWaterMark = kKeyLowWaterMark;
+ const size_t mKeyHighWaterMark = kKeyHighWaterMark;
+
+ /**
+ * Locking Strategy
+ *
+ * Each key in the History has a KeyHistory. To get a shared pointer to
+ * the KeyHistory requires a lookup of mHistory under mLock. Once the shared
+ * pointer to KeyHistory is obtained, the mLock for mHistory can be released.
+ *
+ * Once the shared pointer to the key's KeyHistory is obtained, the KeyHistory
+ * can be locked for read and modification through the method getLockForKey().
+ *
+ * Instead of having a mutex per KeyHistory, we use a hash striped lock
+ * which assigns a mutex based on the hash of the key string.
+ *
+ * Once the last shared pointer reference to KeyHistory is released, it is
+ * destroyed. This is done through the garbage collection method.
+ *
+ * This two level locking allows multiple threads to access the TimeMachine
+ * in parallel.
+ */
+
+ mutable std::mutex mLock; // Lock for mHistory
+ History mHistory; // GUARDED_BY mLock
+
+ // KEY_LOCKS is the number of mutexes for keys.
+ // It need not be a power of 2, but faster that way.
+ static inline constexpr size_t KEY_LOCKS = 256;
+ mutable std::mutex mKeyLocks[KEY_LOCKS]; // Hash-striped lock for KeyHistory based on key.
+};
+
+} // namespace android::mediametrics
diff --git a/services/mediametrics/TransactionLog.h b/services/mediametrics/TransactionLog.h
new file mode 100644
index 0000000..190a99e
--- /dev/null
+++ b/services/mediametrics/TransactionLog.h
@@ -0,0 +1,279 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <any>
+#include <map>
+#include <sstream>
+#include <string>
+
+#include <media/MediaMetricsItem.h>
+
+namespace android::mediametrics {
+
+/**
+ * The TransactionLog is used to record mediametrics::Items to present
+ * different views on the time information (selected by audio, and sorted by key).
+ *
+ * The TransactionLog will always present data in timestamp order. (Perhaps we
+ * just make this submit order).
+ *
+ * These Views have a cost in shared pointer storage, so they aren't quite free.
+ *
+ * The TransactionLog is NOT thread safe.
+ */
+class TransactionLog final { // made final as we have copy constructor instead of dup() override.
+public:
+ // In long term run, the garbage collector aims to keep the
+ // Transaction Log between the Low Water Mark and the High Water Mark.
+
+ // low water mark
+ static inline constexpr size_t kLogItemsLowWater = 5000;
+ // high water mark
+ static inline constexpr size_t kLogItemsHighWater = 10000;
+
+ // Estimated max data usage is 1KB * kLogItemsHighWater.
+
+ TransactionLog() = default;
+
+ TransactionLog(size_t lowWaterMark, size_t highWaterMark)
+ : mLowWaterMark(lowWaterMark)
+ , mHighWaterMark(highWaterMark) {
+ LOG_ALWAYS_FATAL_IF(highWaterMark <= lowWaterMark,
+ "%s: required that highWaterMark:%zu > lowWaterMark:%zu",
+ __func__, highWaterMark, lowWaterMark);
+ }
+
+ // The TransactionLog copy constructor/assignment is effectively an
+ // instantaneous, isochronous snapshot of the other TransactionLog.
+ //
+ // The contents of the Transaction Log are shared pointers to immutable instances -
+ // std::shared_ptr<const mediametrics::Item>, so we use a shallow copy,
+ // which is more efficient in space and execution time than a deep copy,
+ // and gives the same results.
+
+ TransactionLog(const TransactionLog &other) {
+ *this = other;
+ }
+
+ TransactionLog& operator=(const TransactionLog &other) {
+ std::lock_guard lock(mLock);
+ mLog.clear();
+ mItemMap.clear();
+
+ std::lock_guard lock2(other.mLock);
+ mLog = other.mLog;
+ mItemMap = other.mItemMap;
+
+ return *this;
+ }
+
+ /**
+ * Put an item in the TransactionLog.
+ */
+ status_t put(const std::shared_ptr<const mediametrics::Item>& item) {
+ const std::string& key = item->getKey();
+ const int64_t time = item->getTimestamp();
+
+ std::vector<std::any> garbage; // objects destroyed after lock.
+ std::lock_guard lock(mLock);
+
+ (void)gc_l(garbage);
+ mLog.emplace(time, item);
+ mItemMap[key].emplace(time, item);
+ return NO_ERROR; // no errors for now.
+ }
+
+ /**
+ * Returns all records within [startTime, endTime]
+ */
+ std::vector<std::shared_ptr<const mediametrics::Item>> get(
+ int64_t startTime = 0, int64_t endTime = INT64_MAX) const {
+ std::lock_guard lock(mLock);
+ return getItemsInRange_l(mLog, startTime, endTime);
+ }
+
+ /**
+ * Returns all records for a key within [startTime, endTime]
+ */
+ std::vector<std::shared_ptr<const mediametrics::Item>> get(
+ const std::string& key,
+ int64_t startTime = 0, int64_t endTime = INT64_MAX) const {
+ std::lock_guard lock(mLock);
+ auto mapIt = mItemMap.find(key);
+ if (mapIt == mItemMap.end()) return {};
+ return getItemsInRange_l(mapIt->second, startTime, endTime);
+ }
+
+ /**
+ * Returns a pair consisting of the Transaction Log as a string
+ * and the number of lines in the string.
+ *
+ * The number of lines in the returned pair is used as an optimization
+ * for subsequent line limiting.
+ *
+ * \param lines the maximum number of lines in the string returned.
+ */
+ std::pair<std::string, int32_t> dump(int32_t lines) const {
+ std::stringstream ss;
+ int32_t ll = lines;
+ std::lock_guard lock(mLock);
+
+ // All audio items in time order.
+ if (ll > 0) {
+ ss << "Consolidated:\n";
+ --ll;
+ }
+ for (const auto &log : mLog) {
+ if (ll <= 0) break;
+ ss << " " << log.second->toString() << "\n";
+ --ll;
+ }
+
+ // Grouped by item key (category)
+ if (ll > 0) {
+ ss << "Categorized:\n";
+ --ll;
+ }
+ for (const auto &itemMap : mItemMap) {
+ if (ll <= 0) break;
+ ss << " " << itemMap.first << "\n";
+ --ll;
+ for (const auto &item : itemMap.second) {
+ if (ll <= 0) break;
+ ss << " " << item.second->toString() << "\n";
+ --ll;
+ }
+ }
+ return { ss.str(), lines - ll };
+ }
+
+ /**
+ * Returns number of Items in the TransactionLog.
+ */
+ size_t size() const {
+ std::lock_guard lock(mLock);
+ return mLog.size();
+ }
+
+ /**
+ * Clears all Items from the TransactionLog.
+ */
+ // TODO: Garbage Collector, sweep and expire old values
+ void clear() {
+ std::lock_guard lock(mLock);
+ mLog.clear();
+ mItemMap.clear();
+ }
+
+private:
+ using MapTimeItem =
+ std::multimap<int64_t /* time */, std::shared_ptr<const mediametrics::Item>>;
+
+ // GUARDED_BY mLock
+ /**
+ * Garbage collects if the TimeMachine size exceeds the high water mark.
+ *
+ * \param garbage a type-erased vector of elements to be destroyed
+ * outside of lock. Move large items to be destroyed here.
+ *
+ * \return true if garbage collection was done.
+ */
+ bool gc_l(std::vector<std::any>& garbage) {
+ if (mLog.size() < mHighWaterMark) return false;
+
+ ALOGD("%s: garbage collection", __func__);
+
+ auto eraseEnd = mLog.begin();
+ size_t toRemove = mLog.size() - mLowWaterMark;
+ // remove at least those elements.
+
+ // use a stale vector with precise type to avoid type erasure overhead in garbage
+ std::vector<std::shared_ptr<const mediametrics::Item>> stale;
+
+ for (size_t i = 0; i < toRemove; ++i) {
+ stale.emplace_back(std::move(eraseEnd->second));
+ ++eraseEnd; // amortized O(1)
+ }
+ // ensure that eraseEnd is an lower bound on timeToErase.
+ const int64_t timeToErase = eraseEnd->first;
+ while (eraseEnd != mLog.end()) {
+ auto it = eraseEnd;
+ --it; // amortized O(1)
+ if (it->first != timeToErase) {
+ break; // eraseEnd represents a unique time jump.
+ }
+ stale.emplace_back(std::move(eraseEnd->second));
+ ++eraseEnd;
+ }
+
+ mLog.erase(mLog.begin(), eraseEnd); // O(ptr_diff)
+
+ size_t itemMapCount = 0;
+ for (auto it = mItemMap.begin(); it != mItemMap.end();) {
+ auto &keyHist = it->second;
+ auto it2 = keyHist.lower_bound(timeToErase);
+ if (it2 == keyHist.end()) {
+ garbage.emplace_back(std::move(keyHist)); // directly move keyhist to garbage
+ it = mItemMap.erase(it);
+ } else {
+ for (auto it3 = keyHist.begin(); it3 != it2; ++it3) {
+ stale.emplace_back(std::move(it3->second));
+ }
+ keyHist.erase(keyHist.begin(), it2);
+ itemMapCount += keyHist.size();
+ ++it;
+ }
+ }
+
+ garbage.emplace_back(std::move(stale));
+
+ ALOGD("%s(%zu, %zu): log size:%zu item map size:%zu, item map items:%zu",
+ __func__, mLowWaterMark, mHighWaterMark,
+ mLog.size(), mItemMap.size(), itemMapCount);
+ return true;
+ }
+
+ static std::vector<std::shared_ptr<const mediametrics::Item>> getItemsInRange_l(
+ const MapTimeItem& map,
+ int64_t startTime = 0, int64_t endTime = INT64_MAX) {
+ auto it = map.lower_bound(startTime);
+ if (it == map.end()) return {};
+
+ auto it2 = map.upper_bound(endTime);
+
+ std::vector<std::shared_ptr<const mediametrics::Item>> ret;
+ while (it != it2) {
+ ret.push_back(it->second);
+ ++it;
+ }
+ return ret;
+ }
+
+ const size_t mLowWaterMark = kLogItemsLowWater;
+ const size_t mHighWaterMark = kLogItemsHighWater;
+
+ mutable std::mutex mLock;
+
+ // GUARDED_BY mLock
+ MapTimeItem mLog;
+
+ // GUARDED_BY mLock
+ std::map<std::string /* item_key */, MapTimeItem> mItemMap;
+};
+
+} // namespace android::mediametrics
diff --git a/services/mediametrics/Wrap.h b/services/mediametrics/Wrap.h
new file mode 100644
index 0000000..3584e08
--- /dev/null
+++ b/services/mediametrics/Wrap.h
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <memory>
+#include <mutex>
+
+namespace android::mediametrics {
+
+/**
+ * Wraps a shared-ptr for which member access through operator->() behaves
+ * as if the shared-ptr is atomically copied and then (without a lock) -> called.
+ *
+ * See related C++ 20:
+ * https://en.cppreference.com/w/cpp/memory/shared_ptr/atomic2
+ *
+ * EXAMPLE:
+ *
+ * SharedPtrWrap<T> t{};
+ *
+ * thread1() {
+ * t->func(); // safely executes either the original t or the one created by thread2.
+ * }
+ *
+ * thread2() {
+ * t.set(std::make_shared<T>()); // overwrites the original t.
+ * }
+ */
+template <typename T>
+class SharedPtrWrap {
+ mutable std::mutex mLock;
+ std::shared_ptr<T> mPtr;
+
+public:
+ template <typename... Args>
+ explicit SharedPtrWrap(Args&&... args)
+ : mPtr(std::make_shared<T>(std::forward<Args>(args)...))
+ {}
+
+ /**
+ * Gets the current shared pointer. This must return a value, not a reference.
+ *
+ * For compatibility with existing shared_ptr, we do not pass back a
+ * shared_ptr<const T> for the const getter.
+ */
+ std::shared_ptr<T> get() const {
+ std::lock_guard lock(mLock);
+ return mPtr;
+ }
+
+ /**
+ * Sets the current shared pointer, returning the previous shared pointer.
+ */
+ std::shared_ptr<T> set(std::shared_ptr<T> ptr) { // pass by value as we use swap.
+ std::lock_guard lock(mLock);
+ std::swap(ptr, mPtr);
+ return ptr;
+ }
+
+ /**
+ * Returns a shared pointer value representing T at the instant of time when
+ * the call executes. The lifetime of the shared pointer will
+ * be extended as we are returning an instance of the shared_ptr
+ * not a reference to it. The destructor to the returned shared_ptr
+ * will be called sometime after the expression including the member function or
+ * the member variable is evaluated. Do not change to a reference!
+ */
+
+ // For compatibility with existing shared_ptr, we do not pass back a
+ // shared_ptr<const T> for the const operator pointer access.
+ std::shared_ptr<T> operator->() const {
+ return get();
+ }
+ /**
+ * We do not overload operator*() as the reference is not stable if the
+ * lock is not held.
+ */
+};
+
+/**
+ * Wraps member access to the class T by a lock.
+ *
+ * The object T is constructed within the LockWrap to guarantee
+ * locked access at all times. When T's methods are accessed through ->,
+ * a monitor style lock is obtained to prevent multiple threads from executing
+ * methods in the object T at the same time.
+ * Suggested by Kevin R.
+ *
+ * EXAMPLE:
+ *
+ * // Accumulator class which is very slow, requires locking for multiple threads.
+ *
+ * class Accumulator {
+ * int32_t value_ = 0;
+ * public:
+ * void add(int32_t incr) {
+ * const int32_t temp = value_;
+ * sleep(0); // yield
+ * value_ = temp + incr;
+ * }
+ * int32_t get() { return value_; }
+ * };
+ *
+ * // We use LockWrap on Accumulator to have safe multithread access.
+ * android::mediametrics::LockWrap<Accumulator> a{}; // locked accumulator succeeds
+ *
+ * // Conversely, the following line fails:
+ * // auto a = std::make_shared<Accumulator>(); // this fails, only 50% adds atomic.
+ *
+ * constexpr size_t THREADS = 100;
+ * constexpr size_t ITERATIONS = 10;
+ * constexpr int32_t INCREMENT = 1;
+ *
+ * // Test by generating multiple threads, all adding simultaneously.
+ * std::vector<std::future<void>> threads(THREADS);
+ * for (size_t i = 0; i < THREADS; ++i) {
+ * threads.push_back(std::async(std::launch::async, [&] {
+ * for (size_t j = 0; j < ITERATIONS; ++j) {
+ * a->add(INCREMENT); // add needs locked access here.
+ * }
+ * }));
+ * }
+ * threads.clear();
+ *
+ * // If the add operations are not atomic, value will be smaller than expected.
+ * ASSERT_EQ(INCREMENT * THREADS * ITERATIONS, (size_t)a->get());
+ *
+ */
+template <typename T>
+class LockWrap {
+ /**
+ * Holding class that keeps the pointer and the lock.
+ *
+ * We return this holding class from operator->() to keep the lock until the
+ * method function or method variable access is completed.
+ */
+ class LockedPointer {
+ friend LockWrap;
+ LockedPointer(T *t, std::recursive_mutex *lock, std::atomic<size_t> *recursionDepth)
+ : mT(t), mLock(*lock), mRecursionDepth(recursionDepth) { ++*mRecursionDepth; }
+
+ T* const mT;
+ std::lock_guard<std::recursive_mutex> mLock;
+ std::atomic<size_t>* mRecursionDepth;
+ public:
+ ~LockedPointer() {
+ --*mRecursionDepth; // Used for testing, we do not check underflow.
+ }
+
+ const T* operator->() const {
+ return mT;
+ }
+ T* operator->() {
+ return mT;
+ }
+ };
+
+ // We must use a recursive mutex because the end of the full expression may
+ // involve another reference to T->.
+ //
+ // A recursive mutex allows the same thread to recursively acquire,
+ // but different thread would block.
+ //
+ // Example which fails with a normal mutex:
+ //
+ // android::mediametrics::LockWrap<std::vector<int>> v{std::initializer_list<int>{1, 2}};
+ // const int sum = v->operator[](0) + v->operator[](1);
+ //
+ mutable std::recursive_mutex mLock;
+ mutable T mT;
+ mutable std::atomic<size_t> mRecursionDepth{}; // Used for testing.
+
+public:
+ template <typename... Args>
+ explicit LockWrap(Args&&... args) : mT(std::forward<Args>(args)...) {}
+
+ const LockedPointer operator->() const {
+ return LockedPointer(&mT, &mLock, &mRecursionDepth);
+ }
+ LockedPointer operator->() {
+ return LockedPointer(&mT, &mLock, &mRecursionDepth);
+ }
+
+ // Returns the lock depth of the recursive mutex.
+ // @TestApi
+ size_t getRecursionDepth() const {
+ return mRecursionDepth;
+ }
+};
+
+} // namespace android::mediametrics
diff --git a/services/mediametrics/benchmarks/Android.bp b/services/mediametrics/benchmarks/Android.bp
new file mode 100644
index 0000000..b61f44f
--- /dev/null
+++ b/services/mediametrics/benchmarks/Android.bp
@@ -0,0 +1,6 @@
+cc_test {
+ name: "mediametrics_benchmarks",
+ srcs: ["mediametrics_benchmarks.cpp"],
+ shared_libs: ["libbinder", "libmediametrics",],
+ static_libs: ["libgoogle-benchmark"],
+}
diff --git a/services/mediametrics/benchmarks/README.md b/services/mediametrics/benchmarks/README.md
new file mode 100644
index 0000000..7cf767b
--- /dev/null
+++ b/services/mediametrics/benchmarks/README.md
@@ -0,0 +1,4 @@
+This benchmark may fail occasionally, probably due to the binder queue being full.
+If that happens, just re-run it and it will usually work eventually.
+
+adb shell /data/nativetest64/media\_metrics/media\_metrics
diff --git a/services/mediametrics/benchmarks/mediametrics_benchmarks.cpp b/services/mediametrics/benchmarks/mediametrics_benchmarks.cpp
new file mode 100644
index 0000000..f434867
--- /dev/null
+++ b/services/mediametrics/benchmarks/mediametrics_benchmarks.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <media/MediaMetricsItem.h>
+#include <benchmark/benchmark.h>
+
+class MyItem : public android::mediametrics::BaseItem {
+public:
+ static bool mySubmitBuffer() {
+ // Deliberately lame so that we're measuring just the cost to deliver things to the service.
+ return submitBuffer("", 0);
+ }
+};
+
+static void BM_SubmitBuffer(benchmark::State& state)
+{
+ while (state.KeepRunning()) {
+ MyItem myItem;
+ bool ok = myItem.mySubmitBuffer();
+ if (ok == false) {
+ // submitBuffer() currently uses one-way binder IPC, which provides unreliable delivery
+ // with at-most-one guarantee.
+ // It is expected that the call may occasionally fail if the one-way queue is full.
+ // The Iterations magic number below was tuned to reduce, but not eliminate, failures.
+ state.SkipWithError("failed");
+ return;
+ }
+ benchmark::ClobberMemory();
+ }
+}
+
+BENCHMARK(BM_SubmitBuffer)->Iterations(4000); // Adjust magic number until test runs
+
+BENCHMARK_MAIN();
diff --git a/services/mediametrics/iface_statsd.cpp b/services/mediametrics/iface_statsd.cpp
new file mode 100644
index 0000000..3a1eea7
--- /dev/null
+++ b/services/mediametrics/iface_statsd.cpp
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "iface_statsd"
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <dirent.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include <memory>
+#include <string.h>
+#include <pwd.h>
+
+#include "MediaMetricsService.h"
+#include "iface_statsd.h"
+
+#include <statslog.h>
+
+namespace android {
+
+// set of routines that crack a mediametrics::Item
+// and send it off to statsd with the appropriate hooks
+//
+// each mediametrics::Item type (extractor, codec, nuplayer, etc)
+// has its own routine to handle this.
+//
+
+bool enabled_statsd = true;
+
+struct statsd_hooks {
+ const char *key;
+ bool (*handler)(const mediametrics::Item *);
+};
+
+// keep this sorted, so we can do binary searches
+static constexpr struct statsd_hooks statsd_handlers[] =
+{
+ { "audiopolicy", statsd_audiopolicy },
+ { "audiorecord", statsd_audiorecord },
+ { "audiothread", statsd_audiothread },
+ { "audiotrack", statsd_audiotrack },
+ { "codec", statsd_codec},
+ { "drm.vendor.Google.WidevineCDM", statsd_widevineCDM },
+ { "drmmanager", statsd_drmmanager },
+ { "extractor", statsd_extractor },
+ { "mediadrm", statsd_mediadrm },
+ { "nuplayer", statsd_nuplayer },
+ { "nuplayer2", statsd_nuplayer },
+ { "recorder", statsd_recorder },
+};
+
+// give me a record, i'll look at the type and upload appropriately
+bool dump2Statsd(const std::shared_ptr<const mediametrics::Item>& item) {
+ if (item == NULL) return false;
+
+ // get the key
+ std::string key = item->getKey();
+
+ if (!enabled_statsd) {
+ ALOGV("statsd logging disabled for record key=%s", key.c_str());
+ return false;
+ }
+
+ for (const auto &statsd_handler : statsd_handlers) {
+ if (key == statsd_handler.key) {
+ return statsd_handler.handler(item.get());
+ }
+ }
+ return false;
+}
+
+} // namespace android
diff --git a/services/mediametrics/iface_statsd.h b/services/mediametrics/iface_statsd.h
new file mode 100644
index 0000000..19505a4
--- /dev/null
+++ b/services/mediametrics/iface_statsd.h
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+namespace android {
+
+extern bool enabled_statsd;
+
+// component specific dumpers
+extern bool statsd_audiopolicy(const mediametrics::Item *);
+extern bool statsd_audiorecord(const mediametrics::Item *);
+extern bool statsd_audiothread(const mediametrics::Item *);
+extern bool statsd_audiotrack(const mediametrics::Item *);
+extern bool statsd_codec(const mediametrics::Item *);
+extern bool statsd_extractor(const mediametrics::Item *);
+extern bool statsd_nuplayer(const mediametrics::Item *);
+extern bool statsd_recorder(const mediametrics::Item *);
+
+extern bool statsd_mediadrm(const mediametrics::Item *);
+extern bool statsd_widevineCDM(const mediametrics::Item *);
+extern bool statsd_drmmanager(const mediametrics::Item *);
+
+} // namespace android
diff --git a/services/mediametrics/main_mediametrics.cpp b/services/mediametrics/main_mediametrics.cpp
new file mode 100644
index 0000000..ec392e2
--- /dev/null
+++ b/services/mediametrics/main_mediametrics.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "mediametrics"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include "MediaMetricsService.h"
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+
+int main(int argc __unused, char **argv __unused)
+{
+ using namespace android;
+
+ signal(SIGPIPE, SIG_IGN);
+
+ // to match the service name
+ // we're replacing "/system/bin/mediametrics" with "media.metrics"
+ // we add a ".", but discard the path components: we finish with a shorter string
+ strcpy(argv[0], MediaMetricsService::kServiceName);
+
+ defaultServiceManager()->addService(
+ String16(MediaMetricsService::kServiceName), new MediaMetricsService());
+
+ sp<ProcessState> processState(ProcessState::self());
+ // processState->setThreadPoolMaxThreadCount(8);
+ processState->startThreadPool();
+ IPCThreadState::self()->joinThreadPool();
+
+ return EXIT_SUCCESS;
+}
diff --git a/services/mediaanalytics/mediametrics.rc b/services/mediametrics/mediametrics.rc
similarity index 100%
rename from services/mediaanalytics/mediametrics.rc
rename to services/mediametrics/mediametrics.rc
diff --git a/services/mediametrics/statsd_audiopolicy.cpp b/services/mediametrics/statsd_audiopolicy.cpp
new file mode 100644
index 0000000..634c801
--- /dev/null
+++ b/services/mediametrics/statsd_audiopolicy.cpp
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "statsd_audiopolicy"
+#include <utils/Log.h>
+
+#include <dirent.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <pwd.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <statslog.h>
+
+#include "MediaMetricsService.h"
+#include "frameworks/base/core/proto/android/stats/mediametrics/mediametrics.pb.h"
+#include "iface_statsd.h"
+
+namespace android {
+
+bool statsd_audiopolicy(const mediametrics::Item *item)
+{
+ if (item == NULL) return false;
+
+ // these go into the statsd wrapper
+ const nsecs_t timestamp = MediaMetricsService::roundTime(item->getTimestamp());
+ std::string pkgName = item->getPkgName();
+ int64_t pkgVersionCode = item->getPkgVersionCode();
+ int64_t mediaApexVersion = 0;
+
+
+ // the rest into our own proto
+ //
+ ::android::stats::mediametrics::AudioPolicyData metrics_proto;
+
+ // flesh out the protobuf we'll hand off with our data
+ //
+ //int32 char kAudioPolicyStatus[] = "android.media.audiopolicy.status";
+ int32_t status = -1;
+ if (item->getInt32("android.media.audiopolicy.status", &status)) {
+ metrics_proto.set_status(status);
+ }
+ //string char kAudioPolicyRqstSrc[] = "android.media.audiopolicy.rqst.src";
+ std::string rqst_src;
+ if (item->getString("android.media.audiopolicy.rqst.src", &rqst_src)) {
+ metrics_proto.set_request_source(std::move(rqst_src));
+ }
+ //string char kAudioPolicyRqstPkg[] = "android.media.audiopolicy.rqst.pkg";
+ std::string rqst_pkg;
+ if (item->getString("android.media.audiopolicy.rqst.pkg", &rqst_pkg)) {
+ metrics_proto.set_request_package(std::move(rqst_pkg));
+ }
+ //int32 char kAudioPolicyRqstSession[] = "android.media.audiopolicy.rqst.session";
+ int32_t rqst_session = -1;
+ if (item->getInt32("android.media.audiopolicy.rqst.session", &rqst_session)) {
+ metrics_proto.set_request_session(rqst_session);
+ }
+ //string char kAudioPolicyRqstDevice[] = "android.media.audiopolicy.rqst.device";
+ std::string rqst_device;
+ if (item->getString("android.media.audiopolicy.rqst.device", &rqst_device)) {
+ metrics_proto.set_request_device(std::move(rqst_device));
+ }
+
+ //string char kAudioPolicyActiveSrc[] = "android.media.audiopolicy.active.src";
+ std::string active_src;
+ if (item->getString("android.media.audiopolicy.active.src", &active_src)) {
+ metrics_proto.set_active_source(std::move(active_src));
+ }
+ //string char kAudioPolicyActivePkg[] = "android.media.audiopolicy.active.pkg";
+ std::string active_pkg;
+ if (item->getString("android.media.audiopolicy.active.pkg", &active_pkg)) {
+ metrics_proto.set_active_package(std::move(active_pkg));
+ }
+ //int32 char kAudioPolicyActiveSession[] = "android.media.audiopolicy.active.session";
+ int32_t active_session = -1;
+ if (item->getInt32("android.media.audiopolicy.active.session", &active_session)) {
+ metrics_proto.set_active_session(active_session);
+ }
+ //string char kAudioPolicyActiveDevice[] = "android.media.audiopolicy.active.device";
+ std::string active_device;
+ if (item->getString("android.media.audiopolicy.active.device", &active_device)) {
+ metrics_proto.set_active_device(std::move(active_device));
+ }
+
+
+ std::string serialized;
+ if (!metrics_proto.SerializeToString(&serialized)) {
+ ALOGE("Failed to serialize audipolicy metrics");
+ return false;
+ }
+
+ if (enabled_statsd) {
+ android::util::BytesField bf_serialized( serialized.c_str(), serialized.size());
+ (void)android::util::stats_write(android::util::MEDIAMETRICS_AUDIOPOLICY_REPORTED,
+ timestamp, pkgName.c_str(), pkgVersionCode,
+ mediaApexVersion,
+ bf_serialized);
+
+ } else {
+ ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
+ }
+
+ return true;
+}
+
+};
diff --git a/services/mediametrics/statsd_audiorecord.cpp b/services/mediametrics/statsd_audiorecord.cpp
new file mode 100644
index 0000000..69d1661
--- /dev/null
+++ b/services/mediametrics/statsd_audiorecord.cpp
@@ -0,0 +1,158 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "statsd_audiorecord"
+#include <utils/Log.h>
+
+#include <dirent.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <pwd.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <statslog.h>
+
+#include "MediaMetricsService.h"
+#include "frameworks/base/core/proto/android/stats/mediametrics/mediametrics.pb.h"
+#include "iface_statsd.h"
+
+namespace android {
+
+bool statsd_audiorecord(const mediametrics::Item *item)
+{
+ if (item == NULL) return false;
+
+ // these go into the statsd wrapper
+ const nsecs_t timestamp = MediaMetricsService::roundTime(item->getTimestamp());
+ std::string pkgName = item->getPkgName();
+ int64_t pkgVersionCode = item->getPkgVersionCode();
+ int64_t mediaApexVersion = 0;
+
+
+ // the rest into our own proto
+ //
+ ::android::stats::mediametrics::AudioRecordData metrics_proto;
+
+ // flesh out the protobuf we'll hand off with our data
+ //
+ std::string encoding;
+ if (item->getString("android.media.audiorecord.encoding", &encoding)) {
+ metrics_proto.set_encoding(std::move(encoding));
+ }
+
+ std::string source;
+ if (item->getString("android.media.audiorecord.source", &source)) {
+ metrics_proto.set_source(std::move(source));
+ }
+
+ int32_t latency = -1;
+ if (item->getInt32("android.media.audiorecord.latency", &latency)) {
+ metrics_proto.set_latency(latency);
+ }
+
+ int32_t samplerate = -1;
+ if (item->getInt32("android.media.audiorecord.samplerate", &samplerate)) {
+ metrics_proto.set_samplerate(samplerate);
+ }
+
+ int32_t channels = -1;
+ if (item->getInt32("android.media.audiorecord.channels", &channels)) {
+ metrics_proto.set_channels(channels);
+ }
+
+ int64_t createdMs = -1;
+ if (item->getInt64("android.media.audiorecord.createdMs", &createdMs)) {
+ metrics_proto.set_created_millis(createdMs);
+ }
+
+ int64_t durationMs = -1;
+ if (item->getInt64("android.media.audiorecord.durationMs", &durationMs)) {
+ metrics_proto.set_duration_millis(durationMs);
+ }
+
+ int32_t count = -1;
+ if (item->getInt32("android.media.audiorecord.n", &count)) {
+ metrics_proto.set_count(count);
+ }
+
+ int32_t errcode = -1;
+ if (item->getInt32("android.media.audiorecord.errcode", &errcode)) {
+ metrics_proto.set_error_code(errcode);
+ } else if (item->getInt32("android.media.audiorecord.lastError.code", &errcode)) {
+ metrics_proto.set_error_code(errcode);
+ }
+
+ std::string errfunc;
+ if (item->getString("android.media.audiorecord.errfunc", &errfunc)) {
+ metrics_proto.set_error_function(std::move(errfunc));
+ } else if (item->getString("android.media.audiorecord.lastError.at", &errfunc)) {
+ metrics_proto.set_error_function(std::move(errfunc));
+ }
+
+ // portId (int32)
+ int32_t port_id = -1;
+ if (item->getInt32("android.media.audiorecord.portId", &port_id)) {
+ metrics_proto.set_port_id(count);
+ }
+ // frameCount (int32)
+ int32_t frameCount = -1;
+ if (item->getInt32("android.media.audiorecord.frameCount", &frameCount)) {
+ metrics_proto.set_frame_count(frameCount);
+ }
+ // attributes (string)
+ std::string attributes;
+ if (item->getString("android.media.audiorecord.attributes", &attributes)) {
+ metrics_proto.set_attributes(std::move(attributes));
+ }
+ // channelMask (int64)
+ int64_t channelMask = -1;
+ if (item->getInt64("android.media.audiorecord.channelMask", &channelMask)) {
+ metrics_proto.set_channel_mask(channelMask);
+ }
+ // startcount (int64)
+ int64_t startcount = -1;
+ if (item->getInt64("android.media.audiorecord.startcount", &startcount)) {
+ metrics_proto.set_start_count(startcount);
+ }
+
+
+ std::string serialized;
+ if (!metrics_proto.SerializeToString(&serialized)) {
+ ALOGE("Failed to serialize audiorecord metrics");
+ return false;
+ }
+
+ if (enabled_statsd) {
+ android::util::BytesField bf_serialized( serialized.c_str(), serialized.size());
+ (void)android::util::stats_write(android::util::MEDIAMETRICS_AUDIORECORD_REPORTED,
+ timestamp, pkgName.c_str(), pkgVersionCode,
+ mediaApexVersion,
+ bf_serialized);
+
+ } else {
+ ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
+ }
+
+ return true;
+}
+
+};
diff --git a/services/mediametrics/statsd_audiothread.cpp b/services/mediametrics/statsd_audiothread.cpp
new file mode 100644
index 0000000..300151b
--- /dev/null
+++ b/services/mediametrics/statsd_audiothread.cpp
@@ -0,0 +1,207 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "statsd_audiothread"
+#include <utils/Log.h>
+
+#include <dirent.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <pwd.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <statslog.h>
+
+#include "MediaMetricsService.h"
+#include "frameworks/base/core/proto/android/stats/mediametrics/mediametrics.pb.h"
+#include "iface_statsd.h"
+
+namespace android {
+
+bool statsd_audiothread(const mediametrics::Item *item)
+{
+ if (item == NULL) return false;
+
+ // these go into the statsd wrapper
+ const nsecs_t timestamp = MediaMetricsService::roundTime(item->getTimestamp());
+ std::string pkgName = item->getPkgName();
+ int64_t pkgVersionCode = item->getPkgVersionCode();
+ int64_t mediaApexVersion = 0;
+
+
+ // the rest into our own proto
+ //
+ ::android::stats::mediametrics::AudioThreadData metrics_proto;
+
+#define MM_PREFIX "android.media.audiothread."
+
+ // flesh out the protobuf we'll hand off with our data
+ //
+ std::string mytype;
+ if (item->getString(MM_PREFIX "type", &mytype)) {
+ metrics_proto.set_type(std::move(mytype));
+ }
+ int32_t framecount = -1;
+ if (item->getInt32(MM_PREFIX "framecount", &framecount)) {
+ metrics_proto.set_framecount(framecount);
+ }
+ int32_t samplerate = -1;
+ if (item->getInt32(MM_PREFIX "samplerate", &samplerate)) {
+ metrics_proto.set_samplerate(samplerate);
+ }
+ std::string workhist;
+ if (item->getString(MM_PREFIX "workMs.hist", &workhist)) {
+ metrics_proto.set_work_millis_hist(std::move(workhist));
+ }
+ std::string latencyhist;
+ if (item->getString(MM_PREFIX "latencyMs.hist", &latencyhist)) {
+ metrics_proto.set_latency_millis_hist(std::move(latencyhist));
+ }
+ std::string warmuphist;
+ if (item->getString(MM_PREFIX "warmupMs.hist", &warmuphist)) {
+ metrics_proto.set_warmup_millis_hist(std::move(warmuphist));
+ }
+ int64_t underruns = -1;
+ if (item->getInt64(MM_PREFIX "underruns", &underruns)) {
+ metrics_proto.set_underruns(underruns);
+ }
+ int64_t overruns = -1;
+ if (item->getInt64(MM_PREFIX "overruns", &overruns)) {
+ metrics_proto.set_overruns(overruns);
+ }
+ int64_t activeMs = -1;
+ if (item->getInt64(MM_PREFIX "activeMs", &activeMs)) {
+ metrics_proto.set_active_millis(activeMs);
+ }
+ int64_t durationMs = -1;
+ if (item->getInt64(MM_PREFIX "durationMs", &durationMs)) {
+ metrics_proto.set_duration_millis(durationMs);
+ }
+
+ // item->setInt32(MM_PREFIX "id", (int32_t)mId); // IO handle
+ int32_t id = -1;
+ if (item->getInt32(MM_PREFIX "id", &id)) {
+ metrics_proto.set_id(id);
+ }
+ // item->setInt32(MM_PREFIX "portId", (int32_t)mPortId);
+ int32_t port_id = -1;
+ if (item->getInt32(MM_PREFIX "portId", &id)) {
+ metrics_proto.set_port_id(port_id);
+ }
+ // item->setCString(MM_PREFIX "type", threadTypeToString(mType));
+ std::string type;
+ if (item->getString(MM_PREFIX "type", &type)) {
+ metrics_proto.set_type(std::move(type));
+ }
+ // item->setInt32(MM_PREFIX "sampleRate", (int32_t)mSampleRate);
+ int32_t sample_rate = -1;
+ if (item->getInt32(MM_PREFIX "sampleRate", &sample_rate)) {
+ metrics_proto.set_sample_rate(sample_rate);
+ }
+ // item->setInt64(MM_PREFIX "channelMask", (int64_t)mChannelMask);
+ int32_t channel_mask = -1;
+ if (item->getInt32(MM_PREFIX "channelMask", &channel_mask)) {
+ metrics_proto.set_channel_mask(channel_mask);
+ }
+ // item->setCString(MM_PREFIX "encoding", toString(mFormat).c_str());
+ std::string encoding;
+ if (item->getString(MM_PREFIX "encoding", &encoding)) {
+ metrics_proto.set_encoding(std::move(encoding));
+ }
+ // item->setInt32(MM_PREFIX "frameCount", (int32_t)mFrameCount);
+ int32_t frame_count = -1;
+ if (item->getInt32(MM_PREFIX "frameCount", &frame_count)) {
+ metrics_proto.set_frame_count(frame_count);
+ }
+ // item->setCString(MM_PREFIX "outDevice", toString(mOutDevice).c_str());
+ std::string outDevice;
+ if (item->getString(MM_PREFIX "outDevice", &outDevice)) {
+ metrics_proto.set_output_device(std::move(outDevice));
+ }
+ // item->setCString(MM_PREFIX "inDevice", toString(mInDevice).c_str());
+ std::string inDevice;
+ if (item->getString(MM_PREFIX "inDevice", &inDevice)) {
+ metrics_proto.set_input_device(std::move(inDevice));
+ }
+ // item->setDouble(MM_PREFIX "ioJitterMs.mean", mIoJitterMs.getMean());
+ double iojitters_ms_mean = -1;
+ if (item->getDouble(MM_PREFIX "ioJitterMs.mean", &iojitters_ms_mean)) {
+ metrics_proto.set_io_jitter_mean_millis(iojitters_ms_mean);
+ }
+ // item->setDouble(MM_PREFIX "ioJitterMs.std", mIoJitterMs.getStdDev());
+ double iojitters_ms_std = -1;
+ if (item->getDouble(MM_PREFIX "ioJitterMs.std", &iojitters_ms_std)) {
+ metrics_proto.set_io_jitter_stddev_millis(iojitters_ms_std);
+ }
+ // item->setDouble(MM_PREFIX "processTimeMs.mean", mProcessTimeMs.getMean());
+ double process_time_ms_mean = -1;
+ if (item->getDouble(MM_PREFIX "processTimeMs.mean", &process_time_ms_mean)) {
+ metrics_proto.set_process_time_mean_millis(process_time_ms_mean);
+ }
+ // item->setDouble(MM_PREFIX "processTimeMs.std", mProcessTimeMs.getStdDev());
+ double process_time_ms_std = -1;
+ if (item->getDouble(MM_PREFIX "processTimeMs.std", &process_time_ms_std)) {
+ metrics_proto.set_process_time_stddev_millis(process_time_ms_std);
+ }
+ // item->setDouble(MM_PREFIX "timestampJitterMs.mean", tsjitter.getMean());
+ double timestamp_jitter_ms_mean = -1;
+ if (item->getDouble(MM_PREFIX "timestampJitterMs.mean", ×tamp_jitter_ms_mean)) {
+ metrics_proto.set_timestamp_jitter_mean_millis(timestamp_jitter_ms_mean);
+ }
+ // item->setDouble(MM_PREFIX "timestampJitterMs.std", tsjitter.getStdDev());
+ double timestamp_jitter_ms_stddev = -1;
+ if (item->getDouble(MM_PREFIX "timestampJitterMs.std", ×tamp_jitter_ms_stddev)) {
+ metrics_proto.set_timestamp_jitter_stddev_millis(timestamp_jitter_ms_stddev);
+ }
+ // item->setDouble(MM_PREFIX "latencyMs.mean", mLatencyMs.getMean());
+ double latency_ms_mean = -1;
+ if (item->getDouble(MM_PREFIX "latencyMs.mean", &latency_ms_mean)) {
+ metrics_proto.set_latency_mean_millis(latency_ms_mean);
+ }
+ // item->setDouble(MM_PREFIX "latencyMs.std", mLatencyMs.getStdDev());
+ double latency_ms_stddev = -1;
+ if (item->getDouble(MM_PREFIX "latencyMs.std", &latency_ms_stddev)) {
+ metrics_proto.set_latency_stddev_millis(latency_ms_stddev);
+ }
+
+
+ std::string serialized;
+ if (!metrics_proto.SerializeToString(&serialized)) {
+ ALOGE("Failed to serialize audiothread metrics");
+ return false;
+ }
+
+ if (enabled_statsd) {
+ android::util::BytesField bf_serialized( serialized.c_str(), serialized.size());
+ (void)android::util::stats_write(android::util::MEDIAMETRICS_AUDIOTHREAD_REPORTED,
+ timestamp, pkgName.c_str(), pkgVersionCode,
+ mediaApexVersion,
+ bf_serialized);
+
+ } else {
+ ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
+ }
+
+ return true;
+}
+
+};
diff --git a/services/mediametrics/statsd_audiotrack.cpp b/services/mediametrics/statsd_audiotrack.cpp
new file mode 100644
index 0000000..397cdf3
--- /dev/null
+++ b/services/mediametrics/statsd_audiotrack.cpp
@@ -0,0 +1,149 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "statsd_audiotrack"
+#include <utils/Log.h>
+
+#include <dirent.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <pwd.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <statslog.h>
+
+#include "MediaMetricsService.h"
+#include "frameworks/base/core/proto/android/stats/mediametrics/mediametrics.pb.h"
+#include "iface_statsd.h"
+
+namespace android {
+
+bool statsd_audiotrack(const mediametrics::Item *item)
+{
+ if (item == NULL) return false;
+
+ // these go into the statsd wrapper
+ const nsecs_t timestamp = MediaMetricsService::roundTime(item->getTimestamp());
+ std::string pkgName = item->getPkgName();
+ int64_t pkgVersionCode = item->getPkgVersionCode();
+ int64_t mediaApexVersion = 0;
+
+
+ // the rest into our own proto
+ //
+ ::android::stats::mediametrics::AudioTrackData metrics_proto;
+
+ // flesh out the protobuf we'll hand off with our data
+ //
+
+ // static constexpr char kAudioTrackStreamType[] = "android.media.audiotrack.streamtype";
+ // optional string streamType;
+ std::string streamtype;
+ if (item->getString("android.media.audiotrack.streamtype", &streamtype)) {
+ metrics_proto.set_stream_type(std::move(streamtype));
+ }
+
+ // static constexpr char kAudioTrackContentType[] = "android.media.audiotrack.type";
+ // optional string contentType;
+ std::string contenttype;
+ if (item->getString("android.media.audiotrack.type", &contenttype)) {
+ metrics_proto.set_content_type(std::move(contenttype));
+ }
+
+ // static constexpr char kAudioTrackUsage[] = "android.media.audiotrack.usage";
+ // optional string trackUsage;
+ std::string trackusage;
+ if (item->getString("android.media.audiotrack.usage", &trackusage)) {
+ metrics_proto.set_track_usage(std::move(trackusage));
+ }
+
+ // static constexpr char kAudioTrackSampleRate[] = "android.media.audiotrack.samplerate";
+ // optional int32 samplerate;
+ int32_t samplerate = -1;
+ if (item->getInt32("android.media.audiotrack.samplerate", &samplerate)) {
+ metrics_proto.set_sample_rate(samplerate);
+ }
+
+ // static constexpr char kAudioTrackChannelMask[] = "android.media.audiotrack.channelmask";
+ // optional int64 channelMask;
+ int64_t channelMask = -1;
+ if (item->getInt64("android.media.audiotrack.channelmask", &channelMask)) {
+ metrics_proto.set_channel_mask(channelMask);
+ }
+
+ // NB: These are not yet exposed as public Java API constants.
+ // static constexpr char kAudioTrackUnderrunFrames[] = "android.media.audiotrack.underrunframes";
+ // optional int32 underrunframes;
+ int32_t underrunframes = -1;
+ if (item->getInt32("android.media.audiotrack.underrunframes", &underrunframes)) {
+ metrics_proto.set_underrun_frames(underrunframes);
+ }
+
+ // static constexpr char kAudioTrackStartupGlitch[] = "android.media.audiotrack.glitch.startup";
+ // optional int32 startupglitch;
+ int32_t startupglitch = -1;
+ if (item->getInt32("android.media.audiotrack.glitch.startup", &startupglitch)) {
+ metrics_proto.set_startup_glitch(startupglitch);
+ }
+
+ // portId (int32)
+ int32_t port_id = -1;
+ if (item->getInt32("android.media.audiotrack.portId", &port_id)) {
+ metrics_proto.set_port_id(port_id);
+ }
+ // encoding (string)
+ std::string encoding;
+ if (item->getString("android.media.audiotrack.encoding", &encoding)) {
+ metrics_proto.set_encoding(std::move(encoding));
+ }
+ // frameCount (int32)
+ int32_t frame_count = -1;
+ if (item->getInt32("android.media.audiotrack.frameCount", &frame_count)) {
+ metrics_proto.set_frame_count(frame_count);
+ }
+ // attributes (string)
+ std::string attributes;
+ if (item->getString("android.media.audiotrack.attributes", &attributes)) {
+ metrics_proto.set_attributes(std::move(attributes));
+ }
+
+ std::string serialized;
+ if (!metrics_proto.SerializeToString(&serialized)) {
+ ALOGE("Failed to serialize audiotrack metrics");
+ return false;
+ }
+
+ if (enabled_statsd) {
+ android::util::BytesField bf_serialized( serialized.c_str(), serialized.size());
+ (void)android::util::stats_write(android::util::MEDIAMETRICS_AUDIOTRACK_REPORTED,
+ timestamp, pkgName.c_str(), pkgVersionCode,
+ mediaApexVersion,
+ bf_serialized);
+
+ } else {
+ ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
+ }
+
+ return true;
+}
+
+};
diff --git a/services/mediametrics/statsd_codec.cpp b/services/mediametrics/statsd_codec.cpp
new file mode 100644
index 0000000..f5fa57e
--- /dev/null
+++ b/services/mediametrics/statsd_codec.cpp
@@ -0,0 +1,191 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "statsd_codec"
+#include <utils/Log.h>
+
+#include <dirent.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <pwd.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <statslog.h>
+
+#include "MediaMetricsService.h"
+#include "frameworks/base/core/proto/android/stats/mediametrics/mediametrics.pb.h"
+#include "iface_statsd.h"
+
+namespace android {
+
+bool statsd_codec(const mediametrics::Item *item)
+{
+ if (item == NULL) return false;
+
+ // these go into the statsd wrapper
+ const nsecs_t timestamp = MediaMetricsService::roundTime(item->getTimestamp());
+ std::string pkgName = item->getPkgName();
+ int64_t pkgVersionCode = item->getPkgVersionCode();
+ int64_t mediaApexVersion = 0;
+
+
+ // the rest into our own proto
+ //
+ ::android::stats::mediametrics::CodecData metrics_proto;
+
+ // flesh out the protobuf we'll hand off with our data
+ //
+ // android.media.mediacodec.codec string
+ std::string codec;
+ if (item->getString("android.media.mediacodec.codec", &codec)) {
+ metrics_proto.set_codec(std::move(codec));
+ }
+ // android.media.mediacodec.mime string
+ std::string mime;
+ if (item->getString("android.media.mediacodec.mime", &mime)) {
+ metrics_proto.set_mime(std::move(mime));
+ }
+ // android.media.mediacodec.mode string
+ std::string mode;
+ if ( item->getString("android.media.mediacodec.mode", &mode)) {
+ metrics_proto.set_mode(std::move(mode));
+ }
+ // android.media.mediacodec.encoder int32
+ int32_t encoder = -1;
+ if ( item->getInt32("android.media.mediacodec.encoder", &encoder)) {
+ metrics_proto.set_encoder(encoder);
+ }
+ // android.media.mediacodec.secure int32
+ int32_t secure = -1;
+ if ( item->getInt32("android.media.mediacodec.secure", &secure)) {
+ metrics_proto.set_secure(secure);
+ }
+ // android.media.mediacodec.width int32
+ int32_t width = -1;
+ if ( item->getInt32("android.media.mediacodec.width", &width)) {
+ metrics_proto.set_width(width);
+ }
+ // android.media.mediacodec.height int32
+ int32_t height = -1;
+ if ( item->getInt32("android.media.mediacodec.height", &height)) {
+ metrics_proto.set_height(height);
+ }
+ // android.media.mediacodec.rotation-degrees int32
+ int32_t rotation = -1;
+ if ( item->getInt32("android.media.mediacodec.rotation-degrees", &rotation)) {
+ metrics_proto.set_rotation(rotation);
+ }
+ // 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);
+ }
+ // android.media.mediacodec.profile int32
+ int32_t profile = -1;
+ if ( item->getInt32("android.media.mediacodec.profile", &profile)) {
+ metrics_proto.set_profile(profile);
+ }
+ // android.media.mediacodec.level int32
+ int32_t level = -1;
+ if ( item->getInt32("android.media.mediacodec.level", &level)) {
+ metrics_proto.set_level(level);
+ }
+ // android.media.mediacodec.maxwidth int32
+ int32_t maxwidth = -1;
+ if ( item->getInt32("android.media.mediacodec.maxwidth", &maxwidth)) {
+ metrics_proto.set_max_width(maxwidth);
+ }
+ // android.media.mediacodec.maxheight int32
+ int32_t maxheight = -1;
+ if ( item->getInt32("android.media.mediacodec.maxheight", &maxheight)) {
+ metrics_proto.set_max_height(maxheight);
+ }
+ // android.media.mediacodec.errcode int32
+ int32_t errcode = -1;
+ if ( item->getInt32("android.media.mediacodec.errcode", &errcode)) {
+ metrics_proto.set_error_code(errcode);
+ }
+ // android.media.mediacodec.errstate string
+ std::string errstate;
+ if ( item->getString("android.media.mediacodec.errstate", &errstate)) {
+ metrics_proto.set_error_state(std::move(errstate));
+ }
+ // android.media.mediacodec.latency.max int64
+ int64_t latency_max = -1;
+ if ( item->getInt64("android.media.mediacodec.latency.max", &latency_max)) {
+ metrics_proto.set_latency_max(latency_max);
+ }
+ // android.media.mediacodec.latency.min int64
+ int64_t latency_min = -1;
+ if ( item->getInt64("android.media.mediacodec.latency.min", &latency_min)) {
+ metrics_proto.set_latency_min(latency_min);
+ }
+ // android.media.mediacodec.latency.avg int64
+ int64_t latency_avg = -1;
+ if ( item->getInt64("android.media.mediacodec.latency.avg", &latency_avg)) {
+ metrics_proto.set_latency_avg(latency_avg);
+ }
+ // android.media.mediacodec.latency.n int64
+ int64_t latency_count = -1;
+ if ( item->getInt64("android.media.mediacodec.latency.n", &latency_count)) {
+ metrics_proto.set_latency_count(latency_count);
+ }
+ // android.media.mediacodec.latency.unknown int64
+ int64_t latency_unknown = -1;
+ if ( item->getInt64("android.media.mediacodec.latency.unknown", &latency_unknown)) {
+ metrics_proto.set_latency_unknown(latency_unknown);
+ }
+ // android.media.mediacodec.queueSecureInputBufferError int32
+ if (int32_t queueSecureInputBufferError = -1;
+ item->getInt32("android.media.mediacodec.queueSecureInputBufferError",
+ &queueSecureInputBufferError)) {
+ metrics_proto.set_queue_secure_input_buffer_error(queueSecureInputBufferError);
+ }
+ // android.media.mediacodec.queueInputBufferError int32
+ if (int32_t queueInputBufferError = -1;
+ item->getInt32("android.media.mediacodec.queueInputBufferError",
+ &queueInputBufferError)) {
+ metrics_proto.set_queue_input_buffer_error(queueInputBufferError);
+ }
+ // android.media.mediacodec.latency.hist NOT EMITTED
+
+ std::string serialized;
+ if (!metrics_proto.SerializeToString(&serialized)) {
+ ALOGE("Failed to serialize codec metrics");
+ return false;
+ }
+
+ if (enabled_statsd) {
+ android::util::BytesField bf_serialized( serialized.c_str(), serialized.size());
+ (void)android::util::stats_write(android::util::MEDIAMETRICS_CODEC_REPORTED,
+ timestamp, pkgName.c_str(), pkgVersionCode,
+ mediaApexVersion,
+ bf_serialized);
+
+ } else {
+ ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
+ }
+
+ return true;
+}
+
+};
diff --git a/services/mediametrics/statsd_drm.cpp b/services/mediametrics/statsd_drm.cpp
new file mode 100644
index 0000000..4f2e861
--- /dev/null
+++ b/services/mediametrics/statsd_drm.cpp
@@ -0,0 +1,156 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "statsd_drm"
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <dirent.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include <string.h>
+#include <pwd.h>
+
+#include "MediaMetricsService.h"
+#include "iface_statsd.h"
+
+#include <statslog.h>
+
+#include <array>
+#include <string>
+
+namespace android {
+
+// mediadrm
+bool statsd_mediadrm(const mediametrics::Item *item)
+{
+ if (item == NULL) return false;
+
+ const nsecs_t timestamp = MediaMetricsService::roundTime(item->getTimestamp());
+ std::string pkgName = item->getPkgName();
+ int64_t pkgVersionCode = item->getPkgVersionCode();
+ int64_t mediaApexVersion = 0;
+
+ char *vendor = NULL;
+ (void) item->getCString("vendor", &vendor);
+ char *description = NULL;
+ (void) item->getCString("description", &description);
+ char *serialized_metrics = NULL;
+ (void) item->getCString("serialized_metrics", &serialized_metrics);
+
+ if (enabled_statsd) {
+ android::util::BytesField bf_serialized(serialized_metrics ? serialized_metrics : NULL,
+ serialized_metrics ? strlen(serialized_metrics)
+ : 0);
+ android::util::stats_write(android::util::MEDIAMETRICS_MEDIADRM_REPORTED,
+ timestamp, pkgName.c_str(), pkgVersionCode,
+ mediaApexVersion,
+ vendor, description,
+ bf_serialized);
+ } else {
+ ALOGV("NOT sending: mediadrm private data (len=%zu)",
+ serialized_metrics ? strlen(serialized_metrics) : 0);
+ }
+
+ free(vendor);
+ free(description);
+ free(serialized_metrics);
+ return true;
+}
+
+// widevineCDM
+bool statsd_widevineCDM(const mediametrics::Item *item)
+{
+ if (item == NULL) return false;
+
+ const nsecs_t timestamp = MediaMetricsService::roundTime(item->getTimestamp());
+ std::string pkgName = item->getPkgName();
+ int64_t pkgVersionCode = item->getPkgVersionCode();
+ int64_t mediaApexVersion = 0;
+
+ char *serialized_metrics = NULL;
+ (void) item->getCString("serialized_metrics", &serialized_metrics);
+
+ if (enabled_statsd) {
+ android::util::BytesField bf_serialized(serialized_metrics ? serialized_metrics : NULL,
+ serialized_metrics ? strlen(serialized_metrics)
+ : 0);
+ android::util::stats_write(android::util::MEDIAMETRICS_DRM_WIDEVINE_REPORTED,
+ timestamp, pkgName.c_str(), pkgVersionCode,
+ mediaApexVersion,
+ bf_serialized);
+ } else {
+ ALOGV("NOT sending: widevine private data (len=%zu)",
+ serialized_metrics ? strlen(serialized_metrics) : 0);
+ }
+
+ free(serialized_metrics);
+ return true;
+}
+
+// drmmanager
+bool statsd_drmmanager(const mediametrics::Item *item)
+{
+ using namespace std::string_literals;
+ if (item == NULL) return false;
+
+ if (!enabled_statsd) {
+ ALOGV("NOT sending: drmmanager data");
+ return true;
+ }
+
+ const nsecs_t timestamp = MediaMetricsService::roundTime(item->getTimestamp());
+ std::string pkgName = item->getPkgName();
+ int64_t pkgVersionCode = item->getPkgVersionCode();
+ int64_t mediaApexVersion = 0;
+
+ char *plugin_id = NULL;
+ (void) item->getCString("plugin_id", &plugin_id);
+ char *description = NULL;
+ (void) item->getCString("description", &description);
+ int32_t method_id = -1;
+ (void) item->getInt32("method_id", &method_id);
+ char *mime_types = NULL;
+ (void) item->getCString("mime_types", &mime_types);
+
+ // Corresponds to the 13 APIs tracked in the MediametricsDrmManagerReported statsd proto
+ // Please see also DrmManager::kMethodIdMap
+ std::array<int64_t, 13> methodCounts{};
+ for (size_t i = 0; i < methodCounts.size() ; i++) {
+ item->getInt64(("method"s + std::to_string(i)).c_str(), &methodCounts[i]);
+ }
+
+ android::util::stats_write(android::util::MEDIAMETRICS_DRMMANAGER_REPORTED,
+ timestamp, pkgName.c_str(), pkgVersionCode, mediaApexVersion,
+ plugin_id, description, method_id, mime_types,
+ methodCounts[0], methodCounts[1], methodCounts[2],
+ methodCounts[3], methodCounts[4], methodCounts[5],
+ methodCounts[6], methodCounts[7], methodCounts[8],
+ methodCounts[9], methodCounts[10], methodCounts[11],
+ methodCounts[12]);
+
+ free(plugin_id);
+ free(description);
+ free(mime_types);
+ return true;
+}
+} // namespace android
diff --git a/services/mediametrics/statsd_extractor.cpp b/services/mediametrics/statsd_extractor.cpp
new file mode 100644
index 0000000..8574358
--- /dev/null
+++ b/services/mediametrics/statsd_extractor.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "statsd_extractor"
+#include <utils/Log.h>
+
+#include <dirent.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <pwd.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <statslog.h>
+
+#include "MediaMetricsService.h"
+#include "frameworks/base/core/proto/android/stats/mediametrics/mediametrics.pb.h"
+#include "iface_statsd.h"
+
+namespace android {
+
+bool statsd_extractor(const mediametrics::Item *item)
+{
+ if (item == NULL) return false;
+
+ // these go into the statsd wrapper
+ const nsecs_t timestamp = MediaMetricsService::roundTime(item->getTimestamp());
+ std::string pkgName = item->getPkgName();
+ int64_t pkgVersionCode = item->getPkgVersionCode();
+ int64_t mediaApexVersion = 0;
+
+
+ // the rest into our own proto
+ //
+ ::android::stats::mediametrics::ExtractorData metrics_proto;
+
+ // flesh out the protobuf we'll hand off with our data
+ //
+
+ // android.media.mediaextractor.fmt string
+ std::string fmt;
+ if (item->getString("android.media.mediaextractor.fmt", &fmt)) {
+ metrics_proto.set_format(std::move(fmt));
+ }
+ // android.media.mediaextractor.mime string
+ std::string mime;
+ if (item->getString("android.media.mediaextractor.mime", &mime)) {
+ metrics_proto.set_mime(std::move(mime));
+ }
+ // android.media.mediaextractor.ntrk int32
+ int32_t ntrk = -1;
+ if (item->getInt32("android.media.mediaextractor.ntrk", &ntrk)) {
+ metrics_proto.set_tracks(ntrk);
+ }
+
+ std::string serialized;
+ if (!metrics_proto.SerializeToString(&serialized)) {
+ ALOGE("Failed to serialize extractor metrics");
+ return false;
+ }
+
+ if (enabled_statsd) {
+ android::util::BytesField bf_serialized( serialized.c_str(), serialized.size());
+ (void)android::util::stats_write(android::util::MEDIAMETRICS_EXTRACTOR_REPORTED,
+ timestamp, pkgName.c_str(), pkgVersionCode,
+ mediaApexVersion,
+ bf_serialized);
+
+ } else {
+ ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
+ }
+
+ return true;
+}
+
+};
diff --git a/services/mediametrics/statsd_nuplayer.cpp b/services/mediametrics/statsd_nuplayer.cpp
new file mode 100644
index 0000000..df7e59f
--- /dev/null
+++ b/services/mediametrics/statsd_nuplayer.cpp
@@ -0,0 +1,170 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "statsd_nuplayer"
+#include <utils/Log.h>
+
+#include <dirent.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <pwd.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <statslog.h>
+
+#include "MediaMetricsService.h"
+#include "frameworks/base/core/proto/android/stats/mediametrics/mediametrics.pb.h"
+#include "iface_statsd.h"
+
+namespace android {
+
+/*
+ * handles nuplayer AND nuplayer2
+ * checks for the union of what the two players generate
+ */
+bool statsd_nuplayer(const mediametrics::Item *item)
+{
+ if (item == NULL) return false;
+
+ // these go into the statsd wrapper
+ const nsecs_t timestamp = MediaMetricsService::roundTime(item->getTimestamp());
+ std::string pkgName = item->getPkgName();
+ int64_t pkgVersionCode = item->getPkgVersionCode();
+ int64_t mediaApexVersion = 0;
+
+
+ // the rest into our own proto
+ //
+ ::android::stats::mediametrics::NuPlayerData metrics_proto;
+
+ // flesh out the protobuf we'll hand off with our data
+ //
+
+ // differentiate between nuplayer and nuplayer2
+ metrics_proto.set_whichplayer(item->getKey().c_str());
+
+ std::string video_mime;
+ if (item->getString("android.media.mediaplayer.video.mime", &video_mime)) {
+ metrics_proto.set_video_mime(std::move(video_mime));
+ }
+ std::string video_codec;
+ if (item->getString("android.media.mediaplayer.video.codec", &video_codec)) {
+ metrics_proto.set_video_codec(std::move(video_codec));
+ }
+
+ int32_t width = -1;
+ if (item->getInt32("android.media.mediaplayer.width", &width)) {
+ metrics_proto.set_width(width);
+ }
+ int32_t height = -1;
+ if (item->getInt32("android.media.mediaplayer.height", &height)) {
+ metrics_proto.set_height(height);
+ }
+
+ int64_t frames = -1;
+ if (item->getInt64("android.media.mediaplayer.frames", &frames)) {
+ metrics_proto.set_frames(frames);
+ }
+ int64_t frames_dropped = -1;
+ if (item->getInt64("android.media.mediaplayer.dropped", &frames_dropped)) {
+ metrics_proto.set_frames_dropped(frames_dropped);
+ }
+ int64_t frames_dropped_startup = -1;
+ if (item->getInt64("android.media.mediaplayer.startupdropped", &frames_dropped_startup)) {
+ metrics_proto.set_frames_dropped_startup(frames_dropped_startup);
+ }
+ double fps = -1.0;
+ if (item->getDouble("android.media.mediaplayer.fps", &fps)) {
+ metrics_proto.set_framerate(fps);
+ }
+
+ std::string audio_mime;
+ if (item->getString("android.media.mediaplayer.audio.mime", &audio_mime)) {
+ metrics_proto.set_audio_mime(std::move(audio_mime));
+ }
+ std::string audio_codec;
+ if (item->getString("android.media.mediaplayer.audio.codec", &audio_codec)) {
+ metrics_proto.set_audio_codec(std::move(audio_codec));
+ }
+
+ int64_t duration_ms = -1;
+ if (item->getInt64("android.media.mediaplayer.durationMs", &duration_ms)) {
+ metrics_proto.set_duration_millis(duration_ms);
+ }
+ int64_t playing_ms = -1;
+ if (item->getInt64("android.media.mediaplayer.playingMs", &playing_ms)) {
+ metrics_proto.set_playing_millis(playing_ms);
+ }
+
+ int32_t err = -1;
+ if (item->getInt32("android.media.mediaplayer.err", &err)) {
+ metrics_proto.set_error(err);
+ }
+ int32_t error_code = -1;
+ if (item->getInt32("android.media.mediaplayer.errcode", &error_code)) {
+ metrics_proto.set_error_code(error_code);
+ }
+ std::string error_state;
+ if (item->getString("android.media.mediaplayer.errstate", &error_state)) {
+ metrics_proto.set_error_state(std::move(error_state));
+ }
+
+ std::string data_source_type;
+ if (item->getString("android.media.mediaplayer.dataSource", &data_source_type)) {
+ metrics_proto.set_data_source_type(std::move(data_source_type));
+ }
+
+ int64_t rebufferingMs = -1;
+ if (item->getInt64("android.media.mediaplayer.rebufferingMs", &rebufferingMs)) {
+ metrics_proto.set_rebuffering_millis(rebufferingMs);
+ }
+ int32_t rebuffers = -1;
+ if (item->getInt32("android.media.mediaplayer.rebuffers", &rebuffers)) {
+ metrics_proto.set_rebuffers(rebuffers);
+ }
+ int32_t rebufferExit = -1;
+ if (item->getInt32("android.media.mediaplayer.rebufferExit", &rebufferExit)) {
+ metrics_proto.set_rebuffer_at_exit(rebufferExit);
+ }
+
+
+ std::string serialized;
+ if (!metrics_proto.SerializeToString(&serialized)) {
+ ALOGE("Failed to serialize nuplayer metrics");
+ return false;
+ }
+
+ if (enabled_statsd) {
+ android::util::BytesField bf_serialized( serialized.c_str(), serialized.size());
+ (void)android::util::stats_write(android::util::MEDIAMETRICS_NUPLAYER_REPORTED,
+ timestamp, pkgName.c_str(), pkgVersionCode,
+ mediaApexVersion,
+ bf_serialized);
+
+ } else {
+ ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
+ }
+
+ return true;
+}
+
+};
diff --git a/services/mediametrics/statsd_recorder.cpp b/services/mediametrics/statsd_recorder.cpp
new file mode 100644
index 0000000..4de1746
--- /dev/null
+++ b/services/mediametrics/statsd_recorder.cpp
@@ -0,0 +1,189 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "statsd_recorder"
+#include <utils/Log.h>
+
+#include <dirent.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <pwd.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <statslog.h>
+
+#include "MediaMetricsService.h"
+#include "frameworks/base/core/proto/android/stats/mediametrics/mediametrics.pb.h"
+#include "iface_statsd.h"
+
+namespace android {
+
+bool statsd_recorder(const mediametrics::Item *item)
+{
+ if (item == NULL) return false;
+
+ // these go into the statsd wrapper
+ const nsecs_t timestamp = MediaMetricsService::roundTime(item->getTimestamp());
+ std::string pkgName = item->getPkgName();
+ int64_t pkgVersionCode = item->getPkgVersionCode();
+ int64_t mediaApexVersion = 0;
+
+
+ // the rest into our own proto
+ //
+ ::android::stats::mediametrics::RecorderData metrics_proto;
+
+ // flesh out the protobuf we'll hand off with our data
+ //
+
+ // string kRecorderAudioMime = "android.media.mediarecorder.audio.mime";
+ std::string audio_mime;
+ if (item->getString("android.media.mediarecorder.audio.mime", &audio_mime)) {
+ metrics_proto.set_audio_mime(std::move(audio_mime));
+ }
+ // string kRecorderVideoMime = "android.media.mediarecorder.video.mime";
+ std::string video_mime;
+ if (item->getString("android.media.mediarecorder.video.mime", &video_mime)) {
+ metrics_proto.set_video_mime(std::move(video_mime));
+ }
+ // int32 kRecorderVideoProfile = "android.media.mediarecorder.video-encoder-profile";
+ int32_t videoProfile = -1;
+ if (item->getInt32("android.media.mediarecorder.video-encoder-profile", &videoProfile)) {
+ metrics_proto.set_video_profile(videoProfile);
+ }
+ // int32 kRecorderVideoLevel = "android.media.mediarecorder.video-encoder-level";
+ int32_t videoLevel = -1;
+ if (item->getInt32("android.media.mediarecorder.video-encoder-level", &videoLevel)) {
+ metrics_proto.set_video_level(videoLevel);
+ }
+ // int32 kRecorderWidth = "android.media.mediarecorder.width";
+ int32_t width = -1;
+ if (item->getInt32("android.media.mediarecorder.width", &width)) {
+ metrics_proto.set_width(width);
+ }
+ // int32 kRecorderHeight = "android.media.mediarecorder.height";
+ int32_t height = -1;
+ if (item->getInt32("android.media.mediarecorder.height", &height)) {
+ metrics_proto.set_height(height);
+ }
+ // int32 kRecorderRotation = "android.media.mediarecorder.rotation";
+ int32_t rotation = -1; // default to 0?
+ if (item->getInt32("android.media.mediarecorder.rotation", &rotation)) {
+ metrics_proto.set_rotation(rotation);
+ }
+ // int32 kRecorderFrameRate = "android.media.mediarecorder.frame-rate";
+ int32_t framerate = -1;
+ if (item->getInt32("android.media.mediarecorder.frame-rate", &framerate)) {
+ metrics_proto.set_framerate(framerate);
+ }
+
+ // int32 kRecorderCaptureFps = "android.media.mediarecorder.capture-fps";
+ int32_t captureFps = -1;
+ if (item->getInt32("android.media.mediarecorder.capture-fps", &captureFps)) {
+ metrics_proto.set_capture_fps(captureFps);
+ }
+ // double kRecorderCaptureFpsEnable = "android.media.mediarecorder.capture-fpsenable";
+ double captureFpsEnable = -1;
+ if (item->getDouble("android.media.mediarecorder.capture-fpsenable", &captureFpsEnable)) {
+ metrics_proto.set_capture_fps_enable(captureFpsEnable);
+ }
+
+ // int64 kRecorderDurationMs = "android.media.mediarecorder.durationMs";
+ int64_t durationMs = -1;
+ if (item->getInt64("android.media.mediarecorder.durationMs", &durationMs)) {
+ metrics_proto.set_duration_millis(durationMs);
+ }
+ // int64 kRecorderPaused = "android.media.mediarecorder.pausedMs";
+ int64_t pausedMs = -1;
+ if (item->getInt64("android.media.mediarecorder.pausedMs", &pausedMs)) {
+ metrics_proto.set_paused_millis(pausedMs);
+ }
+ // int32 kRecorderNumPauses = "android.media.mediarecorder.NPauses";
+ int32_t pausedCount = -1;
+ if (item->getInt32("android.media.mediarecorder.NPauses", &pausedCount)) {
+ metrics_proto.set_paused_count(pausedCount);
+ }
+
+ // int32 kRecorderAudioBitrate = "android.media.mediarecorder.audio-bitrate";
+ int32_t audioBitrate = -1;
+ if (item->getInt32("android.media.mediarecorder.audio-bitrate", &audioBitrate)) {
+ metrics_proto.set_audio_bitrate(audioBitrate);
+ }
+ // int32 kRecorderAudioChannels = "android.media.mediarecorder.audio-channels";
+ int32_t audioChannels = -1;
+ if (item->getInt32("android.media.mediarecorder.audio-channels", &audioChannels)) {
+ metrics_proto.set_audio_channels(audioChannels);
+ }
+ // int32 kRecorderAudioSampleRate = "android.media.mediarecorder.audio-samplerate";
+ int32_t audioSampleRate = -1;
+ if (item->getInt32("android.media.mediarecorder.audio-samplerate", &audioSampleRate)) {
+ metrics_proto.set_audio_samplerate(audioSampleRate);
+ }
+
+ // int32 kRecorderMovieTimescale = "android.media.mediarecorder.movie-timescale";
+ int32_t movieTimescale = -1;
+ if (item->getInt32("android.media.mediarecorder.movie-timescale", &movieTimescale)) {
+ metrics_proto.set_movie_timescale(movieTimescale);
+ }
+ // int32 kRecorderAudioTimescale = "android.media.mediarecorder.audio-timescale";
+ int32_t audioTimescale = -1;
+ if (item->getInt32("android.media.mediarecorder.audio-timescale", &audioTimescale)) {
+ metrics_proto.set_audio_timescale(audioTimescale);
+ }
+ // int32 kRecorderVideoTimescale = "android.media.mediarecorder.video-timescale";
+ int32_t videoTimescale = -1;
+ if (item->getInt32("android.media.mediarecorder.video-timescale", &videoTimescale)) {
+ metrics_proto.set_video_timescale(videoTimescale);
+ }
+
+ // int32 kRecorderVideoBitrate = "android.media.mediarecorder.video-bitrate";
+ int32_t videoBitRate = -1;
+ if (item->getInt32("android.media.mediarecorder.video-bitrate", &videoBitRate)) {
+ metrics_proto.set_video_bitrate(videoBitRate);
+ }
+ // int32 kRecorderVideoIframeInterval = "android.media.mediarecorder.video-iframe-interval";
+ int32_t iFrameInterval = -1;
+ if (item->getInt32("android.media.mediarecorder.video-iframe-interval", &iFrameInterval)) {
+ metrics_proto.set_iframe_interval(iFrameInterval);
+ }
+
+ std::string serialized;
+ if (!metrics_proto.SerializeToString(&serialized)) {
+ ALOGE("Failed to serialize recorder metrics");
+ return false;
+ }
+
+ if (enabled_statsd) {
+ android::util::BytesField bf_serialized( serialized.c_str(), serialized.size());
+ (void)android::util::stats_write(android::util::MEDIAMETRICS_RECORDER_REPORTED,
+ timestamp, pkgName.c_str(), pkgVersionCode,
+ mediaApexVersion,
+ bf_serialized);
+
+ } else {
+ ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
+ }
+
+ return true;
+}
+
+};
diff --git a/services/mediametrics/tests/Android.bp b/services/mediametrics/tests/Android.bp
new file mode 100644
index 0000000..bdeda30
--- /dev/null
+++ b/services/mediametrics/tests/Android.bp
@@ -0,0 +1,27 @@
+cc_test {
+ name: "mediametrics_tests",
+ test_suites: ["device-tests"],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+
+ include_dirs: [
+ "frameworks/av/services/mediametrics",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "liblog",
+ "libmediametrics",
+ "libmediametricsservice",
+ "libmediautils",
+ "libutils",
+ ],
+
+ srcs: [
+ "mediametrics_tests.cpp",
+ ],
+}
diff --git a/services/mediametrics/tests/build_and_run_all_unit_tests.sh b/services/mediametrics/tests/build_and_run_all_unit_tests.sh
new file mode 100755
index 0000000..382be47
--- /dev/null
+++ b/services/mediametrics/tests/build_and_run_all_unit_tests.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+#
+# Run tests in this directory.
+#
+
+if [ -z "$ANDROID_BUILD_TOP" ]; then
+ echo "Android build environment not set"
+ exit -1
+fi
+
+# ensure we have mm
+. $ANDROID_BUILD_TOP/build/envsetup.sh
+
+mm
+
+echo "waiting for device"
+
+adb root && adb wait-for-device remount
+
+echo "========================================"
+
+echo "testing mediametrics"
+adb push $OUT/data/nativetest64/mediametrics_tests/mediametrics_tests /system/bin
+adb shell /system/bin/mediametrics_tests
diff --git a/services/mediametrics/tests/mediametrics_tests.cpp b/services/mediametrics/tests/mediametrics_tests.cpp
new file mode 100644
index 0000000..b8e566e
--- /dev/null
+++ b/services/mediametrics/tests/mediametrics_tests.cpp
@@ -0,0 +1,866 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "mediametrics_tests"
+#include <utils/Log.h>
+
+#include "MediaMetricsService.h"
+
+#include <stdio.h>
+
+#include <gtest/gtest.h>
+#include <media/MediaMetricsItem.h>
+
+using namespace android;
+
+static size_t countNewlines(const char *s) {
+ size_t count = 0;
+ while ((s = strchr(s, '\n')) != nullptr) {
+ ++s;
+ ++count;
+ }
+ return count;
+}
+
+TEST(mediametrics_tests, startsWith) {
+ std::string s("test");
+ ASSERT_EQ(true, android::mediametrics::startsWith(s, "te"));
+ ASSERT_EQ(true, android::mediametrics::startsWith(s, std::string("tes")));
+ ASSERT_EQ(false, android::mediametrics::startsWith(s, "ts"));
+ ASSERT_EQ(false, android::mediametrics::startsWith(s, std::string("est")));
+}
+
+TEST(mediametrics_tests, defer) {
+ bool check = false;
+ {
+ android::mediametrics::Defer defer([&] { check = true; });
+ ASSERT_EQ(false, check);
+ }
+ ASSERT_EQ(true, check);
+}
+
+TEST(mediametrics_tests, shared_ptr_wrap) {
+ // Test shared pointer wrap with simple access
+ android::mediametrics::SharedPtrWrap<std::string> s("123");
+ ASSERT_EQ('1', s->at(0));
+ ASSERT_EQ('2', s->at(1));
+ s->push_back('4');
+ ASSERT_EQ('4', s->at(3));
+
+ const android::mediametrics::SharedPtrWrap<std::string> s2("345");
+ ASSERT_EQ('3', s2->operator[](0)); // s2[0] == '3'
+ // we allow modification through a const shared pointer wrap
+ // for compatibility with shared_ptr.
+ s2->push_back('6');
+ ASSERT_EQ('6', s2->operator[](3)); // s2[3] == '6'
+
+ android::mediametrics::SharedPtrWrap<std::string> s3("");
+ s3.set(std::make_shared<std::string>("abc"));
+ ASSERT_EQ('b', s3->operator[](1)); // s2[1] = 'b';
+
+ // Use Thunk to check whether the destructor was called prematurely
+ // when setting the shared ptr wrap in the middle of a method.
+
+ class Thunk {
+ std::function<void(int)> mF;
+ const int mFinal;
+
+ public:
+ Thunk(decltype(mF) f, int final) : mF(f), mFinal(final) {}
+ ~Thunk() { mF(mFinal); }
+ void thunk(int value) { mF(value); }
+ };
+
+ int counter = 0;
+ android::mediametrics::SharedPtrWrap<Thunk> s4(
+ [&](int value) {
+ s4.set(std::make_shared<Thunk>([](int){}, 0)); // recursively set s4 while in s4.
+ ++counter;
+ ASSERT_EQ(value, counter); // on thunk() value is 1, on destructor this is 2.
+ }, 2);
+
+ // This will fail if the shared ptr wrap doesn't hold a ref count during method access.
+ s4->thunk(1);
+}
+
+TEST(mediametrics_tests, lock_wrap) {
+ // Test lock wrap with simple access
+ android::mediametrics::LockWrap<std::string> s("123");
+ ASSERT_EQ('1', s->at(0));
+ ASSERT_EQ('2', s->at(1));
+ s->push_back('4');
+ ASSERT_EQ('4', s->at(3));
+
+ const android::mediametrics::LockWrap<std::string> s2("345");
+ ASSERT_EQ('3', s2->operator[](0)); // s2[0] == '3'
+ // note: we can't modify s2 due to const, s2->push_back('6');
+
+ android::mediametrics::LockWrap<std::string> s3("");
+ s3->operator=("abc");
+ ASSERT_EQ('b', s3->operator[](1)); // s2[1] = 'b';
+
+ // Check that we can recursively hold lock.
+ android::mediametrics::LockWrap<std::vector<int>> v{std::initializer_list<int>{1, 2}};
+ v->push_back(3);
+ v->push_back(4);
+ ASSERT_EQ(1, v->operator[](0));
+ ASSERT_EQ(2, v->operator[](1));
+ ASSERT_EQ(3, v->operator[](2));
+ ASSERT_EQ(4, v->operator[](3));
+ // The end of the full expression here requires recursive depth of 4.
+ ASSERT_EQ(10, v->operator[](0) + v->operator[](1) + v->operator[](2) + v->operator[](3));
+
+ // Mikhail's note: a non-recursive lock implementation could be used if one obtains
+ // the LockedPointer helper object like this and directly hold the lock through RAII,
+ // though it is trickier in use.
+ //
+ // We include an example here for completeness.
+ {
+ auto l = v.operator->();
+ ASSERT_EQ(10, l->operator[](0) + l->operator[](1) + l->operator[](2) + l->operator[](3));
+ }
+
+ // Use Thunk to check whether we have the lock when calling a method through LockWrap.
+
+ class Thunk {
+ std::function<void()> mF;
+
+ public:
+ Thunk(decltype(mF) f) : mF(f) {}
+ void thunk() { mF(); }
+ };
+
+ android::mediametrics::LockWrap<Thunk> s4([&]{
+ ASSERT_EQ((size_t)1, s4.getRecursionDepth()); // we must be locked when thunk() is called.
+ });
+
+ ASSERT_EQ((size_t)0, s4.getRecursionDepth());
+ // This will fail if we are not locked during method access.
+ s4->thunk();
+ ASSERT_EQ((size_t)0, s4.getRecursionDepth());
+}
+
+TEST(mediametrics_tests, lock_wrap_multithread) {
+ class Accumulator {
+ int32_t value_ = 0;
+ public:
+ void add(int32_t incr) {
+ const int32_t temp = value_;
+ sleep(0); // yield
+ value_ = temp + incr;
+ }
+ int32_t get() { return value_; }
+ };
+
+ android::mediametrics::LockWrap<Accumulator> a{}; // locked accumulator succeeds
+ // auto a = std::make_shared<Accumulator>(); // this fails, only 50% adds atomic.
+
+ constexpr size_t THREADS = 100;
+ constexpr size_t ITERATIONS = 10;
+ constexpr int32_t INCREMENT = 1;
+
+ std::vector<std::future<void>> threads(THREADS);
+ for (size_t i = 0; i < THREADS; ++i) {
+ threads.push_back(std::async(std::launch::async, [&] {
+ for (size_t j = 0; j < ITERATIONS; ++j) {
+ a->add(INCREMENT);
+ }
+ }));
+ }
+ threads.clear();
+
+ // If the add operations are not atomic, value will be smaller than expected.
+ ASSERT_EQ(INCREMENT * THREADS * ITERATIONS, (size_t)a->get());
+}
+
+TEST(mediametrics_tests, instantiate) {
+ sp mediaMetrics = new MediaMetricsService();
+ status_t status;
+
+ // random keys ignored when empty
+ std::unique_ptr<mediametrics::Item> random_key(mediametrics::Item::create("random_key"));
+ status = mediaMetrics->submit(random_key.get());
+ ASSERT_EQ(PERMISSION_DENIED, status);
+
+ // random keys ignored with data
+ random_key->setInt32("foo", 10);
+ status = mediaMetrics->submit(random_key.get());
+ ASSERT_EQ(PERMISSION_DENIED, status);
+
+ // known keys ignored if empty
+ std::unique_ptr<mediametrics::Item> audiotrack_key(mediametrics::Item::create("audiotrack"));
+ status = mediaMetrics->submit(audiotrack_key.get());
+ ASSERT_EQ(BAD_VALUE, status);
+
+ // known keys not ignored if not empty
+ audiotrack_key->addInt32("foo", 10);
+ status = mediaMetrics->submit(audiotrack_key.get());
+ ASSERT_EQ(NO_ERROR, status);
+
+
+ /*
+ // fluent style that goes directly to mediametrics
+ ASSERT_EQ(true, mediametrics::Item("audiorecord")
+ .setInt32("value", 2)
+ .addInt32("bar", 1)
+ .addInt32("value", 3)
+ .selfrecord());
+ */
+
+ mediaMetrics->dump(fileno(stdout), {} /* args */);
+}
+
+TEST(mediametrics_tests, package_installer_check) {
+ ASSERT_EQ(false, MediaMetricsService::useUidForPackage(
+ "abcd", "installer")); // ok, package name has no dot.
+ ASSERT_EQ(false, MediaMetricsService::useUidForPackage(
+ "android.com", "installer")); // ok, package name starts with android
+
+ ASSERT_EQ(false, MediaMetricsService::useUidForPackage(
+ "abc.def", "com.android.foo")); // ok, installer name starts with com.android
+ ASSERT_EQ(false, MediaMetricsService::useUidForPackage(
+ "123.456", "com.google.bar")); // ok, installer name starts with com.google
+ ASSERT_EQ(false, MediaMetricsService::useUidForPackage(
+ "r2.d2", "preload")); // ok, installer name is preload
+
+ ASSERT_EQ(true, MediaMetricsService::useUidForPackage(
+ "abc.def", "installer")); // unknown installer
+ ASSERT_EQ(true, MediaMetricsService::useUidForPackage(
+ "123.456", "installer")); // unknown installer
+ ASSERT_EQ(true, MediaMetricsService::useUidForPackage(
+ "r2.d2", "preload23")); // unknown installer
+
+ ASSERT_EQ(true, MediaMetricsService::useUidForPackage(
+ "com.android.foo", "abc.def")); // unknown installer
+ ASSERT_EQ(true, MediaMetricsService::useUidForPackage(
+ "com.google.bar", "123.456")); // unknown installer
+}
+
+TEST(mediametrics_tests, item_manipulation) {
+ mediametrics::Item item("audiorecord");
+
+ item.setInt32("value", 2).addInt32("bar", 3).addInt32("value", 4);
+
+ int32_t i32;
+ ASSERT_TRUE(item.getInt32("value", &i32));
+ ASSERT_EQ(6, i32);
+
+ ASSERT_TRUE(item.getInt32("bar", &i32));
+ ASSERT_EQ(3, i32);
+
+ item.setInt64("big", INT64_MAX).setInt64("smaller", INT64_MAX - 1).addInt64("smaller", -2);
+
+ int64_t i64;
+ ASSERT_TRUE(item.getInt64("big", &i64));
+ ASSERT_EQ(INT64_MAX, i64);
+
+ ASSERT_TRUE(item.getInt64("smaller", &i64));
+ ASSERT_EQ(INT64_MAX - 3, i64);
+
+ item.setDouble("precise", 10.5).setDouble("small", 0.125).addDouble("precise", 0.25);
+
+ double d;
+ ASSERT_TRUE(item.getDouble("precise", &d));
+ ASSERT_EQ(10.75, d);
+
+ ASSERT_TRUE(item.getDouble("small", &d));
+ ASSERT_EQ(0.125, d);
+
+ char *s;
+ item.setCString("name", "Frank").setCString("mother", "June").setCString("mother", "July");
+ ASSERT_TRUE(item.getCString("name", &s));
+ ASSERT_EQ(0, strcmp(s, "Frank"));
+ free(s);
+
+ ASSERT_TRUE(item.getCString("mother", &s));
+ ASSERT_EQ(0, strcmp(s, "July")); // "July" overwrites "June"
+ free(s);
+
+ item.setRate("burgersPerHour", 5, 2);
+ int64_t b, h;
+ ASSERT_TRUE(item.getRate("burgersPerHour", &b, &h, &d));
+ ASSERT_EQ(5, b);
+ ASSERT_EQ(2, h);
+ ASSERT_EQ(2.5, d);
+
+ item.addRate("burgersPerHour", 4, 2);
+ ASSERT_TRUE(item.getRate("burgersPerHour", &b, &h, &d));
+ ASSERT_EQ(9, b);
+ ASSERT_EQ(4, h);
+ ASSERT_EQ(2.25, d);
+
+ printf("item: %s\n", item.toString().c_str());
+ fflush(stdout);
+
+ sp mediaMetrics = new MediaMetricsService();
+ status_t status = mediaMetrics->submit(&item);
+ ASSERT_EQ(NO_ERROR, status);
+ mediaMetrics->dump(fileno(stdout), {} /* args */);
+}
+
+TEST(mediametrics_tests, superbig_item) {
+ mediametrics::Item item("TheBigOne");
+ constexpr size_t count = 10000;
+
+ for (size_t i = 0; i < count; ++i) {
+ item.setInt32(std::to_string(i).c_str(), i);
+ }
+ for (size_t i = 0; i < count; ++i) {
+ int32_t i32;
+ ASSERT_TRUE(item.getInt32(std::to_string(i).c_str(), &i32));
+ ASSERT_EQ((int32_t)i, i32);
+ }
+}
+
+TEST(mediametrics_tests, superbig_item_removal) {
+ mediametrics::Item item("TheOddBigOne");
+ constexpr size_t count = 10000;
+
+ for (size_t i = 0; i < count; ++i) {
+ item.setInt32(std::to_string(i).c_str(), i);
+ }
+ for (size_t i = 0; i < count; i += 2) {
+ item.filter(std::to_string(i).c_str()); // filter out all the evens.
+ }
+ for (size_t i = 0; i < count; ++i) {
+ int32_t i32;
+ if (i & 1) { // check to see that only the odds are left.
+ ASSERT_TRUE(item.getInt32(std::to_string(i).c_str(), &i32));
+ ASSERT_EQ((int32_t)i, i32);
+ } else {
+ ASSERT_FALSE(item.getInt32(std::to_string(i).c_str(), &i32));
+ }
+ }
+}
+
+TEST(mediametrics_tests, superbig_item_removal2) {
+ mediametrics::Item item("TheOne");
+ constexpr size_t count = 10000;
+
+ for (size_t i = 0; i < count; ++i) {
+ item.setInt32(std::to_string(i).c_str(), i);
+ }
+ static const char *attrs[] = { "1", };
+ item.filterNot(1, attrs);
+
+ for (size_t i = 0; i < count; ++i) {
+ int32_t i32;
+ if (i == 1) { // check to see that there is only one
+ ASSERT_TRUE(item.getInt32(std::to_string(i).c_str(), &i32));
+ ASSERT_EQ((int32_t)i, i32);
+ } else {
+ ASSERT_FALSE(item.getInt32(std::to_string(i).c_str(), &i32));
+ }
+ }
+}
+
+TEST(mediametrics_tests, item_transmutation) {
+ mediametrics::Item item("Alchemist's Stone");
+
+ item.setInt64("convert", 123);
+ int64_t i64;
+ ASSERT_TRUE(item.getInt64("convert", &i64));
+ ASSERT_EQ(123, i64);
+
+ item.addInt32("convert", 2); // changes type of 'convert' from i64 to i32 (and re-init).
+ ASSERT_FALSE(item.getInt64("convert", &i64)); // should be false, no value in i64.
+
+ int32_t i32;
+ ASSERT_TRUE(item.getInt32("convert", &i32)); // check it is i32 and 2 (123 is discarded).
+ ASSERT_EQ(2, i32);
+}
+
+TEST(mediametrics_tests, item_binderization) {
+ mediametrics::Item item;
+ item.setInt32("i32", 1)
+ .setInt64("i64", 2)
+ .setDouble("double", 3.1)
+ .setCString("string", "abc")
+ .setRate("rate", 11, 12);
+
+ Parcel p;
+ item.writeToParcel(&p);
+
+ p.setDataPosition(0); // rewind for reading
+ mediametrics::Item item2;
+ item2.readFromParcel(p);
+
+ ASSERT_EQ(item, item2);
+}
+
+TEST(mediametrics_tests, item_byteserialization) {
+ mediametrics::Item item;
+ item.setInt32("i32", 1)
+ .setInt64("i64", 2)
+ .setDouble("double", 3.1)
+ .setCString("string", "abc")
+ .setRate("rate", 11, 12);
+
+ char *data;
+ size_t length;
+ ASSERT_EQ(0, item.writeToByteString(&data, &length));
+ ASSERT_GT(length, (size_t)0);
+
+ mediametrics::Item item2;
+ item2.readFromByteString(data, length);
+
+ printf("item: %s\n", item.toString().c_str());
+ printf("item2: %s\n", item2.toString().c_str());
+ ASSERT_EQ(item, item2);
+
+ free(data);
+}
+
+TEST(mediametrics_tests, item_iteration) {
+ mediametrics::Item item;
+ item.setInt32("i32", 1)
+ .setInt64("i64", 2)
+ .setDouble("double", 3.125)
+ .setCString("string", "abc")
+ .setRate("rate", 11, 12);
+
+ int mask = 0;
+ for (auto &prop : item) {
+ const char *name = prop.getName();
+ if (!strcmp(name, "i32")) {
+ int32_t i32;
+ ASSERT_TRUE(prop.get(&i32));
+ ASSERT_EQ(1, i32);
+ ASSERT_EQ(1, std::get<int32_t>(prop.get()));
+ mask |= 1;
+ } else if (!strcmp(name, "i64")) {
+ int64_t i64;
+ ASSERT_TRUE(prop.get(&i64));
+ ASSERT_EQ(2, i64);
+ ASSERT_EQ(2, std::get<int64_t>(prop.get()));
+ mask |= 2;
+ } else if (!strcmp(name, "double")) {
+ double d;
+ ASSERT_TRUE(prop.get(&d));
+ ASSERT_EQ(3.125, d);
+ ASSERT_EQ(3.125, std::get<double>(prop.get()));
+ mask |= 4;
+ } else if (!strcmp(name, "string")) {
+ std::string s;
+ ASSERT_TRUE(prop.get(&s));
+ ASSERT_EQ("abc", s);
+ ASSERT_EQ(s, std::get<std::string>(prop.get()));
+ mask |= 8;
+ } else if (!strcmp(name, "rate")) {
+ std::pair<int64_t, int64_t> r;
+ ASSERT_TRUE(prop.get(&r));
+ ASSERT_EQ(11, r.first);
+ ASSERT_EQ(12, r.second);
+ ASSERT_EQ(r, std::get<decltype(r)>(prop.get()));
+ mask |= 16;
+ } else {
+ FAIL();
+ }
+ }
+ ASSERT_EQ(31, mask);
+}
+
+TEST(mediametrics_tests, item_expansion) {
+ mediametrics::LogItem<1> item("I");
+ item.set("i32", (int32_t)1)
+ .set("i64", (int64_t)2)
+ .set("double", (double)3.125)
+ .set("string", "abcdefghijklmnopqrstuvwxyz")
+ .set("rate", std::pair<int64_t, int64_t>(11, 12));
+ ASSERT_TRUE(item.updateHeader());
+
+ mediametrics::Item item2;
+ item2.readFromByteString(item.getBuffer(), item.getLength());
+ ASSERT_EQ((pid_t)-1, item2.getPid());
+ ASSERT_EQ((uid_t)-1, item2.getUid());
+ int mask = 0;
+ for (auto &prop : item2) {
+ const char *name = prop.getName();
+ if (!strcmp(name, "i32")) {
+ int32_t i32;
+ ASSERT_TRUE(prop.get(&i32));
+ ASSERT_EQ(1, i32);
+ mask |= 1;
+ } else if (!strcmp(name, "i64")) {
+ int64_t i64;
+ ASSERT_TRUE(prop.get(&i64));
+ ASSERT_EQ(2, i64);
+ mask |= 2;
+ } else if (!strcmp(name, "double")) {
+ double d;
+ ASSERT_TRUE(prop.get(&d));
+ ASSERT_EQ(3.125, d);
+ mask |= 4;
+ } else if (!strcmp(name, "string")) {
+ std::string s;
+ ASSERT_TRUE(prop.get(&s));
+ ASSERT_EQ("abcdefghijklmnopqrstuvwxyz", s);
+ mask |= 8;
+ } else if (!strcmp(name, "rate")) {
+ std::pair<int64_t, int64_t> r;
+ ASSERT_TRUE(prop.get(&r));
+ ASSERT_EQ(11, r.first);
+ ASSERT_EQ(12, r.second);
+ mask |= 16;
+ } else {
+ FAIL();
+ }
+ }
+ ASSERT_EQ(31, mask);
+}
+
+TEST(mediametrics_tests, item_expansion2) {
+ mediametrics::LogItem<1> item("Bigly");
+ item.setPid(123)
+ .setUid(456);
+ constexpr size_t count = 10000;
+
+ for (size_t i = 0; i < count; ++i) {
+ // printf("recording %zu, %p, len:%zu of %zu remaining:%zu \n", i, item.getBuffer(), item.getLength(), item.getCapacity(), item.getRemaining());
+ item.set(std::to_string(i).c_str(), (int32_t)i);
+ }
+ ASSERT_TRUE(item.updateHeader());
+
+ mediametrics::Item item2;
+ printf("begin buffer:%p length:%zu\n", item.getBuffer(), item.getLength());
+ fflush(stdout);
+ item2.readFromByteString(item.getBuffer(), item.getLength());
+
+ ASSERT_EQ((pid_t)123, item2.getPid());
+ ASSERT_EQ((uid_t)456, item2.getUid());
+ for (size_t i = 0; i < count; ++i) {
+ int32_t i32;
+ ASSERT_TRUE(item2.getInt32(std::to_string(i).c_str(), &i32));
+ ASSERT_EQ((int32_t)i, i32);
+ }
+}
+
+TEST(mediametrics_tests, time_machine_storage) {
+ auto item = std::make_shared<mediametrics::Item>("Key");
+ (*item).set("i32", (int32_t)1)
+ .set("i64", (int64_t)2)
+ .set("double", (double)3.125)
+ .set("string", "abcdefghijklmnopqrstuvwxyz")
+ .set("rate", std::pair<int64_t, int64_t>(11, 12));
+
+ // Let's put the item in
+ android::mediametrics::TimeMachine timeMachine;
+ ASSERT_EQ(NO_ERROR, timeMachine.put(item, true));
+
+ // Can we read the values?
+ int32_t i32;
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key", "i32", &i32, -1));
+ ASSERT_EQ(1, i32);
+
+ int64_t i64;
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key", "i64", &i64, -1));
+ ASSERT_EQ(2, i64);
+
+ double d;
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key", "double", &d, -1));
+ ASSERT_EQ(3.125, d);
+
+ std::string s;
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key", "string", &s, -1));
+ ASSERT_EQ("abcdefghijklmnopqrstuvwxyz", s);
+
+ // Using fully qualified name?
+ i32 = 0;
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key.i32", &i32, -1));
+ ASSERT_EQ(1, i32);
+
+ i64 = 0;
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key.i64", &i64, -1));
+ ASSERT_EQ(2, i64);
+
+ d = 0.;
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key.double", &d, -1));
+ ASSERT_EQ(3.125, d);
+
+ s.clear();
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key.string", &s, -1));
+ ASSERT_EQ("abcdefghijklmnopqrstuvwxyz", s);
+}
+
+TEST(mediametrics_tests, time_machine_remote_key) {
+ auto item = std::make_shared<mediametrics::Item>("Key1");
+ (*item).set("one", (int32_t)1)
+ .set("two", (int32_t)2);
+
+ android::mediametrics::TimeMachine timeMachine;
+ ASSERT_EQ(NO_ERROR, timeMachine.put(item, true));
+
+ auto item2 = std::make_shared<mediametrics::Item>("Key2");
+ (*item2).set("three", (int32_t)3)
+ .set("[Key1]four", (int32_t)4) // affects Key1
+ .set("[Key1]five", (int32_t)5); // affects key1
+
+ ASSERT_EQ(NO_ERROR, timeMachine.put(item2, true));
+
+ auto item3 = std::make_shared<mediametrics::Item>("Key2");
+ (*item3).set("six", (int32_t)6)
+ .set("[Key1]seven", (int32_t)7); // affects Key1
+
+ ASSERT_EQ(NO_ERROR, timeMachine.put(item3, false)); // remote keys not allowed.
+
+ // Can we read the values?
+ int32_t i32;
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key1.one", &i32, -1));
+ ASSERT_EQ(1, i32);
+
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key1.two", &i32, -1));
+ ASSERT_EQ(2, i32);
+
+ ASSERT_EQ(BAD_VALUE, timeMachine.get("Key1.three", &i32, -1));
+
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key2.three", &i32, -1));
+ ASSERT_EQ(3, i32);
+
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key1.four", &i32, -1));
+ ASSERT_EQ(4, i32);
+
+ ASSERT_EQ(BAD_VALUE, timeMachine.get("Key2.four", &i32, -1));
+
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key1.five", &i32, -1));
+ ASSERT_EQ(5, i32);
+
+ ASSERT_EQ(BAD_VALUE, timeMachine.get("Key2.five", &i32, -1));
+
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key2.six", &i32, -1));
+ ASSERT_EQ(6, i32);
+
+ ASSERT_EQ(BAD_VALUE, timeMachine.get("Key2.seven", &i32, -1));
+}
+
+TEST(mediametrics_tests, time_machine_gc) {
+ auto item = std::make_shared<mediametrics::Item>("Key1");
+ (*item).set("one", (int32_t)1)
+ .set("two", (int32_t)2)
+ .setTimestamp(10);
+
+ android::mediametrics::TimeMachine timeMachine(1, 2); // keep at most 2 keys.
+
+ ASSERT_EQ((size_t)0, timeMachine.size());
+
+ ASSERT_EQ(NO_ERROR, timeMachine.put(item, true));
+
+ ASSERT_EQ((size_t)1, timeMachine.size());
+
+ auto item2 = std::make_shared<mediametrics::Item>("Key2");
+ (*item2).set("three", (int32_t)3)
+ .set("[Key1]three", (int32_t)3)
+ .setTimestamp(11);
+
+ ASSERT_EQ(NO_ERROR, timeMachine.put(item2, true));
+ ASSERT_EQ((size_t)2, timeMachine.size());
+
+ //printf("Before\n%s\n\n", timeMachine.dump().c_str());
+
+ auto item3 = std::make_shared<mediametrics::Item>("Key3");
+ (*item3).set("six", (int32_t)6)
+ .set("[Key1]four", (int32_t)4) // affects Key1
+ .set("[Key1]five", (int32_t)5) // affects key1
+ .setTimestamp(12);
+
+ ASSERT_EQ(NO_ERROR, timeMachine.put(item3, true));
+
+ ASSERT_EQ((size_t)2, timeMachine.size());
+
+ // Can we read the values?
+ int32_t i32;
+ ASSERT_EQ(BAD_VALUE, timeMachine.get("Key1.one", &i32, -1));
+ ASSERT_EQ(BAD_VALUE, timeMachine.get("Key1.two", &i32, -1));
+ ASSERT_EQ(BAD_VALUE, timeMachine.get("Key1.three", &i32, -1));
+ ASSERT_EQ(BAD_VALUE, timeMachine.get("Key1.four", &i32, -1));
+ ASSERT_EQ(BAD_VALUE, timeMachine.get("Key1.five", &i32, -1));
+
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key2.three", &i32, -1));
+ ASSERT_EQ(3, i32);
+
+ ASSERT_EQ(NO_ERROR, timeMachine.get("Key3.six", &i32, -1));
+ ASSERT_EQ(6, i32);
+
+ printf("After\n%s\n", timeMachine.dump().first.c_str());
+}
+
+TEST(mediametrics_tests, transaction_log_gc) {
+ auto item = std::make_shared<mediametrics::Item>("Key1");
+ (*item).set("one", (int32_t)1)
+ .set("two", (int32_t)2)
+ .setTimestamp(10);
+
+ android::mediametrics::TransactionLog transactionLog(1, 2); // keep at most 2 items
+ ASSERT_EQ((size_t)0, transactionLog.size());
+
+ ASSERT_EQ(NO_ERROR, transactionLog.put(item));
+ ASSERT_EQ((size_t)1, transactionLog.size());
+
+ auto item2 = std::make_shared<mediametrics::Item>("Key2");
+ (*item2).set("three", (int32_t)3)
+ .set("[Key1]three", (int32_t)3)
+ .setTimestamp(11);
+
+ ASSERT_EQ(NO_ERROR, transactionLog.put(item2));
+ ASSERT_EQ((size_t)2, transactionLog.size());
+
+ auto item3 = std::make_shared<mediametrics::Item>("Key3");
+ (*item3).set("six", (int32_t)6)
+ .set("[Key1]four", (int32_t)4) // affects Key1
+ .set("[Key1]five", (int32_t)5) // affects key1
+ .setTimestamp(12);
+
+ ASSERT_EQ(NO_ERROR, transactionLog.put(item3));
+ ASSERT_EQ((size_t)2, transactionLog.size());
+}
+
+TEST(mediametrics_tests, analytics_actions) {
+ mediametrics::AnalyticsActions analyticsActions;
+ bool action1 = false;
+ bool action2 = false;
+ bool action3 = false;
+ bool action4 = false;
+
+ // check to see whether various actions have been matched.
+ analyticsActions.addAction(
+ "audio.flinger.event",
+ std::string("AudioFlinger"),
+ std::make_shared<mediametrics::AnalyticsActions::Function>(
+ [&](const std::shared_ptr<const android::mediametrics::Item> &) {
+ action1 = true;
+ }));
+
+ analyticsActions.addAction(
+ "audio.*.event",
+ std::string("AudioFlinger"),
+ std::make_shared<mediametrics::AnalyticsActions::Function>(
+ [&](const std::shared_ptr<const android::mediametrics::Item> &) {
+ action2 = true;
+ }));
+
+ analyticsActions.addAction("audio.fl*n*g*r.event",
+ std::string("AudioFlinger"),
+ std::make_shared<mediametrics::AnalyticsActions::Function>(
+ [&](const std::shared_ptr<const android::mediametrics::Item> &) {
+ action3 = true;
+ }));
+
+ analyticsActions.addAction("audio.fl*gn*r.event",
+ std::string("AudioFlinger"),
+ std::make_shared<mediametrics::AnalyticsActions::Function>(
+ [&](const std::shared_ptr<const android::mediametrics::Item> &) {
+ action4 = true;
+ }));
+
+ // make a test item
+ auto item = std::make_shared<mediametrics::Item>("audio.flinger");
+ (*item).set("event", "AudioFlinger");
+
+ // get the actions and execute them
+ auto actions = analyticsActions.getActionsForItem(item);
+ for (const auto& action : actions) {
+ action->operator()(item);
+ }
+
+ // The following should match.
+ ASSERT_EQ(true, action1);
+ ASSERT_EQ(true, action2);
+ ASSERT_EQ(true, action3);
+ ASSERT_EQ(false, action4); // audio.fl*gn*r != audio.flinger
+}
+
+TEST(mediametrics_tests, audio_analytics_permission) {
+ auto item = std::make_shared<mediametrics::Item>("audio.1");
+ (*item).set("one", (int32_t)1)
+ .set("two", (int32_t)2)
+ .setTimestamp(10);
+
+ auto item2 = std::make_shared<mediametrics::Item>("audio.1");
+ (*item2).set("three", (int32_t)3)
+ .setTimestamp(11);
+
+ auto item3 = std::make_shared<mediametrics::Item>("audio.2");
+ (*item3).set("four", (int32_t)4)
+ .setTimestamp(12);
+
+ android::mediametrics::AudioAnalytics audioAnalytics;
+
+ // untrusted entities cannot create a new key.
+ ASSERT_EQ(PERMISSION_DENIED, audioAnalytics.submit(item, false /* isTrusted */));
+ ASSERT_EQ(PERMISSION_DENIED, audioAnalytics.submit(item2, false /* isTrusted */));
+
+ // TODO: Verify contents of AudioAnalytics.
+ // Currently there is no getter API in AudioAnalytics besides dump.
+ ASSERT_EQ(9, audioAnalytics.dump(1000).second /* lines */);
+
+ ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item, true /* isTrusted */));
+ // untrusted entities can add to an existing key
+ ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item2, false /* isTrusted */));
+
+ // Check that we have some info in the dump.
+ ASSERT_LT(9, audioAnalytics.dump(1000).second /* lines */);
+}
+
+TEST(mediametrics_tests, audio_analytics_dump) {
+ auto item = std::make_shared<mediametrics::Item>("audio.1");
+ (*item).set("one", (int32_t)1)
+ .set("two", (int32_t)2)
+ .setTimestamp(10);
+
+ auto item2 = std::make_shared<mediametrics::Item>("audio.1");
+ (*item2).set("three", (int32_t)3)
+ .setTimestamp(11);
+
+ auto item3 = std::make_shared<mediametrics::Item>("audio.2");
+ (*item3).set("four", (int32_t)4)
+ .setTimestamp(12);
+
+ android::mediametrics::AudioAnalytics audioAnalytics;
+
+ ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item, true /* isTrusted */));
+ // untrusted entities can add to an existing key
+ ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item2, false /* isTrusted */));
+ ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item3, true /* isTrusted */));
+
+ // find out how many lines we have.
+ auto [string, lines] = audioAnalytics.dump(1000);
+ ASSERT_EQ(lines, (int32_t) countNewlines(string.c_str()));
+
+ printf("AudioAnalytics: %s", string.c_str());
+ // ensure that dump operates over those lines.
+ for (int32_t ll = 0; ll < lines; ++ll) {
+ auto [s, l] = audioAnalytics.dump(ll);
+ ASSERT_EQ(ll, l);
+ ASSERT_EQ(ll, (int32_t) countNewlines(s.c_str()));
+ }
+}
+
+#if 0
+// Stress test code for garbage collection, you need to enable AID_SHELL as trusted to run
+// in MediaMetricsService.cpp.
+//
+// TODO: Make a dedicated stress test.
+//
+TEST(mediametrics_tests, gc_same_key) {
+ // random keys ignored when empty
+ for (int i = 0; i < 10000000; ++i) {
+ std::unique_ptr<mediametrics::Item> test_key(mediametrics::Item::create("audio.zzz.123"));
+ test_key->set("event#", "hello");
+ test_key->set("value", (int)10);
+ test_key->selfrecord();
+ }
+ //mediaMetrics->dump(fileno(stdout), {} /* args */);
+}
+#endif
diff --git a/services/mediaresourcemanager/Android.bp b/services/mediaresourcemanager/Android.bp
index f3339a0..a3519d5 100644
--- a/services/mediaresourcemanager/Android.bp
+++ b/services/mediaresourcemanager/Android.bp
@@ -12,6 +12,7 @@
"libmedia",
"libmediautils",
"libbinder",
+ "libbinder_ndk",
"libutils",
"liblog",
],
@@ -23,4 +24,6 @@
"-Wall",
],
+ export_include_dirs: ["."],
+
}
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index bdcd5e4..be5af00 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -19,10 +19,13 @@
#define LOG_TAG "ResourceManagerService"
#include <utils/Log.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
#include <binder/IMediaResourceMonitor.h>
#include <binder/IServiceManager.h>
#include <cutils/sched_policy.h>
#include <dirent.h>
+#include <media/MediaResourcePolicy.h>
#include <media/stagefright/ProcessInfo.h>
#include <mediautils/BatteryNotifier.h>
#include <mediautils/SchedulingPolicyService.h>
@@ -37,43 +40,40 @@
namespace android {
-namespace {
+DeathNotifier::DeathNotifier(const std::shared_ptr<ResourceManagerService> &service,
+ int pid, int64_t clientId)
+ : mService(service), mPid(pid), mClientId(clientId) {}
-class DeathNotifier : public IBinder::DeathRecipient {
-public:
- DeathNotifier(const wp<ResourceManagerService> &service, int pid, int64_t clientId)
- : mService(service), mPid(pid), mClientId(clientId) {}
+//static
+void DeathNotifier::BinderDiedCallback(void* cookie) {
+ auto thiz = static_cast<DeathNotifier*>(cookie);
+ thiz->binderDied();
+}
- virtual void binderDied(const wp<IBinder> & /* who */) override {
- // Don't check for pid validity since we know it's already dead.
- sp<ResourceManagerService> service = mService.promote();
- if (service == nullptr) {
- ALOGW("ResourceManagerService is dead as well.");
- return;
- }
- service->removeResource(mPid, mClientId, false);
+void DeathNotifier::binderDied() {
+ // Don't check for pid validity since we know it's already dead.
+ std::shared_ptr<ResourceManagerService> service = mService.lock();
+ if (service == nullptr) {
+ ALOGW("ResourceManagerService is dead as well.");
+ return;
}
+ service->removeResource(mPid, mClientId, false);
-private:
- wp<ResourceManagerService> mService;
- int mPid;
- int64_t mClientId;
-};
-
-} // namespace
+ service->overridePid(mPid, -1);
+}
template <typename T>
-static String8 getString(const Vector<T> &items) {
+static String8 getString(const std::vector<T> &items) {
String8 itemsStr;
for (size_t i = 0; i < items.size(); ++i) {
- itemsStr.appendFormat("%s ", items[i].toString().string());
+ itemsStr.appendFormat("%s ", toString(items[i]).string());
}
return itemsStr;
}
static bool hasResourceType(MediaResource::Type type, const ResourceList& resources) {
for (auto it = resources.begin(); it != resources.end(); it++) {
- if (it->second.mType == type) {
+ if (it->second.type == type) {
return true;
}
}
@@ -105,7 +105,7 @@
static ResourceInfo& getResourceInfoForEdit(
uid_t uid,
int64_t clientId,
- const sp<IResourceManagerClient>& client,
+ const std::shared_ptr<IResourceManagerClient>& client,
ResourceInfos& infos) {
ssize_t index = infos.indexOfKey(clientId);
@@ -121,29 +121,30 @@
return infos.editValueAt(index);
}
-static void notifyResourceGranted(int pid, const Vector<MediaResource> &resources) {
+static void notifyResourceGranted(int pid, const std::vector<MediaResourceParcel> &resources) {
static const char* const kServiceName = "media_resource_monitor";
sp<IBinder> binder = defaultServiceManager()->checkService(String16(kServiceName));
if (binder != NULL) {
sp<IMediaResourceMonitor> service = interface_cast<IMediaResourceMonitor>(binder);
for (size_t i = 0; i < resources.size(); ++i) {
- if (resources[i].mSubType == MediaResource::kAudioCodec) {
+ if (resources[i].subType == MediaResource::SubType::kAudioCodec) {
service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_AUDIO_CODEC);
- } else if (resources[i].mSubType == MediaResource::kVideoCodec) {
+ } else if (resources[i].subType == MediaResource::SubType::kVideoCodec) {
service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_VIDEO_CODEC);
}
}
}
}
-status_t ResourceManagerService::dump(int fd, const Vector<String16>& /* args */) {
+binder_status_t ResourceManagerService::dump(
+ int fd, const char** /*args*/, uint32_t /*numArgs*/) {
String8 result;
if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
result.format("Permission Denial: "
"can't dump ResourceManagerService from pid=%d, uid=%d\n",
- IPCThreadState::self()->getCallingPid(),
- IPCThreadState::self()->getCallingUid());
+ AIBinder_getCallingPid(),
+ AIBinder_getCallingUid());
write(fd, result.string(), result.size());
return PERMISSION_DENIED;
}
@@ -151,6 +152,7 @@
PidResourceInfosMap mapCopy;
bool supportsMultipleSecureCodecs;
bool supportsSecureWithNonSecureCodec;
+ std::map<int, int> overridePidMapCopy;
String8 serviceLog;
{
Mutex::Autolock lock(mLock);
@@ -158,6 +160,7 @@
supportsMultipleSecureCodecs = mSupportsMultipleSecureCodecs;
supportsSecureWithNonSecureCodec = mSupportsSecureWithNonSecureCodec;
serviceLog = mServiceLog->toString(" " /* linePrefix */);
+ overridePidMapCopy = mOverridePidMap;
}
const size_t SIZE = 256;
@@ -182,17 +185,28 @@
snprintf(buffer, SIZE, " Id: %lld\n", (long long)infos[j].clientId);
result.append(buffer);
- snprintf(buffer, SIZE, " Name: %s\n", infos[j].client->getName().string());
+ std::string clientName;
+ Status status = infos[j].client->getName(&clientName);
+ if (!status.isOk()) {
+ clientName = "<unknown client>";
+ }
+ snprintf(buffer, SIZE, " Name: %s\n", clientName.c_str());
result.append(buffer);
const ResourceList &resources = infos[j].resources;
result.append(" Resources:\n");
for (auto it = resources.begin(); it != resources.end(); it++) {
- snprintf(buffer, SIZE, " %s\n", it->second.toString().string());
+ snprintf(buffer, SIZE, " %s\n", toString(it->second).string());
result.append(buffer);
}
}
}
+ result.append(" Process Pid override:\n");
+ for (auto it = overridePidMapCopy.begin(); it != overridePidMapCopy.end(); ++it) {
+ snprintf(buffer, SIZE, " Original Pid: %d, Override Pid: %d\n",
+ it->first, it->second);
+ result.append(buffer);
+ }
result.append(" Events logs (most recent at top):\n");
result.append(serviceLog);
@@ -202,7 +216,7 @@
struct SystemCallbackImpl :
public ResourceManagerService::SystemCallbackInterface {
- SystemCallbackImpl() {}
+ SystemCallbackImpl() : mClientToken(new BBinder()) {}
virtual void noteStartVideo(int uid) override {
BatteryNotifier::getInstance().noteStartVideo(uid);
@@ -213,9 +227,8 @@
virtual void noteResetVideo() override {
BatteryNotifier::getInstance().noteResetVideo();
}
- virtual bool requestCpusetBoost(
- bool enable, const sp<IInterface> &client) override {
- return android::requestCpusetBoost(enable, client);
+ virtual bool requestCpusetBoost(bool enable) override {
+ return android::requestCpusetBoost(enable, mClientToken);
}
protected:
@@ -223,6 +236,7 @@
private:
DISALLOW_EVIL_CONSTRUCTORS(SystemCallbackImpl);
+ sp<IBinder> mClientToken;
};
ResourceManagerService::ResourceManagerService()
@@ -236,66 +250,100 @@
mServiceLog(new ServiceLog()),
mSupportsMultipleSecureCodecs(true),
mSupportsSecureWithNonSecureCodec(true),
- mCpuBoostCount(0) {
+ mCpuBoostCount(0),
+ mDeathRecipient(AIBinder_DeathRecipient_new(DeathNotifier::BinderDiedCallback)) {
mSystemCB->noteResetVideo();
}
+//static
+void ResourceManagerService::instantiate() {
+ std::shared_ptr<ResourceManagerService> service =
+ ::ndk::SharedRefBase::make<ResourceManagerService>();
+ binder_status_t status =
+ AServiceManager_addService(service->asBinder().get(), getServiceName());
+ if (status != STATUS_OK) {
+ return;
+ }
+ // TODO: mediaserver main() is already starting the thread pool,
+ // move this to mediaserver main() when other services in mediaserver
+ // are converted to ndk-platform aidl.
+ //ABinderProcess_startThreadPool();
+}
+
ResourceManagerService::~ResourceManagerService() {}
-void ResourceManagerService::config(const Vector<MediaResourcePolicy> &policies) {
+Status ResourceManagerService::config(const std::vector<MediaResourcePolicyParcel>& policies) {
String8 log = String8::format("config(%s)", getString(policies).string());
mServiceLog->add(log);
Mutex::Autolock lock(mLock);
for (size_t i = 0; i < policies.size(); ++i) {
- String8 type = policies[i].mType;
- String8 value = policies[i].mValue;
- if (type == kPolicySupportsMultipleSecureCodecs) {
+ const std::string &type = policies[i].type;
+ const std::string &value = policies[i].value;
+ if (type == MediaResourcePolicy::kPolicySupportsMultipleSecureCodecs()) {
mSupportsMultipleSecureCodecs = (value == "true");
- } else if (type == kPolicySupportsSecureWithNonSecureCodec) {
+ } else if (type == MediaResourcePolicy::kPolicySupportsSecureWithNonSecureCodec()) {
mSupportsSecureWithNonSecureCodec = (value == "true");
}
}
+ return Status::ok();
}
void ResourceManagerService::onFirstAdded(
- const MediaResource& resource, const ResourceInfo& clientInfo) {
+ const MediaResourceParcel& resource, const ResourceInfo& clientInfo) {
// first time added
- if (resource.mType == MediaResource::kCpuBoost
- && resource.mSubType == MediaResource::kUnspecifiedSubType) {
+ if (resource.type == MediaResource::Type::kCpuBoost
+ && resource.subType == MediaResource::SubType::kUnspecifiedSubType) {
// Request it on every new instance of kCpuBoost, as the media.codec
// could have died, if we only do it the first time subsequent instances
// never gets the boost.
- if (mSystemCB->requestCpusetBoost(true, this) != OK) {
+ if (mSystemCB->requestCpusetBoost(true) != OK) {
ALOGW("couldn't request cpuset boost");
}
mCpuBoostCount++;
- } else if (resource.mType == MediaResource::kBattery
- && resource.mSubType == MediaResource::kVideoCodec) {
+ } else if (resource.type == MediaResource::Type::kBattery
+ && resource.subType == MediaResource::SubType::kVideoCodec) {
mSystemCB->noteStartVideo(clientInfo.uid);
}
}
void ResourceManagerService::onLastRemoved(
- const MediaResource& resource, const ResourceInfo& clientInfo) {
- if (resource.mType == MediaResource::kCpuBoost
- && resource.mSubType == MediaResource::kUnspecifiedSubType
+ const MediaResourceParcel& resource, const ResourceInfo& clientInfo) {
+ if (resource.type == MediaResource::Type::kCpuBoost
+ && resource.subType == MediaResource::SubType::kUnspecifiedSubType
&& mCpuBoostCount > 0) {
if (--mCpuBoostCount == 0) {
- mSystemCB->requestCpusetBoost(false, this);
+ mSystemCB->requestCpusetBoost(false);
}
- } else if (resource.mType == MediaResource::kBattery
- && resource.mSubType == MediaResource::kVideoCodec) {
+ } else if (resource.type == MediaResource::Type::kBattery
+ && resource.subType == MediaResource::SubType::kVideoCodec) {
mSystemCB->noteStopVideo(clientInfo.uid);
}
}
-void ResourceManagerService::addResource(
- int pid,
- int uid,
+void ResourceManagerService::mergeResources(
+ MediaResourceParcel& r1, const MediaResourceParcel& r2) {
+ // The resource entry on record is maintained to be in [0,INT64_MAX].
+ // Clamp if merging in the new resource value causes it to go out of bound.
+ // Note that the new resource value could be negative, eg.DrmSession, the
+ // value goes lower when the session is used more often. During reclaim
+ // the session with the highest value (lowest usage) would be closed.
+ if (r2.value < INT64_MAX - r1.value) {
+ r1.value += r2.value;
+ if (r1.value < 0) {
+ r1.value = 0;
+ }
+ } else {
+ r1.value = INT64_MAX;
+ }
+}
+
+Status ResourceManagerService::addResource(
+ int32_t pid,
+ int32_t uid,
int64_t clientId,
- const sp<IResourceManagerClient> client,
- const Vector<MediaResource> &resources) {
+ const std::shared_ptr<IResourceManagerClient>& client,
+ const std::vector<MediaResourceParcel>& resources) {
String8 log = String8::format("addResource(pid %d, clientId %lld, resources %s)",
pid, (long long) clientId, getString(resources).string());
mServiceLog->add(log);
@@ -303,29 +351,44 @@
Mutex::Autolock lock(mLock);
if (!mProcessInfo->isValidPid(pid)) {
ALOGE("Rejected addResource call with invalid pid.");
- return;
+ return Status::fromServiceSpecificError(BAD_VALUE);
}
ResourceInfos& infos = getResourceInfosForEdit(pid, mMap);
ResourceInfo& info = getResourceInfoForEdit(uid, clientId, client, infos);
for (size_t i = 0; i < resources.size(); ++i) {
- const auto resType = std::make_pair(resources[i].mType, resources[i].mSubType);
+ const auto &res = resources[i];
+ const auto resType = std::tuple(res.type, res.subType, res.id);
+
+ if (res.value < 0 && res.type != MediaResource::Type::kDrmSession) {
+ ALOGW("Ignoring request to remove negative value of non-drm resource");
+ continue;
+ }
if (info.resources.find(resType) == info.resources.end()) {
- onFirstAdded(resources[i], info);
- info.resources[resType] = resources[i];
+ if (res.value <= 0) {
+ // We can't init a new entry with negative value, although it's allowed
+ // to merge in negative values after the initial add.
+ ALOGW("Ignoring request to add new resource entry with value <= 0");
+ continue;
+ }
+ onFirstAdded(res, info);
+ info.resources[resType] = res;
} else {
- info.resources[resType].mValue += resources[i].mValue;
+ mergeResources(info.resources[resType], res);
}
}
- if (info.deathNotifier == nullptr) {
- info.deathNotifier = new DeathNotifier(this, pid, clientId);
- IInterface::asBinder(client)->linkToDeath(info.deathNotifier);
+ if (info.deathNotifier == nullptr && client != nullptr) {
+ info.deathNotifier = new DeathNotifier(ref<ResourceManagerService>(), pid, clientId);
+ AIBinder_linkToDeath(client->asBinder().get(),
+ mDeathRecipient.get(), info.deathNotifier.get());
}
notifyResourceGranted(pid, resources);
+ return Status::ok();
}
-void ResourceManagerService::removeResource(int pid, int64_t clientId,
- const Vector<MediaResource> &resources) {
+Status ResourceManagerService::removeResource(
+ int32_t pid, int64_t clientId,
+ const std::vector<MediaResourceParcel>& resources) {
String8 log = String8::format("removeResource(pid %d, clientId %lld, resources %s)",
pid, (long long) clientId, getString(resources).string());
mServiceLog->add(log);
@@ -333,43 +396,51 @@
Mutex::Autolock lock(mLock);
if (!mProcessInfo->isValidPid(pid)) {
ALOGE("Rejected removeResource call with invalid pid.");
- return;
+ return Status::fromServiceSpecificError(BAD_VALUE);
}
ssize_t index = mMap.indexOfKey(pid);
if (index < 0) {
ALOGV("removeResource: didn't find pid %d for clientId %lld", pid, (long long) clientId);
- return;
+ return Status::ok();
}
ResourceInfos &infos = mMap.editValueAt(index);
index = infos.indexOfKey(clientId);
if (index < 0) {
ALOGV("removeResource: didn't find clientId %lld", (long long) clientId);
- return;
+ return Status::ok();
}
ResourceInfo &info = infos.editValueAt(index);
for (size_t i = 0; i < resources.size(); ++i) {
- const auto resType = std::make_pair(resources[i].mType, resources[i].mSubType);
+ const auto &res = resources[i];
+ const auto resType = std::tuple(res.type, res.subType, res.id);
+
+ if (res.value < 0) {
+ ALOGW("Ignoring request to remove negative value of resource");
+ continue;
+ }
// ignore if we don't have it
if (info.resources.find(resType) != info.resources.end()) {
- MediaResource &resource = info.resources[resType];
- if (resource.mValue > resources[i].mValue) {
- resource.mValue -= resources[i].mValue;
+ MediaResourceParcel &resource = info.resources[resType];
+ if (resource.value > res.value) {
+ resource.value -= res.value;
} else {
- onLastRemoved(resources[i], info);
+ onLastRemoved(res, info);
info.resources.erase(resType);
}
}
}
+ return Status::ok();
}
-void ResourceManagerService::removeClient(int pid, int64_t clientId) {
+Status ResourceManagerService::removeClient(int32_t pid, int64_t clientId) {
removeResource(pid, clientId, true);
+ return Status::ok();
}
-void ResourceManagerService::removeResource(int pid, int64_t clientId, bool checkValid) {
+Status ResourceManagerService::removeResource(int pid, int64_t clientId, bool checkValid) {
String8 log = String8::format(
"removeResource(pid %d, clientId %lld)",
pid, (long long) clientId);
@@ -378,19 +449,19 @@
Mutex::Autolock lock(mLock);
if (checkValid && !mProcessInfo->isValidPid(pid)) {
ALOGE("Rejected removeResource call with invalid pid.");
- return;
+ return Status::fromServiceSpecificError(BAD_VALUE);
}
ssize_t index = mMap.indexOfKey(pid);
if (index < 0) {
ALOGV("removeResource: didn't find pid %d for clientId %lld", pid, (long long) clientId);
- return;
+ return Status::ok();
}
ResourceInfos &infos = mMap.editValueAt(index);
index = infos.indexOfKey(clientId);
if (index < 0) {
ALOGV("removeResource: didn't find clientId %lld", (long long) clientId);
- return;
+ return Status::ok();
}
const ResourceInfo &info = infos[index];
@@ -398,69 +469,84 @@
onLastRemoved(it->second, info);
}
- IInterface::asBinder(info.client)->unlinkToDeath(info.deathNotifier);
+ AIBinder_unlinkToDeath(info.client->asBinder().get(),
+ mDeathRecipient.get(), info.deathNotifier.get());
infos.removeItemsAt(index);
+ return Status::ok();
}
void ResourceManagerService::getClientForResource_l(
- int callingPid, const MediaResource *res, Vector<sp<IResourceManagerClient>> *clients) {
+ int callingPid, const MediaResourceParcel *res,
+ Vector<std::shared_ptr<IResourceManagerClient>> *clients) {
if (res == NULL) {
return;
}
- sp<IResourceManagerClient> client;
- if (getLowestPriorityBiggestClient_l(callingPid, res->mType, &client)) {
+ std::shared_ptr<IResourceManagerClient> client;
+ if (getLowestPriorityBiggestClient_l(callingPid, res->type, &client)) {
clients->push_back(client);
}
}
-bool ResourceManagerService::reclaimResource(
- int callingPid, const Vector<MediaResource> &resources) {
+Status ResourceManagerService::reclaimResource(
+ int32_t callingPid,
+ const std::vector<MediaResourceParcel>& resources,
+ bool* _aidl_return) {
String8 log = String8::format("reclaimResource(callingPid %d, resources %s)",
callingPid, getString(resources).string());
mServiceLog->add(log);
+ *_aidl_return = false;
- Vector<sp<IResourceManagerClient>> clients;
+ Vector<std::shared_ptr<IResourceManagerClient>> clients;
{
Mutex::Autolock lock(mLock);
if (!mProcessInfo->isValidPid(callingPid)) {
ALOGE("Rejected reclaimResource call with invalid callingPid.");
- return false;
+ return Status::fromServiceSpecificError(BAD_VALUE);
}
- const MediaResource *secureCodec = NULL;
- const MediaResource *nonSecureCodec = NULL;
- const MediaResource *graphicMemory = NULL;
+ const MediaResourceParcel *secureCodec = NULL;
+ const MediaResourceParcel *nonSecureCodec = NULL;
+ const MediaResourceParcel *graphicMemory = NULL;
+ const MediaResourceParcel *drmSession = NULL;
for (size_t i = 0; i < resources.size(); ++i) {
- MediaResource::Type type = resources[i].mType;
- if (resources[i].mType == MediaResource::kSecureCodec) {
+ MediaResource::Type type = resources[i].type;
+ if (resources[i].type == MediaResource::Type::kSecureCodec) {
secureCodec = &resources[i];
- } else if (type == MediaResource::kNonSecureCodec) {
+ } else if (type == MediaResource::Type::kNonSecureCodec) {
nonSecureCodec = &resources[i];
- } else if (type == MediaResource::kGraphicMemory) {
+ } else if (type == MediaResource::Type::kGraphicMemory) {
graphicMemory = &resources[i];
+ } else if (type == MediaResource::Type::kDrmSession) {
+ drmSession = &resources[i];
}
}
// first pass to handle secure/non-secure codec conflict
if (secureCodec != NULL) {
if (!mSupportsMultipleSecureCodecs) {
- if (!getAllClients_l(callingPid, MediaResource::kSecureCodec, &clients)) {
- return false;
+ if (!getAllClients_l(callingPid, MediaResource::Type::kSecureCodec, &clients)) {
+ return Status::ok();
}
}
if (!mSupportsSecureWithNonSecureCodec) {
- if (!getAllClients_l(callingPid, MediaResource::kNonSecureCodec, &clients)) {
- return false;
+ if (!getAllClients_l(callingPid, MediaResource::Type::kNonSecureCodec, &clients)) {
+ return Status::ok();
}
}
}
if (nonSecureCodec != NULL) {
if (!mSupportsSecureWithNonSecureCodec) {
- if (!getAllClients_l(callingPid, MediaResource::kSecureCodec, &clients)) {
- return false;
+ if (!getAllClients_l(callingPid, MediaResource::Type::kSecureCodec, &clients)) {
+ return Status::ok();
}
}
}
+ if (drmSession != NULL) {
+ getClientForResource_l(callingPid, drmSession, &clients);
+ if (clients.size() == 0) {
+ return Status::ok();
+ }
+ }
if (clients.size() == 0) {
// if no secure/non-secure codec conflict, run second pass to handle other resources.
@@ -476,32 +562,35 @@
if (clients.size() == 0) {
// if we are here, run the fourth pass to free one codec with the different type.
if (secureCodec != NULL) {
- MediaResource temp(MediaResource::kNonSecureCodec, 1);
+ MediaResource temp(MediaResource::Type::kNonSecureCodec, 1);
getClientForResource_l(callingPid, &temp, &clients);
}
if (nonSecureCodec != NULL) {
- MediaResource temp(MediaResource::kSecureCodec, 1);
+ MediaResource temp(MediaResource::Type::kSecureCodec, 1);
getClientForResource_l(callingPid, &temp, &clients);
}
}
}
if (clients.size() == 0) {
- return false;
+ return Status::ok();
}
- sp<IResourceManagerClient> failedClient;
+ std::shared_ptr<IResourceManagerClient> failedClient;
for (size_t i = 0; i < clients.size(); ++i) {
log = String8::format("reclaimResource from client %p", clients[i].get());
mServiceLog->add(log);
- if (!clients[i]->reclaimResource()) {
+ bool success;
+ Status status = clients[i]->reclaimResource(&success);
+ if (!status.isOk() || !success) {
failedClient = clients[i];
break;
}
}
if (failedClient == NULL) {
- return true;
+ *_aidl_return = true;
+ return Status::ok();
}
{
@@ -526,12 +615,55 @@
}
}
- return false;
+ return Status::ok();
+}
+
+Status ResourceManagerService::overridePid(
+ int originalPid,
+ int newPid) {
+ String8 log = String8::format("overridePid(originalPid %d, newPid %d)",
+ originalPid, newPid);
+ mServiceLog->add(log);
+
+ // allow if this is called from the same process or the process has
+ // permission.
+ if ((AIBinder_getCallingPid() != getpid()) &&
+ (checkCallingPermission(String16(
+ "android.permission.MEDIA_RESOURCE_OVERRIDE_PID")) == false)) {
+ ALOGE(
+ "Permission Denial: can't access overridePid method from pid=%d, "
+ "self pid=%d\n",
+ AIBinder_getCallingPid(), getpid());
+ return Status::fromServiceSpecificError(PERMISSION_DENIED);
+ }
+
+ {
+ Mutex::Autolock lock(mLock);
+ mOverridePidMap.erase(originalPid);
+ if (newPid != -1) {
+ mOverridePidMap.emplace(originalPid, newPid);
+ }
+ }
+
+ return Status::ok();
+}
+
+bool ResourceManagerService::getPriority_l(int pid, int* priority) {
+ int newPid = pid;
+
+ if (mOverridePidMap.find(pid) != mOverridePidMap.end()) {
+ newPid = mOverridePidMap[pid];
+ ALOGD("getPriority_l: use override pid %d instead original pid %d",
+ newPid, pid);
+ }
+
+ return mProcessInfo->getPriority(newPid, priority);
}
bool ResourceManagerService::getAllClients_l(
- int callingPid, MediaResource::Type type, Vector<sp<IResourceManagerClient>> *clients) {
- Vector<sp<IResourceManagerClient>> temp;
+ int callingPid, MediaResource::Type type,
+ Vector<std::shared_ptr<IResourceManagerClient>> *clients) {
+ Vector<std::shared_ptr<IResourceManagerClient>> temp;
for (size_t i = 0; i < mMap.size(); ++i) {
ResourceInfos &infos = mMap.editValueAt(i);
for (size_t j = 0; j < infos.size(); ++j) {
@@ -556,11 +688,12 @@
}
bool ResourceManagerService::getLowestPriorityBiggestClient_l(
- int callingPid, MediaResource::Type type, sp<IResourceManagerClient> *client) {
+ int callingPid, MediaResource::Type type,
+ std::shared_ptr<IResourceManagerClient> *client) {
int lowestPriorityPid;
int lowestPriority;
int callingPriority;
- if (!mProcessInfo->getPriority(callingPid, &callingPriority)) {
+ if (!getPriority_l(callingPid, &callingPriority)) {
ALOGE("getLowestPriorityBiggestClient_l: can't get process priority for pid %d",
callingPid);
return false;
@@ -595,7 +728,7 @@
}
int tempPid = mMap.keyAt(i);
int tempPriority;
- if (!mProcessInfo->getPriority(tempPid, &tempPriority)) {
+ if (!getPriority_l(tempPid, &tempPriority)) {
ALOGV("getLowestPriorityPid_l: can't get priority of pid %d, skipped", tempPid);
// TODO: remove this pid from mMap?
continue;
@@ -615,12 +748,12 @@
bool ResourceManagerService::isCallingPriorityHigher_l(int callingPid, int pid) {
int callingPidPriority;
- if (!mProcessInfo->getPriority(callingPid, &callingPidPriority)) {
+ if (!getPriority_l(callingPid, &callingPidPriority)) {
return false;
}
int priority;
- if (!mProcessInfo->getPriority(pid, &priority)) {
+ if (!getPriority_l(pid, &priority)) {
return false;
}
@@ -628,23 +761,23 @@
}
bool ResourceManagerService::getBiggestClient_l(
- int pid, MediaResource::Type type, sp<IResourceManagerClient> *client) {
+ int pid, MediaResource::Type type, std::shared_ptr<IResourceManagerClient> *client) {
ssize_t index = mMap.indexOfKey(pid);
if (index < 0) {
ALOGE("getBiggestClient_l: can't find resource info for pid %d", pid);
return false;
}
- sp<IResourceManagerClient> clientTemp;
+ std::shared_ptr<IResourceManagerClient> clientTemp;
uint64_t largestValue = 0;
const ResourceInfos &infos = mMap.valueAt(index);
for (size_t i = 0; i < infos.size(); ++i) {
const ResourceList &resources = infos[i].resources;
for (auto it = resources.begin(); it != resources.end(); it++) {
- const MediaResource &resource = it->second;
- if (resource.mType == type) {
- if (resource.mValue > largestValue) {
- largestValue = resource.mValue;
+ const MediaResourceParcel &resource = it->second;
+ if (resource.type == type) {
+ if (resource.value > largestValue) {
+ largestValue = resource.value;
clientTemp = infos[i].client;
}
}
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index f086dc3..f500c62 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -15,30 +15,40 @@
** limitations under the License.
*/
-#ifndef ANDROID_RESOURCEMANAGERSERVICE_H
-#define ANDROID_RESOURCEMANAGERSERVICE_H
+#ifndef ANDROID_MEDIA_RESOURCEMANAGERSERVICE_H
+#define ANDROID_MEDIA_RESOURCEMANAGERSERVICE_H
+#include <aidl/android/media/BnResourceManagerService.h>
#include <arpa/inet.h>
-#include <binder/BinderService.h>
+#include <media/MediaResource.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/String8.h>
#include <utils/threads.h>
#include <utils/Vector.h>
-#include <media/IResourceManagerService.h>
-
namespace android {
+class DeathNotifier;
+class ResourceManagerService;
class ServiceLog;
struct ProcessInfoInterface;
-typedef std::map<std::pair<MediaResource::Type, MediaResource::SubType>, MediaResource> ResourceList;
+using Status = ::ndk::ScopedAStatus;
+using ::aidl::android::media::IResourceManagerClient;
+using ::aidl::android::media::BnResourceManagerService;
+using ::aidl::android::media::MediaResourceParcel;
+using ::aidl::android::media::MediaResourcePolicyParcel;
+
+typedef std::map<std::tuple<
+ MediaResource::Type, MediaResource::SubType, std::vector<int8_t>>,
+ MediaResourceParcel> ResourceList;
+
struct ResourceInfo {
int64_t clientId;
uid_t uid;
- sp<IResourceManagerClient> client;
- sp<IBinder::DeathRecipient> deathNotifier;
+ std::shared_ptr<IResourceManagerClient> client;
+ sp<DeathNotifier> deathNotifier;
ResourceList resources;
};
@@ -46,52 +56,73 @@
typedef KeyedVector<int64_t, ResourceInfo> ResourceInfos;
typedef KeyedVector<int, ResourceInfos> PidResourceInfosMap;
-class ResourceManagerService
- : public BinderService<ResourceManagerService>,
- public BnResourceManagerService
-{
+class DeathNotifier : public RefBase {
+public:
+ DeathNotifier(const std::shared_ptr<ResourceManagerService> &service,
+ int pid, int64_t clientId);
+
+ ~DeathNotifier() {}
+
+ // Implement death recipient
+ static void BinderDiedCallback(void* cookie);
+ void binderDied();
+
+private:
+ std::weak_ptr<ResourceManagerService> mService;
+ int mPid;
+ int64_t mClientId;
+};
+class ResourceManagerService : public BnResourceManagerService {
public:
struct SystemCallbackInterface : public RefBase {
virtual void noteStartVideo(int uid) = 0;
virtual void noteStopVideo(int uid) = 0;
virtual void noteResetVideo() = 0;
- virtual bool requestCpusetBoost(
- bool enable, const sp<IInterface> &client) = 0;
+ virtual bool requestCpusetBoost(bool enable) = 0;
};
static char const *getServiceName() { return "media.resource_manager"; }
+ static void instantiate();
- virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual inline binder_status_t dump(
+ int /*fd*/, const char** /*args*/, uint32_t /*numArgs*/);
ResourceManagerService();
explicit ResourceManagerService(
const sp<ProcessInfoInterface> &processInfo,
const sp<SystemCallbackInterface> &systemResource);
+ virtual ~ResourceManagerService();
// IResourceManagerService interface
- virtual void config(const Vector<MediaResourcePolicy> &policies);
+ Status config(const std::vector<MediaResourcePolicyParcel>& policies) override;
- virtual void addResource(
- int pid,
- int uid,
+ Status addResource(
+ int32_t pid,
+ int32_t uid,
int64_t clientId,
- const sp<IResourceManagerClient> client,
- const Vector<MediaResource> &resources);
+ const std::shared_ptr<IResourceManagerClient>& client,
+ const std::vector<MediaResourceParcel>& resources) override;
- virtual void removeResource(int pid, int64_t clientId,
- const Vector<MediaResource> &resources);
+ Status removeResource(
+ int32_t pid,
+ int64_t clientId,
+ const std::vector<MediaResourceParcel>& resources) override;
- virtual void removeClient(int pid, int64_t clientId);
+ Status removeClient(int32_t pid, int64_t clientId) override;
// Tries to reclaim resource from processes with lower priority than the calling process
// according to the requested resources.
// Returns true if any resource has been reclaimed, otherwise returns false.
- virtual bool reclaimResource(int callingPid, const Vector<MediaResource> &resources);
+ Status reclaimResource(
+ int32_t callingPid,
+ const std::vector<MediaResourceParcel>& resources,
+ bool* _aidl_return) override;
- void removeResource(int pid, int64_t clientId, bool checkValid);
+ Status overridePid(
+ int originalPid,
+ int newPid) override;
-protected:
- virtual ~ResourceManagerService();
+ Status removeResource(int pid, int64_t clientId, bool checkValid);
private:
friend class ResourceManagerServiceTest;
@@ -100,13 +131,13 @@
// Returns false if any client belongs to a process with higher priority than the
// calling process. The clients will remain unchanged if returns false.
bool getAllClients_l(int callingPid, MediaResource::Type type,
- Vector<sp<IResourceManagerClient>> *clients);
+ Vector<std::shared_ptr<IResourceManagerClient>> *clients);
// Gets the client who owns specified resource type from lowest possible priority process.
// Returns false if the calling process priority is not higher than the lowest process
// priority. The client will remain unchanged if returns false.
bool getLowestPriorityBiggestClient_l(int callingPid, MediaResource::Type type,
- sp<IResourceManagerClient> *client);
+ std::shared_ptr<IResourceManagerClient> *client);
// Gets lowest priority process that has the specified resource type.
// Returns false if failed. The output parameters will remain unchanged if failed.
@@ -114,17 +145,24 @@
// Gets the client who owns biggest piece of specified resource type from pid.
// Returns false if failed. The client will remain unchanged if failed.
- bool getBiggestClient_l(int pid, MediaResource::Type type, sp<IResourceManagerClient> *client);
+ bool getBiggestClient_l(int pid, MediaResource::Type type,
+ std::shared_ptr<IResourceManagerClient> *client);
bool isCallingPriorityHigher_l(int callingPid, int pid);
- // A helper function basically calls getLowestPriorityBiggestClient_l and add the result client
- // to the given Vector.
- void getClientForResource_l(
- int callingPid, const MediaResource *res, Vector<sp<IResourceManagerClient>> *clients);
+ // A helper function basically calls getLowestPriorityBiggestClient_l and add
+ // the result client to the given Vector.
+ void getClientForResource_l(int callingPid, const MediaResourceParcel *res,
+ Vector<std::shared_ptr<IResourceManagerClient>> *clients);
- void onFirstAdded(const MediaResource& res, const ResourceInfo& clientInfo);
- void onLastRemoved(const MediaResource& res, const ResourceInfo& clientInfo);
+ void onFirstAdded(const MediaResourceParcel& res, const ResourceInfo& clientInfo);
+ void onLastRemoved(const MediaResourceParcel& res, const ResourceInfo& clientInfo);
+
+ // Merge r2 into r1
+ void mergeResources(MediaResourceParcel& r1, const MediaResourceParcel& r2);
+
+ // Get priority from process's pid
+ bool getPriority_l(int pid, int* priority);
mutable Mutex mLock;
sp<ProcessInfoInterface> mProcessInfo;
@@ -134,10 +172,11 @@
bool mSupportsMultipleSecureCodecs;
bool mSupportsSecureWithNonSecureCodec;
int32_t mCpuBoostCount;
+ ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+ std::map<int, int> mOverridePidMap;
};
// ----------------------------------------------------------------------------
+} // namespace android
-}; // namespace android
-
-#endif // ANDROID_RESOURCEMANAGERSERVICE_H
+#endif // ANDROID_MEDIA_RESOURCEMANAGERSERVICE_H
diff --git a/services/mediaresourcemanager/test/Android.bp b/services/mediaresourcemanager/test/Android.bp
index 543c87c..b6c548c 100644
--- a/services/mediaresourcemanager/test/Android.bp
+++ b/services/mediaresourcemanager/test/Android.bp
@@ -5,6 +5,7 @@
test_suites: ["device-tests"],
shared_libs: [
"libbinder",
+ "libbinder_ndk",
"liblog",
"libmedia",
"libresourcemanagerservice",
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
index ae97ec8..5d839fa 100644
--- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -21,15 +21,28 @@
#include <gtest/gtest.h>
#include "ResourceManagerService.h"
-#include <media/IResourceManagerService.h>
+#include <aidl/android/media/BnResourceManagerClient.h>
#include <media/MediaResource.h>
#include <media/MediaResourcePolicy.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/ProcessInfoInterface.h>
+namespace aidl {
+namespace android {
+namespace media {
+bool operator== (const MediaResourceParcel& lhs, const MediaResourceParcel& rhs) {
+ return lhs.type == rhs.type && lhs.subType == rhs.subType &&
+ lhs.id == rhs.id && lhs.value == rhs.value;
+}}}}
+
namespace android {
-static int64_t getId(const sp<IResourceManagerClient>& client) {
+using Status = ::ndk::ScopedAStatus;
+using ::aidl::android::media::BnResourceManagerClient;
+using ::aidl::android::media::IResourceManagerService;
+using ::aidl::android::media::IResourceManagerClient;
+
+static int64_t getId(const std::shared_ptr<IResourceManagerClient>& client) {
return (int64_t) client.get();
}
@@ -86,8 +99,7 @@
mEventCount++;
}
- virtual bool requestCpusetBoost(
- bool enable, const sp<IInterface> &/*client*/) override {
+ virtual bool requestCpusetBoost(bool enable) override {
mLastEvent = {enable ? EventType::CPUSET_ENABLE : EventType::CPUSET_DISABLE, 0};
mEventCount++;
return true;
@@ -109,18 +121,19 @@
struct TestClient : public BnResourceManagerClient {
- TestClient(int pid, sp<ResourceManagerService> service)
+ TestClient(int pid, const std::shared_ptr<ResourceManagerService> &service)
: mReclaimed(false), mPid(pid), mService(service) {}
- virtual bool reclaimResource() {
- sp<IResourceManagerClient> client(this);
- mService->removeClient(mPid, (int64_t) client.get());
+ Status reclaimResource(bool* _aidl_return) override {
+ mService->removeClient(mPid, getId(ref<TestClient>()));
mReclaimed = true;
- return true;
+ *_aidl_return = true;
+ return Status::ok();
}
- virtual String8 getName() {
- return String8("test_client");
+ Status getName(::std::string* _aidl_return) override {
+ *_aidl_return = "test_client";
+ return Status::ok();
}
bool reclaimed() const {
@@ -131,13 +144,12 @@
mReclaimed = false;
}
-protected:
virtual ~TestClient() {}
private:
bool mReclaimed;
int mPid;
- sp<ResourceManagerService> mService;
+ std::shared_ptr<ResourceManagerService> mService;
DISALLOW_EVIL_CONSTRUCTORS(TestClient);
};
@@ -157,32 +169,40 @@
return lhs.type == rhs.type && lhs.arg == rhs.arg;
}
+#define CHECK_STATUS_TRUE(condition) \
+ EXPECT_TRUE((condition).isOk() && (result))
+
+#define CHECK_STATUS_FALSE(condition) \
+ EXPECT_TRUE((condition).isOk() && !(result))
+
class ResourceManagerServiceTest : public ::testing::Test {
public:
ResourceManagerServiceTest()
: mSystemCB(new TestSystemCallback()),
- mService(new ResourceManagerService(new TestProcessInfo, mSystemCB)),
- mTestClient1(new TestClient(kTestPid1, mService)),
- mTestClient2(new TestClient(kTestPid2, mService)),
- mTestClient3(new TestClient(kTestPid2, mService)) {
+ mService(::ndk::SharedRefBase::make<ResourceManagerService>(
+ new TestProcessInfo, mSystemCB)),
+ mTestClient1(::ndk::SharedRefBase::make<TestClient>(kTestPid1, mService)),
+ mTestClient2(::ndk::SharedRefBase::make<TestClient>(kTestPid2, mService)),
+ mTestClient3(::ndk::SharedRefBase::make<TestClient>(kTestPid2, mService)) {
}
protected:
- static bool isEqualResources(const Vector<MediaResource> &resources1,
+ static bool isEqualResources(const std::vector<MediaResourceParcel> &resources1,
const ResourceList &resources2) {
// convert resource1 to ResourceList
ResourceList r1;
for (size_t i = 0; i < resources1.size(); ++i) {
- const auto resType = std::make_pair(resources1[i].mType, resources1[i].mSubType);
- r1[resType] = resources1[i];
+ const auto &res = resources1[i];
+ const auto resType = std::tuple(res.type, res.subType, res.id);
+ r1[resType] = res;
}
return r1 == resources2;
}
static void expectEqResourceInfo(const ResourceInfo &info,
int uid,
- sp<IResourceManagerClient> client,
- const Vector<MediaResource> &resources) {
+ std::shared_ptr<IResourceManagerClient> client,
+ const std::vector<MediaResourceParcel> &resources) {
EXPECT_EQ(uid, info.uid);
EXPECT_EQ(client, info.client);
EXPECT_TRUE(isEqualResources(resources, info.resources));
@@ -218,25 +238,25 @@
// ---------------------------------------------------------------------------------
void addResource() {
// kTestPid1 mTestClient1
- Vector<MediaResource> resources1;
- resources1.push_back(MediaResource(MediaResource::kSecureCodec, 1));
+ std::vector<MediaResourceParcel> resources1;
+ resources1.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
- resources1.push_back(MediaResource(MediaResource::kGraphicMemory, 200));
- Vector<MediaResource> resources11;
- resources11.push_back(MediaResource(MediaResource::kGraphicMemory, 200));
+ resources1.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 200));
+ std::vector<MediaResourceParcel> resources11;
+ resources11.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 200));
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources11);
// kTestPid2 mTestClient2
- Vector<MediaResource> resources2;
- resources2.push_back(MediaResource(MediaResource::kNonSecureCodec, 1));
- resources2.push_back(MediaResource(MediaResource::kGraphicMemory, 300));
+ std::vector<MediaResourceParcel> resources2;
+ resources2.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
+ resources2.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 300));
mService->addResource(kTestPid2, kTestUid2, getId(mTestClient2), mTestClient2, resources2);
// kTestPid2 mTestClient3
- Vector<MediaResource> resources3;
+ std::vector<MediaResourceParcel> resources3;
mService->addResource(kTestPid2, kTestUid2, getId(mTestClient3), mTestClient3, resources3);
- resources3.push_back(MediaResource(MediaResource::kSecureCodec, 1));
- resources3.push_back(MediaResource(MediaResource::kGraphicMemory, 100));
+ resources3.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
+ resources3.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 100));
mService->addResource(kTestPid2, kTestUid2, getId(mTestClient3), mTestClient3, resources3);
const PidResourceInfosMap &map = mService->mMap;
@@ -255,32 +275,92 @@
expectEqResourceInfo(infos2.valueFor(getId(mTestClient3)), kTestUid2, mTestClient3, resources3);
}
+ void testCombineResourceWithNegativeValues() {
+ // kTestPid1 mTestClient1
+ std::vector<MediaResourceParcel> resources1;
+ resources1.push_back(MediaResource(MediaResource::Type::kDrmSession, -100));
+ resources1.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, -100));
+ mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
+
+ // Expected result:
+ // 1) the client should have been added;
+ // 2) both resource entries should have been rejected, resource list should be empty.
+ const PidResourceInfosMap &map = mService->mMap;
+ EXPECT_EQ(1u, map.size());
+ ssize_t index1 = map.indexOfKey(kTestPid1);
+ ASSERT_GE(index1, 0);
+ const ResourceInfos &infos1 = map[index1];
+ EXPECT_EQ(1u, infos1.size());
+ std::vector<MediaResourceParcel> expected;
+ expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+
+ resources1.clear();
+ resources1.push_back(MediaResource(MediaResource::Type::kDrmSession, INT64_MAX));
+ resources1.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, INT64_MAX));
+ mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
+ resources1.clear();
+ resources1.push_back(MediaResource(MediaResource::Type::kDrmSession, 10));
+ resources1.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 10));
+ mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
+
+ // Expected result:
+ // Both values should saturate to INT64_MAX
+ expected.push_back(MediaResource(MediaResource::Type::kDrmSession, INT64_MAX));
+ expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, INT64_MAX));
+ expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+
+ resources1.clear();
+ resources1.push_back(MediaResource(MediaResource::Type::kDrmSession, -10));
+ resources1.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, -10));
+ mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
+
+ // Expected result:
+ // 1) DrmSession resource should allow negative value addition, and value should drop accordingly
+ // 2) Non-drm session resource should ignore negative value addition.
+ expected.push_back(MediaResource(MediaResource::Type::kDrmSession, INT64_MAX - 10));
+ expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, INT64_MAX));
+ expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+
+ resources1.clear();
+ resources1.push_back(MediaResource(MediaResource::Type::kDrmSession, INT64_MIN));
+ expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, INT64_MIN));
+ mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
+
+ // Expected result:
+ // 1) DrmSession resource value should drop to 0, but the entry shouldn't be removed.
+ // 2) Non-drm session resource should ignore negative value addition.
+ expected.clear();
+ expected.push_back(MediaResource(MediaResource::Type::kDrmSession, 0));
+ expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, INT64_MAX));
+ expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+ }
+
void testConfig() {
EXPECT_TRUE(mService->mSupportsMultipleSecureCodecs);
EXPECT_TRUE(mService->mSupportsSecureWithNonSecureCodec);
- Vector<MediaResourcePolicy> policies1;
+ std::vector<MediaResourcePolicyParcel> policies1;
policies1.push_back(
MediaResourcePolicy(
- String8(kPolicySupportsMultipleSecureCodecs),
- String8("true")));
+ IResourceManagerService::kPolicySupportsMultipleSecureCodecs,
+ "true"));
policies1.push_back(
MediaResourcePolicy(
- String8(kPolicySupportsSecureWithNonSecureCodec),
- String8("false")));
+ IResourceManagerService::kPolicySupportsSecureWithNonSecureCodec,
+ "false"));
mService->config(policies1);
EXPECT_TRUE(mService->mSupportsMultipleSecureCodecs);
EXPECT_FALSE(mService->mSupportsSecureWithNonSecureCodec);
- Vector<MediaResourcePolicy> policies2;
+ std::vector<MediaResourcePolicyParcel> policies2;
policies2.push_back(
MediaResourcePolicy(
- String8(kPolicySupportsMultipleSecureCodecs),
- String8("false")));
+ IResourceManagerService::kPolicySupportsMultipleSecureCodecs,
+ "false"));
policies2.push_back(
MediaResourcePolicy(
- String8(kPolicySupportsSecureWithNonSecureCodec),
- String8("true")));
+ IResourceManagerService::kPolicySupportsSecureWithNonSecureCodec,
+ "true"));
mService->config(policies2);
EXPECT_FALSE(mService->mSupportsMultipleSecureCodecs);
EXPECT_TRUE(mService->mSupportsSecureWithNonSecureCodec);
@@ -288,12 +368,12 @@
void testCombineResource() {
// kTestPid1 mTestClient1
- Vector<MediaResource> resources1;
- resources1.push_back(MediaResource(MediaResource::kSecureCodec, 1));
+ std::vector<MediaResourceParcel> resources1;
+ resources1.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
- Vector<MediaResource> resources11;
- resources11.push_back(MediaResource(MediaResource::kGraphicMemory, 200));
+ std::vector<MediaResourceParcel> resources11;
+ resources11.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 200));
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources11);
const PidResourceInfosMap &map = mService->mMap;
@@ -304,35 +384,35 @@
EXPECT_EQ(1u, infos1.size());
// test adding existing types to combine values
- resources1.push_back(MediaResource(MediaResource::kGraphicMemory, 100));
+ resources1.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 100));
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
- Vector<MediaResource> expected;
- expected.push_back(MediaResource(MediaResource::kSecureCodec, 2));
- expected.push_back(MediaResource(MediaResource::kGraphicMemory, 300));
+ std::vector<MediaResourceParcel> expected;
+ expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, 2));
+ expected.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 300));
expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
// test adding new types (including types that differs only in subType)
- resources11.push_back(MediaResource(MediaResource::kNonSecureCodec, 1));
- resources11.push_back(MediaResource(MediaResource::kSecureCodec, MediaResource::kVideoCodec, 1));
+ resources11.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
+ resources11.push_back(MediaResource(MediaResource::Type::kSecureCodec, MediaResource::SubType::kVideoCodec, 1));
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources11);
expected.clear();
- expected.push_back(MediaResource(MediaResource::kSecureCodec, 2));
- expected.push_back(MediaResource(MediaResource::kNonSecureCodec, 1));
- expected.push_back(MediaResource(MediaResource::kSecureCodec, MediaResource::kVideoCodec, 1));
- expected.push_back(MediaResource(MediaResource::kGraphicMemory, 500));
+ expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, 2));
+ expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
+ expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, MediaResource::SubType::kVideoCodec, 1));
+ expected.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 500));
expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
}
void testRemoveResource() {
// kTestPid1 mTestClient1
- Vector<MediaResource> resources1;
- resources1.push_back(MediaResource(MediaResource::kSecureCodec, 1));
+ std::vector<MediaResourceParcel> resources1;
+ resources1.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
- Vector<MediaResource> resources11;
- resources11.push_back(MediaResource(MediaResource::kGraphicMemory, 200));
+ std::vector<MediaResourceParcel> resources11;
+ resources11.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 200));
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources11);
const PidResourceInfosMap &map = mService->mMap;
@@ -343,23 +423,55 @@
EXPECT_EQ(1u, infos1.size());
// test partial removal
- resources11.editItemAt(0).mValue = 100;
+ resources11[0].value = 100;
mService->removeResource(kTestPid1, getId(mTestClient1), resources11);
- Vector<MediaResource> expected;
- expected.push_back(MediaResource(MediaResource::kSecureCodec, 1));
- expected.push_back(MediaResource(MediaResource::kGraphicMemory, 100));
+ std::vector<MediaResourceParcel> expected;
+ expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
+ expected.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 100));
+ expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+
+ // test removal request with negative value, should be ignored
+ resources11[0].value = -10000;
+ mService->removeResource(kTestPid1, getId(mTestClient1), resources11);
+
expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
// test complete removal with overshoot value
- resources11.editItemAt(0).mValue = 1000;
+ resources11[0].value = 1000;
mService->removeResource(kTestPid1, getId(mTestClient1), resources11);
expected.clear();
- expected.push_back(MediaResource(MediaResource::kSecureCodec, 1));
+ expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
}
+ void testOverridePid() {
+
+ bool result;
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
+ resources.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 150));
+
+ // ### secure codec can't coexist and secure codec can coexist with non-secure codec ###
+ {
+ addResource();
+ mService->mSupportsMultipleSecureCodecs = false;
+ mService->mSupportsSecureWithNonSecureCodec = true;
+
+ // priority too low to reclaim resource
+ CHECK_STATUS_FALSE(mService->reclaimResource(kLowPriorityPid, resources, &result));
+
+ // override Low Priority Pid with High Priority Pid
+ mService->overridePid(kLowPriorityPid, kHighPriorityPid);
+ CHECK_STATUS_TRUE(mService->reclaimResource(kLowPriorityPid, resources, &result));
+
+ // restore Low Priority Pid
+ mService->overridePid(kLowPriorityPid, -1);
+ CHECK_STATUS_FALSE(mService->reclaimResource(kLowPriorityPid, resources, &result));
+ }
+ }
+
void testRemoveClient() {
addResource();
@@ -379,8 +491,8 @@
void testGetAllClients() {
addResource();
- MediaResource::Type type = MediaResource::kSecureCodec;
- Vector<sp<IResourceManagerClient> > clients;
+ MediaResource::Type type = MediaResource::Type::kSecureCodec;
+ Vector<std::shared_ptr<IResourceManagerClient> > clients;
EXPECT_FALSE(mService->getAllClients_l(kLowPriorityPid, type, &clients));
// some higher priority process (e.g. kTestPid2) owns the resource, so getAllClients_l
// will fail.
@@ -394,9 +506,10 @@
}
void testReclaimResourceSecure() {
- Vector<MediaResource> resources;
- resources.push_back(MediaResource(MediaResource::kSecureCodec, 1));
- resources.push_back(MediaResource(MediaResource::kGraphicMemory, 150));
+ bool result;
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
+ resources.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 150));
// ### secure codec can't coexist and secure codec can coexist with non-secure codec ###
{
@@ -405,19 +518,19 @@
mService->mSupportsSecureWithNonSecureCodec = true;
// priority too low
- EXPECT_FALSE(mService->reclaimResource(kLowPriorityPid, resources));
- EXPECT_FALSE(mService->reclaimResource(kMidPriorityPid, resources));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kLowPriorityPid, resources, &result));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kMidPriorityPid, resources, &result));
// reclaim all secure codecs
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
verifyClients(true /* c1 */, false /* c2 */, true /* c3 */);
// call again should reclaim one largest graphic memory from lowest process
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
// nothing left
- EXPECT_FALSE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
}
// ### secure codecs can't coexist and secure codec can't coexist with non-secure codec ###
@@ -427,15 +540,15 @@
mService->mSupportsSecureWithNonSecureCodec = false;
// priority too low
- EXPECT_FALSE(mService->reclaimResource(kLowPriorityPid, resources));
- EXPECT_FALSE(mService->reclaimResource(kMidPriorityPid, resources));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kLowPriorityPid, resources, &result));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kMidPriorityPid, resources, &result));
// reclaim all secure and non-secure codecs
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
verifyClients(true /* c1 */, true /* c2 */, true /* c3 */);
// nothing left
- EXPECT_FALSE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
}
@@ -446,23 +559,23 @@
mService->mSupportsSecureWithNonSecureCodec = false;
// priority too low
- EXPECT_FALSE(mService->reclaimResource(kLowPriorityPid, resources));
- EXPECT_FALSE(mService->reclaimResource(kMidPriorityPid, resources));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kLowPriorityPid, resources, &result));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kMidPriorityPid, resources, &result));
// reclaim all non-secure codecs
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
// call again should reclaim one largest graphic memory from lowest process
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
// call again should reclaim another largest graphic memory from lowest process
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
verifyClients(false /* c1 */, false /* c2 */, true /* c3 */);
// nothing left
- EXPECT_FALSE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
}
// ### secure codecs can coexist and secure codec can coexist with non-secure codec ###
@@ -472,22 +585,22 @@
mService->mSupportsSecureWithNonSecureCodec = true;
// priority too low
- EXPECT_FALSE(mService->reclaimResource(kLowPriorityPid, resources));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kLowPriorityPid, resources, &result));
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
// one largest graphic memory from lowest process got reclaimed
verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
// call again should reclaim another graphic memory from lowest process
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
// call again should reclaim another graphic memory from lowest process
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
verifyClients(false /* c1 */, false /* c2 */, true /* c3 */);
// nothing left
- EXPECT_FALSE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
}
// ### secure codecs can coexist and secure codec can coexist with non-secure codec ###
@@ -496,27 +609,28 @@
mService->mSupportsMultipleSecureCodecs = true;
mService->mSupportsSecureWithNonSecureCodec = true;
- Vector<MediaResource> resources;
- resources.push_back(MediaResource(MediaResource::kSecureCodec, 1));
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
// secure codec from lowest process got reclaimed
verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
// call again should reclaim another secure codec from lowest process
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
verifyClients(false /* c1 */, false /* c2 */, true /* c3 */);
// no more secure codec, non-secure codec will be reclaimed.
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
}
}
void testReclaimResourceNonSecure() {
- Vector<MediaResource> resources;
- resources.push_back(MediaResource(MediaResource::kNonSecureCodec, 1));
- resources.push_back(MediaResource(MediaResource::kGraphicMemory, 150));
+ bool result;
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
+ resources.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 150));
// ### secure codec can't coexist with non-secure codec ###
{
@@ -524,19 +638,19 @@
mService->mSupportsSecureWithNonSecureCodec = false;
// priority too low
- EXPECT_FALSE(mService->reclaimResource(kLowPriorityPid, resources));
- EXPECT_FALSE(mService->reclaimResource(kMidPriorityPid, resources));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kLowPriorityPid, resources, &result));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kMidPriorityPid, resources, &result));
// reclaim all secure codecs
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
verifyClients(true /* c1 */, false /* c2 */, true /* c3 */);
// call again should reclaim one graphic memory from lowest process
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
// nothing left
- EXPECT_FALSE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
}
@@ -546,22 +660,22 @@
mService->mSupportsSecureWithNonSecureCodec = true;
// priority too low
- EXPECT_FALSE(mService->reclaimResource(kLowPriorityPid, resources));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kLowPriorityPid, resources, &result));
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
// one largest graphic memory from lowest process got reclaimed
verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
// call again should reclaim another graphic memory from lowest process
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
// call again should reclaim another graphic memory from lowest process
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
verifyClients(false /* c1 */, false /* c2 */, true /* c3 */);
// nothing left
- EXPECT_FALSE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
}
// ### secure codec can coexist with non-secure codec ###
@@ -569,15 +683,15 @@
addResource();
mService->mSupportsSecureWithNonSecureCodec = true;
- Vector<MediaResource> resources;
- resources.push_back(MediaResource(MediaResource::kNonSecureCodec, 1));
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
// one non secure codec from lowest process got reclaimed
verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
// no more non-secure codec, secure codec from lowest priority process will be reclaimed
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
// clean up client 3 which still left
@@ -586,8 +700,8 @@
}
void testGetLowestPriorityBiggestClient() {
- MediaResource::Type type = MediaResource::kGraphicMemory;
- sp<IResourceManagerClient> client;
+ MediaResource::Type type = MediaResource::Type::kGraphicMemory;
+ std::shared_ptr<IResourceManagerClient> client;
EXPECT_FALSE(mService->getLowestPriorityBiggestClient_l(kHighPriorityPid, type, &client));
addResource();
@@ -595,8 +709,8 @@
EXPECT_FALSE(mService->getLowestPriorityBiggestClient_l(kLowPriorityPid, type, &client));
EXPECT_TRUE(mService->getLowestPriorityBiggestClient_l(kHighPriorityPid, type, &client));
- // kTestPid1 is the lowest priority process with MediaResource::kGraphicMemory.
- // mTestClient1 has the largest MediaResource::kGraphicMemory within kTestPid1.
+ // kTestPid1 is the lowest priority process with MediaResource::Type::kGraphicMemory.
+ // mTestClient1 has the largest MediaResource::Type::kGraphicMemory within kTestPid1.
EXPECT_EQ(mTestClient1, client);
}
@@ -605,7 +719,7 @@
int priority;
TestProcessInfo processInfo;
- MediaResource::Type type = MediaResource::kGraphicMemory;
+ MediaResource::Type type = MediaResource::Type::kGraphicMemory;
EXPECT_FALSE(mService->getLowestPriorityPid_l(type, &pid, &priority));
addResource();
@@ -616,7 +730,7 @@
processInfo.getPriority(kTestPid1, &priority1);
EXPECT_EQ(priority1, priority);
- type = MediaResource::kNonSecureCodec;
+ type = MediaResource::Type::kNonSecureCodec;
EXPECT_TRUE(mService->getLowestPriorityPid_l(type, &pid, &priority));
EXPECT_EQ(kTestPid2, pid);
int priority2;
@@ -625,8 +739,8 @@
}
void testGetBiggestClient() {
- MediaResource::Type type = MediaResource::kGraphicMemory;
- sp<IResourceManagerClient> client;
+ MediaResource::Type type = MediaResource::Type::kGraphicMemory;
+ std::shared_ptr<IResourceManagerClient> client;
EXPECT_FALSE(mService->getBiggestClient_l(kTestPid2, type, &client));
addResource();
@@ -647,8 +761,8 @@
EXPECT_EQ(EventType::VIDEO_RESET, mSystemCB->lastEventType());
// new client request should cause VIDEO_ON
- Vector<MediaResource> resources1;
- resources1.push_back(MediaResource(MediaResource::kBattery, MediaResource::kVideoCodec, 1));
+ std::vector<MediaResourceParcel> resources1;
+ resources1.push_back(MediaResource(MediaResource::Type::kBattery, MediaResource::SubType::kVideoCodec, 1));
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
EXPECT_EQ(2u, mSystemCB->eventCount());
EXPECT_EQ(EventEntry({EventType::VIDEO_ON, kTestUid1}), mSystemCB->lastEvent());
@@ -658,8 +772,8 @@
EXPECT_EQ(2u, mSystemCB->eventCount());
// new client request should cause VIDEO_ON
- Vector<MediaResource> resources2;
- resources2.push_back(MediaResource(MediaResource::kBattery, MediaResource::kVideoCodec, 2));
+ std::vector<MediaResourceParcel> resources2;
+ resources2.push_back(MediaResource(MediaResource::Type::kBattery, MediaResource::SubType::kVideoCodec, 2));
mService->addResource(kTestPid2, kTestUid2, getId(mTestClient2), mTestClient2, resources2);
EXPECT_EQ(3u, mSystemCB->eventCount());
EXPECT_EQ(EventEntry({EventType::VIDEO_ON, kTestUid2}), mSystemCB->lastEvent());
@@ -686,8 +800,8 @@
EXPECT_EQ(EventType::VIDEO_RESET, mSystemCB->lastEventType());
// new client request should cause CPUSET_ENABLE
- Vector<MediaResource> resources1;
- resources1.push_back(MediaResource(MediaResource::kCpuBoost, 1));
+ std::vector<MediaResourceParcel> resources1;
+ resources1.push_back(MediaResource(MediaResource::Type::kCpuBoost, 1));
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
EXPECT_EQ(2u, mSystemCB->eventCount());
EXPECT_EQ(EventType::CPUSET_ENABLE, mSystemCB->lastEventType());
@@ -697,8 +811,8 @@
EXPECT_EQ(2u, mSystemCB->eventCount());
// new client request should cause CPUSET_ENABLE
- Vector<MediaResource> resources2;
- resources2.push_back(MediaResource(MediaResource::kCpuBoost, 2));
+ std::vector<MediaResourceParcel> resources2;
+ resources2.push_back(MediaResource(MediaResource::Type::kCpuBoost, 2));
mService->addResource(kTestPid2, kTestUid2, getId(mTestClient2), mTestClient2, resources2);
EXPECT_EQ(3u, mSystemCB->eventCount());
EXPECT_EQ(EventType::CPUSET_ENABLE, mSystemCB->lastEventType());
@@ -719,10 +833,10 @@
}
sp<TestSystemCallback> mSystemCB;
- sp<ResourceManagerService> mService;
- sp<IResourceManagerClient> mTestClient1;
- sp<IResourceManagerClient> mTestClient2;
- sp<IResourceManagerClient> mTestClient3;
+ std::shared_ptr<ResourceManagerService> mService;
+ std::shared_ptr<IResourceManagerClient> mTestClient1;
+ std::shared_ptr<IResourceManagerClient> mTestClient2;
+ std::shared_ptr<IResourceManagerClient> mTestClient3;
};
TEST_F(ResourceManagerServiceTest, config) {
@@ -737,6 +851,10 @@
testCombineResource();
}
+TEST_F(ResourceManagerServiceTest, combineResourceNegative) {
+ testCombineResourceWithNegativeValues();
+}
+
TEST_F(ResourceManagerServiceTest, removeResource) {
testRemoveResource();
}
@@ -778,4 +896,8 @@
testCpusetBoost();
}
+TEST_F(ResourceManagerServiceTest, overridePid) {
+ testOverridePid();
+}
+
} // namespace android
diff --git a/services/mediatranscoding/.clang-format b/services/mediatranscoding/.clang-format
new file mode 100644
index 0000000..f14cc88
--- /dev/null
+++ b/services/mediatranscoding/.clang-format
@@ -0,0 +1,33 @@
+---
+BasedOnStyle: Google
+AllowShortFunctionsOnASingleLine: Inline
+AllowShortIfStatementsOnASingleLine: true
+AllowShortLoopsOnASingleLine: true
+BinPackArguments: true
+BinPackParameters: true
+CommentPragmas: NOLINT:.*
+ContinuationIndentWidth: 8
+DerivePointerAlignment: false
+IndentWidth: 4
+PointerAlignment: Left
+TabWidth: 4
+
+# Deviations from the above file:
+# "Don't indent the section label"
+AccessModifierOffset: -4
+# "Each line of text in your code should be at most 100 columns long."
+ColumnLimit: 100
+# "Constructor initializer lists can be all on one line or with subsequent
+# lines indented eight spaces.". clang-format does not support having the colon
+# on the same line as the constructor function name, so this is the best
+# approximation of that rule, which makes all entries in the list (except the
+# first one) have an eight space indentation.
+ConstructorInitializerIndentWidth: 6
+# There is nothing in go/droidcppstyle about case labels, but there seems to be
+# more code that does not indent the case labels in frameworks/base.
+IndentCaseLabels: false
+# There have been some bugs in which subsequent formatting operations introduce
+# weird comment jumps.
+ReflowComments: false
+# Android does support C++11 now.
+Standard: Cpp11
\ No newline at end of file
diff --git a/services/mediatranscoding/Android.bp b/services/mediatranscoding/Android.bp
new file mode 100644
index 0000000..17347a9
--- /dev/null
+++ b/services/mediatranscoding/Android.bp
@@ -0,0 +1,65 @@
+// service library
+cc_library_shared {
+ name: "libmediatranscodingservice",
+
+ srcs: ["MediaTranscodingService.cpp"],
+
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "liblog",
+ "libmediatranscoding",
+ "libutils",
+ ],
+
+ static_libs: [
+ "mediatranscoding_aidl_interface-ndk_platform",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+}
+
+cc_binary {
+ name: "mediatranscoding",
+
+ srcs: [
+ "main_mediatranscodingservice.cpp",
+ ],
+
+ shared_libs: [
+ "libbase",
+ // TODO(hkuang): Use libbinder_ndk
+ "libbinder",
+ "libutils",
+ "liblog",
+ "libbase",
+ "libmediatranscoding",
+ "libmediatranscodingservice",
+ ],
+
+ static_libs: [
+ "mediatranscoding_aidl_interface-ndk_platform",
+ ],
+
+ target: {
+ android: {
+ product_variables: {
+ malloc_not_svelte: {
+ // Scudo increases memory footprint, so only enable on
+ // non-svelte devices.
+ shared_libs: ["libc_scudo"],
+ },
+ },
+ },
+ },
+
+ init_rc: ["mediatranscoding.rc"],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+}
diff --git a/media/libmediaplayer2/nuplayer2/MODULE_LICENSE_APACHE2 b/services/mediatranscoding/MODULE_LICENSE_APACHE2
similarity index 100%
rename from media/libmediaplayer2/nuplayer2/MODULE_LICENSE_APACHE2
rename to services/mediatranscoding/MODULE_LICENSE_APACHE2
diff --git a/services/mediatranscoding/MediaTranscodingService.cpp b/services/mediatranscoding/MediaTranscodingService.cpp
new file mode 100644
index 0000000..82d4161
--- /dev/null
+++ b/services/mediatranscoding/MediaTranscodingService.cpp
@@ -0,0 +1,198 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaTranscodingService"
+#include <MediaTranscodingService.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <private/android_filesystem_config.h>
+#include <utils/Log.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+// Convenience methods for constructing binder::Status objects for error returns
+#define STATUS_ERROR_FMT(errorCode, errorString, ...) \
+ Status::fromServiceSpecificErrorWithMessage( \
+ errorCode, \
+ String8::format("%s:%d: " errorString, __FUNCTION__, __LINE__, ##__VA_ARGS__))
+
+// Can MediaTranscoding service trust the caller based on the calling UID?
+// TODO(hkuang): Add MediaProvider's UID.
+static bool isTrustedCallingUid(uid_t uid) {
+ switch (uid) {
+ case AID_ROOT: // root user
+ case AID_SYSTEM:
+ case AID_SHELL:
+ case AID_MEDIA: // mediaserver
+ return true;
+ default:
+ return false;
+ }
+}
+
+MediaTranscodingService::MediaTranscodingService()
+ : mTranscodingClientManager(TranscodingClientManager::getInstance()) {
+ ALOGV("MediaTranscodingService is created");
+}
+
+MediaTranscodingService::~MediaTranscodingService() {
+ ALOGE("Should not be in ~MediaTranscodingService");
+}
+
+binder_status_t MediaTranscodingService::dump(int fd, const char** /*args*/, uint32_t /*numArgs*/) {
+ String8 result;
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, "MediaTranscodingService: %p\n", this);
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+
+ Vector<String16> args;
+ mTranscodingClientManager.dumpAllClients(fd, args);
+ return OK;
+}
+
+//static
+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;
+ }
+}
+
+Status MediaTranscodingService::registerClient(
+ const std::shared_ptr<ITranscodingServiceClient>& in_client,
+ const std::string& in_opPackageName, int32_t in_clientUid, int32_t in_clientPid,
+ int32_t* _aidl_return) {
+ if (in_client == nullptr) {
+ ALOGE("Client can not be null");
+ *_aidl_return = kInvalidJobId;
+ return Status::fromServiceSpecificError(ERROR_ILLEGAL_ARGUMENT);
+ }
+
+ int32_t callingPid = AIBinder_getCallingPid();
+ int32_t callingUid = AIBinder_getCallingUid();
+
+ // Check if we can trust clientUid. Only privilege caller could forward the uid on app client's behalf.
+ if (in_clientUid == USE_CALLING_UID) {
+ in_clientUid = callingUid;
+ } else if (!isTrustedCallingUid(callingUid)) {
+ ALOGE("MediaTranscodingService::registerClient failed (calling PID %d, calling UID %d) "
+ "rejected "
+ "(don't trust clientUid %d)",
+ in_clientPid, in_clientUid, in_clientUid);
+ return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
+ "Untrusted caller (calling PID %d, UID %d) trying to "
+ "register client",
+ in_clientPid, in_clientUid);
+ }
+
+ // Check if we can trust clientPid. Only privilege caller could forward the pid on app client's behalf.
+ if (in_clientPid == USE_CALLING_PID) {
+ in_clientPid = callingPid;
+ } else if (!isTrustedCallingUid(callingUid)) {
+ ALOGE("MediaTranscodingService::registerClient client failed (calling PID %d, calling UID "
+ "%d) rejected "
+ "(don't trust clientPid %d)",
+ in_clientPid, in_clientUid, in_clientPid);
+ return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
+ "Untrusted caller (calling PID %d, UID %d) trying to "
+ "register client",
+ in_clientPid, in_clientUid);
+ }
+
+ // We know the clientId must be equal to its pid as we assigned client's pid as its clientId.
+ int32_t clientId = in_clientPid;
+
+ // Checks if the client already registers.
+ if (mTranscodingClientManager.isClientIdRegistered(clientId)) {
+ return Status::fromServiceSpecificError(ERROR_ALREADY_EXISTS);
+ }
+
+ // Creates the client and uses its process id as client id.
+ std::unique_ptr<TranscodingClientManager::ClientInfo> newClient =
+ std::make_unique<TranscodingClientManager::ClientInfo>(
+ in_client, clientId, in_clientPid, in_clientUid, in_opPackageName);
+ status_t err = mTranscodingClientManager.addClient(std::move(newClient));
+ if (err != OK) {
+ *_aidl_return = kInvalidClientId;
+ return STATUS_ERROR_FMT(err, "Failed to add client to TranscodingClientManager");
+ }
+
+ ALOGD("Assign client: %s pid: %d, uid: %d with id: %d", in_opPackageName.c_str(), in_clientPid,
+ in_clientUid, clientId);
+
+ *_aidl_return = clientId;
+ return Status::ok();
+}
+
+Status MediaTranscodingService::unregisterClient(int32_t clientId, bool* _aidl_return) {
+ ALOGD("unregisterClient id: %d", clientId);
+ int32_t callingUid = AIBinder_getCallingUid();
+ int32_t callingPid = AIBinder_getCallingPid();
+
+ // Only the client with clientId or the trusted caller could unregister the client.
+ if (callingPid != clientId) {
+ if (!isTrustedCallingUid(callingUid)) {
+ ALOGE("Untrusted caller (calling PID %d, UID %d) trying to "
+ "unregister client with id: %d",
+ callingUid, callingPid, clientId);
+ *_aidl_return = true;
+ return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
+ "Untrusted caller (calling PID %d, UID %d) trying to "
+ "unregister client with id: %d",
+ callingUid, callingPid, clientId);
+ }
+ }
+
+ *_aidl_return = (mTranscodingClientManager.removeClient(clientId) == OK);
+ return Status::ok();
+}
+
+Status MediaTranscodingService::getNumOfClients(int32_t* _aidl_return) {
+ ALOGD("MediaTranscodingService::getNumOfClients");
+ *_aidl_return = mTranscodingClientManager.getNumOfClients();
+ return Status::ok();
+}
+
+Status MediaTranscodingService::submitRequest(int32_t /*clientId*/,
+ const TranscodingRequestParcel& /*request*/,
+ TranscodingJobParcel* /*job*/,
+ int32_t* /*_aidl_return*/) {
+ // TODO(hkuang): Add implementation.
+ return Status::ok();
+}
+
+Status MediaTranscodingService::cancelJob(int32_t /*in_clientId*/, int32_t /*in_jobId*/,
+ bool* /*_aidl_return*/) {
+ // TODO(hkuang): Add implementation.
+ return Status::ok();
+}
+
+Status MediaTranscodingService::getJobWithId(int32_t /*in_jobId*/,
+ TranscodingJobParcel* /*out_job*/,
+ bool* /*_aidl_return*/) {
+ // TODO(hkuang): Add implementation.
+ return Status::ok();
+}
+
+} // namespace android
diff --git a/services/mediatranscoding/MediaTranscodingService.h b/services/mediatranscoding/MediaTranscodingService.h
new file mode 100644
index 0000000..cc69727
--- /dev/null
+++ b/services/mediatranscoding/MediaTranscodingService.h
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_MEDIA_TRANSCODING_SERVICE_H
+#define ANDROID_MEDIA_TRANSCODING_SERVICE_H
+
+#include <aidl/android/media/BnMediaTranscodingService.h>
+#include <binder/IServiceManager.h>
+#include <media/TranscodingClientManager.h>
+
+namespace android {
+
+using Status = ::ndk::ScopedAStatus;
+using ::aidl::android::media::BnMediaTranscodingService;
+using ::aidl::android::media::ITranscodingServiceClient;
+using ::aidl::android::media::TranscodingJobParcel;
+using ::aidl::android::media::TranscodingRequestParcel;
+
+class MediaTranscodingService : public BnMediaTranscodingService {
+public:
+ static constexpr int32_t kInvalidJobId = -1;
+ static constexpr int32_t kInvalidClientId = -1;
+
+ MediaTranscodingService();
+ virtual ~MediaTranscodingService();
+
+ static void instantiate();
+
+ static const char* getServiceName() { return "media.transcoding"; }
+
+ Status registerClient(const std::shared_ptr<ITranscodingServiceClient>& in_client,
+ const std::string& in_opPackageName, int32_t in_clientUid,
+ int32_t in_clientPid, int32_t* _aidl_return) override;
+
+ Status unregisterClient(int32_t clientId, bool* _aidl_return) override;
+
+ Status getNumOfClients(int32_t* _aidl_return) override;
+
+ Status submitRequest(int32_t in_clientId, const TranscodingRequestParcel& in_request,
+ TranscodingJobParcel* out_job, int32_t* _aidl_return) override;
+
+ Status cancelJob(int32_t in_clientId, int32_t in_jobId, bool* _aidl_return) override;
+
+ Status getJobWithId(int32_t in_jobId, TranscodingJobParcel* out_job,
+ bool* _aidl_return) override;
+
+ virtual inline binder_status_t dump(int /*fd*/, const char** /*args*/, uint32_t /*numArgs*/);
+
+private:
+ friend class MediaTranscodingServiceTest;
+
+ mutable std::mutex mServiceLock;
+
+ TranscodingClientManager& mTranscodingClientManager;
+};
+
+} // namespace android
+
+#endif // ANDROID_MEDIA_TRANSCODING_SERVICE_H
diff --git a/services/mediatranscoding/NOTICE b/services/mediatranscoding/NOTICE
new file mode 100644
index 0000000..9f46052
--- /dev/null
+++ b/services/mediatranscoding/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-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.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/services/mediatranscoding/OWNERS b/services/mediatranscoding/OWNERS
new file mode 100644
index 0000000..825c586
--- /dev/null
+++ b/services/mediatranscoding/OWNERS
@@ -0,0 +1,4 @@
+akersten@google.com
+hkuang@google.com
+lnilsson@google.com
+
diff --git a/services/mediatranscoding/main_mediatranscodingservice.cpp b/services/mediatranscoding/main_mediatranscodingservice.cpp
new file mode 100644
index 0000000..7d862e6
--- /dev/null
+++ b/services/mediatranscoding/main_mediatranscodingservice.cpp
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+#include <android-base/logging.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+
+#include "MediaTranscodingService.h"
+
+using namespace android;
+
+int main(int argc __unused, char** argv) {
+ LOG(INFO) << "media transcoding service starting";
+
+ // TODO(hkuang): Start the service with libbinder_ndk.
+ strcpy(argv[0], "media.transcoding");
+ sp<ProcessState> proc(ProcessState::self());
+ sp<IServiceManager> sm = defaultServiceManager();
+ android::MediaTranscodingService::instantiate();
+
+ ProcessState::self()->startThreadPool();
+ IPCThreadState::self()->joinThreadPool();
+}
diff --git a/services/mediatranscoding/mediatranscoding.rc b/services/mediatranscoding/mediatranscoding.rc
new file mode 100644
index 0000000..2dc547f
--- /dev/null
+++ b/services/mediatranscoding/mediatranscoding.rc
@@ -0,0 +1,6 @@
+service media.transcoding /system/bin/mediatranscoding
+ class main
+ user media
+ group media
+ ioprio rt 4
+ writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
diff --git a/services/mediatranscoding/tests/Android.bp b/services/mediatranscoding/tests/Android.bp
new file mode 100644
index 0000000..e0e040c
--- /dev/null
+++ b/services/mediatranscoding/tests/Android.bp
@@ -0,0 +1,35 @@
+// Build the unit tests for MediaTranscodingService
+
+cc_defaults {
+ name: "mediatranscodingservice_test_defaults",
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+
+ include_dirs: [
+ "frameworks/av/services/mediatranscoding",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "libbinder_ndk",
+ "liblog",
+ "libutils",
+ "libmediatranscodingservice",
+ ],
+
+ static_libs: [
+ "mediatranscoding_aidl_interface-ndk_platform",
+ ],
+}
+
+// MediaTranscodingService unit test
+cc_test {
+ name: "mediatranscodingservice_tests",
+ defaults: ["mediatranscodingservice_test_defaults"],
+
+ srcs: ["mediatranscodingservice_tests.cpp"],
+}
\ No newline at end of file
diff --git a/services/mediatranscoding/tests/build_and_run_all_unit_tests.sh b/services/mediatranscoding/tests/build_and_run_all_unit_tests.sh
new file mode 100644
index 0000000..bcdc7f7
--- /dev/null
+++ b/services/mediatranscoding/tests/build_and_run_all_unit_tests.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+#
+# Run tests in this directory.
+#
+
+if [ -z "$ANDROID_BUILD_TOP" ]; then
+ echo "Android build environment not set"
+ exit -1
+fi
+
+# ensure we have mm
+. $ANDROID_BUILD_TOP/build/envsetup.sh
+
+mm
+
+echo "waiting for device"
+
+adb root && adb wait-for-device remount && adb sync
+
+echo "========================================"
+
+echo "testing mediatranscodingservice"
+adb shell /data/nativetest64/mediatranscodingservice_tests/mediatranscodingservice_tests
diff --git a/services/mediatranscoding/tests/mediatranscodingservice_tests.cpp b/services/mediatranscoding/tests/mediatranscodingservice_tests.cpp
new file mode 100644
index 0000000..5a791fe
--- /dev/null
+++ b/services/mediatranscoding/tests/mediatranscodingservice_tests.cpp
@@ -0,0 +1,239 @@
+/*
+ * 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.
+ */
+
+// Unit Test for MediaTranscoding Service.
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaTranscodingServiceTest"
+
+#include <aidl/android/media/BnTranscodingServiceClient.h>
+#include <aidl/android/media/IMediaTranscodingService.h>
+#include <aidl/android/media/ITranscodingServiceClient.h>
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <android/binder_ibinder_jni.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <cutils/ashmem.h>
+#include <gtest/gtest.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <utils/Log.h>
+
+namespace android {
+
+namespace media {
+
+using Status = ::ndk::ScopedAStatus;
+using aidl::android::media::BnTranscodingServiceClient;
+using aidl::android::media::IMediaTranscodingService;
+using aidl::android::media::ITranscodingServiceClient;
+
+constexpr int32_t kInvalidClientId = -5;
+
+// Note that -1 is valid and means using calling pid/uid for the service. But only privilege caller could
+// use them. This test is not a privilege caller.
+constexpr int32_t kInvalidClientPid = -5;
+constexpr int32_t kInvalidClientUid = -5;
+constexpr const char* kInvalidClientOpPackageName = "";
+
+constexpr int32_t kClientUseCallingPid = -1;
+constexpr int32_t kClientUseCallingUid = -1;
+constexpr const char* kClientOpPackageName = "TestClient";
+
+class MediaTranscodingServiceTest : public ::testing::Test {
+public:
+ MediaTranscodingServiceTest() { ALOGD("MediaTranscodingServiceTest created"); }
+
+ void SetUp() override {
+ ::ndk::SpAIBinder binder(AServiceManager_getService("media.transcoding"));
+ mService = IMediaTranscodingService::fromBinder(binder);
+ if (mService == nullptr) {
+ ALOGE("Failed to connect to the media.trascoding service.");
+ return;
+ }
+ }
+
+ ~MediaTranscodingServiceTest() { ALOGD("MediaTranscodingingServiceTest destroyed"); }
+
+ std::shared_ptr<IMediaTranscodingService> mService = nullptr;
+};
+
+struct TestClient : public BnTranscodingServiceClient {
+ TestClient(const std::shared_ptr<IMediaTranscodingService>& service) : mService(service) {
+ ALOGD("TestClient Created");
+ }
+
+ Status getName(std::string* _aidl_return) override {
+ *_aidl_return = "test_client";
+ return Status::ok();
+ }
+
+ Status onTranscodingFinished(
+ int32_t /* in_jobId */,
+ const ::aidl::android::media::TranscodingResultParcel& /* in_result */) override {
+ return Status::ok();
+ }
+
+ Status onTranscodingFailed(
+ int32_t /* in_jobId */,
+ ::aidl::android::media::TranscodingErrorCode /*in_errorCode */) override {
+ return Status::ok();
+ }
+
+ Status onAwaitNumberOfJobsChanged(int32_t /* in_jobId */, int32_t /* in_oldAwaitNumber */,
+ int32_t /* in_newAwaitNumber */) override {
+ return Status::ok();
+ }
+
+ Status onProgressUpdate(int32_t /* in_jobId */, int32_t /* in_progress */) override {
+ return Status::ok();
+ }
+
+ virtual ~TestClient() { ALOGI("TestClient destroyed"); };
+
+private:
+ std::shared_ptr<IMediaTranscodingService> mService;
+};
+
+TEST_F(MediaTranscodingServiceTest, TestRegisterNullClient) {
+ std::shared_ptr<ITranscodingServiceClient> client = nullptr;
+ int32_t clientId = 0;
+ Status status = mService->registerClient(client, kClientOpPackageName, kClientUseCallingUid,
+ kClientUseCallingPid, &clientId);
+ EXPECT_FALSE(status.isOk());
+}
+
+TEST_F(MediaTranscodingServiceTest, TestRegisterClientWithInvalidClientPid) {
+ std::shared_ptr<ITranscodingServiceClient> client =
+ ::ndk::SharedRefBase::make<TestClient>(mService);
+ EXPECT_TRUE(client != nullptr);
+
+ // Register the client with the service.
+ int32_t clientId = 0;
+ Status status = mService->registerClient(client, kClientOpPackageName, kClientUseCallingUid,
+ kInvalidClientPid, &clientId);
+ EXPECT_FALSE(status.isOk());
+}
+
+TEST_F(MediaTranscodingServiceTest, TestRegisterClientWithInvalidClientUid) {
+ std::shared_ptr<ITranscodingServiceClient> client =
+ ::ndk::SharedRefBase::make<TestClient>(mService);
+ EXPECT_TRUE(client != nullptr);
+
+ // Register the client with the service.
+ int32_t clientId = 0;
+ Status status = mService->registerClient(client, kClientOpPackageName, kInvalidClientUid,
+ kClientUseCallingPid, &clientId);
+ EXPECT_FALSE(status.isOk());
+}
+
+TEST_F(MediaTranscodingServiceTest, TestRegisterClientWithInvalidClientPackageName) {
+ std::shared_ptr<ITranscodingServiceClient> client =
+ ::ndk::SharedRefBase::make<TestClient>(mService);
+ EXPECT_TRUE(client != nullptr);
+
+ // Register the client with the service.
+ int32_t clientId = 0;
+ Status status = mService->registerClient(client, kInvalidClientOpPackageName,
+ kClientUseCallingUid, kClientUseCallingPid, &clientId);
+ EXPECT_FALSE(status.isOk());
+}
+
+TEST_F(MediaTranscodingServiceTest, TestRegisterOneClient) {
+ std::shared_ptr<ITranscodingServiceClient> client =
+ ::ndk::SharedRefBase::make<TestClient>(mService);
+ EXPECT_TRUE(client != nullptr);
+
+ // Register the client with the service.
+ int32_t clientId = 0;
+ Status status = mService->registerClient(client, kClientOpPackageName, kClientUseCallingPid,
+ kClientUseCallingUid, &clientId);
+ ALOGD("client id is %d", clientId);
+ EXPECT_TRUE(status.isOk());
+
+ // Validate the clientId.
+ EXPECT_TRUE(clientId > 0);
+
+ // Check the number of Clients.
+ int32_t numOfClients;
+ status = mService->getNumOfClients(&numOfClients);
+ EXPECT_TRUE(status.isOk());
+ EXPECT_EQ(1, numOfClients);
+
+ // Unregister the client.
+ bool res;
+ status = mService->unregisterClient(clientId, &res);
+ EXPECT_TRUE(status.isOk());
+ EXPECT_TRUE(res);
+}
+
+TEST_F(MediaTranscodingServiceTest, TestUnRegisterClientWithInvalidClientId) {
+ std::shared_ptr<ITranscodingServiceClient> client =
+ ::ndk::SharedRefBase::make<TestClient>(mService);
+ EXPECT_TRUE(client != nullptr);
+
+ // Register the client with the service.
+ int32_t clientId = 0;
+ Status status = mService->registerClient(client, kClientOpPackageName, kClientUseCallingUid,
+ kClientUseCallingPid, &clientId);
+ ALOGD("client id is %d", clientId);
+ EXPECT_TRUE(status.isOk());
+
+ // Validate the clientId.
+ EXPECT_TRUE(clientId > 0);
+
+ // Check the number of Clients.
+ int32_t numOfClients;
+ status = mService->getNumOfClients(&numOfClients);
+ EXPECT_TRUE(status.isOk());
+ EXPECT_EQ(1, numOfClients);
+
+ // Unregister the client with invalid ID
+ bool res;
+ mService->unregisterClient(kInvalidClientId, &res);
+ EXPECT_FALSE(res);
+
+ // Unregister the valid client.
+ mService->unregisterClient(clientId, &res);
+}
+
+TEST_F(MediaTranscodingServiceTest, TestRegisterClientTwice) {
+ std::shared_ptr<ITranscodingServiceClient> client =
+ ::ndk::SharedRefBase::make<TestClient>(mService);
+ EXPECT_TRUE(client != nullptr);
+
+ // Register the client with the service.
+ int32_t clientId = 0;
+ Status status = mService->registerClient(client, kClientOpPackageName, kClientUseCallingUid,
+ kClientUseCallingPid, &clientId);
+ EXPECT_TRUE(status.isOk());
+
+ // Validate the clientId.
+ EXPECT_TRUE(clientId > 0);
+
+ // Register the client again and expects failure.
+ status = mService->registerClient(client, kClientOpPackageName, kClientUseCallingUid,
+ kClientUseCallingPid, &clientId);
+ EXPECT_FALSE(status.isOk());
+
+ // Unregister the valid client.
+ bool res;
+ mService->unregisterClient(clientId, &res);
+}
+
+} // namespace media
+} // namespace android
diff --git a/services/minijail/Android.bp b/services/minijail/Android.bp
index 07a94cc..0713a87 100644
--- a/services/minijail/Android.bp
+++ b/services/minijail/Android.bp
@@ -17,10 +17,14 @@
cc_library_shared {
name: "libavservices_minijail",
defaults: ["libavservices_minijail_defaults"],
+ vendor_available: true,
export_include_dirs: ["."],
}
-// Small library for media.extractor and media.codec sandboxing.
+// By adding "vendor_available: true" to "libavservices_minijail", we don't
+// need to have "libavservices_minijail_vendor" any longer.
+// "libavservices_minijail_vendor" will be removed, once we replace it with
+// "libavservices_minijail" in all vendor modules. (b/146313710)
cc_library_shared {
name: "libavservices_minijail_vendor",
vendor: true,
diff --git a/services/oboeservice/AAudioClientTracker.cpp b/services/oboeservice/AAudioClientTracker.cpp
index 8572561..6e14434 100644
--- a/services/oboeservice/AAudioClientTracker.cpp
+++ b/services/oboeservice/AAudioClientTracker.cpp
@@ -75,10 +75,10 @@
std::lock_guard<std::mutex> lock(mLock);
if (mNotificationClients.count(pid) == 0) {
- sp<NotificationClient> notificationClient = new NotificationClient(pid);
+ sp<IBinder> binder = IInterface::asBinder(client);
+ sp<NotificationClient> notificationClient = new NotificationClient(pid, binder);
mNotificationClients[pid] = notificationClient;
- sp<IBinder> binder = IInterface::asBinder(client);
status_t status = binder->linkToDeath(notificationClient);
ALOGW_IF(status != NO_ERROR, "registerClient() linkToDeath = %d\n", status);
return AAudioConvert_androidToAAudioResult(status);
@@ -113,7 +113,7 @@
if (notificationClient == 0) {
// This will get called the first time the audio server registers an internal stream.
ALOGV("registerClientStream(%d,) unrecognized pid\n", pid);
- notificationClient = new NotificationClient(pid);
+ notificationClient = new NotificationClient(pid, nullptr);
mNotificationClients[pid] = notificationClient;
}
notificationClient->registerClientStream(serviceStream);
@@ -136,8 +136,8 @@
return AAUDIO_OK;
}
-AAudioClientTracker::NotificationClient::NotificationClient(pid_t pid)
- : mProcessId(pid) {
+AAudioClientTracker::NotificationClient::NotificationClient(pid_t pid, const sp<IBinder>& binder)
+ : mProcessId(pid), mBinder(binder) {
}
AAudioClientTracker::NotificationClient::~NotificationClient() {
diff --git a/services/oboeservice/AAudioClientTracker.h b/services/oboeservice/AAudioClientTracker.h
index accf1a7..00ff467 100644
--- a/services/oboeservice/AAudioClientTracker.h
+++ b/services/oboeservice/AAudioClientTracker.h
@@ -73,7 +73,7 @@
*/
class NotificationClient : public IBinder::DeathRecipient {
public:
- NotificationClient(pid_t pid);
+ NotificationClient(pid_t pid, const android::sp<IBinder>& binder);
virtual ~NotificationClient();
int32_t getStreamCount();
@@ -91,6 +91,8 @@
mutable std::mutex mLock;
const pid_t mProcessId;
std::set<android::sp<AAudioServiceStreamBase>> mStreams;
+ // hold onto binder to receive death notifications
+ android::sp<IBinder> mBinder;
};
mutable std::mutex mLock;
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index a1fc0ea..82cc90e 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -284,7 +284,7 @@
serviceEndpoint->close();
mSharedCloseCount++;
- ALOGV("%s() %p for device %d",
+ ALOGV("%s(%p) closed for device %d",
__func__, serviceEndpoint.get(), serviceEndpoint->getDeviceId());
}
}
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index e6a8375..af8c67b3 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -78,6 +78,11 @@
AAudioClientTracker::getInstance().registerClient(pid, client);
}
+bool AAudioService::isCallerInService() {
+ return mAudioClient.clientPid == IPCThreadState::self()->getCallingPid() &&
+ mAudioClient.clientUid == IPCThreadState::self()->getCallingUid();
+}
+
aaudio_handle_t AAudioService::openStream(const aaudio::AAudioStreamRequest &request,
aaudio::AAudioStreamConfiguration &configurationOutput) {
aaudio_result_t result = AAUDIO_OK;
@@ -105,8 +110,7 @@
if (sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE) {
// only trust audioserver for in service indication
bool inService = false;
- if (mAudioClient.clientPid == IPCThreadState::self()->getCallingPid() &&
- mAudioClient.clientUid == IPCThreadState::self()->getCallingUid()) {
+ if (isCallerInService()) {
inService = request.isInService();
}
serviceStream = new AAudioServiceStreamMMAP(*this, inService);
@@ -274,12 +278,14 @@
result = AAUDIO_ERROR_INVALID_STATE;
} else {
const pid_t ownerPid = IPCThreadState::self()->getCallingPid(); // TODO review
+ int32_t priority = isCallerInService()
+ ? kRealTimeAudioPriorityService : kRealTimeAudioPriorityClient;
serviceStream->setRegisteredThread(clientThreadId);
int err = android::requestPriority(ownerPid, clientThreadId,
- DEFAULT_AUDIO_PRIORITY, true /* isForApp */);
+ priority, true /* isForApp */);
if (err != 0) {
ALOGE("AAudioService::registerAudioThread(%d) failed, errno = %d, priority = %d",
- clientThreadId, errno, DEFAULT_AUDIO_PRIORITY);
+ clientThreadId, errno, priority);
result = AAUDIO_ERROR_INTERNAL;
}
}
diff --git a/services/oboeservice/AAudioService.h b/services/oboeservice/AAudioService.h
index d21b1cd..43a59c3 100644
--- a/services/oboeservice/AAudioService.h
+++ b/services/oboeservice/AAudioService.h
@@ -87,6 +87,10 @@
private:
+ /** @return true if the client is the audioserver
+ */
+ bool isCallerInService();
+
/**
* Lookup stream and then validate access to the stream.
* @param streamHandle
@@ -106,9 +110,10 @@
aaudio::AAudioStreamTracker mStreamTracker;
- enum constants {
- DEFAULT_AUDIO_PRIORITY = 2
- };
+ // TODO Extract the priority constants from services/audioflinger/Threads.cpp
+ // and share them with this code. Look for "kPriorityFastMixer".
+ static constexpr int32_t kRealTimeAudioPriorityClient = 2;
+ static constexpr int32_t kRealTimeAudioPriorityService = 3;
};
} /* namespace android */
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index 553754e..2753f1f 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -62,6 +62,7 @@
result << " InputPreset: " << getInputPreset() << "\n";
result << " Reference Count: " << mOpenCount << "\n";
result << " Session Id: " << getSessionId() << "\n";
+ result << " Privacy Sensitive: " << isPrivacySensitive() << "\n";
result << " Connected: " << mConnected.load() << "\n";
result << " Registered Streams:" << "\n";
result << AAudioServiceStreamShared::dumpHeader() << "\n";
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index b05baa4..5bdb8eb 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -90,9 +90,14 @@
const audio_source_t source = (direction == AAUDIO_DIRECTION_INPUT)
? AAudioConvert_inputPresetToAudioSource(getInputPreset())
: AUDIO_SOURCE_DEFAULT;
- const audio_flags_mask_t flags = AUDIO_FLAG_LOW_LATENCY |
- AAudioConvert_allowCapturePolicyToAudioFlagsMask(getAllowedCapturePolicy());
-
+ audio_flags_mask_t flags;
+ if (direction == AAUDIO_DIRECTION_OUTPUT) {
+ flags = AUDIO_FLAG_LOW_LATENCY
+ | AAudioConvert_allowCapturePolicyToAudioFlagsMask(getAllowedCapturePolicy());
+ } else {
+ flags = AUDIO_FLAG_LOW_LATENCY
+ | AAudioConvert_privacySensitiveToAudioFlagsMask(isPrivacySensitive());
+ }
const audio_attributes_t attributes = {
.content_type = contentType,
.usage = usage,
diff --git a/services/oboeservice/AAudioServiceEndpointShared.cpp b/services/oboeservice/AAudioServiceEndpointShared.cpp
index 0a415fd..9b3b3b8 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.cpp
+++ b/services/oboeservice/AAudioServiceEndpointShared.cpp
@@ -85,7 +85,7 @@
}
aaudio_result_t AAudioServiceEndpointShared::close() {
- return getStreamInternal()->close();
+ return getStreamInternal()->releaseCloseFinal();
}
// Glue between C and C++ callbacks.
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index 880a3d7..39e90b1 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -56,7 +56,8 @@
LOG_ALWAYS_FATAL_IF(!(getState() == AAUDIO_STREAM_STATE_CLOSED
|| getState() == AAUDIO_STREAM_STATE_UNINITIALIZED
|| getState() == AAUDIO_STREAM_STATE_DISCONNECTED),
- "service stream still open, state = %d", getState());
+ "service stream %p still open, state = %d",
+ this, getState());
}
std::string AAudioServiceStreamBase::dumpHeader() {
@@ -126,13 +127,13 @@
}
aaudio_result_t AAudioServiceStreamBase::close() {
- aaudio_result_t result = AAUDIO_OK;
if (getState() == AAUDIO_STREAM_STATE_CLOSED) {
return AAUDIO_OK;
}
stop();
+ aaudio_result_t result = AAUDIO_OK;
sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
if (endpoint == nullptr) {
result = AAUDIO_ERROR_INVALID_STATE;
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.cpp b/services/oboeservice/AAudioServiceStreamMMAP.cpp
index 837b080..f4e72b7 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.cpp
+++ b/services/oboeservice/AAudioServiceStreamMMAP.cpp
@@ -49,16 +49,6 @@
, mInService(inService) {
}
-aaudio_result_t AAudioServiceStreamMMAP::close() {
- if (getState() == AAUDIO_STREAM_STATE_CLOSED) {
- return AAUDIO_OK;
- }
-
- stop();
-
- return AAudioServiceStreamBase::close();
-}
-
// Open stream on HAL and pass information about the shared memory buffer back to the client.
aaudio_result_t AAudioServiceStreamMMAP::open(const aaudio::AAudioStreamRequest &request) {
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.h b/services/oboeservice/AAudioServiceStreamMMAP.h
index 1509f7d..3d56623 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.h
+++ b/services/oboeservice/AAudioServiceStreamMMAP.h
@@ -67,8 +67,6 @@
aaudio_result_t stopClient(audio_port_handle_t clientHandle) override;
- aaudio_result_t close() override;
-
const char *getTypeText() const override { return "MMAP"; }
protected:
diff --git a/services/oboeservice/Android.bp b/services/oboeservice/Android.bp
new file mode 100644
index 0000000..64d835b
--- /dev/null
+++ b/services/oboeservice/Android.bp
@@ -0,0 +1,66 @@
+// 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.
+
+cc_library_shared {
+
+ name: "libaaudioservice",
+
+ srcs: [
+ "AAudioClientTracker.cpp",
+ "AAudioEndpointManager.cpp",
+ "AAudioMixer.cpp",
+ "AAudioService.cpp",
+ "AAudioServiceEndpoint.cpp",
+ "AAudioServiceEndpointCapture.cpp",
+ "AAudioServiceEndpointMMAP.cpp",
+ "AAudioServiceEndpointPlay.cpp",
+ "AAudioServiceEndpointShared.cpp",
+ "AAudioServiceStreamBase.cpp",
+ "AAudioServiceStreamMMAP.cpp",
+ "AAudioServiceStreamShared.cpp",
+ "AAudioStreamTracker.cpp",
+ "AAudioThread.cpp",
+ "SharedMemoryProxy.cpp",
+ "SharedRingBuffer.cpp",
+ "TimestampScheduler.cpp",
+ ],
+
+ cflags: [
+ "-Wno-unused-parameter",
+ "-Wall",
+ "-Werror",
+ ],
+
+ shared_libs: [
+ "libaaudio_internal",
+ "libaudioclient",
+ "libaudioflinger",
+ "libaudioutils",
+ "libbase",
+ "libbinder",
+ "libcutils",
+ "liblog",
+ "libmediautils",
+ "libutils",
+ ],
+
+ header_libs: [
+ "libaudiohal_headers",
+ ],
+
+ include_dirs: [
+ "frameworks/av/media/libnbaio/include_mono",
+ "frameworks/av/media/libnbaio/include",
+ ],
+}
diff --git a/services/oboeservice/Android.mk b/services/oboeservice/Android.mk
deleted file mode 100644
index 3d5f140..0000000
--- a/services/oboeservice/Android.mk
+++ /dev/null
@@ -1,61 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# AAudio Service
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libaaudioservice
-LOCAL_MODULE_TAGS := optional
-
-LIBAAUDIO_DIR := ../../media/libaaudio
-LIBAAUDIO_SRC_DIR := $(LIBAAUDIO_DIR)/src
-
-LOCAL_C_INCLUDES := \
- $(TOPDIR)frameworks/av/services/audioflinger \
- $(call include-path-for, audio-utils) \
- frameworks/native/include \
- system/core/base/include \
- $(TOP)/frameworks/native/media/libaaudio/include/include \
- $(TOP)/frameworks/av/media/libaaudio/include \
- $(TOP)/frameworks/av/media/utils/include \
- frameworks/native/include \
- $(TOP)/external/tinyalsa/include \
- $(TOP)/frameworks/av/media/libaaudio/src
-
-LOCAL_SRC_FILES += \
- SharedMemoryProxy.cpp \
- SharedRingBuffer.cpp \
- AAudioClientTracker.cpp \
- AAudioEndpointManager.cpp \
- AAudioMixer.cpp \
- AAudioService.cpp \
- AAudioServiceEndpoint.cpp \
- AAudioServiceEndpointCapture.cpp \
- AAudioServiceEndpointMMAP.cpp \
- AAudioServiceEndpointPlay.cpp \
- AAudioServiceEndpointShared.cpp \
- AAudioServiceStreamBase.cpp \
- AAudioServiceStreamMMAP.cpp \
- AAudioServiceStreamShared.cpp \
- AAudioStreamTracker.cpp \
- TimestampScheduler.cpp \
- AAudioThread.cpp
-
-LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-
-# LOCAL_CFLAGS += -fvisibility=hidden
-LOCAL_CFLAGS += -Wno-unused-parameter
-LOCAL_CFLAGS += -Wall -Werror
-
-LOCAL_SHARED_LIBRARIES := \
- libaaudio \
- libaudioflinger \
- libaudioclient \
- libbinder \
- libcutils \
- libmediautils \
- libutils \
- liblog
-
-include $(BUILD_SHARED_LIBRARY)
-
-
diff --git a/services/soundtrigger/Android.bp b/services/soundtrigger/Android.bp
deleted file mode 100644
index 3f02f48..0000000
--- a/services/soundtrigger/Android.bp
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2014 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.
-
-cc_library_shared {
- name: "libsoundtriggerservice",
-
- srcs: [
- "SoundTriggerHwService.cpp",
- "SoundTriggerHalHidl.cpp",
- ],
-
- shared_libs: [
- "liblog",
- "libutils",
- "libbinder",
- "libcutils",
- "libhardware",
- "libsoundtrigger",
- "libaudioclient",
- "libaudioutils",
- "libmediautils",
-
- "libhwbinder",
- "libhidlbase",
- "libhidlmemory",
- "libhidltransport",
- "libbase",
- "libaudiohal",
- "libaudiohal_deathhandler",
- "android.hardware.soundtrigger@2.0",
- "android.hardware.soundtrigger@2.1",
- "android.hardware.soundtrigger@2.2",
- "android.hardware.audio.common@2.0",
- "android.hidl.allocator@1.0",
- "android.hidl.memory@1.0",
- ],
-
- include_dirs: ["frameworks/av/services/audioflinger"],
-
- cflags: [
- "-Wall",
- "-Werror",
- ],
-}
diff --git a/services/soundtrigger/OWNERS b/services/soundtrigger/OWNERS
deleted file mode 100644
index e83f6b9..0000000
--- a/services/soundtrigger/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-elaurent@google.com
-thorntonc@google.com
diff --git a/services/soundtrigger/SoundTriggerHalHidl.cpp b/services/soundtrigger/SoundTriggerHalHidl.cpp
deleted file mode 100644
index 68d54c7..0000000
--- a/services/soundtrigger/SoundTriggerHalHidl.cpp
+++ /dev/null
@@ -1,839 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "SoundTriggerHalHidl"
-//#define LOG_NDEBUG 0
-
-#include <android/hidl/allocator/1.0/IAllocator.h>
-#include <media/audiohal/hidl/HalDeathHandler.h>
-#include <utils/Log.h>
-#include "SoundTriggerHalHidl.h"
-#include <hidlmemory/mapping.h>
-#include <hwbinder/IPCThreadState.h>
-#include <hwbinder/ProcessState.h>
-
-namespace android {
-
-using ::android::hardware::ProcessState;
-using ::android::hardware::Return;
-using ::android::hardware::Status;
-using ::android::hardware::Void;
-using ::android::hardware::audio::common::V2_0::AudioDevice;
-using ::android::hardware::hidl_memory;
-using ::android::hidl::allocator::V1_0::IAllocator;
-using ::android::hidl::memory::V1_0::IMemory;
-
-namespace {
-
-// Backs up by the vector with the contents of shared memory.
-// It is assumed that the passed hidl_vector is empty, so it's
-// not cleared if the memory is a null object.
-// The caller needs to keep the returned sp<IMemory> as long as
-// the data is needed.
-std::pair<bool, sp<IMemory>> memoryAsVector(const hidl_memory& m, hidl_vec<uint8_t>* vec) {
- sp<IMemory> memory;
- if (m.size() == 0) {
- return std::make_pair(true, memory);
- }
- memory = mapMemory(m);
- if (memory != nullptr) {
- memory->read();
- vec->setToExternal(static_cast<uint8_t*>(static_cast<void*>(memory->getPointer())),
- memory->getSize());
- return std::make_pair(true, memory);
- }
- ALOGE("%s: Could not map HIDL memory to IMemory", __func__);
- return std::make_pair(false, memory);
-}
-
-// Moves the data from the vector into allocated shared memory,
-// emptying the vector.
-// It is assumed that the passed hidl_memory is a null object, so it's
-// not reset if the vector is empty.
-// The caller needs to keep the returned sp<IMemory> as long as
-// the data is needed.
-std::pair<bool, sp<IMemory>> moveVectorToMemory(hidl_vec<uint8_t>* v, hidl_memory* mem) {
- sp<IMemory> memory;
- if (v->size() == 0) {
- return std::make_pair(true, memory);
- }
- sp<IAllocator> ashmem = IAllocator::getService("ashmem");
- if (ashmem == 0) {
- ALOGE("Failed to retrieve ashmem allocator service");
- return std::make_pair(false, memory);
- }
- bool success = false;
- Return<void> r = ashmem->allocate(v->size(), [&](bool s, const hidl_memory& m) {
- success = s;
- if (success) *mem = m;
- });
- if (r.isOk() && success) {
- memory = hardware::mapMemory(*mem);
- if (memory != 0) {
- memory->update();
- memcpy(memory->getPointer(), v->data(), v->size());
- memory->commit();
- v->resize(0);
- return std::make_pair(true, memory);
- } else {
- ALOGE("Failed to map allocated ashmem");
- }
- } else {
- ALOGE("Failed to allocate %llu bytes from ashmem", (unsigned long long)v->size());
- }
- return std::make_pair(false, memory);
-}
-
-} // namespace
-
-/* static */
-sp<SoundTriggerHalInterface> SoundTriggerHalInterface::connectModule(const char *moduleName)
-{
- return new SoundTriggerHalHidl(moduleName);
-}
-
-int SoundTriggerHalHidl::getProperties(struct sound_trigger_properties *properties)
-{
- sp<ISoundTriggerHw> soundtrigger = getService();
- if (soundtrigger == 0) {
- return -ENODEV;
- }
-
- ISoundTriggerHw::Properties halProperties;
- Return<void> hidlReturn;
- int ret;
- {
- AutoMutex lock(mHalLock);
- hidlReturn = soundtrigger->getProperties([&](int rc, auto res) {
- ret = rc;
- halProperties = res;
- ALOGI("getProperties res implementor %s", res.implementor.c_str());
- });
- }
-
- if (hidlReturn.isOk()) {
- if (ret == 0) {
- convertPropertiesFromHal(properties, &halProperties);
- }
- } else {
- ALOGE("getProperties error %s", hidlReturn.description().c_str());
- return FAILED_TRANSACTION;
- }
- ALOGI("getProperties ret %d", ret);
- return ret;
-}
-
-int SoundTriggerHalHidl::loadSoundModel(struct sound_trigger_sound_model *sound_model,
- sound_model_callback_t callback,
- void *cookie,
- sound_model_handle_t *handle)
-{
- if (handle == NULL) {
- return -EINVAL;
- }
-
- sp<ISoundTriggerHw> soundtrigger = getService();
- if (soundtrigger == 0) {
- return -ENODEV;
- }
-
- uint32_t modelId;
- {
- AutoMutex lock(mLock);
- do {
- modelId = nextUniqueId();
- ALOGI("loadSoundModel modelId %u", modelId);
- sp<SoundModel> model = mSoundModels.valueFor(modelId);
- ALOGI("loadSoundModel model %p", model.get());
- } while (mSoundModels.valueFor(modelId) != 0 && modelId != 0);
- }
- LOG_ALWAYS_FATAL_IF(modelId == 0,
- "loadSoundModel(): wrap around in sound model IDs, num loaded models %zd",
- mSoundModels.size());
-
- Return<void> hidlReturn;
- int ret;
- SoundModelHandle halHandle;
- sp<V2_1_ISoundTriggerHw> soundtrigger_2_1 = toService2_1(soundtrigger);
- sp<V2_2_ISoundTriggerHw> soundtrigger_2_2 = toService2_2(soundtrigger);
- if (sound_model->type == SOUND_MODEL_TYPE_KEYPHRASE) {
- if (soundtrigger_2_2) {
- V2_2_ISoundTriggerHw::PhraseSoundModel halSoundModel;
- auto result = convertPhraseSoundModelToHal(&halSoundModel, sound_model);
- if (result.first) {
- AutoMutex lock(mHalLock);
- hidlReturn = soundtrigger_2_2->loadPhraseSoundModel_2_1(
- halSoundModel,
- this, modelId, [&](int32_t retval, auto res) {
- ret = retval;
- halHandle = res;
- });
- } else {
- return NO_MEMORY;
- }
- } else if (soundtrigger_2_1) {
- V2_1_ISoundTriggerHw::PhraseSoundModel halSoundModel;
- auto result = convertPhraseSoundModelToHal(&halSoundModel, sound_model);
- if (result.first) {
- AutoMutex lock(mHalLock);
- hidlReturn = soundtrigger_2_1->loadPhraseSoundModel_2_1(
- halSoundModel,
- this, modelId, [&](int32_t retval, auto res) {
- ret = retval;
- halHandle = res;
- });
- } else {
- return NO_MEMORY;
- }
- } else {
- ISoundTriggerHw::PhraseSoundModel halSoundModel;
- convertPhraseSoundModelToHal(&halSoundModel, sound_model);
- AutoMutex lock(mHalLock);
- hidlReturn = soundtrigger->loadPhraseSoundModel(
- halSoundModel,
- this, modelId, [&](int32_t retval, auto res) {
- ret = retval;
- halHandle = res;
- });
- }
- } else {
- if (soundtrigger_2_2) {
- V2_2_ISoundTriggerHw::SoundModel halSoundModel;
- auto result = convertSoundModelToHal(&halSoundModel, sound_model);
- if (result.first) {
- AutoMutex lock(mHalLock);
- hidlReturn = soundtrigger_2_2->loadSoundModel_2_1(halSoundModel,
- this, modelId, [&](int32_t retval, auto res) {
- ret = retval;
- halHandle = res;
- });
- } else {
- return NO_MEMORY;
- }
- } else if (soundtrigger_2_1) {
- V2_1_ISoundTriggerHw::SoundModel halSoundModel;
- auto result = convertSoundModelToHal(&halSoundModel, sound_model);
- if (result.first) {
- AutoMutex lock(mHalLock);
- hidlReturn = soundtrigger_2_1->loadSoundModel_2_1(halSoundModel,
- this, modelId, [&](int32_t retval, auto res) {
- ret = retval;
- halHandle = res;
- });
- } else {
- return NO_MEMORY;
- }
- } else {
- ISoundTriggerHw::SoundModel halSoundModel;
- convertSoundModelToHal(&halSoundModel, sound_model);
- AutoMutex lock(mHalLock);
- hidlReturn = soundtrigger->loadSoundModel(halSoundModel,
- this, modelId, [&](int32_t retval, auto res) {
- ret = retval;
- halHandle = res;
- });
- }
- }
-
- if (hidlReturn.isOk()) {
- if (ret == 0) {
- AutoMutex lock(mLock);
- *handle = (sound_model_handle_t)modelId;
- sp<SoundModel> model = new SoundModel(*handle, callback, cookie, halHandle);
- mSoundModels.add(*handle, model);
- }
- } else {
- ALOGE("loadSoundModel error %s", hidlReturn.description().c_str());
- return FAILED_TRANSACTION;
- }
-
- return ret;
-}
-
-int SoundTriggerHalHidl::unloadSoundModel(sound_model_handle_t handle)
-{
- sp<ISoundTriggerHw> soundtrigger = getService();
- if (soundtrigger == 0) {
- return -ENODEV;
- }
-
- sp<SoundModel> model = removeModel(handle);
- if (model == 0) {
- ALOGE("unloadSoundModel model not found for handle %u", handle);
- return -EINVAL;
- }
-
- Return<int32_t> hidlReturn(0);
- {
- AutoMutex lock(mHalLock);
- hidlReturn = soundtrigger->unloadSoundModel(model->mHalHandle);
- }
-
- if (!hidlReturn.isOk()) {
- ALOGE("unloadSoundModel error %s", hidlReturn.description().c_str());
- return FAILED_TRANSACTION;
- }
-
- return hidlReturn;
-}
-
-int SoundTriggerHalHidl::startRecognition(sound_model_handle_t handle,
- const struct sound_trigger_recognition_config *config,
- recognition_callback_t callback,
- void *cookie)
-{
- sp<ISoundTriggerHw> soundtrigger = getService();
- if (soundtrigger == 0) {
- return -ENODEV;
- }
-
- sp<SoundModel> model = getModel(handle);
- if (model == 0) {
- ALOGE("startRecognition model not found for handle %u", handle);
- return -EINVAL;
- }
-
- model->mRecognitionCallback = callback;
- model->mRecognitionCookie = cookie;
-
- sp<V2_1_ISoundTriggerHw> soundtrigger_2_1 = toService2_1(soundtrigger);
- sp<V2_2_ISoundTriggerHw> soundtrigger_2_2 = toService2_2(soundtrigger);
- Return<int32_t> hidlReturn(0);
-
- if (soundtrigger_2_2) {
- V2_2_ISoundTriggerHw::RecognitionConfig halConfig;
- auto result = convertRecognitionConfigToHal(&halConfig, config);
- if (result.first) {
- AutoMutex lock(mHalLock);
- hidlReturn = soundtrigger_2_2->startRecognition_2_1(
- model->mHalHandle, halConfig, this, handle);
- } else {
- return NO_MEMORY;
- }
- } else if (soundtrigger_2_1) {
- V2_1_ISoundTriggerHw::RecognitionConfig halConfig;
- auto result = convertRecognitionConfigToHal(&halConfig, config);
- if (result.first) {
- AutoMutex lock(mHalLock);
- hidlReturn = soundtrigger_2_1->startRecognition_2_1(
- model->mHalHandle, halConfig, this, handle);
- } else {
- return NO_MEMORY;
- }
- } else {
- ISoundTriggerHw::RecognitionConfig halConfig;
- convertRecognitionConfigToHal(&halConfig, config);
- {
- AutoMutex lock(mHalLock);
- hidlReturn = soundtrigger->startRecognition(model->mHalHandle, halConfig, this, handle);
- }
- }
-
- if (!hidlReturn.isOk()) {
- ALOGE("startRecognition error %s", hidlReturn.description().c_str());
- return FAILED_TRANSACTION;
- }
- return hidlReturn;
-}
-
-int SoundTriggerHalHidl::stopRecognition(sound_model_handle_t handle)
-{
- sp<ISoundTriggerHw> soundtrigger = getService();
- if (soundtrigger == 0) {
- return -ENODEV;
- }
-
- sp<SoundModel> model = getModel(handle);
- if (model == 0) {
- ALOGE("stopRecognition model not found for handle %u", handle);
- return -EINVAL;
- }
-
- Return<int32_t> hidlReturn(0);
- {
- AutoMutex lock(mHalLock);
- hidlReturn = soundtrigger->stopRecognition(model->mHalHandle);
- }
-
- if (!hidlReturn.isOk()) {
- ALOGE("stopRecognition error %s", hidlReturn.description().c_str());
- return FAILED_TRANSACTION;
- }
- return hidlReturn;
-}
-
-int SoundTriggerHalHidl::stopAllRecognitions()
-{
- sp<ISoundTriggerHw> soundtrigger = getService();
- if (soundtrigger == 0) {
- return -ENODEV;
- }
-
- Return<int32_t> hidlReturn(0);
- {
- AutoMutex lock(mHalLock);
- hidlReturn = soundtrigger->stopAllRecognitions();
- }
-
- if (!hidlReturn.isOk()) {
- ALOGE("stopAllRecognitions error %s", hidlReturn.description().c_str());
- return FAILED_TRANSACTION;
- }
- return hidlReturn;
-}
-
-int SoundTriggerHalHidl::getModelState(sound_model_handle_t handle)
-{
- sp<ISoundTriggerHw> soundtrigger = getService();
- if (soundtrigger == 0) {
- return -ENODEV;
- }
-
- sp<V2_2_ISoundTriggerHw> soundtrigger_2_2 = toService2_2(soundtrigger);
- if (soundtrigger_2_2 == 0) {
- ALOGE("getModelState not supported");
- return -ENODEV;
- }
-
- sp<SoundModel> model = getModel(handle);
- if (model == 0) {
- ALOGE("getModelState model not found for handle %u", handle);
- return -EINVAL;
- }
-
- int ret = NO_ERROR;
- Return<int32_t> hidlReturn(0);
- {
- AutoMutex lock(mHalLock);
- hidlReturn = soundtrigger_2_2->getModelState(model->mHalHandle);
- }
- if (!hidlReturn.isOk()) {
- ALOGE("getModelState error %s", hidlReturn.description().c_str());
- ret = FAILED_TRANSACTION;
- }
- return ret;
-}
-
-SoundTriggerHalHidl::SoundTriggerHalHidl(const char *moduleName)
- : mModuleName(moduleName), mNextUniqueId(1)
-{
- LOG_ALWAYS_FATAL_IF(strcmp(mModuleName, "primary") != 0,
- "Treble soundtrigger only supports primary module");
-}
-
-SoundTriggerHalHidl::~SoundTriggerHalHidl()
-{
-}
-
-sp<ISoundTriggerHw> SoundTriggerHalHidl::getService()
-{
- AutoMutex lock(mLock);
- if (mISoundTrigger == 0) {
- if (mModuleName == NULL) {
- mModuleName = "primary";
- }
- mISoundTrigger = ISoundTriggerHw::getService();
- if (mISoundTrigger != 0) {
- mISoundTrigger->linkToDeath(HalDeathHandler::getInstance(), 0 /*cookie*/);
- }
- }
- return mISoundTrigger;
-}
-
-sp<V2_1_ISoundTriggerHw> SoundTriggerHalHidl::toService2_1(const sp<ISoundTriggerHw>& s)
-{
- auto castResult_2_1 = V2_1_ISoundTriggerHw::castFrom(s);
- return castResult_2_1.isOk() ? static_cast<sp<V2_1_ISoundTriggerHw>>(castResult_2_1) : nullptr;
-}
-
-sp<V2_2_ISoundTriggerHw> SoundTriggerHalHidl::toService2_2(const sp<ISoundTriggerHw>& s)
-{
- auto castResult_2_2 = V2_2_ISoundTriggerHw::castFrom(s);
- return castResult_2_2.isOk() ? static_cast<sp<V2_2_ISoundTriggerHw>>(castResult_2_2) : nullptr;
-}
-
-sp<SoundTriggerHalHidl::SoundModel> SoundTriggerHalHidl::getModel(sound_model_handle_t handle)
-{
- AutoMutex lock(mLock);
- return mSoundModels.valueFor(handle);
-}
-
-sp<SoundTriggerHalHidl::SoundModel> SoundTriggerHalHidl::removeModel(sound_model_handle_t handle)
-{
- AutoMutex lock(mLock);
- sp<SoundModel> model = mSoundModels.valueFor(handle);
- mSoundModels.removeItem(handle);
- return model;
-}
-
-uint32_t SoundTriggerHalHidl::nextUniqueId()
-{
- return (uint32_t) atomic_fetch_add_explicit(&mNextUniqueId,
- (uint_fast32_t) 1, memory_order_acq_rel);
-}
-
-void SoundTriggerHalHidl::convertUuidToHal(Uuid *halUuid,
- const sound_trigger_uuid_t *uuid)
-{
- halUuid->timeLow = uuid->timeLow;
- halUuid->timeMid = uuid->timeMid;
- halUuid->versionAndTimeHigh = uuid->timeHiAndVersion;
- halUuid->variantAndClockSeqHigh = uuid->clockSeq;
- memcpy(halUuid->node.data(), &uuid->node[0], sizeof(uuid->node));
-}
-
-void SoundTriggerHalHidl::convertUuidFromHal(sound_trigger_uuid_t *uuid,
- const Uuid *halUuid)
-{
- uuid->timeLow = halUuid->timeLow;
- uuid->timeMid = halUuid->timeMid;
- uuid->timeHiAndVersion = halUuid->versionAndTimeHigh;
- uuid->clockSeq = halUuid->variantAndClockSeqHigh;
- memcpy(&uuid->node[0], halUuid->node.data(), sizeof(uuid->node));
-}
-
-void SoundTriggerHalHidl::convertPropertiesFromHal(
- struct sound_trigger_properties *properties,
- const ISoundTriggerHw::Properties *halProperties)
-{
- strlcpy(properties->implementor,
- halProperties->implementor.c_str(), SOUND_TRIGGER_MAX_STRING_LEN);
- strlcpy(properties->description,
- halProperties->description.c_str(), SOUND_TRIGGER_MAX_STRING_LEN);
- properties->version = halProperties->version;
- convertUuidFromHal(&properties->uuid, &halProperties->uuid);
- properties->max_sound_models = halProperties->maxSoundModels;
- properties->max_key_phrases = halProperties->maxKeyPhrases;
- properties->max_users = halProperties->maxUsers;
- properties->recognition_modes = halProperties->recognitionModes;
- properties->capture_transition = (bool)halProperties->captureTransition;
- properties->max_buffer_ms = halProperties->maxBufferMs;
- properties->concurrent_capture = (bool)halProperties->concurrentCapture;
- properties->trigger_in_event = (bool)halProperties->triggerInEvent;
- properties->power_consumption_mw = halProperties->powerConsumptionMw;
-}
-
-void SoundTriggerHalHidl::convertTriggerPhraseToHal(
- ISoundTriggerHw::Phrase *halTriggerPhrase,
- const struct sound_trigger_phrase *triggerPhrase)
-{
- halTriggerPhrase->id = triggerPhrase->id;
- halTriggerPhrase->recognitionModes = triggerPhrase->recognition_mode;
- halTriggerPhrase->users.setToExternal((uint32_t *)&triggerPhrase->users[0], triggerPhrase->num_users);
- halTriggerPhrase->locale = triggerPhrase->locale;
- halTriggerPhrase->text = triggerPhrase->text;
-}
-
-
-void SoundTriggerHalHidl::convertTriggerPhrasesToHal(
- hidl_vec<ISoundTriggerHw::Phrase> *halTriggerPhrases,
- struct sound_trigger_phrase_sound_model *keyPhraseModel)
-{
- halTriggerPhrases->resize(keyPhraseModel->num_phrases);
- for (unsigned int i = 0; i < keyPhraseModel->num_phrases; i++) {
- convertTriggerPhraseToHal(&(*halTriggerPhrases)[i], &keyPhraseModel->phrases[i]);
- }
-}
-
-void SoundTriggerHalHidl::convertSoundModelToHal(ISoundTriggerHw::SoundModel *halModel,
- const struct sound_trigger_sound_model *soundModel)
-{
- halModel->type = (SoundModelType)soundModel->type;
- convertUuidToHal(&halModel->uuid, &soundModel->uuid);
- convertUuidToHal(&halModel->vendorUuid, &soundModel->vendor_uuid);
- halModel->data.setToExternal((uint8_t *)soundModel + soundModel->data_offset, soundModel->data_size);
-}
-
-std::pair<bool, sp<IMemory>> SoundTriggerHalHidl::convertSoundModelToHal(
- V2_1_ISoundTriggerHw::SoundModel *halModel,
- const struct sound_trigger_sound_model *soundModel)
-{
- convertSoundModelToHal(&halModel->header, soundModel);
- return moveVectorToMemory(&halModel->header.data, &halModel->data);
-}
-
-void SoundTriggerHalHidl::convertPhraseSoundModelToHal(
- ISoundTriggerHw::PhraseSoundModel *halKeyPhraseModel,
- const struct sound_trigger_sound_model *soundModel)
-{
- struct sound_trigger_phrase_sound_model *keyPhraseModel =
- (struct sound_trigger_phrase_sound_model *)soundModel;
- convertTriggerPhrasesToHal(&halKeyPhraseModel->phrases, keyPhraseModel);
- convertSoundModelToHal(&halKeyPhraseModel->common, soundModel);
-}
-
-std::pair<bool, sp<IMemory>> SoundTriggerHalHidl::convertPhraseSoundModelToHal(
- V2_1_ISoundTriggerHw::PhraseSoundModel *halKeyPhraseModel,
- const struct sound_trigger_sound_model *soundModel)
-{
- struct sound_trigger_phrase_sound_model *keyPhraseModel =
- (struct sound_trigger_phrase_sound_model *)soundModel;
- convertTriggerPhrasesToHal(&halKeyPhraseModel->phrases, keyPhraseModel);
- return convertSoundModelToHal(&halKeyPhraseModel->common, soundModel);
-}
-
-void SoundTriggerHalHidl::convertPhraseRecognitionExtraToHal(
- PhraseRecognitionExtra *halExtra,
- const struct sound_trigger_phrase_recognition_extra *extra)
-{
- halExtra->id = extra->id;
- halExtra->recognitionModes = extra->recognition_modes;
- halExtra->confidenceLevel = extra->confidence_level;
- halExtra->levels.resize(extra->num_levels);
- for (unsigned int i = 0; i < extra->num_levels; i++) {
- halExtra->levels[i].userId = extra->levels[i].user_id;
- halExtra->levels[i].levelPercent = extra->levels[i].level;
- }
-}
-
-void SoundTriggerHalHidl::convertRecognitionConfigToHal(
- ISoundTriggerHw::RecognitionConfig *halConfig,
- const struct sound_trigger_recognition_config *config)
-{
- halConfig->captureHandle = config->capture_handle;
- halConfig->captureDevice = (AudioDevice)config->capture_device;
- halConfig->captureRequested = (uint32_t)config->capture_requested;
-
- halConfig->phrases.resize(config->num_phrases);
- for (unsigned int i = 0; i < config->num_phrases; i++) {
- convertPhraseRecognitionExtraToHal(&halConfig->phrases[i],
- &config->phrases[i]);
- }
-
- halConfig->data.setToExternal((uint8_t *)config + config->data_offset, config->data_size);
-}
-
-std::pair<bool, sp<IMemory>> SoundTriggerHalHidl::convertRecognitionConfigToHal(
- V2_1_ISoundTriggerHw::RecognitionConfig *halConfig,
- const struct sound_trigger_recognition_config *config)
-{
- convertRecognitionConfigToHal(&halConfig->header, config);
- return moveVectorToMemory(&halConfig->header.data, &halConfig->data);
-}
-
-
-// ISoundTriggerHwCallback
-::android::hardware::Return<void> SoundTriggerHalHidl::recognitionCallback(
- const V2_0_ISoundTriggerHwCallback::RecognitionEvent& halEvent,
- CallbackCookie cookie)
-{
- sp<SoundModel> model;
- {
- AutoMutex lock(mLock);
- model = mSoundModels.valueFor((SoundModelHandle)cookie);
- if (model == 0) {
- return Return<void>();
- }
- }
- struct sound_trigger_recognition_event *event = convertRecognitionEventFromHal(&halEvent);
- if (event == NULL) {
- return Return<void>();
- }
- event->model = model->mHandle;
- model->mRecognitionCallback(event, model->mRecognitionCookie);
-
- free(event);
-
- return Return<void>();
-}
-
-::android::hardware::Return<void> SoundTriggerHalHidl::phraseRecognitionCallback(
- const V2_0_ISoundTriggerHwCallback::PhraseRecognitionEvent& halEvent,
- CallbackCookie cookie)
-{
- sp<SoundModel> model;
- {
- AutoMutex lock(mLock);
- model = mSoundModels.valueFor((SoundModelHandle)cookie);
- if (model == 0) {
- return Return<void>();
- }
- }
-
- struct sound_trigger_phrase_recognition_event *event =
- convertPhraseRecognitionEventFromHal(&halEvent);
- if (event == NULL) {
- return Return<void>();
- }
- event->common.model = model->mHandle;
- model->mRecognitionCallback(&event->common, model->mRecognitionCookie);
-
- free(event);
-
- return Return<void>();
-}
-
-::android::hardware::Return<void> SoundTriggerHalHidl::soundModelCallback(
- const V2_0_ISoundTriggerHwCallback::ModelEvent& halEvent,
- CallbackCookie cookie)
-{
- sp<SoundModel> model;
- {
- AutoMutex lock(mLock);
- model = mSoundModels.valueFor((SoundModelHandle)cookie);
- if (model == 0) {
- return Return<void>();
- }
- }
-
- struct sound_trigger_model_event *event = convertSoundModelEventFromHal(&halEvent);
- if (event == NULL) {
- return Return<void>();
- }
-
- event->model = model->mHandle;
- model->mSoundModelCallback(event, model->mSoundModelCookie);
-
- free(event);
-
- return Return<void>();
-}
-
-::android::hardware::Return<void> SoundTriggerHalHidl::recognitionCallback_2_1(
- const ISoundTriggerHwCallback::RecognitionEvent& event, CallbackCookie cookie) {
- // The data vector in the 'header' part of V2.1 structure is empty, thus copying is cheap.
- V2_0_ISoundTriggerHwCallback::RecognitionEvent event_2_0 = event.header;
- auto result = memoryAsVector(event.data, &event_2_0.data);
- return result.first ? recognitionCallback(event_2_0, cookie) : Void();
-}
-
-::android::hardware::Return<void> SoundTriggerHalHidl::phraseRecognitionCallback_2_1(
- const ISoundTriggerHwCallback::PhraseRecognitionEvent& event, int32_t cookie) {
- V2_0_ISoundTriggerHwCallback::PhraseRecognitionEvent event_2_0;
- // The data vector in the 'header' part of V2.1 structure is empty, thus copying is cheap.
- event_2_0.common = event.common.header;
- event_2_0.phraseExtras.setToExternal(
- const_cast<PhraseRecognitionExtra*>(event.phraseExtras.data()),
- event.phraseExtras.size());
- auto result = memoryAsVector(event.common.data, &event_2_0.common.data);
- return result.first ? phraseRecognitionCallback(event_2_0, cookie) : Void();
-}
-
-::android::hardware::Return<void> SoundTriggerHalHidl::soundModelCallback_2_1(
- const ISoundTriggerHwCallback::ModelEvent& event, CallbackCookie cookie) {
- // The data vector in the 'header' part of V2.1 structure is empty, thus copying is cheap.
- V2_0_ISoundTriggerHwCallback::ModelEvent event_2_0 = event.header;
- auto result = memoryAsVector(event.data, &event_2_0.data);
- return result.first ? soundModelCallback(event_2_0, cookie) : Void();
-}
-
-
-struct sound_trigger_model_event *SoundTriggerHalHidl::convertSoundModelEventFromHal(
- const V2_0_ISoundTriggerHwCallback::ModelEvent *halEvent)
-{
- struct sound_trigger_model_event *event = (struct sound_trigger_model_event *)malloc(
- sizeof(struct sound_trigger_model_event) +
- halEvent->data.size());
- if (event == NULL) {
- return NULL;
- }
-
- event->status = (int)halEvent->status;
- // event->model to be set by caller
- event->data_offset = sizeof(struct sound_trigger_model_event);
- event->data_size = halEvent->data.size();
- uint8_t *dst = (uint8_t *)event + event->data_offset;
- uint8_t *src = (uint8_t *)&halEvent->data[0];
- memcpy(dst, src, halEvent->data.size());
-
- return event;
-}
-
-void SoundTriggerHalHidl::convertPhraseRecognitionExtraFromHal(
- struct sound_trigger_phrase_recognition_extra *extra,
- const PhraseRecognitionExtra *halExtra)
-{
- extra->id = halExtra->id;
- extra->recognition_modes = halExtra->recognitionModes;
- extra->confidence_level = halExtra->confidenceLevel;
-
- size_t i;
- for (i = 0; i < halExtra->levels.size() && i < SOUND_TRIGGER_MAX_USERS; i++) {
- extra->levels[i].user_id = halExtra->levels[i].userId;
- extra->levels[i].level = halExtra->levels[i].levelPercent;
- }
- extra->num_levels = (unsigned int)i;
-}
-
-
-struct sound_trigger_phrase_recognition_event* SoundTriggerHalHidl::convertPhraseRecognitionEventFromHal(
- const V2_0_ISoundTriggerHwCallback::PhraseRecognitionEvent *halPhraseEvent)
-{
- if (halPhraseEvent->common.type != SoundModelType::KEYPHRASE) {
- ALOGE("Received non-keyphrase event type as PhraseRecognitionEvent");
- return NULL;
- }
- struct sound_trigger_phrase_recognition_event *phraseEvent =
- (struct sound_trigger_phrase_recognition_event *)malloc(
- sizeof(struct sound_trigger_phrase_recognition_event) +
- halPhraseEvent->common.data.size());
- if (phraseEvent == NULL) {
- return NULL;
- }
- phraseEvent->common.data_offset = sizeof(sound_trigger_phrase_recognition_event);
-
- for (unsigned int i = 0; i < halPhraseEvent->phraseExtras.size(); i++) {
- convertPhraseRecognitionExtraFromHal(&phraseEvent->phrase_extras[i],
- &halPhraseEvent->phraseExtras[i]);
- }
- phraseEvent->num_phrases = halPhraseEvent->phraseExtras.size();
-
- fillRecognitionEventFromHal(&phraseEvent->common, &halPhraseEvent->common);
- return phraseEvent;
-}
-
-struct sound_trigger_recognition_event *SoundTriggerHalHidl::convertRecognitionEventFromHal(
- const V2_0_ISoundTriggerHwCallback::RecognitionEvent *halEvent)
-{
- if (halEvent->type == SoundModelType::KEYPHRASE) {
- ALOGE("Received keyphrase event type as RecognitionEvent");
- return NULL;
- }
- struct sound_trigger_recognition_event *event;
- event = (struct sound_trigger_recognition_event *)malloc(
- sizeof(struct sound_trigger_recognition_event) + halEvent->data.size());
- if (event == NULL) {
- return NULL;
- }
- event->data_offset = sizeof(sound_trigger_recognition_event);
-
- fillRecognitionEventFromHal(event, halEvent);
- return event;
-}
-
-void SoundTriggerHalHidl::fillRecognitionEventFromHal(
- struct sound_trigger_recognition_event *event,
- const V2_0_ISoundTriggerHwCallback::RecognitionEvent *halEvent)
-{
- event->status = (int)halEvent->status;
- event->type = (sound_trigger_sound_model_type_t)halEvent->type;
- // event->model to be set by caller
- event->capture_available = (bool)halEvent->captureAvailable;
- event->capture_session = halEvent->captureSession;
- event->capture_delay_ms = halEvent->captureDelayMs;
- event->capture_preamble_ms = halEvent->capturePreambleMs;
- event->trigger_in_data = (bool)halEvent->triggerInData;
- event->audio_config.sample_rate = halEvent->audioConfig.sampleRateHz;
- event->audio_config.channel_mask = (audio_channel_mask_t)halEvent->audioConfig.channelMask;
- event->audio_config.format = (audio_format_t)halEvent->audioConfig.format;
-
- event->data_size = halEvent->data.size();
- uint8_t *dst = (uint8_t *)event + event->data_offset;
- uint8_t *src = (uint8_t *)&halEvent->data[0];
- memcpy(dst, src, halEvent->data.size());
-}
-
-} // namespace android
diff --git a/services/soundtrigger/SoundTriggerHalHidl.h b/services/soundtrigger/SoundTriggerHalHidl.h
deleted file mode 100644
index fb9e39e..0000000
--- a/services/soundtrigger/SoundTriggerHalHidl.h
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_SOUNDTRIGGER_HAL_HIDL_H
-#define ANDROID_HARDWARE_SOUNDTRIGGER_HAL_HIDL_H
-
-#include <utility>
-
-#include <stdatomic.h>
-#include <utils/RefBase.h>
-#include <utils/KeyedVector.h>
-#include <utils/Vector.h>
-#include <utils/threads.h>
-#include "SoundTriggerHalInterface.h"
-#include <android/hardware/soundtrigger/2.0/types.h>
-#include <android/hardware/soundtrigger/2.1/ISoundTriggerHw.h>
-#include <android/hardware/soundtrigger/2.2/ISoundTriggerHw.h>
-#include <android/hardware/soundtrigger/2.0/ISoundTriggerHwCallback.h>
-#include <android/hardware/soundtrigger/2.1/ISoundTriggerHwCallback.h>
-
-namespace android {
-
-using ::android::hardware::audio::common::V2_0::Uuid;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::soundtrigger::V2_0::ConfidenceLevel;
-using ::android::hardware::soundtrigger::V2_0::PhraseRecognitionExtra;
-using ::android::hardware::soundtrigger::V2_0::SoundModelType;
-using ::android::hardware::soundtrigger::V2_0::SoundModelHandle;
-using ::android::hardware::soundtrigger::V2_0::ISoundTriggerHw;
-using V2_0_ISoundTriggerHwCallback =
- ::android::hardware::soundtrigger::V2_0::ISoundTriggerHwCallback;
-using V2_1_ISoundTriggerHw =
- ::android::hardware::soundtrigger::V2_1::ISoundTriggerHw;
-using V2_1_ISoundTriggerHwCallback =
- ::android::hardware::soundtrigger::V2_1::ISoundTriggerHwCallback;
-using ::android::hidl::memory::V1_0::IMemory;
-using V2_2_ISoundTriggerHw =
- ::android::hardware::soundtrigger::V2_2::ISoundTriggerHw;
-
-class SoundTriggerHalHidl : public SoundTriggerHalInterface,
- public virtual V2_1_ISoundTriggerHwCallback
-
-{
-public:
- virtual int getProperties(struct sound_trigger_properties *properties);
-
- /*
- * Load a sound model. Once loaded, recognition of this model can be started and stopped.
- * Only one active recognition per model at a time. The SoundTrigger service will handle
- * concurrent recognition requests by different users/applications on the same model.
- * The implementation returns a unique handle used by other functions (unload_sound_model(),
- * start_recognition(), etc...
- */
- virtual int loadSoundModel(struct sound_trigger_sound_model *sound_model,
- sound_model_callback_t callback,
- void *cookie,
- sound_model_handle_t *handle);
-
- /*
- * Unload a sound model. A sound model can be unloaded to make room for a new one to overcome
- * implementation limitations.
- */
- virtual int unloadSoundModel(sound_model_handle_t handle);
-
- /* Start recognition on a given model. Only one recognition active at a time per model.
- * Once recognition succeeds of fails, the callback is called.
- * TODO: group recognition configuration parameters into one struct and add key phrase options.
- */
- virtual int startRecognition(sound_model_handle_t handle,
- const struct sound_trigger_recognition_config *config,
- recognition_callback_t callback,
- void *cookie);
-
- /* Stop recognition on a given model.
- * The implementation does not have to call the callback when stopped via this method.
- */
- virtual int stopRecognition(sound_model_handle_t handle);
-
- /* Stop recognition on all models.
- * Only supported for device api versions SOUND_TRIGGER_DEVICE_API_VERSION_1_1 or above.
- * If no implementation is provided, stop_recognition will be called for each running model.
- */
- virtual int stopAllRecognitions();
-
- /* Get the current state of a given model.
- * Returns 0 or an error code. If successful the state will be returned asynchronously
- * via a recognition event in the callback method that was registered in the
- * startRecognition() method.
- * Only supported for device api versions SOUND_TRIGGER_DEVICE_API_VERSION_1_2 or above.
- */
- virtual int getModelState(sound_model_handle_t handle);
-
- // ISoundTriggerHwCallback
- virtual ::android::hardware::Return<void> recognitionCallback(
- const V2_0_ISoundTriggerHwCallback::RecognitionEvent& event, CallbackCookie cookie);
- virtual ::android::hardware::Return<void> phraseRecognitionCallback(
- const V2_0_ISoundTriggerHwCallback::PhraseRecognitionEvent& event, int32_t cookie);
- virtual ::android::hardware::Return<void> soundModelCallback(
- const V2_0_ISoundTriggerHwCallback::ModelEvent& event, CallbackCookie cookie);
- virtual ::android::hardware::Return<void> recognitionCallback_2_1(
- const RecognitionEvent& event, CallbackCookie cookie);
- virtual ::android::hardware::Return<void> phraseRecognitionCallback_2_1(
- const PhraseRecognitionEvent& event, int32_t cookie);
- virtual ::android::hardware::Return<void> soundModelCallback_2_1(
- const ModelEvent& event, CallbackCookie cookie);
-private:
- class SoundModel : public RefBase {
- public:
- SoundModel(sound_model_handle_t handle, sound_model_callback_t callback,
- void *cookie, android::hardware::soundtrigger::V2_0::SoundModelHandle halHandle)
- : mHandle(handle), mHalHandle(halHandle),
- mSoundModelCallback(callback), mSoundModelCookie(cookie),
- mRecognitionCallback(NULL), mRecognitionCookie(NULL) {}
- ~SoundModel() {}
-
- sound_model_handle_t mHandle;
- android::hardware::soundtrigger::V2_0::SoundModelHandle mHalHandle;
- sound_model_callback_t mSoundModelCallback;
- void * mSoundModelCookie;
- recognition_callback_t mRecognitionCallback;
- void * mRecognitionCookie;
- };
-
- friend class SoundTriggerHalInterface;
-
- explicit SoundTriggerHalHidl(const char *moduleName = NULL);
- virtual ~SoundTriggerHalHidl();
-
- void convertUuidToHal(Uuid *halUuid,
- const sound_trigger_uuid_t *uuid);
- void convertUuidFromHal(sound_trigger_uuid_t *uuid,
- const Uuid *halUuid);
-
- void convertPropertiesFromHal(
- struct sound_trigger_properties *properties,
- const ISoundTriggerHw::Properties *halProperties);
-
- void convertTriggerPhraseToHal(
- ISoundTriggerHw::Phrase *halTriggerPhrase,
- const struct sound_trigger_phrase *triggerPhrase);
- void convertTriggerPhrasesToHal(
- hidl_vec<ISoundTriggerHw::Phrase> *halTriggerPhrases,
- struct sound_trigger_phrase_sound_model *keyPhraseModel);
- void convertSoundModelToHal(ISoundTriggerHw::SoundModel *halModel,
- const struct sound_trigger_sound_model *soundModel);
- std::pair<bool, sp<IMemory>> convertSoundModelToHal(
- V2_1_ISoundTriggerHw::SoundModel *halModel,
- const struct sound_trigger_sound_model *soundModel)
- __attribute__((warn_unused_result));
- void convertPhraseSoundModelToHal(ISoundTriggerHw::PhraseSoundModel *halKeyPhraseModel,
- const struct sound_trigger_sound_model *soundModel);
- std::pair<bool, sp<IMemory>> convertPhraseSoundModelToHal(
- V2_1_ISoundTriggerHw::PhraseSoundModel *halKeyPhraseModel,
- const struct sound_trigger_sound_model *soundModel)
- __attribute__((warn_unused_result));
-
- void convertPhraseRecognitionExtraToHal(
- PhraseRecognitionExtra *halExtra,
- const struct sound_trigger_phrase_recognition_extra *extra);
- void convertRecognitionConfigToHal(ISoundTriggerHw::RecognitionConfig *halConfig,
- const struct sound_trigger_recognition_config *config);
- std::pair<bool, sp<IMemory>> convertRecognitionConfigToHal(
- V2_1_ISoundTriggerHw::RecognitionConfig *halConfig,
- const struct sound_trigger_recognition_config *config)
- __attribute__((warn_unused_result));
-
- struct sound_trigger_model_event *convertSoundModelEventFromHal(
- const V2_0_ISoundTriggerHwCallback::ModelEvent *halEvent);
- void convertPhraseRecognitionExtraFromHal(
- struct sound_trigger_phrase_recognition_extra *extra,
- const PhraseRecognitionExtra *halExtra);
- struct sound_trigger_phrase_recognition_event* convertPhraseRecognitionEventFromHal(
- const V2_0_ISoundTriggerHwCallback::PhraseRecognitionEvent *halPhraseEvent);
- struct sound_trigger_recognition_event *convertRecognitionEventFromHal(
- const V2_0_ISoundTriggerHwCallback::RecognitionEvent *halEvent);
- void fillRecognitionEventFromHal(
- struct sound_trigger_recognition_event *event,
- const V2_0_ISoundTriggerHwCallback::RecognitionEvent *halEvent);
-
- uint32_t nextUniqueId();
- sp<ISoundTriggerHw> getService();
- sp<V2_1_ISoundTriggerHw> toService2_1(const sp<ISoundTriggerHw>& s);
- sp<V2_2_ISoundTriggerHw> toService2_2(const sp<ISoundTriggerHw>& s);
- sp<SoundModel> getModel(sound_model_handle_t handle);
- sp<SoundModel> removeModel(sound_model_handle_t handle);
-
- static pthread_once_t sOnceControl;
- static void sOnceInit();
-
- Mutex mLock;
- Mutex mHalLock;
- const char *mModuleName;
- volatile atomic_uint_fast32_t mNextUniqueId;
- // Effect chains without a valid thread
- DefaultKeyedVector< sound_model_handle_t , sp<SoundModel> > mSoundModels;
- sp<::android::hardware::soundtrigger::V2_0::ISoundTriggerHw> mISoundTrigger;
-};
-
-} // namespace android
-
-#endif // ANDROID_HARDWARE_SOUNDTRIGGER_HAL_HIDL_H
diff --git a/services/soundtrigger/SoundTriggerHalInterface.h b/services/soundtrigger/SoundTriggerHalInterface.h
deleted file mode 100644
index 0183ece..0000000
--- a/services/soundtrigger/SoundTriggerHalInterface.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_SOUNDTRIGGER_HAL_INTERFACE_H
-#define ANDROID_HARDWARE_SOUNDTRIGGER_HAL_INTERFACE_H
-
-#include <utils/RefBase.h>
-#include <system/sound_trigger.h>
-#include <hardware/sound_trigger.h>
-
-namespace android {
-
-class SoundTriggerHalInterface : public virtual RefBase
-{
-public:
- /* get a sound trigger HAL instance */
- static sp<SoundTriggerHalInterface> connectModule(const char *moduleName);
-
- virtual ~SoundTriggerHalInterface() {}
-
- virtual int getProperties(struct sound_trigger_properties *properties) = 0;
-
- /*
- * Load a sound model. Once loaded, recognition of this model can be started and stopped.
- * Only one active recognition per model at a time. The SoundTrigger service will handle
- * concurrent recognition requests by different users/applications on the same model.
- * The implementation returns a unique handle used by other functions (unload_sound_model(),
- * start_recognition(), etc...
- */
- virtual int loadSoundModel(struct sound_trigger_sound_model *sound_model,
- sound_model_callback_t callback,
- void *cookie,
- sound_model_handle_t *handle) = 0;
-
- /*
- * Unload a sound model. A sound model can be unloaded to make room for a new one to overcome
- * implementation limitations.
- */
- virtual int unloadSoundModel(sound_model_handle_t handle) = 0;
-
- /* Start recognition on a given model. Only one recognition active at a time per model.
- * Once recognition succeeds of fails, the callback is called.
- * TODO: group recognition configuration parameters into one struct and add key phrase options.
- */
- virtual int startRecognition(sound_model_handle_t handle,
- const struct sound_trigger_recognition_config *config,
- recognition_callback_t callback,
- void *cookie) = 0;
-
- /* Stop recognition on a given model.
- * The implementation does not have to call the callback when stopped via this method.
- */
- virtual int stopRecognition(sound_model_handle_t handle) = 0;
-
- /* Stop recognition on all models.
- * Only supported for device api versions SOUND_TRIGGER_DEVICE_API_VERSION_1_1 or above.
- * If no implementation is provided, stop_recognition will be called for each running model.
- */
- virtual int stopAllRecognitions() = 0;
-
- /* Get the current state of a given model.
- * Returns 0 or an error code. If successful the state will be returned asynchronously
- * via a recognition event in the callback method that was registered in the
- * startRecognition() method.
- * Only supported for device api versions SOUND_TRIGGER_DEVICE_API_VERSION_1_2 or above.
- */
- virtual int getModelState(sound_model_handle_t handle) = 0;
-
-protected:
- SoundTriggerHalInterface() {}
-};
-
-} // namespace android
-
-#endif // ANDROID_HARDWARE_SOUNDTRIGGER_HAL_INTERFACE_H
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
deleted file mode 100644
index 51afdcd..0000000
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ /dev/null
@@ -1,1156 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "SoundTriggerHwService"
-//#define LOG_NDEBUG 0
-
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <pthread.h>
-
-#include <audio_utils/clock.h>
-#include <system/sound_trigger.h>
-#include <cutils/atomic.h>
-#include <cutils/properties.h>
-#include <hardware/hardware.h>
-#include <media/AudioSystem.h>
-#include <mediautils/ServiceUtilities.h>
-#include <utils/Errors.h>
-#include <utils/Log.h>
-#include <binder/IServiceManager.h>
-#include <binder/MemoryBase.h>
-#include <binder/MemoryHeapBase.h>
-#include <system/sound_trigger.h>
-#include "SoundTriggerHwService.h"
-
-#define HW_MODULE_PREFIX "primary"
-namespace android {
-
-namespace {
-
-// Given an IMemory, returns a copy of its content along with its size.
-// Returns nullptr on failure or if input is nullptr.
-std::pair<std::unique_ptr<uint8_t[]>,
- size_t> CopyToArray(const sp<IMemory>& mem) {
- if (mem == nullptr) {
- return std::make_pair(nullptr, 0);
- }
-
- const size_t size = mem->size();
- if (size == 0) {
- return std::make_pair(nullptr, 0);
- }
-
- std::unique_ptr<uint8_t[]> ar = std::make_unique<uint8_t[]>(size);
- if (ar == nullptr) {
- return std::make_pair(nullptr, 0);
- }
-
- memcpy(ar.get(), mem->pointer(), size);
- return std::make_pair(std::move(ar), size);
-}
-
-}
-
-SoundTriggerHwService::SoundTriggerHwService()
- : BnSoundTriggerHwService(),
- mNextUniqueId(1),
- mMemoryDealer(new MemoryDealer(1024 * 1024, "SoundTriggerHwService")),
- mCaptureState(false)
-{
-}
-
-void SoundTriggerHwService::onFirstRef()
-{
- int rc;
-
- sp<SoundTriggerHalInterface> halInterface =
- SoundTriggerHalInterface::connectModule(HW_MODULE_PREFIX);
-
- if (halInterface == 0) {
- ALOGW("could not connect to HAL");
- return;
- }
- sound_trigger_module_descriptor descriptor;
- rc = halInterface->getProperties(&descriptor.properties);
- if (rc != 0) {
- ALOGE("could not read implementation properties");
- return;
- }
- descriptor.handle =
- (sound_trigger_module_handle_t)android_atomic_inc(&mNextUniqueId);
- ALOGI("loaded default module %s, handle %d", descriptor.properties.description,
- descriptor.handle);
-
- sp<Module> module = new Module(this, halInterface, descriptor);
- mModules.add(descriptor.handle, module);
- mCallbackThread = new CallbackThread(this);
-}
-
-SoundTriggerHwService::~SoundTriggerHwService()
-{
- if (mCallbackThread != 0) {
- mCallbackThread->exit();
- }
-}
-
-status_t SoundTriggerHwService::listModules(const String16& opPackageName,
- struct sound_trigger_module_descriptor *modules,
- uint32_t *numModules)
-{
- ALOGV("listModules");
- if (!captureHotwordAllowed(opPackageName,
- IPCThreadState::self()->getCallingPid(),
- IPCThreadState::self()->getCallingUid())) {
- return PERMISSION_DENIED;
- }
-
- AutoMutex lock(mServiceLock);
- if (numModules == NULL || (*numModules != 0 && modules == NULL)) {
- return BAD_VALUE;
- }
- size_t maxModules = *numModules;
- *numModules = mModules.size();
- for (size_t i = 0; i < mModules.size() && i < maxModules; i++) {
- modules[i] = mModules.valueAt(i)->descriptor();
- }
- return NO_ERROR;
-}
-
-status_t SoundTriggerHwService::attach(const String16& opPackageName,
- const sound_trigger_module_handle_t handle,
- const sp<ISoundTriggerClient>& client,
- sp<ISoundTrigger>& moduleInterface)
-{
- ALOGV("attach module %d", handle);
- if (!captureHotwordAllowed(opPackageName,
- IPCThreadState::self()->getCallingPid(),
- IPCThreadState::self()->getCallingUid())) {
- return PERMISSION_DENIED;
- }
-
- AutoMutex lock(mServiceLock);
- moduleInterface.clear();
- if (client == 0) {
- return BAD_VALUE;
- }
- ssize_t index = mModules.indexOfKey(handle);
- if (index < 0) {
- return BAD_VALUE;
- }
- sp<Module> module = mModules.valueAt(index);
-
- sp<ModuleClient> moduleClient = module->addClient(client, opPackageName);
- if (moduleClient == 0) {
- return NO_INIT;
- }
-
- moduleClient->setCaptureState_l(mCaptureState);
- moduleInterface = moduleClient;
-
- return NO_ERROR;
-}
-
-status_t SoundTriggerHwService::setCaptureState(bool active)
-{
- ALOGV("setCaptureState %d", active);
- AutoMutex lock(mServiceLock);
- mCaptureState = active;
- for (size_t i = 0; i < mModules.size(); i++) {
- mModules.valueAt(i)->setCaptureState_l(active);
- }
- return NO_ERROR;
-}
-
-
-static const int kDumpLockTimeoutNs = 1 * NANOS_PER_SECOND;
-
-static bool dumpTryLock(Mutex& mutex)
-{
- status_t err = mutex.timedLock(kDumpLockTimeoutNs);
- return err == NO_ERROR;
-}
-
-status_t SoundTriggerHwService::dump(int fd, const Vector<String16>& args __unused) {
- String8 result;
- if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
- result.appendFormat("Permission Denial: can't dump SoundTriggerHwService");
- write(fd, result.string(), result.size());
- } else {
- bool locked = dumpTryLock(mServiceLock);
- // failed to lock - SoundTriggerHwService is probably deadlocked
- if (!locked) {
- result.append("SoundTriggerHwService may be deadlocked\n");
- write(fd, result.string(), result.size());
- }
-
- if (locked) mServiceLock.unlock();
- }
- return NO_ERROR;
-}
-
-status_t SoundTriggerHwService::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
- return BnSoundTriggerHwService::onTransact(code, data, reply, flags);
-}
-
-
-// static
-void SoundTriggerHwService::recognitionCallback(struct sound_trigger_recognition_event *event,
- void *cookie)
-{
- Module *module = (Module *)cookie;
- if (module == NULL) {
- return;
- }
- sp<SoundTriggerHwService> service = module->service().promote();
- if (service == 0) {
- return;
- }
-
- service->sendRecognitionEvent(event, module);
-}
-
-sp<IMemory> SoundTriggerHwService::prepareRecognitionEvent(
- struct sound_trigger_recognition_event *event)
-{
- AutoMutex lock(mMemoryDealerLock);
- sp<IMemory> eventMemory;
-
- //sanitize event
- switch (event->type) {
- case SOUND_MODEL_TYPE_KEYPHRASE:
- ALOGW_IF(event->data_size != 0 && event->data_offset !=
- sizeof(struct sound_trigger_phrase_recognition_event),
- "prepareRecognitionEvent(): invalid data offset %u for keyphrase event type",
- event->data_offset);
- event->data_offset = sizeof(struct sound_trigger_phrase_recognition_event);
- break;
- case SOUND_MODEL_TYPE_GENERIC:
- ALOGW_IF(event->data_size != 0 && event->data_offset !=
- sizeof(struct sound_trigger_generic_recognition_event),
- "prepareRecognitionEvent(): invalid data offset %u for generic event type",
- event->data_offset);
- event->data_offset = sizeof(struct sound_trigger_generic_recognition_event);
- break;
- case SOUND_MODEL_TYPE_UNKNOWN:
- ALOGW_IF(event->data_size != 0 && event->data_offset !=
- sizeof(struct sound_trigger_recognition_event),
- "prepareRecognitionEvent(): invalid data offset %u for unknown event type",
- event->data_offset);
- event->data_offset = sizeof(struct sound_trigger_recognition_event);
- break;
- default:
- return eventMemory;
- }
-
- size_t size = event->data_offset + event->data_size;
- eventMemory = mMemoryDealer->allocate(size);
- if (eventMemory == 0 || eventMemory->pointer() == NULL) {
- eventMemory.clear();
- return eventMemory;
- }
- memcpy(eventMemory->pointer(), event, size);
-
- return eventMemory;
-}
-
-void SoundTriggerHwService::sendRecognitionEvent(struct sound_trigger_recognition_event *event,
- Module *module)
-{
- if (module == NULL) {
- return;
- }
- sp<IMemory> eventMemory = prepareRecognitionEvent(event);
- if (eventMemory == 0) {
- return;
- }
-
- sp<CallbackEvent> callbackEvent = new CallbackEvent(CallbackEvent::TYPE_RECOGNITION,
- eventMemory);
- callbackEvent->setModule(module);
- sendCallbackEvent(callbackEvent);
-}
-
-// static
-void SoundTriggerHwService::soundModelCallback(struct sound_trigger_model_event *event,
- void *cookie)
-{
- Module *module = (Module *)cookie;
- if (module == NULL) {
- return;
- }
- sp<SoundTriggerHwService> service = module->service().promote();
- if (service == 0) {
- return;
- }
-
- service->sendSoundModelEvent(event, module);
-}
-
-sp<IMemory> SoundTriggerHwService::prepareSoundModelEvent(struct sound_trigger_model_event *event)
-{
- AutoMutex lock(mMemoryDealerLock);
- sp<IMemory> eventMemory;
-
- size_t size = event->data_offset + event->data_size;
- eventMemory = mMemoryDealer->allocate(size);
- if (eventMemory == 0 || eventMemory->pointer() == NULL) {
- eventMemory.clear();
- return eventMemory;
- }
- memcpy(eventMemory->pointer(), event, size);
-
- return eventMemory;
-}
-
-void SoundTriggerHwService::sendSoundModelEvent(struct sound_trigger_model_event *event,
- Module *module)
-{
- sp<IMemory> eventMemory = prepareSoundModelEvent(event);
- if (eventMemory == 0) {
- return;
- }
- sp<CallbackEvent> callbackEvent = new CallbackEvent(CallbackEvent::TYPE_SOUNDMODEL,
- eventMemory);
- callbackEvent->setModule(module);
- sendCallbackEvent(callbackEvent);
-}
-
-
-sp<IMemory> SoundTriggerHwService::prepareServiceStateEvent(sound_trigger_service_state_t state)
-{
- AutoMutex lock(mMemoryDealerLock);
- sp<IMemory> eventMemory;
-
- size_t size = sizeof(sound_trigger_service_state_t);
- eventMemory = mMemoryDealer->allocate(size);
- if (eventMemory == 0 || eventMemory->pointer() == NULL) {
- eventMemory.clear();
- return eventMemory;
- }
- *((sound_trigger_service_state_t *)eventMemory->pointer()) = state;
- return eventMemory;
-}
-
-void SoundTriggerHwService::sendServiceStateEvent(sound_trigger_service_state_t state,
- Module *module)
-{
- sp<IMemory> eventMemory = prepareServiceStateEvent(state);
- if (eventMemory == 0) {
- return;
- }
- sp<CallbackEvent> callbackEvent = new CallbackEvent(CallbackEvent::TYPE_SERVICE_STATE,
- eventMemory);
- callbackEvent->setModule(module);
- sendCallbackEvent(callbackEvent);
-}
-
-void SoundTriggerHwService::sendServiceStateEvent(sound_trigger_service_state_t state,
- ModuleClient *moduleClient)
-{
- sp<IMemory> eventMemory = prepareServiceStateEvent(state);
- if (eventMemory == 0) {
- return;
- }
- sp<CallbackEvent> callbackEvent = new CallbackEvent(CallbackEvent::TYPE_SERVICE_STATE,
- eventMemory);
- callbackEvent->setModuleClient(moduleClient);
- sendCallbackEvent(callbackEvent);
-}
-
-void SoundTriggerHwService::sendCallbackEvent(const sp<CallbackEvent>& event)
-{
- mCallbackThread->sendCallbackEvent(event);
-}
-
-void SoundTriggerHwService::onCallbackEvent(const sp<CallbackEvent>& event)
-{
- ALOGV("onCallbackEvent");
- sp<Module> module;
- sp<ModuleClient> moduleClient;
- {
- AutoMutex lock(mServiceLock);
- //CallbackEvent is either for Module or ModuleClient
- module = event->mModule.promote();
- if (module == 0) {
- moduleClient = event->mModuleClient.promote();
- if (moduleClient == 0) {
- return;
- }
- } else {
- // Sanity check on this being a Module we know about.
- bool foundModule = false;
- for (size_t i = 0; i < mModules.size(); i++) {
- if (mModules.valueAt(i).get() == module.get()) {
- foundModule = true;
- break;
- }
- }
- if (!foundModule) {
- ALOGE("onCallbackEvent for unknown module");
- return;
- }
- }
- }
- if (module != 0) {
- ALOGV("onCallbackEvent for module");
- module->onCallbackEvent(event);
- } else if (moduleClient != 0) {
- ALOGV("onCallbackEvent for moduleClient");
- moduleClient->onCallbackEvent(event);
- }
- {
- AutoMutex lock(mServiceLock);
- // clear now to execute with mServiceLock locked
- event->mMemory.clear();
- }
-}
-
-#undef LOG_TAG
-#define LOG_TAG "SoundTriggerHwService::CallbackThread"
-
-SoundTriggerHwService::CallbackThread::CallbackThread(const wp<SoundTriggerHwService>& service)
- : mService(service)
-{
-}
-
-SoundTriggerHwService::CallbackThread::~CallbackThread()
-{
- while (!mEventQueue.isEmpty()) {
- mEventQueue[0]->mMemory.clear();
- mEventQueue.removeAt(0);
- }
-}
-
-void SoundTriggerHwService::CallbackThread::onFirstRef()
-{
- run("soundTrigger cbk", ANDROID_PRIORITY_URGENT_AUDIO);
-}
-
-bool SoundTriggerHwService::CallbackThread::threadLoop()
-{
- while (!exitPending()) {
- sp<CallbackEvent> event;
- sp<SoundTriggerHwService> service;
- {
- Mutex::Autolock _l(mCallbackLock);
- while (mEventQueue.isEmpty() && !exitPending()) {
- ALOGV("CallbackThread::threadLoop() sleep");
- mCallbackCond.wait(mCallbackLock);
- ALOGV("CallbackThread::threadLoop() wake up");
- }
- if (exitPending()) {
- break;
- }
- event = mEventQueue[0];
- mEventQueue.removeAt(0);
- service = mService.promote();
- }
- if (service != 0) {
- service->onCallbackEvent(event);
- }
- }
- return false;
-}
-
-void SoundTriggerHwService::CallbackThread::exit()
-{
- Mutex::Autolock _l(mCallbackLock);
- requestExit();
- mCallbackCond.broadcast();
-}
-
-void SoundTriggerHwService::CallbackThread::sendCallbackEvent(
- const sp<SoundTriggerHwService::CallbackEvent>& event)
-{
- AutoMutex lock(mCallbackLock);
- mEventQueue.add(event);
- mCallbackCond.signal();
-}
-
-SoundTriggerHwService::CallbackEvent::CallbackEvent(event_type type, sp<IMemory> memory)
- : mType(type), mMemory(memory)
-{
-}
-
-SoundTriggerHwService::CallbackEvent::~CallbackEvent()
-{
-}
-
-
-#undef LOG_TAG
-#define LOG_TAG "SoundTriggerHwService::Module"
-
-SoundTriggerHwService::Module::Module(const sp<SoundTriggerHwService>& service,
- const sp<SoundTriggerHalInterface>& halInterface,
- sound_trigger_module_descriptor descriptor)
- : mService(service), mHalInterface(halInterface), mDescriptor(descriptor),
- mServiceState(SOUND_TRIGGER_STATE_NO_INIT)
-{
-}
-
-SoundTriggerHwService::Module::~Module() {
- mModuleClients.clear();
-}
-
-sp<SoundTriggerHwService::ModuleClient>
-SoundTriggerHwService::Module::addClient(const sp<ISoundTriggerClient>& client,
- const String16& opPackageName)
-{
- AutoMutex lock(mLock);
- sp<ModuleClient> moduleClient;
-
- for (size_t i = 0; i < mModuleClients.size(); i++) {
- if (mModuleClients[i]->client() == client) {
- // Client already present, reuse client
- return moduleClient;
- }
- }
- moduleClient = new ModuleClient(this, client, opPackageName);
-
- ALOGV("addClient() client %p", moduleClient.get());
- mModuleClients.add(moduleClient);
-
- return moduleClient;
-}
-
-void SoundTriggerHwService::Module::detach(const sp<ModuleClient>& moduleClient)
-{
- ALOGV("Module::detach()");
- Vector<audio_session_t> releasedSessions;
-
- {
- AutoMutex lock(mLock);
- ssize_t index = -1;
-
- for (size_t i = 0; i < mModuleClients.size(); i++) {
- if (mModuleClients[i] == moduleClient) {
- index = i;
- break;
- }
- }
- if (index == -1) {
- return;
- }
-
- ALOGV("remove client %p", moduleClient.get());
- mModuleClients.removeAt(index);
-
- // Iterate in reverse order as models are removed from list inside the loop.
- for (size_t i = mModels.size(); i > 0; i--) {
- sp<Model> model = mModels.valueAt(i - 1);
- if (moduleClient == model->mModuleClient) {
- mModels.removeItemsAt(i - 1);
- ALOGV("detach() unloading model %d", model->mHandle);
- if (mHalInterface != 0) {
- if (model->mState == Model::STATE_ACTIVE) {
- mHalInterface->stopRecognition(model->mHandle);
- }
- mHalInterface->unloadSoundModel(model->mHandle);
- }
- releasedSessions.add(model->mCaptureSession);
- }
- }
- }
-
- for (size_t i = 0; i < releasedSessions.size(); i++) {
- // do not call AudioSystem methods with mLock held
- AudioSystem::releaseSoundTriggerSession(releasedSessions[i]);
- }
-}
-
-status_t SoundTriggerHwService::Module::loadSoundModel(const sp<IMemory>& modelMemory,
- sp<ModuleClient> moduleClient,
- sound_model_handle_t *handle)
-{
- ALOGV("loadSoundModel() handle");
- if (mHalInterface == 0) {
- return NO_INIT;
- }
-
- auto immutableMemory = CopyToArray(modelMemory);
- if (immutableMemory.first == nullptr) {
- return NO_MEMORY;
- }
-
- struct sound_trigger_sound_model* sound_model =
- (struct sound_trigger_sound_model*) immutableMemory.first.get();
-
- size_t structSize;
- if (sound_model->type == SOUND_MODEL_TYPE_KEYPHRASE) {
- structSize = sizeof(struct sound_trigger_phrase_sound_model);
- } else {
- structSize = sizeof(struct sound_trigger_sound_model);
- }
-
- if (sound_model->data_offset < structSize ||
- sound_model->data_size > (UINT_MAX - sound_model->data_offset) ||
- immutableMemory.second < sound_model->data_offset ||
- sound_model->data_size >
- (immutableMemory.second - sound_model->data_offset)) {
- android_errorWriteLog(0x534e4554, "30148546");
- ALOGE("loadSoundModel() data_size is too big");
- return BAD_VALUE;
- }
-
- audio_session_t session;
- audio_io_handle_t ioHandle;
- audio_devices_t device;
- // do not call AudioSystem methods with mLock held
- status_t status = AudioSystem::acquireSoundTriggerSession(&session, &ioHandle, &device);
- if (status != NO_ERROR) {
- return status;
- }
-
- {
- AutoMutex lock(mLock);
-
- if (mModels.size() >= mDescriptor.properties.max_sound_models) {
- ALOGW("loadSoundModel(): Not loading, max number of models (%d) would be exceeded",
- mDescriptor.properties.max_sound_models);
- status = INVALID_OPERATION;
- goto exit;
- }
-
- status = mHalInterface->loadSoundModel(sound_model,
- SoundTriggerHwService::soundModelCallback,
- this, handle);
- if (status != NO_ERROR) {
- goto exit;
- }
-
- sp<Model> model = new Model(*handle, session, ioHandle, device, sound_model->type,
- moduleClient);
- mModels.replaceValueFor(*handle, model);
- }
-exit:
- if (status != NO_ERROR) {
- // do not call AudioSystem methods with mLock held
- AudioSystem::releaseSoundTriggerSession(session);
- }
- return status;
-}
-
-status_t SoundTriggerHwService::Module::unloadSoundModel(sound_model_handle_t handle)
-{
- ALOGV("unloadSoundModel() model handle %d", handle);
- status_t status;
- audio_session_t session;
-
- {
- AutoMutex lock(mLock);
- if (mHalInterface == 0) {
- return NO_INIT;
- }
- ssize_t index = mModels.indexOfKey(handle);
- if (index < 0) {
- return BAD_VALUE;
- }
- sp<Model> model = mModels.valueAt(index);
- mModels.removeItem(handle);
- if (model->mState == Model::STATE_ACTIVE) {
- mHalInterface->stopRecognition(model->mHandle);
- model->mState = Model::STATE_IDLE;
- }
- status = mHalInterface->unloadSoundModel(handle);
- session = model->mCaptureSession;
- }
- // do not call AudioSystem methods with mLock held
- AudioSystem::releaseSoundTriggerSession(session);
- return status;
-}
-
-status_t SoundTriggerHwService::Module::startRecognition(sound_model_handle_t handle,
- const sp<IMemory>& dataMemory)
-{
- ALOGV("startRecognition() model handle %d", handle);
- if (mHalInterface == 0) {
- return NO_INIT;
- }
-
- auto immutableMemory = CopyToArray(dataMemory);
- if (immutableMemory.first == nullptr) {
- return NO_MEMORY;
- }
-
- struct sound_trigger_recognition_config* config =
- (struct sound_trigger_recognition_config*) immutableMemory.first.get();
-
- if (config->data_offset < sizeof(struct sound_trigger_recognition_config) ||
- config->data_size > (UINT_MAX - config->data_offset) ||
- immutableMemory.second < config->data_offset ||
- config->data_size >
- (immutableMemory.second - config->data_offset)) {
- ALOGE("startRecognition() data_size is too big");
- return BAD_VALUE;
- }
-
- AutoMutex lock(mLock);
- if (mServiceState == SOUND_TRIGGER_STATE_DISABLED) {
- return INVALID_OPERATION;
- }
- sp<Model> model = getModel(handle);
- if (model == 0) {
- return BAD_VALUE;
- }
-
- if (model->mState == Model::STATE_ACTIVE) {
- return INVALID_OPERATION;
- }
-
-
- //TODO: get capture handle and device from audio policy service
- config->capture_handle = model->mCaptureIOHandle;
- config->capture_device = model->mCaptureDevice;
- status_t status = mHalInterface->startRecognition(handle, config,
- SoundTriggerHwService::recognitionCallback,
- this);
-
- if (status == NO_ERROR) {
- model->mState = Model::STATE_ACTIVE;
- model->mConfig = *config;
- }
-
- return status;
-}
-
-status_t SoundTriggerHwService::Module::stopRecognition(sound_model_handle_t handle)
-{
- ALOGV("stopRecognition() model handle %d", handle);
- if (mHalInterface == 0) {
- return NO_INIT;
- }
- AutoMutex lock(mLock);
- sp<Model> model = getModel(handle);
- if (model == 0) {
- return BAD_VALUE;
- }
-
- if (model->mState != Model::STATE_ACTIVE) {
- return INVALID_OPERATION;
- }
- mHalInterface->stopRecognition(handle);
- model->mState = Model::STATE_IDLE;
- return NO_ERROR;
-}
-
-status_t SoundTriggerHwService::Module::getModelState(sound_model_handle_t handle)
-{
- ALOGV("getModelState() model handle %d", handle);
- if (mHalInterface == 0) {
- return NO_INIT;
- }
- AutoMutex lock(mLock);
- sp<Model> model = getModel(handle);
- if (model == 0) {
- return BAD_VALUE;
- }
-
- if (model->mState != Model::STATE_ACTIVE) {
- return INVALID_OPERATION;
- }
-
- return mHalInterface->getModelState(handle);
-}
-
-void SoundTriggerHwService::Module::onCallbackEvent(const sp<CallbackEvent>& event)
-{
- ALOGV("onCallbackEvent type %d", event->mType);
-
- sp<IMemory> eventMemory = event->mMemory;
-
- if (eventMemory == 0 || eventMemory->pointer() == NULL) {
- return;
- }
- if (mModuleClients.isEmpty()) {
- ALOGI("%s no clients", __func__);
- return;
- }
-
- Vector< sp<ModuleClient> > clients;
-
- switch (event->mType) {
- case CallbackEvent::TYPE_RECOGNITION: {
- struct sound_trigger_recognition_event *recognitionEvent =
- (struct sound_trigger_recognition_event *)eventMemory->pointer();
- {
- AutoMutex lock(mLock);
- sp<Model> model = getModel(recognitionEvent->model);
- if (model == 0) {
- ALOGW("%s model == 0", __func__);
- return;
- }
- if (model->mState != Model::STATE_ACTIVE) {
- ALOGV("onCallbackEvent model->mState %d != Model::STATE_ACTIVE", model->mState);
- return;
- }
-
- recognitionEvent->capture_session = model->mCaptureSession;
- model->mState = Model::STATE_IDLE;
- clients.add(model->mModuleClient);
- }
- } break;
- case CallbackEvent::TYPE_SOUNDMODEL: {
- struct sound_trigger_model_event *soundmodelEvent =
- (struct sound_trigger_model_event *)eventMemory->pointer();
- {
- AutoMutex lock(mLock);
- sp<Model> model = getModel(soundmodelEvent->model);
- if (model == 0) {
- ALOGW("%s model == 0", __func__);
- return;
- }
- clients.add(model->mModuleClient);
- }
- } break;
- case CallbackEvent::TYPE_SERVICE_STATE: {
- {
- AutoMutex lock(mLock);
- for (size_t i = 0; i < mModuleClients.size(); i++) {
- if (mModuleClients[i] != 0) {
- clients.add(mModuleClients[i]);
- }
- }
- }
- } break;
- default:
- LOG_ALWAYS_FATAL("onCallbackEvent unknown event type %d", event->mType);
- }
-
- for (size_t i = 0; i < clients.size(); i++) {
- clients[i]->onCallbackEvent(event);
- }
-}
-
-sp<SoundTriggerHwService::Model> SoundTriggerHwService::Module::getModel(
- sound_model_handle_t handle)
-{
- sp<Model> model;
- ssize_t index = mModels.indexOfKey(handle);
- if (index >= 0) {
- model = mModels.valueAt(index);
- }
- return model;
-}
-
-// Called with mServiceLock held
-void SoundTriggerHwService::Module::setCaptureState_l(bool active)
-{
- ALOGV("Module::setCaptureState_l %d", active);
- sp<SoundTriggerHwService> service;
- sound_trigger_service_state_t state;
-
- Vector< sp<IMemory> > events;
- {
- AutoMutex lock(mLock);
- state = (active && !mDescriptor.properties.concurrent_capture) ?
- SOUND_TRIGGER_STATE_DISABLED : SOUND_TRIGGER_STATE_ENABLED;
-
- if (state == mServiceState) {
- return;
- }
-
- mServiceState = state;
-
- service = mService.promote();
- if (service == 0) {
- return;
- }
-
- if (state == SOUND_TRIGGER_STATE_ENABLED) {
- goto exit;
- }
-
- const bool supports_stop_all =
- (mHalInterface != 0) && (mHalInterface->stopAllRecognitions() != -ENOSYS);
-
- for (size_t i = 0; i < mModels.size(); i++) {
- sp<Model> model = mModels.valueAt(i);
- if (model->mState == Model::STATE_ACTIVE) {
- if (mHalInterface != 0 && !supports_stop_all) {
- mHalInterface->stopRecognition(model->mHandle);
- }
- // keep model in ACTIVE state so that event is processed by onCallbackEvent()
- if (model->mType == SOUND_MODEL_TYPE_KEYPHRASE) {
- struct sound_trigger_phrase_recognition_event event;
- memset(&event, 0, sizeof(struct sound_trigger_phrase_recognition_event));
- event.num_phrases = model->mConfig.num_phrases;
- for (size_t i = 0; i < event.num_phrases; i++) {
- event.phrase_extras[i] = model->mConfig.phrases[i];
- }
- event.common.status = RECOGNITION_STATUS_ABORT;
- event.common.type = model->mType;
- event.common.model = model->mHandle;
- event.common.data_size = 0;
- sp<IMemory> eventMemory = service->prepareRecognitionEvent(&event.common);
- if (eventMemory != 0) {
- events.add(eventMemory);
- }
- } else if (model->mType == SOUND_MODEL_TYPE_GENERIC) {
- struct sound_trigger_generic_recognition_event event;
- memset(&event, 0, sizeof(struct sound_trigger_generic_recognition_event));
- event.common.status = RECOGNITION_STATUS_ABORT;
- event.common.type = model->mType;
- event.common.model = model->mHandle;
- event.common.data_size = 0;
- sp<IMemory> eventMemory = service->prepareRecognitionEvent(&event.common);
- if (eventMemory != 0) {
- events.add(eventMemory);
- }
- } else if (model->mType == SOUND_MODEL_TYPE_UNKNOWN) {
- struct sound_trigger_phrase_recognition_event event;
- memset(&event, 0, sizeof(struct sound_trigger_phrase_recognition_event));
- event.common.status = RECOGNITION_STATUS_ABORT;
- event.common.type = model->mType;
- event.common.model = model->mHandle;
- event.common.data_size = 0;
- sp<IMemory> eventMemory = service->prepareRecognitionEvent(&event.common);
- if (eventMemory != 0) {
- events.add(eventMemory);
- }
- } else {
- goto exit;
- }
- }
- }
- }
-
- for (size_t i = 0; i < events.size(); i++) {
- sp<CallbackEvent> callbackEvent = new CallbackEvent(CallbackEvent::TYPE_RECOGNITION,
- events[i]);
- callbackEvent->setModule(this);
- service->sendCallbackEvent(callbackEvent);
- }
-
-exit:
- service->sendServiceStateEvent(state, this);
-}
-
-
-SoundTriggerHwService::Model::Model(sound_model_handle_t handle, audio_session_t session,
- audio_io_handle_t ioHandle, audio_devices_t device,
- sound_trigger_sound_model_type_t type,
- sp<ModuleClient>& moduleClient) :
- mHandle(handle), mState(STATE_IDLE), mCaptureSession(session),
- mCaptureIOHandle(ioHandle), mCaptureDevice(device), mType(type),
- mModuleClient(moduleClient)
-{
-}
-
-#undef LOG_TAG
-#define LOG_TAG "SoundTriggerHwService::ModuleClient"
-
-SoundTriggerHwService::ModuleClient::ModuleClient(const sp<Module>& module,
- const sp<ISoundTriggerClient>& client,
- const String16& opPackageName)
- : mModule(module), mClient(client), mOpPackageName(opPackageName)
-{
-}
-
-void SoundTriggerHwService::ModuleClient::onFirstRef()
-{
- sp<IBinder> binder = IInterface::asBinder(mClient);
- if (binder != 0) {
- binder->linkToDeath(this);
- }
-}
-
-SoundTriggerHwService::ModuleClient::~ModuleClient()
-{
-}
-
-status_t SoundTriggerHwService::ModuleClient::dump(int fd __unused,
- const Vector<String16>& args __unused) {
- String8 result;
- return NO_ERROR;
-}
-
-void SoundTriggerHwService::ModuleClient::detach() {
- ALOGV("detach()");
- if (!captureHotwordAllowed(mOpPackageName,
- IPCThreadState::self()->getCallingPid(),
- IPCThreadState::self()->getCallingUid())) {
- return;
- }
-
- {
- AutoMutex lock(mLock);
- if (mClient != 0) {
- IInterface::asBinder(mClient)->unlinkToDeath(this);
- mClient.clear();
- }
- }
-
- sp<Module> module = mModule.promote();
- if (module == 0) {
- return;
- }
- module->detach(this);
-}
-
-status_t SoundTriggerHwService::ModuleClient::loadSoundModel(const sp<IMemory>& modelMemory,
- sound_model_handle_t *handle)
-{
- ALOGV("loadSoundModel() handle");
- if (!captureHotwordAllowed(mOpPackageName,
- IPCThreadState::self()->getCallingPid(),
- IPCThreadState::self()->getCallingUid())) {
- return PERMISSION_DENIED;
- }
- if (checkIMemory(modelMemory) != NO_ERROR) {
- return BAD_VALUE;
- }
-
- sp<Module> module = mModule.promote();
- if (module == 0) {
- return NO_INIT;
- }
- return module->loadSoundModel(modelMemory, this, handle);
-}
-
-status_t SoundTriggerHwService::ModuleClient::unloadSoundModel(sound_model_handle_t handle)
-{
- ALOGV("unloadSoundModel() model handle %d", handle);
- if (!captureHotwordAllowed(mOpPackageName,
- IPCThreadState::self()->getCallingPid(),
- IPCThreadState::self()->getCallingUid())) {
- return PERMISSION_DENIED;
- }
-
- sp<Module> module = mModule.promote();
- if (module == 0) {
- return NO_INIT;
- }
- return module->unloadSoundModel(handle);
-}
-
-status_t SoundTriggerHwService::ModuleClient::startRecognition(sound_model_handle_t handle,
- const sp<IMemory>& dataMemory)
-{
- ALOGV("startRecognition() model handle %d", handle);
- if (!captureHotwordAllowed(mOpPackageName,
- IPCThreadState::self()->getCallingPid(),
- IPCThreadState::self()->getCallingUid())) {
- return PERMISSION_DENIED;
- }
- if (checkIMemory(dataMemory) != NO_ERROR) {
- return BAD_VALUE;
- }
-
- sp<Module> module = mModule.promote();
- if (module == 0) {
- return NO_INIT;
- }
- return module->startRecognition(handle, dataMemory);
-}
-
-status_t SoundTriggerHwService::ModuleClient::stopRecognition(sound_model_handle_t handle)
-{
- ALOGV("stopRecognition() model handle %d", handle);
- if (!captureHotwordAllowed(mOpPackageName,
- IPCThreadState::self()->getCallingPid(),
- IPCThreadState::self()->getCallingUid())) {
- return PERMISSION_DENIED;
- }
-
- sp<Module> module = mModule.promote();
- if (module == 0) {
- return NO_INIT;
- }
- return module->stopRecognition(handle);
-}
-
-status_t SoundTriggerHwService::ModuleClient::getModelState(sound_model_handle_t handle)
-{
- ALOGV("getModelState() model handle %d", handle);
- if (!captureHotwordAllowed(mOpPackageName,
- IPCThreadState::self()->getCallingPid(),
- IPCThreadState::self()->getCallingUid())) {
- return PERMISSION_DENIED;
- }
-
- sp<Module> module = mModule.promote();
- if (module == 0) {
- return NO_INIT;
- }
- return module->getModelState(handle);
-}
-
-void SoundTriggerHwService::ModuleClient::setCaptureState_l(bool active)
-{
- ALOGV("ModuleClient::setCaptureState_l %d", active);
- sp<SoundTriggerHwService> service;
- sound_trigger_service_state_t state;
-
- sp<Module> module = mModule.promote();
- if (module == 0) {
- return;
- }
- {
- AutoMutex lock(mLock);
- state = (active && !module->isConcurrentCaptureAllowed()) ?
- SOUND_TRIGGER_STATE_DISABLED : SOUND_TRIGGER_STATE_ENABLED;
-
- service = module->service().promote();
- if (service == 0) {
- return;
- }
- }
- service->sendServiceStateEvent(state, this);
-}
-
-void SoundTriggerHwService::ModuleClient::onCallbackEvent(const sp<CallbackEvent>& event)
-{
- ALOGV("ModuleClient onCallbackEvent type %d", event->mType);
-
- sp<IMemory> eventMemory = event->mMemory;
-
- if (eventMemory == 0 || eventMemory->pointer() == NULL) {
- return;
- }
-
- sp<ISoundTriggerClient> client;
- {
- AutoMutex lock(mLock);
- client = mClient;
- }
-
- if (client != 0) {
- switch (event->mType) {
- case CallbackEvent::TYPE_RECOGNITION: {
- client->onRecognitionEvent(eventMemory);
- } break;
- case CallbackEvent::TYPE_SOUNDMODEL: {
- client->onSoundModelEvent(eventMemory);
- } break;
- case CallbackEvent::TYPE_SERVICE_STATE: {
- client->onServiceStateChange(eventMemory);
- } break;
- default:
- LOG_ALWAYS_FATAL("onCallbackEvent unknown event type %d", event->mType);
- }
- }
-}
-
-void SoundTriggerHwService::ModuleClient::binderDied(
- const wp<IBinder> &who __unused) {
- ALOGW("client binder died for client %p", this);
- detach();
-}
-
-}; // namespace android
diff --git a/services/soundtrigger/SoundTriggerHwService.h b/services/soundtrigger/SoundTriggerHwService.h
deleted file mode 100644
index 43ad611..0000000
--- a/services/soundtrigger/SoundTriggerHwService.h
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_SOUNDTRIGGER_HAL_SERVICE_H
-#define ANDROID_HARDWARE_SOUNDTRIGGER_HAL_SERVICE_H
-
-#include <utils/Vector.h>
-//#include <binder/AppOpsManager.h>
-#include <binder/MemoryDealer.h>
-#include <binder/BinderService.h>
-#include <binder/IAppOpsCallback.h>
-#include <soundtrigger/ISoundTriggerHwService.h>
-#include <soundtrigger/ISoundTrigger.h>
-#include <soundtrigger/ISoundTriggerClient.h>
-#include <system/sound_trigger.h>
-#include "SoundTriggerHalInterface.h"
-
-namespace android {
-
-class MemoryHeapBase;
-
-class SoundTriggerHwService :
- public BinderService<SoundTriggerHwService>,
- public BnSoundTriggerHwService
-{
- friend class BinderService<SoundTriggerHwService>;
-public:
- class Module;
- class ModuleClient;
-
- static char const* getServiceName() { return "media.sound_trigger_hw"; }
-
- SoundTriggerHwService();
- virtual ~SoundTriggerHwService();
-
- // ISoundTriggerHwService
- virtual status_t listModules(const String16& opPackageName,
- struct sound_trigger_module_descriptor *modules,
- uint32_t *numModules);
-
- virtual status_t attach(const String16& opPackageName,
- const sound_trigger_module_handle_t handle,
- const sp<ISoundTriggerClient>& client,
- sp<ISoundTrigger>& module);
-
- virtual status_t setCaptureState(bool active);
-
- virtual status_t onTransact(uint32_t code, const Parcel& data,
- Parcel* reply, uint32_t flags);
-
- virtual status_t dump(int fd, const Vector<String16>& args);
-
- class Model : public RefBase {
- public:
-
- enum {
- STATE_IDLE,
- STATE_ACTIVE
- };
-
- Model(sound_model_handle_t handle, audio_session_t session, audio_io_handle_t ioHandle,
- audio_devices_t device, sound_trigger_sound_model_type_t type,
- sp<ModuleClient>& moduleClient);
- ~Model() {}
-
- sound_model_handle_t mHandle;
- int mState;
- audio_session_t mCaptureSession;
- audio_io_handle_t mCaptureIOHandle;
- audio_devices_t mCaptureDevice;
- sound_trigger_sound_model_type_t mType;
- struct sound_trigger_recognition_config mConfig;
- sp<ModuleClient> mModuleClient;
- };
-
- class CallbackEvent : public RefBase {
- public:
- typedef enum {
- TYPE_RECOGNITION,
- TYPE_SOUNDMODEL,
- TYPE_SERVICE_STATE,
- } event_type;
- CallbackEvent(event_type type, sp<IMemory> memory);
-
- virtual ~CallbackEvent();
-
- void setModule(wp<Module> module) { mModule = module; }
- void setModuleClient(wp<ModuleClient> moduleClient) { mModuleClient = moduleClient; }
-
- event_type mType;
- sp<IMemory> mMemory;
- wp<Module> mModule;
- wp<ModuleClient> mModuleClient;
- };
-
- class Module : public RefBase {
- public:
-
- Module(const sp<SoundTriggerHwService>& service,
- const sp<SoundTriggerHalInterface>& halInterface,
- sound_trigger_module_descriptor descriptor);
-
- virtual ~Module();
-
- virtual status_t loadSoundModel(const sp<IMemory>& modelMemory,
- sp<ModuleClient> moduleClient,
- sound_model_handle_t *handle);
-
- virtual status_t unloadSoundModel(sound_model_handle_t handle);
-
- virtual status_t startRecognition(sound_model_handle_t handle,
- const sp<IMemory>& dataMemory);
- virtual status_t stopRecognition(sound_model_handle_t handle);
- virtual status_t getModelState(sound_model_handle_t handle);
-
- sp<SoundTriggerHalInterface> halInterface() const { return mHalInterface; }
- struct sound_trigger_module_descriptor descriptor() { return mDescriptor; }
- wp<SoundTriggerHwService> service() const { return mService; }
- bool isConcurrentCaptureAllowed() const { return mDescriptor.properties.concurrent_capture; }
-
- sp<Model> getModel(sound_model_handle_t handle);
-
- void setCaptureState_l(bool active);
-
- sp<ModuleClient> addClient(const sp<ISoundTriggerClient>& client,
- const String16& opPackageName);
-
- void detach(const sp<ModuleClient>& moduleClient);
-
- void onCallbackEvent(const sp<CallbackEvent>& event);
-
- private:
-
- Mutex mLock;
- wp<SoundTriggerHwService> mService;
- sp<SoundTriggerHalInterface> mHalInterface;
- struct sound_trigger_module_descriptor mDescriptor;
- Vector< sp<ModuleClient> > mModuleClients;
- DefaultKeyedVector< sound_model_handle_t, sp<Model> > mModels;
- sound_trigger_service_state_t mServiceState;
- }; // class Module
-
- class ModuleClient : public virtual RefBase,
- public BnSoundTrigger,
- public IBinder::DeathRecipient {
- public:
-
- ModuleClient(const sp<Module>& module,
- const sp<ISoundTriggerClient>& client,
- const String16& opPackageName);
-
- virtual ~ModuleClient();
-
- virtual void detach();
-
- virtual status_t loadSoundModel(const sp<IMemory>& modelMemory,
- sound_model_handle_t *handle);
-
- virtual status_t unloadSoundModel(sound_model_handle_t handle);
-
- virtual status_t startRecognition(sound_model_handle_t handle,
- const sp<IMemory>& dataMemory);
- virtual status_t stopRecognition(sound_model_handle_t handle);
- virtual status_t getModelState(sound_model_handle_t handle);
-
- virtual status_t dump(int fd, const Vector<String16>& args);
-
- virtual void onFirstRef();
-
- // IBinder::DeathRecipient implementation
- virtual void binderDied(const wp<IBinder> &who);
-
- void onCallbackEvent(const sp<CallbackEvent>& event);
-
- void setCaptureState_l(bool active);
-
- sp<ISoundTriggerClient> client() const { return mClient; }
-
- private:
-
- mutable Mutex mLock;
- wp<Module> mModule;
- sp<ISoundTriggerClient> mClient;
- const String16 mOpPackageName;
- }; // class ModuleClient
-
- class CallbackThread : public Thread {
- public:
-
- explicit CallbackThread(const wp<SoundTriggerHwService>& service);
-
- virtual ~CallbackThread();
-
- // Thread virtuals
- virtual bool threadLoop();
-
- // RefBase
- virtual void onFirstRef();
-
- void exit();
- void sendCallbackEvent(const sp<CallbackEvent>& event);
-
- private:
- wp<SoundTriggerHwService> mService;
- Condition mCallbackCond;
- Mutex mCallbackLock;
- Vector< sp<CallbackEvent> > mEventQueue;
- };
-
- static void recognitionCallback(struct sound_trigger_recognition_event *event, void *cookie);
- sp<IMemory> prepareRecognitionEvent(struct sound_trigger_recognition_event *event);
- void sendRecognitionEvent(struct sound_trigger_recognition_event *event, Module *module);
-
- static void soundModelCallback(struct sound_trigger_model_event *event, void *cookie);
- sp<IMemory> prepareSoundModelEvent(struct sound_trigger_model_event *event);
- void sendSoundModelEvent(struct sound_trigger_model_event *event, Module *module);
-
- sp<IMemory> prepareServiceStateEvent(sound_trigger_service_state_t state);
- void sendServiceStateEvent(sound_trigger_service_state_t state, Module *module);
- void sendServiceStateEvent(sound_trigger_service_state_t state,
- ModuleClient *moduleClient);
-
- void sendCallbackEvent(const sp<CallbackEvent>& event);
- void onCallbackEvent(const sp<CallbackEvent>& event);
-
-private:
-
- virtual void onFirstRef();
-
- Mutex mServiceLock;
- volatile int32_t mNextUniqueId;
- DefaultKeyedVector< sound_trigger_module_handle_t, sp<Module> > mModules;
- sp<CallbackThread> mCallbackThread;
- sp<MemoryDealer> mMemoryDealer;
- Mutex mMemoryDealerLock;
- bool mCaptureState;
-};
-
-} // namespace android
-
-#endif // ANDROID_HARDWARE_SOUNDTRIGGER_HAL_SERVICE_H
diff --git a/soundtrigger/Android.bp b/soundtrigger/Android.bp
deleted file mode 100644
index 6178153..0000000
--- a/soundtrigger/Android.bp
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2014 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.
-
-cc_library_shared {
- name: "libsoundtrigger",
-
- srcs: [
- "SoundTrigger.cpp",
- "ISoundTrigger.cpp",
- "ISoundTriggerClient.cpp",
- "ISoundTriggerHwService.cpp",
- ],
-
- shared_libs: [
- "libcutils",
- "libutils",
- "liblog",
- "libbinder",
- ],
-
- cflags: [
- "-Werror",
- "-Wall",
- ],
-}
diff --git a/soundtrigger/ISoundTrigger.cpp b/soundtrigger/ISoundTrigger.cpp
deleted file mode 100644
index f5b4b59..0000000
--- a/soundtrigger/ISoundTrigger.cpp
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
-**
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#define LOG_TAG "ISoundTrigger"
-#include <utils/Log.h>
-#include <utils/Errors.h>
-#include <binder/IMemory.h>
-#include <soundtrigger/ISoundTrigger.h>
-#include <soundtrigger/ISoundTriggerHwService.h>
-#include <soundtrigger/ISoundTriggerClient.h>
-#include <system/sound_trigger.h>
-
-namespace android {
-
-enum {
- DETACH = IBinder::FIRST_CALL_TRANSACTION,
- LOAD_SOUND_MODEL,
- UNLOAD_SOUND_MODEL,
- START_RECOGNITION,
- STOP_RECOGNITION,
- GET_MODEL_STATE,
-};
-
-class BpSoundTrigger: public BpInterface<ISoundTrigger>
-{
-public:
- explicit BpSoundTrigger(const sp<IBinder>& impl)
- : BpInterface<ISoundTrigger>(impl)
- {
- }
-
- void detach()
- {
- ALOGV("detach");
- Parcel data, reply;
- data.writeInterfaceToken(ISoundTrigger::getInterfaceDescriptor());
- remote()->transact(DETACH, data, &reply);
- }
-
- status_t loadSoundModel(const sp<IMemory>& modelMemory,
- sound_model_handle_t *handle)
- {
- if (modelMemory == 0 || handle == NULL) {
- return BAD_VALUE;
- }
- Parcel data, reply;
- data.writeInterfaceToken(ISoundTrigger::getInterfaceDescriptor());
- data.writeStrongBinder(IInterface::asBinder(modelMemory));
- status_t status = remote()->transact(LOAD_SOUND_MODEL, data, &reply);
- if (status != NO_ERROR) {
- return status;
- }
- status = (status_t)reply.readInt32();
- if (status == NO_ERROR) {
- reply.read(handle, sizeof(sound_model_handle_t));
- }
- return status;
- }
-
- virtual status_t unloadSoundModel(sound_model_handle_t handle)
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISoundTrigger::getInterfaceDescriptor());
- data.write(&handle, sizeof(sound_model_handle_t));
- status_t status = remote()->transact(UNLOAD_SOUND_MODEL, data, &reply);
- if (status == NO_ERROR) {
- status = (status_t)reply.readInt32();
- }
- return status;
- }
-
- virtual status_t startRecognition(sound_model_handle_t handle,
- const sp<IMemory>& dataMemory)
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISoundTrigger::getInterfaceDescriptor());
- data.write(&handle, sizeof(sound_model_handle_t));
- if (dataMemory == 0) {
- data.writeInt32(0);
- } else {
- data.writeInt32(dataMemory->size());
- }
- data.writeStrongBinder(IInterface::asBinder(dataMemory));
- status_t status = remote()->transact(START_RECOGNITION, data, &reply);
- if (status == NO_ERROR) {
- status = (status_t)reply.readInt32();
- }
- return status;
- }
-
- virtual status_t stopRecognition(sound_model_handle_t handle)
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISoundTrigger::getInterfaceDescriptor());
- data.write(&handle, sizeof(sound_model_handle_t));
- status_t status = remote()->transact(STOP_RECOGNITION, data, &reply);
- if (status == NO_ERROR) {
- status = (status_t)reply.readInt32();
- }
- return status;
- }
-
- virtual status_t getModelState(sound_model_handle_t handle)
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISoundTrigger::getInterfaceDescriptor());
- data.write(&handle, sizeof(sound_model_handle_t));
- status_t status = remote()->transact(GET_MODEL_STATE, data, &reply);
- if (status == NO_ERROR) {
- status = (status_t)reply.readInt32();
- }
- return status;
- }
-
-};
-
-IMPLEMENT_META_INTERFACE(SoundTrigger, "android.hardware.ISoundTrigger");
-
-// ----------------------------------------------------------------------
-
-status_t BnSoundTrigger::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch(code) {
- case DETACH: {
- ALOGV("DETACH");
- CHECK_INTERFACE(ISoundTrigger, data, reply);
- detach();
- return NO_ERROR;
- } break;
- case LOAD_SOUND_MODEL: {
- CHECK_INTERFACE(ISoundTrigger, data, reply);
- sp<IMemory> modelMemory = interface_cast<IMemory>(
- data.readStrongBinder());
- sound_model_handle_t handle;
- status_t status = loadSoundModel(modelMemory, &handle);
- reply->writeInt32(status);
- if (status == NO_ERROR) {
- reply->write(&handle, sizeof(sound_model_handle_t));
- }
- return NO_ERROR;
- }
- case UNLOAD_SOUND_MODEL: {
- CHECK_INTERFACE(ISoundTrigger, data, reply);
- sound_model_handle_t handle;
- data.read(&handle, sizeof(sound_model_handle_t));
- status_t status = unloadSoundModel(handle);
- reply->writeInt32(status);
- return NO_ERROR;
- }
- case START_RECOGNITION: {
- CHECK_INTERFACE(ISoundTrigger, data, reply);
- sound_model_handle_t handle;
- data.read(&handle, sizeof(sound_model_handle_t));
- sp<IMemory> dataMemory;
- if (data.readInt32() != 0) {
- dataMemory = interface_cast<IMemory>(data.readStrongBinder());
- }
- status_t status = startRecognition(handle, dataMemory);
- reply->writeInt32(status);
- return NO_ERROR;
- }
- case STOP_RECOGNITION: {
- CHECK_INTERFACE(ISoundTrigger, data, reply);
- sound_model_handle_t handle;
- data.read(&handle, sizeof(sound_model_handle_t));
- status_t status = stopRecognition(handle);
- reply->writeInt32(status);
- return NO_ERROR;
- }
- case GET_MODEL_STATE: {
- CHECK_INTERFACE(ISoundTrigger, data, reply);
- sound_model_handle_t handle;
- status_t status = UNKNOWN_ERROR;
- status_t ret = data.read(&handle, sizeof(sound_model_handle_t));
- if (ret == NO_ERROR) {
- status = getModelState(handle);
- }
- reply->writeInt32(status);
- return ret;
- }
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/soundtrigger/ISoundTriggerClient.cpp b/soundtrigger/ISoundTriggerClient.cpp
deleted file mode 100644
index 1385631..0000000
--- a/soundtrigger/ISoundTriggerClient.cpp
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
-**
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <binder/IMemory.h>
-#include <binder/Parcel.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <soundtrigger/ISoundTriggerClient.h>
-
-namespace android {
-
-enum {
- ON_RECOGNITION_EVENT = IBinder::FIRST_CALL_TRANSACTION,
- ON_SOUNDMODEL_EVENT,
- ON_SERVICE_STATE_CHANGE
-};
-
-class BpSoundTriggerClient: public BpInterface<ISoundTriggerClient>
-{
-
-public:
- explicit BpSoundTriggerClient(const sp<IBinder>& impl)
- : BpInterface<ISoundTriggerClient>(impl)
- {
- }
-
- virtual void onRecognitionEvent(const sp<IMemory>& eventMemory)
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISoundTriggerClient::getInterfaceDescriptor());
- data.writeStrongBinder(IInterface::asBinder(eventMemory));
- remote()->transact(ON_RECOGNITION_EVENT,
- data,
- &reply);
- }
-
- virtual void onSoundModelEvent(const sp<IMemory>& eventMemory)
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISoundTriggerClient::getInterfaceDescriptor());
- data.writeStrongBinder(IInterface::asBinder(eventMemory));
- remote()->transact(ON_SOUNDMODEL_EVENT,
- data,
- &reply);
- }
- virtual void onServiceStateChange(const sp<IMemory>& eventMemory)
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISoundTriggerClient::getInterfaceDescriptor());
- data.writeStrongBinder(IInterface::asBinder(eventMemory));
- remote()->transact(ON_SERVICE_STATE_CHANGE,
- data,
- &reply);
- }
-};
-
-IMPLEMENT_META_INTERFACE(SoundTriggerClient,
- "android.hardware.ISoundTriggerClient");
-
-// ----------------------------------------------------------------------
-
-status_t BnSoundTriggerClient::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch(code) {
- case ON_RECOGNITION_EVENT: {
- CHECK_INTERFACE(ISoundTriggerClient, data, reply);
- sp<IMemory> eventMemory = interface_cast<IMemory>(
- data.readStrongBinder());
- onRecognitionEvent(eventMemory);
- return NO_ERROR;
- } break;
- case ON_SOUNDMODEL_EVENT: {
- CHECK_INTERFACE(ISoundTriggerClient, data, reply);
- sp<IMemory> eventMemory = interface_cast<IMemory>(
- data.readStrongBinder());
- onSoundModelEvent(eventMemory);
- return NO_ERROR;
- } break;
- case ON_SERVICE_STATE_CHANGE: {
- CHECK_INTERFACE(ISoundTriggerClient, data, reply);
- sp<IMemory> eventMemory = interface_cast<IMemory>(
- data.readStrongBinder());
- onServiceStateChange(eventMemory);
- return NO_ERROR;
- } break;
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/soundtrigger/ISoundTriggerHwService.cpp b/soundtrigger/ISoundTriggerHwService.cpp
deleted file mode 100644
index bd107b4..0000000
--- a/soundtrigger/ISoundTriggerHwService.cpp
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
-**
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#define LOG_TAG "BpSoundTriggerHwService"
-//#define LOG_NDEBUG 0
-
-#include <utils/Log.h>
-#include <utils/Errors.h>
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <binder/IMemory.h>
-#include <binder/Parcel.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-
-#include <soundtrigger/ISoundTriggerHwService.h>
-#include <soundtrigger/ISoundTrigger.h>
-#include <soundtrigger/ISoundTriggerClient.h>
-
-namespace android {
-
-enum {
- LIST_MODULES = IBinder::FIRST_CALL_TRANSACTION,
- ATTACH,
- SET_CAPTURE_STATE,
-};
-
-#define MAX_ITEMS_PER_LIST 1024
-
-class BpSoundTriggerHwService: public BpInterface<ISoundTriggerHwService>
-{
-public:
- explicit BpSoundTriggerHwService(const sp<IBinder>& impl)
- : BpInterface<ISoundTriggerHwService>(impl)
- {
- }
-
- virtual status_t listModules(const String16& opPackageName,
- struct sound_trigger_module_descriptor *modules,
- uint32_t *numModules)
- {
- if (numModules == NULL || (*numModules != 0 && modules == NULL)) {
- return BAD_VALUE;
- }
- Parcel data, reply;
- data.writeInterfaceToken(ISoundTriggerHwService::getInterfaceDescriptor());
- data.writeString16(opPackageName);
- unsigned int numModulesReq = (modules == NULL) ? 0 : *numModules;
- data.writeInt32(numModulesReq);
- status_t status = remote()->transact(LIST_MODULES, data, &reply);
- if (status == NO_ERROR) {
- status = (status_t)reply.readInt32();
- *numModules = (unsigned int)reply.readInt32();
- }
- ALOGV("listModules() status %d got *numModules %d", status, *numModules);
- if (status == NO_ERROR) {
- if (numModulesReq > *numModules) {
- numModulesReq = *numModules;
- }
- if (numModulesReq > 0) {
- reply.read(modules, numModulesReq * sizeof(struct sound_trigger_module_descriptor));
- }
- }
- return status;
- }
-
- virtual status_t attach(const String16& opPackageName,
- const sound_trigger_module_handle_t handle,
- const sp<ISoundTriggerClient>& client,
- sp<ISoundTrigger>& module)
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISoundTriggerHwService::getInterfaceDescriptor());
- data.writeString16(opPackageName);
- data.write(&handle, sizeof(sound_trigger_module_handle_t));
- data.writeStrongBinder(IInterface::asBinder(client));
- status_t status = remote()->transact(ATTACH, data, &reply);
- if (status != NO_ERROR) {
- return status;
- }
- status = reply.readInt32();
- if (reply.readInt32() != 0) {
- module = interface_cast<ISoundTrigger>(reply.readStrongBinder());
- }
- return status;
- }
-
- virtual status_t setCaptureState(bool active)
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISoundTriggerHwService::getInterfaceDescriptor());
- data.writeInt32(active);
- status_t status = remote()->transact(SET_CAPTURE_STATE, data, &reply);
- if (status == NO_ERROR) {
- status = reply.readInt32();
- }
- return status;
- }
-
-};
-
-IMPLEMENT_META_INTERFACE(SoundTriggerHwService, "android.hardware.ISoundTriggerHwService");
-
-// ----------------------------------------------------------------------
-
-status_t BnSoundTriggerHwService::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch(code) {
- case LIST_MODULES: {
- CHECK_INTERFACE(ISoundTriggerHwService, data, reply);
- String16 opPackageName;
- status_t status = data.readString16(&opPackageName);
- if (status != NO_ERROR) {
- return status;
- }
- unsigned int numModulesReq = data.readInt32();
- if (numModulesReq > MAX_ITEMS_PER_LIST) {
- numModulesReq = MAX_ITEMS_PER_LIST;
- }
- unsigned int numModules = numModulesReq;
- struct sound_trigger_module_descriptor *modules =
- (struct sound_trigger_module_descriptor *)calloc(numModulesReq,
- sizeof(struct sound_trigger_module_descriptor));
- if (modules == NULL) {
- reply->writeInt32(NO_MEMORY);
- reply->writeInt32(0);
- return NO_ERROR;
- }
- status = listModules(opPackageName, modules, &numModules);
- reply->writeInt32(status);
- reply->writeInt32(numModules);
- ALOGV("LIST_MODULES status %d got numModules %d", status, numModules);
-
- if (status == NO_ERROR) {
- if (numModulesReq > numModules) {
- numModulesReq = numModules;
- }
- reply->write(modules,
- numModulesReq * sizeof(struct sound_trigger_module_descriptor));
- }
- free(modules);
- return NO_ERROR;
- }
-
- case ATTACH: {
- CHECK_INTERFACE(ISoundTriggerHwService, data, reply);
- String16 opPackageName;
- status_t status = data.readString16(&opPackageName);
- if (status != NO_ERROR) {
- return status;
- }
- sound_trigger_module_handle_t handle;
- data.read(&handle, sizeof(sound_trigger_module_handle_t));
- sp<ISoundTriggerClient> client =
- interface_cast<ISoundTriggerClient>(data.readStrongBinder());
- sp<ISoundTrigger> module;
- status = attach(opPackageName, handle, client, module);
- reply->writeInt32(status);
- if (module != 0) {
- reply->writeInt32(1);
- reply->writeStrongBinder(IInterface::asBinder(module));
- } else {
- reply->writeInt32(0);
- }
- return NO_ERROR;
- } break;
-
- case SET_CAPTURE_STATE: {
- CHECK_INTERFACE(ISoundTriggerHwService, data, reply);
- reply->writeInt32(setCaptureState((bool)data.readInt32()));
- return NO_ERROR;
- } break;
-
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/soundtrigger/OWNERS b/soundtrigger/OWNERS
deleted file mode 100644
index e83f6b9..0000000
--- a/soundtrigger/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-elaurent@google.com
-thorntonc@google.com
diff --git a/soundtrigger/SoundTrigger.cpp b/soundtrigger/SoundTrigger.cpp
deleted file mode 100644
index 9708ea7..0000000
--- a/soundtrigger/SoundTrigger.cpp
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
-**
-** Copyright (C) 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#define LOG_TAG "SoundTrigger"
-//#define LOG_NDEBUG 0
-
-#include <utils/Log.h>
-#include <utils/threads.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <binder/IMemory.h>
-
-#include <soundtrigger/SoundTrigger.h>
-#include <soundtrigger/ISoundTrigger.h>
-#include <soundtrigger/ISoundTriggerHwService.h>
-#include <soundtrigger/ISoundTriggerClient.h>
-#include <soundtrigger/SoundTriggerCallback.h>
-
-namespace android {
-
-namespace {
- sp<ISoundTriggerHwService> gSoundTriggerHwService;
- const int kSoundTriggerHwServicePollDelay = 500000; // 0.5s
- const char* kSoundTriggerHwServiceName = "media.sound_trigger_hw";
- Mutex gLock;
-
- class DeathNotifier : public IBinder::DeathRecipient
- {
- public:
- DeathNotifier() {
- }
-
- virtual void binderDied(const wp<IBinder>& who __unused) {
- ALOGV("binderDied");
- Mutex::Autolock _l(gLock);
- gSoundTriggerHwService.clear();
- ALOGW("Sound trigger service died!");
- }
- };
-
- sp<DeathNotifier> gDeathNotifier;
-}; // namespace anonymous
-
-const sp<ISoundTriggerHwService> SoundTrigger::getSoundTriggerHwService()
-{
- Mutex::Autolock _l(gLock);
- if (gSoundTriggerHwService.get() == 0) {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder;
- do {
- binder = sm->getService(String16(kSoundTriggerHwServiceName));
- if (binder != 0) {
- break;
- }
- ALOGW("SoundTriggerHwService not published, waiting...");
- usleep(kSoundTriggerHwServicePollDelay);
- } while(true);
- if (gDeathNotifier == NULL) {
- gDeathNotifier = new DeathNotifier();
- }
- binder->linkToDeath(gDeathNotifier);
- gSoundTriggerHwService = interface_cast<ISoundTriggerHwService>(binder);
- }
- ALOGE_IF(gSoundTriggerHwService == 0, "no SoundTriggerHwService!?");
- return gSoundTriggerHwService;
-}
-
-// Static methods
-status_t SoundTrigger::listModules(const String16& opPackageName,
- struct sound_trigger_module_descriptor *modules,
- uint32_t *numModules)
-{
- ALOGV("listModules()");
- const sp<ISoundTriggerHwService> service = getSoundTriggerHwService();
- if (service == 0) {
- return NO_INIT;
- }
- return service->listModules(opPackageName, modules, numModules);
-}
-
-sp<SoundTrigger> SoundTrigger::attach(const String16& opPackageName,
- const sound_trigger_module_handle_t module,
- const sp<SoundTriggerCallback>& callback)
-{
- ALOGV("attach()");
- sp<SoundTrigger> soundTrigger;
- const sp<ISoundTriggerHwService> service = getSoundTriggerHwService();
- if (service == 0) {
- return soundTrigger;
- }
- soundTrigger = new SoundTrigger(module, callback);
- status_t status = service->attach(opPackageName, module, soundTrigger,
- soundTrigger->mISoundTrigger);
-
- if (status == NO_ERROR && soundTrigger->mISoundTrigger != 0) {
- IInterface::asBinder(soundTrigger->mISoundTrigger)->linkToDeath(soundTrigger);
- } else {
- ALOGW("Error %d connecting to sound trigger service", status);
- soundTrigger.clear();
- }
- return soundTrigger;
-}
-
-
-status_t SoundTrigger::setCaptureState(bool active)
-{
- ALOGV("setCaptureState(%d)", active);
- const sp<ISoundTriggerHwService> service = getSoundTriggerHwService();
- if (service == 0) {
- return NO_INIT;
- }
- return service->setCaptureState(active);
-}
-
-// SoundTrigger
-SoundTrigger::SoundTrigger(sound_trigger_module_handle_t /*module*/,
- const sp<SoundTriggerCallback>& callback)
- : mCallback(callback)
-{
-}
-
-SoundTrigger::~SoundTrigger()
-{
- if (mISoundTrigger != 0) {
- mISoundTrigger->detach();
- }
-}
-
-
-void SoundTrigger::detach() {
- ALOGV("detach()");
- Mutex::Autolock _l(mLock);
- mCallback.clear();
- if (mISoundTrigger != 0) {
- mISoundTrigger->detach();
- IInterface::asBinder(mISoundTrigger)->unlinkToDeath(this);
- mISoundTrigger = 0;
- }
-}
-
-status_t SoundTrigger::loadSoundModel(const sp<IMemory>& modelMemory,
- sound_model_handle_t *handle)
-{
- Mutex::Autolock _l(mLock);
- if (mISoundTrigger == 0) {
- return NO_INIT;
- }
-
- return mISoundTrigger->loadSoundModel(modelMemory, handle);
-}
-
-status_t SoundTrigger::unloadSoundModel(sound_model_handle_t handle)
-{
- Mutex::Autolock _l(mLock);
- if (mISoundTrigger == 0) {
- return NO_INIT;
- }
- return mISoundTrigger->unloadSoundModel(handle);
-}
-
-status_t SoundTrigger::startRecognition(sound_model_handle_t handle,
- const sp<IMemory>& dataMemory)
-{
- Mutex::Autolock _l(mLock);
- if (mISoundTrigger == 0) {
- return NO_INIT;
- }
- return mISoundTrigger->startRecognition(handle, dataMemory);
-}
-
-status_t SoundTrigger::stopRecognition(sound_model_handle_t handle)
-{
- Mutex::Autolock _l(mLock);
- if (mISoundTrigger == 0) {
- return NO_INIT;
- }
- return mISoundTrigger->stopRecognition(handle);
-}
-
-status_t SoundTrigger::getModelState(sound_model_handle_t handle)
-{
- Mutex::Autolock _l(mLock);
- if (mISoundTrigger == 0) {
- return NO_INIT;
- }
- return mISoundTrigger->getModelState(handle);
-}
-
-// BpSoundTriggerClient
-void SoundTrigger::onRecognitionEvent(const sp<IMemory>& eventMemory)
-{
- Mutex::Autolock _l(mLock);
- if (eventMemory == 0 || eventMemory->pointer() == NULL) {
- return;
- }
-
- if (mCallback != 0) {
- mCallback->onRecognitionEvent(
- (struct sound_trigger_recognition_event *)eventMemory->pointer());
- }
-}
-
-void SoundTrigger::onSoundModelEvent(const sp<IMemory>& eventMemory)
-{
- Mutex::Autolock _l(mLock);
- if (eventMemory == 0 || eventMemory->pointer() == NULL) {
- return;
- }
-
- if (mCallback != 0) {
- mCallback->onSoundModelEvent(
- (struct sound_trigger_model_event *)eventMemory->pointer());
- }
-}
-
-void SoundTrigger::onServiceStateChange(const sp<IMemory>& eventMemory)
-{
- Mutex::Autolock _l(mLock);
- if (eventMemory == 0 || eventMemory->pointer() == NULL) {
- return;
- }
-
- if (mCallback != 0) {
- mCallback->onServiceStateChange(
- *((sound_trigger_service_state_t *)eventMemory->pointer()));
- }
-}
-
-//IBinder::DeathRecipient
-void SoundTrigger::binderDied(const wp<IBinder>& who __unused) {
- Mutex::Autolock _l(mLock);
- ALOGW("SoundTrigger server binder Died ");
- mISoundTrigger = 0;
- if (mCallback != 0) {
- mCallback->onServiceDied();
- }
-}
-
-status_t SoundTrigger::stringToGuid(const char *str, sound_trigger_uuid_t *guid)
-{
- if (str == NULL || guid == NULL) {
- return BAD_VALUE;
- }
-
- int tmp[10];
-
- if (sscanf(str, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
- tmp, tmp+1, tmp+2, tmp+3, tmp+4, tmp+5, tmp+6, tmp+7, tmp+8, tmp+9) < 10) {
- return BAD_VALUE;
- }
- guid->timeLow = (uint32_t)tmp[0];
- guid->timeMid = (uint16_t)tmp[1];
- guid->timeHiAndVersion = (uint16_t)tmp[2];
- guid->clockSeq = (uint16_t)tmp[3];
- guid->node[0] = (uint8_t)tmp[4];
- guid->node[1] = (uint8_t)tmp[5];
- guid->node[2] = (uint8_t)tmp[6];
- guid->node[3] = (uint8_t)tmp[7];
- guid->node[4] = (uint8_t)tmp[8];
- guid->node[5] = (uint8_t)tmp[9];
-
- return NO_ERROR;
-}
-
-status_t SoundTrigger::guidToString(const sound_trigger_uuid_t *guid, char *str, size_t maxLen)
-{
- if (guid == NULL || str == NULL) {
- return BAD_VALUE;
- }
-
- snprintf(str, maxLen, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
- guid->timeLow,
- guid->timeMid,
- guid->timeHiAndVersion,
- guid->clockSeq,
- guid->node[0],
- guid->node[1],
- guid->node[2],
- guid->node[3],
- guid->node[4],
- guid->node[5]);
-
- return NO_ERROR;
-}
-
-}; // namespace android
diff --git a/tools/OWNERS b/tools/OWNERS
deleted file mode 100644
index f9cb567..0000000
--- a/tools/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-gkasten@google.com
diff --git a/tools/mainline_hook.sh b/tools/mainline_hook.sh
new file mode 100755
index 0000000..58afb49
--- /dev/null
+++ b/tools/mainline_hook.sh
@@ -0,0 +1,84 @@
+#!/bin/bash
+LOCAL_DIR="$( dirname "${BASH_SOURCE}" )"
+
+MAINLINE_FRAMEWORKS_AV_PATHS=(
+ media/extractors/
+ media/codec2/components/
+ media/libstagefright/codecs/amrnb
+ media/libstagefright/codecs/amrwb
+ media/libstagefright/codecs/amrwbenc
+ media/libstagefright/codecs/common
+ media/libstagefright/codecs/mp3dec
+ media/libstagefright/codecs/m4v_h263
+ media/libstagefright/flac/dec
+ media/libstagefright/mpeg2ts
+)
+
+MAINLINE_EXTERNAL_PROJECTS=(
+ external/aac
+ external/flac
+ external/libaac
+ external/libaom
+ external/libavc
+ external/libgav1
+ external/libgsm
+ external/libhevc
+ external/libmpeg2
+ external/libopus
+ external/libvpx
+ external/libxaac
+ external/sonivox
+ external/tremolo
+)
+
+DEV_BRANCH=qt-aml-media-dev
+RED=$(tput setaf 1)
+NORMAL=$(tput sgr0)
+WARNING_FULL="${RED}Please upload this change in ${DEV_BRANCH} unless it is restricted
+from mainline release until next dessert release. Low/moderate security bugs
+are restricted this way.${NORMAL}"
+WARNING_PARTIAL="${RED}It looks like your change has mainline and non-mainline changes;
+Consider separating them into two separate CLs -- one for mainline files,
+one for non-mainline files.${NORMAL}"
+PWD=`pwd`
+
+if git branch -vv | grep -q -P "^\*[^\[]+\[goog/qt-aml-media-dev"; then
+ # Change appears to be in mainline dev branch
+ exit 0
+fi
+
+for path in "${MAINLINE_EXTERNAL_PROJECTS[@]}"; do
+ if [[ $PWD =~ $path ]]; then
+ echo -e "${RED}The source of truth for '$path' is in ${DEV_BRANCH}.${NORMAL}"
+ echo -e ${WARNING_FULL}
+ exit 1
+ fi
+done
+
+if [[ ! $PWD =~ frameworks/av ]]; then
+ exit 0
+fi
+
+mainline_count=0
+total_count=0
+echo
+while read -r file ; do
+ (( total_count++ ))
+ for path in "${MAINLINE_FRAMEWORKS_AV_PATHS[@]}"; do
+ if [[ $file =~ ^$path ]]; then
+ echo -e "${RED}The source of truth for '$file' is in ${DEV_BRANCH}.${NORMAL}"
+ (( mainline_count++ ))
+ break
+ fi
+ done
+done < <(git show --name-only --pretty=format: $1 | grep -- "$2")
+
+if (( mainline_count != 0 )); then
+ if (( mainline_count == total_count )); then
+ echo -e ${WARNING_FULL}
+ else
+ echo -e ${WARNING_PARTIAL}
+ fi
+ exit 1
+fi
+exit 0
diff --git a/tools/resampler_tools/Android.mk b/tools/resampler_tools/Android.mk
deleted file mode 100644
index bba5199..0000000
--- a/tools/resampler_tools/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright 2005 The Android Open Source Project
-#
-# Android.mk for resampler_tools
-#
-
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
- fir.cpp
-
-LOCAL_MODULE := fir
-
-LOCAL_CFLAGS := -Werror -Wall
-
-include $(BUILD_HOST_EXECUTABLE)
diff --git a/tools/resampler_tools/OWNERS b/tools/resampler_tools/OWNERS
deleted file mode 100644
index b4a6798..0000000
--- a/tools/resampler_tools/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-hunga@google.com
diff --git a/tools/resampler_tools/fir.cpp b/tools/resampler_tools/fir.cpp
deleted file mode 100644
index fe4d212..0000000
--- a/tools/resampler_tools/fir.cpp
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <math.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-
-static inline double sinc(double x) {
- if (fabs(x) == 0.0f) return 1.0f;
- return sin(x) / x;
-}
-
-static inline double sqr(double x) {
- return x*x;
-}
-
-static inline int64_t toint(double x, int64_t maxval) {
- int64_t v;
-
- v = static_cast<int64_t>(floor(x * maxval + 0.5));
- if (v >= maxval) {
- return maxval - 1; // error!
- }
- return v;
-}
-
-static double I0(double x) {
- // from the Numerical Recipes in C p. 237
- double ax,ans,y;
- ax=fabs(x);
- if (ax < 3.75) {
- y=x/3.75;
- y*=y;
- ans=1.0+y*(3.5156229+y*(3.0899424+y*(1.2067492
- +y*(0.2659732+y*(0.360768e-1+y*0.45813e-2)))));
- } else {
- y=3.75/ax;
- ans=(exp(ax)/sqrt(ax))*(0.39894228+y*(0.1328592e-1
- +y*(0.225319e-2+y*(-0.157565e-2+y*(0.916281e-2
- +y*(-0.2057706e-1+y*(0.2635537e-1+y*(-0.1647633e-1
- +y*0.392377e-2))))))));
- }
- return ans;
-}
-
-static double kaiser(int k, int N, double beta) {
- if (k < 0 || k > N)
- return 0;
- return I0(beta * sqrt(1.0 - sqr((2.0*k)/N - 1.0))) / I0(beta);
-}
-
-static void usage(char* name) {
- fprintf(stderr,
- "usage: %s [-h] [-d] [-D] [-s sample_rate] [-c cut-off_frequency] [-n half_zero_crossings]"
- " [-f {float|fixed|fixed16}] [-b beta] [-v dBFS] [-l lerp]\n"
- " %s [-h] [-d] [-D] [-s sample_rate] [-c cut-off_frequency] [-n half_zero_crossings]"
- " [-f {float|fixed|fixed16}] [-b beta] [-v dBFS] -p M/N\n"
- " -h this help message\n"
- " -d debug, print comma-separated coefficient table\n"
- " -D generate extra declarations\n"
- " -p generate poly-phase filter coefficients, with sample increment M/N\n"
- " -s sample rate (48000)\n"
- " -c cut-off frequency (20478)\n"
- " -n number of zero-crossings on one side (8)\n"
- " -l number of lerping bits (4)\n"
- " -m number of polyphases (related to -l, default 16)\n"
- " -f output format, can be fixed, fixed16, or float (fixed)\n"
- " -b kaiser window parameter beta (7.865 [-80dB])\n"
- " -v attenuation in dBFS (0)\n",
- name, name
- );
- exit(0);
-}
-
-int main(int argc, char** argv)
-{
- // nc is the number of bits to store the coefficients
- int nc = 32;
- bool polyphase = false;
- unsigned int polyM = 160;
- unsigned int polyN = 147;
- bool debug = false;
- double Fs = 48000;
- double Fc = 20478;
- double atten = 1;
- int format = 0; // 0=fixed, 1=float
- bool declarations = false;
-
- // in order to keep the errors associated with the linear
- // interpolation of the coefficients below the quantization error
- // we must satisfy:
- // 2^nz >= 2^(nc/2)
- //
- // for 16 bit coefficients that would be 256
- //
- // note that increasing nz only increases memory requirements,
- // but doesn't increase the amount of computation to do.
- //
- //
- // see:
- // Smith, J.O. Digital Audio Resampling Home Page
- // https://ccrma.stanford.edu/~jos/resample/, 2011-03-29
- //
-
- // | 0.1102*(A - 8.7) A > 50
- // beta = | 0.5842*(A - 21)^0.4 + 0.07886*(A - 21) 21 <= A <= 50
- // | 0 A < 21
- // with A is the desired stop-band attenuation in dBFS
- //
- // for eg:
- //
- // 30 dB 2.210
- // 40 dB 3.384
- // 50 dB 4.538
- // 60 dB 5.658
- // 70 dB 6.764
- // 80 dB 7.865
- // 90 dB 8.960
- // 100 dB 10.056
- double beta = 7.865;
-
- // 2*nzc = (A - 8) / (2.285 * dw)
- // with dw the transition width = 2*pi*dF/Fs
- //
- int nzc = 8;
-
- /*
- * Example:
- * 44.1 KHz to 48 KHz resampling
- * 100 dB rejection above 28 KHz
- * (the spectrum will fold around 24 KHz and we want 100 dB rejection
- * at the point where the folding reaches 20 KHz)
- * ...___|_____
- * | \|
- * | ____/|\____
- * |/alias| \
- * ------/------+------\---------> KHz
- * 20 24 28
- *
- * Transition band 8 KHz, or dw = 1.0472
- *
- * beta = 10.056
- * nzc = 20
- */
-
- int M = 1 << 4; // number of phases for interpolation
- int ch;
- while ((ch = getopt(argc, argv, ":hds:c:n:f:l:m:b:p:v:z:D")) != -1) {
- switch (ch) {
- case 'd':
- debug = true;
- break;
- case 'D':
- declarations = true;
- break;
- case 'p':
- if (sscanf(optarg, "%u/%u", &polyM, &polyN) != 2) {
- usage(argv[0]);
- }
- polyphase = true;
- break;
- case 's':
- Fs = atof(optarg);
- break;
- case 'c':
- Fc = atof(optarg);
- break;
- case 'n':
- nzc = atoi(optarg);
- break;
- case 'm':
- M = atoi(optarg);
- break;
- case 'l':
- M = 1 << atoi(optarg);
- break;
- case 'f':
- if (!strcmp(optarg, "fixed")) {
- format = 0;
- }
- else if (!strcmp(optarg, "fixed16")) {
- format = 0;
- nc = 16;
- }
- else if (!strcmp(optarg, "float")) {
- format = 1;
- }
- else {
- usage(argv[0]);
- }
- break;
- case 'b':
- beta = atof(optarg);
- break;
- case 'v':
- atten = pow(10, -fabs(atof(optarg))*0.05 );
- break;
- case 'h':
- default:
- usage(argv[0]);
- break;
- }
- }
-
- // cut off frequency ratio Fc/Fs
- double Fcr = Fc / Fs;
-
- // total number of coefficients (one side)
-
- const int N = M * nzc;
-
- // lerp (which is most useful if M is a power of 2)
-
- int nz = 0; // recalculate nz as the bits needed to represent M
- for (int i = M-1 ; i; i>>=1, nz++);
- // generate the right half of the filter
- if (!debug) {
- printf("// cmd-line:");
- for (int i=0 ; i<argc ; i++) {
- printf(" %s", argv[i]);
- }
- printf("\n");
- if (declarations) {
- if (!polyphase) {
- printf("const int32_t RESAMPLE_FIR_SIZE = %d;\n", N);
- printf("const int32_t RESAMPLE_FIR_INT_PHASES = %d;\n", M);
- printf("const int32_t RESAMPLE_FIR_NUM_COEF = %d;\n", nzc);
- } else {
- printf("const int32_t RESAMPLE_FIR_SIZE = %d;\n", 2*nzc*polyN);
- printf("const int32_t RESAMPLE_FIR_NUM_COEF = %d;\n", 2*nzc);
- }
- if (!format) {
- printf("const int32_t RESAMPLE_FIR_COEF_BITS = %d;\n", nc);
- }
- printf("\n");
- printf("static %s resampleFIR[] = {", !format ? "int32_t" : "float");
- }
- }
-
- if (!polyphase) {
- for (int i=0 ; i<=M ; i++) { // an extra set of coefs for interpolation
- for (int j=0 ; j<nzc ; j++) {
- int ix = j*M + i;
- double x = (2.0 * M_PI * ix * Fcr) / M;
- double y = kaiser(ix+N, 2*N, beta) * sinc(x) * 2.0 * Fcr;
- y *= atten;
-
- if (!debug) {
- if (j == 0)
- printf("\n ");
- }
- if (!format) {
- int64_t yi = toint(y, 1ULL<<(nc-1));
- if (nc > 16) {
- printf("0x%08x,", int32_t(yi));
- } else {
- printf("0x%04x,", int32_t(yi)&0xffff);
- }
- } else {
- printf("%.9g%s", y, debug ? "," : "f,");
- }
- if (j != nzc-1) {
- printf(" ");
- }
- }
- }
- } else {
- for (unsigned int j=0 ; j<polyN ; j++) {
- // calculate the phase
- double p = ((polyM*j) % polyN) / double(polyN);
- if (!debug) printf("\n ");
- else printf("\n");
- // generate a FIR per phase
- for (int i=-nzc ; i<nzc ; i++) {
- double x = 2.0 * M_PI * Fcr * (i + p);
- double y = kaiser(i+N, 2*N, beta) * sinc(x) * 2.0 * Fcr;;
- y *= atten;
- if (!format) {
- int64_t yi = toint(y, 1ULL<<(nc-1));
- if (nc > 16) {
- printf("0x%08x,", int32_t(yi));
- } else {
- printf("0x%04x,", int32_t(yi)&0xffff);
- }
- } else {
- printf("%.9g%s", y, debug ? "," : "f,");
- }
-
- if (i != nzc-1) {
- printf(" ");
- }
- }
- }
- }
-
- if (!debug && declarations) {
- printf("\n};");
- }
- printf("\n");
- return 0;
-}
-
-// http://www.csee.umbc.edu/help/sound/AFsp-V2R1/html/audio/ResampAudio.html